4 * Routines to implement Compact Rise-and-Run-length Encoding (CoRRE). This
5 * code is based on krw's original javatel rfbserver.
9 * Copyright (C) 2002 RealVNC Ltd.
10 * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
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.
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.
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,
32 * rreBeforeBuf contains pixel data in the client's format.
33 * rreAfterBuf contains the RRE encoded version. If the RRE encoded version is
34 * larger than the raw data or if it exceeds rreAfterBufSize then
35 * raw encoding is used instead.
38 static int rreBeforeBufSize = 0;
39 static char *rreBeforeBuf = NULL;
41 static int rreAfterBufSize = 0;
42 static char *rreAfterBuf = NULL;
43 static int rreAfterBufLen;
45 static int subrectEncode8(CARD8 *data, int w, int h);
46 static int subrectEncode16(CARD16 *data, int w, int h);
47 static int subrectEncode32(CARD32 *data, int w, int h);
48 static CARD32 getBgColour(char *data, int size, int bpp);
49 static Bool rfbSendSmallRectEncodingCoRRE(rfbClientPtr cl, int x, int y,
54 * rfbSendRectEncodingCoRRE - send an arbitrary size rectangle using CoRRE
59 rfbSendRectEncodingCoRRE(cl, x, y, w, h)
63 if (h > cl->correMaxHeight) {
64 return (rfbSendRectEncodingCoRRE(cl, x, y, w, cl->correMaxHeight) &&
65 rfbSendRectEncodingCoRRE(cl, x, y + cl->correMaxHeight, w,
66 h - cl->correMaxHeight));
69 if (w > cl->correMaxWidth) {
70 return (rfbSendRectEncodingCoRRE(cl, x, y, cl->correMaxWidth, h) &&
71 rfbSendRectEncodingCoRRE(cl, x + cl->correMaxWidth, y,
72 w - cl->correMaxWidth, h));
75 return rfbSendSmallRectEncodingCoRRE(cl, x, y, w, h);
81 * rfbSendSmallRectEncodingCoRRE - send a small (guaranteed < 256x256)
82 * rectangle using CoRRE encoding.
86 rfbSendSmallRectEncodingCoRRE(cl, x, y, w, h)
90 rfbFramebufferUpdateRectHeader rect;
94 char *fbptr = (rfbScreen.pfbMemory + (rfbScreen.paddedWidthInBytes * y)
95 + (x * (rfbScreen.bitsPerPixel / 8)));
97 int maxRawSize = (rfbScreen.width * rfbScreen.height
98 * (cl->format.bitsPerPixel / 8));
100 if (rreBeforeBufSize < maxRawSize) {
101 rreBeforeBufSize = maxRawSize;
102 if (rreBeforeBuf == NULL)
103 rreBeforeBuf = (char *)xalloc(rreBeforeBufSize);
105 rreBeforeBuf = (char *)xrealloc(rreBeforeBuf, rreBeforeBufSize);
108 if (rreAfterBufSize < maxRawSize) {
109 rreAfterBufSize = maxRawSize;
110 if (rreAfterBuf == NULL)
111 rreAfterBuf = (char *)xalloc(rreAfterBufSize);
113 rreAfterBuf = (char *)xrealloc(rreAfterBuf, rreAfterBufSize);
116 (*cl->translateFn)(cl->translateLookupTable, &rfbServerFormat,
117 &cl->format, fbptr, rreBeforeBuf,
118 rfbScreen.paddedWidthInBytes, w, h);
120 switch (cl->format.bitsPerPixel) {
122 nSubrects = subrectEncode8((CARD8 *)rreBeforeBuf, w, h);
125 nSubrects = subrectEncode16((CARD16 *)rreBeforeBuf, w, h);
128 nSubrects = subrectEncode32((CARD32 *)rreBeforeBuf, w, h);
131 rfbLog("getBgColour: bpp %d?\n",cl->format.bitsPerPixel);
137 /* RRE encoding was too large, use raw */
139 return rfbSendRectEncodingRaw(cl, x, y, w, h);
142 cl->rfbRectanglesSent[rfbEncodingCoRRE]++;
143 cl->rfbBytesSent[rfbEncodingCoRRE] += (sz_rfbFramebufferUpdateRectHeader
144 + sz_rfbRREHeader + rreAfterBufLen);
146 if (ublen + sz_rfbFramebufferUpdateRectHeader + sz_rfbRREHeader
149 if (!rfbSendUpdateBuf(cl))
153 rect.r.x = Swap16IfLE(x);
154 rect.r.y = Swap16IfLE(y);
155 rect.r.w = Swap16IfLE(w);
156 rect.r.h = Swap16IfLE(h);
157 rect.encoding = Swap32IfLE(rfbEncodingCoRRE);
159 memcpy(&updateBuf[ublen], (char *)&rect,
160 sz_rfbFramebufferUpdateRectHeader);
161 ublen += sz_rfbFramebufferUpdateRectHeader;
163 hdr.nSubrects = Swap32IfLE(nSubrects);
165 memcpy(&updateBuf[ublen], (char *)&hdr, sz_rfbRREHeader);
166 ublen += sz_rfbRREHeader;
168 for (i = 0; i < rreAfterBufLen;) {
170 int bytesToCopy = UPDATE_BUF_SIZE - ublen;
172 if (i + bytesToCopy > rreAfterBufLen) {
173 bytesToCopy = rreAfterBufLen - i;
176 memcpy(&updateBuf[ublen], &rreAfterBuf[i], bytesToCopy);
178 ublen += bytesToCopy;
181 if (ublen == UPDATE_BUF_SIZE) {
182 if (!rfbSendUpdateBuf(cl))
193 * subrectEncode() encodes the given multicoloured rectangle as a background
194 * colour overwritten by single-coloured rectangles. It returns the number
195 * of subrectangles in the encoded buffer, or -1 if subrect encoding won't
196 * fit in the buffer. It puts the encoded rectangles in rreAfterBuf. The
197 * single-colour rectangle partition is not optimal, but does find the biggest
198 * horizontal or vertical rectangle top-left anchored to each consecutive
199 * coordinate position.
201 * The coding scheme is simply [<bgcolour><subrect><subrect>...] where each
202 * <subrect> is [<colour><x><y><w><h>].
205 #define DEFINE_SUBRECT_ENCODE(bpp) \
207 subrectEncode##bpp(data,w,h) \
213 rfbCoRRERectangle subrect; \
216 int hx=0,hy,vx=0,vy; \
221 int thex,they,thew,theh; \
224 CARD##bpp bg = (CARD##bpp)getBgColour((char*)data,w*h,bpp); \
226 *((CARD##bpp*)rreAfterBuf) = bg; \
228 rreAfterBufLen = (bpp/8); \
230 for (y=0; y<h; y++) { \
232 for (x=0; x<w; x++) { \
233 if (line[x] != bg) { \
237 for (j=y; j<h; j++) { \
239 if (seg[x] != cl) {break;} \
241 while ((seg[i] == cl) && (i < w)) i += 1; \
243 if (j == y) vx = hx = i; \
244 if (i < vx) vx = i; \
245 if ((hyflag > 0) && (i >= hx)) {hy += 1;} else {hyflag = 0;} \
249 /* We now have two possible subrects: (x,y,hx,hy) and (x,y,vx,vy) \
250 * We'll choose the bigger of the two. \
260 if ((hw*hh) > (vw*vh)) { \
273 newLen = rreAfterBufLen + (bpp/8) + sz_rfbCoRRERectangle; \
274 if ((newLen > (w * h * (bpp/8))) || (newLen > rreAfterBufSize)) \
278 *((CARD##bpp*)(rreAfterBuf + rreAfterBufLen)) = cl; \
279 rreAfterBufLen += (bpp/8); \
280 memcpy(&rreAfterBuf[rreAfterBufLen],&subrect,sz_rfbCoRRERectangle); \
281 rreAfterBufLen += sz_rfbCoRRERectangle; \
284 * Now mark the subrect as done. \
286 for (j=they; j < (they+theh); j++) { \
287 for (i=thex; i < (thex+thew); i++) { \
298 DEFINE_SUBRECT_ENCODE(8)
299 DEFINE_SUBRECT_ENCODE(16)
300 DEFINE_SUBRECT_ENCODE(32)
304 * getBgColour() gets the most prevalent colour in a byte array.
307 getBgColour(data,size,bpp)
315 static int counts[NUMCLRS];
323 return ((CARD16 *)data)[0];
324 } else if (bpp == 32) {
325 return ((CARD32 *)data)[0];
327 rfbLog("getBgColour: bpp %d?\n",bpp);
332 for (i=0; i<NUMCLRS; i++) {
336 for (j=0; j<size; j++) {
337 k = (int)(((CARD8 *)data)[j]);
339 rfbLog("getBgColour: unusual colour = %d\n", k);
343 if (counts[k] > maxcount) {
344 maxcount = counts[k];
345 maxclr = ((CARD8 *)data)[j];