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
* OSXvnc Copyright (C) 2001 Dan McGuirk <mcguirk@incompleteness.net>.
11
* Original Xvnc code Copyright (C) 1999 AT&T Laboratories Cambridge.
12
* All Rights Reserved.
14
* This is free software; you can redistribute it and/or modify
15
* it under the terms of the GNU General Public License as published by
16
* the Free Software Foundation; either version 2 of the License, or
17
* (at your option) any later version.
19
* This software is distributed in the hope that it will be useful,
20
* but WITHOUT ANY WARRANTY; without even the implied warranty of
21
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22
* GNU General Public License for more details.
24
* You should have received a copy of the GNU General Public License
25
* along with this software; if not, write to the Free Software
26
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
33
* rreBeforeBuf contains pixel data in the client's format.
34
* rreAfterBuf contains the RRE encoded version. If the RRE encoded version is
35
* larger than the raw data or if it exceeds rreAfterBufSize then
36
* raw encoding is used instead.
39
static int rreBeforeBufSize = 0;
40
static char *rreBeforeBuf = NULL;
42
static int rreAfterBufSize = 0;
43
static char *rreAfterBuf = NULL;
44
static int rreAfterBufLen;
46
static int subrectEncode8(uint8_t *data, int w, int h);
47
static int subrectEncode16(uint16_t *data, int w, int h);
48
static int subrectEncode32(uint32_t *data, int w, int h);
49
static uint32_t getBgColour(char *data, int size, int bpp);
50
static rfbBool rfbSendSmallRectEncodingCoRRE(rfbClientPtr cl, int x, int y,
55
* rfbSendRectEncodingCoRRE - send an arbitrary size rectangle using CoRRE
60
rfbSendRectEncodingCoRRE(cl, x, y, w, h)
64
if (h > cl->correMaxHeight) {
65
return (rfbSendRectEncodingCoRRE(cl, x, y, w, cl->correMaxHeight) &&
66
rfbSendRectEncodingCoRRE(cl, x, y + cl->correMaxHeight, w,
67
h - cl->correMaxHeight));
70
if (w > cl->correMaxWidth) {
71
return (rfbSendRectEncodingCoRRE(cl, x, y, cl->correMaxWidth, h) &&
72
rfbSendRectEncodingCoRRE(cl, x + cl->correMaxWidth, y,
73
w - cl->correMaxWidth, h));
76
rfbSendSmallRectEncodingCoRRE(cl, x, y, w, h);
83
* rfbSendSmallRectEncodingCoRRE - send a small (guaranteed < 256x256)
84
* rectangle using CoRRE encoding.
88
rfbSendSmallRectEncodingCoRRE(cl, x, y, w, h)
92
rfbFramebufferUpdateRectHeader rect;
96
char *fbptr = (cl->screen->frameBuffer + (cl->screen->paddedWidthInBytes * y)
97
+ (x * (cl->screen->bitsPerPixel / 8)));
99
int maxRawSize = (cl->screen->width * cl->screen->height
100
* (cl->format.bitsPerPixel / 8));
102
if (rreBeforeBufSize < maxRawSize) {
103
rreBeforeBufSize = maxRawSize;
104
if (rreBeforeBuf == NULL)
105
rreBeforeBuf = (char *)malloc(rreBeforeBufSize);
107
rreBeforeBuf = (char *)realloc(rreBeforeBuf, rreBeforeBufSize);
110
if (rreAfterBufSize < maxRawSize) {
111
rreAfterBufSize = maxRawSize;
112
if (rreAfterBuf == NULL)
113
rreAfterBuf = (char *)malloc(rreAfterBufSize);
115
rreAfterBuf = (char *)realloc(rreAfterBuf, rreAfterBufSize);
118
(*cl->translateFn)(cl->translateLookupTable,&(cl->screen->rfbServerFormat),
119
&cl->format, fbptr, rreBeforeBuf,
120
cl->screen->paddedWidthInBytes, w, h);
122
switch (cl->format.bitsPerPixel) {
124
nSubrects = subrectEncode8((uint8_t *)rreBeforeBuf, w, h);
127
nSubrects = subrectEncode16((uint16_t *)rreBeforeBuf, w, h);
130
nSubrects = subrectEncode32((uint32_t *)rreBeforeBuf, w, h);
133
rfbLog("getBgColour: bpp %d?\n",cl->format.bitsPerPixel);
139
/* RRE encoding was too large, use raw */
141
return rfbSendRectEncodingRaw(cl, x, y, w, h);
144
cl->rfbRectanglesSent[rfbEncodingCoRRE]++;
145
cl->rfbBytesSent[rfbEncodingCoRRE] += (sz_rfbFramebufferUpdateRectHeader
146
+ sz_rfbRREHeader + rreAfterBufLen);
148
if (cl->ublen + sz_rfbFramebufferUpdateRectHeader + sz_rfbRREHeader
151
if (!rfbSendUpdateBuf(cl))
155
rect.r.x = Swap16IfLE(x);
156
rect.r.y = Swap16IfLE(y);
157
rect.r.w = Swap16IfLE(w);
158
rect.r.h = Swap16IfLE(h);
159
rect.encoding = Swap32IfLE(rfbEncodingCoRRE);
161
memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,
162
sz_rfbFramebufferUpdateRectHeader);
163
cl->ublen += sz_rfbFramebufferUpdateRectHeader;
165
hdr.nSubrects = Swap32IfLE(nSubrects);
167
memcpy(&cl->updateBuf[cl->ublen], (char *)&hdr, sz_rfbRREHeader);
168
cl->ublen += sz_rfbRREHeader;
170
for (i = 0; i < rreAfterBufLen;) {
172
int bytesToCopy = UPDATE_BUF_SIZE - cl->ublen;
174
if (i + bytesToCopy > rreAfterBufLen) {
175
bytesToCopy = rreAfterBufLen - i;
178
memcpy(&cl->updateBuf[cl->ublen], &rreAfterBuf[i], bytesToCopy);
180
cl->ublen += bytesToCopy;
183
if (cl->ublen == UPDATE_BUF_SIZE) {
184
if (!rfbSendUpdateBuf(cl))
195
* subrectEncode() encodes the given multicoloured rectangle as a background
196
* colour overwritten by single-coloured rectangles. It returns the number
197
* of subrectangles in the encoded buffer, or -1 if subrect encoding won't
198
* fit in the buffer. It puts the encoded rectangles in rreAfterBuf. The
199
* single-colour rectangle partition is not optimal, but does find the biggest
200
* horizontal or vertical rectangle top-left anchored to each consecutive
201
* coordinate position.
203
* The coding scheme is simply [<bgcolour><subrect><subrect>...] where each
204
* <subrect> is [<colour><x><y><w><h>].
207
#define DEFINE_SUBRECT_ENCODE(bpp) \
209
subrectEncode##bpp(data,w,h) \
210
uint##bpp##_t *data; \
215
rfbCoRRERectangle subrect; \
218
int hx=0,hy,vx=0,vy; \
220
uint##bpp##_t *seg; \
221
uint##bpp##_t *line; \
223
int thex,they,thew,theh; \
226
uint##bpp##_t bg = (uint##bpp##_t)getBgColour((char*)data,w*h,bpp); \
228
*((uint##bpp##_t*)rreAfterBuf) = bg; \
230
rreAfterBufLen = (bpp/8); \
232
for (y=0; y<h; y++) { \
234
for (x=0; x<w; x++) { \
235
if (line[x] != bg) { \
239
for (j=y; j<h; j++) { \
241
if (seg[x] != cl) {break;} \
243
while ((seg[i] == cl) && (i < w)) i += 1; \
245
if (j == y) vx = hx = i; \
246
if (i < vx) vx = i; \
247
if ((hyflag > 0) && (i >= hx)) {hy += 1;} else {hyflag = 0;} \
251
/* We now have two possible subrects: (x,y,hx,hy) and (x,y,vx,vy) \
252
* We'll choose the bigger of the two. \
262
if ((hw*hh) > (vw*vh)) { \
275
newLen = rreAfterBufLen + (bpp/8) + sz_rfbCoRRERectangle; \
276
if ((newLen > (w * h * (bpp/8))) || (newLen > rreAfterBufSize)) \
280
*((uint##bpp##_t*)(rreAfterBuf + rreAfterBufLen)) = cl; \
281
rreAfterBufLen += (bpp/8); \
282
memcpy(&rreAfterBuf[rreAfterBufLen],&subrect,sz_rfbCoRRERectangle); \
283
rreAfterBufLen += sz_rfbCoRRERectangle; \
286
* Now mark the subrect as done. \
288
for (j=they; j < (they+theh); j++) { \
289
for (i=thex; i < (thex+thew); i++) { \
300
DEFINE_SUBRECT_ENCODE(8)
301
DEFINE_SUBRECT_ENCODE(16)
302
DEFINE_SUBRECT_ENCODE(32)
306
* getBgColour() gets the most prevalent colour in a byte array.
309
getBgColour(data,size,bpp)
317
static int counts[NUMCLRS];
325
return ((uint16_t *)data)[0];
326
} else if (bpp == 32) {
327
return ((uint32_t *)data)[0];
329
rfbLog("getBgColour: bpp %d?\n",bpp);
334
for (i=0; i<NUMCLRS; i++) {
338
for (j=0; j<size; j++) {
339
k = (int)(((uint8_t *)data)[j]);
341
rfbLog("getBgColour: unusual colour = %d\n", k);
345
if (counts[k] > maxcount) {
346
maxcount = counts[k];
347
maxclr = ((uint8_t *)data)[j];