1 #define CONCAT_I(a, b) a ## b
2 #define CONCAT(a, b) CONCAT_I(a, b)
3 #define pixel_t CONCAT(uint, CONCAT(BPP, _t))
4 #ifdef GENERIC
5 #define NAME CONCAT(generic_, BPP)
6 #else
7 #define NAME BPP
8 #endif
9 
10 static void CONCAT(send_hextile_tile_, NAME)(VncState *vs,
11                                              int x, int y, int w, int h,
12                                              void *last_bg_,
13                                              void *last_fg_,
14                                              int *has_bg, int *has_fg)
15 {
16     VncDisplay *vd = vs->vd;
17     uint8_t *row = vnc_server_fb_ptr(vd, x, y);
18     pixel_t *irow = (pixel_t *)row;
19     int j, i;
20     pixel_t *last_bg = (pixel_t *)last_bg_;
21     pixel_t *last_fg = (pixel_t *)last_fg_;
22     pixel_t bg = 0;
23     pixel_t fg = 0;
24     int n_colors = 0;
25     int bg_count = 0;
26     int fg_count = 0;
27     int flags = 0;
28     uint8_t data[(vs->client_pf.bytes_per_pixel + 2) * 16 * 16];
29     int n_data = 0;
30     int n_subtiles = 0;
31 
32     for (j = 0; j < h; j++) {
33 	for (i = 0; i < w; i++) {
34 	    switch (n_colors) {
35 	    case 0:
36 		bg = irow[i];
37 		n_colors = 1;
38 		break;
39 	    case 1:
40 		if (irow[i] != bg) {
41 		    fg = irow[i];
42 		    n_colors = 2;
43 		}
44 		break;
45 	    case 2:
46 		if (irow[i] != bg && irow[i] != fg) {
47 		    n_colors = 3;
48 		} else {
49 		    if (irow[i] == bg)
50 			bg_count++;
51 		    else if (irow[i] == fg)
52 			fg_count++;
53 		}
54 		break;
55 	    default:
56 		break;
57 	    }
58 	}
59 	if (n_colors > 2)
60 	    break;
61 	irow += vnc_server_fb_stride(vd) / sizeof(pixel_t);
62     }
63 
64     if (n_colors > 1 && fg_count > bg_count) {
65 	pixel_t tmp = fg;
66 	fg = bg;
67 	bg = tmp;
68     }
69 
70     if (!*has_bg || *last_bg != bg) {
71 	flags |= 0x02;
72 	*has_bg = 1;
73 	*last_bg = bg;
74     }
75 
76     if (n_colors < 3 && (!*has_fg || *last_fg != fg)) {
77 	flags |= 0x04;
78 	*has_fg = 1;
79 	*last_fg = fg;
80     }
81 
82     switch (n_colors) {
83     case 1:
84 	n_data = 0;
85 	break;
86     case 2:
87 	flags |= 0x08;
88 
89 	irow = (pixel_t *)row;
90 
91 	for (j = 0; j < h; j++) {
92 	    int min_x = -1;
93 	    for (i = 0; i < w; i++) {
94 		if (irow[i] == fg) {
95 		    if (min_x == -1)
96 			min_x = i;
97 		} else if (min_x != -1) {
98 		    hextile_enc_cord(data + n_data, min_x, j, i - min_x, 1);
99 		    n_data += 2;
100 		    n_subtiles++;
101 		    min_x = -1;
102 		}
103 	    }
104 	    if (min_x != -1) {
105 		hextile_enc_cord(data + n_data, min_x, j, i - min_x, 1);
106 		n_data += 2;
107 		n_subtiles++;
108 	    }
109 	    irow += vnc_server_fb_stride(vd) / sizeof(pixel_t);
110 	}
111 	break;
112     case 3:
113 	flags |= 0x18;
114 
115 	irow = (pixel_t *)row;
116 
117 	if (!*has_bg || *last_bg != bg)
118 	    flags |= 0x02;
119 
120 	for (j = 0; j < h; j++) {
121 	    int has_color = 0;
122 	    int min_x = -1;
123 	    pixel_t color = 0; /* shut up gcc */
124 
125 	    for (i = 0; i < w; i++) {
126 		if (!has_color) {
127 		    if (irow[i] == bg)
128 			continue;
129 		    color = irow[i];
130 		    min_x = i;
131 		    has_color = 1;
132 		} else if (irow[i] != color) {
133 		    has_color = 0;
134 #ifdef GENERIC
135                     vnc_convert_pixel(vs, data + n_data, color);
136                     n_data += vs->client_pf.bytes_per_pixel;
137 #else
138 		    memcpy(data + n_data, &color, sizeof(color));
139                     n_data += sizeof(pixel_t);
140 #endif
141 		    hextile_enc_cord(data + n_data, min_x, j, i - min_x, 1);
142 		    n_data += 2;
143 		    n_subtiles++;
144 
145 		    min_x = -1;
146 		    if (irow[i] != bg) {
147 			color = irow[i];
148 			min_x = i;
149 			has_color = 1;
150 		    }
151 		}
152 	    }
153 	    if (has_color) {
154 #ifdef GENERIC
155                 vnc_convert_pixel(vs, data + n_data, color);
156                 n_data += vs->client_pf.bytes_per_pixel;
157 #else
158                 memcpy(data + n_data, &color, sizeof(color));
159                 n_data += sizeof(pixel_t);
160 #endif
161 		hextile_enc_cord(data + n_data, min_x, j, i - min_x, 1);
162 		n_data += 2;
163 		n_subtiles++;
164 	    }
165 	    irow += vnc_server_fb_stride(vd) / sizeof(pixel_t);
166 	}
167 
168 	/* A SubrectsColoured subtile invalidates the foreground color */
169 	*has_fg = 0;
170 	if (n_data > (w * h * sizeof(pixel_t))) {
171 	    n_colors = 4;
172 	    flags = 0x01;
173 	    *has_bg = 0;
174 
175 	    /* we really don't have to invalidate either the bg or fg
176 	       but we've lost the old values.  oh well. */
177 	}
178         break;
179     default:
180 	break;
181     }
182 
183     if (n_colors > 3) {
184 	flags = 0x01;
185 	*has_fg = 0;
186 	*has_bg = 0;
187 	n_colors = 4;
188     }
189 
190     vnc_write_u8(vs, flags);
191     if (n_colors < 4) {
192 	if (flags & 0x02)
193 	    vs->write_pixels(vs, last_bg, sizeof(pixel_t));
194 	if (flags & 0x04)
195 	    vs->write_pixels(vs, last_fg, sizeof(pixel_t));
196 	if (n_subtiles) {
197 	    vnc_write_u8(vs, n_subtiles);
198 	    vnc_write(vs, data, n_data);
199 	}
200     } else {
201 	for (j = 0; j < h; j++) {
202 	    vs->write_pixels(vs, row, w * 4);
203 	    row += vnc_server_fb_stride(vd);
204 	}
205     }
206 }
207 
208 #undef NAME
209 #undef pixel_t
210 #undef CONCAT_I
211 #undef CONCAT
212