|  | #define CONCAT_I(a, b) a ## b | 
|  | #define CONCAT(a, b) CONCAT_I(a, b) | 
|  | #define pixel_t CONCAT(uint, CONCAT(BPP, _t)) | 
|  | #ifdef GENERIC | 
|  | #define NAME CONCAT(generic_, BPP) | 
|  | #else | 
|  | #define NAME BPP | 
|  | #endif | 
|  |  | 
|  | static void CONCAT(send_hextile_tile_, NAME)(VncState *vs, | 
|  | int x, int y, int w, int h, | 
|  | void *last_bg_, | 
|  | void *last_fg_, | 
|  | int *has_bg, int *has_fg) | 
|  | { | 
|  | VncDisplay *vd = vs->vd; | 
|  | uint8_t *row = vnc_server_fb_ptr(vd, x, y); | 
|  | pixel_t *irow = (pixel_t *)row; | 
|  | int j, i; | 
|  | pixel_t *last_bg = (pixel_t *)last_bg_; | 
|  | pixel_t *last_fg = (pixel_t *)last_fg_; | 
|  | pixel_t bg = 0; | 
|  | pixel_t fg = 0; | 
|  | int n_colors = 0; | 
|  | int bg_count = 0; | 
|  | int fg_count = 0; | 
|  | int flags = 0; | 
|  | uint8_t data[(vs->client_pf.bytes_per_pixel + 2) * 16 * 16]; | 
|  | int n_data = 0; | 
|  | int n_subtiles = 0; | 
|  |  | 
|  | for (j = 0; j < h; j++) { | 
|  | for (i = 0; i < w; i++) { | 
|  | switch (n_colors) { | 
|  | case 0: | 
|  | bg = irow[i]; | 
|  | n_colors = 1; | 
|  | break; | 
|  | case 1: | 
|  | if (irow[i] != bg) { | 
|  | fg = irow[i]; | 
|  | n_colors = 2; | 
|  | } | 
|  | break; | 
|  | case 2: | 
|  | if (irow[i] != bg && irow[i] != fg) { | 
|  | n_colors = 3; | 
|  | } else { | 
|  | if (irow[i] == bg) | 
|  | bg_count++; | 
|  | else if (irow[i] == fg) | 
|  | fg_count++; | 
|  | } | 
|  | break; | 
|  | default: | 
|  | break; | 
|  | } | 
|  | } | 
|  | if (n_colors > 2) | 
|  | break; | 
|  | irow += vnc_server_fb_stride(vd) / sizeof(pixel_t); | 
|  | } | 
|  |  | 
|  | if (n_colors > 1 && fg_count > bg_count) { | 
|  | pixel_t tmp = fg; | 
|  | fg = bg; | 
|  | bg = tmp; | 
|  | } | 
|  |  | 
|  | if (!*has_bg || *last_bg != bg) { | 
|  | flags |= 0x02; | 
|  | *has_bg = 1; | 
|  | *last_bg = bg; | 
|  | } | 
|  |  | 
|  | if (n_colors < 3 && (!*has_fg || *last_fg != fg)) { | 
|  | flags |= 0x04; | 
|  | *has_fg = 1; | 
|  | *last_fg = fg; | 
|  | } | 
|  |  | 
|  | switch (n_colors) { | 
|  | case 1: | 
|  | n_data = 0; | 
|  | break; | 
|  | case 2: | 
|  | flags |= 0x08; | 
|  |  | 
|  | irow = (pixel_t *)row; | 
|  |  | 
|  | for (j = 0; j < h; j++) { | 
|  | int min_x = -1; | 
|  | for (i = 0; i < w; i++) { | 
|  | if (irow[i] == fg) { | 
|  | if (min_x == -1) | 
|  | min_x = i; | 
|  | } else if (min_x != -1) { | 
|  | hextile_enc_cord(data + n_data, min_x, j, i - min_x, 1); | 
|  | n_data += 2; | 
|  | n_subtiles++; | 
|  | min_x = -1; | 
|  | } | 
|  | } | 
|  | if (min_x != -1) { | 
|  | hextile_enc_cord(data + n_data, min_x, j, i - min_x, 1); | 
|  | n_data += 2; | 
|  | n_subtiles++; | 
|  | } | 
|  | irow += vnc_server_fb_stride(vd) / sizeof(pixel_t); | 
|  | } | 
|  | break; | 
|  | case 3: | 
|  | flags |= 0x18; | 
|  |  | 
|  | irow = (pixel_t *)row; | 
|  |  | 
|  | if (!*has_bg || *last_bg != bg) | 
|  | flags |= 0x02; | 
|  |  | 
|  | for (j = 0; j < h; j++) { | 
|  | int has_color = 0; | 
|  | int min_x = -1; | 
|  | pixel_t color = 0; /* shut up gcc */ | 
|  |  | 
|  | for (i = 0; i < w; i++) { | 
|  | if (!has_color) { | 
|  | if (irow[i] == bg) | 
|  | continue; | 
|  | color = irow[i]; | 
|  | min_x = i; | 
|  | has_color = 1; | 
|  | } else if (irow[i] != color) { | 
|  | has_color = 0; | 
|  | #ifdef GENERIC | 
|  | vnc_convert_pixel(vs, data + n_data, color); | 
|  | n_data += vs->client_pf.bytes_per_pixel; | 
|  | #else | 
|  | memcpy(data + n_data, &color, sizeof(color)); | 
|  | n_data += sizeof(pixel_t); | 
|  | #endif | 
|  | hextile_enc_cord(data + n_data, min_x, j, i - min_x, 1); | 
|  | n_data += 2; | 
|  | n_subtiles++; | 
|  |  | 
|  | min_x = -1; | 
|  | if (irow[i] != bg) { | 
|  | color = irow[i]; | 
|  | min_x = i; | 
|  | has_color = 1; | 
|  | } | 
|  | } | 
|  | } | 
|  | if (has_color) { | 
|  | #ifdef GENERIC | 
|  | vnc_convert_pixel(vs, data + n_data, color); | 
|  | n_data += vs->client_pf.bytes_per_pixel; | 
|  | #else | 
|  | memcpy(data + n_data, &color, sizeof(color)); | 
|  | n_data += sizeof(pixel_t); | 
|  | #endif | 
|  | hextile_enc_cord(data + n_data, min_x, j, i - min_x, 1); | 
|  | n_data += 2; | 
|  | n_subtiles++; | 
|  | } | 
|  | irow += vnc_server_fb_stride(vd) / sizeof(pixel_t); | 
|  | } | 
|  |  | 
|  | /* A SubrectsColoured subtile invalidates the foreground color */ | 
|  | *has_fg = 0; | 
|  | if (n_data > (w * h * sizeof(pixel_t))) { | 
|  | n_colors = 4; | 
|  | flags = 0x01; | 
|  | *has_bg = 0; | 
|  |  | 
|  | /* we really don't have to invalidate either the bg or fg | 
|  | but we've lost the old values.  oh well. */ | 
|  | } | 
|  | break; | 
|  | default: | 
|  | break; | 
|  | } | 
|  |  | 
|  | if (n_colors > 3) { | 
|  | flags = 0x01; | 
|  | *has_fg = 0; | 
|  | *has_bg = 0; | 
|  | n_colors = 4; | 
|  | } | 
|  |  | 
|  | vnc_write_u8(vs, flags); | 
|  | if (n_colors < 4) { | 
|  | if (flags & 0x02) | 
|  | vs->write_pixels(vs, last_bg, sizeof(pixel_t)); | 
|  | if (flags & 0x04) | 
|  | vs->write_pixels(vs, last_fg, sizeof(pixel_t)); | 
|  | if (n_subtiles) { | 
|  | vnc_write_u8(vs, n_subtiles); | 
|  | vnc_write(vs, data, n_data); | 
|  | } | 
|  | } else { | 
|  | for (j = 0; j < h; j++) { | 
|  | vs->write_pixels(vs, row, w * 4); | 
|  | row += vnc_server_fb_stride(vd); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | #undef NAME | 
|  | #undef pixel_t | 
|  | #undef CONCAT_I | 
|  | #undef CONCAT |