2 * Graphics Context support for generic rootless X server
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.
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.
32 #ifdef HAVE_DIX_CONFIG_H
33 #include <dix-config.h>
36 #include <stddef.h> /* For NULL */
38 #include "scrnintstr.h"
40 #include "pixmapstr.h"
41 #include "windowstr.h"
42 #include "dixfontstr.h"
43 #include "mivalidate.h"
46 #include <sys/types.h>
50 #include "rootlessCommon.h"
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
, pointer pvalue
, int nrects
);
59 static void RootlessDestroyClip(GCPtr pGC
);
60 static void RootlessCopyClip(GCPtr pgcDst
, GCPtr pgcSrc
);
62 Bool
RootlessCreateGC(GCPtr pGC
);
64 GCFuncs rootlessGCFuncs
= {
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
,
86 static RegionPtr
RootlessCopyPlane(DrawablePtr pSrc
, DrawablePtr dst
,
87 GCPtr pGC
, int srcx
, int srcy
,
88 int w
, int h
, int dstx
, int dsty
,
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
,
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
,
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
, pointer unused
);
117 static void RootlessPolyGlyphBlt(DrawablePtr dst
, GCPtr pGC
, int x
, int y
,
118 unsigned int nglyph
, CharInfoPtr
* ppci
,
120 static void RootlessPushPixels(GCPtr pGC
, PixmapPtr pBitMap
, DrawablePtr dst
,
121 int dx
, int dy
, int xOrg
, int yOrg
);
123 static GCOps rootlessGCOps
= {
132 RootlessPolyRectangle
,
135 RootlessPolyFillRect
,
141 RootlessImageGlyphBlt
,
142 RootlessPolyGlyphBlt
,
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
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
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.
167 The three macros below are used to implement this. Drawing ops that can
168 potentially have their planemask relaxed look like:
176 if (canAccelxxx(..) && otherwise-suitable)
177 GC_UNSET_PM(gc, dst);
179 gc->funcs->OP(gc, ...);
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
193 #define GC_RESTORE(pGC, pDraw) \
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; \
207 #define GC_UNSET_PM(pGC, pDraw) \
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; \
223 #define VALIDATE_GC(pGC, changes, pDrawable) \
225 pGC->funcs->ValidateGC(pGC, changes, pDrawable); \
226 if (((WindowPtr) pDrawable)->viewable) { \
227 gcrec->originalOps = pGC->ops; \
231 static RootlessWindowRec
*
232 canAccelBlit(DrawablePtr pDraw
, GCPtr pGC
)
235 RootlessWindowRec
*winRec
;
238 if (pGC
->alu
!= GXcopy
)
241 if (pDraw
->type
!= DRAWABLE_WINDOW
)
244 pm
= ~RootlessAlphaMask(pDraw
->bitsPerPixel
);
245 if ((pGC
->planemask
& pm
) != pm
)
248 pTop
= TopLevelParent((WindowPtr
) pDraw
);
252 winRec
= WINREC(pTop
);
259 static inline RootlessWindowRec
*
260 canAccelFill(DrawablePtr pDraw
, GCPtr pGC
)
262 if (pGC
->fillStyle
!= FillSolid
)
265 return canAccelBlit(pDraw
, pGC
);
269 * Screen function to create a graphics context
272 RootlessCreateGC(GCPtr pGC
)
274 RootlessGCRec
*gcrec
;
275 RootlessScreenRec
*s
;
278 SCREEN_UNWRAP(pGC
->pScreen
, CreateGC
);
279 s
= SCREENREC(pGC
->pScreen
);
280 result
= s
->CreateGC(pGC
);
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
;
288 SCREEN_WRAP(pGC
->pScreen
, CreateGC
);
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.
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; \
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; \
319 RootlessValidateGC(GCPtr pGC
, unsigned long changes
, DrawablePtr pDrawable
)
323 gcrec
->originalOps
= NULL
;
325 if (pDrawable
->type
== DRAWABLE_WINDOW
) {
326 #ifdef ROOTLESS_PROTECT_ALPHA
327 unsigned int depth
= pDrawable
->depth
;
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
;
336 VALIDATE_GC(pGC
, changes
, pDrawable
);
340 pGC
->funcs
->ValidateGC(pGC
, changes
, pDrawable
);
347 RootlessChangeGC(GCPtr pGC
, unsigned long mask
)
350 pGC
->funcs
->ChangeGC(pGC
, mask
);
355 RootlessCopyGC(GCPtr pGCSrc
, unsigned long mask
, GCPtr pGCDst
)
357 GCFUNC_UNWRAP(pGCDst
);
358 pGCDst
->funcs
->CopyGC(pGCSrc
, mask
, pGCDst
);
363 RootlessDestroyGC(GCPtr pGC
)
366 pGC
->funcs
->DestroyGC(pGC
);
371 RootlessChangeClip(GCPtr pGC
, int type
, pointer pvalue
, int nrects
)
374 pGC
->funcs
->ChangeClip(pGC
, type
, pvalue
, nrects
);
379 RootlessDestroyClip(GCPtr pGC
)
382 pGC
->funcs
->DestroyClip(pGC
);
387 RootlessCopyClip(GCPtr pgcDst
, GCPtr pgcSrc
)
389 GCFUNC_UNWRAP(pgcDst
);
390 pgcDst
->funcs
->CopyClip(pgcDst
, pgcSrc
);
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.
402 // assumes both funcs and ops are wrapped
403 #define GCOP_UNWRAP(pGC) \
404 RootlessGCRec *gcrec = (RootlessGCRec *) \
405 dixLookupPrivate(&(pGC)->devPrivates, rootlessGCPrivateKey); \
406 GCFuncs *saveFuncs = pGC->funcs; \
407 (pGC)->funcs = gcrec->originalFuncs; \
408 (pGC)->ops = gcrec->originalOps;
410 #define GCOP_WRAP(pGC) \
411 gcrec->originalOps = (pGC)->ops; \
412 (pGC)->funcs = saveFuncs; \
413 (pGC)->ops = &rootlessGCOps;
416 RootlessFillSpans(DrawablePtr dst
, GCPtr pGC
, int nInit
,
417 DDXPointPtr pptInit
, int *pwidthInit
, int sorted
)
421 RL_DEBUG_MSG("fill spans start ");
424 pGC
->ops
->FillSpans(dst
, pGC
, nInit
, pptInit
, pwidthInit
, sorted
);
427 DDXPointPtr ppt
= pptInit
;
428 int *pwidth
= pwidthInit
;
433 box
.x2
= box
.x1
+ *pwidth
;
434 box
.y2
= box
.y1
= ppt
->y
;
441 if (box
.x2
< (ppt
->x
+ *pwidth
))
442 box
.x2
= ppt
->x
+ *pwidth
;
445 else if (box
.y2
< ppt
->y
)
451 RootlessStartDrawing((WindowPtr
) dst
);
453 if (canAccelFill(dst
, pGC
)) {
454 GC_UNSET_PM(pGC
, dst
);
457 pGC
->ops
->FillSpans(dst
, pGC
, nInit
, pptInit
, pwidthInit
, sorted
);
459 TRIM_AND_TRANSLATE_BOX(box
, dst
, pGC
);
460 if (BOX_NOT_EMPTY(box
))
461 RootlessDamageBox((WindowPtr
) dst
, &box
);
464 GC_RESTORE(pGC
, dst
);
466 RL_DEBUG_MSG("fill spans end\n");
470 RootlessSetSpans(DrawablePtr dst
, GCPtr pGC
, char *pSrc
,
471 DDXPointPtr pptInit
, int *pwidthInit
, int nspans
, int sorted
)
474 RL_DEBUG_MSG("set spans start ");
477 pGC
->ops
->SetSpans(dst
, pGC
, pSrc
, pptInit
, pwidthInit
, nspans
, sorted
);
480 DDXPointPtr ppt
= pptInit
;
481 int *pwidth
= pwidthInit
;
486 box
.x2
= box
.x1
+ *pwidth
;
487 box
.y2
= box
.y1
= ppt
->y
;
494 if (box
.x2
< (ppt
->x
+ *pwidth
))
495 box
.x2
= ppt
->x
+ *pwidth
;
498 else if (box
.y2
< ppt
->y
)
504 RootlessStartDrawing((WindowPtr
) dst
);
505 pGC
->ops
->SetSpans(dst
, pGC
, pSrc
, pptInit
, pwidthInit
, nspans
, sorted
);
507 TRIM_AND_TRANSLATE_BOX(box
, dst
, pGC
);
508 if (BOX_NOT_EMPTY(box
))
509 RootlessDamageBox((WindowPtr
) dst
, &box
);
512 RL_DEBUG_MSG("set spans end\n");
516 RootlessPutImage(DrawablePtr dst
, GCPtr pGC
,
517 int depth
, int x
, int y
, int w
, int h
,
518 int leftPad
, int format
, char *pBits
)
523 RL_DEBUG_MSG("put image start ");
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
);
538 RL_DEBUG_MSG("put image end\n");
541 /* changed area is *dest* rect */
543 RootlessCopyArea(DrawablePtr pSrc
, DrawablePtr dst
, GCPtr pGC
,
544 int srcx
, int srcy
, int w
, int h
, int dstx
, int dsty
)
552 RL_DEBUG_MSG("copy area start (src 0x%x, dst 0x%x)", pSrc
, dst
);
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) */
559 if (canAccelBlit(pSrc
, pGC
)) {
560 GC_UNSET_PM(pGC
, dst
);
563 RootlessStartDrawing((WindowPtr
) pSrc
);
565 RootlessStartDrawing((WindowPtr
) dst
);
566 result
= pGC
->ops
->CopyArea(pSrc
, dst
, pGC
, srcx
, srcy
, w
, h
, dstx
, dsty
);
568 box
.x1
= dstx
+ dst
->x
;
570 box
.y1
= dsty
+ dst
->y
;
574 if (BOX_NOT_EMPTY(box
))
575 RootlessDamageBox((WindowPtr
) dst
, &box
);
577 GC_RESTORE(pGC
, dst
);
579 RL_DEBUG_MSG("copy area end\n");
583 /* changed area is *dest* rect */
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
)
594 RL_DEBUG_MSG("copy plane start ");
596 if (pSrc
->type
== DRAWABLE_WINDOW
&& IsFramedWindow((WindowPtr
) pSrc
)) {
597 RootlessStartDrawing((WindowPtr
) pSrc
);
599 RootlessStartDrawing((WindowPtr
) dst
);
600 result
= pGC
->ops
->CopyPlane(pSrc
, dst
, pGC
, srcx
, srcy
, w
, h
,
603 box
.x1
= dstx
+ dst
->x
;
605 box
.y1
= dsty
+ dst
->y
;
609 if (BOX_NOT_EMPTY(box
))
610 RootlessDamageBox((WindowPtr
) dst
, &box
);
613 RL_DEBUG_MSG("copy plane end\n");
617 // Options for size of changed area:
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))
624 /* changed area is box around all points */
626 RootlessPolyPoint(DrawablePtr dst
, GCPtr pGC
,
627 int mode
, int npt
, DDXPointPtr pptInit
)
630 RL_DEBUG_MSG("polypoint start ");
632 RootlessStartDrawing((WindowPtr
) dst
);
633 pGC
->ops
->PolyPoint(dst
, pGC
, mode
, npt
, pptInit
);
636 #if ROOTLESS_CHANGED_AREA==0
646 TRIM_AND_TRANSLATE_BOX(box
, dst
, pGC
);
647 if (BOX_NOT_EMPTY(box
))
648 RootlessDamageBox((WindowPtr
) dst
, &box
);
654 #elif ROOTLESS_CHANGED_AREA==1
658 box
.x2
= box
.x1
= pptInit
->x
;
659 box
.y2
= box
.y1
= pptInit
->y
;
662 if (box
.x1
> pptInit
->x
)
664 else if (box
.x2
< pptInit
->x
)
666 if (box
.y1
> pptInit
->y
)
668 else if (box
.y2
< pptInit
->y
)
675 TRIM_AND_TRANSLATE_BOX(box
, dst
, pGC
);
676 if (BOX_NOT_EMPTY(box
))
677 RootlessDamageBox((WindowPtr
) dst
, &box
);
679 #elif ROOTLESS_CHANGED_AREA==2
680 // clever(?) method: accumulate point in 20-pixel radius
684 box
.x2
= box
.x1
= firstx
= pptInit
->x
;
685 box
.y2
= box
.y1
= firsty
= pptInit
->y
;
688 if (abs(pptInit
->x
- firstx
) > 20 || abs(pptInit
->y
- firsty
) > 20) {
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
;
698 if (box
.x1
> pptInit
->x
)
700 else if (box
.x2
< pptInit
->x
)
702 if (box
.y1
> pptInit
->y
)
704 else if (box
.y2
< pptInit
->y
)
710 TRIM_AND_TRANSLATE_BOX(box
, dst
, pGC
);
711 if (BOX_NOT_EMPTY(box
))
712 RootlessDamageBox((WindowPtr
) dst
, &box
);
713 #endif /* ROOTLESS_CHANGED_AREA */
717 RL_DEBUG_MSG("polypoint end\n");
720 #undef ROOTLESS_CHANGED_AREA
722 /* changed area is box around each line */
724 RootlessPolylines(DrawablePtr dst
, GCPtr pGC
,
725 int mode
, int npt
, DDXPointPtr pptInit
)
728 RL_DEBUG_MSG("poly lines start ");
730 RootlessStartDrawing((WindowPtr
) dst
);
731 pGC
->ops
->Polylines(dst
, pGC
, mode
, npt
, pptInit
);
735 int extra
= pGC
->lineWidth
>> 1;
737 box
.x2
= box
.x1
= pptInit
->x
;
738 box
.y2
= box
.y1
= pptInit
->y
;
741 if (pGC
->joinStyle
== JoinMiter
)
742 extra
= 6 * pGC
->lineWidth
;
743 else if (pGC
->capStyle
== CapProjecting
)
744 extra
= pGC
->lineWidth
;
747 if (mode
== CoordModePrevious
) {
768 if (box
.x1
> pptInit
->x
)
770 else if (box
.x2
< pptInit
->x
)
772 if (box
.y1
> pptInit
->y
)
774 else if (box
.y2
< pptInit
->y
)
789 TRIM_AND_TRANSLATE_BOX(box
, dst
, pGC
);
790 if (BOX_NOT_EMPTY(box
))
791 RootlessDamageBox((WindowPtr
) dst
, &box
);
795 RL_DEBUG_MSG("poly lines end\n");
798 /* changed area is box around each line segment */
800 RootlessPolySegment(DrawablePtr dst
, GCPtr pGC
, int nseg
, xSegment
* pSeg
)
803 RL_DEBUG_MSG("poly segment start (win 0x%x)", dst
);
805 RootlessStartDrawing((WindowPtr
) dst
);
806 pGC
->ops
->PolySegment(dst
, pGC
, nseg
, pSeg
);
810 int extra
= pGC
->lineWidth
;
812 if (pGC
->capStyle
!= CapProjecting
)
815 if (pSeg
->x2
> pSeg
->x1
) {
824 if (pSeg
->y2
> pSeg
->y1
) {
835 if (pSeg
->x2
> pSeg
->x1
) {
836 if (pSeg
->x1
< box
.x1
)
838 if (pSeg
->x2
> box
.x2
)
842 if (pSeg
->x2
< box
.x1
)
844 if (pSeg
->x1
> box
.x2
)
847 if (pSeg
->y2
> pSeg
->y1
) {
848 if (pSeg
->y1
< box
.y1
)
850 if (pSeg
->y2
> box
.y2
)
854 if (pSeg
->y2
< box
.y1
)
856 if (pSeg
->y1
> box
.y2
)
871 TRIM_AND_TRANSLATE_BOX(box
, dst
, pGC
);
872 if (BOX_NOT_EMPTY(box
))
873 RootlessDamageBox((WindowPtr
) dst
, &box
);
877 RL_DEBUG_MSG("poly segment end\n");
880 /* changed area is box around each line (not entire rects) */
882 RootlessPolyRectangle(DrawablePtr dst
, GCPtr pGC
,
883 int nRects
, xRectangle
*pRects
)
886 RL_DEBUG_MSG("poly rectangle start ");
888 RootlessStartDrawing((WindowPtr
) dst
);
889 pGC
->ops
->PolyRectangle(dst
, pGC
, nRects
, pRects
);
893 int offset1
, offset2
, offset3
;
895 offset2
= pGC
->lineWidth
;
898 offset1
= offset2
>> 1;
899 offset3
= offset2
- offset1
;
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
);
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
);
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
);
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
);
939 RL_DEBUG_MSG("poly rectangle end\n");
942 /* changed area is box around each arc (assumes all arcs are 360 degrees) */
944 RootlessPolyArc(DrawablePtr dst
, GCPtr pGC
, int narcs
, xArc
* parcs
)
947 RL_DEBUG_MSG("poly arc start ");
949 RootlessStartDrawing((WindowPtr
) dst
);
950 pGC
->ops
->PolyArc(dst
, pGC
, narcs
, parcs
);
953 int extra
= pGC
->lineWidth
>> 1;
957 box
.x2
= box
.x1
+ parcs
->width
;
959 box
.y2
= box
.y1
+ parcs
->height
;
961 /* should I break these up instead ? */
965 if (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
)
971 if (box
.y2
< (parcs
->y
+ parcs
->height
))
972 box
.y2
= parcs
->y
+ parcs
->height
;
985 TRIM_AND_TRANSLATE_BOX(box
, dst
, pGC
);
986 if (BOX_NOT_EMPTY(box
))
987 RootlessDamageBox((WindowPtr
) dst
, &box
);
991 RL_DEBUG_MSG("poly arc end\n");
994 /* changed area is box around each poly */
996 RootlessFillPolygon(DrawablePtr dst
, GCPtr pGC
,
997 int shape
, int mode
, int count
, DDXPointPtr pptInit
)
1001 RL_DEBUG_MSG("fill poly start (win 0x%x, fillStyle 0x%x)", dst
,
1005 pGC
->ops
->FillPolygon(dst
, pGC
, shape
, mode
, count
, pptInit
);
1008 DDXPointPtr ppt
= pptInit
;
1012 box
.x2
= box
.x1
= ppt
->x
;
1013 box
.y2
= box
.y1
= ppt
->y
;
1015 if (mode
!= CoordModeOrigin
) {
1025 else if (box
.x2
< x
)
1029 else if (box
.y2
< y
)
1036 if (box
.x1
> ppt
->x
)
1038 else if (box
.x2
< ppt
->x
)
1040 if (box
.y1
> ppt
->y
)
1042 else if (box
.y2
< ppt
->y
)
1050 RootlessStartDrawing((WindowPtr
) dst
);
1052 if (canAccelFill(dst
, pGC
)) {
1053 GC_UNSET_PM(pGC
, dst
);
1056 pGC
->ops
->FillPolygon(dst
, pGC
, shape
, mode
, count
, pptInit
);
1058 TRIM_AND_TRANSLATE_BOX(box
, dst
, pGC
);
1059 if (BOX_NOT_EMPTY(box
))
1060 RootlessDamageBox((WindowPtr
) dst
, &box
);
1063 GC_RESTORE(pGC
, dst
);
1065 RL_DEBUG_MSG("fill poly end\n");
1068 /* changed area is the rects */
1070 RootlessPolyFillRect(DrawablePtr dst
, GCPtr pGC
,
1071 int nRectsInit
, xRectangle
*pRectsInit
)
1075 RL_DEBUG_MSG("fill rect start (win 0x%x, fillStyle 0x%x)", dst
,
1078 if (nRectsInit
<= 0) {
1079 pGC
->ops
->PolyFillRect(dst
, pGC
, nRectsInit
, pRectsInit
);
1083 xRectangle
*pRects
= pRectsInit
;
1084 int nRects
= nRectsInit
;
1087 box
.x2
= box
.x1
+ pRects
->width
;
1089 box
.y2
= box
.y1
+ pRects
->height
;
1093 if (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
)
1099 if (box
.y2
< (pRects
->y
+ pRects
->height
))
1100 box
.y2
= pRects
->y
+ pRects
->height
;
1103 RootlessStartDrawing((WindowPtr
) dst
);
1105 if (canAccelFill(dst
, pGC
)) {
1106 GC_UNSET_PM(pGC
, dst
);
1109 pGC
->ops
->PolyFillRect(dst
, pGC
, nRectsInit
, pRectsInit
);
1111 TRIM_AND_TRANSLATE_BOX(box
, dst
, pGC
);
1112 if (BOX_NOT_EMPTY(box
))
1113 RootlessDamageBox((WindowPtr
) dst
, &box
);
1116 GC_RESTORE(pGC
, dst
);
1118 RL_DEBUG_MSG("fill rect end\n");
1121 /* changed area is box around each arc (assuming arcs are all 360 degrees) */
1123 RootlessPolyFillArc(DrawablePtr dst
, GCPtr pGC
, int narcsInit
, xArc
* parcsInit
)
1127 RL_DEBUG_MSG("fill arc start ");
1129 if (narcsInit
> 0) {
1131 int narcs
= narcsInit
;
1132 xArc
*parcs
= parcsInit
;
1135 box
.x2
= box
.x1
+ parcs
->width
;
1137 box
.y2
= box
.y1
+ parcs
->height
;
1139 /* should I break these up instead ? */
1143 if (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
)
1149 if (box
.y2
< (parcs
->y
+ parcs
->height
))
1150 box
.y2
= parcs
->y
+ parcs
->height
;
1153 RootlessStartDrawing((WindowPtr
) dst
);
1155 if (canAccelFill(dst
, pGC
)) {
1156 GC_UNSET_PM(pGC
, dst
);
1159 pGC
->ops
->PolyFillArc(dst
, pGC
, narcsInit
, parcsInit
);
1161 TRIM_AND_TRANSLATE_BOX(box
, dst
, pGC
);
1162 if (BOX_NOT_EMPTY(box
))
1163 RootlessDamageBox((WindowPtr
) dst
, &box
);
1166 pGC
->ops
->PolyFillArc(dst
, pGC
, narcsInit
, parcsInit
);
1169 GC_RESTORE(pGC
, dst
);
1171 RL_DEBUG_MSG("fill arc end\n");
1175 RootlessImageText8(DrawablePtr dst
, GCPtr pGC
,
1176 int x
, int y
, int count
, char *chars
)
1180 RL_DEBUG_MSG("imagetext8 start ");
1183 int top
, bot
, Min
, Max
;
1186 top
= max(FONTMAXBOUNDS(pGC
->font
, ascent
), FONTASCENT(pGC
->font
));
1187 bot
= max(FONTMAXBOUNDS(pGC
->font
, descent
), FONTDESCENT(pGC
->font
));
1189 Min
= count
* FONTMINBOUNDS(pGC
->font
, characterWidth
);
1192 Max
= count
* FONTMAXBOUNDS(pGC
->font
, characterWidth
);
1197 box
.x1
= dst
->x
+ x
+ Min
+ FONTMINBOUNDS(pGC
->font
, leftSideBearing
);
1198 box
.x2
= dst
->x
+ x
+ Max
+ FONTMAXBOUNDS(pGC
->font
, rightSideBearing
);
1200 box
.y1
= dst
->y
+ y
- top
;
1201 box
.y2
= dst
->y
+ y
+ bot
;
1203 RootlessStartDrawing((WindowPtr
) dst
);
1205 if (canAccelFill(dst
, pGC
)) {
1206 GC_UNSET_PM(pGC
, dst
);
1209 pGC
->ops
->ImageText8(dst
, pGC
, x
, y
, count
, chars
);
1212 if (BOX_NOT_EMPTY(box
))
1213 RootlessDamageBox((WindowPtr
) dst
, &box
);
1216 pGC
->ops
->ImageText8(dst
, pGC
, x
, y
, count
, chars
);
1219 GC_RESTORE(pGC
, dst
);
1221 RL_DEBUG_MSG("imagetext8 end\n");
1225 RootlessPolyText8(DrawablePtr dst
, GCPtr pGC
,
1226 int x
, int y
, int count
, char *chars
)
1228 int width
; // the result, sorta
1232 RL_DEBUG_MSG("polytext8 start ");
1234 RootlessStartDrawing((WindowPtr
) dst
);
1235 width
= pGC
->ops
->PolyText8(dst
, pGC
, x
, y
, count
, chars
);
1242 box
.x1
= dst
->x
+ x
+ FONTMINBOUNDS(pGC
->font
, leftSideBearing
);
1243 box
.x2
= dst
->x
+ x
+ FONTMAXBOUNDS(pGC
->font
, rightSideBearing
);
1252 box
.y1
= dst
->y
+ y
- FONTMAXBOUNDS(pGC
->font
, ascent
);
1253 box
.y2
= dst
->y
+ y
+ FONTMAXBOUNDS(pGC
->font
, descent
);
1256 if (BOX_NOT_EMPTY(box
))
1257 RootlessDamageBox((WindowPtr
) dst
, &box
);
1261 RL_DEBUG_MSG("polytext8 end\n");
1266 RootlessImageText16(DrawablePtr dst
, GCPtr pGC
,
1267 int x
, int y
, int count
, unsigned short *chars
)
1271 RL_DEBUG_MSG("imagetext16 start ");
1274 int top
, bot
, Min
, Max
;
1277 top
= max(FONTMAXBOUNDS(pGC
->font
, ascent
), FONTASCENT(pGC
->font
));
1278 bot
= max(FONTMAXBOUNDS(pGC
->font
, descent
), FONTDESCENT(pGC
->font
));
1280 Min
= count
* FONTMINBOUNDS(pGC
->font
, characterWidth
);
1283 Max
= count
* FONTMAXBOUNDS(pGC
->font
, characterWidth
);
1288 box
.x1
= dst
->x
+ x
+ Min
+ FONTMINBOUNDS(pGC
->font
, leftSideBearing
);
1289 box
.x2
= dst
->x
+ x
+ Max
+ FONTMAXBOUNDS(pGC
->font
, rightSideBearing
);
1291 box
.y1
= dst
->y
+ y
- top
;
1292 box
.y2
= dst
->y
+ y
+ bot
;
1294 RootlessStartDrawing((WindowPtr
) dst
);
1296 if (canAccelFill(dst
, pGC
)) {
1297 GC_UNSET_PM(pGC
, dst
);
1300 pGC
->ops
->ImageText16(dst
, pGC
, x
, y
, count
, chars
);
1303 if (BOX_NOT_EMPTY(box
))
1304 RootlessDamageBox((WindowPtr
) dst
, &box
);
1307 pGC
->ops
->ImageText16(dst
, pGC
, x
, y
, count
, chars
);
1310 GC_RESTORE(pGC
, dst
);
1312 RL_DEBUG_MSG("imagetext16 end\n");
1316 RootlessPolyText16(DrawablePtr dst
, GCPtr pGC
,
1317 int x
, int y
, int count
, unsigned short *chars
)
1319 int width
; // the result, sorta
1323 RL_DEBUG_MSG("polytext16 start ");
1325 RootlessStartDrawing((WindowPtr
) dst
);
1326 width
= pGC
->ops
->PolyText16(dst
, pGC
, x
, y
, count
, chars
);
1333 box
.x1
= dst
->x
+ x
+ FONTMINBOUNDS(pGC
->font
, leftSideBearing
);
1334 box
.x2
= dst
->x
+ x
+ FONTMAXBOUNDS(pGC
->font
, rightSideBearing
);
1343 box
.y1
= dst
->y
+ y
- FONTMAXBOUNDS(pGC
->font
, ascent
);
1344 box
.y2
= dst
->y
+ y
+ FONTMAXBOUNDS(pGC
->font
, descent
);
1347 if (BOX_NOT_EMPTY(box
))
1348 RootlessDamageBox((WindowPtr
) dst
, &box
);
1352 RL_DEBUG_MSG("polytext16 end\n");
1357 RootlessImageGlyphBlt(DrawablePtr dst
, GCPtr pGC
,
1358 int x
, int y
, unsigned int nglyphInit
,
1359 CharInfoPtr
* ppciInit
, pointer unused
)
1363 RL_DEBUG_MSG("imageglyph start ");
1365 if (nglyphInit
> 0) {
1366 int top
, bot
, width
= 0;
1368 unsigned int nglyph
= nglyphInit
;
1369 CharInfoPtr
*ppci
= ppciInit
;
1371 top
= max(FONTMAXBOUNDS(pGC
->font
, ascent
), FONTASCENT(pGC
->font
));
1372 bot
= max(FONTMAXBOUNDS(pGC
->font
, descent
), FONTDESCENT(pGC
->font
));
1374 box
.x1
= ppci
[0]->metrics
.leftSideBearing
;
1377 box
.x2
= ppci
[nglyph
- 1]->metrics
.rightSideBearing
-
1378 ppci
[nglyph
- 1]->metrics
.characterWidth
;
1382 box
.x2
+= dst
->x
+ x
;
1383 box
.x1
+= dst
->x
+ x
;
1386 width
+= (*ppci
)->metrics
.characterWidth
;
1395 box
.y1
= dst
->y
+ y
- top
;
1396 box
.y2
= dst
->y
+ y
+ bot
;
1398 RootlessStartDrawing((WindowPtr
) dst
);
1400 if (canAccelFill(dst
, pGC
)) {
1401 GC_UNSET_PM(pGC
, dst
);
1404 pGC
->ops
->ImageGlyphBlt(dst
, pGC
, x
, y
, nglyphInit
, ppciInit
, unused
);
1407 if (BOX_NOT_EMPTY(box
))
1408 RootlessDamageBox((WindowPtr
) dst
, &box
);
1411 pGC
->ops
->ImageGlyphBlt(dst
, pGC
, x
, y
, nglyphInit
, ppciInit
, unused
);
1414 GC_RESTORE(pGC
, dst
);
1416 RL_DEBUG_MSG("imageglyph end\n");
1420 RootlessPolyGlyphBlt(DrawablePtr dst
, GCPtr pGC
,
1421 int x
, int y
, unsigned int nglyph
,
1422 CharInfoPtr
* ppci
, pointer pglyphBase
)
1425 RL_DEBUG_MSG("polyglyph start ");
1427 RootlessStartDrawing((WindowPtr
) dst
);
1428 pGC
->ops
->PolyGlyphBlt(dst
, pGC
, x
, y
, nglyph
, ppci
, pglyphBase
);
1434 box
.x1
= dst
->x
+ x
+ ppci
[0]->metrics
.leftSideBearing
;
1435 box
.x2
= dst
->x
+ x
+ ppci
[nglyph
- 1]->metrics
.rightSideBearing
;
1441 width
+= (*ppci
)->metrics
.characterWidth
;
1451 box
.y1
= dst
->y
+ y
- FONTMAXBOUNDS(pGC
->font
, ascent
);
1452 box
.y2
= dst
->y
+ y
+ FONTMAXBOUNDS(pGC
->font
, descent
);
1455 if (BOX_NOT_EMPTY(box
))
1456 RootlessDamageBox((WindowPtr
) dst
, &box
);
1460 RL_DEBUG_MSG("polyglyph end\n");
1463 /* changed area is in dest */
1465 RootlessPushPixels(GCPtr pGC
, PixmapPtr pBitMap
, DrawablePtr dst
,
1466 int dx
, int dy
, int xOrg
, int yOrg
)
1471 RL_DEBUG_MSG("push pixels start ");
1473 RootlessStartDrawing((WindowPtr
) dst
);
1474 pGC
->ops
->PushPixels(pGC
, pBitMap
, dst
, dx
, dy
, xOrg
, yOrg
);
1476 box
.x1
= xOrg
+ dst
->x
;
1477 box
.x2
= box
.x1
+ dx
;
1478 box
.y1
= yOrg
+ dst
->y
;
1479 box
.y2
= box
.y1
+ dy
;
1482 if (BOX_NOT_EMPTY(box
))
1483 RootlessDamageBox((WindowPtr
) dst
, &box
);
1486 RL_DEBUG_MSG("push pixels end\n");