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