LibVNCServer/LibVNCClient
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  if (!cursor)
262  return NULL;
263 
264  cursor->cleanup=TRUE;
265  cursor->width=width;
266  cursor->height=height;
267  /*cursor->backRed=cursor->backGreen=cursor->backBlue=0xffff;*/
268  cursor->foreRed=cursor->foreGreen=cursor->foreBlue=0xffff;
269 
270  cursor->source = (unsigned char*)calloc(w,height);
271  if (!cursor->source) {
272  free(cursor);
273  return NULL;
274  }
275  cursor->cleanupSource = TRUE;
276  for(j=0,cp=cursorString;j<height;j++)
277  for(i=0,bit=0x80;i<width;i++,bit=(bit&1)?0x80:bit>>1,cp++)
278  if(*cp!=' ') cursor->source[j*w+i/8]|=bit;
279 
280  if(maskString) {
281  cursor->mask = (unsigned char*)calloc(w,height);
282  if (!cursor->mask) {
283  free(cursor->source);
284  free(cursor);
285  return NULL;
286  }
287  for(j=0,cp=maskString;j<height;j++)
288  for(i=0,bit=0x80;i<width;i++,bit=(bit&1)?0x80:bit>>1,cp++)
289  if(*cp!=' ') cursor->mask[j*w+i/8]|=bit;
290  } else
291  cursor->mask = (unsigned char*)rfbMakeMaskForXCursor(width,height,(char*)cursor->source);
292  cursor->cleanupMask = TRUE;
293 
294  return(cursor);
295 }
296 
297 char* rfbMakeMaskForXCursor(int width,int height,char* source)
298 {
299  int i,j,w=(width+7)/8;
300  char* mask=(char*)calloc(w,height);
301  unsigned char c;
302 
303  if (!mask)
304  return NULL;
305 
306  for(j=0;j<height;j++)
307  for(i=w-1;i>=0;i--) {
308  c=source[j*w+i];
309  if(j>0) c|=source[(j-1)*w+i];
310  if(j<height-1) c|=source[(j+1)*w+i];
311 
312  if(i>0 && (c&0x80))
313  mask[j*w+i-1]|=0x01;
314  if(i<w-1 && (c&0x01))
315  mask[j*w+i+1]|=0x80;
316 
317  mask[j*w+i]|=(c<<1)|c|(c>>1);
318  }
319 
320  return(mask);
321 }
322 
323 /* this function dithers the alpha using Floyd-Steinberg */
324 
325 char* rfbMakeMaskFromAlphaSource(int width,int height,unsigned char* alphaSource)
326 {
327  int* error=(int*)calloc(sizeof(int),width);
328  int i,j,currentError=0,maskStride=(width+7)/8;
329  unsigned char* result=(unsigned char*)calloc(maskStride,height);
330 
331  if (!error || !result) {
332  free(error);
333  free(result);
334  return NULL;
335  }
336 
337  for(j=0;j<height;j++)
338  for(i=0;i<width;i++) {
339  int right,middle,left;
340  currentError+=alphaSource[i+width*j]+error[i];
341 
342  if(currentError<0x80) {
343  /* set to transparent */
344  /* alpha was treated as 0 */
345  } else {
346  /* set to solid */
347  result[i/8+j*maskStride]|=(0x100>>(i&7));
348  /* alpha was treated as 0xff */
349  currentError-=0xff;
350  }
351  /* propagate to next row */
352  right=currentError/16;
353  middle=currentError*5/16;
354  left=currentError*3/16;
355  currentError-=right+middle+left;
356  error[i]=right;
357  if(i>0) {
358  error[i-1]=middle;
359  if(i>1)
360  error[i-2]=left;
361  }
362  }
363  free(error);
364  return (char *) result;
365 }
366 
367 void rfbFreeCursor(rfbCursorPtr cursor)
368 {
369  if(cursor) {
370  if(cursor->cleanupRichSource && cursor->richSource)
371  free(cursor->richSource);
372  if(cursor->cleanupRichSource && cursor->alphaSource)
373  free(cursor->alphaSource);
374  if(cursor->cleanupSource && cursor->source)
375  free(cursor->source);
376  if(cursor->cleanupMask && cursor->mask)
377  free(cursor->mask);
378  if(cursor->cleanup)
379  free(cursor);
380  else {
381  cursor->cleanup=cursor->cleanupSource=cursor->cleanupMask
382  =cursor->cleanupRichSource=FALSE;
383  cursor->source=cursor->mask=cursor->richSource=NULL;
384  cursor->alphaSource=NULL;
385  }
386  }
387 
388 }
389 
390 /* background and foregroud colour have to be set beforehand */
391 void rfbMakeXCursorFromRichCursor(rfbScreenInfoPtr rfbScreen,rfbCursorPtr cursor)
392 {
393  rfbPixelFormat* format=&rfbScreen->serverFormat;
394  int i,j,w=(cursor->width+7)/8,bpp=format->bitsPerPixel/8,
395  width=cursor->width*bpp;
396  uint32_t background;
397  char *back=(char*)&background;
398  unsigned char bit;
399  int interp = 0;
400 
401  if(cursor->source && cursor->cleanupSource)
402  free(cursor->source);
403  cursor->source=(unsigned char*)calloc(w,cursor->height);
404  if(!cursor->source)
405  return;
406  cursor->cleanupSource=TRUE;
407 
408  if(format->bigEndian) {
409  back+=4-bpp;
410  }
411 
412  /* all zeros means we should interpolate to black+white ourselves */
413  if (!cursor->backRed && !cursor->backGreen && !cursor->backBlue &&
414  !cursor->foreRed && !cursor->foreGreen && !cursor->foreBlue) {
415  if (format->trueColour && (bpp == 1 || bpp == 2 || bpp == 4)) {
416  interp = 1;
417  cursor->foreRed = cursor->foreGreen = cursor->foreBlue = 0xffff;
418  }
419  }
420 
421  background = ((format->redMax * cursor->backRed) / 0xffff) << format->redShift |
422  ((format->greenMax * cursor->backGreen) / 0xffff) << format->greenShift |
423  ((format->blueMax * cursor->backBlue) / 0xffff) << format->blueShift;
424 
425 #define SETRGB(u) \
426  r = (255 * (((format->redMax << format->redShift) & (*u)) >> format->redShift)) / format->redMax; \
427  g = (255 * (((format->greenMax << format->greenShift) & (*u)) >> format->greenShift)) / format->greenMax; \
428  b = (255 * (((format->blueMax << format->blueShift) & (*u)) >> format->blueShift)) / format->blueMax;
429 
430 #ifdef DEBUG_CURSOR
431  fprintf(stderr, "interp: %d\n", interp);
432 #endif
433 
434  for(j=0;j<cursor->height;j++) {
435  for(i=0,bit=0x80;i<cursor->width;i++,bit=(bit&1)?0x80:bit>>1) {
436  if (interp) {
437  int r = 0, g = 0, b = 0, grey;
438  unsigned char *p = cursor->richSource+j*width+i*bpp;
439  if (bpp == 1) {
440  unsigned char* uc = (unsigned char*) p;
441  SETRGB(uc);
442  } else if (bpp == 2) {
443  unsigned short* us = (unsigned short*) p;
444  SETRGB(us);
445  } else if (bpp == 4) {
446  unsigned int* ui = (unsigned int*) p;
447  SETRGB(ui);
448  }
449  grey = (r + g + b) / 3;
450  if (grey >= 128) {
451  cursor->source[j*w+i/8]|=bit;
452 #ifdef DEBUG_CURSOR
453  fprintf(stderr, "1");
454  } else {
455  fprintf(stderr, "0");
456 #endif
457  }
458 
459  } else if(memcmp(cursor->richSource+j*width+i*bpp, back, bpp)) {
460  cursor->source[j*w+i/8]|=bit;
461  }
462  }
463 #ifdef DEBUG_CURSOR
464  fprintf(stderr, "\n");
465 #endif
466  }
467 }
468 
469 void rfbMakeRichCursorFromXCursor(rfbScreenInfoPtr rfbScreen,rfbCursorPtr cursor)
470 {
471  rfbPixelFormat* format=&rfbScreen->serverFormat;
472  int i,j,w=(cursor->width+7)/8,bpp=format->bitsPerPixel/8;
473  uint32_t background,foreground;
474  char *back=(char*)&background,*fore=(char*)&foreground;
475  unsigned char *cp;
476  unsigned char bit;
477 
478  if(cursor->richSource && cursor->cleanupRichSource)
479  free(cursor->richSource);
480  cp=cursor->richSource=(unsigned char*)calloc(cursor->width*bpp,cursor->height);
481  if(!cp)
482  return;
483  cursor->cleanupRichSource=TRUE;
484 
485  if(format->bigEndian) {
486  back+=4-bpp;
487  fore+=4-bpp;
488  }
489 
490  background=(uint32_t)cursor->backRed<<format->redShift|
491  (uint32_t)cursor->backGreen<<format->greenShift|(uint32_t)cursor->backBlue<<format->blueShift;
492  foreground=(uint32_t)cursor->foreRed<<format->redShift|
493  (uint32_t)cursor->foreGreen<<format->greenShift|(uint32_t)cursor->foreBlue<<format->blueShift;
494 
495  for(j=0;j<cursor->height;j++)
496  for(i=0,bit=0x80;i<cursor->width;i++,bit=(bit&1)?0x80:bit>>1,cp+=bpp)
497  if(cursor->source[j*w+i/8]&bit) memcpy(cp,fore,bpp);
498  else memcpy(cp,back,bpp);
499 }
500 
501 /* functions to draw/hide cursor directly in the frame buffer */
502 
503 void rfbHideCursor(rfbClientPtr cl)
504 {
505  rfbScreenInfoPtr s=cl->screen;
506  rfbCursorPtr c=s->cursor;
507  int j,x1,x2,y1,y2,bpp=s->serverFormat.bitsPerPixel/8,
508  rowstride=s->paddedWidthInBytes;
509  LOCK(s->cursorMutex);
510  if(!c) {
511  UNLOCK(s->cursorMutex);
512  return;
513  }
514 
515  /* restore what is under the cursor */
516  x1=cl->cursorX-c->xhot;
517  x2=x1+c->width;
518  if(x1<0) x1=0;
519  if(x2>=s->width) x2=s->width-1;
520  x2-=x1; if(x2<=0) {
521  UNLOCK(s->cursorMutex);
522  return;
523  }
524  y1=cl->cursorY-c->yhot;
525  y2=y1+c->height;
526  if(y1<0) y1=0;
527  if(y2>=s->height) y2=s->height-1;
528  y2-=y1; if(y2<=0) {
529  UNLOCK(s->cursorMutex);
530  return;
531  }
532 
533  /* get saved data */
534  for(j=0;j<y2;j++)
535  memcpy(s->frameBuffer+(y1+j)*rowstride+x1*bpp,
536  s->underCursorBuffer+j*x2*bpp,
537  x2*bpp);
538 
539  /* Copy to all scaled versions */
540  rfbScaledScreenUpdate(s, x1, y1, x1+x2, y1+y2);
541 
542  UNLOCK(s->cursorMutex);
543 }
544 
545 void rfbShowCursor(rfbClientPtr cl)
546 {
547  rfbScreenInfoPtr s=cl->screen;
548  rfbCursorPtr c=s->cursor;
549  int i,j,x1,x2,y1,y2,i1,j1,bpp=s->serverFormat.bitsPerPixel/8,
550  rowstride=s->paddedWidthInBytes,
551  bufSize,w;
552  rfbBool wasChanged=FALSE;
553 
554  if(!c) return;
555  LOCK(s->cursorMutex);
556 
557  bufSize=c->width*c->height*bpp;
558  w=(c->width+7)/8;
559  if(s->underCursorBufferLen<bufSize) {
560  if(s->underCursorBuffer!=NULL)
561  free(s->underCursorBuffer);
562  s->underCursorBuffer=malloc(bufSize);
563  s->underCursorBufferLen=bufSize;
564  }
565 
566  /* save what is under the cursor */
567  i1=j1=0; /* offset in cursor */
568  x1=cl->cursorX-c->xhot;
569  x2=x1+c->width;
570  if(x1<0) { i1=-x1; x1=0; }
571  if(x2>=s->width) x2=s->width-1;
572  x2-=x1; if(x2<=0) {
573  UNLOCK(s->cursorMutex);
574  return; /* nothing to do */
575  }
576 
577  y1=cl->cursorY-c->yhot;
578  y2=y1+c->height;
579  if(y1<0) { j1=-y1; y1=0; }
580  if(y2>=s->height) y2=s->height-1;
581  y2-=y1; if(y2<=0) {
582  UNLOCK(s->cursorMutex);
583  return; /* nothing to do */
584  }
585 
586  /* save data */
587  for(j=0;j<y2;j++) {
588  char* dest=s->underCursorBuffer+j*x2*bpp;
589  const char* src=s->frameBuffer+(y1+j)*rowstride+x1*bpp;
590  unsigned int count=x2*bpp;
591  if(wasChanged || memcmp(dest,src,count)) {
592  wasChanged=TRUE;
593  memcpy(dest,src,count);
594  }
595  }
596 
597  if(!c->richSource)
599 
600  if (c->alphaSource) {
601  int rmax, rshift;
602  int gmax, gshift;
603  int bmax, bshift;
604  int amax = 255; /* alphaSource is always 8bits of info per pixel */
605  unsigned int rmask, gmask, bmask;
606 
607  rmax = s->serverFormat.redMax;
608  gmax = s->serverFormat.greenMax;
609  bmax = s->serverFormat.blueMax;
610  rshift = s->serverFormat.redShift;
611  gshift = s->serverFormat.greenShift;
612  bshift = s->serverFormat.blueShift;
613 
614  rmask = (rmax << rshift);
615  gmask = (gmax << gshift);
616  bmask = (bmax << bshift);
617 
618  for(j=0;j<y2;j++) {
619  for(i=0;i<x2;i++) {
620  /*
621  * we loop over the whole cursor ignoring c->mask[],
622  * using the extracted alpha value instead.
623  */
624  char *dest;
625  unsigned char *src, *aptr;
626  unsigned int val, dval, sval;
627  int rdst, gdst, bdst; /* fb RGB */
628  int asrc, rsrc, gsrc, bsrc; /* rich source ARGB */
629 
630  dest = s->frameBuffer + (j+y1)*rowstride + (i+x1)*bpp;
631  src = c->richSource + (j+j1)*c->width*bpp + (i+i1)*bpp;
632  aptr = c->alphaSource + (j+j1)*c->width + (i+i1);
633 
634  asrc = *aptr;
635  if (!asrc) {
636  continue;
637  }
638 
639  if (bpp == 1) {
640  dval = *((unsigned char*) dest);
641  sval = *((unsigned char*) src);
642  } else if (bpp == 2) {
643  dval = *((unsigned short*) dest);
644  sval = *((unsigned short*) src);
645  } else if (bpp == 3) {
646  unsigned char *dst = (unsigned char *) dest;
647  dval = 0;
648  dval |= ((*(dst+0)) << 0);
649  dval |= ((*(dst+1)) << 8);
650  dval |= ((*(dst+2)) << 16);
651  sval = 0;
652  sval |= ((*(src+0)) << 0);
653  sval |= ((*(src+1)) << 8);
654  sval |= ((*(src+2)) << 16);
655  } else if (bpp == 4) {
656  dval = *((unsigned int*) dest);
657  sval = *((unsigned int*) src);
658  } else {
659  continue;
660  }
661 
662  /* extract dest and src RGB */
663  rdst = (dval & rmask) >> rshift; /* fb */
664  gdst = (dval & gmask) >> gshift;
665  bdst = (dval & bmask) >> bshift;
666 
667  rsrc = (sval & rmask) >> rshift; /* richcursor */
668  gsrc = (sval & gmask) >> gshift;
669  bsrc = (sval & bmask) >> bshift;
670 
671  /* blend in fb data. */
672  if (! c->alphaPreMultiplied) {
673  rsrc = (asrc * rsrc)/amax;
674  gsrc = (asrc * gsrc)/amax;
675  bsrc = (asrc * bsrc)/amax;
676  }
677  rdst = rsrc + ((amax - asrc) * rdst)/amax;
678  gdst = gsrc + ((amax - asrc) * gdst)/amax;
679  bdst = bsrc + ((amax - asrc) * bdst)/amax;
680 
681  val = 0;
682  val |= (rdst << rshift);
683  val |= (gdst << gshift);
684  val |= (bdst << bshift);
685 
686  /* insert the cooked pixel into the fb */
687  memcpy(dest, &val, bpp);
688  }
689  }
690  } else {
691  /* now the cursor has to be drawn */
692  for(j=0;j<y2;j++)
693  for(i=0;i<x2;i++)
694  if((c->mask[(j+j1)*w+(i+i1)/8]<<((i+i1)&7))&0x80)
695  memcpy(s->frameBuffer+(j+y1)*rowstride+(i+x1)*bpp,
696  c->richSource+(j+j1)*c->width*bpp+(i+i1)*bpp,bpp);
697  }
698 
699  /* Copy to all scaled versions */
700  rfbScaledScreenUpdate(s, x1, y1, x1+x2, y1+y2);
701 
702  UNLOCK(s->cursorMutex);
703 }
704 
705 /*
706  * If enableCursorShapeUpdates is FALSE, and the cursor is hidden, make sure
707  * that if the frameBuffer was transmitted with a cursor drawn, then that
708  * region gets redrawn.
709  */
710 
711 void rfbRedrawAfterHideCursor(rfbClientPtr cl,sraRegionPtr updateRegion)
712 {
713  rfbScreenInfoPtr s = cl->screen;
714  rfbCursorPtr c = s->cursor;
715 
716  if(c) {
717  int x,y,x2,y2;
718 
719  x = cl->cursorX-c->xhot;
720  y = cl->cursorY-c->yhot;
721  x2 = x+c->width;
722  y2 = y+c->height;
723 
724  if(sraClipRect2(&x,&y,&x2,&y2,0,0,s->width,s->height)) {
725  sraRegionPtr rect;
726  rect = sraRgnCreateRect(x,y,x2,y2);
727  if(updateRegion) {
728  sraRgnOr(updateRegion,rect);
729  } else {
730  LOCK(cl->updateMutex);
731  sraRgnOr(cl->modifiedRegion,rect);
732  UNLOCK(cl->updateMutex);
733  }
734  sraRgnDestroy(rect);
735  }
736  }
737 }
738 
739 #ifdef DEBUG
740 
741 static void rfbPrintXCursor(rfbCursorPtr cursor)
742 {
743  int i,i1,j,w=(cursor->width+7)/8;
744  unsigned char bit;
745  for(j=0;j<cursor->height;j++) {
746  for(i=0,i1=0,bit=0x80;i1<cursor->width;i1++,i+=(bit&1)?1:0,bit=(bit&1)?0x80:bit>>1)
747  if(cursor->source[j*w+i]&bit) putchar('#'); else putchar(' ');
748  putchar(':');
749  for(i=0,i1=0,bit=0x80;i1<cursor->width;i1++,i+=(bit&1)?1:0,bit=(bit&1)?0x80:bit>>1)
750  if(cursor->mask[j*w+i]&bit) putchar('#'); else putchar(' ');
751  putchar('\n');
752  }
753 }
754 
755 #endif
756 
757 void rfbSetCursor(rfbScreenInfoPtr rfbScreen,rfbCursorPtr c)
758 {
759  rfbClientIteratorPtr iterator;
760  rfbClientPtr cl;
761 
762  LOCK(rfbScreen->cursorMutex);
763 
764  if(rfbScreen->cursor) {
765  iterator=rfbGetClientIterator(rfbScreen);
766  while((cl=rfbClientIteratorNext(iterator)))
767  if(!cl->enableCursorShapeUpdates)
768  rfbRedrawAfterHideCursor(cl,NULL);
769  rfbReleaseClientIterator(iterator);
770 
771  if(rfbScreen->cursor->cleanup)
772  rfbFreeCursor(rfbScreen->cursor);
773  }
774 
775  rfbScreen->cursor = c;
776 
777  iterator=rfbGetClientIterator(rfbScreen);
778  while((cl=rfbClientIteratorNext(iterator))) {
779  cl->cursorWasChanged = TRUE;
780  if(!cl->enableCursorShapeUpdates)
781  rfbRedrawAfterHideCursor(cl,NULL);
782  }
783  rfbReleaseClientIterator(iterator);
784 
785  UNLOCK(rfbScreen->cursorMutex);
786 }
787 
void rfbScaledScreenUpdate(rfbScreenInfoPtr screen, int x1, int y1, int x2, int y2)
Definition: scale.c:258
char * rfbMakeMaskFromAlphaSource(int width, int height, unsigned char *alphaSource)
Definition: cursor.c:325
int x
Definition: SDLvncviewer.c:34
rfbCursorPtr rfbMakeXCursor(int width, int height, char *cursorString, char *maskString)
Definition: cursor.c:254
sraRegion * sraRgnCreateRect(int x1, int y1, int x2, int y2)
Definition: rfbregion.c:520
rfbClientIteratorPtr rfbGetClientIterator(rfbScreenInfoPtr rfbScreen)
Definition: rfbserver.c:167
uint8_t backGreen
Definition: rfbproto.h:906
#define TRUE
Definition: rfbproto.h:112
uint16_t redMax
Definition: rfbproto.h:173
#define UNLOCK(mutex)
Definition: threading.h:83
char * rfbMakeMaskForXCursor(int width, int height, char *source)
Definition: cursor.c:297
struct sraRegion * sraRegionPtr
Definition: rfb.h:381
#define Swap32IfLE(l)
Definition: rfb.h:718
int8_t rfbBool
Definition: rfbproto.h:108
char mask
Definition: SDLvncviewer.c:19
unsigned char rfbReverseByte[0x100]
Definition: cursor.c:209
#define height
Definition: vncev.c:19
#define SETRGB(u)
uint8_t blueShift
Definition: rfbproto.h:195
#define UPDATE_BUF_SIZE
UPDATE_BUF_SIZE must be big enough to send at least one whole line of the framebuffer.
Definition: rfb.h:558
uint8_t greenShift
Definition: rfbproto.h:193
uint16_t y
Definition: rfbproto.h:142
rfbBool rfbSendUpdateBuf(rfbClientPtr cl)
Definition: rfbserver.c:3615
uint16_t h
Definition: rfbproto.h:144
uint8_t foreGreen
Definition: rfbproto.h:903
void rfbSetCursor(rfbScreenInfoPtr rfbScreen, rfbCursorPtr c)
Definition: cursor.c:757
uint16_t w
Definition: rfbproto.h:143
void rfbShowCursor(rfbClientPtr cl)
Definition: cursor.c:545
#define sz_rfbXCursorColors
Definition: rfbproto.h:910
rfbClientPtr rfbClientIteratorNext(rfbClientIteratorPtr iterator)
Definition: rfbserver.c:208
void rfbStatRecordEncodingSent(rfbClientPtr cl, uint32_t type, int byteCount, int byteIfRaw)
Definition: stats.c:220
uint8_t bitsPerPixel
Definition: rfbproto.h:156
uint16_t x
Definition: rfbproto.h:141
void rfbMakeRichCursorFromXCursor(rfbScreenInfoPtr rfbScreen, rfbCursorPtr cursor)
Definition: cursor.c:469
int y
Definition: SDLvncviewer.c:34
uint8_t trueColour
Definition: rfbproto.h:166
void rfbHideCursor(rfbClientPtr cl)
Definition: cursor.c:503
#define rfbEncodingPointerPos
Definition: rfbproto.h:504
void rfbConvertLSBCursorBitmapOrMask(int width, int height, unsigned char *bitmap)
Definition: cursor.c:245
void sraRgnDestroy(sraRegion *rgn)
Definition: rfbregion.c:545
#define LOCK(mutex)
Definition: threading.h:82
rfbBool rfbSendCursorPos(rfbClientPtr cl)
Definition: cursor.c:181
uint8_t redShift
Definition: rfbproto.h:181
#define sz_rfbFramebufferUpdateRectHeader
Definition: rfbproto.h:567
void rfbMakeXCursorFromRichCursor(rfbScreenInfoPtr rfbScreen, rfbCursorPtr cursor)
Definition: cursor.c:391
#define rfbEncodingRichCursor
Definition: rfbproto.h:503
void rfbFreeCursor(rfbCursorPtr cursor)
Definition: cursor.c:367
void sraRgnOr(sraRegion *dst, const sraRegion *src)
Definition: rfbregion.c:562
Definition: rfb.h:896
uint16_t blueMax
Definition: rfbproto.h:179
uint16_t greenMax
Definition: rfbproto.h:177
rfbBool rfbSendCursorShape(rfbClientPtr cl)
Definition: cursor.c:36
uint8_t backBlue
Definition: rfbproto.h:907
void rfbReleaseClientIterator(rfbClientIteratorPtr iterator)
Definition: rfbserver.c:234
uint8_t bigEndian
Definition: rfbproto.h:160
#define FALSE
Definition: rfbproto.h:110
uint8_t foreBlue
Definition: rfbproto.h:904
uint8_t foreRed
Definition: rfbproto.h:902
#define width
Definition: vncev.c:18
uint8_t backRed
Definition: rfbproto.h:905
#define rfbEncodingXCursor
Definition: rfbproto.h:502
rfbBool sraClipRect2(int *x, int *y, int *x2, int *y2, int cx, int cy, int cx2, int cy2)
Definition: rfbregion.c:813
void rfbRedrawAfterHideCursor(rfbClientPtr cl, sraRegionPtr updateRegion)
Definition: cursor.c:711
#define Swap16IfLE(s)
Definition: rfb.h:716