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(®, &box, 1);
526 RegionIntersect(®, ®, &pWin->clipList);
527
528 (*pScreen->ClearToBackground) (pWin, x, y, w, h, generateExposures);
529
530 if (!generateExposures) {
531 add_changed(pScreen, ®);
532 }
533
534 RegionUninit(®);
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(®);
1271 RegionCopy(®, pGC->pCompositeClip);
1272
1273 if (pDrawable->type == DRAWABLE_WINDOW)
1274 RegionIntersect(®, ®, &((WindowPtr)pDrawable)->borderClip);
1275
1276 (*pGC->ops->FillSpans) (pDrawable, pGC, nInit, pptInit, pwidthInit, fSorted);
1277
1278 add_changed(pGC->pScreen, ®);
1279
1280 RegionUninit(®);
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(®);
1297 RegionCopy(®, pGC->pCompositeClip);
1298
1299 if (pDrawable->type == DRAWABLE_WINDOW)
1300 RegionIntersect(®, ®, &((WindowPtr)pDrawable)->borderClip);
1301
1302 (*pGC->ops->SetSpans) (pDrawable, pGC, psrc, ppt, pwidth, nspans, fSorted);
1303
1304 add_changed(pGC->pScreen, ®);
1305
1306 RegionUninit(®);
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(®, &box, 1);
1328 RegionIntersect(®, ®, pGC->pCompositeClip);
1329
1330 (*pGC->ops->PutImage) (pDrawable, pGC, depth, x, y, w, h, leftPad, format,
1331 pBits);
1332
1333 add_changed(pGC->pScreen, ®);
1334
1335 RegionUninit(®);
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(®, &box, 1);
1436 RegionIntersect(®, ®, 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, ®);
1442
1443 RegionUninit(®);
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(®, &box, 1);
1500 RegionIntersect(®, ®, pGC->pCompositeClip);
1501
1502 (*pGC->ops->PolyPoint) (pDrawable, pGC, mode, npt, pts);
1503
1504 add_changed(pGC->pScreen, ®);
1505
1506 RegionUninit(®);
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(®, &box, 1);
1939 RegionIntersect(®, ®, pGC->pCompositeClip);
1940
1941 (*pGC->ops->FillPolygon) (pDrawable, pGC, shape, mode, count, pts);
1942
1943 add_changed(pGC->pScreen, ®);
1944
1945 RegionUninit(®);
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(®, &box, 1);
2131 RegionIntersect(®, ®, pGC->pCompositeClip);
2132
2133 ret = (*pGC->ops->PolyText8) (pDrawable, pGC, x, y, count, chars);
2134
2135 add_changed(pGC->pScreen, ®);
2136
2137 RegionUninit(®);
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(®, &box, 1);
2165 RegionIntersect(®, ®, pGC->pCompositeClip);
2166
2167 ret = (*pGC->ops->PolyText16) (pDrawable, pGC, x, y, count, chars);
2168
2169 add_changed(pGC->pScreen, ®);
2170
2171 RegionUninit(®);
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(®, &box, 1);
2198 RegionIntersect(®, ®, pGC->pCompositeClip);
2199
2200 (*pGC->ops->ImageText8) (pDrawable, pGC, x, y, count, chars);
2201
2202 add_changed(pGC->pScreen, ®);
2203
2204 RegionUninit(®);
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(®, &box, 1);
2229 RegionIntersect(®, ®, pGC->pCompositeClip);
2230
2231 (*pGC->ops->ImageText16) (pDrawable, pGC, x, y, count, chars);
2232
2233 add_changed(pGC->pScreen, ®);
2234
2235 RegionUninit(®);
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(®, &box, 1);
2261 RegionIntersect(®, ®, pGC->pCompositeClip);
2262
2263 (*pGC->ops->ImageGlyphBlt) (pDrawable, pGC, x, y, nglyph, ppci, pglyphBase);
2264
2265 add_changed(pGC->pScreen, ®);
2266
2267 RegionUninit(®);
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(®, &box, 1);
2293 RegionIntersect(®, ®, pGC->pCompositeClip);
2294
2295 (*pGC->ops->PolyGlyphBlt) (pDrawable, pGC, x, y, nglyph, ppci, pglyphBase);
2296
2297 add_changed(pGC->pScreen, ®);
2298
2299 RegionUninit(®);
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(®, &box, 1);
2323 RegionIntersect(®, ®, pGC->pCompositeClip);
2324
2325 (*pGC->ops->PushPixels) (pGC, pBitMap, pDrawable, w, h, x, y);
2326
2327 add_changed(pGC->pScreen, ®);
2328
2329 RegionUninit(®);
2330
2331 GC_OP_EPILOGUE(pGC);
2332 }
2333