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