blob: d040e4f53d8171d07099be73dcb948cbb0a60d83 [file] [log] [blame]
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +00001/* Copyright (C) 2002-2003 RealVNC Ltd. All Rights Reserved.
2 *
3 * 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);
507
Peter Åstrand014f0302005-03-31 11:27:37 +0000508 // For some reason, this hook is sometimes called with a negative
509 // xDst. This causes graphics errors, as well as error messages of
510 // the type:
511 // ComparingUpdateTracker: rect outside fb (-47,76-171,89)
512 // I've never observed a negative yDst, but let's check it anyway.
Peter Åstrand90e74f42005-03-31 15:13:41 +0000513 if ((xDst >= 0) && (yDst >= 0)) {
514 box.x1 = pDst->pDrawable->x + xDst;
515 box.y1 = pDst->pDrawable->y + yDst;
516 box.x2 = box.x1 + width;
517 box.y2 = box.y1 + height;
Peter Åstrand014f0302005-03-31 11:27:37 +0000518
Peter Åstrand90e74f42005-03-31 15:13:41 +0000519 RegionHelper changed(pScreen, &box, 0);
520 vncHooksScreen->desktop->add_changed(changed.reg);
521 }
Peter Åstrandf1794c32005-03-10 13:28:04 +0000522
523 ps->Composite = vncHooksScreen->Composite;
524 (*ps->Composite)(op, pSrc, pMask, pDst, xSrc, ySrc,
525 xMask, yMask, xDst, yDst, width, height);
526 ps->Composite = vncHooksComposite;
527}
528
529#endif /* RENDER */
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000530
531
532/////////////////////////////////////////////////////////////////////////////
533//
534// GC "funcs"
535//
536
537// GCFuncUnwrapper is a helper class which unwraps the GC funcs and ops in its
538// constructor and rewraps them in its destructor.
539
540class GCFuncUnwrapper {
541public:
542 GCFuncUnwrapper(GCPtr pGC_) : pGC(pGC_) {
543 vncHooksGC = (vncHooksGCPtr)pGC->devPrivates[vncHooksGCIndex].ptr;
544 pGC->funcs = vncHooksGC->wrappedFuncs;
545 if (vncHooksGC->wrappedOps)
546 pGC->ops = vncHooksGC->wrappedOps;
547 }
548 ~GCFuncUnwrapper() {
549 vncHooksGC->wrappedFuncs = pGC->funcs;
550 pGC->funcs = &vncHooksGCFuncs;
551 if (vncHooksGC->wrappedOps) {
552 vncHooksGC->wrappedOps = pGC->ops;
553 pGC->ops = &vncHooksGCOps;
554 }
555 }
556 GCPtr pGC;
557 vncHooksGCPtr vncHooksGC;
558};
559
560
561// ValidateGC - wrap the "ops" if a viewable window
562
563static void vncHooksValidateGC(GCPtr pGC, unsigned long changes,
564 DrawablePtr pDrawable)
565{
566 GCFuncUnwrapper u(pGC);
567
568 DBGPRINT((stderr,"vncHooksValidateGC called\n"));
569
570 (*pGC->funcs->ValidateGC) (pGC, changes, pDrawable);
571
572 u.vncHooksGC->wrappedOps = 0;
573 if (pDrawable->type == DRAWABLE_WINDOW && ((WindowPtr)pDrawable)->viewable) {
574 WindowPtr pWin = (WindowPtr)pDrawable;
575 RegionPtr pRegion = &pWin->clipList;
576
577 if (pGC->subWindowMode == IncludeInferiors)
578 pRegion = &pWin->borderClip;
579 if (REGION_NOTEMPTY(pDrawable->pScreen, pRegion)) {
580 u.vncHooksGC->wrappedOps = pGC->ops;
581 DBGPRINT((stderr,"vncHooksValidateGC: wrapped GC ops\n"));
582 }
583 }
584}
585
586// Other GC funcs - just unwrap and call on
587
588static void vncHooksChangeGC(GCPtr pGC, unsigned long mask) {
589 GCFuncUnwrapper u(pGC);
590 (*pGC->funcs->ChangeGC) (pGC, mask);
591}
592static void vncHooksCopyGC(GCPtr src, unsigned long mask, GCPtr dst) {
593 GCFuncUnwrapper u(dst);
594 (*dst->funcs->CopyGC) (src, mask, dst);
595}
596static void vncHooksDestroyGC(GCPtr pGC) {
597 GCFuncUnwrapper u(pGC);
598 (*pGC->funcs->DestroyGC) (pGC);
599}
600static void vncHooksChangeClip(GCPtr pGC, int type, pointer pValue, int nrects)
601{
602 GCFuncUnwrapper u(pGC);
603 (*pGC->funcs->ChangeClip) (pGC, type, pValue, nrects);
604}
605static void vncHooksDestroyClip(GCPtr pGC) {
606 GCFuncUnwrapper u(pGC);
607 (*pGC->funcs->DestroyClip) (pGC);
608}
609static void vncHooksCopyClip(GCPtr dst, GCPtr src) {
610 GCFuncUnwrapper u(dst);
611 (*dst->funcs->CopyClip) (dst, src);
612}
613
614
615/////////////////////////////////////////////////////////////////////////////
616//
617// GC "ops"
618//
619
620// GCOpUnwrapper is a helper class which unwraps the GC funcs and ops in its
621// constructor and rewraps them in its destructor.
622
623class GCOpUnwrapper {
624public:
625 GCOpUnwrapper(DrawablePtr pDrawable, GCPtr pGC_)
626 : pGC(pGC_), pScreen(pDrawable->pScreen)
627 {
628 vncHooksGC = (vncHooksGCPtr)pGC->devPrivates[vncHooksGCIndex].ptr;
629 oldFuncs = pGC->funcs;
630 pGC->funcs = vncHooksGC->wrappedFuncs;
631 pGC->ops = vncHooksGC->wrappedOps;
632 }
633 ~GCOpUnwrapper() {
634 vncHooksGC->wrappedOps = pGC->ops;
635 pGC->funcs = oldFuncs;
636 pGC->ops = &vncHooksGCOps;
637 }
638 GCPtr pGC;
639 vncHooksGCPtr vncHooksGC;
640 GCFuncs* oldFuncs;
641 ScreenPtr pScreen;
642};
643
644#define GC_OP_UNWRAPPER(pDrawable, pGC, name) \
645 GCOpUnwrapper u(pDrawable, pGC); \
646 ScreenPtr pScreen = (pDrawable)->pScreen; \
647 vncHooksScreenPtr vncHooksScreen \
648 = ((vncHooksScreenPtr)pScreen->devPrivates[vncHooksScreenIndex].ptr); \
649 DBGPRINT((stderr,"vncHooks" #name " called\n"));
650
651
652// FillSpans - changed region is the whole of borderClip. This is pessimistic,
653// but I believe this function is rarely used so it doesn't matter.
654
655static void vncHooksFillSpans(DrawablePtr pDrawable, GCPtr pGC, int nInit,
656 DDXPointPtr pptInit, int *pwidthInit,
657 int fSorted)
658{
659 GC_OP_UNWRAPPER(pDrawable, pGC, FillSpans);
660
661 RegionHelper changed(pScreen, &((WindowPtr)pDrawable)->borderClip);
662
663 (*pGC->ops->FillSpans) (pDrawable, pGC, nInit, pptInit, pwidthInit, fSorted);
664
665 vncHooksScreen->desktop->add_changed(changed.reg);
666}
667
668// SetSpans - changed region is the whole of borderClip. This is pessimistic,
669// but I believe this function is rarely used so it doesn't matter.
670
671static void vncHooksSetSpans(DrawablePtr pDrawable, GCPtr pGC, char *psrc,
672 DDXPointPtr ppt, int *pwidth, int nspans,
673 int fSorted)
674{
675 GC_OP_UNWRAPPER(pDrawable, pGC, SetSpans);
676
677 RegionHelper changed(pScreen, &((WindowPtr)pDrawable)->borderClip);
678
679 (*pGC->ops->SetSpans) (pDrawable, pGC, psrc, ppt, pwidth, nspans, fSorted);
680
681 vncHooksScreen->desktop->add_changed(changed.reg);
682}
683
684// PutImage - changed region is the given rectangle, clipped by pCompositeClip
685
686static void vncHooksPutImage(DrawablePtr pDrawable, GCPtr pGC, int depth,
687 int x, int y, int w, int h, int leftPad,
688 int format, char *pBits)
689{
690 GC_OP_UNWRAPPER(pDrawable, pGC, PutImage);
691
692 BoxRec box;
693 box.x1 = x + pDrawable->x;
694 box.y1 = y + pDrawable->y;
695 box.x2 = box.x1 + w;
696 box.y2 = box.y1 + h;
697
698 RegionHelper changed(pScreen, &box, 0);
699
700 REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC));
701
702 (*pGC->ops->PutImage) (pDrawable, pGC, depth, x, y, w, h, leftPad, format,
703 pBits);
704
705 vncHooksScreen->desktop->add_changed(changed.reg);
706}
707
708// CopyArea - destination of the copy is the dest rectangle, clipped by
709// pCompositeClip. Any parts of the destination which cannot be copied from
710// the source (could be all of it) go into the changed region.
711
712static RegionPtr vncHooksCopyArea(DrawablePtr pSrc, DrawablePtr pDst,
713 GCPtr pGC, int srcx, int srcy, int w, int h,
714 int dstx, int dsty)
715{
716 GC_OP_UNWRAPPER(pDst, pGC, CopyArea);
717
718 BoxRec box;
719 box.x1 = dstx + pDst->x;
720 box.y1 = dsty + pDst->y;
721 box.x2 = box.x1 + w;
722 box.y2 = box.y1 + h;
723
724 RegionHelper dst(pScreen, &box, 0);
725 REGION_INTERSECT(pScreen, dst.reg, dst.reg, COMPOSITE_CLIP(pGC));
726
727 RegionHelper src(pScreen);
728
729 if ((pSrc->type == DRAWABLE_WINDOW) && (pSrc->pScreen == pScreen)) {
730 box.x1 = srcx + pSrc->x;
731 box.y1 = srcy + pSrc->y;
732 box.x2 = box.x1 + w;
733 box.y2 = box.y1 + h;
734
735 src.init(&box, 0);
736 REGION_INTERSECT(pScreen, src.reg, src.reg, &((WindowPtr)pSrc)->clipList);
737 REGION_TRANSLATE(pScreen, src.reg,
738 dstx + pDst->x - srcx - pSrc->x,
739 dsty + pDst->y - srcy - pSrc->y);
740 } else {
741 src.init(NullBox, 0);
742 }
743
744 RegionHelper changed(pScreen, NullBox, 0);
745 REGION_SUBTRACT(pScreen, changed.reg, dst.reg, src.reg);
746 REGION_INTERSECT(pScreen, dst.reg, dst.reg, src.reg);
747
748 RegionPtr rgn = (*pGC->ops->CopyArea) (pSrc, pDst, pGC, srcx, srcy, w, h,
749 dstx, dsty);
750
751 if (REGION_NOTEMPTY(pScreen, dst.reg))
752 vncHooksScreen->desktop->add_copied(dst.reg,
753 dstx + pDst->x - srcx - pSrc->x,
754 dsty + pDst->y - srcy - pSrc->y);
755
756 if (REGION_NOTEMPTY(pScreen, changed.reg))
757 vncHooksScreen->desktop->add_changed(changed.reg);
758
759 return rgn;
760}
761
762
763// CopyPlane - changed region is the destination rectangle, clipped by
764// pCompositeClip
765
766static RegionPtr vncHooksCopyPlane(DrawablePtr pSrc, DrawablePtr pDst,
767 GCPtr pGC, int srcx, int srcy, int w, int h,
768 int dstx, int dsty, unsigned long plane)
769{
770 GC_OP_UNWRAPPER(pDst, pGC, CopyPlane);
771
772 BoxRec box;
773 box.x1 = dstx + pDst->x;
774 box.y1 = dsty + pDst->y;
775 box.x2 = box.x1 + w;
776 box.y2 = box.y1 + h;
777
778 RegionHelper changed(pScreen, &box, 0);
779
780 REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC));
781
782 RegionPtr rgn = (*pGC->ops->CopyPlane) (pSrc, pDst, pGC, srcx, srcy, w, h,
783 dstx, dsty, plane);
784 vncHooksScreen->desktop->add_changed(changed.reg);
785
786 return rgn;
787}
788
789// PolyPoint - changed region is the bounding rect, clipped by pCompositeClip
790
791static void vncHooksPolyPoint(DrawablePtr pDrawable, GCPtr pGC, int mode,
792 int npt, xPoint *pts)
793{
794 GC_OP_UNWRAPPER(pDrawable, pGC, PolyPoint);
795
796 if (npt == 0) {
797 (*pGC->ops->PolyPoint) (pDrawable, pGC, mode, npt, pts);
798 return;
799 }
800
801 int minX = pts[0].x;
802 int maxX = pts[0].x;
803 int minY = pts[0].y;
804 int maxY = pts[0].y;
805
806 if (mode == CoordModePrevious) {
807 int x = pts[0].x;
808 int y = pts[0].y;
809
810 for (int i = 1; i < npt; i++) {
811 x += pts[i].x;
812 y += pts[i].y;
813 if (x < minX) minX = x;
814 if (x > maxX) maxX = x;
815 if (y < minY) minY = y;
816 if (y > maxY) maxY = y;
817 }
818 } else {
819 for (int i = 1; i < npt; i++) {
820 if (pts[i].x < minX) minX = pts[i].x;
821 if (pts[i].x > maxX) maxX = pts[i].x;
822 if (pts[i].y < minY) minY = pts[i].y;
823 if (pts[i].y > maxY) maxY = pts[i].y;
824 }
825 }
826
827 BoxRec box;
828 box.x1 = minX + pDrawable->x;
829 box.y1 = minY + pDrawable->y;
830 box.x2 = maxX + 1 + pDrawable->x;
831 box.y2 = maxY + 1 + pDrawable->y;
832
833 RegionHelper changed(pScreen, &box, 0);
834
835 REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC));
836
837 (*pGC->ops->PolyPoint) (pDrawable, pGC, mode, npt, pts);
838
839 vncHooksScreen->desktop->add_changed(changed.reg);
840}
841
842// Polylines - changed region is the union of the bounding rects of each line,
843// clipped by pCompositeClip. If there are more than MAX_RECTS_PER_OP lines,
844// just use the bounding rect of all the lines.
845
846static void vncHooksPolylines(DrawablePtr pDrawable, GCPtr pGC, int mode,
847 int npt, DDXPointPtr ppts)
848{
849 GC_OP_UNWRAPPER(pDrawable, pGC, Polylines);
850
851 if (npt == 0) {
852 (*pGC->ops->Polylines) (pDrawable, pGC, mode, npt, ppts);
853 return;
854 }
855
856 int nRegRects = npt - 1;
857 xRectangle regRects[MAX_RECTS_PER_OP];
858
859 int lw = pGC->lineWidth;
860 if (lw == 0) lw = 1;
861
862 if (npt == 1)
863 {
864 // a single point
865 nRegRects = 1;
866 regRects[0].x = pDrawable->x + ppts[0].x - lw;
867 regRects[0].y = pDrawable->y + ppts[0].y - lw;
868 regRects[0].width = 2*lw;
869 regRects[0].height = 2*lw;
870 }
871 else
872 {
873 /*
874 * mitered joins can project quite a way from
875 * the line end; the 11 degree miter limit limits
876 * this extension to lw / (2 * tan(11/2)), rounded up
877 * and converted to int yields 6 * lw
878 */
879
880 int extra = lw / 2;
881 if (pGC->joinStyle == JoinMiter) {
882 extra = 6 * lw;
883 }
884
885 int prevX, prevY, curX, curY;
886 int rectX1, rectY1, rectX2, rectY2;
887 int minX, minY, maxX, maxY;
888
889 prevX = ppts[0].x + pDrawable->x;
890 prevY = ppts[0].y + pDrawable->y;
891 minX = maxX = prevX;
892 minY = maxY = prevY;
893
894 for (int i = 0; i < nRegRects; i++) {
895 if (mode == CoordModeOrigin) {
896 curX = pDrawable->x + ppts[i+1].x;
897 curY = pDrawable->y + ppts[i+1].y;
898 } else {
899 curX = prevX + ppts[i+1].x;
900 curY = prevY + ppts[i+1].y;
901 }
902
903 if (prevX > curX) {
904 rectX1 = curX - extra;
905 rectX2 = prevX + extra + 1;
906 } else {
907 rectX1 = prevX - extra;
908 rectX2 = curX + extra + 1;
909 }
910
911 if (prevY > curY) {
912 rectY1 = curY - extra;
913 rectY2 = prevY + extra + 1;
914 } else {
915 rectY1 = prevY - extra;
916 rectY2 = curY + extra + 1;
917 }
918
919 if (nRegRects <= MAX_RECTS_PER_OP) {
920 regRects[i].x = rectX1;
921 regRects[i].y = rectY1;
922 regRects[i].width = rectX2 - rectX1;
923 regRects[i].height = rectY2 - rectY1;
924 } else {
925 if (rectX1 < minX) minX = rectX1;
926 if (rectY1 < minY) minY = rectY1;
927 if (rectX2 > maxX) maxX = rectX2;
928 if (rectY2 > maxY) maxY = rectY2;
929 }
930
931 prevX = curX;
932 prevY = curY;
933 }
934
935 if (nRegRects > MAX_RECTS_PER_OP) {
936 regRects[0].x = minX;
937 regRects[0].y = minY;
938 regRects[0].width = maxX - minX;
939 regRects[0].height = maxY - minY;
940 nRegRects = 1;
941 }
942 }
943
944 RegionHelper changed(pScreen, nRegRects, regRects);
945
946 REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC));
947
948 (*pGC->ops->Polylines) (pDrawable, pGC, mode, npt, ppts);
949
950 vncHooksScreen->desktop->add_changed(changed.reg);
951}
952
953// PolySegment - changed region is the union of the bounding rects of each
954// segment, clipped by pCompositeClip. If there are more than MAX_RECTS_PER_OP
955// segments, just use the bounding rect of all the segments.
956
957static void vncHooksPolySegment(DrawablePtr pDrawable, GCPtr pGC, int nseg,
958 xSegment *segs)
959{
960 GC_OP_UNWRAPPER(pDrawable, pGC, PolySegment);
961
962 if (nseg == 0) {
963 (*pGC->ops->PolySegment) (pDrawable, pGC, nseg, segs);
964 return;
965 }
966
967 xRectangle regRects[MAX_RECTS_PER_OP];
968 int nRegRects = nseg;
969
970 int lw = pGC->lineWidth;
971 int extra = lw / 2;
972
973 int rectX1, rectY1, rectX2, rectY2;
974 int minX, minY, maxX, maxY;
975
976 minX = maxX = segs[0].x1;
977 minY = maxY = segs[0].y1;
978
979 for (int i = 0; i < nseg; i++) {
980 if (segs[i].x1 > segs[i].x2) {
981 rectX1 = pDrawable->x + segs[i].x2 - extra;
982 rectX2 = pDrawable->x + segs[i].x1 + extra + 1;
983 } else {
984 rectX1 = pDrawable->x + segs[i].x1 - extra;
985 rectX2 = pDrawable->x + segs[i].x2 + extra + 1;
986 }
987
988 if (segs[i].y1 > segs[i].y2) {
989 rectY1 = pDrawable->y + segs[i].y2 - extra;
990 rectY2 = pDrawable->y + segs[i].y1 + extra + 1;
991 } else {
992 rectY1 = pDrawable->y + segs[i].y1 - extra;
993 rectY2 = pDrawable->y + segs[i].y2 + extra + 1;
994 }
995
996 if (nseg <= MAX_RECTS_PER_OP) {
997 regRects[i].x = rectX1;
998 regRects[i].y = rectY1;
999 regRects[i].width = rectX2 - rectX1;
1000 regRects[i].height = rectY2 - rectY1;
1001 } else {
1002 if (rectX1 < minX) minX = rectX1;
1003 if (rectY1 < minY) minY = rectY1;
1004 if (rectX2 > maxX) maxX = rectX2;
1005 if (rectY2 > maxY) maxY = rectY2;
1006 }
1007 }
1008
1009 if (nseg > MAX_RECTS_PER_OP) {
1010 regRects[0].x = minX;
1011 regRects[0].y = minY;
1012 regRects[0].width = maxX - minX;
1013 regRects[0].height = maxY - minY;
1014 nRegRects = 1;
1015 }
1016
1017 RegionHelper changed(pScreen, nRegRects, regRects);
1018
1019 REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC));
1020
1021 (*pGC->ops->PolySegment) (pDrawable, pGC, nseg, segs);
1022
1023 vncHooksScreen->desktop->add_changed(changed.reg);
1024}
1025
1026// PolyRectangle - changed region is the union of the bounding rects around
1027// each side of the outline rectangles, clipped by pCompositeClip. If there
1028// are more than MAX_RECTS_PER_OP rectangles, just use the bounding rect of all
1029// the rectangles.
1030
1031static void vncHooksPolyRectangle(DrawablePtr pDrawable, GCPtr pGC, int nrects,
1032 xRectangle *rects)
1033{
1034 GC_OP_UNWRAPPER(pDrawable, pGC, PolyRectangle);
1035
1036 if (nrects == 0) {
1037 (*pGC->ops->PolyRectangle) (pDrawable, pGC, nrects, rects);
1038 return;
1039 }
1040
1041 xRectangle regRects[MAX_RECTS_PER_OP*4];
1042 int nRegRects = nrects * 4;
1043
1044 int lw = pGC->lineWidth;
1045 int extra = lw / 2;
1046
1047 int rectX1, rectY1, rectX2, rectY2;
1048 int minX, minY, maxX, maxY;
1049
1050 minX = maxX = rects[0].x;
1051 minY = maxY = rects[0].y;
1052
1053 for (int i = 0; i < nrects; i++) {
1054 if (nrects <= MAX_RECTS_PER_OP) {
1055 regRects[i*4].x = rects[i].x - extra + pDrawable->x;
1056 regRects[i*4].y = rects[i].y - extra + pDrawable->y;
1057 regRects[i*4].width = rects[i].width + 1 + 2 * extra;
1058 regRects[i*4].height = 1 + 2 * extra;
1059
1060 regRects[i*4+1].x = rects[i].x - extra + pDrawable->x;
1061 regRects[i*4+1].y = rects[i].y - extra + pDrawable->y;
1062 regRects[i*4+1].width = 1 + 2 * extra;
1063 regRects[i*4+1].height = rects[i].height + 1 + 2 * extra;
1064
1065 regRects[i*4+2].x = rects[i].x + rects[i].width - extra + pDrawable->x;
1066 regRects[i*4+2].y = rects[i].y - extra + pDrawable->y;
1067 regRects[i*4+2].width = 1 + 2 * extra;
1068 regRects[i*4+2].height = rects[i].height + 1 + 2 * extra;
1069
1070 regRects[i*4+3].x = rects[i].x - extra + pDrawable->x;
1071 regRects[i*4+3].y = rects[i].y + rects[i].height - extra + pDrawable->y;
1072 regRects[i*4+3].width = rects[i].width + 1 + 2 * extra;
1073 regRects[i*4+3].height = 1 + 2 * extra;
1074 } else {
1075 rectX1 = pDrawable->x + rects[i].x - extra;
1076 rectY1 = pDrawable->y + rects[i].y - extra;
1077 rectX2 = pDrawable->x + rects[i].x + rects[i].width + extra+1;
1078 rectY2 = pDrawable->y + rects[i].y + rects[i].height + extra+1;
1079 if (rectX1 < minX) minX = rectX1;
1080 if (rectY1 < minY) minY = rectY1;
1081 if (rectX2 > maxX) maxX = rectX2;
1082 if (rectY2 > maxY) maxY = rectY2;
1083 }
1084 }
1085
1086 if (nrects > MAX_RECTS_PER_OP) {
1087 regRects[0].x = minX;
1088 regRects[0].y = minY;
1089 regRects[0].width = maxX - minX;
1090 regRects[0].height = maxY - minY;
1091 nRegRects = 1;
1092 }
1093
1094 RegionHelper changed(pScreen, nRegRects, regRects);
1095
1096 REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC));
1097
1098 (*pGC->ops->PolyRectangle) (pDrawable, pGC, nrects, rects);
1099
1100 vncHooksScreen->desktop->add_changed(changed.reg);
1101}
1102
1103// PolyArc - changed region is the union of bounding rects around each arc,
1104// clipped by pCompositeClip. If there are more than MAX_RECTS_PER_OP
1105// arcs, just use the bounding rect of all the arcs.
1106
1107static void vncHooksPolyArc(DrawablePtr pDrawable, GCPtr pGC, int narcs,
1108 xArc *arcs)
1109{
1110 GC_OP_UNWRAPPER(pDrawable, pGC, PolyArc);
1111
1112 if (narcs == 0) {
1113 (*pGC->ops->PolyArc) (pDrawable, pGC, narcs, arcs);
1114 return;
1115 }
1116
1117 xRectangle regRects[MAX_RECTS_PER_OP];
1118 int nRegRects = narcs;
1119
1120 int lw = pGC->lineWidth;
1121 if (lw == 0) lw = 1;
1122 int extra = lw / 2;
1123
1124 int rectX1, rectY1, rectX2, rectY2;
1125 int minX, minY, maxX, maxY;
1126
1127 minX = maxX = arcs[0].x;
1128 minY = maxY = arcs[0].y;
1129
1130 for (int i = 0; i < narcs; i++) {
1131 if (narcs <= MAX_RECTS_PER_OP) {
1132 regRects[i].x = arcs[i].x - extra + pDrawable->x;
1133 regRects[i].y = arcs[i].y - extra + pDrawable->y;
1134 regRects[i].width = arcs[i].width + lw;
1135 regRects[i].height = arcs[i].height + lw;
1136 } else {
1137 rectX1 = pDrawable->x + arcs[i].x - extra;
1138 rectY1 = pDrawable->y + arcs[i].y - extra;
1139 rectX2 = pDrawable->x + arcs[i].x + arcs[i].width + lw;
1140 rectY2 = pDrawable->y + arcs[i].y + arcs[i].height + lw;
1141 if (rectX1 < minX) minX = rectX1;
1142 if (rectY1 < minY) minY = rectY1;
1143 if (rectX2 > maxX) maxX = rectX2;
1144 if (rectY2 > maxY) maxY = rectY2;
1145 }
1146 }
1147
1148 if (narcs > MAX_RECTS_PER_OP) {
1149 regRects[0].x = minX;
1150 regRects[0].y = minY;
1151 regRects[0].width = maxX - minX;
1152 regRects[0].height = maxY - minY;
1153 nRegRects = 1;
1154 }
1155
1156 RegionHelper changed(pScreen, nRegRects, regRects);
1157
1158 REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC));
1159
1160 (*pGC->ops->PolyArc) (pDrawable, pGC, narcs, arcs);
1161
1162 vncHooksScreen->desktop->add_changed(changed.reg);
1163}
1164
1165
1166// FillPolygon - changed region is the bounding rect around the polygon,
1167// clipped by pCompositeClip
1168
1169static void vncHooksFillPolygon(DrawablePtr pDrawable, GCPtr pGC, int shape,
1170 int mode, int count, DDXPointPtr pts)
1171{
1172 GC_OP_UNWRAPPER(pDrawable, pGC, FillPolygon);
1173
1174 if (count == 0) {
1175 (*pGC->ops->FillPolygon) (pDrawable, pGC, shape, mode, count, pts);
1176 return;
1177 }
1178
1179 int minX = pts[0].x;
1180 int maxX = pts[0].x;
1181 int minY = pts[0].y;
1182 int maxY = pts[0].y;
1183
1184 if (mode == CoordModePrevious) {
1185 int x = pts[0].x;
1186 int y = pts[0].y;
1187
1188 for (int i = 1; i < count; i++) {
1189 x += pts[i].x;
1190 y += pts[i].y;
1191 if (x < minX) minX = x;
1192 if (x > maxX) maxX = x;
1193 if (y < minY) minY = y;
1194 if (y > maxY) maxY = y;
1195 }
1196 } else {
1197 for (int i = 1; i < count; i++) {
1198 if (pts[i].x < minX) minX = pts[i].x;
1199 if (pts[i].x > maxX) maxX = pts[i].x;
1200 if (pts[i].y < minY) minY = pts[i].y;
1201 if (pts[i].y > maxY) maxY = pts[i].y;
1202 }
1203 }
1204
1205 BoxRec box;
1206 box.x1 = minX + pDrawable->x;
1207 box.y1 = minY + pDrawable->y;
1208 box.x2 = maxX + 1 + pDrawable->x;
1209 box.y2 = maxY + 1 + pDrawable->y;
1210
1211 RegionHelper changed(pScreen, &box, 0);
1212
1213 REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC));
1214
1215 (*pGC->ops->FillPolygon) (pDrawable, pGC, shape, mode, count, pts);
1216
1217 vncHooksScreen->desktop->add_changed(changed.reg);
1218}
1219
1220// PolyFillRect - changed region is the union of the rectangles, clipped by
1221// pCompositeClip. If there are more than MAX_RECTS_PER_OP rectangles, just
1222// use the bounding rect of all the rectangles.
1223
1224static void vncHooksPolyFillRect(DrawablePtr pDrawable, GCPtr pGC, int nrects,
1225 xRectangle *rects)
1226{
1227 GC_OP_UNWRAPPER(pDrawable, pGC, PolyFillRect);
1228
1229 if (nrects == 0) {
1230 (*pGC->ops->PolyFillRect) (pDrawable, pGC, nrects, rects);
1231 return;
1232 }
1233
1234 xRectangle regRects[MAX_RECTS_PER_OP];
1235 int nRegRects = nrects;
1236 int rectX1, rectY1, rectX2, rectY2;
1237 int minX, minY, maxX, maxY;
1238 minX = maxX = rects[0].x;
1239 minY = maxY = rects[0].y;
1240
1241 for (int i = 0; i < nrects; i++) {
1242 if (nrects <= MAX_RECTS_PER_OP) {
1243 regRects[i].x = rects[i].x + pDrawable->x;
1244 regRects[i].y = rects[i].y + pDrawable->y;
1245 regRects[i].width = rects[i].width;
1246 regRects[i].height = rects[i].height;
1247 } else {
1248 rectX1 = pDrawable->x + rects[i].x;
1249 rectY1 = pDrawable->y + rects[i].y;
1250 rectX2 = pDrawable->x + rects[i].x + rects[i].width;
1251 rectY2 = pDrawable->y + rects[i].y + rects[i].height;
1252 if (rectX1 < minX) minX = rectX1;
1253 if (rectY1 < minY) minY = rectY1;
1254 if (rectX2 > maxX) maxX = rectX2;
1255 if (rectY2 > maxY) maxY = rectY2;
1256 }
1257 }
1258
1259 if (nrects > MAX_RECTS_PER_OP) {
1260 regRects[0].x = minX;
1261 regRects[0].y = minY;
1262 regRects[0].width = maxX - minX;
1263 regRects[0].height = maxY - minY;
1264 nRegRects = 1;
1265 }
1266
1267 RegionHelper changed(pScreen, nRegRects, regRects);
1268
1269 REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC));
1270
1271 (*pGC->ops->PolyFillRect) (pDrawable, pGC, nrects, rects);
1272
1273 vncHooksScreen->desktop->add_changed(changed.reg);
1274}
1275
1276// PolyFillArc - changed region is the union of bounding rects around each arc,
1277// clipped by pCompositeClip. If there are more than MAX_RECTS_PER_OP arcs,
1278// just use the bounding rect of all the arcs.
1279
1280static void vncHooksPolyFillArc(DrawablePtr pDrawable, GCPtr pGC, int narcs,
1281 xArc *arcs)
1282{
1283 GC_OP_UNWRAPPER(pDrawable, pGC, PolyFillArc);
1284
1285 if (narcs == 0) {
1286 (*pGC->ops->PolyFillArc) (pDrawable, pGC, narcs, arcs);
1287 return;
1288 }
1289
1290 xRectangle regRects[MAX_RECTS_PER_OP];
1291 int nRegRects = narcs;
1292
1293 int lw = pGC->lineWidth;
1294 if (lw == 0) lw = 1;
1295 int extra = lw / 2;
1296
1297 int rectX1, rectY1, rectX2, rectY2;
1298 int minX, minY, maxX, maxY;
1299
1300 minX = maxX = arcs[0].x;
1301 minY = maxY = arcs[0].y;
1302
1303 for (int i = 0; i < narcs; i++) {
1304 if (narcs <= MAX_RECTS_PER_OP) {
1305 regRects[i].x = arcs[i].x - extra + pDrawable->x;
1306 regRects[i].y = arcs[i].y - extra + pDrawable->y;
1307 regRects[i].width = arcs[i].width + lw;
1308 regRects[i].height = arcs[i].height + lw;
1309 } else {
1310 rectX1 = pDrawable->x + arcs[i].x - extra;
1311 rectY1 = pDrawable->y + arcs[i].y - extra;
1312 rectX2 = pDrawable->x + arcs[i].x + arcs[i].width + lw;
1313 rectY2 = pDrawable->y + arcs[i].y + arcs[i].height + lw;
1314 if (rectX1 < minX) minX = rectX1;
1315 if (rectY1 < minY) minY = rectY1;
1316 if (rectX2 > maxX) maxX = rectX2;
1317 if (rectY2 > maxY) maxY = rectY2;
1318 }
1319 }
1320
1321 if (narcs > MAX_RECTS_PER_OP) {
1322 regRects[0].x = minX;
1323 regRects[0].y = minY;
1324 regRects[0].width = maxX - minX;
1325 regRects[0].height = maxY - minY;
1326 nRegRects = 1;
1327 }
1328
1329 RegionHelper changed(pScreen, nRegRects, regRects);
1330
1331 REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC));
1332
1333 (*pGC->ops->PolyFillArc) (pDrawable, pGC, narcs, arcs);
1334
1335 vncHooksScreen->desktop->add_changed(changed.reg);
1336}
1337
1338// GetTextBoundingRect - calculate a bounding rectangle around n chars of a
1339// font. Not particularly accurate, but good enough.
1340
1341static void GetTextBoundingRect(DrawablePtr pDrawable, FontPtr font, int x,
1342 int y, int nchars, BoxPtr box)
1343{
1344 int ascent = max(FONTASCENT(font), FONTMAXBOUNDS(font, ascent));
1345 int descent = max(FONTDESCENT(font), FONTMAXBOUNDS(font, descent));
1346 int charWidth = max(FONTMAXBOUNDS(font,rightSideBearing),
1347 FONTMAXBOUNDS(font,characterWidth));
1348
1349 box->x1 = pDrawable->x + x;
1350 box->y1 = pDrawable->y + y - ascent;
1351 box->x2 = box->x1 + charWidth * nchars;
1352 box->y2 = box->y1 + ascent + descent;
1353
1354 if (FONTMINBOUNDS(font,leftSideBearing) < 0)
1355 box->x1 += FONTMINBOUNDS(font,leftSideBearing);
1356}
1357
1358// PolyText8 - changed region is bounding rect around count chars, clipped by
1359// pCompositeClip
1360
1361static int vncHooksPolyText8(DrawablePtr pDrawable, GCPtr pGC, int x, int y,
1362 int count, char *chars)
1363{
1364 GC_OP_UNWRAPPER(pDrawable, pGC, PolyText8);
1365
1366 if (count == 0)
1367 return (*pGC->ops->PolyText8) (pDrawable, pGC, x, y, count, chars);
1368
1369 BoxRec box;
1370 GetTextBoundingRect(pDrawable, pGC->font, x, y, count, &box);
1371
1372 RegionHelper changed(pScreen, &box, 0);
1373
1374 REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC));
1375
1376 int ret = (*pGC->ops->PolyText8) (pDrawable, pGC, x, y, count, chars);
1377
1378 vncHooksScreen->desktop->add_changed(changed.reg);
1379
1380 return ret;
1381}
1382
1383// PolyText16 - changed region is bounding rect around count chars, clipped by
1384// pCompositeClip
1385
1386static int vncHooksPolyText16(DrawablePtr pDrawable, GCPtr pGC, int x, int y,
1387 int count, unsigned short *chars)
1388{
1389 GC_OP_UNWRAPPER(pDrawable, pGC, PolyText16);
1390
1391 if (count == 0)
1392 return (*pGC->ops->PolyText16) (pDrawable, pGC, x, y, count, chars);
1393
1394 BoxRec box;
1395 GetTextBoundingRect(pDrawable, pGC->font, x, y, count, &box);
1396
1397 RegionHelper changed(pScreen, &box, 0);
1398
1399 REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC));
1400
1401 int ret = (*pGC->ops->PolyText16) (pDrawable, pGC, x, y, count, chars);
1402
1403 vncHooksScreen->desktop->add_changed(changed.reg);
1404
1405 return ret;
1406}
1407
1408// ImageText8 - changed region is bounding rect around count chars, clipped by
1409// pCompositeClip
1410
1411static void vncHooksImageText8(DrawablePtr pDrawable, GCPtr pGC, int x, int y,
1412 int count, char *chars)
1413{
1414 GC_OP_UNWRAPPER(pDrawable, pGC, ImageText8);
1415
1416 if (count == 0) {
1417 (*pGC->ops->ImageText8) (pDrawable, pGC, x, y, count, chars);
1418 return;
1419 }
1420
1421 BoxRec box;
1422 GetTextBoundingRect(pDrawable, pGC->font, x, y, count, &box);
1423
1424 RegionHelper changed(pScreen, &box, 0);
1425
1426 REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC));
1427
1428 (*pGC->ops->ImageText8) (pDrawable, pGC, x, y, count, chars);
1429
1430 vncHooksScreen->desktop->add_changed(changed.reg);
1431}
1432
1433// ImageText16 - changed region is bounding rect around count chars, clipped by
1434// pCompositeClip
1435
1436static void vncHooksImageText16(DrawablePtr pDrawable, GCPtr pGC, int x, int y,
1437 int count, unsigned short *chars)
1438{
1439 GC_OP_UNWRAPPER(pDrawable, pGC, ImageText16);
1440
1441 if (count == 0) {
1442 (*pGC->ops->ImageText16) (pDrawable, pGC, x, y, count, chars);
1443 return;
1444 }
1445
1446 BoxRec box;
1447 GetTextBoundingRect(pDrawable, pGC->font, x, y, count, &box);
1448
1449 RegionHelper changed(pScreen, &box, 0);
1450
1451 REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC));
1452
1453 (*pGC->ops->ImageText16) (pDrawable, pGC, x, y, count, chars);
1454
1455 vncHooksScreen->desktop->add_changed(changed.reg);
1456}
1457
1458// ImageGlyphBlt - changed region is bounding rect around nglyph chars, clipped
1459// by pCompositeClip
1460
1461static void vncHooksImageGlyphBlt(DrawablePtr pDrawable, GCPtr pGC, int x,
1462 int y, unsigned int nglyph,
1463 CharInfoPtr *ppci, pointer pglyphBase)
1464{
1465 GC_OP_UNWRAPPER(pDrawable, pGC, ImageGlyphBlt);
1466
1467 if (nglyph == 0) {
1468 (*pGC->ops->ImageGlyphBlt) (pDrawable, pGC, x, y, nglyph, ppci,pglyphBase);
1469 return;
1470 }
1471
1472 BoxRec box;
1473 GetTextBoundingRect(pDrawable, pGC->font, x, y, nglyph, &box);
1474
1475 RegionHelper changed(pScreen, &box, 0);
1476
1477 REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC));
1478
1479 (*pGC->ops->ImageGlyphBlt) (pDrawable, pGC, x, y, nglyph, ppci, pglyphBase);
1480
1481 vncHooksScreen->desktop->add_changed(changed.reg);
1482}
1483
1484// PolyGlyphBlt - changed region is bounding rect around nglyph chars, clipped
1485// by pCompositeClip
1486
1487static void vncHooksPolyGlyphBlt(DrawablePtr pDrawable, GCPtr pGC, int x,
1488 int y, unsigned int nglyph,
1489 CharInfoPtr *ppci, pointer pglyphBase)
1490{
1491 GC_OP_UNWRAPPER(pDrawable, pGC, PolyGlyphBlt);
1492
1493 if (nglyph == 0) {
1494 (*pGC->ops->PolyGlyphBlt) (pDrawable, pGC, x, y, nglyph, ppci,pglyphBase);
1495 return;
1496 }
1497
1498 BoxRec box;
1499 GetTextBoundingRect(pDrawable, pGC->font, x, y, nglyph, &box);
1500
1501 RegionHelper changed(pScreen, &box, 0);
1502
1503 REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC));
1504
1505 (*pGC->ops->PolyGlyphBlt) (pDrawable, pGC, x, y, nglyph, ppci, pglyphBase);
1506
1507 vncHooksScreen->desktop->add_changed(changed.reg);
1508}
1509
1510// PushPixels - changed region is the given rectangle, clipped by
1511// pCompositeClip
1512
1513static void vncHooksPushPixels(GCPtr pGC, PixmapPtr pBitMap,
1514 DrawablePtr pDrawable, int w, int h, int x,
1515 int y)
1516{
1517 GC_OP_UNWRAPPER(pDrawable, pGC, PushPixels);
1518
1519 BoxRec box;
1520 box.x1 = x + pDrawable->x;
1521 box.y1 = y + pDrawable->y;
1522 box.x2 = box.x1 + w;
1523 box.y2 = box.y1 + h;
1524
1525 RegionHelper changed(pScreen, &box, 0);
1526
1527 REGION_INTERSECT(pScreen, changed.reg, changed.reg, COMPOSITE_CLIP(pGC));
1528
1529 (*pGC->ops->PushPixels) (pGC, pBitMap, pDrawable, w, h, x, y);
1530
1531 vncHooksScreen->desktop->add_changed(changed.reg);
1532}