LibVNCServer/LibVNCClient
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
cursor.c
Go to the documentation of this file.
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
36 rfbSendCursorShape(rfbClientPtr cl)
37 {
38  rfbCursorPtr pCursor;
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);
56  } else {
57  if(pCursor && !pCursor->source)
58  rfbMakeXCursorFromRichCursor(cl->screen,pCursor);
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) {
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,
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);
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
181 rfbSendCursorPos(rfbClientPtr cl)
182 {
184 
186  if (!rfbSendUpdateBuf(cl))
187  return FALSE;
188  }
189 
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,
199 
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 
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 
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 
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 
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 
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 */
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 
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 
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 
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)
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 
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 
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 
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