1 /*
2  * Graphics Context support for generic rootless X server
3  */
4 /*
5  * Copyright (c) 2001 Greg Parker. All Rights Reserved.
6  * Copyright (c) 2002-2003 Torrey T. Lyons. All Rights Reserved.
7  * Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
8  *
9  * Permission is hereby granted, free of charge, to any person obtaining a
10  * copy of this software and associated documentation files (the "Software"),
11  * to deal in the Software without restriction, including without limitation
12  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13  * and/or sell copies of the Software, and to permit persons to whom the
14  * Software is furnished to do so, subject to the following conditions:
15  *
16  * The above copyright notice and this permission notice shall be included in
17  * all copies or substantial portions of the Software.
18  *
19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22  * THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
23  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
24  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25  * DEALINGS IN THE SOFTWARE.
26  *
27  * Except as contained in this notice, the name(s) of the above copyright
28  * holders shall not be used in advertising or otherwise to promote the sale,
29  * use or other dealings in this Software without prior written authorization.
30  */
31 
32 #ifdef HAVE_DIX_CONFIG_H
33 #include <dix-config.h>
34 #endif
35 
36 #include <stddef.h>             /* For NULL */
37 #include "mi.h"
38 #include "scrnintstr.h"
39 #include "gcstruct.h"
40 #include "pixmapstr.h"
41 #include "windowstr.h"
42 #include "dixfontstr.h"
43 #include "mivalidate.h"
44 #include "fb.h"
45 
46 #include <sys/types.h>
47 #include <sys/stat.h>
48 #include <fcntl.h>
49 
50 #include "rootlessCommon.h"
51 
52 // GC functions
53 static void RootlessValidateGC(GCPtr pGC, unsigned long changes,
54                                DrawablePtr pDrawable);
55 static void RootlessChangeGC(GCPtr pGC, unsigned long mask);
56 static void RootlessCopyGC(GCPtr pGCSrc, unsigned long mask, GCPtr pGCDst);
57 static void RootlessDestroyGC(GCPtr pGC);
58 static void RootlessChangeClip(GCPtr pGC, int type, void *pvalue, int nrects);
59 static void RootlessDestroyClip(GCPtr pGC);
60 static void RootlessCopyClip(GCPtr pgcDst, GCPtr pgcSrc);
61 
62 Bool RootlessCreateGC(GCPtr pGC);
63 
64 GCFuncs rootlessGCFuncs = {
65     RootlessValidateGC,
66     RootlessChangeGC,
67     RootlessCopyGC,
68     RootlessDestroyGC,
69     RootlessChangeClip,
70     RootlessDestroyClip,
71     RootlessCopyClip,
72 };
73 
74 // GC operations
75 static void RootlessFillSpans(DrawablePtr dst, GCPtr pGC, int nInit,
76                               DDXPointPtr pptInit, int *pwidthInit, int sorted);
77 static void RootlessSetSpans(DrawablePtr dst, GCPtr pGC, char *pSrc,
78                              DDXPointPtr pptInit, int *pwidthInit,
79                              int nspans, int sorted);
80 static void RootlessPutImage(DrawablePtr dst, GCPtr pGC,
81                              int depth, int x, int y, int w, int h,
82                              int leftPad, int format, char *pBits);
83 static RegionPtr RootlessCopyArea(DrawablePtr pSrc, DrawablePtr dst, GCPtr pGC,
84                                   int srcx, int srcy, int w, int h,
85                                   int dstx, int dsty);
86 static RegionPtr RootlessCopyPlane(DrawablePtr pSrc, DrawablePtr dst,
87                                    GCPtr pGC, int srcx, int srcy,
88                                    int w, int h, int dstx, int dsty,
89                                    unsigned long plane);
90 static void RootlessPolyPoint(DrawablePtr dst, GCPtr pGC,
91                               int mode, int npt, DDXPointPtr pptInit);
92 static void RootlessPolylines(DrawablePtr dst, GCPtr pGC,
93                               int mode, int npt, DDXPointPtr pptInit);
94 static void RootlessPolySegment(DrawablePtr dst, GCPtr pGC,
95                                 int nseg, xSegment * pSeg);
96 static void RootlessPolyRectangle(DrawablePtr dst, GCPtr pGC,
97                                   int nRects, xRectangle *pRects);
98 static void RootlessPolyArc(DrawablePtr dst, GCPtr pGC, int narcs,
99                             xArc * parcs);
100 static void RootlessFillPolygon(DrawablePtr dst, GCPtr pGC, int shape, int mode,
101                                 int count, DDXPointPtr pptInit);
102 static void RootlessPolyFillRect(DrawablePtr dst, GCPtr pGC, int nRectsInit,
103                                  xRectangle *pRectsInit);
104 static void RootlessPolyFillArc(DrawablePtr dst, GCPtr pGC, int narcsInit,
105                                 xArc * parcsInit);
106 static int RootlessPolyText8(DrawablePtr dst, GCPtr pGC, int x, int y,
107                              int count, char *chars);
108 static int RootlessPolyText16(DrawablePtr dst, GCPtr pGC, int x, int y,
109                               int count, unsigned short *chars);
110 static void RootlessImageText8(DrawablePtr dst, GCPtr pGC, int x, int y,
111                                int count, char *chars);
112 static void RootlessImageText16(DrawablePtr dst, GCPtr pGC, int x, int y,
113                                 int count, unsigned short *chars);
114 static void RootlessImageGlyphBlt(DrawablePtr dst, GCPtr pGC, int x, int y,
115                                   unsigned int nglyphInit,
116                                   CharInfoPtr * ppciInit, void *unused);
117 static void RootlessPolyGlyphBlt(DrawablePtr dst, GCPtr pGC, int x, int y,
118                                  unsigned int nglyph, CharInfoPtr * ppci,
119                                  void *pglyphBase);
120 static void RootlessPushPixels(GCPtr pGC, PixmapPtr pBitMap, DrawablePtr dst,
121                                int dx, int dy, int xOrg, int yOrg);
122 
123 static GCOps rootlessGCOps = {
124     RootlessFillSpans,
125     RootlessSetSpans,
126     RootlessPutImage,
127     RootlessCopyArea,
128     RootlessCopyPlane,
129     RootlessPolyPoint,
130     RootlessPolylines,
131     RootlessPolySegment,
132     RootlessPolyRectangle,
133     RootlessPolyArc,
134     RootlessFillPolygon,
135     RootlessPolyFillRect,
136     RootlessPolyFillArc,
137     RootlessPolyText8,
138     RootlessPolyText16,
139     RootlessImageText8,
140     RootlessImageText16,
141     RootlessImageGlyphBlt,
142     RootlessPolyGlyphBlt,
143     RootlessPushPixels
144 };
145 
146 /*
147    If ROOTLESS_PROTECT_ALPHA is set, we have to make sure that the alpha
148    channel of the on screen windows is always opaque. fb makes this harder
149    than it would otherwise be by noticing that a planemask of 0x00ffffff
150    includes all bits when depth==24, and so it "optimizes" the planemask to
151    0xffffffff. We work around this by temporarily setting depth=bpp while
152    changing the GC.
153 
154    So the normal situation (in 32 bit mode) is that the planemask is
155    0x00ffffff and thus fb leaves the alpha channel alone. The rootless
156    implementation is responsible for setting the alpha channel opaque
157    initially.
158 
159    Unfortunately drawing with a planemask that doesn't have all bits set
160    normally causes fb to fall off its fastest paths when blitting and
161    filling.  So we try to recognize when we can relax the planemask back to
162    0xffffffff, and do that for the duration of the drawing operation,
163    setting the alpha channel in fg/bg pixels to opaque at the same time. We
164    can do this when drawing op is GXcopy. We can also do this when copying
165    from another window since its alpha channel must also be opaque.
166 
167    The three macros below are used to implement this. Drawing ops that can
168    potentially have their planemask relaxed look like:
169 
170    OP {
171        GC_SAVE(gc);
172        GCOP_UNWRAP(gc);
173 
174        ...
175 
176        if (canAccelxxx(..) && otherwise-suitable)
177             GC_UNSET_PM(gc, dst);
178 
179        gc->funcs->OP(gc, ...);
180 
181        GC_RESTORE(gc, dst);
182        GCOP_WRAP(gc);
183    }
184 
185  */
186 
187 #define GC_SAVE(pGC) 				\
188     unsigned long _save_fg = (pGC)->fgPixel;	\
189     unsigned long _save_bg = (pGC)->bgPixel;	\
190     unsigned long _save_pm = (pGC)->planemask;	\
191     Bool _changed = FALSE
192 
193 #define GC_RESTORE(pGC, pDraw)					\
194     do {							\
195         if (_changed) {						\
196             unsigned int depth = (pDraw)->depth;		\
197             (pGC)->fgPixel = _save_fg;				\
198             (pGC)->bgPixel = _save_bg;				\
199             (pGC)->planemask = _save_pm;			\
200             (pDraw)->depth = (pDraw)->bitsPerPixel;		\
201             VALIDATE_GC(pGC, GCForeground | GCBackground |	\
202                         GCPlaneMask, pDraw);			\
203             (pDraw)->depth = depth;				\
204         }							\
205     } while (0)
206 
207 #define GC_UNSET_PM(pGC, pDraw)						\
208     do {								\
209         unsigned int mask = RootlessAlphaMask ((pDraw)->bitsPerPixel);	\
210         if (((pGC)->planemask & mask) != mask) {			\
211             unsigned int depth = (pDraw)->depth;			\
212             (pGC)->fgPixel |= mask;					\
213             (pGC)->bgPixel |= mask;					\
214             (pGC)->planemask |= mask;					\
215             (pDraw)->depth = (pDraw)->bitsPerPixel;			\
216             VALIDATE_GC(pGC, GCForeground |				\
217                         GCBackground | GCPlaneMask, pDraw);		\
218             (pDraw)->depth = depth;					\
219             _changed = TRUE;						\
220         }								\
221     } while (0)
222 
223 #define VALIDATE_GC(pGC, changes, pDrawable)				\
224     do {								\
225         pGC->funcs->ValidateGC(pGC, changes, pDrawable);		\
226         if (((WindowPtr) pDrawable)->viewable) {			\
227             gcrec->originalOps = pGC->ops;				\
228         }								\
229     } while(0)
230 
231 static RootlessWindowRec *
canAccelBlit(DrawablePtr pDraw,GCPtr pGC)232 canAccelBlit(DrawablePtr pDraw, GCPtr pGC)
233 {
234     WindowPtr pTop;
235     RootlessWindowRec *winRec;
236     unsigned int pm;
237 
238     if (pGC->alu != GXcopy)
239         return NULL;
240 
241     if (pDraw->type != DRAWABLE_WINDOW)
242         return NULL;
243 
244     pm = ~RootlessAlphaMask(pDraw->bitsPerPixel);
245     if ((pGC->planemask & pm) != pm)
246         return NULL;
247 
248     pTop = TopLevelParent((WindowPtr) pDraw);
249     if (pTop == NULL)
250         return NULL;
251 
252     winRec = WINREC(pTop);
253     if (winRec == NULL)
254         return NULL;
255 
256     return winRec;
257 }
258 
259 static inline RootlessWindowRec *
canAccelFill(DrawablePtr pDraw,GCPtr pGC)260 canAccelFill(DrawablePtr pDraw, GCPtr pGC)
261 {
262     if (pGC->fillStyle != FillSolid)
263         return NULL;
264 
265     return canAccelBlit(pDraw, pGC);
266 }
267 
268 /*
269  * Screen function to create a graphics context
270  */
271 Bool
RootlessCreateGC(GCPtr pGC)272 RootlessCreateGC(GCPtr pGC)
273 {
274     RootlessGCRec *gcrec;
275     RootlessScreenRec *s;
276     Bool result;
277 
278     SCREEN_UNWRAP(pGC->pScreen, CreateGC);
279     s = SCREENREC(pGC->pScreen);
280     result = s->CreateGC(pGC);
281 
282     gcrec = (RootlessGCRec *)
283         dixLookupPrivate(&pGC->devPrivates, rootlessGCPrivateKey);
284     gcrec->originalOps = NULL;  // don't wrap ops yet
285     gcrec->originalFuncs = pGC->funcs;
286     pGC->funcs = &rootlessGCFuncs;
287 
288     SCREEN_WRAP(pGC->pScreen, CreateGC);
289     return result;
290 }
291 
292 /*
293  * GC funcs
294  *
295  * These wrap lower level GC funcs.
296  * ValidateGC wraps the GC ops iff dest is viewable.
297  * All the others just unwrap and call.
298  */
299 
300 // GCFUNC_UNRAP assumes funcs have been wrapped and
301 // does not assume ops have been wrapped
302 #define GCFUNC_UNWRAP(pGC) \
303     RootlessGCRec *gcrec = (RootlessGCRec *) \
304 	dixLookupPrivate(&(pGC)->devPrivates, rootlessGCPrivateKey); \
305     (pGC)->funcs = gcrec->originalFuncs; \
306     if (gcrec->originalOps) { \
307         (pGC)->ops = gcrec->originalOps; \
308 }
309 
310 #define GCFUNC_WRAP(pGC) \
311     gcrec->originalFuncs = (pGC)->funcs; \
312     (pGC)->funcs = &rootlessGCFuncs; \
313     if (gcrec->originalOps) { \
314         gcrec->originalOps = (pGC)->ops; \
315         (pGC)->ops = &rootlessGCOps; \
316 }
317 
318 static void
RootlessValidateGC(GCPtr pGC,unsigned long changes,DrawablePtr pDrawable)319 RootlessValidateGC(GCPtr pGC, unsigned long changes, DrawablePtr pDrawable)
320 {
321     GCFUNC_UNWRAP(pGC);
322 
323     gcrec->originalOps = NULL;
324 
325     if (pDrawable->type == DRAWABLE_WINDOW) {
326 #ifdef ROOTLESS_PROTECT_ALPHA
327         unsigned int depth = pDrawable->depth;
328 
329         // We force a planemask so fb doesn't overwrite the alpha channel.
330         // Left to its own devices, fb will optimize away the planemask.
331         pDrawable->depth = pDrawable->bitsPerPixel;
332         pGC->planemask &= ~RootlessAlphaMask(pDrawable->bitsPerPixel);
333         VALIDATE_GC(pGC, changes | GCPlaneMask, pDrawable);
334         pDrawable->depth = depth;
335 #else
336         VALIDATE_GC(pGC, changes, pDrawable);
337 #endif
338     }
339     else {
340         pGC->funcs->ValidateGC(pGC, changes, pDrawable);
341     }
342 
343     GCFUNC_WRAP(pGC);
344 }
345 
346 static void
RootlessChangeGC(GCPtr pGC,unsigned long mask)347 RootlessChangeGC(GCPtr pGC, unsigned long mask)
348 {
349     GCFUNC_UNWRAP(pGC);
350     pGC->funcs->ChangeGC(pGC, mask);
351     GCFUNC_WRAP(pGC);
352 }
353 
354 static void
RootlessCopyGC(GCPtr pGCSrc,unsigned long mask,GCPtr pGCDst)355 RootlessCopyGC(GCPtr pGCSrc, unsigned long mask, GCPtr pGCDst)
356 {
357     GCFUNC_UNWRAP(pGCDst);
358     pGCDst->funcs->CopyGC(pGCSrc, mask, pGCDst);
359     GCFUNC_WRAP(pGCDst);
360 }
361 
362 static void
RootlessDestroyGC(GCPtr pGC)363 RootlessDestroyGC(GCPtr pGC)
364 {
365     GCFUNC_UNWRAP(pGC);
366     pGC->funcs->DestroyGC(pGC);
367     GCFUNC_WRAP(pGC);
368 }
369 
370 static void
RootlessChangeClip(GCPtr pGC,int type,void * pvalue,int nrects)371 RootlessChangeClip(GCPtr pGC, int type, void *pvalue, int nrects)
372 {
373     GCFUNC_UNWRAP(pGC);
374     pGC->funcs->ChangeClip(pGC, type, pvalue, nrects);
375     GCFUNC_WRAP(pGC);
376 }
377 
378 static void
RootlessDestroyClip(GCPtr pGC)379 RootlessDestroyClip(GCPtr pGC)
380 {
381     GCFUNC_UNWRAP(pGC);
382     pGC->funcs->DestroyClip(pGC);
383     GCFUNC_WRAP(pGC);
384 }
385 
386 static void
RootlessCopyClip(GCPtr pgcDst,GCPtr pgcSrc)387 RootlessCopyClip(GCPtr pgcDst, GCPtr pgcSrc)
388 {
389     GCFUNC_UNWRAP(pgcDst);
390     pgcDst->funcs->CopyClip(pgcDst, pgcSrc);
391     GCFUNC_WRAP(pgcDst);
392 }
393 
394 /*
395  * GC ops
396  *
397  * We can't use shadowfb because shadowfb assumes one pixmap
398  * and our root window is a special case.
399  * However, much of this code is copied from shadowfb.
400  */
401 
402 // assumes both funcs and ops are wrapped
403 #define GCOP_UNWRAP(pGC) \
404     RootlessGCRec *gcrec = (RootlessGCRec *) \
405         dixLookupPrivate(&(pGC)->devPrivates, rootlessGCPrivateKey); \
406     const GCFuncs *saveFuncs = pGC->funcs; \
407     (pGC)->funcs = gcrec->originalFuncs; \
408     (pGC)->ops = gcrec->originalOps;
409 
410 #define GCOP_WRAP(pGC) \
411     gcrec->originalOps = (pGC)->ops; \
412     (pGC)->funcs = saveFuncs; \
413     (pGC)->ops = &rootlessGCOps;
414 
415 static void
RootlessFillSpans(DrawablePtr dst,GCPtr pGC,int nInit,DDXPointPtr pptInit,int * pwidthInit,int sorted)416 RootlessFillSpans(DrawablePtr dst, GCPtr pGC, int nInit,
417                   DDXPointPtr pptInit, int *pwidthInit, int sorted)
418 {
419     GC_SAVE(pGC);
420     GCOP_UNWRAP(pGC);
421     RL_DEBUG_MSG("fill spans start ");
422 
423     if (nInit <= 0) {
424         pGC->ops->FillSpans(dst, pGC, nInit, pptInit, pwidthInit, sorted);
425     }
426     else {
427         DDXPointPtr ppt = pptInit;
428         int *pwidth = pwidthInit;
429         int i = nInit;
430         BoxRec box;
431 
432         box.x1 = ppt->x;
433         box.x2 = box.x1 + *pwidth;
434         box.y2 = box.y1 = ppt->y;
435 
436         while (--i) {
437             ppt++;
438             pwidth++;
439             if (box.x1 > ppt->x)
440                 box.x1 = ppt->x;
441             if (box.x2 < (ppt->x + *pwidth))
442                 box.x2 = ppt->x + *pwidth;
443             if (box.y1 > ppt->y)
444                 box.y1 = ppt->y;
445             else if (box.y2 < ppt->y)
446                 box.y2 = ppt->y;
447         }
448 
449         box.y2++;
450 
451         RootlessStartDrawing((WindowPtr) dst);
452 
453         if (canAccelFill(dst, pGC)) {
454             GC_UNSET_PM(pGC, dst);
455         }
456 
457         pGC->ops->FillSpans(dst, pGC, nInit, pptInit, pwidthInit, sorted);
458 
459         TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
460         if (BOX_NOT_EMPTY(box))
461             RootlessDamageBox((WindowPtr) dst, &box);
462     }
463 
464     GC_RESTORE(pGC, dst);
465     GCOP_WRAP(pGC);
466     RL_DEBUG_MSG("fill spans end\n");
467 }
468 
469 static void
RootlessSetSpans(DrawablePtr dst,GCPtr pGC,char * pSrc,DDXPointPtr pptInit,int * pwidthInit,int nspans,int sorted)470 RootlessSetSpans(DrawablePtr dst, GCPtr pGC, char *pSrc,
471                  DDXPointPtr pptInit, int *pwidthInit, int nspans, int sorted)
472 {
473     GCOP_UNWRAP(pGC);
474     RL_DEBUG_MSG("set spans start ");
475 
476     if (nspans <= 0) {
477         pGC->ops->SetSpans(dst, pGC, pSrc, pptInit, pwidthInit, nspans, sorted);
478     }
479     else {
480         DDXPointPtr ppt = pptInit;
481         int *pwidth = pwidthInit;
482         int i = nspans;
483         BoxRec box;
484 
485         box.x1 = ppt->x;
486         box.x2 = box.x1 + *pwidth;
487         box.y2 = box.y1 = ppt->y;
488 
489         while (--i) {
490             ppt++;
491             pwidth++;
492             if (box.x1 > ppt->x)
493                 box.x1 = ppt->x;
494             if (box.x2 < (ppt->x + *pwidth))
495                 box.x2 = ppt->x + *pwidth;
496             if (box.y1 > ppt->y)
497                 box.y1 = ppt->y;
498             else if (box.y2 < ppt->y)
499                 box.y2 = ppt->y;
500         }
501 
502         box.y2++;
503 
504         RootlessStartDrawing((WindowPtr) dst);
505         pGC->ops->SetSpans(dst, pGC, pSrc, pptInit, pwidthInit, nspans, sorted);
506 
507         TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
508         if (BOX_NOT_EMPTY(box))
509             RootlessDamageBox((WindowPtr) dst, &box);
510     }
511     GCOP_WRAP(pGC);
512     RL_DEBUG_MSG("set spans end\n");
513 }
514 
515 static void
RootlessPutImage(DrawablePtr dst,GCPtr pGC,int depth,int x,int y,int w,int h,int leftPad,int format,char * pBits)516 RootlessPutImage(DrawablePtr dst, GCPtr pGC,
517                  int depth, int x, int y, int w, int h,
518                  int leftPad, int format, char *pBits)
519 {
520     BoxRec box;
521 
522     GCOP_UNWRAP(pGC);
523     RL_DEBUG_MSG("put image start ");
524 
525     RootlessStartDrawing((WindowPtr) dst);
526     pGC->ops->PutImage(dst, pGC, depth, x, y, w, h, leftPad, format, pBits);
527 
528     box.x1 = x + dst->x;
529     box.x2 = box.x1 + w;
530     box.y1 = y + dst->y;
531     box.y2 = box.y1 + h;
532 
533     TRIM_BOX(box, pGC);
534     if (BOX_NOT_EMPTY(box))
535         RootlessDamageBox((WindowPtr) dst, &box);
536 
537     GCOP_WRAP(pGC);
538     RL_DEBUG_MSG("put image end\n");
539 }
540 
541 /* changed area is *dest* rect */
542 static RegionPtr
RootlessCopyArea(DrawablePtr pSrc,DrawablePtr dst,GCPtr pGC,int srcx,int srcy,int w,int h,int dstx,int dsty)543 RootlessCopyArea(DrawablePtr pSrc, DrawablePtr dst, GCPtr pGC,
544                  int srcx, int srcy, int w, int h, int dstx, int dsty)
545 {
546     RegionPtr result;
547     BoxRec box;
548 
549     GC_SAVE(pGC);
550     GCOP_UNWRAP(pGC);
551 
552     RL_DEBUG_MSG("copy area start (src 0x%x, dst 0x%x)", pSrc, dst);
553 
554     if (pSrc->type == DRAWABLE_WINDOW && IsFramedWindow((WindowPtr) pSrc)) {
555         /* If both source and dest are windows, and we're doing
556            a simple copy operation, we can remove the alpha-protecting
557            planemask (since source has opaque alpha as well) */
558 
559         if (canAccelBlit(pSrc, pGC)) {
560             GC_UNSET_PM(pGC, dst);
561         }
562 
563         RootlessStartDrawing((WindowPtr) pSrc);
564     }
565     RootlessStartDrawing((WindowPtr) dst);
566     result = pGC->ops->CopyArea(pSrc, dst, pGC, srcx, srcy, w, h, dstx, dsty);
567 
568     box.x1 = dstx + dst->x;
569     box.x2 = box.x1 + w;
570     box.y1 = dsty + dst->y;
571     box.y2 = box.y1 + h;
572 
573     TRIM_BOX(box, pGC);
574     if (BOX_NOT_EMPTY(box))
575         RootlessDamageBox((WindowPtr) dst, &box);
576 
577     GC_RESTORE(pGC, dst);
578     GCOP_WRAP(pGC);
579     RL_DEBUG_MSG("copy area end\n");
580     return result;
581 }
582 
583 /* changed area is *dest* rect */
584 static RegionPtr
RootlessCopyPlane(DrawablePtr pSrc,DrawablePtr dst,GCPtr pGC,int srcx,int srcy,int w,int h,int dstx,int dsty,unsigned long plane)585 RootlessCopyPlane(DrawablePtr pSrc, DrawablePtr dst,
586                   GCPtr pGC, int srcx, int srcy,
587                   int w, int h, int dstx, int dsty, unsigned long plane)
588 {
589     RegionPtr result;
590     BoxRec box;
591 
592     GCOP_UNWRAP(pGC);
593 
594     RL_DEBUG_MSG("copy plane start ");
595 
596     if (pSrc->type == DRAWABLE_WINDOW && IsFramedWindow((WindowPtr) pSrc)) {
597         RootlessStartDrawing((WindowPtr) pSrc);
598     }
599     RootlessStartDrawing((WindowPtr) dst);
600     result = pGC->ops->CopyPlane(pSrc, dst, pGC, srcx, srcy, w, h,
601                                  dstx, dsty, plane);
602 
603     box.x1 = dstx + dst->x;
604     box.x2 = box.x1 + w;
605     box.y1 = dsty + dst->y;
606     box.y2 = box.y1 + h;
607 
608     TRIM_BOX(box, pGC);
609     if (BOX_NOT_EMPTY(box))
610         RootlessDamageBox((WindowPtr) dst, &box);
611 
612     GCOP_WRAP(pGC);
613     RL_DEBUG_MSG("copy plane end\n");
614     return result;
615 }
616 
617 // Options for size of changed area:
618 //  0 = box per point
619 //  1 = big box around all points
620 //  2 = accumulate point in 20 pixel radius
621 #define ROOTLESS_CHANGED_AREA 1
622 #define abs(a) ((a) > 0 ? (a) : -(a))
623 
624 /* changed area is box around all points */
625 static void
RootlessPolyPoint(DrawablePtr dst,GCPtr pGC,int mode,int npt,DDXPointPtr pptInit)626 RootlessPolyPoint(DrawablePtr dst, GCPtr pGC,
627                   int mode, int npt, DDXPointPtr pptInit)
628 {
629     GCOP_UNWRAP(pGC);
630     RL_DEBUG_MSG("polypoint start ");
631 
632     RootlessStartDrawing((WindowPtr) dst);
633     pGC->ops->PolyPoint(dst, pGC, mode, npt, pptInit);
634 
635     if (npt > 0) {
636 #if ROOTLESS_CHANGED_AREA==0
637         // box per point
638         BoxRec box;
639 
640         while (npt) {
641             box.x1 = pptInit->x;
642             box.y1 = pptInit->y;
643             box.x2 = box.x1 + 1;
644             box.y2 = box.y1 + 1;
645 
646             TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
647             if (BOX_NOT_EMPTY(box))
648                 RootlessDamageBox((WindowPtr) dst, &box);
649 
650             npt--;
651             pptInit++;
652         }
653 
654 #elif ROOTLESS_CHANGED_AREA==1
655         // one big box
656         BoxRec box;
657 
658         box.x2 = box.x1 = pptInit->x;
659         box.y2 = box.y1 = pptInit->y;
660         while (--npt) {
661             pptInit++;
662             if (box.x1 > pptInit->x)
663                 box.x1 = pptInit->x;
664             else if (box.x2 < pptInit->x)
665                 box.x2 = pptInit->x;
666             if (box.y1 > pptInit->y)
667                 box.y1 = pptInit->y;
668             else if (box.y2 < pptInit->y)
669                 box.y2 = pptInit->y;
670         }
671 
672         box.x2++;
673         box.y2++;
674 
675         TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
676         if (BOX_NOT_EMPTY(box))
677             RootlessDamageBox((WindowPtr) dst, &box);
678 
679 #elif ROOTLESS_CHANGED_AREA==2
680         // clever(?) method: accumulate point in 20-pixel radius
681         BoxRec box;
682         int firstx, firsty;
683 
684         box.x2 = box.x1 = firstx = pptInit->x;
685         box.y2 = box.y1 = firsty = pptInit->y;
686         while (--npt) {
687             pptInit++;
688             if (abs(pptInit->x - firstx) > 20 || abs(pptInit->y - firsty) > 20) {
689                 box.x2++;
690                 box.y2++;
691                 TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
692                 if (BOX_NOT_EMPTY(box))
693                     RootlessDamageBox((WindowPtr) dst, &box);
694                 box.x2 = box.x1 = firstx = pptInit->x;
695                 box.y2 = box.y1 = firsty = pptInit->y;
696             }
697             else {
698                 if (box.x1 > pptInit->x)
699                     box.x1 = pptInit->x;
700                 else if (box.x2 < pptInit->x)
701                     box.x2 = pptInit->x;
702                 if (box.y1 > pptInit->y)
703                     box.y1 = pptInit->y;
704                 else if (box.y2 < pptInit->y)
705                     box.y2 = pptInit->y;
706             }
707         }
708         box.x2++;
709         box.y2++;
710         TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
711         if (BOX_NOT_EMPTY(box))
712             RootlessDamageBox((WindowPtr) dst, &box);
713 #endif                          /* ROOTLESS_CHANGED_AREA */
714     }
715 
716     GCOP_WRAP(pGC);
717     RL_DEBUG_MSG("polypoint end\n");
718 }
719 
720 #undef ROOTLESS_CHANGED_AREA
721 
722 /* changed area is box around each line */
723 static void
RootlessPolylines(DrawablePtr dst,GCPtr pGC,int mode,int npt,DDXPointPtr pptInit)724 RootlessPolylines(DrawablePtr dst, GCPtr pGC,
725                   int mode, int npt, DDXPointPtr pptInit)
726 {
727     GCOP_UNWRAP(pGC);
728     RL_DEBUG_MSG("poly lines start ");
729 
730     RootlessStartDrawing((WindowPtr) dst);
731     pGC->ops->Polylines(dst, pGC, mode, npt, pptInit);
732 
733     if (npt > 0) {
734         BoxRec box;
735         int extra = pGC->lineWidth >> 1;
736 
737         box.x2 = box.x1 = pptInit->x;
738         box.y2 = box.y1 = pptInit->y;
739 
740         if (npt > 1) {
741             if (pGC->joinStyle == JoinMiter)
742                 extra = 6 * pGC->lineWidth;
743             else if (pGC->capStyle == CapProjecting)
744                 extra = pGC->lineWidth;
745         }
746 
747         if (mode == CoordModePrevious) {
748             int x = box.x1;
749             int y = box.y1;
750 
751             while (--npt) {
752                 pptInit++;
753                 x += pptInit->x;
754                 y += pptInit->y;
755                 if (box.x1 > x)
756                     box.x1 = x;
757                 else if (box.x2 < x)
758                     box.x2 = x;
759                 if (box.y1 > y)
760                     box.y1 = y;
761                 else if (box.y2 < y)
762                     box.y2 = y;
763             }
764         }
765         else {
766             while (--npt) {
767                 pptInit++;
768                 if (box.x1 > pptInit->x)
769                     box.x1 = pptInit->x;
770                 else if (box.x2 < pptInit->x)
771                     box.x2 = pptInit->x;
772                 if (box.y1 > pptInit->y)
773                     box.y1 = pptInit->y;
774                 else if (box.y2 < pptInit->y)
775                     box.y2 = pptInit->y;
776             }
777         }
778 
779         box.x2++;
780         box.y2++;
781 
782         if (extra) {
783             box.x1 -= extra;
784             box.x2 += extra;
785             box.y1 -= extra;
786             box.y2 += extra;
787         }
788 
789         TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
790         if (BOX_NOT_EMPTY(box))
791             RootlessDamageBox((WindowPtr) dst, &box);
792     }
793 
794     GCOP_WRAP(pGC);
795     RL_DEBUG_MSG("poly lines end\n");
796 }
797 
798 /* changed area is box around each line segment */
799 static void
RootlessPolySegment(DrawablePtr dst,GCPtr pGC,int nseg,xSegment * pSeg)800 RootlessPolySegment(DrawablePtr dst, GCPtr pGC, int nseg, xSegment * pSeg)
801 {
802     GCOP_UNWRAP(pGC);
803     RL_DEBUG_MSG("poly segment start (win 0x%x)", dst);
804 
805     RootlessStartDrawing((WindowPtr) dst);
806     pGC->ops->PolySegment(dst, pGC, nseg, pSeg);
807 
808     if (nseg > 0) {
809         BoxRec box;
810         int extra = pGC->lineWidth;
811 
812         if (pGC->capStyle != CapProjecting)
813             extra >>= 1;
814 
815         if (pSeg->x2 > pSeg->x1) {
816             box.x1 = pSeg->x1;
817             box.x2 = pSeg->x2;
818         }
819         else {
820             box.x2 = pSeg->x1;
821             box.x1 = pSeg->x2;
822         }
823 
824         if (pSeg->y2 > pSeg->y1) {
825             box.y1 = pSeg->y1;
826             box.y2 = pSeg->y2;
827         }
828         else {
829             box.y2 = pSeg->y1;
830             box.y1 = pSeg->y2;
831         }
832 
833         while (--nseg) {
834             pSeg++;
835             if (pSeg->x2 > pSeg->x1) {
836                 if (pSeg->x1 < box.x1)
837                     box.x1 = pSeg->x1;
838                 if (pSeg->x2 > box.x2)
839                     box.x2 = pSeg->x2;
840             }
841             else {
842                 if (pSeg->x2 < box.x1)
843                     box.x1 = pSeg->x2;
844                 if (pSeg->x1 > box.x2)
845                     box.x2 = pSeg->x1;
846             }
847             if (pSeg->y2 > pSeg->y1) {
848                 if (pSeg->y1 < box.y1)
849                     box.y1 = pSeg->y1;
850                 if (pSeg->y2 > box.y2)
851                     box.y2 = pSeg->y2;
852             }
853             else {
854                 if (pSeg->y2 < box.y1)
855                     box.y1 = pSeg->y2;
856                 if (pSeg->y1 > box.y2)
857                     box.y2 = pSeg->y1;
858             }
859         }
860 
861         box.x2++;
862         box.y2++;
863 
864         if (extra) {
865             box.x1 -= extra;
866             box.x2 += extra;
867             box.y1 -= extra;
868             box.y2 += extra;
869         }
870 
871         TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
872         if (BOX_NOT_EMPTY(box))
873             RootlessDamageBox((WindowPtr) dst, &box);
874     }
875 
876     GCOP_WRAP(pGC);
877     RL_DEBUG_MSG("poly segment end\n");
878 }
879 
880 /* changed area is box around each line (not entire rects) */
881 static void
RootlessPolyRectangle(DrawablePtr dst,GCPtr pGC,int nRects,xRectangle * pRects)882 RootlessPolyRectangle(DrawablePtr dst, GCPtr pGC,
883                       int nRects, xRectangle *pRects)
884 {
885     GCOP_UNWRAP(pGC);
886     RL_DEBUG_MSG("poly rectangle start ");
887 
888     RootlessStartDrawing((WindowPtr) dst);
889     pGC->ops->PolyRectangle(dst, pGC, nRects, pRects);
890 
891     if (nRects > 0) {
892         BoxRec box;
893         int offset1, offset2, offset3;
894 
895         offset2 = pGC->lineWidth;
896         if (!offset2)
897             offset2 = 1;
898         offset1 = offset2 >> 1;
899         offset3 = offset2 - offset1;
900 
901         while (nRects--) {
902             box.x1 = pRects->x - offset1;
903             box.y1 = pRects->y - offset1;
904             box.x2 = box.x1 + pRects->width + offset2;
905             box.y2 = box.y1 + offset2;
906             TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
907             if (BOX_NOT_EMPTY(box))
908                 RootlessDamageBox((WindowPtr) dst, &box);
909 
910             box.x1 = pRects->x - offset1;
911             box.y1 = pRects->y + offset3;
912             box.x2 = box.x1 + offset2;
913             box.y2 = box.y1 + pRects->height - offset2;
914             TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
915             if (BOX_NOT_EMPTY(box))
916                 RootlessDamageBox((WindowPtr) dst, &box);
917 
918             box.x1 = pRects->x + pRects->width - offset1;
919             box.y1 = pRects->y + offset3;
920             box.x2 = box.x1 + offset2;
921             box.y2 = box.y1 + pRects->height - offset2;
922             TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
923             if (BOX_NOT_EMPTY(box))
924                 RootlessDamageBox((WindowPtr) dst, &box);
925 
926             box.x1 = pRects->x - offset1;
927             box.y1 = pRects->y + pRects->height - offset1;
928             box.x2 = box.x1 + pRects->width + offset2;
929             box.y2 = box.y1 + offset2;
930             TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
931             if (BOX_NOT_EMPTY(box))
932                 RootlessDamageBox((WindowPtr) dst, &box);
933 
934             pRects++;
935         }
936     }
937 
938     GCOP_WRAP(pGC);
939     RL_DEBUG_MSG("poly rectangle end\n");
940 }
941 
942 /* changed area is box around each arc (assumes all arcs are 360 degrees) */
943 static void
RootlessPolyArc(DrawablePtr dst,GCPtr pGC,int narcs,xArc * parcs)944 RootlessPolyArc(DrawablePtr dst, GCPtr pGC, int narcs, xArc * parcs)
945 {
946     GCOP_UNWRAP(pGC);
947     RL_DEBUG_MSG("poly arc start ");
948 
949     RootlessStartDrawing((WindowPtr) dst);
950     pGC->ops->PolyArc(dst, pGC, narcs, parcs);
951 
952     if (narcs > 0) {
953         int extra = pGC->lineWidth >> 1;
954         BoxRec box;
955 
956         box.x1 = parcs->x;
957         box.x2 = box.x1 + parcs->width;
958         box.y1 = parcs->y;
959         box.y2 = box.y1 + parcs->height;
960 
961         /* should I break these up instead ? */
962 
963         while (--narcs) {
964             parcs++;
965             if (box.x1 > parcs->x)
966                 box.x1 = parcs->x;
967             if (box.x2 < (parcs->x + parcs->width))
968                 box.x2 = parcs->x + parcs->width;
969             if (box.y1 > parcs->y)
970                 box.y1 = parcs->y;
971             if (box.y2 < (parcs->y + parcs->height))
972                 box.y2 = parcs->y + parcs->height;
973         }
974 
975         if (extra) {
976             box.x1 -= extra;
977             box.x2 += extra;
978             box.y1 -= extra;
979             box.y2 += extra;
980         }
981 
982         box.x2++;
983         box.y2++;
984 
985         TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
986         if (BOX_NOT_EMPTY(box))
987             RootlessDamageBox((WindowPtr) dst, &box);
988     }
989 
990     GCOP_WRAP(pGC);
991     RL_DEBUG_MSG("poly arc end\n");
992 }
993 
994 /* changed area is box around each poly */
995 static void
RootlessFillPolygon(DrawablePtr dst,GCPtr pGC,int shape,int mode,int count,DDXPointPtr pptInit)996 RootlessFillPolygon(DrawablePtr dst, GCPtr pGC,
997                     int shape, int mode, int count, DDXPointPtr pptInit)
998 {
999     GC_SAVE(pGC);
1000     GCOP_UNWRAP(pGC);
1001     RL_DEBUG_MSG("fill poly start (win 0x%x, fillStyle 0x%x)", dst,
1002                  pGC->fillStyle);
1003 
1004     if (count <= 2) {
1005         pGC->ops->FillPolygon(dst, pGC, shape, mode, count, pptInit);
1006     }
1007     else {
1008         DDXPointPtr ppt = pptInit;
1009         int i = count;
1010         BoxRec box;
1011 
1012         box.x2 = box.x1 = ppt->x;
1013         box.y2 = box.y1 = ppt->y;
1014 
1015         if (mode != CoordModeOrigin) {
1016             int x = box.x1;
1017             int y = box.y1;
1018 
1019             while (--i) {
1020                 ppt++;
1021                 x += ppt->x;
1022                 y += ppt->y;
1023                 if (box.x1 > x)
1024                     box.x1 = x;
1025                 else if (box.x2 < x)
1026                     box.x2 = x;
1027                 if (box.y1 > y)
1028                     box.y1 = y;
1029                 else if (box.y2 < y)
1030                     box.y2 = y;
1031             }
1032         }
1033         else {
1034             while (--i) {
1035                 ppt++;
1036                 if (box.x1 > ppt->x)
1037                     box.x1 = ppt->x;
1038                 else if (box.x2 < ppt->x)
1039                     box.x2 = ppt->x;
1040                 if (box.y1 > ppt->y)
1041                     box.y1 = ppt->y;
1042                 else if (box.y2 < ppt->y)
1043                     box.y2 = ppt->y;
1044             }
1045         }
1046 
1047         box.x2++;
1048         box.y2++;
1049 
1050         RootlessStartDrawing((WindowPtr) dst);
1051 
1052         if (canAccelFill(dst, pGC)) {
1053             GC_UNSET_PM(pGC, dst);
1054         }
1055 
1056         pGC->ops->FillPolygon(dst, pGC, shape, mode, count, pptInit);
1057 
1058         TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
1059         if (BOX_NOT_EMPTY(box))
1060             RootlessDamageBox((WindowPtr) dst, &box);
1061     }
1062 
1063     GC_RESTORE(pGC, dst);
1064     GCOP_WRAP(pGC);
1065     RL_DEBUG_MSG("fill poly end\n");
1066 }
1067 
1068 /* changed area is the rects */
1069 static void
RootlessPolyFillRect(DrawablePtr dst,GCPtr pGC,int nRectsInit,xRectangle * pRectsInit)1070 RootlessPolyFillRect(DrawablePtr dst, GCPtr pGC,
1071                      int nRectsInit, xRectangle *pRectsInit)
1072 {
1073     GC_SAVE(pGC);
1074     GCOP_UNWRAP(pGC);
1075     RL_DEBUG_MSG("fill rect start (win 0x%x, fillStyle 0x%x)", dst,
1076                  pGC->fillStyle);
1077 
1078     if (nRectsInit <= 0) {
1079         pGC->ops->PolyFillRect(dst, pGC, nRectsInit, pRectsInit);
1080     }
1081     else {
1082         BoxRec box;
1083         xRectangle *pRects = pRectsInit;
1084         int nRects = nRectsInit;
1085 
1086         box.x1 = pRects->x;
1087         box.x2 = box.x1 + pRects->width;
1088         box.y1 = pRects->y;
1089         box.y2 = box.y1 + pRects->height;
1090 
1091         while (--nRects) {
1092             pRects++;
1093             if (box.x1 > pRects->x)
1094                 box.x1 = pRects->x;
1095             if (box.x2 < (pRects->x + pRects->width))
1096                 box.x2 = pRects->x + pRects->width;
1097             if (box.y1 > pRects->y)
1098                 box.y1 = pRects->y;
1099             if (box.y2 < (pRects->y + pRects->height))
1100                 box.y2 = pRects->y + pRects->height;
1101         }
1102 
1103         RootlessStartDrawing((WindowPtr) dst);
1104 
1105         if (canAccelFill(dst, pGC)) {
1106             GC_UNSET_PM(pGC, dst);
1107         }
1108 
1109         pGC->ops->PolyFillRect(dst, pGC, nRectsInit, pRectsInit);
1110 
1111         TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
1112         if (BOX_NOT_EMPTY(box))
1113             RootlessDamageBox((WindowPtr) dst, &box);
1114     }
1115 
1116     GC_RESTORE(pGC, dst);
1117     GCOP_WRAP(pGC);
1118     RL_DEBUG_MSG("fill rect end\n");
1119 }
1120 
1121 /* changed area is box around each arc (assuming arcs are all 360 degrees) */
1122 static void
RootlessPolyFillArc(DrawablePtr dst,GCPtr pGC,int narcsInit,xArc * parcsInit)1123 RootlessPolyFillArc(DrawablePtr dst, GCPtr pGC, int narcsInit, xArc * parcsInit)
1124 {
1125     GC_SAVE(pGC);
1126     GCOP_UNWRAP(pGC);
1127     RL_DEBUG_MSG("fill arc start ");
1128 
1129     if (narcsInit > 0) {
1130         BoxRec box;
1131         int narcs = narcsInit;
1132         xArc *parcs = parcsInit;
1133 
1134         box.x1 = parcs->x;
1135         box.x2 = box.x1 + parcs->width;
1136         box.y1 = parcs->y;
1137         box.y2 = box.y1 + parcs->height;
1138 
1139         /* should I break these up instead ? */
1140 
1141         while (--narcs) {
1142             parcs++;
1143             if (box.x1 > parcs->x)
1144                 box.x1 = parcs->x;
1145             if (box.x2 < (parcs->x + parcs->width))
1146                 box.x2 = parcs->x + parcs->width;
1147             if (box.y1 > parcs->y)
1148                 box.y1 = parcs->y;
1149             if (box.y2 < (parcs->y + parcs->height))
1150                 box.y2 = parcs->y + parcs->height;
1151         }
1152 
1153         RootlessStartDrawing((WindowPtr) dst);
1154 
1155         if (canAccelFill(dst, pGC)) {
1156             GC_UNSET_PM(pGC, dst);
1157         }
1158 
1159         pGC->ops->PolyFillArc(dst, pGC, narcsInit, parcsInit);
1160 
1161         TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
1162         if (BOX_NOT_EMPTY(box))
1163             RootlessDamageBox((WindowPtr) dst, &box);
1164     }
1165     else {
1166         pGC->ops->PolyFillArc(dst, pGC, narcsInit, parcsInit);
1167     }
1168 
1169     GC_RESTORE(pGC, dst);
1170     GCOP_WRAP(pGC);
1171     RL_DEBUG_MSG("fill arc end\n");
1172 }
1173 
1174 static void
RootlessImageText8(DrawablePtr dst,GCPtr pGC,int x,int y,int count,char * chars)1175 RootlessImageText8(DrawablePtr dst, GCPtr pGC,
1176                    int x, int y, int count, char *chars)
1177 {
1178     GC_SAVE(pGC);
1179     GCOP_UNWRAP(pGC);
1180     RL_DEBUG_MSG("imagetext8 start ");
1181 
1182     if (count > 0) {
1183         int top, bot, Min, Max;
1184         BoxRec box;
1185 
1186         top = max(FONTMAXBOUNDS(pGC->font, ascent), FONTASCENT(pGC->font));
1187         bot = max(FONTMAXBOUNDS(pGC->font, descent), FONTDESCENT(pGC->font));
1188 
1189         Min = count * FONTMINBOUNDS(pGC->font, characterWidth);
1190         if (Min > 0)
1191             Min = 0;
1192         Max = count * FONTMAXBOUNDS(pGC->font, characterWidth);
1193         if (Max < 0)
1194             Max = 0;
1195 
1196         /* ugh */
1197         box.x1 = dst->x + x + Min + FONTMINBOUNDS(pGC->font, leftSideBearing);
1198         box.x2 = dst->x + x + Max + FONTMAXBOUNDS(pGC->font, rightSideBearing);
1199 
1200         box.y1 = dst->y + y - top;
1201         box.y2 = dst->y + y + bot;
1202 
1203         RootlessStartDrawing((WindowPtr) dst);
1204 
1205         if (canAccelFill(dst, pGC)) {
1206             GC_UNSET_PM(pGC, dst);
1207         }
1208 
1209         pGC->ops->ImageText8(dst, pGC, x, y, count, chars);
1210 
1211         TRIM_BOX(box, pGC);
1212         if (BOX_NOT_EMPTY(box))
1213             RootlessDamageBox((WindowPtr) dst, &box);
1214     }
1215     else {
1216         pGC->ops->ImageText8(dst, pGC, x, y, count, chars);
1217     }
1218 
1219     GC_RESTORE(pGC, dst);
1220     GCOP_WRAP(pGC);
1221     RL_DEBUG_MSG("imagetext8 end\n");
1222 }
1223 
1224 static int
RootlessPolyText8(DrawablePtr dst,GCPtr pGC,int x,int y,int count,char * chars)1225 RootlessPolyText8(DrawablePtr dst, GCPtr pGC,
1226                   int x, int y, int count, char *chars)
1227 {
1228     int width;                  // the result, sorta
1229 
1230     GCOP_UNWRAP(pGC);
1231 
1232     RL_DEBUG_MSG("polytext8 start ");
1233 
1234     RootlessStartDrawing((WindowPtr) dst);
1235     width = pGC->ops->PolyText8(dst, pGC, x, y, count, chars);
1236     width -= x;
1237 
1238     if (width > 0) {
1239         BoxRec box;
1240 
1241         /* ugh */
1242         box.x1 = dst->x + x + FONTMINBOUNDS(pGC->font, leftSideBearing);
1243         box.x2 = dst->x + x + FONTMAXBOUNDS(pGC->font, rightSideBearing);
1244 
1245         if (count > 1) {
1246             if (width > 0)
1247                 box.x2 += width;
1248             else
1249                 box.x1 += width;
1250         }
1251 
1252         box.y1 = dst->y + y - FONTMAXBOUNDS(pGC->font, ascent);
1253         box.y2 = dst->y + y + FONTMAXBOUNDS(pGC->font, descent);
1254 
1255         TRIM_BOX(box, pGC);
1256         if (BOX_NOT_EMPTY(box))
1257             RootlessDamageBox((WindowPtr) dst, &box);
1258     }
1259 
1260     GCOP_WRAP(pGC);
1261     RL_DEBUG_MSG("polytext8 end\n");
1262     return width + x;
1263 }
1264 
1265 static void
RootlessImageText16(DrawablePtr dst,GCPtr pGC,int x,int y,int count,unsigned short * chars)1266 RootlessImageText16(DrawablePtr dst, GCPtr pGC,
1267                     int x, int y, int count, unsigned short *chars)
1268 {
1269     GC_SAVE(pGC);
1270     GCOP_UNWRAP(pGC);
1271     RL_DEBUG_MSG("imagetext16 start ");
1272 
1273     if (count > 0) {
1274         int top, bot, Min, Max;
1275         BoxRec box;
1276 
1277         top = max(FONTMAXBOUNDS(pGC->font, ascent), FONTASCENT(pGC->font));
1278         bot = max(FONTMAXBOUNDS(pGC->font, descent), FONTDESCENT(pGC->font));
1279 
1280         Min = count * FONTMINBOUNDS(pGC->font, characterWidth);
1281         if (Min > 0)
1282             Min = 0;
1283         Max = count * FONTMAXBOUNDS(pGC->font, characterWidth);
1284         if (Max < 0)
1285             Max = 0;
1286 
1287         /* ugh */
1288         box.x1 = dst->x + x + Min + FONTMINBOUNDS(pGC->font, leftSideBearing);
1289         box.x2 = dst->x + x + Max + FONTMAXBOUNDS(pGC->font, rightSideBearing);
1290 
1291         box.y1 = dst->y + y - top;
1292         box.y2 = dst->y + y + bot;
1293 
1294         RootlessStartDrawing((WindowPtr) dst);
1295 
1296         if (canAccelFill(dst, pGC)) {
1297             GC_UNSET_PM(pGC, dst);
1298         }
1299 
1300         pGC->ops->ImageText16(dst, pGC, x, y, count, chars);
1301 
1302         TRIM_BOX(box, pGC);
1303         if (BOX_NOT_EMPTY(box))
1304             RootlessDamageBox((WindowPtr) dst, &box);
1305     }
1306     else {
1307         pGC->ops->ImageText16(dst, pGC, x, y, count, chars);
1308     }
1309 
1310     GC_RESTORE(pGC, dst);
1311     GCOP_WRAP(pGC);
1312     RL_DEBUG_MSG("imagetext16 end\n");
1313 }
1314 
1315 static int
RootlessPolyText16(DrawablePtr dst,GCPtr pGC,int x,int y,int count,unsigned short * chars)1316 RootlessPolyText16(DrawablePtr dst, GCPtr pGC,
1317                    int x, int y, int count, unsigned short *chars)
1318 {
1319     int width;                  // the result, sorta
1320 
1321     GCOP_UNWRAP(pGC);
1322 
1323     RL_DEBUG_MSG("polytext16 start ");
1324 
1325     RootlessStartDrawing((WindowPtr) dst);
1326     width = pGC->ops->PolyText16(dst, pGC, x, y, count, chars);
1327     width -= x;
1328 
1329     if (width > 0) {
1330         BoxRec box;
1331 
1332         /* ugh */
1333         box.x1 = dst->x + x + FONTMINBOUNDS(pGC->font, leftSideBearing);
1334         box.x2 = dst->x + x + FONTMAXBOUNDS(pGC->font, rightSideBearing);
1335 
1336         if (count > 1) {
1337             if (width > 0)
1338                 box.x2 += width;
1339             else
1340                 box.x1 += width;
1341         }
1342 
1343         box.y1 = dst->y + y - FONTMAXBOUNDS(pGC->font, ascent);
1344         box.y2 = dst->y + y + FONTMAXBOUNDS(pGC->font, descent);
1345 
1346         TRIM_BOX(box, pGC);
1347         if (BOX_NOT_EMPTY(box))
1348             RootlessDamageBox((WindowPtr) dst, &box);
1349     }
1350 
1351     GCOP_WRAP(pGC);
1352     RL_DEBUG_MSG("polytext16 end\n");
1353     return width + x;
1354 }
1355 
1356 static void
RootlessImageGlyphBlt(DrawablePtr dst,GCPtr pGC,int x,int y,unsigned int nglyphInit,CharInfoPtr * ppciInit,void * unused)1357 RootlessImageGlyphBlt(DrawablePtr dst, GCPtr pGC,
1358                       int x, int y, unsigned int nglyphInit,
1359                       CharInfoPtr * ppciInit, void *unused)
1360 {
1361     GC_SAVE(pGC);
1362     GCOP_UNWRAP(pGC);
1363     RL_DEBUG_MSG("imageglyph start ");
1364 
1365     if (nglyphInit > 0) {
1366         int top, bot, width = 0;
1367         BoxRec box;
1368         unsigned int nglyph = nglyphInit;
1369         CharInfoPtr *ppci = ppciInit;
1370 
1371         top = max(FONTMAXBOUNDS(pGC->font, ascent), FONTASCENT(pGC->font));
1372         bot = max(FONTMAXBOUNDS(pGC->font, descent), FONTDESCENT(pGC->font));
1373 
1374         box.x1 = ppci[0]->metrics.leftSideBearing;
1375         if (box.x1 > 0)
1376             box.x1 = 0;
1377         box.x2 = ppci[nglyph - 1]->metrics.rightSideBearing -
1378             ppci[nglyph - 1]->metrics.characterWidth;
1379         if (box.x2 < 0)
1380             box.x2 = 0;
1381 
1382         box.x2 += dst->x + x;
1383         box.x1 += dst->x + x;
1384 
1385         while (nglyph--) {
1386             width += (*ppci)->metrics.characterWidth;
1387             ppci++;
1388         }
1389 
1390         if (width > 0)
1391             box.x2 += width;
1392         else
1393             box.x1 += width;
1394 
1395         box.y1 = dst->y + y - top;
1396         box.y2 = dst->y + y + bot;
1397 
1398         RootlessStartDrawing((WindowPtr) dst);
1399 
1400         if (canAccelFill(dst, pGC)) {
1401             GC_UNSET_PM(pGC, dst);
1402         }
1403 
1404         pGC->ops->ImageGlyphBlt(dst, pGC, x, y, nglyphInit, ppciInit, unused);
1405 
1406         TRIM_BOX(box, pGC);
1407         if (BOX_NOT_EMPTY(box))
1408             RootlessDamageBox((WindowPtr) dst, &box);
1409     }
1410     else {
1411         pGC->ops->ImageGlyphBlt(dst, pGC, x, y, nglyphInit, ppciInit, unused);
1412     }
1413 
1414     GC_RESTORE(pGC, dst);
1415     GCOP_WRAP(pGC);
1416     RL_DEBUG_MSG("imageglyph end\n");
1417 }
1418 
1419 static void
RootlessPolyGlyphBlt(DrawablePtr dst,GCPtr pGC,int x,int y,unsigned int nglyph,CharInfoPtr * ppci,void * pglyphBase)1420 RootlessPolyGlyphBlt(DrawablePtr dst, GCPtr pGC,
1421                      int x, int y, unsigned int nglyph,
1422                      CharInfoPtr * ppci, void *pglyphBase)
1423 {
1424     GCOP_UNWRAP(pGC);
1425     RL_DEBUG_MSG("polyglyph start ");
1426 
1427     RootlessStartDrawing((WindowPtr) dst);
1428     pGC->ops->PolyGlyphBlt(dst, pGC, x, y, nglyph, ppci, pglyphBase);
1429 
1430     if (nglyph > 0) {
1431         BoxRec box;
1432 
1433         /* ugh */
1434         box.x1 = dst->x + x + ppci[0]->metrics.leftSideBearing;
1435         box.x2 = dst->x + x + ppci[nglyph - 1]->metrics.rightSideBearing;
1436 
1437         if (nglyph > 1) {
1438             int width = 0;
1439 
1440             while (--nglyph) {
1441                 width += (*ppci)->metrics.characterWidth;
1442                 ppci++;
1443             }
1444 
1445             if (width > 0)
1446                 box.x2 += width;
1447             else
1448                 box.x1 += width;
1449         }
1450 
1451         box.y1 = dst->y + y - FONTMAXBOUNDS(pGC->font, ascent);
1452         box.y2 = dst->y + y + FONTMAXBOUNDS(pGC->font, descent);
1453 
1454         TRIM_BOX(box, pGC);
1455         if (BOX_NOT_EMPTY(box))
1456             RootlessDamageBox((WindowPtr) dst, &box);
1457     }
1458 
1459     GCOP_WRAP(pGC);
1460     RL_DEBUG_MSG("polyglyph end\n");
1461 }
1462 
1463 /* changed area is in dest */
1464 static void
RootlessPushPixels(GCPtr pGC,PixmapPtr pBitMap,DrawablePtr dst,int dx,int dy,int xOrg,int yOrg)1465 RootlessPushPixels(GCPtr pGC, PixmapPtr pBitMap, DrawablePtr dst,
1466                    int dx, int dy, int xOrg, int yOrg)
1467 {
1468     BoxRec box;
1469 
1470     GCOP_UNWRAP(pGC);
1471     RL_DEBUG_MSG("push pixels start ");
1472 
1473     RootlessStartDrawing((WindowPtr) dst);
1474     pGC->ops->PushPixels(pGC, pBitMap, dst, dx, dy, xOrg, yOrg);
1475 
1476     box.x1 = xOrg + dst->x;
1477     box.x2 = box.x1 + dx;
1478     box.y1 = yOrg + dst->y;
1479     box.y2 = box.y1 + dy;
1480 
1481     TRIM_BOX(box, pGC);
1482     if (BOX_NOT_EMPTY(box))
1483         RootlessDamageBox((WindowPtr) dst, &box);
1484 
1485     GCOP_WRAP(pGC);
1486     RL_DEBUG_MSG("push pixels end\n");
1487 }
1488