1 /*
2 * cursor.c - support for cursor shape updates.
3 */
4
5 /*
6 * Copyright (C) 2000, 2001 Const Kaplinsky. All Rights Reserved.
7 * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
8 *
9 * This is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This software is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this software; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
22 * USA.
23 */
24
25 #include <rfb/rfb.h>
26 #include <rfb/rfbregion.h>
27 #include "private.h"
28
29 void rfbScaledScreenUpdate(rfbScreenInfoPtr screen, int x1, int y1, int x2, int y2);
30
31 /*
32 * Send cursor shape either in X-style format or in client pixel format.
33 */
34
35 rfbBool
rfbSendCursorShape(rfbClientPtr cl)36 rfbSendCursorShape(rfbClientPtr cl)
37 {
38 rfbCursorPtr pCursor;
39 rfbFramebufferUpdateRectHeader rect;
40 rfbXCursorColors colors;
41 int saved_ublen;
42 int bitmapRowBytes, maskBytes, dataBytes;
43 int i, j;
44 uint8_t *bitmapData;
45 uint8_t bitmapByte;
46
47 /* TODO: scale the cursor data to the correct size */
48
49 pCursor = cl->screen->getCursorPtr(cl);
50 /*if(!pCursor) return TRUE;*/
51
52 if (cl->useRichCursorEncoding) {
53 if(pCursor && !pCursor->richSource)
54 rfbMakeRichCursorFromXCursor(cl->screen,pCursor);
55 rect.encoding = Swap32IfLE(rfbEncodingRichCursor);
56 } else {
57 if(pCursor && !pCursor->source)
58 rfbMakeXCursorFromRichCursor(cl->screen,pCursor);
59 rect.encoding = Swap32IfLE(rfbEncodingXCursor);
60 }
61
62 /* If there is no cursor, send update with empty cursor data. */
63
64 if ( pCursor && pCursor->width == 1 &&
65 pCursor->height == 1 &&
66 pCursor->mask[0] == 0 ) {
67 pCursor = NULL;
68 }
69
70 if (pCursor == NULL) {
71 if (cl->ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE ) {
72 if (!rfbSendUpdateBuf(cl))
73 return FALSE;
74 }
75 rect.r.x = rect.r.y = 0;
76 rect.r.w = rect.r.h = 0;
77 memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,
78 sz_rfbFramebufferUpdateRectHeader);
79 cl->ublen += sz_rfbFramebufferUpdateRectHeader;
80
81 if (!rfbSendUpdateBuf(cl))
82 return FALSE;
83
84 return TRUE;
85 }
86
87 /* Calculate data sizes. */
88
89 bitmapRowBytes = (pCursor->width + 7) / 8;
90 maskBytes = bitmapRowBytes * pCursor->height;
91 dataBytes = (cl->useRichCursorEncoding) ?
92 (pCursor->width * pCursor->height *
93 (cl->format.bitsPerPixel / 8)) : maskBytes;
94
95 /* Send buffer contents if needed. */
96
97 if ( cl->ublen + sz_rfbFramebufferUpdateRectHeader +
98 sz_rfbXCursorColors + maskBytes + dataBytes > UPDATE_BUF_SIZE ) {
99 if (!rfbSendUpdateBuf(cl))
100 return FALSE;
101 }
102
103 if ( cl->ublen + sz_rfbFramebufferUpdateRectHeader +
104 sz_rfbXCursorColors + maskBytes + dataBytes > UPDATE_BUF_SIZE ) {
105 return FALSE; /* FIXME. */
106 }
107
108 saved_ublen = cl->ublen;
109
110 /* Prepare rectangle header. */
111
112 rect.r.x = Swap16IfLE(pCursor->xhot);
113 rect.r.y = Swap16IfLE(pCursor->yhot);
114 rect.r.w = Swap16IfLE(pCursor->width);
115 rect.r.h = Swap16IfLE(pCursor->height);
116
117 memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,sz_rfbFramebufferUpdateRectHeader);
118 cl->ublen += sz_rfbFramebufferUpdateRectHeader;
119
120 /* Prepare actual cursor data (depends on encoding used). */
121
122 if (!cl->useRichCursorEncoding) {
123 /* XCursor encoding. */
124 colors.foreRed = (char)(pCursor->foreRed >> 8);
125 colors.foreGreen = (char)(pCursor->foreGreen >> 8);
126 colors.foreBlue = (char)(pCursor->foreBlue >> 8);
127 colors.backRed = (char)(pCursor->backRed >> 8);
128 colors.backGreen = (char)(pCursor->backGreen >> 8);
129 colors.backBlue = (char)(pCursor->backBlue >> 8);
130
131 memcpy(&cl->updateBuf[cl->ublen], (char *)&colors, sz_rfbXCursorColors);
132 cl->ublen += sz_rfbXCursorColors;
133
134 bitmapData = (uint8_t *)pCursor->source;
135
136 for (i = 0; i < pCursor->height; i++) {
137 for (j = 0; j < bitmapRowBytes; j++) {
138 bitmapByte = bitmapData[i * bitmapRowBytes + j];
139 cl->updateBuf[cl->ublen++] = (char)bitmapByte;
140 }
141 }
142 } else {
143 /* RichCursor encoding. */
144 int bpp1=cl->screen->serverFormat.bitsPerPixel/8,
145 bpp2=cl->format.bitsPerPixel/8;
146 (*cl->translateFn)(cl->translateLookupTable,
147 &(cl->screen->serverFormat),
148 &cl->format, (char*)pCursor->richSource,
149 &cl->updateBuf[cl->ublen],
150 pCursor->width*bpp1, pCursor->width, pCursor->height);
151
152 cl->ublen += pCursor->width*bpp2*pCursor->height;
153 }
154
155 /* Prepare transparency mask. */
156
157 bitmapData = (uint8_t *)pCursor->mask;
158
159 for (i = 0; i < pCursor->height; i++) {
160 for (j = 0; j < bitmapRowBytes; j++) {
161 bitmapByte = bitmapData[i * bitmapRowBytes + j];
162 cl->updateBuf[cl->ublen++] = (char)bitmapByte;
163 }
164 }
165
166 /* Send everything we have prepared in the cl->updateBuf[]. */
167 rfbStatRecordEncodingSent(cl, (cl->useRichCursorEncoding ? rfbEncodingRichCursor : rfbEncodingXCursor),
168 sz_rfbFramebufferUpdateRectHeader + (cl->ublen - saved_ublen), sz_rfbFramebufferUpdateRectHeader + (cl->ublen - saved_ublen));
169
170 if (!rfbSendUpdateBuf(cl))
171 return FALSE;
172
173 return TRUE;
174 }
175
176 /*
177 * Send cursor position (PointerPos pseudo-encoding).
178 */
179
180 rfbBool
rfbSendCursorPos(rfbClientPtr cl)181 rfbSendCursorPos(rfbClientPtr cl)
182 {
183 rfbFramebufferUpdateRectHeader rect;
184
185 if (cl->ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE) {
186 if (!rfbSendUpdateBuf(cl))
187 return FALSE;
188 }
189
190 rect.encoding = Swap32IfLE(rfbEncodingPointerPos);
191 rect.r.x = Swap16IfLE(cl->screen->cursorX);
192 rect.r.y = Swap16IfLE(cl->screen->cursorY);
193 rect.r.w = 0;
194 rect.r.h = 0;
195
196 memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,
197 sz_rfbFramebufferUpdateRectHeader);
198 cl->ublen += sz_rfbFramebufferUpdateRectHeader;
199
200 rfbStatRecordEncodingSent(cl, rfbEncodingPointerPos, sz_rfbFramebufferUpdateRectHeader, sz_rfbFramebufferUpdateRectHeader);
201
202 if (!rfbSendUpdateBuf(cl))
203 return FALSE;
204
205 return TRUE;
206 }
207
208 /* conversion routine for predefined cursors in LSB order */
209 unsigned char rfbReverseByte[0x100] = {
210 /* copied from Xvnc/lib/font/util/utilbitmap.c */
211 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
212 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
213 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
214 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
215 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
216 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
217 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
218 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
219 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
220 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
221 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
222 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
223 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
224 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
225 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
226 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
227 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
228 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
229 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
230 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
231 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
232 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
233 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
234 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
235 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
236 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
237 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
238 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
239 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
240 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
241 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
242 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
243 };
244
rfbConvertLSBCursorBitmapOrMask(int width,int height,unsigned char * bitmap)245 void rfbConvertLSBCursorBitmapOrMask(int width,int height,unsigned char* bitmap)
246 {
247 int i,t=(width+7)/8*height;
248 for(i=0;i<t;i++)
249 bitmap[i]=rfbReverseByte[(int)bitmap[i]];
250 }
251
252 /* Cursor creation. You "paint" a cursor and let these routines do the work */
253
rfbMakeXCursor(int width,int height,char * cursorString,char * maskString)254 rfbCursorPtr rfbMakeXCursor(int width,int height,char* cursorString,char* maskString)
255 {
256 int i,j,w=(width+7)/8;
257 rfbCursorPtr cursor = (rfbCursorPtr)calloc(1,sizeof(rfbCursor));
258 char* cp;
259 unsigned char bit;
260
261 cursor->cleanup=TRUE;
262 cursor->width=width;
263 cursor->height=height;
264 /*cursor->backRed=cursor->backGreen=cursor->backBlue=0xffff;*/
265 cursor->foreRed=cursor->foreGreen=cursor->foreBlue=0xffff;
266
267 cursor->source = (unsigned char*)calloc(w,height);
268 cursor->cleanupSource = TRUE;
269 for(j=0,cp=cursorString;j<height;j++)
270 for(i=0,bit=0x80;i<width;i++,bit=(bit&1)?0x80:bit>>1,cp++)
271 if(*cp!=' ') cursor->source[j*w+i/8]|=bit;
272
273 if(maskString) {
274 cursor->mask = (unsigned char*)calloc(w,height);
275 for(j=0,cp=maskString;j<height;j++)
276 for(i=0,bit=0x80;i<width;i++,bit=(bit&1)?0x80:bit>>1,cp++)
277 if(*cp!=' ') cursor->mask[j*w+i/8]|=bit;
278 } else
279 cursor->mask = (unsigned char*)rfbMakeMaskForXCursor(width,height,(char*)cursor->source);
280 cursor->cleanupMask = TRUE;
281
282 return(cursor);
283 }
284
rfbMakeMaskForXCursor(int width,int height,char * source)285 char* rfbMakeMaskForXCursor(int width,int height,char* source)
286 {
287 int i,j,w=(width+7)/8;
288 char* mask=(char*)calloc(w,height);
289 unsigned char c;
290
291 for(j=0;j<height;j++)
292 for(i=w-1;i>=0;i--) {
293 c=source[j*w+i];
294 if(j>0) c|=source[(j-1)*w+i];
295 if(j<height-1) c|=source[(j+1)*w+i];
296
297 if(i>0 && (c&0x80))
298 mask[j*w+i-1]|=0x01;
299 if(i<w-1 && (c&0x01))
300 mask[j*w+i+1]|=0x80;
301
302 mask[j*w+i]|=(c<<1)|c|(c>>1);
303 }
304
305 return(mask);
306 }
307
308 /* this function dithers the alpha using Floyd-Steinberg */
309
rfbMakeMaskFromAlphaSource(int width,int height,unsigned char * alphaSource)310 char* rfbMakeMaskFromAlphaSource(int width,int height,unsigned char* alphaSource)
311 {
312 int* error=(int*)calloc(sizeof(int),width);
313 int i,j,currentError=0,maskStride=(width+7)/8;
314 unsigned char* result=(unsigned char*)calloc(maskStride,height);
315
316 for(j=0;j<height;j++)
317 for(i=0;i<width;i++) {
318 int right,middle,left;
319 currentError+=alphaSource[i+width*j]+error[i];
320
321 if(currentError<0x80) {
322 /* set to transparent */
323 /* alpha was treated as 0 */
324 } else {
325 /* set to solid */
326 result[i/8+j*maskStride]|=(0x100>>(i&7));
327 /* alpha was treated as 0xff */
328 currentError-=0xff;
329 }
330 /* propagate to next row */
331 right=currentError/16;
332 middle=currentError*5/16;
333 left=currentError*3/16;
334 currentError-=right+middle+left;
335 error[i]=right;
336 if(i>0) {
337 error[i-1]=middle;
338 if(i>1)
339 error[i-2]=left;
340 }
341 }
342 free(error);
343 return (char *) result;
344 }
345
rfbFreeCursor(rfbCursorPtr cursor)346 void rfbFreeCursor(rfbCursorPtr cursor)
347 {
348 if(cursor) {
349 if(cursor->cleanupRichSource && cursor->richSource)
350 free(cursor->richSource);
351 if(cursor->cleanupRichSource && cursor->alphaSource)
352 free(cursor->alphaSource);
353 if(cursor->cleanupSource && cursor->source)
354 free(cursor->source);
355 if(cursor->cleanupMask && cursor->mask)
356 free(cursor->mask);
357 if(cursor->cleanup)
358 free(cursor);
359 else {
360 cursor->cleanup=cursor->cleanupSource=cursor->cleanupMask
361 =cursor->cleanupRichSource=FALSE;
362 cursor->source=cursor->mask=cursor->richSource=NULL;
363 cursor->alphaSource=NULL;
364 }
365 }
366
367 }
368
369 /* background and foregroud colour have to be set beforehand */
rfbMakeXCursorFromRichCursor(rfbScreenInfoPtr rfbScreen,rfbCursorPtr cursor)370 void rfbMakeXCursorFromRichCursor(rfbScreenInfoPtr rfbScreen,rfbCursorPtr cursor)
371 {
372 rfbPixelFormat* format=&rfbScreen->serverFormat;
373 int i,j,w=(cursor->width+7)/8,bpp=format->bitsPerPixel/8,
374 width=cursor->width*bpp;
375 uint32_t background;
376 char *back=(char*)&background;
377 unsigned char bit;
378 int interp = 0, db = 0;
379
380 if(cursor->source && cursor->cleanupSource)
381 free(cursor->source);
382 cursor->source=(unsigned char*)calloc(w,cursor->height);
383 cursor->cleanupSource=TRUE;
384
385 if(format->bigEndian) {
386 back+=4-bpp;
387 }
388
389 /* all zeros means we should interpolate to black+white ourselves */
390 if (!cursor->backRed && !cursor->backGreen && !cursor->backBlue &&
391 !cursor->foreRed && !cursor->foreGreen && !cursor->foreBlue) {
392 if (format->trueColour && (bpp == 1 || bpp == 2 || bpp == 4)) {
393 interp = 1;
394 cursor->foreRed = cursor->foreGreen = cursor->foreBlue = 0xffff;
395 }
396 }
397
398 background = ((format->redMax * cursor->backRed) / 0xffff) << format->redShift |
399 ((format->greenMax * cursor->backGreen) / 0xffff) << format->greenShift |
400 ((format->blueMax * cursor->backBlue) / 0xffff) << format->blueShift;
401
402 #define SETRGB(u) \
403 r = (255 * (((format->redMax << format->redShift) & (*u)) >> format->redShift)) / format->redMax; \
404 g = (255 * (((format->greenMax << format->greenShift) & (*u)) >> format->greenShift)) / format->greenMax; \
405 b = (255 * (((format->blueMax << format->blueShift) & (*u)) >> format->blueShift)) / format->blueMax;
406
407 if (db) fprintf(stderr, "interp: %d\n", interp);
408
409 for(j=0;j<cursor->height;j++) {
410 for(i=0,bit=0x80;i<cursor->width;i++,bit=(bit&1)?0x80:bit>>1) {
411 if (interp) {
412 int r = 0, g = 0, b = 0, grey;
413 unsigned char *p = cursor->richSource+j*width+i*bpp;
414 if (bpp == 1) {
415 unsigned char* uc = (unsigned char*) p;
416 SETRGB(uc);
417 } else if (bpp == 2) {
418 unsigned short* us = (unsigned short*) p;
419 SETRGB(us);
420 } else if (bpp == 4) {
421 unsigned int* ui = (unsigned int*) p;
422 SETRGB(ui);
423 }
424 grey = (r + g + b) / 3;
425 if (grey >= 128) {
426 cursor->source[j*w+i/8]|=bit;
427 if (db) fprintf(stderr, "1");
428 } else {
429 if (db) fprintf(stderr, "0");
430 }
431
432 } else if(memcmp(cursor->richSource+j*width+i*bpp, back, bpp)) {
433 cursor->source[j*w+i/8]|=bit;
434 }
435 }
436 if (db) fprintf(stderr, "\n");
437 }
438 }
439
rfbMakeRichCursorFromXCursor(rfbScreenInfoPtr rfbScreen,rfbCursorPtr cursor)440 void rfbMakeRichCursorFromXCursor(rfbScreenInfoPtr rfbScreen,rfbCursorPtr cursor)
441 {
442 rfbPixelFormat* format=&rfbScreen->serverFormat;
443 int i,j,w=(cursor->width+7)/8,bpp=format->bitsPerPixel/8;
444 uint32_t background,foreground;
445 char *back=(char*)&background,*fore=(char*)&foreground;
446 unsigned char *cp;
447 unsigned char bit;
448
449 if(cursor->richSource && cursor->cleanupRichSource)
450 free(cursor->richSource);
451 cp=cursor->richSource=(unsigned char*)calloc(cursor->width*bpp,cursor->height);
452 cursor->cleanupRichSource=TRUE;
453
454 if(format->bigEndian) {
455 back+=4-bpp;
456 fore+=4-bpp;
457 }
458
459 background=cursor->backRed<<format->redShift|
460 cursor->backGreen<<format->greenShift|cursor->backBlue<<format->blueShift;
461 foreground=cursor->foreRed<<format->redShift|
462 cursor->foreGreen<<format->greenShift|cursor->foreBlue<<format->blueShift;
463
464 for(j=0;j<cursor->height;j++)
465 for(i=0,bit=0x80;i<cursor->width;i++,bit=(bit&1)?0x80:bit>>1,cp+=bpp)
466 if(cursor->source[j*w+i/8]&bit) memcpy(cp,fore,bpp);
467 else memcpy(cp,back,bpp);
468 }
469
470 /* functions to draw/hide cursor directly in the frame buffer */
471
rfbHideCursor(rfbClientPtr cl)472 void rfbHideCursor(rfbClientPtr cl)
473 {
474 rfbScreenInfoPtr s=cl->screen;
475 rfbCursorPtr c=s->cursor;
476 int j,x1,x2,y1,y2,bpp=s->serverFormat.bitsPerPixel/8,
477 rowstride=s->paddedWidthInBytes;
478 LOCK(s->cursorMutex);
479 if(!c) {
480 UNLOCK(s->cursorMutex);
481 return;
482 }
483
484 /* restore what is under the cursor */
485 x1=cl->cursorX-c->xhot;
486 x2=x1+c->width;
487 if(x1<0) x1=0;
488 if(x2>=s->width) x2=s->width-1;
489 x2-=x1; if(x2<=0) {
490 UNLOCK(s->cursorMutex);
491 return;
492 }
493 y1=cl->cursorY-c->yhot;
494 y2=y1+c->height;
495 if(y1<0) y1=0;
496 if(y2>=s->height) y2=s->height-1;
497 y2-=y1; if(y2<=0) {
498 UNLOCK(s->cursorMutex);
499 return;
500 }
501
502 /* get saved data */
503 for(j=0;j<y2;j++)
504 memcpy(s->frameBuffer+(y1+j)*rowstride+x1*bpp,
505 s->underCursorBuffer+j*x2*bpp,
506 x2*bpp);
507
508 /* Copy to all scaled versions */
509 rfbScaledScreenUpdate(s, x1, y1, x1+x2, y1+y2);
510
511 UNLOCK(s->cursorMutex);
512 }
513
rfbShowCursor(rfbClientPtr cl)514 void rfbShowCursor(rfbClientPtr cl)
515 {
516 rfbScreenInfoPtr s=cl->screen;
517 rfbCursorPtr c=s->cursor;
518 int i,j,x1,x2,y1,y2,i1,j1,bpp=s->serverFormat.bitsPerPixel/8,
519 rowstride=s->paddedWidthInBytes,
520 bufSize,w;
521 rfbBool wasChanged=FALSE;
522
523 if(!c) return;
524 LOCK(s->cursorMutex);
525
526 bufSize=c->width*c->height*bpp;
527 w=(c->width+7)/8;
528 if(s->underCursorBufferLen<bufSize) {
529 if(s->underCursorBuffer!=NULL)
530 free(s->underCursorBuffer);
531 s->underCursorBuffer=malloc(bufSize);
532 s->underCursorBufferLen=bufSize;
533 }
534
535 /* save what is under the cursor */
536 i1=j1=0; /* offset in cursor */
537 x1=cl->cursorX-c->xhot;
538 x2=x1+c->width;
539 if(x1<0) { i1=-x1; x1=0; }
540 if(x2>=s->width) x2=s->width-1;
541 x2-=x1; if(x2<=0) {
542 UNLOCK(s->cursorMutex);
543 return; /* nothing to do */
544 }
545
546 y1=cl->cursorY-c->yhot;
547 y2=y1+c->height;
548 if(y1<0) { j1=-y1; y1=0; }
549 if(y2>=s->height) y2=s->height-1;
550 y2-=y1; if(y2<=0) {
551 UNLOCK(s->cursorMutex);
552 return; /* nothing to do */
553 }
554
555 /* save data */
556 for(j=0;j<y2;j++) {
557 char* dest=s->underCursorBuffer+j*x2*bpp;
558 const char* src=s->frameBuffer+(y1+j)*rowstride+x1*bpp;
559 unsigned int count=x2*bpp;
560 if(wasChanged || memcmp(dest,src,count)) {
561 wasChanged=TRUE;
562 memcpy(dest,src,count);
563 }
564 }
565
566 if(!c->richSource)
567 rfbMakeRichCursorFromXCursor(s,c);
568
569 if (c->alphaSource) {
570 int rmax, rshift;
571 int gmax, gshift;
572 int bmax, bshift;
573 int amax = 255; /* alphaSource is always 8bits of info per pixel */
574 unsigned int rmask, gmask, bmask;
575
576 rmax = s->serverFormat.redMax;
577 gmax = s->serverFormat.greenMax;
578 bmax = s->serverFormat.blueMax;
579 rshift = s->serverFormat.redShift;
580 gshift = s->serverFormat.greenShift;
581 bshift = s->serverFormat.blueShift;
582
583 rmask = (rmax << rshift);
584 gmask = (gmax << gshift);
585 bmask = (bmax << bshift);
586
587 for(j=0;j<y2;j++) {
588 for(i=0;i<x2;i++) {
589 /*
590 * we loop over the whole cursor ignoring c->mask[],
591 * using the extracted alpha value instead.
592 */
593 char *dest;
594 unsigned char *src, *aptr;
595 unsigned int val, dval, sval;
596 int rdst, gdst, bdst; /* fb RGB */
597 int asrc, rsrc, gsrc, bsrc; /* rich source ARGB */
598
599 dest = s->frameBuffer + (j+y1)*rowstride + (i+x1)*bpp;
600 src = c->richSource + (j+j1)*c->width*bpp + (i+i1)*bpp;
601 aptr = c->alphaSource + (j+j1)*c->width + (i+i1);
602
603 asrc = *aptr;
604 if (!asrc) {
605 continue;
606 }
607
608 if (bpp == 1) {
609 dval = *((unsigned char*) dest);
610 sval = *((unsigned char*) src);
611 } else if (bpp == 2) {
612 dval = *((unsigned short*) dest);
613 sval = *((unsigned short*) src);
614 } else if (bpp == 3) {
615 unsigned char *dst = (unsigned char *) dest;
616 dval = 0;
617 dval |= ((*(dst+0)) << 0);
618 dval |= ((*(dst+1)) << 8);
619 dval |= ((*(dst+2)) << 16);
620 sval = 0;
621 sval |= ((*(src+0)) << 0);
622 sval |= ((*(src+1)) << 8);
623 sval |= ((*(src+2)) << 16);
624 } else if (bpp == 4) {
625 dval = *((unsigned int*) dest);
626 sval = *((unsigned int*) src);
627 } else {
628 continue;
629 }
630
631 /* extract dest and src RGB */
632 rdst = (dval & rmask) >> rshift; /* fb */
633 gdst = (dval & gmask) >> gshift;
634 bdst = (dval & bmask) >> bshift;
635
636 rsrc = (sval & rmask) >> rshift; /* richcursor */
637 gsrc = (sval & gmask) >> gshift;
638 bsrc = (sval & bmask) >> bshift;
639
640 /* blend in fb data. */
641 if (! c->alphaPreMultiplied) {
642 rsrc = (asrc * rsrc)/amax;
643 gsrc = (asrc * gsrc)/amax;
644 bsrc = (asrc * bsrc)/amax;
645 }
646 rdst = rsrc + ((amax - asrc) * rdst)/amax;
647 gdst = gsrc + ((amax - asrc) * gdst)/amax;
648 bdst = bsrc + ((amax - asrc) * bdst)/amax;
649
650 val = 0;
651 val |= (rdst << rshift);
652 val |= (gdst << gshift);
653 val |= (bdst << bshift);
654
655 /* insert the cooked pixel into the fb */
656 memcpy(dest, &val, bpp);
657 }
658 }
659 } else {
660 /* now the cursor has to be drawn */
661 for(j=0;j<y2;j++)
662 for(i=0;i<x2;i++)
663 if((c->mask[(j+j1)*w+(i+i1)/8]<<((i+i1)&7))&0x80)
664 memcpy(s->frameBuffer+(j+y1)*rowstride+(i+x1)*bpp,
665 c->richSource+(j+j1)*c->width*bpp+(i+i1)*bpp,bpp);
666 }
667
668 /* Copy to all scaled versions */
669 rfbScaledScreenUpdate(s, x1, y1, x1+x2, y1+y2);
670
671 UNLOCK(s->cursorMutex);
672 }
673
674 /*
675 * If enableCursorShapeUpdates is FALSE, and the cursor is hidden, make sure
676 * that if the frameBuffer was transmitted with a cursor drawn, then that
677 * region gets redrawn.
678 */
679
rfbRedrawAfterHideCursor(rfbClientPtr cl,sraRegionPtr updateRegion)680 void rfbRedrawAfterHideCursor(rfbClientPtr cl,sraRegionPtr updateRegion)
681 {
682 rfbScreenInfoPtr s = cl->screen;
683 rfbCursorPtr c = s->cursor;
684
685 if(c) {
686 int x,y,x2,y2;
687
688 x = cl->cursorX-c->xhot;
689 y = cl->cursorY-c->yhot;
690 x2 = x+c->width;
691 y2 = y+c->height;
692
693 if(sraClipRect2(&x,&y,&x2,&y2,0,0,s->width,s->height)) {
694 sraRegionPtr rect;
695 rect = sraRgnCreateRect(x,y,x2,y2);
696 if(updateRegion) {
697 sraRgnOr(updateRegion,rect);
698 } else {
699 LOCK(cl->updateMutex);
700 sraRgnOr(cl->modifiedRegion,rect);
701 UNLOCK(cl->updateMutex);
702 }
703 sraRgnDestroy(rect);
704 }
705 }
706 }
707
708 #ifdef DEBUG
709
rfbPrintXCursor(rfbCursorPtr cursor)710 static void rfbPrintXCursor(rfbCursorPtr cursor)
711 {
712 int i,i1,j,w=(cursor->width+7)/8;
713 unsigned char bit;
714 for(j=0;j<cursor->height;j++) {
715 for(i=0,i1=0,bit=0x80;i1<cursor->width;i1++,i+=(bit&1)?1:0,bit=(bit&1)?0x80:bit>>1)
716 if(cursor->source[j*w+i]&bit) putchar('#'); else putchar(' ');
717 putchar(':');
718 for(i=0,i1=0,bit=0x80;i1<cursor->width;i1++,i+=(bit&1)?1:0,bit=(bit&1)?0x80:bit>>1)
719 if(cursor->mask[j*w+i]&bit) putchar('#'); else putchar(' ');
720 putchar('\n');
721 }
722 }
723
724 #endif
725
rfbSetCursor(rfbScreenInfoPtr rfbScreen,rfbCursorPtr c)726 void rfbSetCursor(rfbScreenInfoPtr rfbScreen,rfbCursorPtr c)
727 {
728 rfbClientIteratorPtr iterator;
729 rfbClientPtr cl;
730
731 LOCK(rfbScreen->cursorMutex);
732
733 if(rfbScreen->cursor) {
734 iterator=rfbGetClientIterator(rfbScreen);
735 while((cl=rfbClientIteratorNext(iterator)))
736 if(!cl->enableCursorShapeUpdates)
737 rfbRedrawAfterHideCursor(cl,NULL);
738 rfbReleaseClientIterator(iterator);
739
740 if(rfbScreen->cursor->cleanup)
741 rfbFreeCursor(rfbScreen->cursor);
742 }
743
744 rfbScreen->cursor = c;
745
746 iterator=rfbGetClientIterator(rfbScreen);
747 while((cl=rfbClientIteratorNext(iterator))) {
748 cl->cursorWasChanged = TRUE;
749 if(!cl->enableCursorShapeUpdates)
750 rfbRedrawAfterHideCursor(cl,NULL);
751 }
752 rfbReleaseClientIterator(iterator);
753
754 UNLOCK(rfbScreen->cursorMutex);
755 }
756
757