blob: ce8e7f0258f180cb1353003fe315533ed91163af [file] [log] [blame]
Constantin Kaplinsky95f6f7a2006-04-17 04:17:23 +00001/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
2 *
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +00003 * This is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This software is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this software; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
16 * USA.
17 */
18
19#include <stdio.h>
20#include "XserverDesktop.h"
21#include "vncHooks.h"
22
23extern "C" {
24#define class c_class
25#define private c_private
26#include "scrnintstr.h"
27#include "windowstr.h"
28#include "gcstruct.h"
29#include "regionstr.h"
30#include "dixfontstr.h"
31#include "colormapst.h"
Peter Åstrandf1794c32005-03-10 13:28:04 +000032#ifdef RENDER
33#include "picturestr.h"
34#endif
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +000035
36#ifdef GC_HAS_COMPOSITE_CLIP
37#define COMPOSITE_CLIP(gc) ((gc)->pCompositeClip)
38#else
39#include "mfb.h"
40#define COMPOSITE_CLIP(gc) \
41 (((mfbPrivGCPtr)((gc)->devPrivates[mfbGCPrivateIndex].ptr))->pCompositeClip)
42#endif
43
44#undef class
45#undef private
46}
47
48#include "RegionHelper.h"
49
50#define DBGPRINT(x) //(fprintf x)
51
52// MAX_RECTS_PER_OP is the maximum number of rectangles we generate from
53// operations like Polylines and PolySegment. If the operation is more complex
54// than this, we simply use the bounding box. Ideally it would be a
55// command-line option, but that would involve an extra malloc each time, so we
56// fix it here.
57#define MAX_RECTS_PER_OP 5
58
59static unsigned long vncHooksGeneration = 0;
60
61// vncHooksScreenRec and vncHooksGCRec contain pointers to the original
62// functions which we "wrap" in order to hook the screen changes. The screen
63// functions are each wrapped individually, while the GC "funcs" and "ops" are
64// wrapped as a unit.
65
66typedef struct {
67 XserverDesktop* desktop;
68
69 CloseScreenProcPtr CloseScreen;
70 CreateGCProcPtr CreateGC;
71 PaintWindowBackgroundProcPtr PaintWindowBackground;
72 PaintWindowBorderProcPtr PaintWindowBorder;
73 CopyWindowProcPtr CopyWindow;
74 ClearToBackgroundProcPtr ClearToBackground;
75 RestoreAreasProcPtr RestoreAreas;
76 InstallColormapProcPtr InstallColormap;
77 StoreColorsProcPtr StoreColors;
78 DisplayCursorProcPtr DisplayCursor;
79 ScreenBlockHandlerProcPtr BlockHandler;
Peter Åstrandf1794c32005-03-10 13:28:04 +000080#ifdef RENDER
81 CompositeProcPtr Composite;
82#endif
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +000083} vncHooksScreenRec, *vncHooksScreenPtr;
84
85typedef struct {
86 GCFuncs *wrappedFuncs;
87 GCOps *wrappedOps;
88} vncHooksGCRec, *vncHooksGCPtr;
89
90static int vncHooksScreenIndex;
91static int vncHooksGCIndex;
92
93
94// screen functions
95
96static Bool vncHooksCloseScreen(int i, ScreenPtr pScreen);
97static Bool vncHooksCreateGC(GCPtr pGC);
98static void vncHooksPaintWindowBackground(WindowPtr pWin, RegionPtr pRegion,
99 int what);
100static void vncHooksPaintWindowBorder(WindowPtr pWin, RegionPtr pRegion,
101 int what);
102static void vncHooksCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg,
103 RegionPtr pOldRegion);
104static void vncHooksClearToBackground(WindowPtr pWin, int x, int y, int w,
105 int h, Bool generateExposures);
106static RegionPtr vncHooksRestoreAreas(WindowPtr pWin, RegionPtr prgnExposed);
107static void vncHooksInstallColormap(ColormapPtr pColormap);
108static void vncHooksStoreColors(ColormapPtr pColormap, int ndef,
109 xColorItem* pdef);
110static Bool vncHooksDisplayCursor(ScreenPtr pScreen, CursorPtr cursor);
111static void vncHooksBlockHandler(int i, pointer blockData, pointer pTimeout,
112 pointer pReadmask);
Peter Åstrandf1794c32005-03-10 13:28:04 +0000113#ifdef RENDER
114static void vncHooksComposite(CARD8 op, PicturePtr pSrc, PicturePtr pMask,
115 PicturePtr pDst, INT16 xSrc, INT16 ySrc, INT16 xMask,
116 INT16 yMask, INT16 xDst, INT16 yDst, CARD16 width, CARD16 height);
117#endif
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000118
119// GC "funcs"
120
121static void vncHooksValidateGC(GCPtr pGC, unsigned long changes,
122 DrawablePtr pDrawable);
123static void vncHooksChangeGC(GCPtr pGC, unsigned long mask);
124static void vncHooksCopyGC(GCPtr src, unsigned long mask, GCPtr dst);
125static void vncHooksDestroyGC(GCPtr pGC);
126static void vncHooksChangeClip(GCPtr pGC, int type, pointer pValue,int nrects);
127static void vncHooksDestroyClip(GCPtr pGC);
128static void vncHooksCopyClip(GCPtr dst, GCPtr src);
129
130static GCFuncs vncHooksGCFuncs = {
131 vncHooksValidateGC, vncHooksChangeGC, vncHooksCopyGC, vncHooksDestroyGC,
132 vncHooksChangeClip, vncHooksDestroyClip, vncHooksCopyClip,
133};
134
135// GC "ops"
136
137static void vncHooksFillSpans(DrawablePtr pDrawable, GCPtr pGC, int nInit,
138 DDXPointPtr pptInit, int *pwidthInit,
139 int fSorted);
140static void vncHooksSetSpans(DrawablePtr pDrawable, GCPtr pGC, char *psrc,
141 DDXPointPtr ppt, int *pwidth, int nspans,
142 int fSorted);
143static void vncHooksPutImage(DrawablePtr pDrawable, GCPtr pGC, int depth,
144 int x, int y, int w, int h, int leftPad,
145 int format, char *pBits);
146static RegionPtr vncHooksCopyArea(DrawablePtr pSrc, DrawablePtr pDst,
147 GCPtr pGC, int srcx, int srcy, int w, int h,
148 int dstx, int dsty);
149static RegionPtr vncHooksCopyPlane(DrawablePtr pSrc, DrawablePtr pDst,
150 GCPtr pGC, int srcx, int srcy, int w, int h,
151 int dstx, int dsty, unsigned long plane);
152static void vncHooksPolyPoint(DrawablePtr pDrawable, GCPtr pGC, int mode,
153 int npt, xPoint *pts);
154static void vncHooksPolylines(DrawablePtr pDrawable, GCPtr pGC, int mode,
155 int npt, DDXPointPtr ppts);
156static void vncHooksPolySegment(DrawablePtr pDrawable, GCPtr pGC, int nseg,
157 xSegment *segs);
158static void vncHooksPolyRectangle(DrawablePtr pDrawable, GCPtr pGC, int nrects,
159 xRectangle *rects);
160static void vncHooksPolyArc(DrawablePtr pDrawable, GCPtr pGC, int narcs,
161 xArc *arcs);
162static void vncHooksFillPolygon(DrawablePtr pDrawable, GCPtr pGC, int shape,
163 int mode, int count, DDXPointPtr pts);
164static void vncHooksPolyFillRect(DrawablePtr pDrawable, GCPtr pGC, int nrects,
165 xRectangle *rects);
166static void vncHooksPolyFillArc(DrawablePtr pDrawable, GCPtr pGC, int narcs,
167 xArc *arcs);
168static int vncHooksPolyText8(DrawablePtr pDrawable, GCPtr pGC, int x, int y,
169 int count, char *chars);
170static int vncHooksPolyText16(DrawablePtr pDrawable, GCPtr pGC, int x, int y,
171 int count, unsigned short *chars);
172static void vncHooksImageText8(DrawablePtr pDrawable, GCPtr pGC, int x, int y,
173 int count, char *chars);
174static void vncHooksImageText16(DrawablePtr pDrawable, GCPtr pGC, int x, int y,
175 int count, unsigned short *chars);
176static void vncHooksImageGlyphBlt(DrawablePtr pDrawable, GCPtr pGC, int x,
177 int y, unsigned int nglyph,
178 CharInfoPtr *ppci, pointer pglyphBase);
179static void vncHooksPolyGlyphBlt(DrawablePtr pDrawable, GCPtr pGC, int x,
180 int y, unsigned int nglyph,
181 CharInfoPtr *ppci, pointer pglyphBase);
182static void vncHooksPushPixels(GCPtr pGC, PixmapPtr pBitMap,
183 DrawablePtr pDrawable, int w, int h, int x,
184 int y);
185
186static GCOps vncHooksGCOps = {
187 vncHooksFillSpans, vncHooksSetSpans, vncHooksPutImage, vncHooksCopyArea,
188 vncHooksCopyPlane, vncHooksPolyPoint, vncHooksPolylines, vncHooksPolySegment,
189 vncHooksPolyRectangle, vncHooksPolyArc, vncHooksFillPolygon,
190 vncHooksPolyFillRect, vncHooksPolyFillArc, vncHooksPolyText8,
191 vncHooksPolyText16, vncHooksImageText8, vncHooksImageText16,
192 vncHooksImageGlyphBlt, vncHooksPolyGlyphBlt, vncHooksPushPixels
193};
194
195
196
197/////////////////////////////////////////////////////////////////////////////
198// vncHooksInit() is called at initialisation time and every time the server
199// resets. It is called once for each screen, but the indexes are only
200// allocated once for each server generation.
201
202Bool vncHooksInit(ScreenPtr pScreen, XserverDesktop* desktop)
203{
204 vncHooksScreenPtr vncHooksScreen;
205
206 if (vncHooksGeneration != serverGeneration) {
207 vncHooksGeneration = serverGeneration;
208
209 vncHooksScreenIndex = AllocateScreenPrivateIndex();
210 if (vncHooksScreenIndex < 0) {
211 ErrorF("vncHooksInit: AllocateScreenPrivateIndex failed\n");
212 return FALSE;
213 }
214
215 vncHooksGCIndex = AllocateGCPrivateIndex();
216 if (vncHooksGCIndex < 0) {
217 ErrorF("vncHooksInit: AllocateGCPrivateIndex failed\n");
218 return FALSE;
219 }
220 }
221
222 if (!AllocateGCPrivate(pScreen, vncHooksGCIndex, sizeof(vncHooksGCRec))) {
223 ErrorF("vncHooksInit: AllocateGCPrivate failed\n");
224 return FALSE;
225 }
226
227 vncHooksScreen = (vncHooksScreenPtr)xnfalloc(sizeof(vncHooksScreenRec));
228 pScreen->devPrivates[vncHooksScreenIndex].ptr = (pointer)vncHooksScreen;
229
230 vncHooksScreen->desktop = desktop;
231
232 vncHooksScreen->CloseScreen = pScreen->CloseScreen;
233 vncHooksScreen->CreateGC = pScreen->CreateGC;
234 vncHooksScreen->PaintWindowBackground = pScreen->PaintWindowBackground;
235 vncHooksScreen->PaintWindowBorder = pScreen->PaintWindowBorder;
236 vncHooksScreen->CopyWindow = pScreen->CopyWindow;
237 vncHooksScreen->ClearToBackground = pScreen->ClearToBackground;
238 vncHooksScreen->RestoreAreas = pScreen->RestoreAreas;
239 vncHooksScreen->InstallColormap = pScreen->InstallColormap;
240 vncHooksScreen->StoreColors = pScreen->StoreColors;
241 vncHooksScreen->DisplayCursor = pScreen->DisplayCursor;
242 vncHooksScreen->BlockHandler = pScreen->BlockHandler;
Peter Åstrandf1794c32005-03-10 13:28:04 +0000243#ifdef RENDER
244 PictureScreenPtr ps;
245 ps = GetPictureScreenIfSet(pScreen);
246 if (ps) {
247 vncHooksScreen->Composite = ps->Composite;
248 }
249#endif
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000250
251 pScreen->CloseScreen = vncHooksCloseScreen;
252 pScreen->CreateGC = vncHooksCreateGC;
253 pScreen->PaintWindowBackground = vncHooksPaintWindowBackground;
254 pScreen->PaintWindowBorder = vncHooksPaintWindowBorder;
255 pScreen->CopyWindow = vncHooksCopyWindow;
256 pScreen->ClearToBackground = vncHooksClearToBackground;
257 pScreen->RestoreAreas = vncHooksRestoreAreas;
258 pScreen->InstallColormap = vncHooksInstallColormap;
259 pScreen->StoreColors = vncHooksStoreColors;
260 pScreen->DisplayCursor = vncHooksDisplayCursor;
261 pScreen->BlockHandler = vncHooksBlockHandler;
Peter Åstrandf1794c32005-03-10 13:28:04 +0000262#ifdef RENDER
263 if (ps) {
264 ps->Composite = vncHooksComposite;
265 }
266#endif
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000267
268 return TRUE;
269}
270
271
272
273/////////////////////////////////////////////////////////////////////////////
274//
275// screen functions
276//
277
278// SCREEN_UNWRAP and SCREEN_REWRAP unwrap and rewrap the given screen function.
279// It would be nice to do this with a C++ class, but each function is of a
280// distinct type, so it would have to use templates, and it's not worth that
281// much pain.
282
283#define SCREEN_UNWRAP(scrn,field) \
284 ScreenPtr pScreen = scrn; \
285 vncHooksScreenPtr vncHooksScreen \
286 = ((vncHooksScreenPtr)pScreen->devPrivates[vncHooksScreenIndex].ptr); \
287 pScreen->field = vncHooksScreen->field; \
288 DBGPRINT((stderr,"vncHooks" #field " called\n"));
289
290#define SCREEN_REWRAP(field) pScreen->field = vncHooks##field;
291
292
293// CloseScreen - unwrap the screen functions and call the original CloseScreen
294// function
295
296static Bool vncHooksCloseScreen(int i, ScreenPtr pScreen_)
297{
298 SCREEN_UNWRAP(pScreen_, CloseScreen);
299
300 pScreen->CreateGC = vncHooksScreen->CreateGC;
301 pScreen->PaintWindowBackground = vncHooksScreen->PaintWindowBackground;
302 pScreen->PaintWindowBorder = vncHooksScreen->PaintWindowBorder;
303 pScreen->CopyWindow = vncHooksScreen->CopyWindow;
304 pScreen->ClearToBackground = vncHooksScreen->ClearToBackground;
305 pScreen->RestoreAreas = vncHooksScreen->RestoreAreas;
306 pScreen->InstallColormap = vncHooksScreen->InstallColormap;
307 pScreen->StoreColors = vncHooksScreen->StoreColors;
308 pScreen->DisplayCursor = vncHooksScreen->DisplayCursor;
309 pScreen->BlockHandler = vncHooksScreen->BlockHandler;
310
311 xfree((pointer)vncHooksScreen);
312
313 DBGPRINT((stderr,"vncHooksCloseScreen: unwrapped screen functions\n"));
314
315 return (*pScreen->CloseScreen)(i, pScreen);
316}
317
318// CreateGC - wrap the "GC funcs"
319
320static Bool vncHooksCreateGC(GCPtr pGC)
321{
322 SCREEN_UNWRAP(pGC->pScreen, CreateGC);
323
324 vncHooksGCPtr vncHooksGC
325 = (vncHooksGCPtr)pGC->devPrivates[vncHooksGCIndex].ptr;
326
327 Bool ret = (*pScreen->CreateGC) (pGC);
328
329 vncHooksGC->wrappedOps = 0;
330 vncHooksGC->wrappedFuncs = pGC->funcs;
331 pGC->funcs = &vncHooksGCFuncs;
332
333 SCREEN_REWRAP(CreateGC);
334
335 return ret;
336}
337
338// PaintWindowBackground - changed region is the given region
339
340static void vncHooksPaintWindowBackground(WindowPtr pWin, RegionPtr pRegion,
341 int what)
342{
343 SCREEN_UNWRAP(pWin->drawable.pScreen, PaintWindowBackground);
344
345 RegionHelper changed(pScreen, pRegion);
346
347 (*pScreen->PaintWindowBackground) (pWin, pRegion, what);
348
349 vncHooksScreen->desktop->add_changed(changed.reg);
350
351 SCREEN_REWRAP(PaintWindowBackground);
352}
353
354// PaintWindowBorder - changed region is the given region
355
356static void vncHooksPaintWindowBorder(WindowPtr pWin, RegionPtr pRegion,
357 int what)
358{
359 SCREEN_UNWRAP(pWin->drawable.pScreen, PaintWindowBorder);
360
361 RegionHelper changed(pScreen, pRegion);
362
363 (*pScreen->PaintWindowBorder) (pWin, pRegion, what);
364
365 vncHooksScreen->desktop->add_changed(changed.reg);
366
367 SCREEN_REWRAP(PaintWindowBorder);
368}
369
370// CopyWindow - destination of the copy is the old region, clipped by
371// borderClip, translated by the delta. This call only does the copy - it
372// doesn't affect any other bits.
373
374static void vncHooksCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg,
375 RegionPtr pOldRegion)
376{
377 SCREEN_UNWRAP(pWin->drawable.pScreen, CopyWindow);
378
379 RegionHelper copied(pScreen, pOldRegion);
380 int dx = pWin->drawable.x - ptOldOrg.x;
381 int dy = pWin->drawable.y - ptOldOrg.y;
382 REGION_TRANSLATE(pScreen, copied.reg, dx, dy);
383 REGION_INTERSECT(pWin->drawable.pScreen, copied.reg, copied.reg,
384 &pWin->borderClip);
385
386 (*pScreen->CopyWindow) (pWin, ptOldOrg, pOldRegion);
387
388 vncHooksScreen->desktop->add_copied(copied.reg, dx, dy);
389
390 SCREEN_REWRAP(CopyWindow);
391}
392
393// ClearToBackground - changed region is the given rectangle, clipped by
394// clipList, but only if generateExposures is false.
395
396static void vncHooksClearToBackground(WindowPtr pWin, int x, int y, int w,
397 int h, Bool generateExposures)
398{
399 SCREEN_UNWRAP(pWin->drawable.pScreen, ClearToBackground);
400
401 BoxRec box;
402 box.x1 = x + pWin->drawable.x;
403 box.y1 = y + pWin->drawable.y;
404 box.x2 = w ? (box.x1 + w) : (pWin->drawable.x + pWin->drawable.width);
405 box.y2 = h ? (box.y1 + h) : (pWin->drawable.y + pWin->drawable.height);
406
407 RegionHelper changed(pScreen, &box, 0);
408
409 REGION_INTERSECT(pScreen, changed.reg, changed.reg, &pWin->clipList);
410
411 (*pScreen->ClearToBackground) (pWin, x, y, w, h, generateExposures);
412
413 if (!generateExposures) {
414 vncHooksScreen->desktop->add_changed(changed.reg);
415 }
416
417 SCREEN_REWRAP(ClearToBackground);
418}
419
420// RestoreAreas - changed region is the given region
421
422static RegionPtr vncHooksRestoreAreas(WindowPtr pWin, RegionPtr pRegion)
423{
424 SCREEN_UNWRAP(pWin->drawable.pScreen, RestoreAreas);
425
426 RegionHelper changed(pScreen, pRegion);
427
428 RegionPtr result = (*pScreen->RestoreAreas) (pWin, pRegion);
429
430 vncHooksScreen->desktop->add_changed(changed.reg);
431
432 SCREEN_REWRAP(RestoreAreas);
433
434 return result;
435}
436
437// InstallColormap - get the new colormap
438
439static void vncHooksInstallColormap(ColormapPtr pColormap)
440{
441 SCREEN_UNWRAP(pColormap->pScreen, InstallColormap);
442
443 (*pScreen->InstallColormap) (pColormap);
444
445 vncHooksScreen->desktop->setColormap(pColormap);
446
447 SCREEN_REWRAP(InstallColormap);
448}
449
450// StoreColors - get the colormap changes
451
452static void vncHooksStoreColors(ColormapPtr pColormap, int ndef,
453 xColorItem* pdef)
454{
455 SCREEN_UNWRAP(pColormap->pScreen, StoreColors);
456
457 (*pScreen->StoreColors) (pColormap, ndef, pdef);
458
459 vncHooksScreen->desktop->setColourMapEntries(pColormap, ndef, pdef);
460
461 SCREEN_REWRAP(StoreColors);
462}
463
464// DisplayCursor - get the cursor shape
465
466static Bool vncHooksDisplayCursor(ScreenPtr pScreen_, CursorPtr cursor)
467{
468 SCREEN_UNWRAP(pScreen_, DisplayCursor);
469
470 Bool ret = (*pScreen->DisplayCursor) (pScreen, cursor);
471
472 vncHooksScreen->desktop->setCursor(cursor);
473
474 SCREEN_REWRAP(DisplayCursor);
475
476 return ret;
477}
478
479// BlockHandler - ignore any changes during the block handler - it's likely
480// these are just drawing the cursor.
481
482static void vncHooksBlockHandler(int i, pointer blockData, pointer pTimeout,
483 pointer pReadmask)
484{
485 SCREEN_UNWRAP(screenInfo.screens[i], BlockHandler);
486
487 vncHooksScreen->desktop->ignoreHooks(true);
488
489 (*pScreen->BlockHandler) (i, blockData, pTimeout, pReadmask);
490
491 vncHooksScreen->desktop->ignoreHooks(false);
492
493 SCREEN_REWRAP(BlockHandler);
494}
495
Peter Åstrandf1794c32005-03-10 13:28:04 +0000496// Composite - needed for RENDER
497
498#ifdef RENDER
499void vncHooksComposite(CARD8 op, PicturePtr pSrc, PicturePtr pMask,
500 PicturePtr pDst, INT16 xSrc, INT16 ySrc, INT16 xMask,
501 INT16 yMask, INT16 xDst, INT16 yDst, CARD16 width, CARD16 height)
502{
503 ScreenPtr pScreen = pDst->pDrawable->pScreen;
504 vncHooksScreenPtr vncHooksScreen = ((vncHooksScreenPtr)pScreen->devPrivates[vncHooksScreenIndex].ptr);
505 BoxRec box;
506 PictureScreenPtr ps = GetPictureScreen(pScreen);
Peter Åstrandd77d6aa2005-08-17 08:33:29 +0000507 rfb::Rect rect1, rect2;
Peter Åstrandf1794c32005-03-10 13:28:04 +0000508
Peter Åstrandd77d6aa2005-08-17 08:33:29 +0000509 rect1.setXYWH(pDst->pDrawable->x + xDst,
510 pDst->pDrawable->y + yDst,
511 width,
512 height);
513
514 rect2 = rect1.intersect(vncHooksScreen->desktop->getRect());
515 if (!rect2.is_empty()) {
516 box.x1 = rect2.tl.x;
517 box.y1 = rect2.tl.y;
518 box.x2 = rect2.br.x;
519 box.y2 = rect2.br.y;
520 RegionHelper changed(pScreen, &box, 0);
521 vncHooksScreen->desktop->add_changed(changed.reg);
522 }
Peter Åstrandf1794c32005-03-10 13:28:04 +0000523
524 ps->Composite = vncHooksScreen->Composite;
525 (*ps->Composite)(op, pSrc, pMask, pDst, xSrc, ySrc,
526 xMask, yMask, xDst, yDst, width, height);
527 ps->Composite = vncHooksComposite;
528}
529
530#endif /* RENDER */
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000531
532
533/////////////////////////////////////////////////////////////////////////////
534//
535// GC "funcs"
536//
537
538// GCFuncUnwrapper is a helper class which unwraps the GC funcs and ops in its
539// constructor and rewraps them in its destructor.
540
541class GCFuncUnwrapper {
542public:
543 GCFuncUnwrapper(GCPtr pGC_) : pGC(pGC_) {
544 vncHooksGC = (vncHooksGCPtr)pGC->devPrivates[vncHooksGCIndex].ptr;
545 pGC->funcs = vncHooksGC->wrappedFuncs;
546 if (vncHooksGC->wrappedOps)
547 pGC->ops = vncHooksGC->wrappedOps;
548 }
549 ~GCFuncUnwrapper() {
550 vncHooksGC->wrappedFuncs = pGC->funcs;
551 pGC->funcs = &vncHooksGCFuncs;
552 if (vncHooksGC->wrappedOps) {
553 vncHooksGC->wrappedOps = pGC->ops;
554 pGC->ops = &vncHooksGCOps;
555 }
556 }
557 GCPtr pGC;
558 vncHooksGCPtr vncHooksGC;
559};
560
561
562// ValidateGC - wrap the "ops" if a viewable window
563
564static void vncHooksValidateGC(GCPtr pGC, unsigned long changes,
565 DrawablePtr pDrawable)
566{
567 GCFuncUnwrapper u(pGC);
568
569 DBGPRINT((stderr,"vncHooksValidateGC called\n"));
570
571 (*pGC->funcs->ValidateGC) (pGC, changes, pDrawable);
572
573 u.vncHooksGC->wrappedOps = 0;
574 if (pDrawable->type == DRAWABLE_WINDOW && ((WindowPtr)pDrawable)->viewable) {
575 WindowPtr pWin = (WindowPtr)pDrawable;
576 RegionPtr pRegion = &pWin->clipList;
577
578 if (pGC->subWindowMode == IncludeInferiors)
579 pRegion = &pWin->borderClip;
580 if (REGION_NOTEMPTY(pDrawable->pScreen, pRegion)) {
581 u.vncHooksGC->wrappedOps = pGC->ops;
582 DBGPRINT((stderr,"vncHooksValidateGC: wrapped GC ops\n"));
583 }
584 }
585}
586
587// Other GC funcs - just unwrap and call on
588
589static void vncHooksChangeGC(GCPtr pGC, unsigned long mask) {
590 GCFuncUnwrapper u(pGC);
591 (*pGC->funcs->ChangeGC) (pGC, mask);
592}
593static void vncHooksCopyGC(GCPtr src, unsigned long mask, GCPtr dst) {
594 GCFuncUnwrapper u(dst);
595 (*dst->funcs->CopyGC) (src, mask, dst);
596}
597static void vncHooksDestroyGC(GCPtr pGC) {
598 GCFuncUnwrapper u(pGC);
599 (*pGC->funcs->DestroyGC) (pGC);
600}
601static void vncHooksChangeClip(GCPtr pGC, int type, pointer pValue, int nrects)
602{
603 GCFuncUnwrapper u(pGC);
604 (*pGC->funcs->ChangeClip) (pGC, type, pValue, nrects);
605}
606static void vncHooksDestroyClip(GCPtr pGC) {
607 GCFuncUnwrapper u(pGC);
608 (*pGC->funcs->DestroyClip) (pGC);
609}
610static void vncHooksCopyClip(GCPtr dst, GCPtr src) {
611 GCFuncUnwrapper u(dst);
612 (*dst->funcs->CopyClip) (dst, src);
613}
614
615
616/////////////////////////////////////////////////////////////////////////////
617//
618// GC "ops"
619//
620
621// GCOpUnwrapper is a helper class which unwraps the GC funcs and ops in its
622// constructor and rewraps them in its destructor.
623
624class GCOpUnwrapper {
625public:
626 GCOpUnwrapper(DrawablePtr pDrawable, GCPtr pGC_)
627 : pGC(pGC_), pScreen(pDrawable->pScreen)
628 {
629 vncHooksGC = (vncHooksGCPtr)pGC->devPrivates[vncHooksGCIndex].ptr;
630 oldFuncs = pGC->funcs;
631 pGC->funcs = vncHooksGC->wrappedFuncs;
632 pGC->ops = vncHooksGC->wrappedOps;
633 }
634 ~GCOpUnwrapper() {
635 vncHooksGC->wrappedOps = pGC->ops;
636 pGC->funcs = oldFuncs;
637 pGC->ops = &vncHooksGCOps;
638 }
639 GCPtr pGC;
640 vncHooksGCPtr vncHooksGC;
641 GCFuncs* oldFuncs;
642 ScreenPtr pScreen;
643};
644
645#define GC_OP_UNWRAPPER(pDrawable, pGC, name) \
646 GCOpUnwrapper u(pDrawable, pGC); \
647 ScreenPtr pScreen = (pDrawable)->pScreen; \
648 vncHooksScreenPtr vncHooksScreen \
649 = ((vncHooksScreenPtr)pScreen->devPrivates[vncHooksScreenIndex].ptr); \
650 DBGPRINT((stderr,"vncHooks" #name " called\n"));
651
652
653// FillSpans - changed region is the whole of borderClip. This is pessimistic,
654// but I believe this function is rarely used so it doesn't matter.
655
656static void vncHooksFillSpans(DrawablePtr pDrawable, GCPtr pGC, int nInit,
657 DDXPointPtr pptInit, int *pwidthInit,
658 int fSorted)
659{
660 GC_OP_UNWRAPPER(pDrawable, pGC, FillSpans);
661
662 RegionHelper changed(pScreen, &((WindowPtr)pDrawable)->borderClip);
663
664 (*pGC->ops->FillSpans) (pDrawable, pGC, nInit, pptInit, pwidthInit, fSorted);
665
666 vncHooksScreen->desktop->add_changed(changed.reg);
667}
668
669// SetSpans - changed region is the whole of borderClip. This is pessimistic,
670// but I believe this function is rarely used so it doesn't matter.
671
672static void vncHooksSetSpans(DrawablePtr pDrawable, GCPtr pGC, char *psrc,
673 DDXPointPtr ppt, int *pwidth, int nspans,
674 int fSorted)
675{
676 GC_OP_UNWRAPPER(pDrawable, pGC, SetSpans);
677
678 RegionHelper changed(pScreen, &((WindowPtr)pDrawable)->borderClip);
679
680 (*pGC->ops->SetSpans) (pDrawable, pGC, psrc, ppt, pwidth, nspans, fSorted);
681
682 vncHooksScreen->desktop->add_changed(changed.reg);
683}
684
685// PutImage - changed region is the given rectangle, clipped by pCompositeClip
686
687static void vncHooksPutImage(DrawablePtr pDrawable, GCPtr pGC, int depth,
688 int x, int y, int w, int h, int leftPad,
689 int format, char *pBits)
690{
691 GC_OP_UNWRAPPER(pDrawable, pGC, PutImage);
692
693 BoxRec box;
694 box.x1 = x + pDrawable->x;
695 box.y1 = y + pDrawable->y;
696 box.x2 = box.x1 + w;
697 box.y2 = box.y1 + h;
698
699 RegionHelper changed(pScreen, &box, 0);
700
701 REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC));
702
703 (*pGC->ops->PutImage) (pDrawable, pGC, depth, x, y, w, h, leftPad, format,
704 pBits);
705
706 vncHooksScreen->desktop->add_changed(changed.reg);
707}
708
709// CopyArea - destination of the copy is the dest rectangle, clipped by
710// pCompositeClip. Any parts of the destination which cannot be copied from
711// the source (could be all of it) go into the changed region.
712
713static RegionPtr vncHooksCopyArea(DrawablePtr pSrc, DrawablePtr pDst,
714 GCPtr pGC, int srcx, int srcy, int w, int h,
715 int dstx, int dsty)
716{
717 GC_OP_UNWRAPPER(pDst, pGC, CopyArea);
718
719 BoxRec box;
720 box.x1 = dstx + pDst->x;
721 box.y1 = dsty + pDst->y;
722 box.x2 = box.x1 + w;
723 box.y2 = box.y1 + h;
724
725 RegionHelper dst(pScreen, &box, 0);
726 REGION_INTERSECT(pScreen, dst.reg, dst.reg, COMPOSITE_CLIP(pGC));
727
728 RegionHelper src(pScreen);
729
730 if ((pSrc->type == DRAWABLE_WINDOW) && (pSrc->pScreen == pScreen)) {
731 box.x1 = srcx + pSrc->x;
732 box.y1 = srcy + pSrc->y;
733 box.x2 = box.x1 + w;
734 box.y2 = box.y1 + h;
735
736 src.init(&box, 0);
737 REGION_INTERSECT(pScreen, src.reg, src.reg, &((WindowPtr)pSrc)->clipList);
738 REGION_TRANSLATE(pScreen, src.reg,
739 dstx + pDst->x - srcx - pSrc->x,
740 dsty + pDst->y - srcy - pSrc->y);
741 } else {
742 src.init(NullBox, 0);
743 }
744
745 RegionHelper changed(pScreen, NullBox, 0);
746 REGION_SUBTRACT(pScreen, changed.reg, dst.reg, src.reg);
747 REGION_INTERSECT(pScreen, dst.reg, dst.reg, src.reg);
748
749 RegionPtr rgn = (*pGC->ops->CopyArea) (pSrc, pDst, pGC, srcx, srcy, w, h,
750 dstx, dsty);
751
752 if (REGION_NOTEMPTY(pScreen, dst.reg))
753 vncHooksScreen->desktop->add_copied(dst.reg,
754 dstx + pDst->x - srcx - pSrc->x,
755 dsty + pDst->y - srcy - pSrc->y);
756
757 if (REGION_NOTEMPTY(pScreen, changed.reg))
758 vncHooksScreen->desktop->add_changed(changed.reg);
759
760 return rgn;
761}
762
763
764// CopyPlane - changed region is the destination rectangle, clipped by
765// pCompositeClip
766
767static RegionPtr vncHooksCopyPlane(DrawablePtr pSrc, DrawablePtr pDst,
768 GCPtr pGC, int srcx, int srcy, int w, int h,
769 int dstx, int dsty, unsigned long plane)
770{
771 GC_OP_UNWRAPPER(pDst, pGC, CopyPlane);
772
773 BoxRec box;
774 box.x1 = dstx + pDst->x;
775 box.y1 = dsty + pDst->y;
776 box.x2 = box.x1 + w;
777 box.y2 = box.y1 + h;
778
779 RegionHelper changed(pScreen, &box, 0);
780
781 REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC));
782
783 RegionPtr rgn = (*pGC->ops->CopyPlane) (pSrc, pDst, pGC, srcx, srcy, w, h,
784 dstx, dsty, plane);
785 vncHooksScreen->desktop->add_changed(changed.reg);
786
787 return rgn;
788}
789
790// PolyPoint - changed region is the bounding rect, clipped by pCompositeClip
791
792static void vncHooksPolyPoint(DrawablePtr pDrawable, GCPtr pGC, int mode,
793 int npt, xPoint *pts)
794{
795 GC_OP_UNWRAPPER(pDrawable, pGC, PolyPoint);
796
797 if (npt == 0) {
798 (*pGC->ops->PolyPoint) (pDrawable, pGC, mode, npt, pts);
799 return;
800 }
801
802 int minX = pts[0].x;
803 int maxX = pts[0].x;
804 int minY = pts[0].y;
805 int maxY = pts[0].y;
806
807 if (mode == CoordModePrevious) {
808 int x = pts[0].x;
809 int y = pts[0].y;
810
811 for (int i = 1; i < npt; i++) {
812 x += pts[i].x;
813 y += pts[i].y;
814 if (x < minX) minX = x;
815 if (x > maxX) maxX = x;
816 if (y < minY) minY = y;
817 if (y > maxY) maxY = y;
818 }
819 } else {
820 for (int i = 1; i < npt; i++) {
821 if (pts[i].x < minX) minX = pts[i].x;
822 if (pts[i].x > maxX) maxX = pts[i].x;
823 if (pts[i].y < minY) minY = pts[i].y;
824 if (pts[i].y > maxY) maxY = pts[i].y;
825 }
826 }
827
828 BoxRec box;
829 box.x1 = minX + pDrawable->x;
830 box.y1 = minY + pDrawable->y;
831 box.x2 = maxX + 1 + pDrawable->x;
832 box.y2 = maxY + 1 + pDrawable->y;
833
834 RegionHelper changed(pScreen, &box, 0);
835
836 REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC));
837
838 (*pGC->ops->PolyPoint) (pDrawable, pGC, mode, npt, pts);
839
840 vncHooksScreen->desktop->add_changed(changed.reg);
841}
842
843// Polylines - changed region is the union of the bounding rects of each line,
844// clipped by pCompositeClip. If there are more than MAX_RECTS_PER_OP lines,
845// just use the bounding rect of all the lines.
846
847static void vncHooksPolylines(DrawablePtr pDrawable, GCPtr pGC, int mode,
848 int npt, DDXPointPtr ppts)
849{
850 GC_OP_UNWRAPPER(pDrawable, pGC, Polylines);
851
852 if (npt == 0) {
853 (*pGC->ops->Polylines) (pDrawable, pGC, mode, npt, ppts);
854 return;
855 }
856
857 int nRegRects = npt - 1;
858 xRectangle regRects[MAX_RECTS_PER_OP];
859
860 int lw = pGC->lineWidth;
861 if (lw == 0) lw = 1;
862
863 if (npt == 1)
864 {
865 // a single point
866 nRegRects = 1;
867 regRects[0].x = pDrawable->x + ppts[0].x - lw;
868 regRects[0].y = pDrawable->y + ppts[0].y - lw;
869 regRects[0].width = 2*lw;
870 regRects[0].height = 2*lw;
871 }
872 else
873 {
874 /*
875 * mitered joins can project quite a way from
876 * the line end; the 11 degree miter limit limits
877 * this extension to lw / (2 * tan(11/2)), rounded up
878 * and converted to int yields 6 * lw
879 */
880
881 int extra = lw / 2;
882 if (pGC->joinStyle == JoinMiter) {
883 extra = 6 * lw;
884 }
885
886 int prevX, prevY, curX, curY;
887 int rectX1, rectY1, rectX2, rectY2;
888 int minX, minY, maxX, maxY;
889
890 prevX = ppts[0].x + pDrawable->x;
891 prevY = ppts[0].y + pDrawable->y;
892 minX = maxX = prevX;
893 minY = maxY = prevY;
894
895 for (int i = 0; i < nRegRects; i++) {
896 if (mode == CoordModeOrigin) {
897 curX = pDrawable->x + ppts[i+1].x;
898 curY = pDrawable->y + ppts[i+1].y;
899 } else {
900 curX = prevX + ppts[i+1].x;
901 curY = prevY + ppts[i+1].y;
902 }
903
904 if (prevX > curX) {
905 rectX1 = curX - extra;
906 rectX2 = prevX + extra + 1;
907 } else {
908 rectX1 = prevX - extra;
909 rectX2 = curX + extra + 1;
910 }
911
912 if (prevY > curY) {
913 rectY1 = curY - extra;
914 rectY2 = prevY + extra + 1;
915 } else {
916 rectY1 = prevY - extra;
917 rectY2 = curY + extra + 1;
918 }
919
920 if (nRegRects <= MAX_RECTS_PER_OP) {
921 regRects[i].x = rectX1;
922 regRects[i].y = rectY1;
923 regRects[i].width = rectX2 - rectX1;
924 regRects[i].height = rectY2 - rectY1;
925 } else {
926 if (rectX1 < minX) minX = rectX1;
927 if (rectY1 < minY) minY = rectY1;
928 if (rectX2 > maxX) maxX = rectX2;
929 if (rectY2 > maxY) maxY = rectY2;
930 }
931
932 prevX = curX;
933 prevY = curY;
934 }
935
936 if (nRegRects > MAX_RECTS_PER_OP) {
937 regRects[0].x = minX;
938 regRects[0].y = minY;
939 regRects[0].width = maxX - minX;
940 regRects[0].height = maxY - minY;
941 nRegRects = 1;
942 }
943 }
944
945 RegionHelper changed(pScreen, nRegRects, regRects);
946
947 REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC));
948
949 (*pGC->ops->Polylines) (pDrawable, pGC, mode, npt, ppts);
950
951 vncHooksScreen->desktop->add_changed(changed.reg);
952}
953
954// PolySegment - changed region is the union of the bounding rects of each
955// segment, clipped by pCompositeClip. If there are more than MAX_RECTS_PER_OP
956// segments, just use the bounding rect of all the segments.
957
958static void vncHooksPolySegment(DrawablePtr pDrawable, GCPtr pGC, int nseg,
959 xSegment *segs)
960{
961 GC_OP_UNWRAPPER(pDrawable, pGC, PolySegment);
962
963 if (nseg == 0) {
964 (*pGC->ops->PolySegment) (pDrawable, pGC, nseg, segs);
965 return;
966 }
967
968 xRectangle regRects[MAX_RECTS_PER_OP];
969 int nRegRects = nseg;
970
971 int lw = pGC->lineWidth;
972 int extra = lw / 2;
973
974 int rectX1, rectY1, rectX2, rectY2;
975 int minX, minY, maxX, maxY;
976
977 minX = maxX = segs[0].x1;
978 minY = maxY = segs[0].y1;
979
980 for (int i = 0; i < nseg; i++) {
981 if (segs[i].x1 > segs[i].x2) {
982 rectX1 = pDrawable->x + segs[i].x2 - extra;
983 rectX2 = pDrawable->x + segs[i].x1 + extra + 1;
984 } else {
985 rectX1 = pDrawable->x + segs[i].x1 - extra;
986 rectX2 = pDrawable->x + segs[i].x2 + extra + 1;
987 }
988
989 if (segs[i].y1 > segs[i].y2) {
990 rectY1 = pDrawable->y + segs[i].y2 - extra;
991 rectY2 = pDrawable->y + segs[i].y1 + extra + 1;
992 } else {
993 rectY1 = pDrawable->y + segs[i].y1 - extra;
994 rectY2 = pDrawable->y + segs[i].y2 + extra + 1;
995 }
996
997 if (nseg <= MAX_RECTS_PER_OP) {
998 regRects[i].x = rectX1;
999 regRects[i].y = rectY1;
1000 regRects[i].width = rectX2 - rectX1;
1001 regRects[i].height = rectY2 - rectY1;
1002 } else {
1003 if (rectX1 < minX) minX = rectX1;
1004 if (rectY1 < minY) minY = rectY1;
1005 if (rectX2 > maxX) maxX = rectX2;
1006 if (rectY2 > maxY) maxY = rectY2;
1007 }
1008 }
1009
1010 if (nseg > MAX_RECTS_PER_OP) {
1011 regRects[0].x = minX;
1012 regRects[0].y = minY;
1013 regRects[0].width = maxX - minX;
1014 regRects[0].height = maxY - minY;
1015 nRegRects = 1;
1016 }
1017
1018 RegionHelper changed(pScreen, nRegRects, regRects);
1019
1020 REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC));
1021
1022 (*pGC->ops->PolySegment) (pDrawable, pGC, nseg, segs);
1023
1024 vncHooksScreen->desktop->add_changed(changed.reg);
1025}
1026
1027// PolyRectangle - changed region is the union of the bounding rects around
1028// each side of the outline rectangles, clipped by pCompositeClip. If there
1029// are more than MAX_RECTS_PER_OP rectangles, just use the bounding rect of all
1030// the rectangles.
1031
1032static void vncHooksPolyRectangle(DrawablePtr pDrawable, GCPtr pGC, int nrects,
1033 xRectangle *rects)
1034{
1035 GC_OP_UNWRAPPER(pDrawable, pGC, PolyRectangle);
1036
1037 if (nrects == 0) {
1038 (*pGC->ops->PolyRectangle) (pDrawable, pGC, nrects, rects);
1039 return;
1040 }
1041
1042 xRectangle regRects[MAX_RECTS_PER_OP*4];
1043 int nRegRects = nrects * 4;
1044
1045 int lw = pGC->lineWidth;
1046 int extra = lw / 2;
1047
1048 int rectX1, rectY1, rectX2, rectY2;
1049 int minX, minY, maxX, maxY;
1050
1051 minX = maxX = rects[0].x;
1052 minY = maxY = rects[0].y;
1053
1054 for (int i = 0; i < nrects; i++) {
1055 if (nrects <= MAX_RECTS_PER_OP) {
1056 regRects[i*4].x = rects[i].x - extra + pDrawable->x;
1057 regRects[i*4].y = rects[i].y - extra + pDrawable->y;
1058 regRects[i*4].width = rects[i].width + 1 + 2 * extra;
1059 regRects[i*4].height = 1 + 2 * extra;
1060
1061 regRects[i*4+1].x = rects[i].x - extra + pDrawable->x;
1062 regRects[i*4+1].y = rects[i].y - extra + pDrawable->y;
1063 regRects[i*4+1].width = 1 + 2 * extra;
1064 regRects[i*4+1].height = rects[i].height + 1 + 2 * extra;
1065
1066 regRects[i*4+2].x = rects[i].x + rects[i].width - extra + pDrawable->x;
1067 regRects[i*4+2].y = rects[i].y - extra + pDrawable->y;
1068 regRects[i*4+2].width = 1 + 2 * extra;
1069 regRects[i*4+2].height = rects[i].height + 1 + 2 * extra;
1070
1071 regRects[i*4+3].x = rects[i].x - extra + pDrawable->x;
1072 regRects[i*4+3].y = rects[i].y + rects[i].height - extra + pDrawable->y;
1073 regRects[i*4+3].width = rects[i].width + 1 + 2 * extra;
1074 regRects[i*4+3].height = 1 + 2 * extra;
1075 } else {
1076 rectX1 = pDrawable->x + rects[i].x - extra;
1077 rectY1 = pDrawable->y + rects[i].y - extra;
1078 rectX2 = pDrawable->x + rects[i].x + rects[i].width + extra+1;
1079 rectY2 = pDrawable->y + rects[i].y + rects[i].height + extra+1;
1080 if (rectX1 < minX) minX = rectX1;
1081 if (rectY1 < minY) minY = rectY1;
1082 if (rectX2 > maxX) maxX = rectX2;
1083 if (rectY2 > maxY) maxY = rectY2;
1084 }
1085 }
1086
1087 if (nrects > MAX_RECTS_PER_OP) {
1088 regRects[0].x = minX;
1089 regRects[0].y = minY;
1090 regRects[0].width = maxX - minX;
1091 regRects[0].height = maxY - minY;
1092 nRegRects = 1;
1093 }
1094
1095 RegionHelper changed(pScreen, nRegRects, regRects);
1096
1097 REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC));
1098
1099 (*pGC->ops->PolyRectangle) (pDrawable, pGC, nrects, rects);
1100
1101 vncHooksScreen->desktop->add_changed(changed.reg);
1102}
1103
1104// PolyArc - changed region is the union of bounding rects around each arc,
1105// clipped by pCompositeClip. If there are more than MAX_RECTS_PER_OP
1106// arcs, just use the bounding rect of all the arcs.
1107
1108static void vncHooksPolyArc(DrawablePtr pDrawable, GCPtr pGC, int narcs,
1109 xArc *arcs)
1110{
1111 GC_OP_UNWRAPPER(pDrawable, pGC, PolyArc);
1112
1113 if (narcs == 0) {
1114 (*pGC->ops->PolyArc) (pDrawable, pGC, narcs, arcs);
1115 return;
1116 }
1117
1118 xRectangle regRects[MAX_RECTS_PER_OP];
1119 int nRegRects = narcs;
1120
1121 int lw = pGC->lineWidth;
1122 if (lw == 0) lw = 1;
1123 int extra = lw / 2;
1124
1125 int rectX1, rectY1, rectX2, rectY2;
1126 int minX, minY, maxX, maxY;
1127
1128 minX = maxX = arcs[0].x;
1129 minY = maxY = arcs[0].y;
1130
1131 for (int i = 0; i < narcs; i++) {
1132 if (narcs <= MAX_RECTS_PER_OP) {
1133 regRects[i].x = arcs[i].x - extra + pDrawable->x;
1134 regRects[i].y = arcs[i].y - extra + pDrawable->y;
1135 regRects[i].width = arcs[i].width + lw;
1136 regRects[i].height = arcs[i].height + lw;
1137 } else {
1138 rectX1 = pDrawable->x + arcs[i].x - extra;
1139 rectY1 = pDrawable->y + arcs[i].y - extra;
1140 rectX2 = pDrawable->x + arcs[i].x + arcs[i].width + lw;
1141 rectY2 = pDrawable->y + arcs[i].y + arcs[i].height + lw;
1142 if (rectX1 < minX) minX = rectX1;
1143 if (rectY1 < minY) minY = rectY1;
1144 if (rectX2 > maxX) maxX = rectX2;
1145 if (rectY2 > maxY) maxY = rectY2;
1146 }
1147 }
1148
1149 if (narcs > MAX_RECTS_PER_OP) {
1150 regRects[0].x = minX;
1151 regRects[0].y = minY;
1152 regRects[0].width = maxX - minX;
1153 regRects[0].height = maxY - minY;
1154 nRegRects = 1;
1155 }
1156
1157 RegionHelper changed(pScreen, nRegRects, regRects);
1158
1159 REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC));
1160
1161 (*pGC->ops->PolyArc) (pDrawable, pGC, narcs, arcs);
1162
1163 vncHooksScreen->desktop->add_changed(changed.reg);
1164}
1165
1166
1167// FillPolygon - changed region is the bounding rect around the polygon,
1168// clipped by pCompositeClip
1169
1170static void vncHooksFillPolygon(DrawablePtr pDrawable, GCPtr pGC, int shape,
1171 int mode, int count, DDXPointPtr pts)
1172{
1173 GC_OP_UNWRAPPER(pDrawable, pGC, FillPolygon);
1174
1175 if (count == 0) {
1176 (*pGC->ops->FillPolygon) (pDrawable, pGC, shape, mode, count, pts);
1177 return;
1178 }
1179
1180 int minX = pts[0].x;
1181 int maxX = pts[0].x;
1182 int minY = pts[0].y;
1183 int maxY = pts[0].y;
1184
1185 if (mode == CoordModePrevious) {
1186 int x = pts[0].x;
1187 int y = pts[0].y;
1188
1189 for (int i = 1; i < count; i++) {
1190 x += pts[i].x;
1191 y += pts[i].y;
1192 if (x < minX) minX = x;
1193 if (x > maxX) maxX = x;
1194 if (y < minY) minY = y;
1195 if (y > maxY) maxY = y;
1196 }
1197 } else {
1198 for (int i = 1; i < count; i++) {
1199 if (pts[i].x < minX) minX = pts[i].x;
1200 if (pts[i].x > maxX) maxX = pts[i].x;
1201 if (pts[i].y < minY) minY = pts[i].y;
1202 if (pts[i].y > maxY) maxY = pts[i].y;
1203 }
1204 }
1205
1206 BoxRec box;
1207 box.x1 = minX + pDrawable->x;
1208 box.y1 = minY + pDrawable->y;
1209 box.x2 = maxX + 1 + pDrawable->x;
1210 box.y2 = maxY + 1 + pDrawable->y;
1211
1212 RegionHelper changed(pScreen, &box, 0);
1213
1214 REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC));
1215
1216 (*pGC->ops->FillPolygon) (pDrawable, pGC, shape, mode, count, pts);
1217
1218 vncHooksScreen->desktop->add_changed(changed.reg);
1219}
1220
1221// PolyFillRect - changed region is the union of the rectangles, clipped by
1222// pCompositeClip. If there are more than MAX_RECTS_PER_OP rectangles, just
1223// use the bounding rect of all the rectangles.
1224
1225static void vncHooksPolyFillRect(DrawablePtr pDrawable, GCPtr pGC, int nrects,
1226 xRectangle *rects)
1227{
1228 GC_OP_UNWRAPPER(pDrawable, pGC, PolyFillRect);
1229
1230 if (nrects == 0) {
1231 (*pGC->ops->PolyFillRect) (pDrawable, pGC, nrects, rects);
1232 return;
1233 }
1234
1235 xRectangle regRects[MAX_RECTS_PER_OP];
1236 int nRegRects = nrects;
1237 int rectX1, rectY1, rectX2, rectY2;
1238 int minX, minY, maxX, maxY;
1239 minX = maxX = rects[0].x;
1240 minY = maxY = rects[0].y;
1241
1242 for (int i = 0; i < nrects; i++) {
1243 if (nrects <= MAX_RECTS_PER_OP) {
1244 regRects[i].x = rects[i].x + pDrawable->x;
1245 regRects[i].y = rects[i].y + pDrawable->y;
1246 regRects[i].width = rects[i].width;
1247 regRects[i].height = rects[i].height;
1248 } else {
1249 rectX1 = pDrawable->x + rects[i].x;
1250 rectY1 = pDrawable->y + rects[i].y;
1251 rectX2 = pDrawable->x + rects[i].x + rects[i].width;
1252 rectY2 = pDrawable->y + rects[i].y + rects[i].height;
1253 if (rectX1 < minX) minX = rectX1;
1254 if (rectY1 < minY) minY = rectY1;
1255 if (rectX2 > maxX) maxX = rectX2;
1256 if (rectY2 > maxY) maxY = rectY2;
1257 }
1258 }
1259
1260 if (nrects > MAX_RECTS_PER_OP) {
1261 regRects[0].x = minX;
1262 regRects[0].y = minY;
1263 regRects[0].width = maxX - minX;
1264 regRects[0].height = maxY - minY;
1265 nRegRects = 1;
1266 }
1267
1268 RegionHelper changed(pScreen, nRegRects, regRects);
1269
1270 REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC));
1271
1272 (*pGC->ops->PolyFillRect) (pDrawable, pGC, nrects, rects);
1273
1274 vncHooksScreen->desktop->add_changed(changed.reg);
1275}
1276
1277// PolyFillArc - changed region is the union of bounding rects around each arc,
1278// clipped by pCompositeClip. If there are more than MAX_RECTS_PER_OP arcs,
1279// just use the bounding rect of all the arcs.
1280
1281static void vncHooksPolyFillArc(DrawablePtr pDrawable, GCPtr pGC, int narcs,
1282 xArc *arcs)
1283{
1284 GC_OP_UNWRAPPER(pDrawable, pGC, PolyFillArc);
1285
1286 if (narcs == 0) {
1287 (*pGC->ops->PolyFillArc) (pDrawable, pGC, narcs, arcs);
1288 return;
1289 }
1290
1291 xRectangle regRects[MAX_RECTS_PER_OP];
1292 int nRegRects = narcs;
1293
1294 int lw = pGC->lineWidth;
1295 if (lw == 0) lw = 1;
1296 int extra = lw / 2;
1297
1298 int rectX1, rectY1, rectX2, rectY2;
1299 int minX, minY, maxX, maxY;
1300
1301 minX = maxX = arcs[0].x;
1302 minY = maxY = arcs[0].y;
1303
1304 for (int i = 0; i < narcs; i++) {
1305 if (narcs <= MAX_RECTS_PER_OP) {
1306 regRects[i].x = arcs[i].x - extra + pDrawable->x;
1307 regRects[i].y = arcs[i].y - extra + pDrawable->y;
1308 regRects[i].width = arcs[i].width + lw;
1309 regRects[i].height = arcs[i].height + lw;
1310 } else {
1311 rectX1 = pDrawable->x + arcs[i].x - extra;
1312 rectY1 = pDrawable->y + arcs[i].y - extra;
1313 rectX2 = pDrawable->x + arcs[i].x + arcs[i].width + lw;
1314 rectY2 = pDrawable->y + arcs[i].y + arcs[i].height + lw;
1315 if (rectX1 < minX) minX = rectX1;
1316 if (rectY1 < minY) minY = rectY1;
1317 if (rectX2 > maxX) maxX = rectX2;
1318 if (rectY2 > maxY) maxY = rectY2;
1319 }
1320 }
1321
1322 if (narcs > MAX_RECTS_PER_OP) {
1323 regRects[0].x = minX;
1324 regRects[0].y = minY;
1325 regRects[0].width = maxX - minX;
1326 regRects[0].height = maxY - minY;
1327 nRegRects = 1;
1328 }
1329
1330 RegionHelper changed(pScreen, nRegRects, regRects);
1331
1332 REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC));
1333
1334 (*pGC->ops->PolyFillArc) (pDrawable, pGC, narcs, arcs);
1335
1336 vncHooksScreen->desktop->add_changed(changed.reg);
1337}
1338
1339// GetTextBoundingRect - calculate a bounding rectangle around n chars of a
1340// font. Not particularly accurate, but good enough.
1341
1342static void GetTextBoundingRect(DrawablePtr pDrawable, FontPtr font, int x,
1343 int y, int nchars, BoxPtr box)
1344{
Constantin Kaplinsky95f6f7a2006-04-17 04:17:23 +00001345 int ascent = __rfbmax(FONTASCENT(font), FONTMAXBOUNDS(font, ascent));
1346 int descent = __rfbmax(FONTDESCENT(font), FONTMAXBOUNDS(font, descent));
1347 int charWidth = __rfbmax(FONTMAXBOUNDS(font,rightSideBearing),
1348 FONTMAXBOUNDS(font,characterWidth));
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +00001349
1350 box->x1 = pDrawable->x + x;
1351 box->y1 = pDrawable->y + y - ascent;
1352 box->x2 = box->x1 + charWidth * nchars;
1353 box->y2 = box->y1 + ascent + descent;
1354
1355 if (FONTMINBOUNDS(font,leftSideBearing) < 0)
1356 box->x1 += FONTMINBOUNDS(font,leftSideBearing);
1357}
1358
1359// PolyText8 - changed region is bounding rect around count chars, clipped by
1360// pCompositeClip
1361
1362static int vncHooksPolyText8(DrawablePtr pDrawable, GCPtr pGC, int x, int y,
1363 int count, char *chars)
1364{
1365 GC_OP_UNWRAPPER(pDrawable, pGC, PolyText8);
1366
1367 if (count == 0)
1368 return (*pGC->ops->PolyText8) (pDrawable, pGC, x, y, count, chars);
1369
1370 BoxRec box;
1371 GetTextBoundingRect(pDrawable, pGC->font, x, y, count, &box);
1372
1373 RegionHelper changed(pScreen, &box, 0);
1374
1375 REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC));
1376
1377 int ret = (*pGC->ops->PolyText8) (pDrawable, pGC, x, y, count, chars);
1378
1379 vncHooksScreen->desktop->add_changed(changed.reg);
1380
1381 return ret;
1382}
1383
1384// PolyText16 - changed region is bounding rect around count chars, clipped by
1385// pCompositeClip
1386
1387static int vncHooksPolyText16(DrawablePtr pDrawable, GCPtr pGC, int x, int y,
1388 int count, unsigned short *chars)
1389{
1390 GC_OP_UNWRAPPER(pDrawable, pGC, PolyText16);
1391
1392 if (count == 0)
1393 return (*pGC->ops->PolyText16) (pDrawable, pGC, x, y, count, chars);
1394
1395 BoxRec box;
1396 GetTextBoundingRect(pDrawable, pGC->font, x, y, count, &box);
1397
1398 RegionHelper changed(pScreen, &box, 0);
1399
1400 REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC));
1401
1402 int ret = (*pGC->ops->PolyText16) (pDrawable, pGC, x, y, count, chars);
1403
1404 vncHooksScreen->desktop->add_changed(changed.reg);
1405
1406 return ret;
1407}
1408
1409// ImageText8 - changed region is bounding rect around count chars, clipped by
1410// pCompositeClip
1411
1412static void vncHooksImageText8(DrawablePtr pDrawable, GCPtr pGC, int x, int y,
1413 int count, char *chars)
1414{
1415 GC_OP_UNWRAPPER(pDrawable, pGC, ImageText8);
1416
1417 if (count == 0) {
1418 (*pGC->ops->ImageText8) (pDrawable, pGC, x, y, count, chars);
1419 return;
1420 }
1421
1422 BoxRec box;
1423 GetTextBoundingRect(pDrawable, pGC->font, x, y, count, &box);
1424
1425 RegionHelper changed(pScreen, &box, 0);
1426
1427 REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC));
1428
1429 (*pGC->ops->ImageText8) (pDrawable, pGC, x, y, count, chars);
1430
1431 vncHooksScreen->desktop->add_changed(changed.reg);
1432}
1433
1434// ImageText16 - changed region is bounding rect around count chars, clipped by
1435// pCompositeClip
1436
1437static void vncHooksImageText16(DrawablePtr pDrawable, GCPtr pGC, int x, int y,
1438 int count, unsigned short *chars)
1439{
1440 GC_OP_UNWRAPPER(pDrawable, pGC, ImageText16);
1441
1442 if (count == 0) {
1443 (*pGC->ops->ImageText16) (pDrawable, pGC, x, y, count, chars);
1444 return;
1445 }
1446
1447 BoxRec box;
1448 GetTextBoundingRect(pDrawable, pGC->font, x, y, count, &box);
1449
1450 RegionHelper changed(pScreen, &box, 0);
1451
1452 REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC));
1453
1454 (*pGC->ops->ImageText16) (pDrawable, pGC, x, y, count, chars);
1455
1456 vncHooksScreen->desktop->add_changed(changed.reg);
1457}
1458
1459// ImageGlyphBlt - changed region is bounding rect around nglyph chars, clipped
1460// by pCompositeClip
1461
1462static void vncHooksImageGlyphBlt(DrawablePtr pDrawable, GCPtr pGC, int x,
1463 int y, unsigned int nglyph,
1464 CharInfoPtr *ppci, pointer pglyphBase)
1465{
1466 GC_OP_UNWRAPPER(pDrawable, pGC, ImageGlyphBlt);
1467
1468 if (nglyph == 0) {
1469 (*pGC->ops->ImageGlyphBlt) (pDrawable, pGC, x, y, nglyph, ppci,pglyphBase);
1470 return;
1471 }
1472
1473 BoxRec box;
1474 GetTextBoundingRect(pDrawable, pGC->font, x, y, nglyph, &box);
1475
1476 RegionHelper changed(pScreen, &box, 0);
1477
1478 REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC));
1479
1480 (*pGC->ops->ImageGlyphBlt) (pDrawable, pGC, x, y, nglyph, ppci, pglyphBase);
1481
1482 vncHooksScreen->desktop->add_changed(changed.reg);
1483}
1484
1485// PolyGlyphBlt - changed region is bounding rect around nglyph chars, clipped
1486// by pCompositeClip
1487
1488static void vncHooksPolyGlyphBlt(DrawablePtr pDrawable, GCPtr pGC, int x,
1489 int y, unsigned int nglyph,
1490 CharInfoPtr *ppci, pointer pglyphBase)
1491{
1492 GC_OP_UNWRAPPER(pDrawable, pGC, PolyGlyphBlt);
1493
1494 if (nglyph == 0) {
1495 (*pGC->ops->PolyGlyphBlt) (pDrawable, pGC, x, y, nglyph, ppci,pglyphBase);
1496 return;
1497 }
1498
1499 BoxRec box;
1500 GetTextBoundingRect(pDrawable, pGC->font, x, y, nglyph, &box);
1501
1502 RegionHelper changed(pScreen, &box, 0);
1503
1504 REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC));
1505
1506 (*pGC->ops->PolyGlyphBlt) (pDrawable, pGC, x, y, nglyph, ppci, pglyphBase);
1507
1508 vncHooksScreen->desktop->add_changed(changed.reg);
1509}
1510
1511// PushPixels - changed region is the given rectangle, clipped by
1512// pCompositeClip
1513
1514static void vncHooksPushPixels(GCPtr pGC, PixmapPtr pBitMap,
1515 DrawablePtr pDrawable, int w, int h, int x,
1516 int y)
1517{
1518 GC_OP_UNWRAPPER(pDrawable, pGC, PushPixels);
1519
1520 BoxRec box;
1521 box.x1 = x + pDrawable->x;
1522 box.y1 = y + pDrawable->y;
1523 box.x2 = box.x1 + w;
1524 box.y2 = box.y1 + h;
1525
1526 RegionHelper changed(pScreen, &box, 0);
1527
1528 REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC));
1529
1530 (*pGC->ops->PushPixels) (pGC, pBitMap, pDrawable, w, h, x, y);
1531
1532 vncHooksScreen->desktop->add_changed(changed.reg);
1533}