LibVNCServer/LibVNCClient
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
hextile.c
Go to the documentation of this file.
1 /*
2  * hextile.c
3  *
4  * Routines to implement Hextile Encoding
5  */
6 
7 /*
8  * OSXvnc Copyright (C) 2001 Dan McGuirk <mcguirk@incompleteness.net>.
9  * Original Xvnc code Copyright (C) 1999 AT&T Laboratories Cambridge.
10  * All Rights Reserved.
11  *
12  * This is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 2 of the License, or
15  * (at your option) any later version.
16  *
17  * This software is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this software; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
25  * USA.
26  */
27 
28 #include <rfb/rfb.h>
29 
30 static rfbBool sendHextiles8(rfbClientPtr cl, int x, int y, int w, int h);
31 static rfbBool sendHextiles16(rfbClientPtr cl, int x, int y, int w, int h);
32 static rfbBool sendHextiles32(rfbClientPtr cl, int x, int y, int w, int h);
33 
34 
35 /*
36  * rfbSendRectEncodingHextile - send a rectangle using hextile encoding.
37  */
38 
39 rfbBool
41  int x,
42  int y,
43  int w,
44  int h)
45 {
47 
49  if (!rfbSendUpdateBuf(cl))
50  return FALSE;
51  }
52 
53  rect.r.x = Swap16IfLE(x);
54  rect.r.y = Swap16IfLE(y);
55  rect.r.w = Swap16IfLE(w);
56  rect.r.h = Swap16IfLE(h);
58 
59  memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,
62 
65  sz_rfbFramebufferUpdateRectHeader + w * (cl->format.bitsPerPixel / 8) * h);
66 
67  switch (cl->format.bitsPerPixel) {
68  case 8:
69  return sendHextiles8(cl, x, y, w, h);
70  case 16:
71  return sendHextiles16(cl, x, y, w, h);
72  case 32:
73  return sendHextiles32(cl, x, y, w, h);
74  }
75 
76  rfbLog("rfbSendRectEncodingHextile: bpp %d?\n", cl->format.bitsPerPixel);
77  return FALSE;
78 }
79 
80 
81 #define PUT_PIXEL8(pix) (cl->updateBuf[cl->ublen++] = (pix))
82 
83 #define PUT_PIXEL16(pix) (cl->updateBuf[cl->ublen++] = ((char*)&(pix))[0], \
84  cl->updateBuf[cl->ublen++] = ((char*)&(pix))[1])
85 
86 #define PUT_PIXEL32(pix) (cl->updateBuf[cl->ublen++] = ((char*)&(pix))[0], \
87  cl->updateBuf[cl->ublen++] = ((char*)&(pix))[1], \
88  cl->updateBuf[cl->ublen++] = ((char*)&(pix))[2], \
89  cl->updateBuf[cl->ublen++] = ((char*)&(pix))[3])
90 
91 
92 #define DEFINE_SEND_HEXTILES(bpp) \
93  \
94  \
95 static rfbBool subrectEncode##bpp(rfbClientPtr cli, uint##bpp##_t *data, \
96  int w, int h, uint##bpp##_t bg, uint##bpp##_t fg, rfbBool mono);\
97 static void testColours##bpp(uint##bpp##_t *data, int size, rfbBool *mono, \
98  rfbBool *solid, uint##bpp##_t *bg, uint##bpp##_t *fg); \
99  \
100  \
101 /* \
102  * rfbSendHextiles \
103  */ \
104  \
105 static rfbBool \
106 sendHextiles##bpp(rfbClientPtr cl, int rx, int ry, int rw, int rh) { \
107  int x, y, w, h; \
108  int startUblen; \
109  char *fbptr; \
110  uint##bpp##_t bg = 0, fg = 0, newBg, newFg; \
111  rfbBool mono, solid; \
112  rfbBool validBg = FALSE; \
113  rfbBool validFg = FALSE; \
114  uint##bpp##_t clientPixelData[16*16*(bpp/8)]; \
115  \
116  for (y = ry; y < ry+rh; y += 16) { \
117  for (x = rx; x < rx+rw; x += 16) { \
118  w = h = 16; \
119  if (rx+rw - x < 16) \
120  w = rx+rw - x; \
121  if (ry+rh - y < 16) \
122  h = ry+rh - y; \
123  \
124  if ((cl->ublen + 1 + (2 + 16 * 16) * (bpp/8)) > \
125  UPDATE_BUF_SIZE) { \
126  if (!rfbSendUpdateBuf(cl)) \
127  return FALSE; \
128  } \
129  \
130  fbptr = (cl->scaledScreen->frameBuffer + (cl->scaledScreen->paddedWidthInBytes * y) \
131  + (x * (cl->scaledScreen->bitsPerPixel / 8))); \
132  \
133  (*cl->translateFn)(cl->translateLookupTable, &(cl->screen->serverFormat), \
134  &cl->format, fbptr, (char *)clientPixelData, \
135  cl->scaledScreen->paddedWidthInBytes, w, h); \
136  \
137  startUblen = cl->ublen; \
138  cl->updateBuf[startUblen] = 0; \
139  cl->ublen++; \
140  rfbStatRecordEncodingSentAdd(cl, rfbEncodingHextile, 1); \
141  \
142  testColours##bpp(clientPixelData, w * h, \
143  &mono, &solid, &newBg, &newFg); \
144  \
145  if (!validBg || (newBg != bg)) { \
146  validBg = TRUE; \
147  bg = newBg; \
148  cl->updateBuf[startUblen] |= rfbHextileBackgroundSpecified; \
149  PUT_PIXEL##bpp(bg); \
150  } \
151  \
152  if (solid) { \
153  continue; \
154  } \
155  \
156  cl->updateBuf[startUblen] |= rfbHextileAnySubrects; \
157  \
158  if (mono) { \
159  if (!validFg || (newFg != fg)) { \
160  validFg = TRUE; \
161  fg = newFg; \
162  cl->updateBuf[startUblen] |= rfbHextileForegroundSpecified; \
163  PUT_PIXEL##bpp(fg); \
164  } \
165  } else { \
166  validFg = FALSE; \
167  cl->updateBuf[startUblen] |= rfbHextileSubrectsColoured; \
168  } \
169  \
170  if (!subrectEncode##bpp(cl, clientPixelData, w, h, bg, fg, mono)) { \
171  /* encoding was too large, use raw */ \
172  validBg = FALSE; \
173  validFg = FALSE; \
174  cl->ublen = startUblen; \
175  cl->updateBuf[cl->ublen++] = rfbHextileRaw; \
176  (*cl->translateFn)(cl->translateLookupTable, \
177  &(cl->screen->serverFormat), &cl->format, fbptr, \
178  (char *)clientPixelData, \
179  cl->scaledScreen->paddedWidthInBytes, w, h); \
180  \
181  memcpy(&cl->updateBuf[cl->ublen], (char *)clientPixelData, \
182  w * h * (bpp/8)); \
183  \
184  cl->ublen += w * h * (bpp/8); \
185  rfbStatRecordEncodingSentAdd(cl, rfbEncodingHextile, \
186  w * h * (bpp/8)); \
187  } \
188  } \
189  } \
190  \
191  return TRUE; \
192 } \
193  \
194  \
195 static rfbBool \
196 subrectEncode##bpp(rfbClientPtr cl, uint##bpp##_t *data, int w, int h, \
197  uint##bpp##_t bg, uint##bpp##_t fg, rfbBool mono) \
198 { \
199  uint##bpp##_t cl2; \
200  int x,y; \
201  int i,j; \
202  int hx=0,hy,vx=0,vy; \
203  int hyflag; \
204  uint##bpp##_t *seg; \
205  uint##bpp##_t *line; \
206  int hw,hh,vw,vh; \
207  int thex,they,thew,theh; \
208  int numsubs = 0; \
209  int newLen; \
210  int nSubrectsUblen; \
211  \
212  nSubrectsUblen = cl->ublen; \
213  cl->ublen++; \
214  rfbStatRecordEncodingSentAdd(cl, rfbEncodingHextile, 1); \
215  \
216  for (y=0; y<h; y++) { \
217  line = data+(y*w); \
218  for (x=0; x<w; x++) { \
219  if (line[x] != bg) { \
220  cl2 = line[x]; \
221  hy = y-1; \
222  hyflag = 1; \
223  for (j=y; j<h; j++) { \
224  seg = data+(j*w); \
225  if (seg[x] != cl2) {break;} \
226  i = x; \
227  while ((seg[i] == cl2) && (i < w)) i += 1; \
228  i -= 1; \
229  if (j == y) vx = hx = i; \
230  if (i < vx) vx = i; \
231  if ((hyflag > 0) && (i >= hx)) { \
232  hy += 1; \
233  } else { \
234  hyflag = 0; \
235  } \
236  } \
237  vy = j-1; \
238  \
239  /* We now have two possible subrects: (x,y,hx,hy) and \
240  * (x,y,vx,vy). We'll choose the bigger of the two. \
241  */ \
242  hw = hx-x+1; \
243  hh = hy-y+1; \
244  vw = vx-x+1; \
245  vh = vy-y+1; \
246  \
247  thex = x; \
248  they = y; \
249  \
250  if ((hw*hh) > (vw*vh)) { \
251  thew = hw; \
252  theh = hh; \
253  } else { \
254  thew = vw; \
255  theh = vh; \
256  } \
257  \
258  if (mono) { \
259  newLen = cl->ublen - nSubrectsUblen + 2; \
260  } else { \
261  newLen = cl->ublen - nSubrectsUblen + bpp/8 + 2; \
262  } \
263  \
264  if (newLen > (w * h * (bpp/8))) \
265  return FALSE; \
266  \
267  numsubs += 1; \
268  \
269  if (!mono) PUT_PIXEL##bpp(cl2); \
270  \
271  cl->updateBuf[cl->ublen++] = rfbHextilePackXY(thex,they); \
272  cl->updateBuf[cl->ublen++] = rfbHextilePackWH(thew,theh); \
273  rfbStatRecordEncodingSentAdd(cl, rfbEncodingHextile, 1); \
274  \
275  /* \
276  * Now mark the subrect as done. \
277  */ \
278  for (j=they; j < (they+theh); j++) { \
279  for (i=thex; i < (thex+thew); i++) { \
280  data[j*w+i] = bg; \
281  } \
282  } \
283  } \
284  } \
285  } \
286  \
287  cl->updateBuf[nSubrectsUblen] = numsubs; \
288  \
289  return TRUE; \
290 } \
291  \
292  \
293 /* \
294  * testColours() tests if there are one (solid), two (mono) or more \
295  * colours in a tile and gets a reasonable guess at the best background \
296  * pixel, and the foreground pixel for mono. \
297  */ \
298  \
299 static void \
300 testColours##bpp(uint##bpp##_t *data, int size, rfbBool *mono, rfbBool *solid, \
301  uint##bpp##_t *bg, uint##bpp##_t *fg) { \
302  uint##bpp##_t colour1 = 0, colour2 = 0; \
303  int n1 = 0, n2 = 0; \
304  *mono = TRUE; \
305  *solid = TRUE; \
306  \
307  for (; size > 0; size--, data++) { \
308  \
309  if (n1 == 0) \
310  colour1 = *data; \
311  \
312  if (*data == colour1) { \
313  n1++; \
314  continue; \
315  } \
316  \
317  if (n2 == 0) { \
318  *solid = FALSE; \
319  colour2 = *data; \
320  } \
321  \
322  if (*data == colour2) { \
323  n2++; \
324  continue; \
325  } \
326  \
327  *mono = FALSE; \
328  break; \
329  } \
330  \
331  if (n1 > n2) { \
332  *bg = colour1; \
333  *fg = colour2; \
334  } else { \
335  *bg = colour2; \
336  *fg = colour1; \
337  } \
338 }
339