1/*
2 * Copyright (C) 2002 RealVNC Ltd.  All Rights Reserved.
3 * Copyright (C) 2003 Sun Microsystems, Inc.
4 *
5 * This is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This software is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this software; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
18 * USA.
19 */
20
21/*
22 * zrle.c
23 *
24 * Routines to implement Zlib Run-length Encoding (ZRLE).
25 */
26
27#include "rfb/rfb.h"
28#include "private.h"
29#include "zrleoutstream.h"
30
31
32#define GET_IMAGE_INTO_BUF(tx,ty,tw,th,buf)                                \
33{  char *fbptr = (cl->scaledScreen->frameBuffer                                   \
34		 + (cl->scaledScreen->paddedWidthInBytes * ty)                   \
35                 + (tx * (cl->scaledScreen->bitsPerPixel / 8)));                 \
36                                                                           \
37  (*cl->translateFn)(cl->translateLookupTable, &cl->screen->serverFormat,\
38                     &cl->format, fbptr, (char*)buf,                       \
39                     cl->scaledScreen->paddedWidthInBytes, tw, th); }
40
41#define EXTRA_ARGS , rfbClientPtr cl
42
43#define ENDIAN_LITTLE 0
44#define ENDIAN_BIG 1
45#define ENDIAN_NO 2
46#define BPP 8
47#define ZYWRLE_ENDIAN ENDIAN_NO
48#include <zrleencodetemplate.c>
49#undef BPP
50#define BPP 15
51#undef ZYWRLE_ENDIAN
52#define ZYWRLE_ENDIAN ENDIAN_LITTLE
53#include <zrleencodetemplate.c>
54#undef ZYWRLE_ENDIAN
55#define ZYWRLE_ENDIAN ENDIAN_BIG
56#include <zrleencodetemplate.c>
57#undef BPP
58#define BPP 16
59#undef ZYWRLE_ENDIAN
60#define ZYWRLE_ENDIAN ENDIAN_LITTLE
61#include <zrleencodetemplate.c>
62#undef ZYWRLE_ENDIAN
63#define ZYWRLE_ENDIAN ENDIAN_BIG
64#include <zrleencodetemplate.c>
65#undef BPP
66#define BPP 32
67#undef ZYWRLE_ENDIAN
68#define ZYWRLE_ENDIAN ENDIAN_LITTLE
69#include <zrleencodetemplate.c>
70#undef ZYWRLE_ENDIAN
71#define ZYWRLE_ENDIAN ENDIAN_BIG
72#include <zrleencodetemplate.c>
73#define CPIXEL 24A
74#undef ZYWRLE_ENDIAN
75#define ZYWRLE_ENDIAN ENDIAN_LITTLE
76#include <zrleencodetemplate.c>
77#undef ZYWRLE_ENDIAN
78#define ZYWRLE_ENDIAN ENDIAN_BIG
79#include <zrleencodetemplate.c>
80#undef CPIXEL
81#define CPIXEL 24B
82#undef ZYWRLE_ENDIAN
83#define ZYWRLE_ENDIAN ENDIAN_LITTLE
84#include <zrleencodetemplate.c>
85#undef ZYWRLE_ENDIAN
86#define ZYWRLE_ENDIAN ENDIAN_BIG
87#include <zrleencodetemplate.c>
88#undef CPIXEL
89#undef BPP
90
91
92/*
93 * zrleBeforeBuf contains pixel data in the client's format.  It must be at
94 * least one pixel bigger than the largest tile of pixel data, since the
95 * ZRLE encoding algorithm writes to the position one past the end of the pixel
96 * data.
97 */
98
99
100/*
101 * rfbSendRectEncodingZRLE - send a given rectangle using ZRLE encoding.
102 */
103
104rfbBool rfbSendRectEncodingZRLE(rfbClientPtr cl, int x, int y, int w, int h)
105{
106  zrleOutStream* zos;
107  rfbFramebufferUpdateRectHeader rect;
108  rfbZRLEHeader hdr;
109  int i;
110  char *zrleBeforeBuf;
111
112  if (cl->zrleBeforeBuf == NULL) {
113	cl->zrleBeforeBuf = (char *) malloc(rfbZRLETileWidth * rfbZRLETileHeight * 4 + 4);
114  }
115  zrleBeforeBuf = cl->zrleBeforeBuf;
116
117  if (cl->preferredEncoding == rfbEncodingZYWRLE) {
118	  if (cl->tightQualityLevel < 0) {
119		  cl->zywrleLevel = 1;
120	  } else if (cl->tightQualityLevel < 3) {
121		  cl->zywrleLevel = 3;
122	  } else if (cl->tightQualityLevel < 6) {
123		  cl->zywrleLevel = 2;
124	  } else {
125		  cl->zywrleLevel = 1;
126	  }
127  } else
128	  cl->zywrleLevel = 0;
129
130  if (!cl->zrleData)
131    cl->zrleData = zrleOutStreamNew();
132  zos = cl->zrleData;
133  zos->in.ptr = zos->in.start;
134  zos->out.ptr = zos->out.start;
135
136  switch (cl->format.bitsPerPixel) {
137
138  case 8:
139    zrleEncode8NE(x, y, w, h, zos, zrleBeforeBuf, cl);
140    break;
141
142  case 16:
143	if (cl->format.greenMax > 0x1F) {
144		if (cl->format.bigEndian)
145		  zrleEncode16BE(x, y, w, h, zos, zrleBeforeBuf, cl);
146		else
147		  zrleEncode16LE(x, y, w, h, zos, zrleBeforeBuf, cl);
148	} else {
149		if (cl->format.bigEndian)
150		  zrleEncode15BE(x, y, w, h, zos, zrleBeforeBuf, cl);
151		else
152		  zrleEncode15LE(x, y, w, h, zos, zrleBeforeBuf, cl);
153	}
154    break;
155
156  case 32: {
157    rfbBool fitsInLS3Bytes
158      = ((cl->format.redMax   << cl->format.redShift)   < (1<<24) &&
159         (cl->format.greenMax << cl->format.greenShift) < (1<<24) &&
160         (cl->format.blueMax  << cl->format.blueShift)  < (1<<24));
161
162    rfbBool fitsInMS3Bytes = (cl->format.redShift   > 7  &&
163                           cl->format.greenShift > 7  &&
164                           cl->format.blueShift  > 7);
165
166    if ((fitsInLS3Bytes && !cl->format.bigEndian) ||
167        (fitsInMS3Bytes && cl->format.bigEndian)) {
168	if (cl->format.bigEndian)
169		zrleEncode24ABE(x, y, w, h, zos, zrleBeforeBuf, cl);
170	else
171		zrleEncode24ALE(x, y, w, h, zos, zrleBeforeBuf, cl);
172    }
173    else if ((fitsInLS3Bytes && cl->format.bigEndian) ||
174             (fitsInMS3Bytes && !cl->format.bigEndian)) {
175	if (cl->format.bigEndian)
176		zrleEncode24BBE(x, y, w, h, zos, zrleBeforeBuf, cl);
177	else
178		zrleEncode24BLE(x, y, w, h, zos, zrleBeforeBuf, cl);
179    }
180    else {
181	if (cl->format.bigEndian)
182		zrleEncode32BE(x, y, w, h, zos, zrleBeforeBuf, cl);
183	else
184		zrleEncode32LE(x, y, w, h, zos, zrleBeforeBuf, cl);
185    }
186  }
187    break;
188  }
189
190  rfbStatRecordEncodingSent(cl, rfbEncodingZRLE, sz_rfbFramebufferUpdateRectHeader + sz_rfbZRLEHeader + ZRLE_BUFFER_LENGTH(&zos->out),
191      + w * (cl->format.bitsPerPixel / 8) * h);
192
193  if (cl->ublen + sz_rfbFramebufferUpdateRectHeader + sz_rfbZRLEHeader
194      > UPDATE_BUF_SIZE)
195    {
196      if (!rfbSendUpdateBuf(cl))
197        return FALSE;
198    }
199
200  rect.r.x = Swap16IfLE(x);
201  rect.r.y = Swap16IfLE(y);
202  rect.r.w = Swap16IfLE(w);
203  rect.r.h = Swap16IfLE(h);
204  rect.encoding = Swap32IfLE(cl->preferredEncoding);
205
206  memcpy(cl->updateBuf+cl->ublen, (char *)&rect,
207         sz_rfbFramebufferUpdateRectHeader);
208  cl->ublen += sz_rfbFramebufferUpdateRectHeader;
209
210  hdr.length = Swap32IfLE(ZRLE_BUFFER_LENGTH(&zos->out));
211
212  memcpy(cl->updateBuf+cl->ublen, (char *)&hdr, sz_rfbZRLEHeader);
213  cl->ublen += sz_rfbZRLEHeader;
214
215  /* copy into updateBuf and send from there.  Maybe should send directly? */
216
217  for (i = 0; i < ZRLE_BUFFER_LENGTH(&zos->out);) {
218
219    int bytesToCopy = UPDATE_BUF_SIZE - cl->ublen;
220
221    if (i + bytesToCopy > ZRLE_BUFFER_LENGTH(&zos->out)) {
222      bytesToCopy = ZRLE_BUFFER_LENGTH(&zos->out) - i;
223    }
224
225    memcpy(cl->updateBuf+cl->ublen, (uint8_t*)zos->out.start + i, bytesToCopy);
226
227    cl->ublen += bytesToCopy;
228    i += bytesToCopy;
229
230    if (cl->ublen == UPDATE_BUF_SIZE) {
231      if (!rfbSendUpdateBuf(cl))
232        return FALSE;
233    }
234  }
235
236  return TRUE;
237}
238
239
240void rfbFreeZrleData(rfbClientPtr cl)
241{
242	if (cl->zrleData) {
243		zrleOutStreamFree(cl->zrleData);
244	}
245	cl->zrleData = NULL;
246
247	if (cl->zrleBeforeBuf) {
248		free(cl->zrleBeforeBuf);
249	}
250	cl->zrleBeforeBuf = NULL;
251
252	if (cl->paletteHelper) {
253		free(cl->paletteHelper);
254	}
255	cl->paletteHelper = NULL;
256}
257
258