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