4
* Routines to implement Rise-and-Run-length Encoding (RRE). This
5
* code is based on krw's original javatel rfbserver.
9
* OSXvnc Copyright (C) 2001 Dan McGuirk <mcguirk@incompleteness.net>.
10
* Original Xvnc code Copyright (C) 1999 AT&T Laboratories Cambridge.
11
* All Rights Reserved.
13
* This is free software; you can redistribute it and/or modify
14
* it under the terms of the GNU General Public License as published by
15
* the Free Software Foundation; either version 2 of the License, or
16
* (at your option) any later version.
18
* This software is distributed in the hope that it will be useful,
19
* but WITHOUT ANY WARRANTY; without even the implied warranty of
20
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21
* GNU General Public License for more details.
23
* You should have received a copy of the GNU General Public License
24
* along with this software; if not, write to the Free Software
25
* 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(uint8_t *data, int w, int h);
46
static int subrectEncode16(uint16_t *data, int w, int h);
47
static int subrectEncode32(uint32_t *data, int w, int h);
48
static uint32_t getBgColour(char *data, int size, int bpp);
52
* rfbSendRectEncodingRRE - send a given rectangle using RRE encoding.
56
rfbSendRectEncodingRRE(cl, x, y, w, h)
60
rfbFramebufferUpdateRectHeader rect;
64
char *fbptr = (cl->screen->frameBuffer + (cl->screen->paddedWidthInBytes * y)
65
+ (x * (cl->screen->bitsPerPixel / 8)));
67
int maxRawSize = (cl->screen->width * cl->screen->height
68
* (cl->format.bitsPerPixel / 8));
70
if (rreBeforeBufSize < maxRawSize) {
71
rreBeforeBufSize = maxRawSize;
72
if (rreBeforeBuf == NULL)
73
rreBeforeBuf = (char *)malloc(rreBeforeBufSize);
75
rreBeforeBuf = (char *)realloc(rreBeforeBuf, rreBeforeBufSize);
78
if (rreAfterBufSize < maxRawSize) {
79
rreAfterBufSize = maxRawSize;
80
if (rreAfterBuf == NULL)
81
rreAfterBuf = (char *)malloc(rreAfterBufSize);
83
rreAfterBuf = (char *)realloc(rreAfterBuf, rreAfterBufSize);
86
(*cl->translateFn)(cl->translateLookupTable,
87
&(cl->screen->rfbServerFormat),
88
&cl->format, fbptr, rreBeforeBuf,
89
cl->screen->paddedWidthInBytes, w, h);
91
switch (cl->format.bitsPerPixel) {
93
nSubrects = subrectEncode8((uint8_t *)rreBeforeBuf, w, h);
96
nSubrects = subrectEncode16((uint16_t *)rreBeforeBuf, w, h);
99
nSubrects = subrectEncode32((uint32_t *)rreBeforeBuf, w, h);
102
rfbLog("getBgColour: bpp %d?\n",cl->format.bitsPerPixel);
108
/* RRE encoding was too large, use raw */
110
return rfbSendRectEncodingRaw(cl, x, y, w, h);
113
cl->rfbRectanglesSent[rfbEncodingRRE]++;
114
cl->rfbBytesSent[rfbEncodingRRE] += (sz_rfbFramebufferUpdateRectHeader
115
+ sz_rfbRREHeader + rreAfterBufLen);
117
if (cl->ublen + sz_rfbFramebufferUpdateRectHeader + sz_rfbRREHeader
120
if (!rfbSendUpdateBuf(cl))
124
rect.r.x = Swap16IfLE(x);
125
rect.r.y = Swap16IfLE(y);
126
rect.r.w = Swap16IfLE(w);
127
rect.r.h = Swap16IfLE(h);
128
rect.encoding = Swap32IfLE(rfbEncodingRRE);
130
memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,
131
sz_rfbFramebufferUpdateRectHeader);
132
cl->ublen += sz_rfbFramebufferUpdateRectHeader;
134
hdr.nSubrects = Swap32IfLE(nSubrects);
136
memcpy(&cl->updateBuf[cl->ublen], (char *)&hdr, sz_rfbRREHeader);
137
cl->ublen += sz_rfbRREHeader;
139
for (i = 0; i < rreAfterBufLen;) {
141
int bytesToCopy = UPDATE_BUF_SIZE - cl->ublen;
143
if (i + bytesToCopy > rreAfterBufLen) {
144
bytesToCopy = rreAfterBufLen - i;
147
memcpy(&cl->updateBuf[cl->ublen], &rreAfterBuf[i], bytesToCopy);
149
cl->ublen += bytesToCopy;
152
if (cl->ublen == UPDATE_BUF_SIZE) {
153
if (!rfbSendUpdateBuf(cl))
164
* subrectEncode() encodes the given multicoloured rectangle as a background
165
* colour overwritten by single-coloured rectangles. It returns the number
166
* of subrectangles in the encoded buffer, or -1 if subrect encoding won't
167
* fit in the buffer. It puts the encoded rectangles in rreAfterBuf. The
168
* single-colour rectangle partition is not optimal, but does find the biggest
169
* horizontal or vertical rectangle top-left anchored to each consecutive
170
* coordinate position.
172
* The coding scheme is simply [<bgcolour><subrect><subrect>...] where each
173
* <subrect> is [<colour><x><y><w><h>].
176
#define DEFINE_SUBRECT_ENCODE(bpp) \
178
subrectEncode##bpp(data,w,h) \
179
uint##bpp##_t *data; \
184
rfbRectangle subrect; \
187
int hx=0,hy,vx=0,vy; \
189
uint##bpp##_t *seg; \
190
uint##bpp##_t *line; \
192
int thex,they,thew,theh; \
195
uint##bpp##_t bg = (uint##bpp##_t)getBgColour((char*)data,w*h,bpp); \
197
*((uint##bpp##_t*)rreAfterBuf) = bg; \
199
rreAfterBufLen = (bpp/8); \
201
for (y=0; y<h; y++) { \
203
for (x=0; x<w; x++) { \
204
if (line[x] != bg) { \
208
for (j=y; j<h; j++) { \
210
if (seg[x] != cl) {break;} \
212
while ((seg[i] == cl) && (i < w)) i += 1; \
214
if (j == y) vx = hx = i; \
215
if (i < vx) vx = i; \
216
if ((hyflag > 0) && (i >= hx)) {hy += 1;} else {hyflag = 0;} \
220
/* We now have two possible subrects: (x,y,hx,hy) and (x,y,vx,vy) \
221
* We'll choose the bigger of the two. \
231
if ((hw*hh) > (vw*vh)) { \
239
subrect.x = Swap16IfLE(thex); \
240
subrect.y = Swap16IfLE(they); \
241
subrect.w = Swap16IfLE(thew); \
242
subrect.h = Swap16IfLE(theh); \
244
newLen = rreAfterBufLen + (bpp/8) + sz_rfbRectangle; \
245
if ((newLen > (w * h * (bpp/8))) || (newLen > rreAfterBufSize)) \
249
*((uint##bpp##_t*)(rreAfterBuf + rreAfterBufLen)) = cl; \
250
rreAfterBufLen += (bpp/8); \
251
memcpy(&rreAfterBuf[rreAfterBufLen],&subrect,sz_rfbRectangle); \
252
rreAfterBufLen += sz_rfbRectangle; \
255
* Now mark the subrect as done. \
257
for (j=they; j < (they+theh); j++) { \
258
for (i=thex; i < (thex+thew); i++) { \
269
DEFINE_SUBRECT_ENCODE(8)
270
DEFINE_SUBRECT_ENCODE(16)
271
DEFINE_SUBRECT_ENCODE(32)
275
* getBgColour() gets the most prevalent colour in a byte array.
278
getBgColour(data,size,bpp)
286
static int counts[NUMCLRS];
294
return ((uint16_t *)data)[0];
295
} else if (bpp == 32) {
296
return ((uint32_t *)data)[0];
298
rfbLog("getBgColour: bpp %d?\n",bpp);
303
for (i=0; i<NUMCLRS; i++) {
307
for (j=0; j<size; j++) {
308
k = (int)(((uint8_t *)data)[j]);
310
rfbErr("getBgColour: unusual colour = %d\n", k);
314
if (counts[k] > maxcount) {
315
maxcount = counts[k];
316
maxclr = ((uint8_t *)data)[j];