Revision 5136a052

b/Makefile.objs
107 107
ui-obj-$(CONFIG_CURSES) += curses.o
108 108
ui-obj-y += vnc.o d3des.o
109 109
ui-obj-y += vnc-enc-zlib.o vnc-enc-hextile.o
110
ui-obj-y += vnc-enc-tight.o
110
ui-obj-y += vnc-enc-tight.o vnc-palette.o
111 111
ui-obj-$(CONFIG_VNC_TLS) += vnc-tls.o vnc-auth-vencrypt.o
112 112
ui-obj-$(CONFIG_VNC_SASL) += vnc-auth-sasl.o
113 113
ui-obj-$(CONFIG_COCOA) += cocoa.o
b/ui/vnc-enc-tight.c
39 39
#include "qemu-common.h"
40 40

  
41 41
#include "bswap.h"
42
#include "qdict.h"
43 42
#include "qint.h"
44 43
#include "vnc.h"
45 44
#include "vnc-enc-tight.h"
45
#include "vnc-palette.h"
46 46

  
47 47
/* Compression level stuff. The following array contains various
48 48
   encoder parameters for each of 10 compression levels (0..9).
......
89 89
};
90 90

  
91 91
static int send_png_rect(VncState *vs, int x, int y, int w, int h,
92
                         QDict *palette);
92
                         VncPalette *palette);
93 93

  
94 94
static bool tight_can_send_png_rect(VncState *vs, int w, int h)
95 95
{
......
313 313
/*
314 314
 * Code to determine how many different colors used in rectangle.
315 315
 */
316

  
317
static void tight_palette_rgb2buf(uint32_t rgb, int bpp, uint8_t buf[6])
318
{
319
    memset(buf, 0, 6);
320

  
321
    if (bpp == 32) {
322
        buf[0] = ((rgb >> 24) & 0xFF);
323
        buf[1] = ((rgb >> 16) & 0xFF);
324
        buf[2] = ((rgb >>  8) & 0xFF);
325
        buf[3] = ((rgb >>  0) & 0xFF);
326
        buf[4] = ((buf[0] & 1) == 0) << 3 | ((buf[1] & 1) == 0) << 2;
327
        buf[4]|= ((buf[2] & 1) == 0) << 1 | ((buf[3] & 1) == 0) << 0;
328
        buf[0] |= 1;
329
        buf[1] |= 1;
330
        buf[2] |= 1;
331
        buf[3] |= 1;
332
    }
333
    if (bpp == 16) {
334
        buf[0] = ((rgb >> 8) & 0xFF);
335
        buf[1] = ((rgb >> 0) & 0xFF);
336
        buf[2] = ((buf[0] & 1) == 0) << 1 | ((buf[1] & 1) == 0) << 0;
337
        buf[0] |= 1;
338
        buf[1] |= 1;
339
    }
340
}
341

  
342
static uint32_t tight_palette_buf2rgb(int bpp, const uint8_t *buf)
343
{
344
    uint32_t rgb = 0;
345

  
346
    if (bpp == 32) {
347
        rgb |= ((buf[0] & ~1) | !((buf[4] >> 3) & 1)) << 24;
348
        rgb |= ((buf[1] & ~1) | !((buf[4] >> 2) & 1)) << 16;
349
        rgb |= ((buf[2] & ~1) | !((buf[4] >> 1) & 1)) <<  8;
350
        rgb |= ((buf[3] & ~1) | !((buf[4] >> 0) & 1)) <<  0;
351
    }
352
    if (bpp == 16) {
353
        rgb |= ((buf[0] & ~1) | !((buf[2] >> 1) & 1)) << 8;
354
        rgb |= ((buf[1] & ~1) | !((buf[2] >> 0) & 1)) << 0;
355
    }
356
    return rgb;
357
}
358

  
359

  
360
static int tight_palette_insert(QDict *palette, uint32_t rgb, int bpp, int max)
361
{
362
    uint8_t key[6];
363
    int idx = qdict_size(palette);
364
    bool present;
365

  
366
    tight_palette_rgb2buf(rgb, bpp, key);
367
    present = qdict_haskey(palette, (char *)key);
368
    if (idx >= max && !present) {
369
        return 0;
370
    }
371
    if (!present) {
372
        qdict_put(palette, (char *)key, qint_from_int(idx));
373
    }
374
    return qdict_size(palette);
375
}
376

  
377 316
#define DEFINE_FILL_PALETTE_FUNCTION(bpp)                               \
378 317
                                                                        \
379 318
    static int                                                          \
380 319
    tight_fill_palette##bpp(VncState *vs, int x, int y,                 \
381 320
                            int max, size_t count,                      \
382 321
                            uint32_t *bg, uint32_t *fg,                 \
383
                            struct QDict **palette) {                   \
322
                            VncPalette **palette) {                     \
384 323
        uint##bpp##_t *data;                                            \
385 324
        uint##bpp##_t c0, c1, ci;                                       \
386 325
        int i, n0, n1;                                                  \
......
427 366
            return 0;                                                   \
428 367
        }                                                               \
429 368
                                                                        \
430
        *palette = qdict_new();                                         \
431
        tight_palette_insert(*palette, c0, bpp, max);                   \
432
        tight_palette_insert(*palette, c1, bpp, max);                   \
433
        tight_palette_insert(*palette, ci, bpp, max);                   \
369
        *palette = palette_new(max, bpp);                               \
370
        palette_put(*palette, c0);                                      \
371
        palette_put(*palette, c1);                                      \
372
        palette_put(*palette, ci);                                      \
434 373
                                                                        \
435 374
        for (i++; i < count; i++) {                                     \
436 375
            if (data[i] == ci) {                                        \
437 376
                continue;                                               \
438 377
            } else {                                                    \
439 378
                ci = data[i];                                           \
440
                if (!tight_palette_insert(*palette, (uint32_t)ci,       \
441
                                          bpp, max)) {                  \
379
                if (!palette_put(*palette, (uint32_t)ci)) {             \
442 380
                    return 0;                                           \
443 381
                }                                                       \
444 382
            }                                                           \
445 383
        }                                                               \
446 384
                                                                        \
447
        return qdict_size(*palette);                                    \
385
        return palette_size(*palette);                                  \
448 386
    }
449 387

  
450 388
DEFINE_FILL_PALETTE_FUNCTION(8)
......
453 391

  
454 392
static int tight_fill_palette(VncState *vs, int x, int y,
455 393
                              size_t count, uint32_t *bg, uint32_t *fg,
456
                              struct QDict **palette)
394
                              VncPalette **palette)
457 395
{
458 396
    int max;
459 397

  
......
478 416
    return 0;
479 417
}
480 418

  
481
/* Callback to dump a palette with qdict_iter
482
static void print_palette(const char *key, QObject *obj, void *opaque)
483
{
484
    uint8_t idx = qint_get_int(qobject_to_qint(obj));
485
    uint32_t rgb = tight_palette_buf2rgb(32, (uint8_t *)key);
486

  
487
    fprintf(stderr, "%.2x ", (unsigned char)*key);
488
    while (*key++)
489
        fprintf(stderr, "%.2x ", (unsigned char)*key);
490

  
491
    fprintf(stderr, ": idx: %x rgb: %x\n", idx, rgb);
492
}
493
*/
494

  
495 419
/*
496 420
 * Converting truecolor samples into palette indices.
497 421
 */
......
499 423
                                                                        \
500 424
    static void                                                         \
501 425
    tight_encode_indexed_rect##bpp(uint8_t *buf, int count,             \
502
                                   struct QDict *palette) {             \
426
                                   VncPalette *palette) {               \
503 427
        uint##bpp##_t *src;                                             \
504 428
        uint##bpp##_t rgb;                                              \
505
        uint8_t key[6];                                                 \
506 429
        int i, rep;                                                     \
507 430
        uint8_t idx;                                                    \
508 431
                                                                        \
......
515 438
            while (i < count && *src == rgb) {                          \
516 439
                rep++, src++, i++;                                      \
517 440
            }                                                           \
518
            tight_palette_rgb2buf(rgb, bpp, key);                       \
519
            if (!qdict_haskey(palette, (char *)key)) {                  \
520
                /*                                                      \
521
                 * Should never happen, but don't break everything      \
522
                 * if it does, use the first color instead              \
523
                 */                                                     \
441
            idx = palette_idx(palette, rgb);                            \
442
            /*                                                          \
443
             * Should never happen, but don't break everything          \
444
             * if it does, use the first color instead                  \
445
             */                                                         \
446
            if (idx == -1) {                                            \
524 447
                idx = 0;                                                \
525
            } else {                                                    \
526
                idx = qdict_get_int(palette, (char *)key);              \
527 448
            }                                                           \
528 449
            while (rep >= 0) {                                          \
529 450
                *buf++ = idx;                                           \
......
1035 956
#ifdef CONFIG_VNC_PNG
1036 957
    if (tight_can_send_png_rect(vs, w, h)) {
1037 958
        int ret;
1038
        QDict *palette = qdict_new();
1039 959
        int bpp = vs->clientds.pf.bytes_per_pixel * 8;
960
        VncPalette *palette = palette_new(2, bpp);
1040 961

  
1041
        tight_palette_insert(palette, bg, bpp, 2);
1042
        tight_palette_insert(palette, fg, bpp, 2);
962
        palette_put(palette, bg);
963
        palette_put(palette, fg);
1043 964
        ret = send_png_rect(vs, x, y, w, h, palette);
1044
        QDECREF(palette);
965
        palette_destroy(palette);
1045 966
        return ret;
1046 967
    }
1047 968
#endif
......
1091 1012
#endif
1092 1013
};
1093 1014

  
1094
static void write_palette(const char *key, QObject *obj, void *opaque)
1015
static void write_palette(int idx, uint32_t color, void *opaque)
1095 1016
{
1096 1017
    struct palette_cb_priv *priv = opaque;
1097 1018
    VncState *vs = priv->vs;
1098 1019
    uint32_t bytes = vs->clientds.pf.bytes_per_pixel;
1099
    uint8_t idx = qint_get_int(qobject_to_qint(obj));
1100 1020

  
1101 1021
    if (bytes == 4) {
1102
        uint32_t color = tight_palette_buf2rgb(32, (uint8_t *)key);
1103

  
1104 1022
        ((uint32_t*)priv->header)[idx] = color;
1105 1023
    } else {
1106
        uint16_t color = tight_palette_buf2rgb(16, (uint8_t *)key);
1107

  
1108 1024
        ((uint16_t*)priv->header)[idx] = color;
1109 1025
    }
1110 1026
}
......
1145 1061
}
1146 1062

  
1147 1063
static int send_palette_rect(VncState *vs, int x, int y,
1148
                             int w, int h, struct QDict *palette)
1064
                             int w, int h, VncPalette *palette)
1149 1065
{
1150 1066
    int stream = 2;
1151 1067
    int level = tight_conf[vs->tight_compression].idx_zlib_level;
......
1158 1074
    }
1159 1075
#endif
1160 1076

  
1161
    colors = qdict_size(palette);
1077
    colors = palette_size(palette);
1162 1078

  
1163 1079
    vnc_write_u8(vs, (stream | VNC_TIGHT_EXPLICIT_FILTER) << 4);
1164 1080
    vnc_write_u8(vs, VNC_TIGHT_FILTER_PALETTE);
......
1168 1084
    case 4:
1169 1085
    {
1170 1086
        size_t old_offset, offset;
1171
        uint32_t header[qdict_size(palette)];
1087
        uint32_t header[palette_size(palette)];
1172 1088
        struct palette_cb_priv priv = { vs, (uint8_t *)header };
1173 1089

  
1174 1090
        old_offset = vs->output.offset;
1175
        qdict_iter(palette, write_palette, &priv);
1091
        palette_iter(palette, write_palette, &priv);
1176 1092
        vnc_write(vs, header, sizeof(header));
1177 1093

  
1178 1094
        if (vs->tight_pixel24) {
......
1185 1101
    }
1186 1102
    case 2:
1187 1103
    {
1188
        uint16_t header[qdict_size(palette)];
1104
        uint16_t header[palette_size(palette)];
1189 1105
        struct palette_cb_priv priv = { vs, (uint8_t *)header };
1190 1106

  
1191
        qdict_iter(palette, write_palette, &priv);
1107
        palette_iter(palette, write_palette, &priv);
1192 1108
        vnc_write(vs, header, sizeof(header));
1193 1109
        tight_encode_indexed_rect16(vs->tight.buffer, w * h, palette);
1194 1110
        break;
......
1370 1286
 * PNG compression stuff.
1371 1287
 */
1372 1288
#ifdef CONFIG_VNC_PNG
1373
static void write_png_palette(const char *key, QObject *obj, void *opaque)
1289
static void write_png_palette(int idx, uint32_t pix, void *opaque)
1374 1290
{
1375 1291
    struct palette_cb_priv *priv = opaque;
1376 1292
    VncState *vs = priv->vs;
1377
    uint32_t bytes = vs->clientds.pf.bytes_per_pixel;
1378
    uint8_t idx = qint_get_int(qobject_to_qint(obj));
1379 1293
    png_colorp color = &priv->png_palette[idx];
1380
    uint32_t pix;
1381

  
1382
    if (bytes == 4) {
1383
        pix = tight_palette_buf2rgb(32, (uint8_t *)key);
1384
    } else {
1385
        pix = tight_palette_buf2rgb(16, (uint8_t *)key);
1386
    }
1387 1294

  
1388 1295
    if (vs->tight_pixel24)
1389 1296
    {
......
1433 1340
}
1434 1341

  
1435 1342
static int send_png_rect(VncState *vs, int x, int y, int w, int h,
1436
                         QDict *palette)
1343
                         VncPalette *palette)
1437 1344
{
1438 1345
    png_byte color_type;
1439 1346
    png_structp png_ptr;
......
1476 1383
        struct palette_cb_priv priv;
1477 1384

  
1478 1385
        png_palette = png_malloc(png_ptr, sizeof(*png_palette) *
1479
                                 qdict_size(palette));
1386
                                 palette_size(palette));
1480 1387

  
1481 1388
        priv.vs = vs;
1482 1389
        priv.png_palette = png_palette;
1483
        qdict_iter(palette, write_png_palette, &priv);
1390
        palette_iter(palette, write_png_palette, &priv);
1484 1391

  
1485
        png_set_PLTE(png_ptr, info_ptr, png_palette, qdict_size(palette));
1392
        png_set_PLTE(png_ptr, info_ptr, png_palette, palette_size(palette));
1486 1393

  
1487 1394
        offset = vs->tight.offset;
1488 1395
        if (vs->clientds.pf.bytes_per_pixel == 4) {
......
1542 1449

  
1543 1450
static int send_sub_rect(VncState *vs, int x, int y, int w, int h)
1544 1451
{
1545
    struct QDict *palette = NULL;
1452
    VncPalette *palette = NULL;
1546 1453
    uint32_t bg = 0, fg = 0;
1547 1454
    int colors;
1548 1455
    int ret = 0;
......
1589 1496
        ret = send_palette_rect(vs, x, y, w, h, palette);
1590 1497
#endif
1591 1498
    }
1592
    QDECREF(palette);
1499
    palette_destroy(palette);
1593 1500
    return ret;
1594 1501
}
1595 1502

  
b/ui/vnc-palette.c
1
/*
2
 * QEMU VNC display driver: palette hash table
3
 *
4
 * From libvncserver/libvncserver/tight.c
5
 * Copyright (C) 2000, 2001 Const Kaplinsky.  All Rights Reserved.
6
 * Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
7
 *
8
 * Copyright (C) 2010 Corentin Chary <corentin.chary@gmail.com>
9
 *
10
 * Permission is hereby granted, free of charge, to any person obtaining a copy
11
 * of this software and associated documentation files (the "Software"), to deal
12
 * in the Software without restriction, including without limitation the rights
13
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
 * copies of the Software, and to permit persons to whom the Software is
15
 * furnished to do so, subject to the following conditions:
16
 *
17
 * The above copyright notice and this permission notice shall be included in
18
 * all copies or substantial portions of the Software.
19
 *
20
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26
 * THE SOFTWARE.
27
 */
28

  
29
#include "vnc-palette.h"
30

  
31
static VncPaletteEntry *palette_find(const VncPalette *palette,
32
                                     uint32_t color, unsigned int hash)
33
{
34
    VncPaletteEntry *entry;
35

  
36
    QLIST_FOREACH(entry, &palette->table[hash], next) {
37
        if (entry->color == color) {
38
            return entry;
39
        }
40
    }
41

  
42
    return NULL;
43
}
44

  
45
static unsigned int palette_hash(uint32_t rgb, int bpp)
46
{
47
    if (bpp == 16) {
48
        return ((unsigned int)(((rgb >> 8) + rgb) & 0xFF));
49
    } else {
50
        return ((unsigned int)(((rgb >> 16) + (rgb >> 8)) & 0xFF));
51
    }
52
}
53

  
54
VncPalette *palette_new(size_t max, int bpp)
55
{
56
    VncPalette *palette;
57

  
58
    palette = qemu_mallocz(sizeof(*palette));
59
    palette->max = max;
60
    palette->bpp = bpp;
61
    return palette;
62
}
63

  
64
void palette_destroy(VncPalette *palette)
65
{
66
    int i;
67

  
68
    if (palette == NULL) {
69
        return ;
70
    }
71

  
72
    for (i = 0; i < VNC_PALETTE_HASH_SIZE; i++) {
73
        VncPaletteEntry *entry = QLIST_FIRST(&palette->table[i]);
74
        while (entry) {
75
            VncPaletteEntry *tmp = QLIST_NEXT(entry, next);
76
            QLIST_REMOVE(entry, next);
77
            qemu_free(entry);
78
            entry = tmp;
79
        }
80
    }
81

  
82
    qemu_free(palette);
83
}
84

  
85
int palette_put(VncPalette *palette, uint32_t color)
86
{
87
    unsigned int hash;
88
    unsigned int idx = palette->size;
89
    VncPaletteEntry *entry;
90

  
91
    hash = palette_hash(color, palette->bpp) % VNC_PALETTE_HASH_SIZE;
92
    entry = palette_find(palette, color, hash);
93

  
94
    if (!entry && palette->size >= palette->max) {
95
        return 0;
96
    }
97
    if (!entry) {
98
        VncPaletteEntry *entry;
99

  
100
        entry = qemu_mallocz(sizeof(*entry));
101
        entry->color = color;
102
        entry->idx = idx;
103
        QLIST_INSERT_HEAD(&palette->table[hash], entry, next);
104
        palette->size++;
105
    }
106
    return palette->size;
107
}
108

  
109
int palette_idx(const VncPalette *palette, uint32_t color)
110
{
111
    VncPaletteEntry *entry;
112
    unsigned int hash;
113

  
114
    hash = palette_hash(color, palette->bpp) % VNC_PALETTE_HASH_SIZE;
115
    entry = palette_find(palette, color, hash);
116
    return (entry == NULL ? -1 : entry->idx);
117
}
118

  
119
size_t palette_size(const VncPalette *palette)
120
{
121
    return palette->size;
122
}
123

  
124
void palette_iter(const VncPalette *palette,
125
                  void (*iter)(int idx, uint32_t color, void *opaque),
126
                  void *opaque)
127
{
128
    int i;
129
    VncPaletteEntry *entry;
130

  
131
    for (i = 0; i < VNC_PALETTE_HASH_SIZE; i++) {
132
        QLIST_FOREACH(entry, &palette->table[i], next) {
133
            iter(entry->idx, entry->color, opaque);
134
        }
135
    }
136
}
b/ui/vnc-palette.h
1
/*
2
 * QEMU VNC display driver: palette hash table
3
 *
4
 * From libvncserver/libvncserver/tight.c
5
 * Copyright (C) 2000, 2001 Const Kaplinsky.  All Rights Reserved.
6
 * Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
7
 *
8
 * Copyright (C) 2010 Corentin Chary <corentin.chary@gmail.com>
9
 *
10
 * Permission is hereby granted, free of charge, to any person obtaining a copy
11
 * of this software and associated documentation files (the "Software"), to deal
12
 * in the Software without restriction, including without limitation the rights
13
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
 * copies of the Software, and to permit persons to whom the Software is
15
 * furnished to do so, subject to the following conditions:
16
 *
17
 * The above copyright notice and this permission notice shall be included in
18
 * all copies or substantial portions of the Software.
19
 *
20
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26
 * THE SOFTWARE.
27
 */
28

  
29
#ifndef VNC_PALETTE_H
30
#define VNC_PALETTE_H
31

  
32
#include "qlist.h"
33
#include "qemu-queue.h"
34
#include <stdint.h>
35

  
36
#define VNC_PALETTE_HASH_SIZE 256
37

  
38
typedef struct VncPaletteEntry {
39
    int idx;
40
    uint32_t color;
41
    QLIST_ENTRY(VncPaletteEntry) next;
42
} VncPaletteEntry;
43

  
44
typedef struct VncPalette {
45
    QObject_HEAD;
46
    size_t size;
47
    size_t max;
48
    int bpp;
49
    QLIST_HEAD(,VncPaletteEntry) table[VNC_PALETTE_HASH_SIZE];
50
} VncPalette;
51

  
52
VncPalette *palette_new(size_t max, int bpp);
53
void palette_destroy(VncPalette *palette);
54

  
55
int palette_put(VncPalette *palette, uint32_t color);
56
int palette_idx(const VncPalette *palette, uint32_t color);
57
size_t palette_size(const VncPalette *palette);
58

  
59
void palette_iter(const VncPalette *palette,
60
                  void (*iter)(int idx, uint32_t color, void *opaque),
61
                  void *opaque);
62

  
63
#endif /* VNC_PALETTE_H */

Also available in: Unified diff