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