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