diff options
Diffstat (limited to 'ui')
-rw-r--r-- | ui/vnc-enc-tight.c | 316 | ||||
-rw-r--r-- | ui/vnc-enc-tight.h | 16 | ||||
-rw-r--r-- | ui/vnc.c | 11 | ||||
-rw-r--r-- | ui/vnc.h | 15 |
4 files changed, 304 insertions, 54 deletions
diff --git a/ui/vnc-enc-tight.c b/ui/vnc-enc-tight.c index 4ff88a8b03..cc57c26796 100644 --- a/ui/vnc-enc-tight.c +++ b/ui/vnc-enc-tight.c @@ -26,13 +26,18 @@ * THE SOFTWARE. */ -#include "qemu-common.h" +#include "config-host.h" +#ifdef CONFIG_VNC_PNG +#include <png.h> +#endif #ifdef CONFIG_VNC_JPEG #include <stdio.h> #include <jpeglib.h> #endif +#include "qemu-common.h" + #include "bswap.h" #include "qdict.h" #include "qint.h" @@ -63,6 +68,29 @@ static const struct { { 65536, 2048, 32, 8192, 9, 9, 9, 6, 200, 500, 96, 80, 200, 500 } }; + +static int tight_send_framebuffer_update(VncState *vs, int x, int y, + int w, int h); + +#ifdef CONFIG_VNC_PNG +static int send_png_rect(VncState *vs, int x, int y, int w, int h, + QDict *palette); + +static bool tight_can_send_png_rect(VncState *vs, int w, int h) +{ + if (vs->tight_type != VNC_ENCODING_TIGHT_PNG) { + return false; + } + + if (ds_get_bytes_per_pixel(vs->ds) == 1 || + vs->clientds.pf.bytes_per_pixel == 1) { + return false; + } + + return true; +} +#endif + /* * Code to guess if given rectangle is suitable for smooth image * compression (by applying "gradient" filter or JPEG coder). @@ -466,6 +494,7 @@ static void print_palette(const char *key, QObject *obj, void *opaque) src = (uint##bpp##_t *) buf; \ \ for (i = 0; i < count; i++) { \ + \ rgb = *src++; \ rep = 0; \ while (i < count && *src == rgb) { \ @@ -937,11 +966,17 @@ static void tight_pack24(VncState *vs, uint8_t *buf, size_t count, size_t *ret) } } -static int send_full_color_rect(VncState *vs, int w, int h) +static int send_full_color_rect(VncState *vs, int x, int y, int w, int h) { int stream = 0; size_t bytes; +#ifdef CONFIG_VNC_PNG + if (tight_can_send_png_rect(vs, w, h)) { + return send_png_rect(vs, x, y, w, h, NULL); + } +#endif + vnc_write_u8(vs, stream << 4); /* no flushing, no filter */ if (vs->tight_pixel24) { @@ -975,12 +1010,27 @@ static int send_solid_rect(VncState *vs) return 1; } -static int send_mono_rect(VncState *vs, int w, int h, uint32_t bg, uint32_t fg) +static int send_mono_rect(VncState *vs, int x, int y, + int w, int h, uint32_t bg, uint32_t fg) { size_t bytes; int stream = 1; int level = tight_conf[vs->tight_compression].mono_zlib_level; +#ifdef CONFIG_VNC_PNG + if (tight_can_send_png_rect(vs, w, h)) { + int ret; + QDict *palette = qdict_new(); + int bpp = vs->clientds.pf.bytes_per_pixel * 8; + + tight_palette_insert(palette, bg, bpp, 2); + tight_palette_insert(palette, fg, bpp, 2); + ret = send_png_rect(vs, x, y, w, h, palette); + QDECREF(palette); + return ret; + } +#endif + bytes = ((w + 7) / 8) * h; vnc_write_u8(vs, (stream | VNC_TIGHT_EXPLICIT_FILTER) << 4); @@ -1021,6 +1071,9 @@ static int send_mono_rect(VncState *vs, int w, int h, uint32_t bg, uint32_t fg) struct palette_cb_priv { VncState *vs; uint8_t *header; +#ifdef CONFIG_VNC_PNG + png_colorp png_palette; +#endif }; static void write_palette(const char *key, QObject *obj, void *opaque) @@ -1041,14 +1094,14 @@ static void write_palette(const char *key, QObject *obj, void *opaque) } } -static bool send_gradient_rect(VncState *vs, int w, int h) +static bool send_gradient_rect(VncState *vs, int x, int y, int w, int h) { int stream = 3; int level = tight_conf[vs->tight_compression].gradient_zlib_level; size_t bytes; if (vs->clientds.pf.bytes_per_pixel == 1) - return send_full_color_rect(vs, w, h); + return send_full_color_rect(vs, x, y, w, h); vnc_write_u8(vs, (stream | VNC_TIGHT_EXPLICIT_FILTER) << 4); vnc_write_u8(vs, VNC_TIGHT_FILTER_GRADIENT); @@ -1076,13 +1129,20 @@ static bool send_gradient_rect(VncState *vs, int w, int h) return (bytes >= 0); } -static int send_palette_rect(VncState *vs, int w, int h, struct QDict *palette) +static int send_palette_rect(VncState *vs, int x, int y, + int w, int h, struct QDict *palette) { int stream = 2; int level = tight_conf[vs->tight_compression].idx_zlib_level; int colors; size_t bytes; +#ifdef CONFIG_VNC_PNG + if (tight_can_send_png_rect(vs, w, h)) { + return send_png_rect(vs, x, y, w, h, palette); + } +#endif + colors = qdict_size(palette); vnc_write_u8(vs, (stream | VNC_TIGHT_EXPLICIT_FILTER) << 4); @@ -1130,12 +1190,9 @@ static int send_palette_rect(VncState *vs, int w, int h, struct QDict *palette) return (bytes >= 0); } -/* - * JPEG compression stuff. - */ -#ifdef CONFIG_VNC_JPEG -static void jpeg_prepare_row24(VncState *vs, uint8_t *dst, int x, int y, - int count) +#if defined(CONFIG_VNC_JPEG) || defined(CONFIG_VNC_PNG) +static void rgb_prepare_row24(VncState *vs, uint8_t *dst, int x, int y, + int count) { VncDisplay *vd = vs->vd; uint32_t *fbptr; @@ -1152,11 +1209,11 @@ static void jpeg_prepare_row24(VncState *vs, uint8_t *dst, int x, int y, } } -#define DEFINE_JPEG_GET_ROW_FUNCTION(bpp) \ +#define DEFINE_RGB_GET_ROW_FUNCTION(bpp) \ \ static void \ - jpeg_prepare_row##bpp(VncState *vs, uint8_t *dst, \ - int x, int y, int count) \ + rgb_prepare_row##bpp(VncState *vs, uint8_t *dst, \ + int x, int y, int count) \ { \ VncDisplay *vd = vs->vd; \ uint##bpp##_t *fbptr; \ @@ -1186,21 +1243,26 @@ static void jpeg_prepare_row24(VncState *vs, uint8_t *dst, int x, int y, } \ } -DEFINE_JPEG_GET_ROW_FUNCTION(16) -DEFINE_JPEG_GET_ROW_FUNCTION(32) +DEFINE_RGB_GET_ROW_FUNCTION(16) +DEFINE_RGB_GET_ROW_FUNCTION(32) -static void jpeg_prepare_row(VncState *vs, uint8_t *dst, int x, int y, - int count) +static void rgb_prepare_row(VncState *vs, uint8_t *dst, int x, int y, + int count) { if (vs->tight_pixel24) - jpeg_prepare_row24(vs, dst, x, y, count); + rgb_prepare_row24(vs, dst, x, y, count); else if (ds_get_bytes_per_pixel(vs->ds) == 4) - jpeg_prepare_row32(vs, dst, x, y, count); + rgb_prepare_row32(vs, dst, x, y, count); else - jpeg_prepare_row16(vs, dst, x, y, count); + rgb_prepare_row16(vs, dst, x, y, count); } +#endif /* CONFIG_VNC_JPEG or CONFIG_VNC_PNG */ /* + * JPEG compression stuff. + */ +#ifdef CONFIG_VNC_JPEG +/* * Destination manager implementation for JPEG library. */ @@ -1245,7 +1307,7 @@ static int send_jpeg_rect(VncState *vs, int x, int y, int w, int h, int quality) int dy; if (ds_get_bytes_per_pixel(vs->ds) == 1) - return send_full_color_rect(vs, w, h); + return send_full_color_rect(vs, x, y, w, h); buffer_reserve(&vs->tight_jpeg, 2048); @@ -1271,7 +1333,7 @@ static int send_jpeg_rect(VncState *vs, int x, int y, int w, int h, int quality) buf = qemu_malloc(w * 3); row[0] = buf; for (dy = 0; dy < h; dy++) { - jpeg_prepare_row(vs, buf, x, y + dy, w); + rgb_prepare_row(vs, buf, x, y + dy, w); jpeg_write_scanlines(&cinfo, row, 1); } qemu_free(buf); @@ -1289,6 +1351,162 @@ static int send_jpeg_rect(VncState *vs, int x, int y, int w, int h, int quality) } #endif /* CONFIG_VNC_JPEG */ +/* + * PNG compression stuff. + */ +#ifdef CONFIG_VNC_PNG +static void write_png_palette(const char *key, QObject *obj, void *opaque) +{ + struct palette_cb_priv *priv = opaque; + VncState *vs = priv->vs; + uint32_t bytes = vs->clientds.pf.bytes_per_pixel; + uint8_t idx = qint_get_int(qobject_to_qint(obj)); + png_colorp color = &priv->png_palette[idx]; + uint32_t pix; + + if (bytes == 4) { + pix = tight_palette_buf2rgb(32, (uint8_t *)key); + } else { + pix = tight_palette_buf2rgb(16, (uint8_t *)key); + } + + if (vs->tight_pixel24) + { + color->red = (pix >> vs->clientds.pf.rshift) & vs->clientds.pf.rmax; + color->green = (pix >> vs->clientds.pf.gshift) & vs->clientds.pf.gmax; + color->blue = (pix >> vs->clientds.pf.bshift) & vs->clientds.pf.bmax; + } + else + { + int red, green, blue; + + red = (pix >> vs->clientds.pf.rshift) & vs->clientds.pf.rmax; + green = (pix >> vs->clientds.pf.gshift) & vs->clientds.pf.gmax; + blue = (pix >> vs->clientds.pf.bshift) & vs->clientds.pf.bmax; + color->red = ((red * 255 + vs->clientds.pf.rmax / 2) / + vs->clientds.pf.rmax); + color->green = ((green * 255 + vs->clientds.pf.gmax / 2) / + vs->clientds.pf.gmax); + color->blue = ((blue * 255 + vs->clientds.pf.bmax / 2) / + vs->clientds.pf.bmax); + } +} + +static void png_write_data(png_structp png_ptr, png_bytep data, + png_size_t length) +{ + VncState *vs = png_get_io_ptr(png_ptr); + + buffer_reserve(&vs->tight_png, vs->tight_png.offset + length); + memcpy(vs->tight_png.buffer + vs->tight_png.offset, data, length); + + vs->tight_png.offset += length; +} + +static void png_flush_data(png_structp png_ptr) +{ +} + +static void *vnc_png_malloc(png_structp png_ptr, png_size_t size) +{ + return qemu_malloc(size); +} + +static void vnc_png_free(png_structp png_ptr, png_voidp ptr) +{ + qemu_free(ptr); +} + +static int send_png_rect(VncState *vs, int x, int y, int w, int h, + QDict *palette) +{ + png_byte color_type; + png_structp png_ptr; + png_infop info_ptr; + png_colorp png_palette = NULL; + size_t offset; + int level = tight_conf[vs->tight_compression].raw_zlib_level; + uint8_t *buf; + int dy; + + png_ptr = png_create_write_struct_2(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL, + NULL, vnc_png_malloc, vnc_png_free); + + if (png_ptr == NULL) + return -1; + + info_ptr = png_create_info_struct(png_ptr); + + if (info_ptr == NULL) { + png_destroy_write_struct(&png_ptr, NULL); + return -1; + } + + png_set_write_fn(png_ptr, (void *) vs, png_write_data, png_flush_data); + png_set_compression_level(png_ptr, level); + + if (palette) { + color_type = PNG_COLOR_TYPE_PALETTE; + } else { + color_type = PNG_COLOR_TYPE_RGB; + } + + png_set_IHDR(png_ptr, info_ptr, w, h, + 8, color_type, PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); + + if (color_type == PNG_COLOR_TYPE_PALETTE) { + struct palette_cb_priv priv; + + png_palette = png_malloc(png_ptr, sizeof(*png_palette) * + qdict_size(palette)); + + priv.vs = vs; + priv.png_palette = png_palette; + qdict_iter(palette, write_png_palette, &priv); + + png_set_PLTE(png_ptr, info_ptr, png_palette, qdict_size(palette)); + + offset = vs->tight.offset; + if (vs->clientds.pf.bytes_per_pixel == 4) { + tight_encode_indexed_rect32(vs->tight.buffer, w * h, palette); + } else { + tight_encode_indexed_rect16(vs->tight.buffer, w * h, palette); + } + } + + png_write_info(png_ptr, info_ptr); + + buffer_reserve(&vs->tight_png, 2048); + buf = qemu_malloc(w * 3); + for (dy = 0; dy < h; dy++) + { + if (color_type == PNG_COLOR_TYPE_PALETTE) { + memcpy(buf, vs->tight.buffer + (dy * w), w); + } else { + rgb_prepare_row(vs, buf, x, y + dy, w); + } + png_write_row(png_ptr, buf); + } + qemu_free(buf); + + png_write_end(png_ptr, NULL); + + if (color_type == PNG_COLOR_TYPE_PALETTE) { + png_free(png_ptr, png_palette); + } + + png_destroy_write_struct(&png_ptr, &info_ptr); + + vnc_write_u8(vs, VNC_TIGHT_PNG << 4); + + tight_send_compact_size(vs, vs->tight_png.offset); + vnc_write(vs, vs->tight_png.buffer, vs->tight_png.offset); + buffer_reset(&vs->tight_png); + return 1; +} +#endif /* CONFIG_VNC_PNG */ + static void vnc_tight_start(VncState *vs) { buffer_reset(&vs->tight); @@ -1312,7 +1530,7 @@ static int send_sub_rect(VncState *vs, int x, int y, int w, int h) int colors; int ret = 0; - vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_TIGHT); + vnc_framebuffer_update(vs, x, y, w, h, vs->tight_type); vnc_tight_start(vs); vnc_raw_send_framebuffer_update(vs, x, y, w, h); @@ -1323,23 +1541,23 @@ static int send_sub_rect(VncState *vs, int x, int y, int w, int h) if (colors == 0) { if (tight_detect_smooth_image(vs, w, h)) { if (vs->tight_quality == -1) { - ret = send_gradient_rect(vs, w, h); + ret = send_gradient_rect(vs, x, y, w, h); } else { #ifdef CONFIG_VNC_JPEG int quality = tight_conf[vs->tight_quality].jpeg_quality; ret = send_jpeg_rect(vs, x, y, w, h, quality); #else - ret = send_full_color_rect(vs, w, h); + ret = send_full_color_rect(vs, x, y, w, h); #endif } } else { - ret = send_full_color_rect(vs, w, h); + ret = send_full_color_rect(vs, x, y, w, h); } } else if (colors == 1) { ret = send_solid_rect(vs); } else if (colors == 2) { - ret = send_mono_rect(vs, w, h, bg, fg); + ret = send_mono_rect(vs, x, y, w, h, bg, fg); } else if (colors <= 256) { #ifdef CONFIG_VNC_JPEG if (colors > 96 && vs->tight_quality != -1 && vs->tight_quality <= 3 && @@ -1348,10 +1566,10 @@ static int send_sub_rect(VncState *vs, int x, int y, int w, int h) ret = send_jpeg_rect(vs, x, y, w, h, quality); } else { - ret = send_palette_rect(vs, w, h, palette); + ret = send_palette_rect(vs, x, y, w, h, palette); } #else - ret = send_palette_rect(vs, w, h, palette); + ret = send_palette_rect(vs, x, y, w, h, palette); #endif } QDECREF(palette); @@ -1360,7 +1578,7 @@ static int send_sub_rect(VncState *vs, int x, int y, int w, int h) static int send_sub_rect_solid(VncState *vs, int x, int y, int w, int h) { - vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_TIGHT); + vnc_framebuffer_update(vs, x, y, w, h, vs->tight_type); vnc_tight_start(vs); vnc_raw_send_framebuffer_update(vs, x, y, w, h); @@ -1453,8 +1671,8 @@ static int find_large_solid_color_rect(VncState *vs, int x, int y, n += send_rect_simple(vs, x, y, w, y_best-y); } if (x_best != x) { - n += vnc_tight_send_framebuffer_update(vs, x, y_best, - x_best-x, h_best); + n += tight_send_framebuffer_update(vs, x, y_best, + x_best-x, h_best); } /* Send solid-color rectangle. */ @@ -1463,14 +1681,14 @@ static int find_large_solid_color_rect(VncState *vs, int x, int y, /* Send remaining rectangles (at right and bottom). */ if (x_best + w_best != x + w) { - n += vnc_tight_send_framebuffer_update(vs, x_best+w_best, - y_best, - w-(x_best-x)-w_best, - h_best); + n += tight_send_framebuffer_update(vs, x_best+w_best, + y_best, + w-(x_best-x)-w_best, + h_best); } if (y_best + h_best != y + h) { - n += vnc_tight_send_framebuffer_update(vs, x, y_best+h_best, - w, h-(y_best-y)-h_best); + n += tight_send_framebuffer_update(vs, x, y_best+h_best, + w, h-(y_best-y)-h_best); } /* Return after all recursive calls are done. */ @@ -1480,8 +1698,8 @@ static int find_large_solid_color_rect(VncState *vs, int x, int y, return n + send_rect_simple(vs, x, y, w, h); } -int vnc_tight_send_framebuffer_update(VncState *vs, int x, int y, - int w, int h) +static int tight_send_framebuffer_update(VncState *vs, int x, int y, + int w, int h) { int max_rows; @@ -1503,6 +1721,20 @@ int vnc_tight_send_framebuffer_update(VncState *vs, int x, int y, return find_large_solid_color_rect(vs, x, y, w, h, max_rows); } +int vnc_tight_send_framebuffer_update(VncState *vs, int x, int y, + int w, int h) +{ + vs->tight_type = VNC_ENCODING_TIGHT; + return tight_send_framebuffer_update(vs, x, y, w, h); +} + +int vnc_tight_png_send_framebuffer_update(VncState *vs, int x, int y, + int w, int h) +{ + vs->tight_type = VNC_ENCODING_TIGHT_PNG; + return tight_send_framebuffer_update(vs, x, y, w, h); +} + void vnc_tight_clear(VncState *vs) { int i; diff --git a/ui/vnc-enc-tight.h b/ui/vnc-enc-tight.h index 9b0910c79a..a3add788e2 100644 --- a/ui/vnc-enc-tight.h +++ b/ui/vnc-enc-tight.h @@ -42,8 +42,9 @@ * bit 3: if 1, then compression stream 3 should be reset; * bits 7-4: if 1000 (0x08), then the compression type is "fill", * if 1001 (0x09), then the compression type is "jpeg", + * if 1010 (0x0A), then the compression type is "png", * if 0xxx, then the compression type is "basic", - * values greater than 1001 are not valid. + * values greater than 1010 are not valid. * * If the compression type is "basic", then bits 6..4 of the * compression control byte (those xxx in 0xxx) specify the following: @@ -53,17 +54,17 @@ * bit 6: if 1, then a "filter id" byte is following this byte. * *-- The data that follows after the compression control byte described - * above depends on the compression type ("fill", "jpeg" or "basic"). + * above depends on the compression type ("fill", "jpeg", "png" or "basic"). * *-- If the compression type is "fill", then the only pixel value follows, in * client pixel format (see NOTE 1). This value applies to all pixels of the * rectangle. * - *-- If the compression type is "jpeg", the following data stream looks like - * this: + *-- If the compression type is "jpeg" or "png", the following data stream + * looks like this: * * 1..3 bytes: data size (N) in compact representation; - * N bytes: JPEG image. + * N bytes: JPEG or PNG image. * * Data size is compactly represented in one, two or three bytes, according * to the following scheme: @@ -144,7 +145,7 @@ *-- NOTE 2. The decoder must reset compression streams' states before * decoding the rectangle, if some of bits 0,1,2,3 in the compression control * byte are set to 1. Note that the decoder must reset zlib streams even if - * the compression type is "fill" or "jpeg". + * the compression type is "fill", "jpeg" or "png". * *-- NOTE 3. The "gradient" filter and "jpeg" compression may be used only * when bits-per-pixel value is either 16 or 32, not 8. @@ -158,7 +159,8 @@ #define VNC_TIGHT_EXPLICIT_FILTER 0x04 #define VNC_TIGHT_FILL 0x08 #define VNC_TIGHT_JPEG 0x09 -#define VNC_TIGHT_MAX_SUBENCODING 0x09 +#define VNC_TIGHT_PNG 0x0A +#define VNC_TIGHT_MAX_SUBENCODING 0x0A /* Filters to improve compression efficiency */ #define VNC_TIGHT_FILTER_COPY 0x00 @@ -351,10 +351,6 @@ void do_info_vnc(Monitor *mon, QObject **ret_data) } } -static inline uint32_t vnc_has_feature(VncState *vs, int feature) { - return (vs->features & (1 << feature)); -} - /* TODO 1) Get the queue working for IO. 2) there is some weirdness when using the -S option (the screen is grey @@ -661,6 +657,9 @@ static int send_framebuffer_update(VncState *vs, int x, int y, int w, int h) case VNC_ENCODING_TIGHT: n = vnc_tight_send_framebuffer_update(vs, x, y, w, h); break; + case VNC_ENCODING_TIGHT_PNG: + n = vnc_tight_png_send_framebuffer_update(vs, x, y, w, h); + break; default: vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_RAW); n = vnc_raw_send_framebuffer_update(vs, x, y, w, h); @@ -1669,6 +1668,10 @@ static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings) vs->features |= VNC_FEATURE_TIGHT_MASK; vs->vnc_encoding = enc; break; + case VNC_ENCODING_TIGHT_PNG: + vs->features |= VNC_FEATURE_TIGHT_PNG_MASK; + vs->vnc_encoding = enc; + break; case VNC_ENCODING_ZLIB: vs->features |= VNC_FEATURE_ZLIB_MASK; vs->vnc_encoding = enc; @@ -172,6 +172,7 @@ struct VncState /* Encoding specific */ /* Tight */ + int tight_type; uint8_t tight_quality; uint8_t tight_compression; uint8_t tight_pixel24; @@ -182,6 +183,9 @@ struct VncState #ifdef CONFIG_VNC_JPEG Buffer tight_jpeg; #endif +#ifdef CONFIG_VNC_PNG + Buffer tight_png; +#endif int tight_levels[4]; z_stream tight_stream[4]; @@ -259,6 +263,7 @@ enum { #define VNC_ENCODING_POINTER_TYPE_CHANGE 0XFFFFFEFF /* -257 */ #define VNC_ENCODING_EXT_KEY_EVENT 0XFFFFFEFE /* -258 */ #define VNC_ENCODING_AUDIO 0XFFFFFEFD /* -259 */ +#define VNC_ENCODING_TIGHT_PNG 0xFFFFFEFC /* -260 */ #define VNC_ENCODING_WMVi 0x574D5669 /***************************************************************************** @@ -275,6 +280,7 @@ enum { #define VNC_TIGHT_CCB_TYPE_MASK (0x0f << 4) #define VNC_TIGHT_CCB_TYPE_FILL (0x08 << 4) #define VNC_TIGHT_CCB_TYPE_JPEG (0x09 << 4) +#define VNC_TIGHT_CCB_TYPE_PNG (0x0A << 4) #define VNC_TIGHT_CCB_BASIC_MAX (0x07 << 4) #define VNC_TIGHT_CCB_BASIC_ZLIB (0x03 << 4) #define VNC_TIGHT_CCB_BASIC_FILTER (0x04 << 4) @@ -293,6 +299,7 @@ enum { #define VNC_FEATURE_ZLIB 5 #define VNC_FEATURE_COPYRECT 6 #define VNC_FEATURE_RICH_CURSOR 7 +#define VNC_FEATURE_TIGHT_PNG 8 #define VNC_FEATURE_RESIZE_MASK (1 << VNC_FEATURE_RESIZE) #define VNC_FEATURE_HEXTILE_MASK (1 << VNC_FEATURE_HEXTILE) @@ -302,6 +309,7 @@ enum { #define VNC_FEATURE_ZLIB_MASK (1 << VNC_FEATURE_ZLIB) #define VNC_FEATURE_COPYRECT_MASK (1 << VNC_FEATURE_COPYRECT) #define VNC_FEATURE_RICH_CURSOR_MASK (1 << VNC_FEATURE_RICH_CURSOR) +#define VNC_FEATURE_TIGHT_PNG_MASK (1 << VNC_FEATURE_TIGHT_PNG) /* Client -> Server message IDs */ @@ -405,6 +413,10 @@ void buffer_append(Buffer *buffer, const void *data, size_t len); char *vnc_socket_local_addr(const char *format, int fd); char *vnc_socket_remote_addr(const char *format, int fd); +static inline uint32_t vnc_has_feature(VncState *vs, int feature) { + return (vs->features & (1 << feature)); +} + /* Framebuffer */ void vnc_framebuffer_update(VncState *vs, int x, int y, int w, int h, int32_t encoding); @@ -423,8 +435,9 @@ void vnc_zlib_zfree(void *x, void *addr); int vnc_zlib_send_framebuffer_update(VncState *vs, int x, int y, int w, int h); void vnc_zlib_clear(VncState *vs); - int vnc_tight_send_framebuffer_update(VncState *vs, int x, int y, int w, int h); +int vnc_tight_png_send_framebuffer_update(VncState *vs, int x, int y, + int w, int h); void vnc_tight_clear(VncState *vs); #endif /* __QEMU_VNC_H */ |