1 /* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
2  * Copyright 2009-2017 Pierre Ossman for Cendio AB
3  *
4  * This is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This software is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this software; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
17  * USA.
18  */
19 
20 #ifdef HAVE_DIX_CONFIG_H
21 #include <dix-config.h>
22 #endif
23 
24 #include <stdio.h>
25 
26 #include "vncHooks.h"
27 #include "vncExtInit.h"
28 
29 #include "xorg-version.h"
30 
31 #include "scrnintstr.h"
32 #include "windowstr.h"
33 #include "cursorstr.h"
34 #include "gcstruct.h"
35 #include "regionstr.h"
36 #include "dixfontstr.h"
37 #include "colormapst.h"
38 #include "picturestr.h"
39 #include "randrstr.h"
40 
41 #define DBGPRINT(x) //(fprintf x)
42 
43 // MAX_RECTS_PER_OP is the maximum number of rectangles we generate from
44 // operations like Polylines and PolySegment.  If the operation is more complex
45 // than this, we simply use the bounding box.  Ideally it would be a
46 // command-line option, but that would involve an extra malloc each time, so we
47 // fix it here.
48 #define MAX_RECTS_PER_OP 5
49 
50 // vncHooksScreenRec and vncHooksGCRec contain pointers to the original
51 // functions which we "wrap" in order to hook the screen changes.  The screen
52 // functions are each wrapped individually, while the GC "funcs" and "ops" are
53 // wrapped as a unit.
54 
55 typedef struct _vncHooksScreenRec {
56   int                          ignoreHooks;
57 
58   CloseScreenProcPtr           CloseScreen;
59   CreateGCProcPtr              CreateGC;
60   CopyWindowProcPtr            CopyWindow;
61   ClearToBackgroundProcPtr     ClearToBackground;
62   DisplayCursorProcPtr         DisplayCursor;
63 #if XORG_AT_LEAST(1, 19, 0)
64   CursorWarpedToProcPtr        CursorWarpedTo;
65 #endif
66   ScreenBlockHandlerProcPtr    BlockHandler;
67   CompositeProcPtr             Composite;
68   GlyphsProcPtr                Glyphs;
69   CompositeRectsProcPtr        CompositeRects;
70   TrapezoidsProcPtr            Trapezoids;
71   TrianglesProcPtr             Triangles;
72   TriStripProcPtr              TriStrip;
73   TriFanProcPtr                TriFan;
74   RRSetConfigProcPtr           rrSetConfig;
75   RRScreenSetSizeProcPtr       rrScreenSetSize;
76   RRCrtcSetProcPtr             rrCrtcSet;
77 } vncHooksScreenRec, *vncHooksScreenPtr;
78 
79 typedef struct _vncHooksGCRec {
80     const GCFuncs *funcs;
81     const GCOps *ops;
82 } vncHooksGCRec, *vncHooksGCPtr;
83 
84 #define wrap(priv, real, mem, func) {\
85     priv->mem = real->mem; \
86     real->mem = func; \
87 }
88 
89 #define unwrap(priv, real, mem) {\
90     real->mem = priv->mem; \
91 }
92 
93 static DevPrivateKeyRec vncHooksScreenKeyRec;
94 static DevPrivateKeyRec vncHooksGCKeyRec;
95 #define vncHooksScreenPrivateKey (&vncHooksScreenKeyRec)
96 #define vncHooksGCPrivateKey (&vncHooksGCKeyRec)
97 
98 #define vncHooksScreenPrivate(pScreen) \
99         (vncHooksScreenPtr) dixLookupPrivate(&(pScreen)->devPrivates, \
100                                              vncHooksScreenPrivateKey)
101 #define vncHooksGCPrivate(pGC) \
102         (vncHooksGCPtr) dixLookupPrivate(&(pGC)->devPrivates, \
103                                          vncHooksGCPrivateKey)
104 
105 // screen functions
106 
107 static Bool vncHooksCloseScreen(ScreenPtr pScreen);
108 static Bool vncHooksCreateGC(GCPtr pGC);
109 static void vncHooksCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg,
110                                RegionPtr pOldRegion);
111 static void vncHooksClearToBackground(WindowPtr pWin, int x, int y, int w,
112                                       int h, Bool generateExposures);
113 static Bool vncHooksDisplayCursor(DeviceIntPtr pDev,
114                                   ScreenPtr pScreen, CursorPtr cursor);
115 #if XORG_AT_LEAST(1, 19, 0)
116 static void vncHooksCursorWarpedTo(DeviceIntPtr pDev,
117                                    ScreenPtr pScreen_, ClientPtr pClient,
118                                    WindowPtr pWindow, SpritePtr pSprite,
119                                    int x, int y);
120 #endif
121 #if XORG_AT_LEAST(1, 19, 0)
122 static void vncHooksBlockHandler(ScreenPtr pScreen, void * pTimeout);
123 #else
124 static void vncHooksBlockHandler(ScreenPtr pScreen, void * pTimeout,
125                                  void * pReadmask);
126 #endif
127 static void vncHooksComposite(CARD8 op, PicturePtr pSrc, PicturePtr pMask,
128 			      PicturePtr pDst, INT16 xSrc, INT16 ySrc, INT16 xMask,
129 			      INT16 yMask, INT16 xDst, INT16 yDst, CARD16 width, CARD16 height);
130 static void vncHooksGlyphs(CARD8 op, PicturePtr pSrc, PicturePtr pDst,
131 			      PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, int nlists,
132 			      GlyphListPtr lists, GlyphPtr * glyphs);
133 static void vncHooksCompositeRects(CARD8 op, PicturePtr pDst,
134             xRenderColor * color, int nRect, xRectangle *rects);
135 static void vncHooksTrapezoids(CARD8 op, PicturePtr pSrc, PicturePtr pDst,
136             PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
137             int ntrap, xTrapezoid * traps);
138 static void vncHooksTriangles(CARD8 op, PicturePtr pSrc, PicturePtr pDst,
139             PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
140             int ntri, xTriangle * tris);
141 static void vncHooksTriStrip(CARD8 op, PicturePtr pSrc, PicturePtr pDst,
142             PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
143             int npoint, xPointFixed * points);
144 static void vncHooksTriFan(CARD8 op, PicturePtr pSrc, PicturePtr pDst,
145             PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
146             int npoint, xPointFixed * points);
147 static Bool vncHooksRandRSetConfig(ScreenPtr pScreen, Rotation rotation,
148                                    int rate, RRScreenSizePtr pSize);
149 static Bool vncHooksRandRScreenSetSize(ScreenPtr pScreen,
150                                        CARD16 width, CARD16 height,
151                                        CARD32 mmWidth, CARD32 mmHeight);
152 static Bool vncHooksRandRCrtcSet(ScreenPtr pScreen, RRCrtcPtr crtc,
153                                  RRModePtr mode, int x, int y,
154                                  Rotation rotation, int numOutputs,
155                                  RROutputPtr *outputs);
156 
157 // GC "funcs"
158 
159 static void vncHooksValidateGC(GCPtr pGC, unsigned long changes,
160                                DrawablePtr pDrawable);
161 static void vncHooksChangeGC(GCPtr pGC, unsigned long mask);
162 static void vncHooksCopyGC(GCPtr src, unsigned long mask, GCPtr dst);
163 static void vncHooksDestroyGC(GCPtr pGC);
164 static void vncHooksChangeClip(GCPtr pGC, int type, void * pValue,int nrects);
165 static void vncHooksDestroyClip(GCPtr pGC);
166 static void vncHooksCopyClip(GCPtr dst, GCPtr src);
167 
168 static GCFuncs vncHooksGCFuncs = {
169   vncHooksValidateGC, vncHooksChangeGC, vncHooksCopyGC, vncHooksDestroyGC,
170   vncHooksChangeClip, vncHooksDestroyClip, vncHooksCopyClip,
171 };
172 
173 // GC "ops"
174 
175 static void vncHooksFillSpans(DrawablePtr pDrawable, GCPtr pGC, int nInit,
176                               DDXPointPtr pptInit, int *pwidthInit,
177                               int fSorted);
178 static void vncHooksSetSpans(DrawablePtr pDrawable, GCPtr pGC, char *psrc,
179                              DDXPointPtr ppt, int *pwidth, int nspans,
180                              int fSorted);
181 static void vncHooksPutImage(DrawablePtr pDrawable, GCPtr pGC, int depth,
182                              int x, int y, int w, int h, int leftPad,
183                              int format, char *pBits);
184 static RegionPtr vncHooksCopyArea(DrawablePtr pSrc, DrawablePtr pDst,
185                                   GCPtr pGC, int srcx, int srcy, int w, int h,
186                                   int dstx, int dsty);
187 static RegionPtr vncHooksCopyPlane(DrawablePtr pSrc, DrawablePtr pDst,
188                                    GCPtr pGC, int srcx, int srcy, int w, int h,
189                                    int dstx, int dsty, unsigned long plane);
190 static void vncHooksPolyPoint(DrawablePtr pDrawable, GCPtr pGC, int mode,
191                               int npt, xPoint *pts);
192 static void vncHooksPolylines(DrawablePtr pDrawable, GCPtr pGC, int mode,
193                               int npt, DDXPointPtr ppts);
194 static void vncHooksPolySegment(DrawablePtr pDrawable, GCPtr pGC, int nseg,
195                                 xSegment *segs);
196 static void vncHooksPolyRectangle(DrawablePtr pDrawable, GCPtr pGC, int nrects,
197                                   xRectangle *rects);
198 static void vncHooksPolyArc(DrawablePtr pDrawable, GCPtr pGC, int narcs,
199                             xArc *arcs);
200 static void vncHooksFillPolygon(DrawablePtr pDrawable, GCPtr pGC, int shape,
201                                 int mode, int count, DDXPointPtr pts);
202 static void vncHooksPolyFillRect(DrawablePtr pDrawable, GCPtr pGC, int nrects,
203                                  xRectangle *rects);
204 static void vncHooksPolyFillArc(DrawablePtr pDrawable, GCPtr pGC, int narcs,
205                                 xArc *arcs);
206 static int vncHooksPolyText8(DrawablePtr pDrawable, GCPtr pGC, int x, int y,
207                              int count, char *chars);
208 static int vncHooksPolyText16(DrawablePtr pDrawable, GCPtr pGC, int x, int y,
209                               int count, unsigned short *chars);
210 static void vncHooksImageText8(DrawablePtr pDrawable, GCPtr pGC, int x, int y,
211                                int count, char *chars);
212 static void vncHooksImageText16(DrawablePtr pDrawable, GCPtr pGC, int x, int y,
213                                 int count, unsigned short *chars);
214 static void vncHooksImageGlyphBlt(DrawablePtr pDrawable, GCPtr pGC, int x,
215                                   int y, unsigned int nglyph,
216                                   CharInfoPtr *ppci, void * pglyphBase);
217 static void vncHooksPolyGlyphBlt(DrawablePtr pDrawable, GCPtr pGC, int x,
218                                  int y, unsigned int nglyph,
219                                  CharInfoPtr *ppci, void * pglyphBase);
220 static void vncHooksPushPixels(GCPtr pGC, PixmapPtr pBitMap,
221                                DrawablePtr pDrawable, int w, int h, int x,
222                                int y);
223 
224 static GCOps vncHooksGCOps = {
225   vncHooksFillSpans, vncHooksSetSpans, vncHooksPutImage, vncHooksCopyArea,
226   vncHooksCopyPlane, vncHooksPolyPoint, vncHooksPolylines, vncHooksPolySegment,
227   vncHooksPolyRectangle, vncHooksPolyArc, vncHooksFillPolygon,
228   vncHooksPolyFillRect, vncHooksPolyFillArc, vncHooksPolyText8,
229   vncHooksPolyText16, vncHooksImageText8, vncHooksImageText16,
230   vncHooksImageGlyphBlt, vncHooksPolyGlyphBlt, vncHooksPushPixels
231 };
232 
233 
234 
235 /////////////////////////////////////////////////////////////////////////////
236 // vncHooksInit() is called at initialisation time and every time the server
237 // resets.  It is called once for each screen, but the indexes are only
238 // allocated once for each server generation.
239 
vncHooksInit(int scrIdx)240 int vncHooksInit(int scrIdx)
241 {
242   ScreenPtr pScreen;
243   vncHooksScreenPtr vncHooksScreen;
244 
245   PictureScreenPtr ps;
246   rrScrPrivPtr rp;
247 
248   pScreen = screenInfo.screens[scrIdx];
249 
250   if (sizeof(BoxRec) != sizeof(struct UpdateRect)) {
251     ErrorF("vncHooksInit: Incompatible BoxRec size\n");
252     return FALSE;
253   }
254 
255   if (!dixRegisterPrivateKey(&vncHooksScreenKeyRec, PRIVATE_SCREEN,
256       sizeof(vncHooksScreenRec))) {
257     ErrorF("vncHooksInit: Allocation of vncHooksScreen failed\n");
258     return FALSE;
259   }
260   if (!dixRegisterPrivateKey(&vncHooksGCKeyRec, PRIVATE_GC,
261       sizeof(vncHooksGCRec))) {
262     ErrorF("vncHooksInit: Allocation of vncHooksGCRec failed\n");
263     return FALSE;
264   }
265 
266   vncHooksScreen = vncHooksScreenPrivate(pScreen);
267 
268   vncHooksScreen->ignoreHooks = 0;
269 
270   wrap(vncHooksScreen, pScreen, CloseScreen, vncHooksCloseScreen);
271   wrap(vncHooksScreen, pScreen, CreateGC, vncHooksCreateGC);
272   wrap(vncHooksScreen, pScreen, CopyWindow, vncHooksCopyWindow);
273   wrap(vncHooksScreen, pScreen, ClearToBackground, vncHooksClearToBackground);
274   wrap(vncHooksScreen, pScreen, DisplayCursor, vncHooksDisplayCursor);
275 #if XORG_AT_LEAST(1, 19, 0)
276   wrap(vncHooksScreen, pScreen, CursorWarpedTo, vncHooksCursorWarpedTo);
277 #endif
278   wrap(vncHooksScreen, pScreen, BlockHandler, vncHooksBlockHandler);
279   ps = GetPictureScreenIfSet(pScreen);
280   if (ps) {
281     wrap(vncHooksScreen, ps, Composite, vncHooksComposite);
282     wrap(vncHooksScreen, ps, Glyphs, vncHooksGlyphs);
283     wrap(vncHooksScreen, ps, CompositeRects, vncHooksCompositeRects);
284     wrap(vncHooksScreen, ps, Trapezoids, vncHooksTrapezoids);
285     wrap(vncHooksScreen, ps, Triangles, vncHooksTriangles);
286     wrap(vncHooksScreen, ps, TriStrip, vncHooksTriStrip);
287     wrap(vncHooksScreen, ps, TriFan, vncHooksTriFan);
288   }
289   rp = rrGetScrPriv(pScreen);
290   if (rp) {
291     /* Some RandR callbacks are optional */
292     if (rp->rrSetConfig)
293       wrap(vncHooksScreen, rp, rrSetConfig, vncHooksRandRSetConfig);
294     if (rp->rrScreenSetSize)
295       wrap(vncHooksScreen, rp, rrScreenSetSize, vncHooksRandRScreenSetSize);
296     if (rp->rrCrtcSet)
297       wrap(vncHooksScreen, rp, rrCrtcSet, vncHooksRandRCrtcSet);
298   }
299 
300   return TRUE;
301 }
302 
303 /////////////////////////////////////////////////////////////////////////////
304 // vncGetScreenImage() grabs a chunk of data from the main screen into the
305 // provided buffer. It lives here rather than in XorgGlue.c because it
306 // temporarily pauses the hooks.
307 
vncGetScreenImage(int scrIdx,int x,int y,int width,int height,char * buffer,int strideBytes)308 void vncGetScreenImage(int scrIdx, int x, int y, int width, int height,
309                        char *buffer, int strideBytes)
310 {
311   ScreenPtr pScreen = screenInfo.screens[scrIdx];
312   vncHooksScreenPtr vncHooksScreen = vncHooksScreenPrivate(pScreen);
313 
314   int i;
315 
316   vncHooksScreen->ignoreHooks++;
317 
318   // We do one line at a time since GetImage() cannot handle stride
319   for (i = y; i < y + height; i++) {
320     DrawablePtr pDrawable;
321     pDrawable = (DrawablePtr) pScreen->root;
322 
323     (*pScreen->GetImage) (pDrawable, x, i, width, 1,
324                           ZPixmap, (unsigned long)~0L, buffer);
325 
326     buffer += strideBytes;
327   }
328 
329   vncHooksScreen->ignoreHooks--;
330 }
331 
332 /////////////////////////////////////////////////////////////////////////////
333 //
334 // Helper functions
335 //
336 
add_changed(ScreenPtr pScreen,RegionPtr reg)337 static inline void add_changed(ScreenPtr pScreen, RegionPtr reg)
338 {
339   vncHooksScreenPtr vncHooksScreen = vncHooksScreenPrivate(pScreen);
340   if (vncHooksScreen->ignoreHooks)
341     return;
342   if (RegionNil(reg))
343     return;
344   vncAddChanged(pScreen->myNum,
345                 RegionNumRects(reg),
346                 (const struct UpdateRect*)RegionRects(reg));
347 }
348 
add_copied(ScreenPtr pScreen,RegionPtr dst,int dx,int dy)349 static inline void add_copied(ScreenPtr pScreen, RegionPtr dst,
350                               int dx, int dy)
351 {
352   vncHooksScreenPtr vncHooksScreen = vncHooksScreenPrivate(pScreen);
353   if (vncHooksScreen->ignoreHooks)
354     return;
355   if (RegionNil(dst))
356     return;
357   vncAddCopied(pScreen->myNum,
358                RegionNumRects(dst),
359                (const struct UpdateRect*)RegionRects(dst), dx, dy);
360 }
361 
is_visible(DrawablePtr drawable)362 static inline Bool is_visible(DrawablePtr drawable)
363 {
364   PixmapPtr scrPixmap;
365 
366   scrPixmap = drawable->pScreen->GetScreenPixmap(drawable->pScreen);
367 
368   if (drawable->type == DRAWABLE_WINDOW) {
369     WindowPtr window;
370     PixmapPtr winPixmap;
371 
372     window = (WindowPtr)drawable;
373     winPixmap = drawable->pScreen->GetWindowPixmap(window);
374 
375     if (!window->viewable)
376       return FALSE;
377 
378     if (winPixmap != scrPixmap)
379       return FALSE;
380 
381     return TRUE;
382   }
383 
384   if (drawable != &scrPixmap->drawable)
385     return FALSE;
386 
387   return TRUE;
388 }
389 
390 /////////////////////////////////////////////////////////////////////////////
391 //
392 // screen functions
393 //
394 
395 // Unwrap and rewrap helpers
396 
397 #define SCREEN_PROLOGUE(scrn,field)                                       \
398   ScreenPtr pScreen = scrn;                                               \
399   vncHooksScreenPtr vncHooksScreen = vncHooksScreenPrivate(pScreen);      \
400   unwrap(vncHooksScreen, pScreen, field);                                 \
401   DBGPRINT((stderr,"vncHooks" #field " called\n"));
402 
403 #define SCREEN_EPILOGUE(field)                                            \
404   wrap(vncHooksScreen, pScreen, field, vncHooks##field);                  \
405 
406 
407 // CloseScreen - unwrap the screen functions and call the original CloseScreen
408 // function
409 
vncHooksCloseScreen(ScreenPtr pScreen_)410 static Bool vncHooksCloseScreen(ScreenPtr pScreen_)
411 {
412   PictureScreenPtr ps;
413   rrScrPrivPtr rp;
414 
415   SCREEN_PROLOGUE(pScreen_, CloseScreen);
416 
417   unwrap(vncHooksScreen, pScreen, CreateGC);
418   unwrap(vncHooksScreen, pScreen, CopyWindow);
419   unwrap(vncHooksScreen, pScreen, ClearToBackground);
420   unwrap(vncHooksScreen, pScreen, DisplayCursor);
421   unwrap(vncHooksScreen, pScreen, BlockHandler);
422   ps = GetPictureScreenIfSet(pScreen);
423   if (ps) {
424     unwrap(vncHooksScreen, ps, Composite);
425     unwrap(vncHooksScreen, ps, Glyphs);
426     unwrap(vncHooksScreen, ps, CompositeRects);
427     unwrap(vncHooksScreen, ps, Trapezoids);
428     unwrap(vncHooksScreen, ps, Triangles);
429     unwrap(vncHooksScreen, ps, TriStrip);
430     unwrap(vncHooksScreen, ps, TriFan);
431   }
432   rp = rrGetScrPriv(pScreen);
433   if (rp) {
434     unwrap(vncHooksScreen, rp, rrSetConfig);
435     unwrap(vncHooksScreen, rp, rrScreenSetSize);
436     unwrap(vncHooksScreen, rp, rrCrtcSet);
437   }
438 
439   DBGPRINT((stderr,"vncHooksCloseScreen: unwrapped screen functions\n"));
440 
441   return (*pScreen->CloseScreen)(pScreen);
442 }
443 
444 // CreateGC - wrap the "GC funcs"
445 
vncHooksCreateGC(GCPtr pGC)446 static Bool vncHooksCreateGC(GCPtr pGC)
447 {
448   vncHooksGCPtr vncHooksGC = vncHooksGCPrivate(pGC);
449   Bool ret;
450 
451   SCREEN_PROLOGUE(pGC->pScreen, CreateGC);
452 
453   ret = (*pScreen->CreateGC) (pGC);
454 
455   vncHooksGC->ops = NULL;
456   vncHooksGC->funcs = pGC->funcs;
457   pGC->funcs = &vncHooksGCFuncs;
458 
459   SCREEN_EPILOGUE(CreateGC);
460 
461   return ret;
462 }
463 
464 // CopyWindow - destination of the copy is the old region, clipped by
465 // borderClip, translated by the delta.  This call only does the copy - it
466 // doesn't affect any other bits.
467 
vncHooksCopyWindow(WindowPtr pWin,DDXPointRec ptOldOrg,RegionPtr pOldRegion)468 static void vncHooksCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg,
469                                RegionPtr pOldRegion)
470 {
471   int dx, dy;
472   BoxRec screen_box;
473   RegionRec copied, screen_rgn;
474 
475   SCREEN_PROLOGUE(pWin->drawable.pScreen, CopyWindow);
476 
477   RegionNull(&copied);
478   RegionCopy(&copied, pOldRegion);
479 
480   screen_box.x1 = 0;
481   screen_box.y1 = 0;
482   screen_box.x2 = pScreen->width;
483   screen_box.y2 = pScreen->height;
484 
485   RegionInitBoxes(&screen_rgn, &screen_box, 1);
486 
487   dx = pWin->drawable.x - ptOldOrg.x;
488   dy = pWin->drawable.y - ptOldOrg.y;
489 
490   // RFB tracks copies in terms of destination rectangle, not source.
491   // We also need to copy with changes to the Window's clipping region.
492   // Finally, make sure we don't get copies to or from regions outside
493   // the framebuffer.
494   RegionIntersect(&copied, &copied, &screen_rgn);
495   RegionTranslate(&copied, dx, dy);
496   RegionIntersect(&copied, &copied, &screen_rgn);
497   RegionIntersect(&copied, &copied, &pWin->borderClip);
498 
499   (*pScreen->CopyWindow) (pWin, ptOldOrg, pOldRegion);
500 
501   add_copied(pScreen, &copied, dx, dy);
502 
503   RegionUninit(&copied);
504   RegionUninit(&screen_rgn);
505 
506   SCREEN_EPILOGUE(CopyWindow);
507 }
508 
509 // ClearToBackground - changed region is the given rectangle, clipped by
510 // clipList, but only if generateExposures is false.
511 
vncHooksClearToBackground(WindowPtr pWin,int x,int y,int w,int h,Bool generateExposures)512 static void vncHooksClearToBackground(WindowPtr pWin, int x, int y, int w,
513                                       int h, Bool generateExposures)
514 {
515   BoxRec box;
516   RegionRec reg;
517 
518   SCREEN_PROLOGUE(pWin->drawable.pScreen, ClearToBackground);
519 
520   box.x1 = x + pWin->drawable.x;
521   box.y1 = y + pWin->drawable.y;
522   box.x2 = w ? (box.x1 + w) : (pWin->drawable.x + pWin->drawable.width);
523   box.y2 = h ? (box.y1 + h) : (pWin->drawable.y + pWin->drawable.height);
524 
525   RegionInitBoxes(&reg, &box, 1);
526   RegionIntersect(&reg, &reg, &pWin->clipList);
527 
528   (*pScreen->ClearToBackground) (pWin, x, y, w, h, generateExposures);
529 
530   if (!generateExposures) {
531     add_changed(pScreen, &reg);
532   }
533 
534   RegionUninit(&reg);
535 
536   SCREEN_EPILOGUE(ClearToBackground);
537 }
538 
539 // DisplayCursor - get the cursor shape
540 
vncHooksDisplayCursor(DeviceIntPtr pDev,ScreenPtr pScreen_,CursorPtr cursor)541 static Bool vncHooksDisplayCursor(DeviceIntPtr pDev,
542                                   ScreenPtr pScreen_, CursorPtr cursor)
543 {
544   Bool ret;
545 
546   SCREEN_PROLOGUE(pScreen_, DisplayCursor);
547 
548   ret = (*pScreen->DisplayCursor) (pDev, pScreen, cursor);
549 
550   /*
551    * XXX DIX calls this function with NULL argument to remove cursor sprite from
552    * screen. Should we handle this in setCursor as well?
553    */
554   if (cursor != NullCursor) {
555     int width, height;
556     int hotX, hotY;
557 
558     unsigned char *rgbaData;
559 
560     width = cursor->bits->width;
561     height = cursor->bits->height;
562 
563     hotX = cursor->bits->xhot;
564     hotY = cursor->bits->yhot;
565 
566     rgbaData = malloc(width * height * 4);
567     if (rgbaData == NULL)
568       goto out;
569 
570     if (cursor->bits->argb) {
571       unsigned char *out;
572       CARD32 *in;
573       int i;
574 
575       in = cursor->bits->argb;
576       out = rgbaData;
577       for (i = 0; i < width*height; i++) {
578         out[0] = (*in >> 16) & 0xff;
579         out[1] = (*in >>  8) & 0xff;
580         out[2] = (*in >>  0) & 0xff;
581         out[3] = (*in >> 24) & 0xff;
582         out += 4;
583         in++;
584       }
585     } else {
586       unsigned char *out;
587       int xMaskBytesPerRow;
588 
589       xMaskBytesPerRow = BitmapBytePad(width);
590 
591       out = rgbaData;
592       for (int y = 0; y < height; y++) {
593         for (int x = 0; x < width; x++) {
594           int byte = y * xMaskBytesPerRow + x / 8;
595 #if (BITMAP_BIT_ORDER == MSBFirst)
596           int bit = 7 - x % 8;
597 #else
598           int bit = x % 8;
599 #endif
600 
601           if (cursor->bits->source[byte] & (1 << bit)) {
602             out[0] = cursor->foreRed;
603             out[1] = cursor->foreGreen;
604             out[2] = cursor->foreBlue;
605           } else {
606             out[0] = cursor->backRed;
607             out[1] = cursor->backGreen;
608             out[2] = cursor->backBlue;
609           }
610 
611           if (cursor->bits->mask[byte] & (1 << bit))
612             out[3] = 0xff;
613           else
614             out[3] = 0x00;
615 
616           out += 4;
617         }
618       }
619     }
620 
621     vncSetCursorSprite(width, height, hotX, hotY, rgbaData);
622 
623     free(rgbaData);
624   }
625 
626 out:
627   SCREEN_EPILOGUE(DisplayCursor);
628 
629   return ret;
630 }
631 
632 // CursorWarpedTo - notify that the cursor was warped
633 
634 #if XORG_AT_LEAST(1, 19, 0)
vncHooksCursorWarpedTo(DeviceIntPtr pDev,ScreenPtr pScreen_,ClientPtr pClient,WindowPtr pWindow,SpritePtr pSprite,int x,int y)635 static void vncHooksCursorWarpedTo(DeviceIntPtr pDev,
636                                    ScreenPtr pScreen_, ClientPtr pClient,
637                                    WindowPtr pWindow, SpritePtr pSprite,
638                                    int x, int y)
639 {
640   SCREEN_PROLOGUE(pScreen_, CursorWarpedTo);
641   vncSetCursorPos(pScreen->myNum, x, y);
642   SCREEN_EPILOGUE(CursorWarpedTo);
643 }
644 #endif
645 
646 // BlockHandler - ignore any changes during the block handler - it's likely
647 // these are just drawing the cursor.
648 
649 #if XORG_AT_LEAST(1, 19, 0)
vncHooksBlockHandler(ScreenPtr pScreen_,void * pTimeout)650 static void vncHooksBlockHandler(ScreenPtr pScreen_, void * pTimeout)
651 #else
652 static void vncHooksBlockHandler(ScreenPtr pScreen_, void * pTimeout,
653                                  void * pReadmask)
654 #endif
655 {
656   SCREEN_PROLOGUE(pScreen_, BlockHandler);
657 
658   vncHooksScreen->ignoreHooks++;
659 
660 #if XORG_AT_LEAST(1, 19, 0)
661   (*pScreen->BlockHandler) (pScreen, pTimeout);
662 #else
663   (*pScreen->BlockHandler) (pScreen, pTimeout, pReadmask);
664 #endif
665 
666   vncHooksScreen->ignoreHooks--;
667 
668   SCREEN_EPILOGUE(BlockHandler);
669 }
670 
671 // Unwrap and rewrap helpers
672 
673 #define RENDER_PROLOGUE(scrn,field)                                       \
674   ScreenPtr pScreen = scrn;                                               \
675   PictureScreenPtr ps = GetPictureScreen(pScreen);                        \
676   vncHooksScreenPtr vncHooksScreen = vncHooksScreenPrivate(pScreen);      \
677   unwrap(vncHooksScreen, ps, field);                                      \
678   DBGPRINT((stderr,"vncHooks" #field " called\n"));
679 
680 #define RENDER_EPILOGUE(field)                                            \
681   wrap(vncHooksScreen, ps, field, vncHooks##field);                       \
682 
683 // Composite - The core of XRENDER
684 
vncHooksComposite(CARD8 op,PicturePtr pSrc,PicturePtr pMask,PicturePtr pDst,INT16 xSrc,INT16 ySrc,INT16 xMask,INT16 yMask,INT16 xDst,INT16 yDst,CARD16 width,CARD16 height)685 static void vncHooksComposite(CARD8 op, PicturePtr pSrc, PicturePtr pMask,
686 		       PicturePtr pDst, INT16 xSrc, INT16 ySrc, INT16 xMask,
687 		       INT16 yMask, INT16 xDst, INT16 yDst, CARD16 width, CARD16 height)
688 {
689   RegionRec changed;
690 
691   RENDER_PROLOGUE(pDst->pDrawable->pScreen, Composite);
692 
693   if (is_visible(pDst->pDrawable)) {
694     BoxRec box;
695     RegionRec fbreg;
696 
697     box.x1 = max(pDst->pDrawable->x + xDst, 0);
698     box.y1 = max(pDst->pDrawable->y + yDst, 0);
699     box.x2 = box.x1 + width;
700     box.y2 = box.y1 + height;
701     RegionInitBoxes(&changed, &box, 1);
702 
703     box.x1 = 0;
704     box.y1 = 0;
705     box.x2 = pScreen->width;
706     box.y2 = pScreen->height;
707     RegionInitBoxes(&fbreg, &box, 1);
708 
709     RegionIntersect(&changed, &changed, &fbreg);
710 
711     RegionUninit(&fbreg);
712   } else {
713     RegionNull(&changed);
714   }
715 
716 
717   (*ps->Composite)(op, pSrc, pMask, pDst, xSrc, ySrc,
718 		   xMask, yMask, xDst, yDst, width, height);
719 
720   add_changed(pScreen, &changed);
721 
722   RegionUninit(&changed);
723 
724   RENDER_EPILOGUE(Composite);
725 }
726 
727 static RegionPtr
GlyphsToRegion(ScreenPtr pScreen,int nlist,GlyphListPtr list,GlyphPtr * glyphs)728 GlyphsToRegion(ScreenPtr pScreen, int nlist, GlyphListPtr list, GlyphPtr *glyphs)
729 {
730   int n;
731   GlyphPtr glyph;
732   int x, y;
733 
734   int nrects = nlist;
735   xRectangle rects[nrects];
736   xRectanglePtr rect;
737 
738   x = 0;
739   y = 0;
740   rect = &rects[0];
741   while (nlist--) {
742     int left, right, top, bottom;
743 
744     x += list->xOff;
745     y += list->yOff;
746     n = list->len;
747     list++;
748 
749     left = INT_MAX;
750     top = INT_MAX;
751     right = -INT_MAX;
752     bottom = -INT_MAX;
753     while (n--) {
754       int gx, gy, gw, gh;
755 
756       glyph = *glyphs++;
757       gx = x - glyph->info.x;
758       gy = y - glyph->info.y;
759       gw = glyph->info.width;
760       gh = glyph->info.height;
761       x += glyph->info.xOff;
762       y += glyph->info.yOff;
763 
764       if (gx < left)
765         left = gx;
766       if (gy < top)
767         top = gy;
768       if (gx + gw > right)
769         right = gx + gw;
770       if (gy + gh > bottom)
771         bottom = gy + gh;
772     }
773 
774     rect->x = left;
775     rect->y = top;
776     if ((right > left) && (bottom > top)) {
777       rect->width = right - left;
778       rect->height = bottom - top;
779     } else {
780       rect->width = 0;
781       rect->height = 0;
782     }
783     rect++;
784   }
785 
786   return RECTS_TO_REGION(pScreen, nrects, rects, CT_NONE);
787 }
788 
789 // Glyphs - Glyph specific version of Composite (caches and whatnot)
790 
vncHooksGlyphs(CARD8 op,PicturePtr pSrc,PicturePtr pDst,PictFormatPtr maskFormat,INT16 xSrc,INT16 ySrc,int nlists,GlyphListPtr lists,GlyphPtr * glyphs)791 static void vncHooksGlyphs(CARD8 op, PicturePtr pSrc, PicturePtr pDst,
792            PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, int nlists,
793            GlyphListPtr lists, GlyphPtr * glyphs)
794 {
795   RegionPtr changed;
796 
797   RENDER_PROLOGUE(pDst->pDrawable->pScreen, Glyphs);
798 
799   if (is_visible(pDst->pDrawable)) {
800     BoxRec fbbox;
801     RegionRec fbreg;
802 
803     changed = GlyphsToRegion(pScreen, nlists, lists, glyphs);
804     RegionTranslate(changed,
805                      pDst->pDrawable->x, pDst->pDrawable->y);
806 
807     fbbox.x1 = 0;
808     fbbox.y1 = 0;
809     fbbox.x2 = pScreen->width;
810     fbbox.y2 = pScreen->height;
811     RegionInitBoxes(&fbreg, &fbbox, 1);
812 
813     RegionIntersect(changed, changed, &fbreg);
814 
815     RegionUninit(&fbreg);
816   } else {
817     changed = RegionCreate(NullBox, 0);
818   }
819 
820   (*ps->Glyphs)(op, pSrc, pDst, maskFormat, xSrc, ySrc, nlists, lists, glyphs);
821 
822   add_changed(pScreen, changed);
823 
824   RegionDestroy(changed);
825 
826   RENDER_EPILOGUE(Glyphs);
827 }
828 
vncHooksCompositeRects(CARD8 op,PicturePtr pDst,xRenderColor * color,int nRect,xRectangle * rects)829 static void vncHooksCompositeRects(CARD8 op, PicturePtr pDst,
830             xRenderColor * color, int nRect, xRectangle *rects)
831 {
832   RegionPtr changed;
833 
834   RENDER_PROLOGUE(pDst->pDrawable->pScreen, CompositeRects);
835 
836   if (is_visible(pDst->pDrawable)) {
837     changed = RECTS_TO_REGION(pScreen, nRect, rects, CT_NONE);
838   } else {
839     changed = RegionCreate(NullBox, 0);
840   }
841 
842   (*ps->CompositeRects)(op, pDst, color, nRect, rects);
843 
844   add_changed(pScreen, changed);
845 
846   RegionDestroy(changed);
847 
848   RENDER_EPILOGUE(CompositeRects);
849 }
850 
FixedToShort(xFixed fixed)851 static inline short FixedToShort(xFixed fixed)
852 {
853   return (fixed + 0x8000) >> 16;
854 }
855 
vncHooksTrapezoids(CARD8 op,PicturePtr pSrc,PicturePtr pDst,PictFormatPtr maskFormat,INT16 xSrc,INT16 ySrc,int ntrap,xTrapezoid * traps)856 static void vncHooksTrapezoids(CARD8 op, PicturePtr pSrc, PicturePtr pDst,
857             PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
858             int ntrap, xTrapezoid * traps)
859 {
860   RegionRec changed;
861 
862   RENDER_PROLOGUE(pDst->pDrawable->pScreen, Trapezoids);
863 
864   if (is_visible(pDst->pDrawable)) {
865     BoxRec box;
866     RegionRec fbreg;
867 
868     // FIXME: We do a very crude bounding box around everything.
869     //        Might not be worth optimizing since this call is rarely
870     //        used.
871     box.x1 = SHRT_MAX;
872     box.y1 = SHRT_MAX;
873     box.x2 = 0;
874     box.y2 = 0;
875     for (int i = 0;i < ntrap;i++) {
876       if (FixedToShort(traps[i].left.p1.x) < box.x1)
877         box.x1 = FixedToShort(traps[i].left.p1.x);
878       if (FixedToShort(traps[i].left.p2.x) < box.x1)
879         box.x1 = FixedToShort(traps[i].left.p2.x);
880       if (FixedToShort(traps[i].top) < box.y1)
881         box.y1 = FixedToShort(traps[i].top);
882       if (FixedToShort(traps[i].right.p1.x) > box.x2)
883         box.x2 = FixedToShort(traps[i].right.p1.x);
884       if (FixedToShort(traps[i].right.p2.x) > box.x2)
885         box.x2 = FixedToShort(traps[i].right.p2.x);
886       if (FixedToShort(traps[i].bottom) > box.y2)
887         box.y2 = FixedToShort(traps[i].bottom);
888     }
889 
890     box.x1 += pDst->pDrawable->x;
891     box.y1 += pDst->pDrawable->y;
892     box.x2 += pDst->pDrawable->x;
893     box.y2 += pDst->pDrawable->y;
894     RegionInitBoxes(&changed, &box, 1);
895 
896     box.x1 = 0;
897     box.y1 = 0;
898     box.x2 = pScreen->width;
899     box.y2 = pScreen->height;
900     RegionInitBoxes(&fbreg, &box, 1);
901 
902     RegionIntersect(&changed, &changed, &fbreg);
903 
904     RegionUninit(&fbreg);
905   } else {
906     RegionNull(&changed);
907   }
908 
909   (*ps->Trapezoids)(op, pSrc, pDst, maskFormat, xSrc, ySrc, ntrap, traps);
910 
911   add_changed(pScreen, &changed);
912 
913   RegionUninit(&changed);
914 
915   RENDER_EPILOGUE(Trapezoids);
916 }
917 
vncHooksTriangles(CARD8 op,PicturePtr pSrc,PicturePtr pDst,PictFormatPtr maskFormat,INT16 xSrc,INT16 ySrc,int ntri,xTriangle * tris)918 static void vncHooksTriangles(CARD8 op, PicturePtr pSrc, PicturePtr pDst,
919             PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
920             int ntri, xTriangle * tris)
921 {
922   RegionRec changed;
923 
924   RENDER_PROLOGUE(pDst->pDrawable->pScreen, Triangles);
925 
926   if (is_visible(pDst->pDrawable)) {
927     BoxRec box;
928     RegionRec fbreg;
929 
930     // FIXME: We do a very crude bounding box around everything.
931     //        Might not be worth optimizing since this call is rarely
932     //        used.
933     box.x1 = SHRT_MAX;
934     box.y1 = SHRT_MAX;
935     box.x2 = 0;
936     box.y2 = 0;
937     for (int i = 0;i < ntri;i++) {
938       xFixed left, right, top, bottom;
939 
940       left = min(min(tris[i].p1.x, tris[i].p2.x), tris[i].p3.x);
941       right = max(max(tris[i].p1.x, tris[i].p2.x), tris[i].p3.x);
942       top = min(min(tris[i].p1.y, tris[i].p2.y), tris[i].p3.y);
943       bottom = max(max(tris[i].p1.y, tris[i].p2.y), tris[i].p3.y);
944 
945       if (FixedToShort(left) < box.x1)
946         box.x1 = FixedToShort(left);
947       if (FixedToShort(top) < box.y1)
948         box.y1 = FixedToShort(top);
949       if (FixedToShort(right) > box.x2)
950         box.x2 = FixedToShort(right);
951       if (FixedToShort(bottom) > box.y2)
952         box.y2 = FixedToShort(bottom);
953     }
954 
955     box.x1 += pDst->pDrawable->x;
956     box.y1 += pDst->pDrawable->y;
957     box.x2 += pDst->pDrawable->x;
958     box.y2 += pDst->pDrawable->y;
959     RegionInitBoxes(&changed, &box, 1);
960 
961     box.x1 = 0;
962     box.y1 = 0;
963     box.x2 = pScreen->width;
964     box.y2 = pScreen->height;
965     RegionInitBoxes(&fbreg, &box, 1);
966 
967     RegionIntersect(&changed, &changed, &fbreg);
968 
969     RegionUninit(&fbreg);
970   } else {
971     RegionNull(&changed);
972   }
973 
974   (*ps->Triangles)(op, pSrc, pDst, maskFormat, xSrc, ySrc, ntri, tris);
975 
976   add_changed(pScreen, &changed);
977 
978   RegionUninit(&changed);
979 
980   RENDER_EPILOGUE(Triangles);
981 }
982 
vncHooksTriStrip(CARD8 op,PicturePtr pSrc,PicturePtr pDst,PictFormatPtr maskFormat,INT16 xSrc,INT16 ySrc,int npoint,xPointFixed * points)983 static void vncHooksTriStrip(CARD8 op, PicturePtr pSrc, PicturePtr pDst,
984             PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
985             int npoint, xPointFixed * points)
986 {
987   RegionRec changed;
988 
989   RENDER_PROLOGUE(pDst->pDrawable->pScreen, TriStrip);
990 
991   if (is_visible(pDst->pDrawable)) {
992     BoxRec box;
993     RegionRec fbreg;
994 
995     // FIXME: We do a very crude bounding box around everything.
996     //        Might not be worth optimizing since this call is rarely
997     //        used.
998     box.x1 = SHRT_MAX;
999     box.y1 = SHRT_MAX;
1000     box.x2 = 0;
1001     box.y2 = 0;
1002     for (int i = 0;i < npoint;i++) {
1003       if (FixedToShort(points[i].x) < box.x1)
1004         box.x1 = FixedToShort(points[i].x);
1005       if (FixedToShort(points[i].y) < box.y1)
1006         box.y1 = FixedToShort(points[i].y);
1007       if (FixedToShort(points[i].x) > box.x2)
1008         box.x2 = FixedToShort(points[i].x);
1009       if (FixedToShort(points[i].y) > box.y2)
1010         box.y2 = FixedToShort(points[i].y);
1011     }
1012 
1013     box.x1 += pDst->pDrawable->x;
1014     box.y1 += pDst->pDrawable->y;
1015     box.x2 += pDst->pDrawable->x;
1016     box.y2 += pDst->pDrawable->y;
1017     RegionInitBoxes(&changed, &box, 1);
1018 
1019     box.x1 = 0;
1020     box.y1 = 0;
1021     box.x2 = pScreen->width;
1022     box.y2 = pScreen->height;
1023     RegionInitBoxes(&fbreg, &box, 1);
1024 
1025     RegionIntersect(&changed, &changed, &fbreg);
1026 
1027     RegionUninit(&fbreg);
1028   } else {
1029     RegionNull(&changed);
1030   }
1031 
1032   (*ps->TriStrip)(op, pSrc, pDst, maskFormat, xSrc, ySrc, npoint, points);
1033 
1034   add_changed(pScreen, &changed);
1035 
1036   RegionUninit(&changed);
1037 
1038   RENDER_EPILOGUE(TriStrip);
1039 }
1040 
vncHooksTriFan(CARD8 op,PicturePtr pSrc,PicturePtr pDst,PictFormatPtr maskFormat,INT16 xSrc,INT16 ySrc,int npoint,xPointFixed * points)1041 static void vncHooksTriFan(CARD8 op, PicturePtr pSrc, PicturePtr pDst,
1042             PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
1043             int npoint, xPointFixed * points)
1044 {
1045   RegionRec changed;
1046 
1047   RENDER_PROLOGUE(pDst->pDrawable->pScreen, TriFan);
1048 
1049   if (is_visible(pDst->pDrawable)) {
1050     BoxRec box;
1051     RegionRec fbreg;
1052 
1053     // FIXME: We do a very crude bounding box around everything.
1054     //        Might not be worth optimizing since this call is rarely
1055     //        used.
1056     box.x1 = SHRT_MAX;
1057     box.y1 = SHRT_MAX;
1058     box.x2 = 0;
1059     box.y2 = 0;
1060     for (int i = 0;i < npoint;i++) {
1061       if (FixedToShort(points[i].x) < box.x1)
1062         box.x1 = FixedToShort(points[i].x);
1063       if (FixedToShort(points[i].y) < box.y1)
1064         box.y1 = FixedToShort(points[i].y);
1065       if (FixedToShort(points[i].x) > box.x2)
1066         box.x2 = FixedToShort(points[i].x);
1067       if (FixedToShort(points[i].y) > box.y2)
1068         box.y2 = FixedToShort(points[i].y);
1069     }
1070 
1071     box.x1 += pDst->pDrawable->x;
1072     box.y1 += pDst->pDrawable->y;
1073     box.x2 += pDst->pDrawable->x;
1074     box.y2 += pDst->pDrawable->y;
1075     RegionInitBoxes(&changed, &box, 1);
1076 
1077     box.x1 = 0;
1078     box.y1 = 0;
1079     box.x2 = pScreen->width;
1080     box.y2 = pScreen->height;
1081     RegionInitBoxes(&fbreg, &box, 1);
1082 
1083     RegionIntersect(&changed, &changed, &fbreg);
1084 
1085     RegionUninit(&fbreg);
1086   } else {
1087     RegionNull(&changed);
1088   }
1089 
1090   (*ps->TriFan)(op, pSrc, pDst, maskFormat, xSrc, ySrc, npoint, points);
1091 
1092   add_changed(pScreen, &changed);
1093 
1094   RegionUninit(&changed);
1095 
1096   RENDER_EPILOGUE(TriFan);
1097 }
1098 
1099 // Unwrap and rewrap helpers
1100 
1101 #define RANDR_PROLOGUE(field)                                             \
1102   rrScrPrivPtr rp = rrGetScrPriv(pScreen);                                \
1103   vncHooksScreenPtr vncHooksScreen = vncHooksScreenPrivate(pScreen);      \
1104   unwrap(vncHooksScreen, rp, rr##field);                                  \
1105   DBGPRINT((stderr,"vncHooksRandR" #field " called\n"));
1106 
1107 #define RANDR_EPILOGUE(field)                                             \
1108   wrap(vncHooksScreen, rp, rr##field, vncHooksRandR##field);              \
1109 
1110 // RandRSetConfig - follow any framebuffer changes
1111 
vncHooksRandRSetConfig(ScreenPtr pScreen,Rotation rotation,int rate,RRScreenSizePtr pSize)1112 static Bool vncHooksRandRSetConfig(ScreenPtr pScreen, Rotation rotation,
1113                                    int rate, RRScreenSizePtr pSize)
1114 {
1115   Bool ret;
1116 
1117   RANDR_PROLOGUE(SetConfig);
1118 
1119   vncPreScreenResize(pScreen->myNum);
1120   ret = (*rp->rrSetConfig)(pScreen, rotation, rate, pSize);
1121   vncPostScreenResize(pScreen->myNum, ret, pScreen->width, pScreen->height);
1122 
1123   RANDR_EPILOGUE(SetConfig);
1124 
1125   if (!ret)
1126     return FALSE;
1127 
1128   return TRUE;
1129 }
1130 
vncHooksRandRScreenSetSize(ScreenPtr pScreen,CARD16 width,CARD16 height,CARD32 mmWidth,CARD32 mmHeight)1131 static Bool vncHooksRandRScreenSetSize(ScreenPtr pScreen,
1132                                        CARD16 width, CARD16 height,
1133                                        CARD32 mmWidth, CARD32 mmHeight)
1134 {
1135   Bool ret;
1136 
1137   RANDR_PROLOGUE(ScreenSetSize);
1138 
1139   vncPreScreenResize(pScreen->myNum);
1140   ret = (*rp->rrScreenSetSize)(pScreen, width, height, mmWidth, mmHeight);
1141   vncPostScreenResize(pScreen->myNum, ret, pScreen->width, pScreen->height);
1142 
1143   RANDR_EPILOGUE(ScreenSetSize);
1144 
1145   if (!ret)
1146     return FALSE;
1147 
1148   return TRUE;
1149 }
1150 
vncHooksRandRCrtcSet(ScreenPtr pScreen,RRCrtcPtr crtc,RRModePtr mode,int x,int y,Rotation rotation,int num_outputs,RROutputPtr * outputs)1151 static Bool vncHooksRandRCrtcSet(ScreenPtr pScreen, RRCrtcPtr crtc,
1152                                  RRModePtr mode, int x, int y,
1153                                  Rotation rotation, int num_outputs,
1154                                  RROutputPtr *outputs)
1155 {
1156   Bool ret;
1157 
1158   RANDR_PROLOGUE(CrtcSet);
1159 
1160   ret = (*rp->rrCrtcSet)(pScreen, crtc, mode, x, y, rotation,
1161                          num_outputs, outputs);
1162 
1163   RANDR_EPILOGUE(CrtcSet);
1164 
1165   if (!ret)
1166     return FALSE;
1167 
1168   vncRefreshScreenLayout(pScreen->myNum);
1169 
1170   return TRUE;
1171 }
1172 
1173 /////////////////////////////////////////////////////////////////////////////
1174 //
1175 // GC "funcs"
1176 //
1177 
1178 // Unwrap and rewrap helpers
1179 
1180 #define GC_FUNC_PROLOGUE(pGC, name)\
1181     vncHooksGCPtr pGCPriv = vncHooksGCPrivate(pGC);\
1182     unwrap(pGCPriv, pGC, funcs);\
1183     if (pGCPriv->ops) unwrap(pGCPriv, pGC, ops)\
1184     DBGPRINT((stderr,"vncHooks" #name " called\n"))
1185 
1186 #define GC_FUNC_EPILOGUE(pGC)\
1187     wrap(pGCPriv, pGC, funcs, &vncHooksGCFuncs);\
1188     if (pGCPriv->ops) wrap(pGCPriv, pGC, ops, &vncHooksGCOps)
1189 
1190 // ValidateGC - wrap the "ops" if the drawable is on screen
1191 
vncHooksValidateGC(GCPtr pGC,unsigned long changes,DrawablePtr pDrawable)1192 static void vncHooksValidateGC(GCPtr pGC, unsigned long changes,
1193                                DrawablePtr pDrawable)
1194 {
1195   GC_FUNC_PROLOGUE(pGC, ValidateGC);
1196   (*pGC->funcs->ValidateGC) (pGC, changes, pDrawable);
1197   if (is_visible(pDrawable)) {
1198     pGCPriv->ops = pGC->ops;
1199     DBGPRINT((stderr,"vncHooksValidateGC: wrapped GC ops\n"));
1200   } else {
1201     pGCPriv->ops = NULL;
1202   }
1203   GC_FUNC_EPILOGUE(pGC);
1204 }
1205 
1206 // Other GC funcs - just unwrap and call on
1207 
vncHooksChangeGC(GCPtr pGC,unsigned long mask)1208 static void vncHooksChangeGC(GCPtr pGC, unsigned long mask) {
1209   GC_FUNC_PROLOGUE(pGC, ChangeGC);
1210   (*pGC->funcs->ChangeGC) (pGC, mask);
1211   GC_FUNC_EPILOGUE(pGC);
1212 }
vncHooksCopyGC(GCPtr src,unsigned long mask,GCPtr dst)1213 static void vncHooksCopyGC(GCPtr src, unsigned long mask, GCPtr dst) {
1214   GC_FUNC_PROLOGUE(dst, CopyGC);
1215   (*dst->funcs->CopyGC) (src, mask, dst);
1216   GC_FUNC_EPILOGUE(dst);
1217 }
vncHooksDestroyGC(GCPtr pGC)1218 static void vncHooksDestroyGC(GCPtr pGC) {
1219   GC_FUNC_PROLOGUE(pGC, DestroyGC);
1220   (*pGC->funcs->DestroyGC) (pGC);
1221   GC_FUNC_EPILOGUE(pGC);
1222 }
vncHooksChangeClip(GCPtr pGC,int type,void * pValue,int nrects)1223 static void vncHooksChangeClip(GCPtr pGC, int type, void * pValue, int nrects)
1224 {
1225   GC_FUNC_PROLOGUE(pGC, ChangeClip);
1226   (*pGC->funcs->ChangeClip) (pGC, type, pValue, nrects);
1227   GC_FUNC_EPILOGUE(pGC);
1228 }
vncHooksDestroyClip(GCPtr pGC)1229 static void vncHooksDestroyClip(GCPtr pGC) {
1230   GC_FUNC_PROLOGUE(pGC, DestroyClip);
1231   (*pGC->funcs->DestroyClip) (pGC);
1232   GC_FUNC_EPILOGUE(pGC);
1233 }
vncHooksCopyClip(GCPtr dst,GCPtr src)1234 static void vncHooksCopyClip(GCPtr dst, GCPtr src) {
1235   GC_FUNC_PROLOGUE(dst, CopyClip);
1236   (*dst->funcs->CopyClip) (dst, src);
1237   GC_FUNC_EPILOGUE(dst);
1238 }
1239 
1240 
1241 /////////////////////////////////////////////////////////////////////////////
1242 //
1243 // GC "ops"
1244 //
1245 
1246 // Unwrap and rewrap helpers
1247 
1248 #define GC_OP_PROLOGUE(pGC, name)\
1249     vncHooksGCPtr pGCPriv = vncHooksGCPrivate(pGC);\
1250     const GCFuncs *oldFuncs = pGC->funcs;\
1251     unwrap(pGCPriv, pGC, funcs);\
1252     unwrap(pGCPriv, pGC, ops);\
1253     DBGPRINT((stderr,"vncHooks" #name " called\n"))
1254 
1255 #define GC_OP_EPILOGUE(pGC)\
1256     wrap(pGCPriv, pGC, funcs, oldFuncs); \
1257     wrap(pGCPriv, pGC, ops, &vncHooksGCOps)
1258 
1259 // FillSpans - assume the entire clip region is damaged. This is pessimistic,
1260 // but I believe this function is rarely used so it doesn't matter.
1261 
vncHooksFillSpans(DrawablePtr pDrawable,GCPtr pGC,int nInit,DDXPointPtr pptInit,int * pwidthInit,int fSorted)1262 static void vncHooksFillSpans(DrawablePtr pDrawable, GCPtr pGC, int nInit,
1263                               DDXPointPtr pptInit, int *pwidthInit,
1264                               int fSorted)
1265 {
1266   RegionRec reg;
1267 
1268   GC_OP_PROLOGUE(pGC, FillSpans);
1269 
1270   RegionNull(&reg);
1271   RegionCopy(&reg, pGC->pCompositeClip);
1272 
1273   if (pDrawable->type == DRAWABLE_WINDOW)
1274     RegionIntersect(&reg, &reg, &((WindowPtr)pDrawable)->borderClip);
1275 
1276   (*pGC->ops->FillSpans) (pDrawable, pGC, nInit, pptInit, pwidthInit, fSorted);
1277 
1278   add_changed(pGC->pScreen, &reg);
1279 
1280   RegionUninit(&reg);
1281 
1282   GC_OP_EPILOGUE(pGC);
1283 }
1284 
1285 // SetSpans - assume the entire clip region is damaged.  This is pessimistic,
1286 // but I believe this function is rarely used so it doesn't matter.
1287 
vncHooksSetSpans(DrawablePtr pDrawable,GCPtr pGC,char * psrc,DDXPointPtr ppt,int * pwidth,int nspans,int fSorted)1288 static void vncHooksSetSpans(DrawablePtr pDrawable, GCPtr pGC, char *psrc,
1289                              DDXPointPtr ppt, int *pwidth, int nspans,
1290                              int fSorted)
1291 {
1292   RegionRec reg;
1293 
1294   GC_OP_PROLOGUE(pGC, SetSpans);
1295 
1296   RegionNull(&reg);
1297   RegionCopy(&reg, pGC->pCompositeClip);
1298 
1299   if (pDrawable->type == DRAWABLE_WINDOW)
1300     RegionIntersect(&reg, &reg, &((WindowPtr)pDrawable)->borderClip);
1301 
1302   (*pGC->ops->SetSpans) (pDrawable, pGC, psrc, ppt, pwidth, nspans, fSorted);
1303 
1304   add_changed(pGC->pScreen, &reg);
1305 
1306   RegionUninit(&reg);
1307 
1308   GC_OP_EPILOGUE(pGC);
1309 }
1310 
1311 // PutImage - changed region is the given rectangle, clipped by pCompositeClip
1312 
vncHooksPutImage(DrawablePtr pDrawable,GCPtr pGC,int depth,int x,int y,int w,int h,int leftPad,int format,char * pBits)1313 static void vncHooksPutImage(DrawablePtr pDrawable, GCPtr pGC, int depth,
1314                              int x, int y, int w, int h, int leftPad,
1315                              int format, char *pBits)
1316 {
1317   BoxRec box;
1318   RegionRec reg;
1319 
1320   GC_OP_PROLOGUE(pGC, PutImage);
1321 
1322   box.x1 = x + pDrawable->x;
1323   box.y1 = y + pDrawable->y;
1324   box.x2 = box.x1 + w;
1325   box.y2 = box.y1 + h;
1326 
1327   RegionInitBoxes(&reg, &box, 1);
1328   RegionIntersect(&reg, &reg, pGC->pCompositeClip);
1329 
1330   (*pGC->ops->PutImage) (pDrawable, pGC, depth, x, y, w, h, leftPad, format,
1331                          pBits);
1332 
1333   add_changed(pGC->pScreen, &reg);
1334 
1335   RegionUninit(&reg);
1336 
1337   GC_OP_EPILOGUE(pGC);
1338 }
1339 
1340 // CopyArea - destination of the copy is the dest rectangle, clipped by
1341 // pCompositeClip.  Any parts of the destination which cannot be copied from
1342 // the source (could be all of it) go into the changed region.
1343 
vncHooksCopyArea(DrawablePtr pSrc,DrawablePtr pDst,GCPtr pGC,int srcx,int srcy,int w,int h,int dstx,int dsty)1344 static RegionPtr vncHooksCopyArea(DrawablePtr pSrc, DrawablePtr pDst,
1345                                   GCPtr pGC, int srcx, int srcy, int w, int h,
1346                                   int dstx, int dsty)
1347 {
1348   RegionRec dst, src, changed;
1349 
1350   RegionPtr ret;
1351 
1352   GC_OP_PROLOGUE(pGC, CopyArea);
1353 
1354   // Apparently this happens now and then...
1355   if ((w == 0) || (h == 0))
1356     RegionNull(&dst);
1357   else {
1358     BoxRec box;
1359 
1360     box.x1 = dstx + pDst->x;
1361     box.y1 = dsty + pDst->y;
1362     box.x2 = box.x1 + w;
1363     box.y2 = box.y1 + h;
1364 
1365     RegionInitBoxes(&dst, &box, 1);
1366   }
1367 
1368   RegionIntersect(&dst, &dst, pGC->pCompositeClip);
1369 
1370   // The source of the data has to be something that's on screen.
1371   if (is_visible(pSrc)) {
1372     BoxRec box;
1373 
1374     box.x1 = srcx + pSrc->x;
1375     box.y1 = srcy + pSrc->y;
1376     box.x2 = box.x1 + w;
1377     box.y2 = box.y1 + h;
1378 
1379     RegionInitBoxes(&src, &box, 1);
1380 
1381     if ((pSrc->type == DRAWABLE_WINDOW) &&
1382         RegionNotEmpty(&((WindowPtr)pSrc)->clipList)) {
1383       RegionIntersect(&src, &src, &((WindowPtr)pSrc)->clipList);
1384     }
1385 
1386     RegionTranslate(&src,
1387                      dstx + pDst->x - srcx - pSrc->x,
1388                      dsty + pDst->y - srcy - pSrc->y);
1389   } else {
1390     RegionNull(&src);
1391   }
1392 
1393   RegionNull(&changed);
1394 
1395   RegionSubtract(&changed, &dst, &src);
1396   RegionIntersect(&dst, &dst, &src);
1397 
1398   ret = (*pGC->ops->CopyArea) (pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty);
1399 
1400   add_copied(pGC->pScreen, &dst,
1401              dstx + pDst->x - srcx - pSrc->x,
1402              dsty + pDst->y - srcy - pSrc->y);
1403 
1404   add_changed(pGC->pScreen, &changed);
1405 
1406   RegionUninit(&dst);
1407   RegionUninit(&src);
1408   RegionUninit(&changed);
1409 
1410   GC_OP_EPILOGUE(pGC);
1411 
1412   return ret;
1413 }
1414 
1415 
1416 // CopyPlane - changed region is the destination rectangle, clipped by
1417 // pCompositeClip
1418 
vncHooksCopyPlane(DrawablePtr pSrc,DrawablePtr pDst,GCPtr pGC,int srcx,int srcy,int w,int h,int dstx,int dsty,unsigned long plane)1419 static RegionPtr vncHooksCopyPlane(DrawablePtr pSrc, DrawablePtr pDst,
1420                                    GCPtr pGC, int srcx, int srcy, int w, int h,
1421                                    int dstx, int dsty, unsigned long plane)
1422 {
1423   BoxRec box;
1424   RegionRec reg;
1425 
1426   RegionPtr ret;
1427 
1428   GC_OP_PROLOGUE(pGC, CopyPlane);
1429 
1430   box.x1 = dstx + pDst->x;
1431   box.y1 = dsty + pDst->y;
1432   box.x2 = box.x1 + w;
1433   box.y2 = box.y1 + h;
1434 
1435   RegionInitBoxes(&reg, &box, 1);
1436   RegionIntersect(&reg, &reg, pGC->pCompositeClip);
1437 
1438   ret = (*pGC->ops->CopyPlane) (pSrc, pDst, pGC, srcx, srcy, w, h,
1439                                 dstx, dsty, plane);
1440 
1441   add_changed(pGC->pScreen, &reg);
1442 
1443   RegionUninit(&reg);
1444 
1445   GC_OP_EPILOGUE(pGC);
1446 
1447   return ret;
1448 }
1449 
1450 // PolyPoint - changed region is the bounding rect, clipped by pCompositeClip
1451 
vncHooksPolyPoint(DrawablePtr pDrawable,GCPtr pGC,int mode,int npt,xPoint * pts)1452 static void vncHooksPolyPoint(DrawablePtr pDrawable, GCPtr pGC, int mode,
1453                               int npt, xPoint *pts)
1454 {
1455   int minX, minY, maxX, maxY;
1456   int i;
1457 
1458   BoxRec box;
1459   RegionRec reg;
1460 
1461   GC_OP_PROLOGUE(pGC, PolyPoint);
1462 
1463   if (npt == 0) {
1464     (*pGC->ops->PolyPoint) (pDrawable, pGC, mode, npt, pts);
1465     goto out;
1466   }
1467 
1468   minX = pts[0].x;
1469   maxX = pts[0].x;
1470   minY = pts[0].y;
1471   maxY = pts[0].y;
1472 
1473   if (mode == CoordModePrevious) {
1474     int x = pts[0].x;
1475     int y = pts[0].y;
1476 
1477     for (i = 1; i < npt; i++) {
1478       x += pts[i].x;
1479       y += pts[i].y;
1480       if (x < minX) minX = x;
1481       if (x > maxX) maxX = x;
1482       if (y < minY) minY = y;
1483       if (y > maxY) maxY = y;
1484     }
1485   } else {
1486     for (i = 1; i < npt; i++) {
1487       if (pts[i].x < minX) minX = pts[i].x;
1488       if (pts[i].x > maxX) maxX = pts[i].x;
1489       if (pts[i].y < minY) minY = pts[i].y;
1490       if (pts[i].y > maxY) maxY = pts[i].y;
1491     }
1492   }
1493 
1494   box.x1 = minX + pDrawable->x;
1495   box.y1 = minY + pDrawable->y;
1496   box.x2 = maxX + 1 + pDrawable->x;
1497   box.y2 = maxY + 1 + pDrawable->y;
1498 
1499   RegionInitBoxes(&reg, &box, 1);
1500   RegionIntersect(&reg, &reg, pGC->pCompositeClip);
1501 
1502   (*pGC->ops->PolyPoint) (pDrawable, pGC, mode, npt, pts);
1503 
1504   add_changed(pGC->pScreen, &reg);
1505 
1506   RegionUninit(&reg);
1507 
1508 out:
1509   GC_OP_EPILOGUE(pGC);
1510 }
1511 
1512 // Polylines - changed region is the union of the bounding rects of each line,
1513 // clipped by pCompositeClip.  If there are more than MAX_RECTS_PER_OP lines,
1514 // just use the bounding rect of all the lines.
1515 
vncHooksPolylines(DrawablePtr pDrawable,GCPtr pGC,int mode,int npt,DDXPointPtr ppts)1516 static void vncHooksPolylines(DrawablePtr pDrawable, GCPtr pGC, int mode,
1517                               int npt, DDXPointPtr ppts)
1518 {
1519   int nRegRects;
1520   xRectangle regRects[MAX_RECTS_PER_OP];
1521 
1522   int lw;
1523 
1524   RegionPtr reg;
1525 
1526   GC_OP_PROLOGUE(pGC, Polylines);
1527 
1528   if (npt == 0) {
1529     (*pGC->ops->Polylines) (pDrawable, pGC, mode, npt, ppts);
1530     goto out;
1531   }
1532 
1533   nRegRects = npt - 1;
1534 
1535   lw = pGC->lineWidth;
1536   if (lw == 0)
1537     lw = 1;
1538 
1539   if (npt == 1)
1540   {
1541     // a single point
1542     nRegRects = 1;
1543     regRects[0].x = pDrawable->x + ppts[0].x - lw;
1544     regRects[0].y = pDrawable->y + ppts[0].y - lw;
1545     regRects[0].width = 2*lw;
1546     regRects[0].height = 2*lw;
1547   }
1548   else
1549   {
1550     /*
1551      * mitered joins can project quite a way from
1552      * the line end; the 11 degree miter limit limits
1553      * this extension to lw / (2 * tan(11/2)), rounded up
1554      * and converted to int yields 6 * lw
1555      */
1556 
1557     int extra;
1558 
1559     int prevX, prevY, curX, curY;
1560     int rectX1, rectY1, rectX2, rectY2;
1561     int minX, minY, maxX, maxY;
1562 
1563     int i;
1564 
1565     extra = lw / 2;
1566     if (pGC->joinStyle == JoinMiter) {
1567       extra = 6 * lw;
1568     }
1569 
1570     prevX = ppts[0].x + pDrawable->x;
1571     prevY = ppts[0].y + pDrawable->y;
1572     minX = maxX = prevX;
1573     minY = maxY = prevY;
1574 
1575     for (i = 0; i < nRegRects; i++) {
1576       if (mode == CoordModeOrigin) {
1577         curX = pDrawable->x + ppts[i+1].x;
1578         curY = pDrawable->y + ppts[i+1].y;
1579       } else {
1580         curX = prevX + ppts[i+1].x;
1581         curY = prevY + ppts[i+1].y;
1582       }
1583 
1584       if (prevX > curX) {
1585         rectX1 = curX - extra;
1586         rectX2 = prevX + extra + 1;
1587       } else {
1588         rectX1 = prevX - extra;
1589         rectX2 = curX + extra + 1;
1590       }
1591 
1592       if (prevY > curY) {
1593         rectY1 = curY - extra;
1594         rectY2 = prevY + extra + 1;
1595       } else {
1596         rectY1 = prevY - extra;
1597         rectY2 = curY + extra + 1;
1598       }
1599 
1600       if (nRegRects <= MAX_RECTS_PER_OP) {
1601         regRects[i].x = rectX1;
1602         regRects[i].y = rectY1;
1603         regRects[i].width = rectX2 - rectX1;
1604         regRects[i].height = rectY2 - rectY1;
1605       } else {
1606         if (rectX1 < minX) minX = rectX1;
1607         if (rectY1 < minY) minY = rectY1;
1608         if (rectX2 > maxX) maxX = rectX2;
1609         if (rectY2 > maxY) maxY = rectY2;
1610       }
1611 
1612       prevX = curX;
1613       prevY = curY;
1614     }
1615 
1616     if (nRegRects > MAX_RECTS_PER_OP) {
1617       regRects[0].x = minX;
1618       regRects[0].y = minY;
1619       regRects[0].width = maxX - minX;
1620       regRects[0].height = maxY - minY;
1621       nRegRects = 1;
1622     }
1623   }
1624 
1625   reg = RECTS_TO_REGION(pGC->pScreen, nRegRects, regRects, CT_NONE);
1626   RegionIntersect(reg, reg, pGC->pCompositeClip);
1627 
1628   (*pGC->ops->Polylines) (pDrawable, pGC, mode, npt, ppts);
1629 
1630   add_changed(pGC->pScreen, reg);
1631 
1632   RegionDestroy(reg);
1633 
1634 out:
1635   GC_OP_EPILOGUE(pGC);
1636 }
1637 
1638 // PolySegment - changed region is the union of the bounding rects of each
1639 // segment, clipped by pCompositeClip.  If there are more than MAX_RECTS_PER_OP
1640 // segments, just use the bounding rect of all the segments.
1641 
vncHooksPolySegment(DrawablePtr pDrawable,GCPtr pGC,int nseg,xSegment * segs)1642 static void vncHooksPolySegment(DrawablePtr pDrawable, GCPtr pGC, int nseg,
1643                                 xSegment *segs)
1644 {
1645   xRectangle regRects[MAX_RECTS_PER_OP];
1646   int nRegRects;
1647 
1648   int lw, extra;
1649 
1650   int rectX1, rectY1, rectX2, rectY2;
1651   int minX, minY, maxX, maxY;
1652 
1653   int i;
1654 
1655   RegionPtr reg;
1656 
1657   GC_OP_PROLOGUE(pGC, PolySegment);
1658 
1659   if (nseg == 0) {
1660     (*pGC->ops->PolySegment) (pDrawable, pGC, nseg, segs);
1661     goto out;
1662   }
1663 
1664   nRegRects = nseg;
1665 
1666   lw = pGC->lineWidth;
1667   extra = lw / 2;
1668 
1669   minX = maxX = segs[0].x1;
1670   minY = maxY = segs[0].y1;
1671 
1672   for (i = 0; i < nseg; i++) {
1673     if (segs[i].x1 > segs[i].x2) {
1674       rectX1 = pDrawable->x + segs[i].x2 - extra;
1675       rectX2 = pDrawable->x + segs[i].x1 + extra + 1;
1676     } else {
1677       rectX1 = pDrawable->x + segs[i].x1 - extra;
1678       rectX2 = pDrawable->x + segs[i].x2 + extra + 1;
1679     }
1680 
1681     if (segs[i].y1 > segs[i].y2) {
1682       rectY1 = pDrawable->y + segs[i].y2 - extra;
1683       rectY2 = pDrawable->y + segs[i].y1 + extra + 1;
1684     } else {
1685       rectY1 = pDrawable->y + segs[i].y1 - extra;
1686       rectY2 = pDrawable->y + segs[i].y2 + extra + 1;
1687     }
1688 
1689     if (nseg <= MAX_RECTS_PER_OP) {
1690       regRects[i].x = rectX1;
1691       regRects[i].y = rectY1;
1692       regRects[i].width = rectX2 - rectX1;
1693       regRects[i].height = rectY2 - rectY1;
1694     } else {
1695       if (rectX1 < minX) minX = rectX1;
1696       if (rectY1 < minY) minY = rectY1;
1697       if (rectX2 > maxX) maxX = rectX2;
1698       if (rectY2 > maxY) maxY = rectY2;
1699     }
1700   }
1701 
1702   if (nseg > MAX_RECTS_PER_OP) {
1703     regRects[0].x = minX;
1704     regRects[0].y = minY;
1705     regRects[0].width = maxX - minX;
1706     regRects[0].height = maxY - minY;
1707     nRegRects = 1;
1708   }
1709 
1710   reg = RECTS_TO_REGION(pGC->pScreen, nRegRects, regRects, CT_NONE);
1711   RegionIntersect(reg, reg, pGC->pCompositeClip);
1712 
1713   (*pGC->ops->PolySegment) (pDrawable, pGC, nseg, segs);
1714 
1715   add_changed(pGC->pScreen, reg);
1716 
1717   RegionDestroy(reg);
1718 
1719 out:
1720   GC_OP_EPILOGUE(pGC);
1721 }
1722 
1723 // PolyRectangle - changed region is the union of the bounding rects around
1724 // each side of the outline rectangles, clipped by pCompositeClip.  If there
1725 // are more than MAX_RECTS_PER_OP rectangles, just use the bounding rect of all
1726 // the rectangles.
1727 
vncHooksPolyRectangle(DrawablePtr pDrawable,GCPtr pGC,int nrects,xRectangle * rects)1728 static void vncHooksPolyRectangle(DrawablePtr pDrawable, GCPtr pGC, int nrects,
1729                                   xRectangle *rects)
1730 {
1731   xRectangle regRects[MAX_RECTS_PER_OP*4];
1732   int nRegRects;
1733 
1734   int lw, extra;
1735 
1736   int rectX1, rectY1, rectX2, rectY2;
1737   int minX, minY, maxX, maxY;
1738 
1739   int i;
1740 
1741   RegionPtr reg;
1742 
1743   GC_OP_PROLOGUE(pGC, PolyRectangle);
1744 
1745   if (nrects == 0) {
1746     (*pGC->ops->PolyRectangle) (pDrawable, pGC, nrects, rects);
1747     goto out;
1748   }
1749 
1750   nRegRects = nrects * 4;
1751 
1752   lw = pGC->lineWidth;
1753   extra = lw / 2;
1754 
1755   minX = maxX = rects[0].x;
1756   minY = maxY = rects[0].y;
1757 
1758   for (i = 0; i < nrects; i++) {
1759     if (nrects <= MAX_RECTS_PER_OP) {
1760       regRects[i*4].x = rects[i].x - extra + pDrawable->x;
1761       regRects[i*4].y = rects[i].y - extra + pDrawable->y;
1762       regRects[i*4].width = rects[i].width + 1 + 2 * extra;
1763       regRects[i*4].height = 1 + 2 * extra;
1764 
1765       regRects[i*4+1].x = rects[i].x - extra + pDrawable->x;
1766       regRects[i*4+1].y = rects[i].y - extra + pDrawable->y;
1767       regRects[i*4+1].width = 1 + 2 * extra;
1768       regRects[i*4+1].height = rects[i].height + 1 + 2 * extra;
1769 
1770       regRects[i*4+2].x = rects[i].x + rects[i].width - extra + pDrawable->x;
1771       regRects[i*4+2].y = rects[i].y - extra + pDrawable->y;
1772       regRects[i*4+2].width = 1 + 2 * extra;
1773       regRects[i*4+2].height = rects[i].height + 1 + 2 * extra;
1774 
1775       regRects[i*4+3].x = rects[i].x - extra + pDrawable->x;
1776       regRects[i*4+3].y = rects[i].y + rects[i].height - extra + pDrawable->y;
1777       regRects[i*4+3].width = rects[i].width + 1 + 2 * extra;
1778       regRects[i*4+3].height = 1 + 2 * extra;
1779     } else {
1780       rectX1 = pDrawable->x + rects[i].x - extra;
1781       rectY1 = pDrawable->y + rects[i].y - extra;
1782       rectX2 = pDrawable->x + rects[i].x + rects[i].width + extra+1;
1783       rectY2 = pDrawable->y + rects[i].y + rects[i].height + extra+1;
1784       if (rectX1 < minX) minX = rectX1;
1785       if (rectY1 < minY) minY = rectY1;
1786       if (rectX2 > maxX) maxX = rectX2;
1787       if (rectY2 > maxY) maxY = rectY2;
1788     }
1789   }
1790 
1791   if (nrects > MAX_RECTS_PER_OP) {
1792     regRects[0].x = minX;
1793     regRects[0].y = minY;
1794     regRects[0].width = maxX - minX;
1795     regRects[0].height = maxY - minY;
1796     nRegRects = 1;
1797   }
1798 
1799   reg = RECTS_TO_REGION(pGC->pScreen, nRegRects, regRects, CT_NONE);
1800   RegionIntersect(reg, reg, pGC->pCompositeClip);
1801 
1802   (*pGC->ops->PolyRectangle) (pDrawable, pGC, nrects, rects);
1803 
1804   add_changed(pGC->pScreen, reg);
1805 
1806   RegionDestroy(reg);
1807 
1808 out:
1809   GC_OP_EPILOGUE(pGC);
1810 }
1811 
1812 // PolyArc - changed region is the union of bounding rects around each arc,
1813 // clipped by pCompositeClip.  If there are more than MAX_RECTS_PER_OP
1814 // arcs, just use the bounding rect of all the arcs.
1815 
vncHooksPolyArc(DrawablePtr pDrawable,GCPtr pGC,int narcs,xArc * arcs)1816 static void vncHooksPolyArc(DrawablePtr pDrawable, GCPtr pGC, int narcs,
1817                             xArc *arcs)
1818 {
1819   xRectangle regRects[MAX_RECTS_PER_OP];
1820   int nRegRects;
1821 
1822   int lw, extra;
1823 
1824   int rectX1, rectY1, rectX2, rectY2;
1825   int minX, minY, maxX, maxY;
1826 
1827   int i;
1828 
1829   RegionPtr reg;
1830 
1831   GC_OP_PROLOGUE(pGC, PolyArc);
1832 
1833   if (narcs == 0) {
1834     (*pGC->ops->PolyArc) (pDrawable, pGC, narcs, arcs);
1835     goto out;
1836   }
1837 
1838   nRegRects = narcs;
1839 
1840   lw = pGC->lineWidth;
1841   if (lw == 0)
1842     lw = 1;
1843   extra = lw / 2;
1844 
1845   minX = maxX = arcs[0].x;
1846   minY = maxY = arcs[0].y;
1847 
1848   for (i = 0; i < narcs; i++) {
1849     if (narcs <= MAX_RECTS_PER_OP) {
1850       regRects[i].x = arcs[i].x - extra + pDrawable->x;
1851       regRects[i].y = arcs[i].y - extra + pDrawable->y;
1852       regRects[i].width = arcs[i].width + lw;
1853       regRects[i].height = arcs[i].height + lw;
1854     } else {
1855       rectX1 = pDrawable->x + arcs[i].x - extra;
1856       rectY1 = pDrawable->y + arcs[i].y - extra;
1857       rectX2 = pDrawable->x + arcs[i].x + arcs[i].width + lw;
1858       rectY2 = pDrawable->y + arcs[i].y + arcs[i].height + lw;
1859       if (rectX1 < minX) minX = rectX1;
1860       if (rectY1 < minY) minY = rectY1;
1861       if (rectX2 > maxX) maxX = rectX2;
1862       if (rectY2 > maxY) maxY = rectY2;
1863     }
1864   }
1865 
1866   if (narcs > MAX_RECTS_PER_OP) {
1867     regRects[0].x = minX;
1868     regRects[0].y = minY;
1869     regRects[0].width = maxX - minX;
1870     regRects[0].height = maxY - minY;
1871     nRegRects = 1;
1872   }
1873 
1874   reg = RECTS_TO_REGION(pGC->pScreen, nRegRects, regRects, CT_NONE);
1875   RegionIntersect(reg, reg, pGC->pCompositeClip);
1876 
1877   (*pGC->ops->PolyArc) (pDrawable, pGC, narcs, arcs);
1878 
1879   add_changed(pGC->pScreen, reg);
1880 
1881   RegionDestroy(reg);
1882 
1883 out:
1884   GC_OP_EPILOGUE(pGC);
1885 }
1886 
1887 
1888 // FillPolygon - changed region is the bounding rect around the polygon,
1889 // clipped by pCompositeClip
1890 
vncHooksFillPolygon(DrawablePtr pDrawable,GCPtr pGC,int shape,int mode,int count,DDXPointPtr pts)1891 static void vncHooksFillPolygon(DrawablePtr pDrawable, GCPtr pGC, int shape,
1892                                 int mode, int count, DDXPointPtr pts)
1893 {
1894   int minX, minY, maxX, maxY;
1895   int i;
1896 
1897   BoxRec box;
1898   RegionRec reg;
1899 
1900   GC_OP_PROLOGUE(pGC, FillPolygon);
1901 
1902   if (count == 0) {
1903     (*pGC->ops->FillPolygon) (pDrawable, pGC, shape, mode, count, pts);
1904     goto out;
1905   }
1906 
1907   minX = pts[0].x;
1908   maxX = pts[0].x;
1909   minY = pts[0].y;
1910   maxY = pts[0].y;
1911 
1912   if (mode == CoordModePrevious) {
1913     int x = pts[0].x;
1914     int y = pts[0].y;
1915 
1916     for (i = 1; i < count; i++) {
1917       x += pts[i].x;
1918       y += pts[i].y;
1919       if (x < minX) minX = x;
1920       if (x > maxX) maxX = x;
1921       if (y < minY) minY = y;
1922       if (y > maxY) maxY = y;
1923     }
1924   } else {
1925     for (i = 1; i < count; i++) {
1926       if (pts[i].x < minX) minX = pts[i].x;
1927       if (pts[i].x > maxX) maxX = pts[i].x;
1928       if (pts[i].y < minY) minY = pts[i].y;
1929       if (pts[i].y > maxY) maxY = pts[i].y;
1930     }
1931   }
1932 
1933   box.x1 = minX + pDrawable->x;
1934   box.y1 = minY + pDrawable->y;
1935   box.x2 = maxX + 1 + pDrawable->x;
1936   box.y2 = maxY + 1 + pDrawable->y;
1937 
1938   RegionInitBoxes(&reg, &box, 1);
1939   RegionIntersect(&reg, &reg, pGC->pCompositeClip);
1940 
1941   (*pGC->ops->FillPolygon) (pDrawable, pGC, shape, mode, count, pts);
1942 
1943   add_changed(pGC->pScreen, &reg);
1944 
1945   RegionUninit(&reg);
1946 
1947 out:
1948   GC_OP_EPILOGUE(pGC);
1949 }
1950 
1951 // PolyFillRect - changed region is the union of the rectangles, clipped by
1952 // pCompositeClip.  If there are more than MAX_RECTS_PER_OP rectangles, just
1953 // use the bounding rect of all the rectangles.
1954 
vncHooksPolyFillRect(DrawablePtr pDrawable,GCPtr pGC,int nrects,xRectangle * rects)1955 static void vncHooksPolyFillRect(DrawablePtr pDrawable, GCPtr pGC, int nrects,
1956                                  xRectangle *rects)
1957 {
1958   xRectangle regRects[MAX_RECTS_PER_OP];
1959   int nRegRects;
1960   int rectX1, rectY1, rectX2, rectY2;
1961   int minX, minY, maxX, maxY;
1962   int i;
1963 
1964   RegionPtr reg;
1965 
1966   GC_OP_PROLOGUE(pGC, PolyFillRect);
1967 
1968   if (nrects == 0) {
1969     (*pGC->ops->PolyFillRect) (pDrawable, pGC, nrects, rects);
1970     goto out;
1971   }
1972 
1973   nRegRects = nrects;
1974   minX = maxX = rects[0].x;
1975   minY = maxY = rects[0].y;
1976 
1977   for (i = 0; i < nrects; i++) {
1978     if (nrects <= MAX_RECTS_PER_OP) {
1979       regRects[i].x = rects[i].x + pDrawable->x;
1980       regRects[i].y = rects[i].y + pDrawable->y;
1981       regRects[i].width = rects[i].width;
1982       regRects[i].height = rects[i].height;
1983     } else {
1984       rectX1 = pDrawable->x + rects[i].x;
1985       rectY1 = pDrawable->y + rects[i].y;
1986       rectX2 = pDrawable->x + rects[i].x + rects[i].width;
1987       rectY2 = pDrawable->y + rects[i].y + rects[i].height;
1988       if (rectX1 < minX) minX = rectX1;
1989       if (rectY1 < minY) minY = rectY1;
1990       if (rectX2 > maxX) maxX = rectX2;
1991       if (rectY2 > maxY) maxY = rectY2;
1992     }
1993   }
1994 
1995   if (nrects > MAX_RECTS_PER_OP) {
1996     regRects[0].x = minX;
1997     regRects[0].y = minY;
1998     regRects[0].width = maxX - minX;
1999     regRects[0].height = maxY - minY;
2000     nRegRects = 1;
2001   }
2002 
2003   reg = RECTS_TO_REGION(pGC->pScreen, nRegRects, regRects, CT_NONE);
2004   RegionIntersect(reg, reg, pGC->pCompositeClip);
2005 
2006   (*pGC->ops->PolyFillRect) (pDrawable, pGC, nrects, rects);
2007 
2008   add_changed(pGC->pScreen, reg);
2009 
2010   RegionDestroy(reg);
2011 
2012 out:
2013   GC_OP_EPILOGUE(pGC);
2014 }
2015 
2016 // PolyFillArc - changed region is the union of bounding rects around each arc,
2017 // clipped by pCompositeClip.  If there are more than MAX_RECTS_PER_OP arcs,
2018 // just use the bounding rect of all the arcs.
2019 
vncHooksPolyFillArc(DrawablePtr pDrawable,GCPtr pGC,int narcs,xArc * arcs)2020 static void vncHooksPolyFillArc(DrawablePtr pDrawable, GCPtr pGC, int narcs,
2021                                 xArc *arcs)
2022 {
2023   xRectangle regRects[MAX_RECTS_PER_OP];
2024   int nRegRects;
2025 
2026   int lw, extra;
2027 
2028   int rectX1, rectY1, rectX2, rectY2;
2029   int minX, minY, maxX, maxY;
2030 
2031   int i;
2032 
2033   RegionPtr reg;
2034 
2035   GC_OP_PROLOGUE(pGC, PolyFillArc);
2036 
2037   if (narcs == 0) {
2038     (*pGC->ops->PolyFillArc) (pDrawable, pGC, narcs, arcs);
2039     goto out;
2040   }
2041 
2042   nRegRects = narcs;
2043 
2044   lw = pGC->lineWidth;
2045   if (lw == 0)
2046     lw = 1;
2047   extra = lw / 2;
2048 
2049   minX = maxX = arcs[0].x;
2050   minY = maxY = arcs[0].y;
2051 
2052   for (i = 0; i < narcs; i++) {
2053     if (narcs <= MAX_RECTS_PER_OP) {
2054       regRects[i].x = arcs[i].x - extra + pDrawable->x;
2055       regRects[i].y = arcs[i].y - extra + pDrawable->y;
2056       regRects[i].width = arcs[i].width + lw;
2057       regRects[i].height = arcs[i].height + lw;
2058     } else {
2059       rectX1 = pDrawable->x + arcs[i].x - extra;
2060       rectY1 = pDrawable->y + arcs[i].y - extra;
2061       rectX2 = pDrawable->x + arcs[i].x + arcs[i].width + lw;
2062       rectY2 = pDrawable->y + arcs[i].y + arcs[i].height + lw;
2063       if (rectX1 < minX) minX = rectX1;
2064       if (rectY1 < minY) minY = rectY1;
2065       if (rectX2 > maxX) maxX = rectX2;
2066       if (rectY2 > maxY) maxY = rectY2;
2067     }
2068   }
2069 
2070   if (narcs > MAX_RECTS_PER_OP) {
2071     regRects[0].x = minX;
2072     regRects[0].y = minY;
2073     regRects[0].width = maxX - minX;
2074     regRects[0].height = maxY - minY;
2075     nRegRects = 1;
2076   }
2077 
2078   reg = RECTS_TO_REGION(pGC->pScreen, nRegRects, regRects, CT_NONE);
2079   RegionIntersect(reg, reg, pGC->pCompositeClip);
2080 
2081   (*pGC->ops->PolyFillArc) (pDrawable, pGC, narcs, arcs);
2082 
2083   add_changed(pGC->pScreen, reg);
2084 
2085   RegionDestroy(reg);
2086 
2087 out:
2088   GC_OP_EPILOGUE(pGC);
2089 }
2090 
2091 // GetTextBoundingRect - calculate a bounding rectangle around n chars of a
2092 // font.  Not particularly accurate, but good enough.
2093 
GetTextBoundingRect(DrawablePtr pDrawable,FontPtr font,int x,int y,int nchars,BoxPtr box)2094 static void GetTextBoundingRect(DrawablePtr pDrawable, FontPtr font, int x,
2095                                 int y, int nchars, BoxPtr box)
2096 {
2097   int ascent = max(FONTASCENT(font), FONTMAXBOUNDS(font, ascent));
2098   int descent = max(FONTDESCENT(font), FONTMAXBOUNDS(font, descent));
2099   int charWidth = max(FONTMAXBOUNDS(font,rightSideBearing),
2100                       FONTMAXBOUNDS(font,characterWidth));
2101 
2102   box->x1 = pDrawable->x + x;
2103   box->y1 = pDrawable->y + y - ascent;
2104   box->x2 = box->x1 + charWidth * nchars;
2105   box->y2 = box->y1 + ascent + descent;
2106 
2107   if (FONTMINBOUNDS(font,leftSideBearing) < 0)
2108     box->x1 += FONTMINBOUNDS(font,leftSideBearing);
2109 }
2110 
2111 // PolyText8 - changed region is bounding rect around count chars, clipped by
2112 // pCompositeClip
2113 
vncHooksPolyText8(DrawablePtr pDrawable,GCPtr pGC,int x,int y,int count,char * chars)2114 static int vncHooksPolyText8(DrawablePtr pDrawable, GCPtr pGC, int x, int y,
2115                              int count, char *chars)
2116 {
2117   int ret;
2118   BoxRec box;
2119   RegionRec reg;
2120 
2121   GC_OP_PROLOGUE(pGC, PolyText8);
2122 
2123   if (count == 0) {
2124     ret = (*pGC->ops->PolyText8) (pDrawable, pGC, x, y, count, chars);
2125     goto out;
2126   }
2127 
2128   GetTextBoundingRect(pDrawable, pGC->font, x, y, count, &box);
2129 
2130   RegionInitBoxes(&reg, &box, 1);
2131   RegionIntersect(&reg, &reg, pGC->pCompositeClip);
2132 
2133   ret = (*pGC->ops->PolyText8) (pDrawable, pGC, x, y, count, chars);
2134 
2135   add_changed(pGC->pScreen, &reg);
2136 
2137   RegionUninit(&reg);
2138 
2139 out:
2140   GC_OP_EPILOGUE(pGC);
2141 
2142   return ret;
2143 }
2144 
2145 // PolyText16 - changed region is bounding rect around count chars, clipped by
2146 // pCompositeClip
2147 
vncHooksPolyText16(DrawablePtr pDrawable,GCPtr pGC,int x,int y,int count,unsigned short * chars)2148 static int vncHooksPolyText16(DrawablePtr pDrawable, GCPtr pGC, int x, int y,
2149                               int count, unsigned short *chars)
2150 {
2151   int ret;
2152   BoxRec box;
2153   RegionRec reg;
2154 
2155   GC_OP_PROLOGUE(pGC, PolyText16);
2156 
2157   if (count == 0) {
2158     ret = (*pGC->ops->PolyText16) (pDrawable, pGC, x, y, count, chars);
2159     goto out;
2160   }
2161 
2162   GetTextBoundingRect(pDrawable, pGC->font, x, y, count, &box);
2163 
2164   RegionInitBoxes(&reg, &box, 1);
2165   RegionIntersect(&reg, &reg, pGC->pCompositeClip);
2166 
2167   ret = (*pGC->ops->PolyText16) (pDrawable, pGC, x, y, count, chars);
2168 
2169   add_changed(pGC->pScreen, &reg);
2170 
2171   RegionUninit(&reg);
2172 
2173 out:
2174   GC_OP_EPILOGUE(pGC);
2175 
2176   return ret;
2177 }
2178 
2179 // ImageText8 - changed region is bounding rect around count chars, clipped by
2180 // pCompositeClip
2181 
vncHooksImageText8(DrawablePtr pDrawable,GCPtr pGC,int x,int y,int count,char * chars)2182 static void vncHooksImageText8(DrawablePtr pDrawable, GCPtr pGC, int x, int y,
2183                                int count, char *chars)
2184 {
2185   BoxRec box;
2186   RegionRec reg;
2187 
2188   GC_OP_PROLOGUE(pGC, ImageText8);
2189 
2190   if (count == 0) {
2191     (*pGC->ops->ImageText8) (pDrawable, pGC, x, y, count, chars);
2192     goto out;
2193   }
2194 
2195   GetTextBoundingRect(pDrawable, pGC->font, x, y, count, &box);
2196 
2197   RegionInitBoxes(&reg, &box, 1);
2198   RegionIntersect(&reg, &reg, pGC->pCompositeClip);
2199 
2200   (*pGC->ops->ImageText8) (pDrawable, pGC, x, y, count, chars);
2201 
2202   add_changed(pGC->pScreen, &reg);
2203 
2204   RegionUninit(&reg);
2205 
2206 out:
2207   GC_OP_EPILOGUE(pGC);
2208 }
2209 
2210 // ImageText16 - changed region is bounding rect around count chars, clipped by
2211 // pCompositeClip
2212 
vncHooksImageText16(DrawablePtr pDrawable,GCPtr pGC,int x,int y,int count,unsigned short * chars)2213 static void vncHooksImageText16(DrawablePtr pDrawable, GCPtr pGC, int x, int y,
2214                                 int count, unsigned short *chars)
2215 {
2216   BoxRec box;
2217   RegionRec reg;
2218 
2219   GC_OP_PROLOGUE(pGC, ImageText16);
2220 
2221   if (count == 0) {
2222     (*pGC->ops->ImageText16) (pDrawable, pGC, x, y, count, chars);
2223     goto out;
2224   }
2225 
2226   GetTextBoundingRect(pDrawable, pGC->font, x, y, count, &box);
2227 
2228   RegionInitBoxes(&reg, &box, 1);
2229   RegionIntersect(&reg, &reg, pGC->pCompositeClip);
2230 
2231   (*pGC->ops->ImageText16) (pDrawable, pGC, x, y, count, chars);
2232 
2233   add_changed(pGC->pScreen, &reg);
2234 
2235   RegionUninit(&reg);
2236 
2237 out:
2238   GC_OP_EPILOGUE(pGC);
2239 }
2240 
2241 // ImageGlyphBlt - changed region is bounding rect around nglyph chars, clipped
2242 // by pCompositeClip
2243 
vncHooksImageGlyphBlt(DrawablePtr pDrawable,GCPtr pGC,int x,int y,unsigned int nglyph,CharInfoPtr * ppci,void * pglyphBase)2244 static void vncHooksImageGlyphBlt(DrawablePtr pDrawable, GCPtr pGC, int x,
2245                                   int y, unsigned int nglyph,
2246                                   CharInfoPtr *ppci, void * pglyphBase)
2247 {
2248   BoxRec box;
2249   RegionRec reg;
2250 
2251   GC_OP_PROLOGUE(pGC, ImageGlyphBlt);
2252 
2253   if (nglyph == 0) {
2254     (*pGC->ops->ImageGlyphBlt) (pDrawable, pGC, x, y, nglyph, ppci,pglyphBase);
2255     goto out;
2256   }
2257 
2258   GetTextBoundingRect(pDrawable, pGC->font, x, y, nglyph, &box);
2259 
2260   RegionInitBoxes(&reg, &box, 1);
2261   RegionIntersect(&reg, &reg, pGC->pCompositeClip);
2262 
2263   (*pGC->ops->ImageGlyphBlt) (pDrawable, pGC, x, y, nglyph, ppci, pglyphBase);
2264 
2265   add_changed(pGC->pScreen, &reg);
2266 
2267   RegionUninit(&reg);
2268 
2269 out:
2270   GC_OP_EPILOGUE(pGC);
2271 }
2272 
2273 // PolyGlyphBlt - changed region is bounding rect around nglyph chars, clipped
2274 // by pCompositeClip
2275 
vncHooksPolyGlyphBlt(DrawablePtr pDrawable,GCPtr pGC,int x,int y,unsigned int nglyph,CharInfoPtr * ppci,void * pglyphBase)2276 static void vncHooksPolyGlyphBlt(DrawablePtr pDrawable, GCPtr pGC, int x,
2277                                  int y, unsigned int nglyph,
2278                                  CharInfoPtr *ppci, void * pglyphBase)
2279 {
2280   BoxRec box;
2281   RegionRec reg;
2282 
2283   GC_OP_PROLOGUE(pGC, PolyGlyphBlt);
2284 
2285   if (nglyph == 0) {
2286     (*pGC->ops->PolyGlyphBlt) (pDrawable, pGC, x, y, nglyph, ppci,pglyphBase);
2287     goto out;
2288   }
2289 
2290   GetTextBoundingRect(pDrawable, pGC->font, x, y, nglyph, &box);
2291 
2292   RegionInitBoxes(&reg, &box, 1);
2293   RegionIntersect(&reg, &reg, pGC->pCompositeClip);
2294 
2295   (*pGC->ops->PolyGlyphBlt) (pDrawable, pGC, x, y, nglyph, ppci, pglyphBase);
2296 
2297   add_changed(pGC->pScreen, &reg);
2298 
2299   RegionUninit(&reg);
2300 
2301 out:
2302   GC_OP_EPILOGUE(pGC);
2303 }
2304 
2305 // PushPixels - changed region is the given rectangle, clipped by
2306 // pCompositeClip
2307 
vncHooksPushPixels(GCPtr pGC,PixmapPtr pBitMap,DrawablePtr pDrawable,int w,int h,int x,int y)2308 static void vncHooksPushPixels(GCPtr pGC, PixmapPtr pBitMap,
2309                                DrawablePtr pDrawable, int w, int h, int x,
2310                                int y)
2311 {
2312   BoxRec box;
2313   RegionRec reg;
2314 
2315   GC_OP_PROLOGUE(pGC, PushPixels);
2316 
2317   box.x1 = x + pDrawable->x;
2318   box.y1 = y + pDrawable->y;
2319   box.x2 = box.x1 + w;
2320   box.y2 = box.y1 + h;
2321 
2322   RegionInitBoxes(&reg, &box, 1);
2323   RegionIntersect(&reg, &reg, pGC->pCompositeClip);
2324 
2325   (*pGC->ops->PushPixels) (pGC, pBitMap, pDrawable, w, h, x, y);
2326 
2327   add_changed(pGC->pScreen, &reg);
2328 
2329   RegionUninit(&reg);
2330 
2331   GC_OP_EPILOGUE(pGC);
2332 }
2333