2 * Graphics Context support for Mac OS X rootless X server
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.
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:
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
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.
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.
31 /* $XFree86: xc/programs/Xserver/hw/darwin/quartz/rootlessGC.c,v 1.3 2002/07/24 05:58:33 torrey Exp $ */
34 #include "scrnintstr.h"
36 #include "pixmapstr.h"
37 #include "windowstr.h"
38 #include "dixfontstr.h"
39 #include "mivalidate.h"
42 #include <sys/types.h>
46 #include "rootless-common.h"
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,
58 static void RootlessDestroyClip(GCPtr pGC);
59 static void RootlessCopyClip(GCPtr pgcDst, GCPtr pgcSrc);
61 GCFuncs rootlessGCFuncs = {
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();
93 static GCOps rootlessGCOps = {
102 RootlessPolyRectangle,
105 RootlessPolyFillRect,
111 RootlessImageGlyphBlt,
112 RootlessPolyGlyphBlt,
114 #ifdef NEED_LINEHELPER
121 RootlessCreateGC(GCPtr pGC)
123 RootlessGCRec *gcrec;
124 RootlessScreenRec *s;
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;
136 SCREEN_WRAP(pGC->pScreen, CreateGC);
142 // ValidateGC wraps gcOps iff dest is viewable. All others just unwrap&call.
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; \
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; \
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)
167 #define GC_SKIP_ROOT(pDst) \
169 if (GC_IS_ROOT (pDst)) \
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.
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.
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).
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.
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
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.
201 The three macros below are used to implement this, drawing ops look
210 if (can_accel_xxx (..) && otherwise-suitable)
211 GC_UNSET_PM (gc, dst);
213 gc->funcs->OP (gc, ...);
215 GC_RESTORE (gc, dst);
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
227 #define GC_RESTORE(pGC, pDraw) \
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; \
241 #define GC_UNSET_PM(pGC, pDraw) \
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; \
258 validate_gc (GCPtr pGC, unsigned long changes, DrawablePtr pDrawable)
260 RootlessGCRec *gcrec = (RootlessGCRec *)
261 (pGC)->devPrivates[rootlessGCPrivateIndex].ptr;
263 pGC->funcs->ValidateGC(pGC, changes, pDrawable);
265 if (((WindowPtr) pDrawable)->viewable)
267 gcrec->originalOps = pGC->ops;
271 static RootlessWindowRec *
272 can_accel_blit (DrawablePtr pDraw, GCPtr pGC)
275 RootlessWindowRec *winRec;
278 if (pGC->alu != GXcopy)
281 if (pDraw->type != DRAWABLE_WINDOW)
284 pm = ~RootlessAlphaMask (pDraw->bitsPerPixel);
285 if ((pGC->planemask & pm) != pm)
288 pTop = TopLevelParent ((WindowPtr) pDraw);
292 winRec = WINREC(pTop);
299 static inline RootlessWindowRec *
300 can_accel_fill (DrawablePtr pDraw, GCPtr pGC)
302 if (pGC->fillStyle != FillSolid)
305 return can_accel_blit (pDraw, pGC);
309 box_bytes (DrawablePtr pDraw, BoxRec *box)
313 pixels = (box->x2 - box->x1) * (box->y2 - box->y1);
315 return pixels * (pDraw->bitsPerPixel >> 3);
319 RootlessValidateGC(GCPtr pGC, unsigned long changes, DrawablePtr pDrawable)
323 gcrec->originalOps = NULL;
325 if (pDrawable->type == DRAWABLE_WINDOW)
327 /* Prevent fb relaxing planemask by telling it we use all
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;
337 pGC->funcs->ValidateGC(pGC, changes, pDrawable);
342 static void RootlessChangeGC(GCPtr pGC, unsigned long mask)
345 pGC->funcs->ChangeGC(pGC, mask);
349 static void RootlessCopyGC(GCPtr pGCSrc, unsigned long mask, GCPtr pGCDst)
351 GCFUNC_UNWRAP(pGCDst);
352 pGCDst->funcs->CopyGC(pGCSrc, mask, pGCDst);
356 static void RootlessDestroyGC(GCPtr pGC)
359 pGC->funcs->DestroyGC(pGC);
363 static void RootlessChangeClip(GCPtr pGC, int type, pointer pvalue, int nrects)
366 pGC->funcs->ChangeClip(pGC, type, pvalue, nrects);
370 static void RootlessDestroyClip(GCPtr pGC)
373 pGC->funcs->DestroyClip(pGC);
377 static void RootlessCopyClip(GCPtr pgcDst, GCPtr pgcSrc)
379 GCFUNC_UNWRAP(pgcDst);
380 pgcDst->funcs->CopyClip(pgcDst, pgcSrc);
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.
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;
398 #define GCOP_WRAP(pGC) \
399 gcrec->originalOps = (pGC)->ops; \
400 (pGC)->funcs = saveFuncs; \
401 (pGC)->ops = &rootlessGCOps;
405 RootlessFillSpans(DrawablePtr dst, GCPtr pGC, int nInit,
406 DDXPointPtr pptInit, int *pwidthInit, int sorted)
412 RL_DEBUG_MSG("fill spans start\n");
415 pGC->ops->FillSpans(dst, pGC, nInit, pptInit, pwidthInit, sorted);
417 DDXPointPtr ppt = pptInit;
418 int *pwidth = pwidthInit;
423 box.x2 = box.x1 + *pwidth;
424 box.y2 = box.y1 = ppt->y;
431 if(box.x2 < (ppt->x + *pwidth))
432 box.x2 = ppt->x + *pwidth;
435 else if(box.y2 < ppt->y)
441 RootlessStartDrawing((WindowPtr) dst);
443 if (can_accel_fill (dst, pGC)
444 && box_bytes (dst, &box) >= xp_fill_bytes_threshold)
446 GC_UNSET_PM (pGC, dst);
449 pGC->ops->FillSpans(dst, pGC, nInit, pptInit, pwidthInit, sorted);
451 TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
452 if(BOX_NOT_EMPTY(box))
453 RootlessDamageBox ((WindowPtr) dst, &box);
455 RootlessFinishedDrawing ((WindowPtr) dst);
458 GC_RESTORE (pGC, dst);
460 RL_DEBUG_MSG("fill spans end\n");
464 RootlessSetSpans(DrawablePtr dst, GCPtr pGC, char *pSrc,
465 DDXPointPtr pptInit, int *pwidthInit,
466 int nspans, int sorted)
470 RL_DEBUG_MSG("set spans start\n");
473 pGC->ops->SetSpans(dst, pGC, pSrc, pptInit, pwidthInit,
476 DDXPointPtr ppt = pptInit;
477 int *pwidth = pwidthInit;
482 box.x2 = box.x1 + *pwidth;
483 box.y2 = box.y1 = ppt->y;
490 if(box.x2 < (ppt->x + *pwidth))
491 box.x2 = ppt->x + *pwidth;
494 else if(box.y2 < ppt->y)
500 RootlessStartDrawing((WindowPtr) dst);
501 pGC->ops->SetSpans(dst, pGC, pSrc, pptInit, pwidthInit,
504 TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
505 if(BOX_NOT_EMPTY(box))
506 RootlessDamageBox ((WindowPtr) dst, &box);
508 RootlessFinishedDrawing ((WindowPtr) dst);
511 RL_DEBUG_MSG("set spans end\n");
515 RootlessPutImage(DrawablePtr dst, GCPtr pGC,
516 int depth, int x, int y, int w, int h,
517 int leftPad, int format, char *pBits)
523 RL_DEBUG_MSG("put image start\n");
525 RootlessStartDrawing((WindowPtr) dst);
526 pGC->ops->PutImage(dst, pGC, depth, x,y,w,h, leftPad, format, pBits);
534 if(BOX_NOT_EMPTY(box))
535 RootlessDamageBox ((WindowPtr) dst, &box);
537 RootlessFinishedDrawing ((WindowPtr) dst);
540 RL_DEBUG_MSG("put image end\n");
543 /* changed area is *dest* rect */
545 RootlessCopyArea(DrawablePtr pSrc, DrawablePtr dst, GCPtr pGC,
546 int srcx, int srcy, int w, int h,
552 Bool src_drawing = FALSE;
554 if (GC_IS_ROOT (dst) || GC_IS_ROOT (pSrc))
555 return NULL; /* nothing exposed */
558 RL_DEBUG_MSG("copy area start (src 0x%x, dst 0x%x)\n", pSrc, dst);
560 if (pSrc->type == DRAWABLE_WINDOW && IsFramedWindow((WindowPtr)pSrc))
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) */
568 bytes = w * h * (pSrc->depth >> 3);
570 if (bytes >= xp_copy_bytes_threshold && can_accel_blit (pSrc, pGC))
572 GC_UNSET_PM (pGC, dst);
575 RootlessStartDrawing((WindowPtr) pSrc);
578 RootlessStartDrawing((WindowPtr) dst);
579 result = pGC->ops->CopyArea(pSrc, dst, pGC, srcx, srcy, w, h, dstx, dsty);
581 box.x1 = dstx + dst->x;
583 box.y1 = dsty + dst->y;
587 if(BOX_NOT_EMPTY(box))
588 RootlessDamageBox ((WindowPtr) dst, &box);
590 RootlessFinishedDrawing ((WindowPtr) dst);
592 RootlessFinishedDrawing ((WindowPtr) pSrc);
594 GC_RESTORE (pGC, dst);
596 RL_DEBUG_MSG("copy area end\n");
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,
608 Bool src_drawing = FALSE;
610 if (GC_IS_ROOT (dst) || GC_IS_ROOT (pSrc))
611 return NULL; /* nothing exposed */
614 RL_DEBUG_MSG("copy plane start\n");
616 if (pSrc->type == DRAWABLE_WINDOW && IsFramedWindow((WindowPtr)pSrc)) {
617 RootlessStartDrawing((WindowPtr) pSrc);
620 RootlessStartDrawing((WindowPtr) dst);
621 result = pGC->ops->CopyPlane(pSrc, dst, pGC, srcx, srcy, w, h,
624 box.x1 = dstx + dst->x;
626 box.y1 = dsty + dst->y;
630 if(BOX_NOT_EMPTY(box))
631 RootlessDamageBox ((WindowPtr) dst, &box);
633 RootlessFinishedDrawing ((WindowPtr) dst);
635 RootlessFinishedDrawing ((WindowPtr) pSrc);
638 RL_DEBUG_MSG("copy plane end\n");
642 // Options for size of changed area:
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))
649 /* changed area is box around all points */
650 static void RootlessPolyPoint(DrawablePtr dst, GCPtr pGC,
651 int mode, int npt, DDXPointPtr pptInit)
655 RL_DEBUG_MSG("polypoint start\n");
657 RootlessStartDrawing((WindowPtr) dst);
658 pGC->ops->PolyPoint(dst, pGC, mode, npt, pptInit);
661 #if ROOTLESS_CHANGED_AREA==0
671 TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
672 if(BOX_NOT_EMPTY(box))
673 RootlessDamageBox ((WindowPtr) dst, &box);
679 #elif ROOTLESS_CHANGED_AREA==1
683 box.x2 = box.x1 = pptInit->x;
684 box.y2 = box.y1 = pptInit->y;
687 if(box.x1 > pptInit->x)
689 else if(box.x2 < pptInit->x)
691 if(box.y1 > pptInit->y)
693 else if(box.y2 < pptInit->y)
700 TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
701 if(BOX_NOT_EMPTY(box))
702 RootlessDamageBox ((WindowPtr) dst, &box);
704 #elif ROOTLESS_CHANGED_AREA==2
705 // clever(?) method: accumulate point in 20-pixel radius
709 box.x2 = box.x1 = firstx = pptInit->x;
710 box.y2 = box.y1 = firsty = pptInit->y;
713 if (abs(pptInit->x - firstx) > 20 ||
714 abs(pptInit->y - firsty) > 20) {
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;
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;
731 TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
732 if(BOX_NOT_EMPTY(box))
733 RootlessDamageBox ((WindowPtr) dst, &box);
734 #endif /* ROOTLESS_CHANGED_AREA */
737 RootlessFinishedDrawing ((WindowPtr) dst);
740 RL_DEBUG_MSG("polypoint end\n");
743 #undef ROOTLESS_CHANGED_AREA
745 /* changed area is box around each line */
746 static void RootlessPolylines(DrawablePtr dst, GCPtr pGC,
747 int mode, int npt, DDXPointPtr pptInit)
751 RL_DEBUG_MSG("poly lines start\n");
753 RootlessStartDrawing((WindowPtr) dst);
754 pGC->ops->Polylines(dst, pGC, mode, npt, pptInit);
758 int extra = pGC->lineWidth >> 1;
760 box.x2 = box.x1 = pptInit->x;
761 box.y2 = box.y1 = pptInit->y;
764 if(pGC->joinStyle == JoinMiter)
765 extra = 6 * pGC->lineWidth;
766 else if(pGC->capStyle == CapProjecting)
767 extra = pGC->lineWidth;
770 if(mode == CoordModePrevious) {
790 if(box.x1 > pptInit->x)
792 else if(box.x2 < pptInit->x)
794 if(box.y1 > pptInit->y)
796 else if(box.y2 < pptInit->y)
811 TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
812 if(BOX_NOT_EMPTY(box))
813 RootlessDamageBox ((WindowPtr) dst, &box);
816 RootlessFinishedDrawing ((WindowPtr) dst);
819 RL_DEBUG_MSG("poly lines end\n");
822 /* changed area is box around each line segment */
823 static void RootlessPolySegment(DrawablePtr dst, GCPtr pGC,
824 int nseg, xSegment *pSeg)
828 RL_DEBUG_MSG("poly segment start (win 0x%x)\n", dst);
830 RootlessStartDrawing((WindowPtr) dst);
831 pGC->ops->PolySegment(dst, pGC, nseg, pSeg);
835 int extra = pGC->lineWidth;
837 if(pGC->capStyle != CapProjecting)
840 if(pSeg->x2 > pSeg->x1) {
848 if(pSeg->y2 > pSeg->y1) {
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;
862 if(pSeg->x2 < box.x1) box.x1 = pSeg->x2;
863 if(pSeg->x1 > box.x2) box.x2 = pSeg->x1;
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;
869 if(pSeg->y2 < box.y1) box.y1 = pSeg->y2;
870 if(pSeg->y1 > box.y2) box.y2 = pSeg->y1;
884 TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
885 if(BOX_NOT_EMPTY(box))
886 RootlessDamageBox ((WindowPtr) dst, &box);
889 RootlessFinishedDrawing ((WindowPtr) dst);
892 RL_DEBUG_MSG("poly segment end\n");
895 /* changed area is box around each line (not entire rects) */
896 static void RootlessPolyRectangle(DrawablePtr dst, GCPtr pGC,
897 int nRects, xRectangle *pRects)
901 RL_DEBUG_MSG("poly rectangle start\n");
903 RootlessStartDrawing((WindowPtr) dst);
904 pGC->ops->PolyRectangle(dst, pGC, nRects, pRects);
908 int offset1, offset2, offset3;
910 offset2 = pGC->lineWidth;
911 if(!offset2) offset2 = 1;
912 offset1 = offset2 >> 1;
913 offset3 = offset2 - offset1;
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);
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);
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);
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);
952 RootlessFinishedDrawing ((WindowPtr) dst);
955 RL_DEBUG_MSG("poly rectangle end\n");
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)
964 RL_DEBUG_MSG("poly arc start\n");
966 RootlessStartDrawing((WindowPtr) dst);
967 pGC->ops->PolyArc(dst, pGC, narcs, parcs);
970 int extra = pGC->lineWidth >> 1;
974 box.x2 = box.x1 + parcs->width;
976 box.y2 = box.y1 + parcs->height;
978 /* should I break these up instead ? */
982 if(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)
988 if(box.y2 < (parcs->y + parcs->height))
989 box.y2 = parcs->y + parcs->height;
1002 TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
1003 if(BOX_NOT_EMPTY(box))
1004 RootlessDamageBox ((WindowPtr) dst, &box);
1007 RootlessFinishedDrawing ((WindowPtr) dst);
1010 RL_DEBUG_MSG("poly arc end\n");
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)
1023 RL_DEBUG_MSG("fill poly start (win 0x%x, fillStyle 0x%x)\n", dst,
1027 pGC->ops->FillPolygon(dst, pGC, shape, mode, count, pptInit);
1029 DDXPointPtr ppt = pptInit;
1033 box.x2 = box.x1 = ppt->x;
1034 box.y2 = box.y1 = ppt->y;
1036 if(mode != CoordModeOrigin) {
1058 else if(box.x2 < ppt->x)
1062 else if(box.y2 < ppt->y)
1070 RootlessStartDrawing((WindowPtr) dst);
1072 if (can_accel_fill (dst, pGC)
1073 && box_bytes (dst, &box) >= xp_fill_bytes_threshold)
1075 GC_UNSET_PM (pGC, dst);
1078 pGC->ops->FillPolygon(dst, pGC, shape, mode, count, pptInit);
1080 TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
1081 if(BOX_NOT_EMPTY(box))
1082 RootlessDamageBox ((WindowPtr) dst, &box);
1084 RootlessFinishedDrawing ((WindowPtr) dst);
1087 GC_RESTORE (pGC, dst);
1089 RL_DEBUG_MSG("fill poly end\n");
1092 /* changed area is the rects */
1093 static void RootlessPolyFillRect(DrawablePtr dst, GCPtr pGC,
1094 int nRectsInit, xRectangle *pRectsInit)
1100 RL_DEBUG_MSG("fill rect start (win 0x%x, fillStyle 0x%x)\n", dst,
1103 if (nRectsInit <= 0) {
1104 pGC->ops->PolyFillRect(dst, pGC, nRectsInit, pRectsInit);
1107 xRectangle *pRects = pRectsInit;
1108 int nRects = nRectsInit;
1111 box.x2 = box.x1 + pRects->width;
1113 box.y2 = box.y1 + pRects->height;
1117 if(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)
1123 if(box.y2 < (pRects->y + pRects->height))
1124 box.y2 = pRects->y + pRects->height;
1127 /* cfb messes with the pRectsInit so we have to do our
1128 calculations first */
1130 RootlessStartDrawing((WindowPtr) dst);
1132 if (can_accel_fill (dst, pGC)
1133 && box_bytes (dst, &box) >= xp_fill_bytes_threshold)
1135 GC_UNSET_PM (pGC, dst);
1138 pGC->ops->PolyFillRect (dst, pGC, nRectsInit, pRectsInit);
1140 TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
1141 if(BOX_NOT_EMPTY(box))
1142 RootlessDamageBox ((WindowPtr) dst, &box);
1144 RootlessFinishedDrawing ((WindowPtr) dst);
1147 GC_RESTORE (pGC, dst);
1149 RL_DEBUG_MSG("fill rect end\n");
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)
1161 RL_DEBUG_MSG("fill arc start\n");
1168 box.x2 = box.x1 + parcs->width;
1170 box.y2 = box.y1 + parcs->height;
1172 /* should I break these up instead ? */
1174 for (i = 0; i < narcs; i++)
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;
1186 RootlessStartDrawing((WindowPtr) dst);
1188 if (can_accel_fill (dst, pGC)
1189 && box_bytes (dst, &box) >= xp_fill_bytes_threshold)
1191 GC_UNSET_PM (pGC, dst);
1194 pGC->ops->PolyFillArc(dst, pGC, narcs, parcs);
1196 TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
1197 if(BOX_NOT_EMPTY(box))
1198 RootlessDamageBox ((WindowPtr) dst, &box);
1200 RootlessFinishedDrawing ((WindowPtr) dst);
1203 pGC->ops->PolyFillArc(dst, pGC, narcs, parcs);
1205 GC_RESTORE (pGC, dst);
1207 RL_DEBUG_MSG("fill arc end\n");
1211 static void RootlessImageText8(DrawablePtr dst, GCPtr pGC,
1212 int x, int y, int count, char *chars)
1218 RL_DEBUG_MSG("imagetext8 start\n");
1220 RootlessStartDrawing((WindowPtr) dst);
1223 int top, bot, Min, Max;
1226 top = max(FONTMAXBOUNDS(pGC->font, ascent), FONTASCENT(pGC->font));
1227 bot = max(FONTMAXBOUNDS(pGC->font, descent), FONTDESCENT(pGC->font));
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;
1235 box.x1 = dst->x + x + Min +
1236 FONTMINBOUNDS(pGC->font, leftSideBearing);
1237 box.x2 = dst->x + x + Max +
1238 FONTMAXBOUNDS(pGC->font, rightSideBearing);
1240 box.y1 = dst->y + y - top;
1241 box.y2 = dst->y + y + bot;
1243 if (can_accel_fill (dst, pGC)
1244 && box_bytes (dst, &box) >= xp_fill_bytes_threshold)
1246 GC_UNSET_PM (pGC, dst);
1249 pGC->ops->ImageText8(dst, pGC, x, y, count, chars);
1252 if(BOX_NOT_EMPTY(box))
1253 RootlessDamageBox ((WindowPtr) dst, &box);
1256 pGC->ops->ImageText8(dst, pGC, x, y, count, chars);
1258 RootlessFinishedDrawing ((WindowPtr) dst);
1260 GC_RESTORE (pGC, dst);
1262 RL_DEBUG_MSG("imagetext8 end\n");
1265 static int RootlessPolyText8(DrawablePtr dst, GCPtr pGC,
1266 int x, int y, int count, char *chars)
1268 int width; // the result, sorta
1270 if (GC_IS_ROOT (dst))
1271 return 0; /* FIXME: ok? */
1274 RL_DEBUG_MSG("polytext8 start\n");
1276 RootlessStartDrawing((WindowPtr) dst);
1277 width = pGC->ops->PolyText8(dst, pGC, x, y, count, chars);
1284 box.x1 = dst->x + x + FONTMINBOUNDS(pGC->font, leftSideBearing);
1285 box.x2 = dst->x + x + FONTMAXBOUNDS(pGC->font, rightSideBearing);
1288 if(width > 0) box.x2 += width;
1289 else box.x1 += width;
1292 box.y1 = dst->y + y - FONTMAXBOUNDS(pGC->font, ascent);
1293 box.y2 = dst->y + y + FONTMAXBOUNDS(pGC->font, descent);
1296 if(BOX_NOT_EMPTY(box))
1297 RootlessDamageBox ((WindowPtr) dst, &box);
1300 RootlessFinishedDrawing ((WindowPtr) dst);
1303 RL_DEBUG_MSG("polytext8 end\n");
1307 static void RootlessImageText16(DrawablePtr dst, GCPtr pGC,
1308 int x, int y, int count, unsigned short *chars)
1314 RL_DEBUG_MSG("imagetext16 start\n");
1317 int top, bot, Min, Max;
1320 top = max(FONTMAXBOUNDS(pGC->font, ascent), FONTASCENT(pGC->font));
1321 bot = max(FONTMAXBOUNDS(pGC->font, descent), FONTDESCENT(pGC->font));
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;
1329 box.x1 = dst->x + x + Min +
1330 FONTMINBOUNDS(pGC->font, leftSideBearing);
1331 box.x2 = dst->x + x + Max +
1332 FONTMAXBOUNDS(pGC->font, rightSideBearing);
1334 box.y1 = dst->y + y - top;
1335 box.y2 = dst->y + y + bot;
1337 RootlessStartDrawing((WindowPtr) dst);
1339 if (can_accel_fill (dst, pGC)
1340 && box_bytes (dst, &box) >= xp_fill_bytes_threshold)
1342 GC_UNSET_PM (pGC, dst);
1345 pGC->ops->ImageText16(dst, pGC, x, y, count, chars);
1348 if(BOX_NOT_EMPTY(box))
1349 RootlessDamageBox ((WindowPtr) dst, &box);
1351 RootlessFinishedDrawing ((WindowPtr) dst);
1354 pGC->ops->ImageText16(dst, pGC, x, y, count, chars);
1356 GC_RESTORE (pGC, dst);
1358 RL_DEBUG_MSG("imagetext16 end\n");
1361 static int RootlessPolyText16(DrawablePtr dst, GCPtr pGC,
1362 int x, int y, int count, unsigned short *chars)
1364 int width; // the result, sorta
1366 if (GC_IS_ROOT (dst))
1367 return 0; /* FIXME: ok? */
1370 RL_DEBUG_MSG("polytext16 start\n");
1372 RootlessStartDrawing((WindowPtr) dst);
1373 width = pGC->ops->PolyText16(dst, pGC, x, y, count, chars);
1380 box.x1 = dst->x + x + FONTMINBOUNDS(pGC->font, leftSideBearing);
1381 box.x2 = dst->x + x + FONTMAXBOUNDS(pGC->font, rightSideBearing);
1384 if(width > 0) box.x2 += width;
1385 else box.x1 += width;
1388 box.y1 = dst->y + y - FONTMAXBOUNDS(pGC->font, ascent);
1389 box.y2 = dst->y + y + FONTMAXBOUNDS(pGC->font, descent);
1392 if(BOX_NOT_EMPTY(box))
1393 RootlessDamageBox ((WindowPtr) dst, &box);
1396 RootlessFinishedDrawing ((WindowPtr) dst);
1399 RL_DEBUG_MSG("polytext16 end\n");
1403 static void RootlessImageGlyphBlt(DrawablePtr dst, GCPtr pGC,
1404 int x, int y, unsigned int nglyph,
1405 CharInfoPtr *ppci, pointer unused)
1409 RL_DEBUG_MSG("imageglyph start\n");
1411 RootlessStartDrawing((WindowPtr) dst);
1412 pGC->ops->ImageGlyphBlt(dst, pGC, x, y, nglyph, ppci, unused);
1415 int top, bot, width = 0;
1418 top = max(FONTMAXBOUNDS(pGC->font, ascent), FONTASCENT(pGC->font));
1419 bot = max(FONTMAXBOUNDS(pGC->font, descent), FONTDESCENT(pGC->font));
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;
1427 box.x2 += dst->x + x;
1428 box.x1 += dst->x + x;
1431 width += (*ppci)->metrics.characterWidth;
1440 box.y1 = dst->y + y - top;
1441 box.y2 = dst->y + y + bot;
1444 if(BOX_NOT_EMPTY(box))
1445 RootlessDamageBox ((WindowPtr) dst, &box);
1448 RootlessFinishedDrawing ((WindowPtr) dst);
1451 RL_DEBUG_MSG("imageglyph end\n");
1454 static void RootlessPolyGlyphBlt(DrawablePtr dst, GCPtr pGC,
1455 int x, int y, unsigned int nglyph,
1456 CharInfoPtr *ppci, pointer pglyphBase)
1460 RL_DEBUG_MSG("polyglyph start\n");
1462 RootlessStartDrawing((WindowPtr) dst);
1463 pGC->ops->PolyGlyphBlt(dst, pGC, x, y, nglyph, ppci, pglyphBase);
1469 box.x1 = dst->x + x + ppci[0]->metrics.leftSideBearing;
1470 box.x2 = dst->x + x + ppci[nglyph - 1]->metrics.rightSideBearing;
1476 width += (*ppci)->metrics.characterWidth;
1480 if(width > 0) box.x2 += width;
1481 else box.x1 += width;
1484 box.y1 = dst->y + y - FONTMAXBOUNDS(pGC->font, ascent);
1485 box.y2 = dst->y + y + FONTMAXBOUNDS(pGC->font, descent);
1488 if(BOX_NOT_EMPTY(box))
1489 RootlessDamageBox ((WindowPtr) dst, &box);
1492 RootlessFinishedDrawing ((WindowPtr) dst);
1495 RL_DEBUG_MSG("polyglyph end\n");
1499 /* changed area is in dest */
1501 RootlessPushPixels(GCPtr pGC, PixmapPtr pBitMap, DrawablePtr dst,
1502 int dx, int dy, int xOrg, int yOrg)
1508 RL_DEBUG_MSG("push pixels start\n");
1510 RootlessStartDrawing((WindowPtr) dst);
1511 pGC->ops->PushPixels(pGC, pBitMap, dst, dx, dy, xOrg, yOrg);
1513 box.x1 = xOrg + dst->x;
1514 box.x2 = box.x1 + dx;
1515 box.y1 = yOrg + dst->y;
1516 box.y2 = box.y1 + dy;
1519 if(BOX_NOT_EMPTY(box))
1520 RootlessDamageBox ((WindowPtr) dst, &box);
1522 RootlessFinishedDrawing ((WindowPtr) dst);
1525 RL_DEBUG_MSG("push pixels end\n");