1706f2543Smrg/*
2706f2543Smrg * Graphics Context support for generic rootless X server
3706f2543Smrg */
4706f2543Smrg/*
5706f2543Smrg * Copyright (c) 2001 Greg Parker. All Rights Reserved.
6706f2543Smrg * Copyright (c) 2002-2003 Torrey T. Lyons. All Rights Reserved.
7706f2543Smrg * Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
8706f2543Smrg *
9706f2543Smrg * Permission is hereby granted, free of charge, to any person obtaining a
10706f2543Smrg * copy of this software and associated documentation files (the "Software"),
11706f2543Smrg * to deal in the Software without restriction, including without limitation
12706f2543Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13706f2543Smrg * and/or sell copies of the Software, and to permit persons to whom the
14706f2543Smrg * Software is furnished to do so, subject to the following conditions:
15706f2543Smrg *
16706f2543Smrg * The above copyright notice and this permission notice shall be included in
17706f2543Smrg * all copies or substantial portions of the Software.
18706f2543Smrg *
19706f2543Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20706f2543Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21706f2543Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22706f2543Smrg * THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
23706f2543Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
24706f2543Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25706f2543Smrg * DEALINGS IN THE SOFTWARE.
26706f2543Smrg *
27706f2543Smrg * Except as contained in this notice, the name(s) of the above copyright
28706f2543Smrg * holders shall not be used in advertising or otherwise to promote the sale,
29706f2543Smrg * use or other dealings in this Software without prior written authorization.
30706f2543Smrg */
31706f2543Smrg
32706f2543Smrg#ifdef HAVE_DIX_CONFIG_H
33706f2543Smrg#include <dix-config.h>
34706f2543Smrg#endif
35706f2543Smrg
36706f2543Smrg#include <stddef.h> /* For NULL */
37706f2543Smrg#include "mi.h"
38706f2543Smrg#include "scrnintstr.h"
39706f2543Smrg#include "gcstruct.h"
40706f2543Smrg#include "pixmapstr.h"
41706f2543Smrg#include "windowstr.h"
42706f2543Smrg#include "dixfontstr.h"
43706f2543Smrg#include "mivalidate.h"
44706f2543Smrg#include "fb.h"
45706f2543Smrg
46706f2543Smrg#include <sys/types.h>
47706f2543Smrg#include <sys/stat.h>
48706f2543Smrg#include <fcntl.h>
49706f2543Smrg
50706f2543Smrg#include "rootlessCommon.h"
51706f2543Smrg
52706f2543Smrg
53706f2543Smrg// GC functions
54706f2543Smrgstatic void RootlessValidateGC(GCPtr pGC, unsigned long changes,
55706f2543Smrg                               DrawablePtr pDrawable);
56706f2543Smrgstatic void RootlessChangeGC(GCPtr pGC, unsigned long mask);
57706f2543Smrgstatic void RootlessCopyGC(GCPtr pGCSrc, unsigned long mask, GCPtr pGCDst);
58706f2543Smrgstatic void RootlessDestroyGC(GCPtr pGC);
59706f2543Smrgstatic void RootlessChangeClip(GCPtr pGC, int type, pointer pvalue,
60706f2543Smrg                               int nrects);
61706f2543Smrgstatic void RootlessDestroyClip(GCPtr pGC);
62706f2543Smrgstatic void RootlessCopyClip(GCPtr pgcDst, GCPtr pgcSrc);
63706f2543Smrg
64706f2543SmrgBool RootlessCreateGC(GCPtr pGC);
65706f2543Smrg
66706f2543SmrgGCFuncs rootlessGCFuncs = {
67706f2543Smrg    RootlessValidateGC,
68706f2543Smrg    RootlessChangeGC,
69706f2543Smrg    RootlessCopyGC,
70706f2543Smrg    RootlessDestroyGC,
71706f2543Smrg    RootlessChangeClip,
72706f2543Smrg    RootlessDestroyClip,
73706f2543Smrg    RootlessCopyClip,
74706f2543Smrg};
75706f2543Smrg
76706f2543Smrg// GC operations
77706f2543Smrgstatic void RootlessFillSpans(DrawablePtr dst, GCPtr pGC, int nInit,
78706f2543Smrg			      DDXPointPtr pptInit, int *pwidthInit,
79706f2543Smrg			      int sorted);
80706f2543Smrgstatic void RootlessSetSpans(DrawablePtr dst, GCPtr pGC, char *pSrc,
81706f2543Smrg			     DDXPointPtr pptInit, int *pwidthInit,
82706f2543Smrg			     int nspans, int sorted);
83706f2543Smrgstatic void RootlessPutImage(DrawablePtr dst, GCPtr pGC,
84706f2543Smrg			     int depth, int x, int y, int w, int h,
85706f2543Smrg			     int leftPad, int format, char *pBits);
86706f2543Smrgstatic RegionPtr RootlessCopyArea(DrawablePtr pSrc, DrawablePtr dst, GCPtr pGC,
87706f2543Smrg				  int srcx, int srcy, int w, int h,
88706f2543Smrg				  int dstx, int dsty);
89706f2543Smrgstatic RegionPtr RootlessCopyPlane(DrawablePtr pSrc, DrawablePtr dst,
90706f2543Smrg                                   GCPtr pGC, int srcx, int srcy,
91706f2543Smrg                                   int w, int h, int dstx, int dsty,
92706f2543Smrg                                   unsigned long plane);
93706f2543Smrgstatic void RootlessPolyPoint(DrawablePtr dst, GCPtr pGC,
94706f2543Smrg                              int mode, int npt, DDXPointPtr pptInit);
95706f2543Smrgstatic void RootlessPolylines(DrawablePtr dst, GCPtr pGC,
96706f2543Smrg                              int mode, int npt, DDXPointPtr pptInit);
97706f2543Smrgstatic void RootlessPolySegment(DrawablePtr dst, GCPtr pGC,
98706f2543Smrg                                int nseg, xSegment *pSeg);
99706f2543Smrgstatic void RootlessPolyRectangle(DrawablePtr dst, GCPtr pGC,
100706f2543Smrg                                  int nRects, xRectangle *pRects);
101706f2543Smrgstatic void RootlessPolyArc(DrawablePtr dst, GCPtr pGC, int narcs, xArc *parcs);
102706f2543Smrgstatic void RootlessFillPolygon(DrawablePtr dst, GCPtr pGC,
103706f2543Smrg                                int shape, int mode, int count,
104706f2543Smrg                                DDXPointPtr pptInit);
105706f2543Smrgstatic void RootlessPolyFillRect(DrawablePtr dst, GCPtr pGC,
106706f2543Smrg                                 int nRectsInit, xRectangle *pRectsInit);
107706f2543Smrgstatic void RootlessPolyFillArc(DrawablePtr dst, GCPtr pGC,
108706f2543Smrg                                int narcsInit, xArc *parcsInit);
109706f2543Smrgstatic int RootlessPolyText8(DrawablePtr dst, GCPtr pGC,
110706f2543Smrg			     int x, int y, int count, char *chars);
111706f2543Smrgstatic int RootlessPolyText16(DrawablePtr dst, GCPtr pGC,
112706f2543Smrg			      int x, int y, int count, unsigned short *chars);
113706f2543Smrgstatic void RootlessImageText8(DrawablePtr dst, GCPtr pGC,
114706f2543Smrg                               int x, int y, int count, char *chars);
115706f2543Smrgstatic void RootlessImageText16(DrawablePtr dst, GCPtr pGC,
116706f2543Smrg                                int x, int y, int count, unsigned short *chars);
117706f2543Smrgstatic void RootlessImageGlyphBlt(DrawablePtr dst, GCPtr pGC,
118706f2543Smrg                                  int x, int y, unsigned int nglyphInit,
119706f2543Smrg                                  CharInfoPtr *ppciInit, pointer unused);
120706f2543Smrgstatic void RootlessPolyGlyphBlt(DrawablePtr dst, GCPtr pGC,
121706f2543Smrg                                 int x, int y, unsigned int nglyph,
122706f2543Smrg                                 CharInfoPtr *ppci, pointer pglyphBase);
123706f2543Smrgstatic void RootlessPushPixels(GCPtr pGC, PixmapPtr pBitMap, DrawablePtr dst,
124706f2543Smrg			       int dx, int dy, int xOrg, int yOrg);
125706f2543Smrg
126706f2543Smrg
127706f2543Smrgstatic GCOps rootlessGCOps = {
128706f2543Smrg    RootlessFillSpans,
129706f2543Smrg    RootlessSetSpans,
130706f2543Smrg    RootlessPutImage,
131706f2543Smrg    RootlessCopyArea,
132706f2543Smrg    RootlessCopyPlane,
133706f2543Smrg    RootlessPolyPoint,
134706f2543Smrg    RootlessPolylines,
135706f2543Smrg    RootlessPolySegment,
136706f2543Smrg    RootlessPolyRectangle,
137706f2543Smrg    RootlessPolyArc,
138706f2543Smrg    RootlessFillPolygon,
139706f2543Smrg    RootlessPolyFillRect,
140706f2543Smrg    RootlessPolyFillArc,
141706f2543Smrg    RootlessPolyText8,
142706f2543Smrg    RootlessPolyText16,
143706f2543Smrg    RootlessImageText8,
144706f2543Smrg    RootlessImageText16,
145706f2543Smrg    RootlessImageGlyphBlt,
146706f2543Smrg    RootlessPolyGlyphBlt,
147706f2543Smrg    RootlessPushPixels
148706f2543Smrg};
149706f2543Smrg
150706f2543Smrg/*
151706f2543Smrg   If ROOTLESS_PROTECT_ALPHA is set, we have to make sure that the alpha
152706f2543Smrg   channel of the on screen windows is always opaque. fb makes this harder
153706f2543Smrg   than it would otherwise be by noticing that a planemask of 0x00ffffff
154706f2543Smrg   includes all bits when depth==24, and so it "optimizes" the planemask to
155706f2543Smrg   0xffffffff. We work around this by temporarily setting depth=bpp while
156706f2543Smrg   changing the GC.
157706f2543Smrg
158706f2543Smrg   So the normal situation (in 32 bit mode) is that the planemask is
159706f2543Smrg   0x00ffffff and thus fb leaves the alpha channel alone. The rootless
160706f2543Smrg   implementation is responsible for setting the alpha channel opaque
161706f2543Smrg   initially.
162706f2543Smrg
163706f2543Smrg   Unfortunately drawing with a planemask that doesn't have all bits set
164706f2543Smrg   normally causes fb to fall off its fastest paths when blitting and
165706f2543Smrg   filling.  So we try to recognize when we can relax the planemask back to
166706f2543Smrg   0xffffffff, and do that for the duration of the drawing operation,
167706f2543Smrg   setting the alpha channel in fg/bg pixels to opaque at the same time. We
168706f2543Smrg   can do this when drawing op is GXcopy. We can also do this when copying
169706f2543Smrg   from another window since its alpha channel must also be opaque.
170706f2543Smrg
171706f2543Smrg   The three macros below are used to implement this. Drawing ops that can
172706f2543Smrg   potentially have their planemask relaxed look like:
173706f2543Smrg
174706f2543Smrg   OP {
175706f2543Smrg       GC_SAVE(gc);
176706f2543Smrg       GCOP_UNWRAP(gc);
177706f2543Smrg
178706f2543Smrg       ...
179706f2543Smrg
180706f2543Smrg       if (canAccelxxx(..) && otherwise-suitable)
181706f2543Smrg            GC_UNSET_PM(gc, dst);
182706f2543Smrg
183706f2543Smrg       gc->funcs->OP(gc, ...);
184706f2543Smrg
185706f2543Smrg       GC_RESTORE(gc, dst);
186706f2543Smrg       GCOP_WRAP(gc);
187706f2543Smrg   }
188706f2543Smrg
189706f2543Smrg */
190706f2543Smrg
191706f2543Smrg#define GC_SAVE(pGC) 				\
192706f2543Smrg    unsigned long _save_fg = (pGC)->fgPixel;	\
193706f2543Smrg    unsigned long _save_bg = (pGC)->bgPixel;	\
194706f2543Smrg    unsigned long _save_pm = (pGC)->planemask;	\
195706f2543Smrg    Bool _changed = FALSE
196706f2543Smrg
197706f2543Smrg#define GC_RESTORE(pGC, pDraw)					\
198706f2543Smrg    do {							\
199706f2543Smrg        if (_changed) {						\
200706f2543Smrg            unsigned int depth = (pDraw)->depth;		\
201706f2543Smrg            (pGC)->fgPixel = _save_fg;				\
202706f2543Smrg            (pGC)->bgPixel = _save_bg;				\
203706f2543Smrg            (pGC)->planemask = _save_pm;			\
204706f2543Smrg            (pDraw)->depth = (pDraw)->bitsPerPixel;		\
205706f2543Smrg            VALIDATE_GC(pGC, GCForeground | GCBackground |	\
206706f2543Smrg                        GCPlaneMask, pDraw);			\
207706f2543Smrg            (pDraw)->depth = depth;				\
208706f2543Smrg        }							\
209706f2543Smrg    } while (0)
210706f2543Smrg
211706f2543Smrg#define GC_UNSET_PM(pGC, pDraw)						\
212706f2543Smrg    do {								\
213706f2543Smrg        unsigned int mask = RootlessAlphaMask ((pDraw)->bitsPerPixel);	\
214706f2543Smrg        if (((pGC)->planemask & mask) != mask) {			\
215706f2543Smrg            unsigned int depth = (pDraw)->depth;			\
216706f2543Smrg            (pGC)->fgPixel |= mask;					\
217706f2543Smrg            (pGC)->bgPixel |= mask;					\
218706f2543Smrg            (pGC)->planemask |= mask;					\
219706f2543Smrg            (pDraw)->depth = (pDraw)->bitsPerPixel;			\
220706f2543Smrg            VALIDATE_GC(pGC, GCForeground |				\
221706f2543Smrg                        GCBackground | GCPlaneMask, pDraw);		\
222706f2543Smrg            (pDraw)->depth = depth;					\
223706f2543Smrg            _changed = TRUE;						\
224706f2543Smrg        }								\
225706f2543Smrg    } while (0)
226706f2543Smrg
227706f2543Smrg#define VALIDATE_GC(pGC, changes, pDrawable)				\
228706f2543Smrg    do {								\
229706f2543Smrg        pGC->funcs->ValidateGC(pGC, changes, pDrawable);		\
230706f2543Smrg        if (((WindowPtr) pDrawable)->viewable) {			\
231706f2543Smrg            gcrec->originalOps = pGC->ops;				\
232706f2543Smrg        }								\
233706f2543Smrg    } while(0)
234706f2543Smrg
235706f2543Smrgstatic RootlessWindowRec *
236706f2543SmrgcanAccelBlit (DrawablePtr pDraw, GCPtr pGC)
237706f2543Smrg{
238706f2543Smrg    WindowPtr pTop;
239706f2543Smrg    RootlessWindowRec *winRec;
240706f2543Smrg    unsigned int pm;
241706f2543Smrg
242706f2543Smrg    if (pGC->alu != GXcopy)
243706f2543Smrg        return NULL;
244706f2543Smrg
245706f2543Smrg    if (pDraw->type != DRAWABLE_WINDOW)
246706f2543Smrg        return NULL;
247706f2543Smrg
248706f2543Smrg    pm = ~RootlessAlphaMask(pDraw->bitsPerPixel);
249706f2543Smrg    if ((pGC->planemask & pm) != pm)
250706f2543Smrg        return NULL;
251706f2543Smrg
252706f2543Smrg    pTop = TopLevelParent((WindowPtr) pDraw);
253706f2543Smrg    if (pTop == NULL)
254706f2543Smrg        return NULL;
255706f2543Smrg
256706f2543Smrg    winRec = WINREC(pTop);
257706f2543Smrg    if (winRec == NULL)
258706f2543Smrg        return NULL;
259706f2543Smrg
260706f2543Smrg    return winRec;
261706f2543Smrg}
262706f2543Smrg
263706f2543Smrgstatic inline RootlessWindowRec *
264706f2543SmrgcanAccelFill(DrawablePtr pDraw, GCPtr pGC)
265706f2543Smrg{
266706f2543Smrg    if (pGC->fillStyle != FillSolid)
267706f2543Smrg        return NULL;
268706f2543Smrg
269706f2543Smrg    return canAccelBlit(pDraw, pGC);
270706f2543Smrg}
271706f2543Smrg
272706f2543Smrg
273706f2543Smrg/*
274706f2543Smrg * Screen function to create a graphics context
275706f2543Smrg */
276706f2543SmrgBool
277706f2543SmrgRootlessCreateGC(GCPtr pGC)
278706f2543Smrg{
279706f2543Smrg    RootlessGCRec *gcrec;
280706f2543Smrg    RootlessScreenRec *s;
281706f2543Smrg    Bool result;
282706f2543Smrg
283706f2543Smrg    SCREEN_UNWRAP(pGC->pScreen, CreateGC);
284706f2543Smrg    s = SCREENREC(pGC->pScreen);
285706f2543Smrg    result = s->CreateGC(pGC);
286706f2543Smrg
287706f2543Smrg    gcrec = (RootlessGCRec *)
288706f2543Smrg	dixLookupPrivate(&pGC->devPrivates, rootlessGCPrivateKey);
289706f2543Smrg    gcrec->originalOps = NULL; // don't wrap ops yet
290706f2543Smrg    gcrec->originalFuncs = pGC->funcs;
291706f2543Smrg    pGC->funcs = &rootlessGCFuncs;
292706f2543Smrg
293706f2543Smrg    SCREEN_WRAP(pGC->pScreen, CreateGC);
294706f2543Smrg    return result;
295706f2543Smrg}
296706f2543Smrg
297706f2543Smrg
298706f2543Smrg/*
299706f2543Smrg * GC funcs
300706f2543Smrg *
301706f2543Smrg * These wrap lower level GC funcs.
302706f2543Smrg * ValidateGC wraps the GC ops iff dest is viewable.
303706f2543Smrg * All the others just unwrap and call.
304706f2543Smrg */
305706f2543Smrg
306706f2543Smrg// GCFUNC_UNRAP assumes funcs have been wrapped and
307706f2543Smrg// does not assume ops have been wrapped
308706f2543Smrg#define GCFUNC_UNWRAP(pGC) \
309706f2543Smrg    RootlessGCRec *gcrec = (RootlessGCRec *) \
310706f2543Smrg	dixLookupPrivate(&(pGC)->devPrivates, rootlessGCPrivateKey); \
311706f2543Smrg    (pGC)->funcs = gcrec->originalFuncs; \
312706f2543Smrg    if (gcrec->originalOps) { \
313706f2543Smrg        (pGC)->ops = gcrec->originalOps; \
314706f2543Smrg}
315706f2543Smrg
316706f2543Smrg#define GCFUNC_WRAP(pGC) \
317706f2543Smrg    gcrec->originalFuncs = (pGC)->funcs; \
318706f2543Smrg    (pGC)->funcs = &rootlessGCFuncs; \
319706f2543Smrg    if (gcrec->originalOps) { \
320706f2543Smrg        gcrec->originalOps = (pGC)->ops; \
321706f2543Smrg        (pGC)->ops = &rootlessGCOps; \
322706f2543Smrg}
323706f2543Smrg
324706f2543Smrg
325706f2543Smrgstatic void
326706f2543SmrgRootlessValidateGC(GCPtr pGC, unsigned long changes, DrawablePtr pDrawable)
327706f2543Smrg{
328706f2543Smrg    GCFUNC_UNWRAP(pGC);
329706f2543Smrg
330706f2543Smrg    gcrec->originalOps = NULL;
331706f2543Smrg
332706f2543Smrg    if (pDrawable->type == DRAWABLE_WINDOW)
333706f2543Smrg    {
334706f2543Smrg#ifdef ROOTLESS_PROTECT_ALPHA
335706f2543Smrg        unsigned int depth = pDrawable->depth;
336706f2543Smrg
337706f2543Smrg        // We force a planemask so fb doesn't overwrite the alpha channel.
338706f2543Smrg        // Left to its own devices, fb will optimize away the planemask.
339706f2543Smrg        pDrawable->depth = pDrawable->bitsPerPixel;
340706f2543Smrg        pGC->planemask &= ~RootlessAlphaMask(pDrawable->bitsPerPixel);
341706f2543Smrg        VALIDATE_GC(pGC, changes | GCPlaneMask, pDrawable);
342706f2543Smrg        pDrawable->depth = depth;
343706f2543Smrg#else
344706f2543Smrg        VALIDATE_GC(pGC, changes, pDrawable);
345706f2543Smrg#endif
346706f2543Smrg    } else {
347706f2543Smrg        pGC->funcs->ValidateGC(pGC, changes, pDrawable);
348706f2543Smrg    }
349706f2543Smrg
350706f2543Smrg    GCFUNC_WRAP(pGC);
351706f2543Smrg}
352706f2543Smrg
353706f2543Smrgstatic void RootlessChangeGC(GCPtr pGC, unsigned long mask)
354706f2543Smrg{
355706f2543Smrg    GCFUNC_UNWRAP(pGC);
356706f2543Smrg    pGC->funcs->ChangeGC(pGC, mask);
357706f2543Smrg    GCFUNC_WRAP(pGC);
358706f2543Smrg}
359706f2543Smrg
360706f2543Smrgstatic void RootlessCopyGC(GCPtr pGCSrc, unsigned long mask, GCPtr pGCDst)
361706f2543Smrg{
362706f2543Smrg    GCFUNC_UNWRAP(pGCDst);
363706f2543Smrg    pGCDst->funcs->CopyGC(pGCSrc, mask, pGCDst);
364706f2543Smrg    GCFUNC_WRAP(pGCDst);
365706f2543Smrg}
366706f2543Smrg
367706f2543Smrgstatic void RootlessDestroyGC(GCPtr pGC)
368706f2543Smrg{
369706f2543Smrg    GCFUNC_UNWRAP(pGC);
370706f2543Smrg    pGC->funcs->DestroyGC(pGC);
371706f2543Smrg    GCFUNC_WRAP(pGC);
372706f2543Smrg}
373706f2543Smrg
374706f2543Smrgstatic void RootlessChangeClip(GCPtr pGC, int type, pointer pvalue, int nrects)
375706f2543Smrg{
376706f2543Smrg    GCFUNC_UNWRAP(pGC);
377706f2543Smrg    pGC->funcs->ChangeClip(pGC, type, pvalue, nrects);
378706f2543Smrg    GCFUNC_WRAP(pGC);
379706f2543Smrg}
380706f2543Smrg
381706f2543Smrgstatic void RootlessDestroyClip(GCPtr pGC)
382706f2543Smrg{
383706f2543Smrg    GCFUNC_UNWRAP(pGC);
384706f2543Smrg    pGC->funcs->DestroyClip(pGC);
385706f2543Smrg    GCFUNC_WRAP(pGC);
386706f2543Smrg}
387706f2543Smrg
388706f2543Smrgstatic void RootlessCopyClip(GCPtr pgcDst, GCPtr pgcSrc)
389706f2543Smrg{
390706f2543Smrg    GCFUNC_UNWRAP(pgcDst);
391706f2543Smrg    pgcDst->funcs->CopyClip(pgcDst, pgcSrc);
392706f2543Smrg    GCFUNC_WRAP(pgcDst);
393706f2543Smrg}
394706f2543Smrg
395706f2543Smrg
396706f2543Smrg/*
397706f2543Smrg * GC ops
398706f2543Smrg *
399706f2543Smrg * We can't use shadowfb because shadowfb assumes one pixmap
400706f2543Smrg * and our root window is a special case.
401706f2543Smrg * However, much of this code is copied from shadowfb.
402706f2543Smrg */
403706f2543Smrg
404706f2543Smrg// assumes both funcs and ops are wrapped
405706f2543Smrg#define GCOP_UNWRAP(pGC) \
406706f2543Smrg    RootlessGCRec *gcrec = (RootlessGCRec *) \
407706f2543Smrg        dixLookupPrivate(&(pGC)->devPrivates, rootlessGCPrivateKey); \
408706f2543Smrg    GCFuncs *saveFuncs = pGC->funcs; \
409706f2543Smrg    (pGC)->funcs = gcrec->originalFuncs; \
410706f2543Smrg    (pGC)->ops = gcrec->originalOps;
411706f2543Smrg
412706f2543Smrg#define GCOP_WRAP(pGC) \
413706f2543Smrg    gcrec->originalOps = (pGC)->ops; \
414706f2543Smrg    (pGC)->funcs = saveFuncs; \
415706f2543Smrg    (pGC)->ops = &rootlessGCOps;
416706f2543Smrg
417706f2543Smrgstatic void
418706f2543SmrgRootlessFillSpans(DrawablePtr dst, GCPtr pGC, int nInit,
419706f2543Smrg                  DDXPointPtr pptInit, int *pwidthInit, int sorted)
420706f2543Smrg{
421706f2543Smrg    GC_SAVE(pGC);
422706f2543Smrg    GCOP_UNWRAP(pGC);
423706f2543Smrg    RL_DEBUG_MSG("fill spans start ");
424706f2543Smrg
425706f2543Smrg    if (nInit <= 0) {
426706f2543Smrg        pGC->ops->FillSpans(dst, pGC, nInit, pptInit, pwidthInit, sorted);
427706f2543Smrg    } else {
428706f2543Smrg        DDXPointPtr ppt = pptInit;
429706f2543Smrg        int *pwidth = pwidthInit;
430706f2543Smrg        int i = nInit;
431706f2543Smrg        BoxRec box;
432706f2543Smrg
433706f2543Smrg        box.x1 = ppt->x;
434706f2543Smrg        box.x2 = box.x1 + *pwidth;
435706f2543Smrg        box.y2 = box.y1 = ppt->y;
436706f2543Smrg
437706f2543Smrg        while (--i) {
438706f2543Smrg            ppt++;
439706f2543Smrg            pwidth++;
440706f2543Smrg            if (box.x1 > ppt->x)
441706f2543Smrg                box.x1 = ppt->x;
442706f2543Smrg            if (box.x2 < (ppt->x + *pwidth))
443706f2543Smrg                box.x2 = ppt->x + *pwidth;
444706f2543Smrg            if (box.y1 > ppt->y)
445706f2543Smrg                box.y1 = ppt->y;
446706f2543Smrg            else if (box.y2 < ppt->y)
447706f2543Smrg                box.y2 = ppt->y;
448706f2543Smrg        }
449706f2543Smrg
450706f2543Smrg        box.y2++;
451706f2543Smrg
452706f2543Smrg        RootlessStartDrawing((WindowPtr) dst);
453706f2543Smrg
454706f2543Smrg        if (canAccelFill(dst, pGC))
455706f2543Smrg        {
456706f2543Smrg            GC_UNSET_PM(pGC, dst);
457706f2543Smrg        }
458706f2543Smrg
459706f2543Smrg        pGC->ops->FillSpans(dst, pGC, nInit, pptInit, pwidthInit, sorted);
460706f2543Smrg
461706f2543Smrg        TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
462706f2543Smrg        if (BOX_NOT_EMPTY(box))
463706f2543Smrg            RootlessDamageBox ((WindowPtr) dst, &box);
464706f2543Smrg    }
465706f2543Smrg
466706f2543Smrg    GC_RESTORE(pGC, dst);
467706f2543Smrg    GCOP_WRAP(pGC);
468706f2543Smrg    RL_DEBUG_MSG("fill spans end\n");
469706f2543Smrg}
470706f2543Smrg
471706f2543Smrgstatic void
472706f2543SmrgRootlessSetSpans(DrawablePtr dst, GCPtr pGC, char *pSrc,
473706f2543Smrg                 DDXPointPtr pptInit, int *pwidthInit,
474706f2543Smrg                 int nspans, int sorted)
475706f2543Smrg{
476706f2543Smrg    GCOP_UNWRAP(pGC);
477706f2543Smrg    RL_DEBUG_MSG("set spans start ");
478706f2543Smrg
479706f2543Smrg    if (nspans <= 0) {
480706f2543Smrg        pGC->ops->SetSpans(dst, pGC, pSrc, pptInit, pwidthInit,
481706f2543Smrg                           nspans, sorted);
482706f2543Smrg    } else {
483706f2543Smrg        DDXPointPtr ppt = pptInit;
484706f2543Smrg        int *pwidth = pwidthInit;
485706f2543Smrg        int i = nspans;
486706f2543Smrg        BoxRec box;
487706f2543Smrg
488706f2543Smrg        box.x1 = ppt->x;
489706f2543Smrg        box.x2 = box.x1 + *pwidth;
490706f2543Smrg        box.y2 = box.y1 = ppt->y;
491706f2543Smrg
492706f2543Smrg        while (--i) {
493706f2543Smrg            ppt++;
494706f2543Smrg            pwidth++;
495706f2543Smrg            if (box.x1 > ppt->x)
496706f2543Smrg                box.x1 = ppt->x;
497706f2543Smrg            if (box.x2 < (ppt->x + *pwidth))
498706f2543Smrg                box.x2 = ppt->x + *pwidth;
499706f2543Smrg            if (box.y1 > ppt->y)
500706f2543Smrg                box.y1 = ppt->y;
501706f2543Smrg            else if (box.y2 < ppt->y)
502706f2543Smrg                box.y2 = ppt->y;
503706f2543Smrg        }
504706f2543Smrg
505706f2543Smrg        box.y2++;
506706f2543Smrg
507706f2543Smrg        RootlessStartDrawing((WindowPtr) dst);
508706f2543Smrg        pGC->ops->SetSpans(dst, pGC, pSrc, pptInit, pwidthInit,
509706f2543Smrg                           nspans, sorted);
510706f2543Smrg
511706f2543Smrg        TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
512706f2543Smrg        if (BOX_NOT_EMPTY(box))
513706f2543Smrg            RootlessDamageBox ((WindowPtr) dst, &box);
514706f2543Smrg    }
515706f2543Smrg    GCOP_WRAP(pGC);
516706f2543Smrg    RL_DEBUG_MSG("set spans end\n");
517706f2543Smrg}
518706f2543Smrg
519706f2543Smrgstatic void
520706f2543SmrgRootlessPutImage(DrawablePtr dst, GCPtr pGC,
521706f2543Smrg                 int depth, int x, int y, int w, int h,
522706f2543Smrg                 int leftPad, int format, char *pBits)
523706f2543Smrg{
524706f2543Smrg    BoxRec box;
525706f2543Smrg
526706f2543Smrg    GCOP_UNWRAP(pGC);
527706f2543Smrg    RL_DEBUG_MSG("put image start ");
528706f2543Smrg
529706f2543Smrg    RootlessStartDrawing((WindowPtr) dst);
530706f2543Smrg    pGC->ops->PutImage(dst, pGC, depth, x,y,w,h, leftPad, format, pBits);
531706f2543Smrg
532706f2543Smrg    box.x1 = x + dst->x;
533706f2543Smrg    box.x2 = box.x1 + w;
534706f2543Smrg    box.y1 = y + dst->y;
535706f2543Smrg    box.y2 = box.y1 + h;
536706f2543Smrg
537706f2543Smrg    TRIM_BOX(box, pGC);
538706f2543Smrg    if (BOX_NOT_EMPTY(box))
539706f2543Smrg        RootlessDamageBox ((WindowPtr) dst, &box);
540706f2543Smrg
541706f2543Smrg    GCOP_WRAP(pGC);
542706f2543Smrg    RL_DEBUG_MSG("put image end\n");
543706f2543Smrg}
544706f2543Smrg
545706f2543Smrg/* changed area is *dest* rect */
546706f2543Smrgstatic RegionPtr
547706f2543SmrgRootlessCopyArea(DrawablePtr pSrc, DrawablePtr dst, GCPtr pGC,
548706f2543Smrg                 int srcx, int srcy, int w, int h,
549706f2543Smrg                 int dstx, int dsty)
550706f2543Smrg{
551706f2543Smrg    RegionPtr result;
552706f2543Smrg    BoxRec box;
553706f2543Smrg
554706f2543Smrg    GC_SAVE(pGC);
555706f2543Smrg    GCOP_UNWRAP(pGC);
556706f2543Smrg
557706f2543Smrg    RL_DEBUG_MSG("copy area start (src 0x%x, dst 0x%x)", pSrc, dst);
558706f2543Smrg
559706f2543Smrg    if (pSrc->type == DRAWABLE_WINDOW && IsFramedWindow((WindowPtr)pSrc)) {
560706f2543Smrg        /* If both source and dest are windows, and we're doing
561706f2543Smrg           a simple copy operation, we can remove the alpha-protecting
562706f2543Smrg           planemask (since source has opaque alpha as well) */
563706f2543Smrg
564706f2543Smrg        if (canAccelBlit(pSrc, pGC))
565706f2543Smrg        {
566706f2543Smrg            GC_UNSET_PM(pGC, dst);
567706f2543Smrg        }
568706f2543Smrg
569706f2543Smrg        RootlessStartDrawing((WindowPtr) pSrc);
570706f2543Smrg    }
571706f2543Smrg    RootlessStartDrawing((WindowPtr) dst);
572706f2543Smrg    result = pGC->ops->CopyArea(pSrc, dst, pGC, srcx, srcy, w, h, dstx, dsty);
573706f2543Smrg
574706f2543Smrg    box.x1 = dstx + dst->x;
575706f2543Smrg    box.x2 = box.x1 + w;
576706f2543Smrg    box.y1 = dsty + dst->y;
577706f2543Smrg    box.y2 = box.y1 + h;
578706f2543Smrg
579706f2543Smrg    TRIM_BOX(box, pGC);
580706f2543Smrg    if (BOX_NOT_EMPTY(box))
581706f2543Smrg        RootlessDamageBox ((WindowPtr) dst, &box);
582706f2543Smrg
583706f2543Smrg    GC_RESTORE(pGC, dst);
584706f2543Smrg    GCOP_WRAP(pGC);
585706f2543Smrg    RL_DEBUG_MSG("copy area end\n");
586706f2543Smrg    return result;
587706f2543Smrg}
588706f2543Smrg
589706f2543Smrg/* changed area is *dest* rect */
590706f2543Smrgstatic RegionPtr RootlessCopyPlane(DrawablePtr pSrc, DrawablePtr dst,
591706f2543Smrg                                   GCPtr pGC, int srcx, int srcy,
592706f2543Smrg                                   int w, int h, int dstx, int dsty,
593706f2543Smrg                                   unsigned long plane)
594706f2543Smrg{
595706f2543Smrg    RegionPtr result;
596706f2543Smrg    BoxRec box;
597706f2543Smrg
598706f2543Smrg    GCOP_UNWRAP(pGC);
599706f2543Smrg
600706f2543Smrg    RL_DEBUG_MSG("copy plane start ");
601706f2543Smrg
602706f2543Smrg    if (pSrc->type == DRAWABLE_WINDOW && IsFramedWindow((WindowPtr)pSrc)) {
603706f2543Smrg        RootlessStartDrawing((WindowPtr) pSrc);
604706f2543Smrg    }
605706f2543Smrg    RootlessStartDrawing((WindowPtr) dst);
606706f2543Smrg    result = pGC->ops->CopyPlane(pSrc, dst, pGC, srcx, srcy, w, h,
607706f2543Smrg                                 dstx, dsty, plane);
608706f2543Smrg
609706f2543Smrg    box.x1 = dstx + dst->x;
610706f2543Smrg    box.x2 = box.x1 + w;
611706f2543Smrg    box.y1 = dsty + dst->y;
612706f2543Smrg    box.y2 = box.y1 + h;
613706f2543Smrg
614706f2543Smrg    TRIM_BOX(box, pGC);
615706f2543Smrg    if (BOX_NOT_EMPTY(box))
616706f2543Smrg        RootlessDamageBox ((WindowPtr) dst, &box);
617706f2543Smrg
618706f2543Smrg    GCOP_WRAP(pGC);
619706f2543Smrg    RL_DEBUG_MSG("copy plane end\n");
620706f2543Smrg    return result;
621706f2543Smrg}
622706f2543Smrg
623706f2543Smrg// Options for size of changed area:
624706f2543Smrg//  0 = box per point
625706f2543Smrg//  1 = big box around all points
626706f2543Smrg//  2 = accumulate point in 20 pixel radius
627706f2543Smrg#define ROOTLESS_CHANGED_AREA 1
628706f2543Smrg#define abs(a) ((a) > 0 ? (a) : -(a))
629706f2543Smrg
630706f2543Smrg/* changed area is box around all points */
631706f2543Smrgstatic void RootlessPolyPoint(DrawablePtr dst, GCPtr pGC,
632706f2543Smrg                              int mode, int npt, DDXPointPtr pptInit)
633706f2543Smrg{
634706f2543Smrg    GCOP_UNWRAP(pGC);
635706f2543Smrg    RL_DEBUG_MSG("polypoint start ");
636706f2543Smrg
637706f2543Smrg    RootlessStartDrawing((WindowPtr) dst);
638706f2543Smrg    pGC->ops->PolyPoint(dst, pGC, mode, npt, pptInit);
639706f2543Smrg
640706f2543Smrg    if (npt > 0) {
641706f2543Smrg#if ROOTLESS_CHANGED_AREA==0
642706f2543Smrg        // box per point
643706f2543Smrg        BoxRec box;
644706f2543Smrg
645706f2543Smrg        while (npt) {
646706f2543Smrg            box.x1 = pptInit->x;
647706f2543Smrg            box.y1 = pptInit->y;
648706f2543Smrg            box.x2 = box.x1 + 1;
649706f2543Smrg            box.y2 = box.y1 + 1;
650706f2543Smrg
651706f2543Smrg            TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
652706f2543Smrg            if (BOX_NOT_EMPTY(box))
653706f2543Smrg                RootlessDamageBox ((WindowPtr) dst, &box);
654706f2543Smrg
655706f2543Smrg            npt--;
656706f2543Smrg            pptInit++;
657706f2543Smrg        }
658706f2543Smrg
659706f2543Smrg#elif ROOTLESS_CHANGED_AREA==1
660706f2543Smrg        // one big box
661706f2543Smrg        BoxRec box;
662706f2543Smrg
663706f2543Smrg        box.x2 = box.x1 = pptInit->x;
664706f2543Smrg        box.y2 = box.y1 = pptInit->y;
665706f2543Smrg        while (--npt) {
666706f2543Smrg            pptInit++;
667706f2543Smrg            if (box.x1 > pptInit->x)
668706f2543Smrg                box.x1 = pptInit->x;
669706f2543Smrg            else if (box.x2 < pptInit->x)
670706f2543Smrg                box.x2 = pptInit->x;
671706f2543Smrg            if (box.y1 > pptInit->y)
672706f2543Smrg                box.y1 = pptInit->y;
673706f2543Smrg            else if (box.y2 < pptInit->y)
674706f2543Smrg                box.y2 = pptInit->y;
675706f2543Smrg        }
676706f2543Smrg
677706f2543Smrg        box.x2++;
678706f2543Smrg        box.y2++;
679706f2543Smrg
680706f2543Smrg        TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
681706f2543Smrg        if (BOX_NOT_EMPTY(box))
682706f2543Smrg            RootlessDamageBox ((WindowPtr) dst, &box);
683706f2543Smrg
684706f2543Smrg#elif ROOTLESS_CHANGED_AREA==2
685706f2543Smrg        // clever(?) method: accumulate point in 20-pixel radius
686706f2543Smrg        BoxRec box;
687706f2543Smrg        int firstx, firsty;
688706f2543Smrg
689706f2543Smrg        box.x2 = box.x1 = firstx = pptInit->x;
690706f2543Smrg        box.y2 = box.y1 = firsty = pptInit->y;
691706f2543Smrg        while (--npt) {
692706f2543Smrg            pptInit++;
693706f2543Smrg            if (abs(pptInit->x - firstx) > 20 ||
694706f2543Smrg                abs(pptInit->y - firsty) > 20) {
695706f2543Smrg                box.x2++;
696706f2543Smrg                box.y2++;
697706f2543Smrg                TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
698706f2543Smrg                if (BOX_NOT_EMPTY(box))
699706f2543Smrg                    RootlessDamageBox ((WindowPtr) dst, &box);
700706f2543Smrg                box.x2 = box.x1 = firstx = pptInit->x;
701706f2543Smrg                box.y2 = box.y1 = firsty = pptInit->y;
702706f2543Smrg            } else {
703706f2543Smrg                if (box.x1 > pptInit->x) box.x1 = pptInit->x;
704706f2543Smrg                else if (box.x2 < pptInit->x) box.x2 = pptInit->x;
705706f2543Smrg                if (box.y1 > pptInit->y) box.y1 = pptInit->y;
706706f2543Smrg                else if (box.y2 < pptInit->y) box.y2 = pptInit->y;
707706f2543Smrg            }
708706f2543Smrg        }
709706f2543Smrg        box.x2++;
710706f2543Smrg        box.y2++;
711706f2543Smrg        TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
712706f2543Smrg        if (BOX_NOT_EMPTY(box))
713706f2543Smrg            RootlessDamageBox((WindowPtr) dst, &box);
714706f2543Smrg#endif  /* ROOTLESS_CHANGED_AREA */
715706f2543Smrg    }
716706f2543Smrg
717706f2543Smrg    GCOP_WRAP(pGC);
718706f2543Smrg    RL_DEBUG_MSG("polypoint end\n");
719706f2543Smrg}
720706f2543Smrg
721706f2543Smrg#undef ROOTLESS_CHANGED_AREA
722706f2543Smrg
723706f2543Smrg/* changed area is box around each line */
724706f2543Smrgstatic void RootlessPolylines(DrawablePtr dst, GCPtr pGC,
725706f2543Smrg                              int mode, int npt, DDXPointPtr pptInit)
726706f2543Smrg{
727706f2543Smrg    GCOP_UNWRAP(pGC);
728706f2543Smrg    RL_DEBUG_MSG("poly lines start ");
729706f2543Smrg
730706f2543Smrg    RootlessStartDrawing((WindowPtr) dst);
731706f2543Smrg    pGC->ops->Polylines(dst, pGC, mode, npt, pptInit);
732706f2543Smrg
733706f2543Smrg    if (npt > 0) {
734706f2543Smrg        BoxRec box;
735706f2543Smrg        int extra = pGC->lineWidth >> 1;
736706f2543Smrg
737706f2543Smrg        box.x2 = box.x1 = pptInit->x;
738706f2543Smrg        box.y2 = box.y1 = pptInit->y;
739706f2543Smrg
740706f2543Smrg        if (npt > 1) {
741706f2543Smrg            if (pGC->joinStyle == JoinMiter)
742706f2543Smrg                extra = 6 * pGC->lineWidth;
743706f2543Smrg            else if (pGC->capStyle == CapProjecting)
744706f2543Smrg                extra = pGC->lineWidth;
745706f2543Smrg        }
746706f2543Smrg
747706f2543Smrg        if (mode == CoordModePrevious) {
748706f2543Smrg            int x = box.x1;
749706f2543Smrg            int y = box.y1;
750706f2543Smrg
751706f2543Smrg            while (--npt) {
752706f2543Smrg                pptInit++;
753706f2543Smrg                x += pptInit->x;
754706f2543Smrg                y += pptInit->y;
755706f2543Smrg                if (box.x1 > x)
756706f2543Smrg                    box.x1 = x;
757706f2543Smrg                else if (box.x2 < x)
758706f2543Smrg                    box.x2 = x;
759706f2543Smrg                if (box.y1 > y)
760706f2543Smrg                    box.y1 = y;
761706f2543Smrg                else if (box.y2 < y)
762706f2543Smrg                    box.y2 = y;
763706f2543Smrg            }
764706f2543Smrg        } else {
765706f2543Smrg            while (--npt) {
766706f2543Smrg                pptInit++;
767706f2543Smrg                if (box.x1 > pptInit->x)
768706f2543Smrg                    box.x1 = pptInit->x;
769706f2543Smrg                else if (box.x2 < pptInit->x)
770706f2543Smrg                    box.x2 = pptInit->x;
771706f2543Smrg                if (box.y1 > pptInit->y)
772706f2543Smrg                    box.y1 = pptInit->y;
773706f2543Smrg                else if (box.y2 < pptInit->y)
774706f2543Smrg                    box.y2 = pptInit->y;
775706f2543Smrg            }
776706f2543Smrg        }
777706f2543Smrg
778706f2543Smrg        box.x2++;
779706f2543Smrg        box.y2++;
780706f2543Smrg
781706f2543Smrg        if (extra) {
782706f2543Smrg            box.x1 -= extra;
783706f2543Smrg            box.x2 += extra;
784706f2543Smrg            box.y1 -= extra;
785706f2543Smrg            box.y2 += extra;
786706f2543Smrg        }
787706f2543Smrg
788706f2543Smrg        TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
789706f2543Smrg        if (BOX_NOT_EMPTY(box))
790706f2543Smrg            RootlessDamageBox ((WindowPtr) dst, &box);
791706f2543Smrg    }
792706f2543Smrg
793706f2543Smrg    GCOP_WRAP(pGC);
794706f2543Smrg    RL_DEBUG_MSG("poly lines end\n");
795706f2543Smrg}
796706f2543Smrg
797706f2543Smrg/* changed area is box around each line segment */
798706f2543Smrgstatic void RootlessPolySegment(DrawablePtr dst, GCPtr pGC,
799706f2543Smrg                                int nseg, xSegment *pSeg)
800706f2543Smrg{
801706f2543Smrg    GCOP_UNWRAP(pGC);
802706f2543Smrg    RL_DEBUG_MSG("poly segment start (win 0x%x)", dst);
803706f2543Smrg
804706f2543Smrg    RootlessStartDrawing((WindowPtr) dst);
805706f2543Smrg    pGC->ops->PolySegment(dst, pGC, nseg, pSeg);
806706f2543Smrg
807706f2543Smrg    if (nseg > 0) {
808706f2543Smrg        BoxRec box;
809706f2543Smrg        int extra = pGC->lineWidth;
810706f2543Smrg
811706f2543Smrg        if (pGC->capStyle != CapProjecting)
812706f2543Smrg        extra >>= 1;
813706f2543Smrg
814706f2543Smrg        if (pSeg->x2 > pSeg->x1) {
815706f2543Smrg            box.x1 = pSeg->x1;
816706f2543Smrg            box.x2 = pSeg->x2;
817706f2543Smrg        } else {
818706f2543Smrg            box.x2 = pSeg->x1;
819706f2543Smrg            box.x1 = pSeg->x2;
820706f2543Smrg        }
821706f2543Smrg
822706f2543Smrg        if (pSeg->y2 > pSeg->y1) {
823706f2543Smrg            box.y1 = pSeg->y1;
824706f2543Smrg            box.y2 = pSeg->y2;
825706f2543Smrg        } else {
826706f2543Smrg            box.y2 = pSeg->y1;
827706f2543Smrg            box.y1 = pSeg->y2;
828706f2543Smrg        }
829706f2543Smrg
830706f2543Smrg        while (--nseg) {
831706f2543Smrg            pSeg++;
832706f2543Smrg            if (pSeg->x2 > pSeg->x1) {
833706f2543Smrg                if (pSeg->x1 < box.x1) box.x1 = pSeg->x1;
834706f2543Smrg                if (pSeg->x2 > box.x2) box.x2 = pSeg->x2;
835706f2543Smrg            } else {
836706f2543Smrg                if (pSeg->x2 < box.x1) box.x1 = pSeg->x2;
837706f2543Smrg                if (pSeg->x1 > box.x2) box.x2 = pSeg->x1;
838706f2543Smrg            }
839706f2543Smrg            if (pSeg->y2 > pSeg->y1) {
840706f2543Smrg                if (pSeg->y1 < box.y1) box.y1 = pSeg->y1;
841706f2543Smrg                if (pSeg->y2 > box.y2) box.y2 = pSeg->y2;
842706f2543Smrg            } else {
843706f2543Smrg                if (pSeg->y2 < box.y1) box.y1 = pSeg->y2;
844706f2543Smrg                if (pSeg->y1 > box.y2) box.y2 = pSeg->y1;
845706f2543Smrg            }
846706f2543Smrg        }
847706f2543Smrg
848706f2543Smrg        box.x2++;
849706f2543Smrg        box.y2++;
850706f2543Smrg
851706f2543Smrg        if (extra) {
852706f2543Smrg            box.x1 -= extra;
853706f2543Smrg            box.x2 += extra;
854706f2543Smrg            box.y1 -= extra;
855706f2543Smrg            box.y2 += extra;
856706f2543Smrg        }
857706f2543Smrg
858706f2543Smrg        TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
859706f2543Smrg        if (BOX_NOT_EMPTY(box))
860706f2543Smrg            RootlessDamageBox ((WindowPtr) dst, &box);
861706f2543Smrg    }
862706f2543Smrg
863706f2543Smrg    GCOP_WRAP(pGC);
864706f2543Smrg    RL_DEBUG_MSG("poly segment end\n");
865706f2543Smrg}
866706f2543Smrg
867706f2543Smrg/* changed area is box around each line (not entire rects) */
868706f2543Smrgstatic void RootlessPolyRectangle(DrawablePtr dst, GCPtr pGC,
869706f2543Smrg                                  int nRects, xRectangle *pRects)
870706f2543Smrg{
871706f2543Smrg    GCOP_UNWRAP(pGC);
872706f2543Smrg    RL_DEBUG_MSG("poly rectangle start ");
873706f2543Smrg
874706f2543Smrg    RootlessStartDrawing((WindowPtr) dst);
875706f2543Smrg    pGC->ops->PolyRectangle(dst, pGC, nRects, pRects);
876706f2543Smrg
877706f2543Smrg    if (nRects > 0) {
878706f2543Smrg        BoxRec box;
879706f2543Smrg        int offset1, offset2, offset3;
880706f2543Smrg
881706f2543Smrg        offset2 = pGC->lineWidth;
882706f2543Smrg        if (!offset2) offset2 = 1;
883706f2543Smrg        offset1 = offset2 >> 1;
884706f2543Smrg        offset3 = offset2 - offset1;
885706f2543Smrg
886706f2543Smrg        while (nRects--) {
887706f2543Smrg            box.x1 = pRects->x - offset1;
888706f2543Smrg            box.y1 = pRects->y - offset1;
889706f2543Smrg            box.x2 = box.x1 + pRects->width + offset2;
890706f2543Smrg            box.y2 = box.y1 + offset2;
891706f2543Smrg            TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
892706f2543Smrg            if (BOX_NOT_EMPTY(box))
893706f2543Smrg                RootlessDamageBox ((WindowPtr) dst, &box);
894706f2543Smrg
895706f2543Smrg            box.x1 = pRects->x - offset1;
896706f2543Smrg            box.y1 = pRects->y + offset3;
897706f2543Smrg            box.x2 = box.x1 + offset2;
898706f2543Smrg            box.y2 = box.y1 + pRects->height - offset2;
899706f2543Smrg            TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
900706f2543Smrg            if (BOX_NOT_EMPTY(box))
901706f2543Smrg                RootlessDamageBox ((WindowPtr) dst, &box);
902706f2543Smrg
903706f2543Smrg            box.x1 = pRects->x + pRects->width - offset1;
904706f2543Smrg            box.y1 = pRects->y + offset3;
905706f2543Smrg            box.x2 = box.x1 + offset2;
906706f2543Smrg            box.y2 = box.y1 + pRects->height - offset2;
907706f2543Smrg            TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
908706f2543Smrg            if (BOX_NOT_EMPTY(box))
909706f2543Smrg                RootlessDamageBox ((WindowPtr) dst, &box);
910706f2543Smrg
911706f2543Smrg            box.x1 = pRects->x - offset1;
912706f2543Smrg            box.y1 = pRects->y + pRects->height - offset1;
913706f2543Smrg            box.x2 = box.x1 + pRects->width + offset2;
914706f2543Smrg            box.y2 = box.y1 + offset2;
915706f2543Smrg            TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
916706f2543Smrg            if (BOX_NOT_EMPTY(box))
917706f2543Smrg                RootlessDamageBox ((WindowPtr) dst, &box);
918706f2543Smrg
919706f2543Smrg            pRects++;
920706f2543Smrg        }
921706f2543Smrg    }
922706f2543Smrg
923706f2543Smrg    GCOP_WRAP(pGC);
924706f2543Smrg    RL_DEBUG_MSG("poly rectangle end\n");
925706f2543Smrg}
926706f2543Smrg
927706f2543Smrg
928706f2543Smrg/* changed area is box around each arc (assumes all arcs are 360 degrees) */
929706f2543Smrgstatic void RootlessPolyArc(DrawablePtr dst, GCPtr pGC, int narcs, xArc *parcs)
930706f2543Smrg{
931706f2543Smrg    GCOP_UNWRAP(pGC);
932706f2543Smrg    RL_DEBUG_MSG("poly arc start ");
933706f2543Smrg
934706f2543Smrg    RootlessStartDrawing((WindowPtr) dst);
935706f2543Smrg    pGC->ops->PolyArc(dst, pGC, narcs, parcs);
936706f2543Smrg
937706f2543Smrg    if (narcs > 0) {
938706f2543Smrg        int extra = pGC->lineWidth >> 1;
939706f2543Smrg        BoxRec box;
940706f2543Smrg
941706f2543Smrg        box.x1 = parcs->x;
942706f2543Smrg        box.x2 = box.x1 + parcs->width;
943706f2543Smrg        box.y1 = parcs->y;
944706f2543Smrg        box.y2 = box.y1 + parcs->height;
945706f2543Smrg
946706f2543Smrg        /* should I break these up instead ? */
947706f2543Smrg
948706f2543Smrg        while (--narcs) {
949706f2543Smrg            parcs++;
950706f2543Smrg            if (box.x1 > parcs->x)
951706f2543Smrg                box.x1 = parcs->x;
952706f2543Smrg            if (box.x2 < (parcs->x + parcs->width))
953706f2543Smrg                box.x2 = parcs->x + parcs->width;
954706f2543Smrg            if (box.y1 > parcs->y)
955706f2543Smrg                box.y1 = parcs->y;
956706f2543Smrg            if (box.y2 < (parcs->y + parcs->height))
957706f2543Smrg                box.y2 = parcs->y + parcs->height;
958706f2543Smrg        }
959706f2543Smrg
960706f2543Smrg        if (extra) {
961706f2543Smrg            box.x1 -= extra;
962706f2543Smrg            box.x2 += extra;
963706f2543Smrg            box.y1 -= extra;
964706f2543Smrg            box.y2 += extra;
965706f2543Smrg        }
966706f2543Smrg
967706f2543Smrg        box.x2++;
968706f2543Smrg        box.y2++;
969706f2543Smrg
970706f2543Smrg        TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
971706f2543Smrg        if (BOX_NOT_EMPTY(box))
972706f2543Smrg            RootlessDamageBox ((WindowPtr) dst, &box);
973706f2543Smrg    }
974706f2543Smrg
975706f2543Smrg    GCOP_WRAP(pGC);
976706f2543Smrg    RL_DEBUG_MSG("poly arc end\n");
977706f2543Smrg}
978706f2543Smrg
979706f2543Smrg
980706f2543Smrg/* changed area is box around each poly */
981706f2543Smrgstatic void RootlessFillPolygon(DrawablePtr dst, GCPtr pGC,
982706f2543Smrg                                int shape, int mode, int count,
983706f2543Smrg                                DDXPointPtr pptInit)
984706f2543Smrg{
985706f2543Smrg    GC_SAVE(pGC);
986706f2543Smrg    GCOP_UNWRAP(pGC);
987706f2543Smrg    RL_DEBUG_MSG("fill poly start (win 0x%x, fillStyle 0x%x)", dst,
988706f2543Smrg                 pGC->fillStyle);
989706f2543Smrg
990706f2543Smrg    if (count <= 2) {
991706f2543Smrg        pGC->ops->FillPolygon(dst, pGC, shape, mode, count, pptInit);
992706f2543Smrg    } else {
993706f2543Smrg        DDXPointPtr ppt = pptInit;
994706f2543Smrg        int i = count;
995706f2543Smrg        BoxRec box;
996706f2543Smrg
997706f2543Smrg        box.x2 = box.x1 = ppt->x;
998706f2543Smrg        box.y2 = box.y1 = ppt->y;
999706f2543Smrg
1000706f2543Smrg        if (mode != CoordModeOrigin) {
1001706f2543Smrg            int x = box.x1;
1002706f2543Smrg            int y = box.y1;
1003706f2543Smrg
1004706f2543Smrg            while (--i) {
1005706f2543Smrg                ppt++;
1006706f2543Smrg                x += ppt->x;
1007706f2543Smrg                y += ppt->y;
1008706f2543Smrg                if (box.x1 > x)
1009706f2543Smrg                    box.x1 = x;
1010706f2543Smrg                else if (box.x2 < x)
1011706f2543Smrg                    box.x2 = x;
1012706f2543Smrg                if (box.y1 > y)
1013706f2543Smrg                    box.y1 = y;
1014706f2543Smrg                else if (box.y2 < y)
1015706f2543Smrg                    box.y2 = y;
1016706f2543Smrg            }
1017706f2543Smrg        } else {
1018706f2543Smrg            while (--i) {
1019706f2543Smrg                ppt++;
1020706f2543Smrg                if (box.x1 > ppt->x)
1021706f2543Smrg                    box.x1 = ppt->x;
1022706f2543Smrg                else if (box.x2 < ppt->x)
1023706f2543Smrg                    box.x2 = ppt->x;
1024706f2543Smrg                if (box.y1 > ppt->y)
1025706f2543Smrg                    box.y1 = ppt->y;
1026706f2543Smrg                else if (box.y2 < ppt->y)
1027706f2543Smrg                    box.y2 = ppt->y;
1028706f2543Smrg            }
1029706f2543Smrg        }
1030706f2543Smrg
1031706f2543Smrg        box.x2++;
1032706f2543Smrg        box.y2++;
1033706f2543Smrg
1034706f2543Smrg        RootlessStartDrawing((WindowPtr) dst);
1035706f2543Smrg
1036706f2543Smrg        if (canAccelFill(dst, pGC))
1037706f2543Smrg        {
1038706f2543Smrg            GC_UNSET_PM(pGC, dst);
1039706f2543Smrg        }
1040706f2543Smrg
1041706f2543Smrg        pGC->ops->FillPolygon(dst, pGC, shape, mode, count, pptInit);
1042706f2543Smrg
1043706f2543Smrg        TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
1044706f2543Smrg        if (BOX_NOT_EMPTY(box))
1045706f2543Smrg            RootlessDamageBox ((WindowPtr) dst, &box);
1046706f2543Smrg    }
1047706f2543Smrg
1048706f2543Smrg    GC_RESTORE(pGC, dst);
1049706f2543Smrg    GCOP_WRAP(pGC);
1050706f2543Smrg    RL_DEBUG_MSG("fill poly end\n");
1051706f2543Smrg}
1052706f2543Smrg
1053706f2543Smrg/* changed area is the rects */
1054706f2543Smrgstatic void RootlessPolyFillRect(DrawablePtr dst, GCPtr pGC,
1055706f2543Smrg                                 int nRectsInit, xRectangle *pRectsInit)
1056706f2543Smrg{
1057706f2543Smrg    GC_SAVE(pGC);
1058706f2543Smrg    GCOP_UNWRAP(pGC);
1059706f2543Smrg    RL_DEBUG_MSG("fill rect start (win 0x%x, fillStyle 0x%x)", dst,
1060706f2543Smrg                 pGC->fillStyle);
1061706f2543Smrg
1062706f2543Smrg    if (nRectsInit <= 0) {
1063706f2543Smrg        pGC->ops->PolyFillRect(dst, pGC, nRectsInit, pRectsInit);
1064706f2543Smrg    } else {
1065706f2543Smrg        BoxRec box;
1066706f2543Smrg        xRectangle *pRects = pRectsInit;
1067706f2543Smrg        int nRects = nRectsInit;
1068706f2543Smrg
1069706f2543Smrg        box.x1 = pRects->x;
1070706f2543Smrg        box.x2 = box.x1 + pRects->width;
1071706f2543Smrg        box.y1 = pRects->y;
1072706f2543Smrg        box.y2 = box.y1 + pRects->height;
1073706f2543Smrg
1074706f2543Smrg        while (--nRects) {
1075706f2543Smrg            pRects++;
1076706f2543Smrg            if (box.x1 > pRects->x)
1077706f2543Smrg                box.x1 = pRects->x;
1078706f2543Smrg            if (box.x2 < (pRects->x + pRects->width))
1079706f2543Smrg                box.x2 = pRects->x + pRects->width;
1080706f2543Smrg            if (box.y1 > pRects->y)
1081706f2543Smrg                box.y1 = pRects->y;
1082706f2543Smrg            if (box.y2 < (pRects->y + pRects->height))
1083706f2543Smrg                box.y2 = pRects->y + pRects->height;
1084706f2543Smrg        }
1085706f2543Smrg
1086706f2543Smrg        RootlessStartDrawing((WindowPtr) dst);
1087706f2543Smrg
1088706f2543Smrg        if (canAccelFill(dst, pGC))
1089706f2543Smrg        {
1090706f2543Smrg            GC_UNSET_PM(pGC, dst);
1091706f2543Smrg        }
1092706f2543Smrg
1093706f2543Smrg       pGC->ops->PolyFillRect(dst, pGC, nRectsInit, pRectsInit);
1094706f2543Smrg
1095706f2543Smrg        TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
1096706f2543Smrg        if (BOX_NOT_EMPTY(box))
1097706f2543Smrg            RootlessDamageBox ((WindowPtr) dst, &box);
1098706f2543Smrg    }
1099706f2543Smrg
1100706f2543Smrg    GC_RESTORE(pGC, dst);
1101706f2543Smrg    GCOP_WRAP(pGC);
1102706f2543Smrg    RL_DEBUG_MSG("fill rect end\n");
1103706f2543Smrg}
1104706f2543Smrg
1105706f2543Smrg
1106706f2543Smrg/* changed area is box around each arc (assuming arcs are all 360 degrees) */
1107706f2543Smrgstatic void RootlessPolyFillArc(DrawablePtr dst, GCPtr pGC,
1108706f2543Smrg                                int narcsInit, xArc *parcsInit)
1109706f2543Smrg{
1110706f2543Smrg    GC_SAVE(pGC);
1111706f2543Smrg    GCOP_UNWRAP(pGC);
1112706f2543Smrg    RL_DEBUG_MSG("fill arc start ");
1113706f2543Smrg
1114706f2543Smrg    if (narcsInit > 0) {
1115706f2543Smrg        BoxRec box;
1116706f2543Smrg        int narcs = narcsInit;
1117706f2543Smrg        xArc *parcs = parcsInit;
1118706f2543Smrg
1119706f2543Smrg        box.x1 = parcs->x;
1120706f2543Smrg        box.x2 = box.x1 + parcs->width;
1121706f2543Smrg        box.y1 = parcs->y;
1122706f2543Smrg        box.y2 = box.y1 + parcs->height;
1123706f2543Smrg
1124706f2543Smrg        /* should I break these up instead ? */
1125706f2543Smrg
1126706f2543Smrg        while (--narcs) {
1127706f2543Smrg            parcs++;
1128706f2543Smrg            if (box.x1 > parcs->x)
1129706f2543Smrg                box.x1 = parcs->x;
1130706f2543Smrg            if (box.x2 < (parcs->x + parcs->width))
1131706f2543Smrg                box.x2 = parcs->x + parcs->width;
1132706f2543Smrg            if (box.y1 > parcs->y)
1133706f2543Smrg                box.y1 = parcs->y;
1134706f2543Smrg            if (box.y2 < (parcs->y + parcs->height))
1135706f2543Smrg                box.y2 = parcs->y + parcs->height;
1136706f2543Smrg        }
1137706f2543Smrg
1138706f2543Smrg        RootlessStartDrawing((WindowPtr) dst);
1139706f2543Smrg
1140706f2543Smrg        if (canAccelFill(dst, pGC))
1141706f2543Smrg        {
1142706f2543Smrg            GC_UNSET_PM(pGC, dst);
1143706f2543Smrg        }
1144706f2543Smrg
1145706f2543Smrg        pGC->ops->PolyFillArc(dst, pGC, narcsInit, parcsInit);
1146706f2543Smrg
1147706f2543Smrg        TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
1148706f2543Smrg        if (BOX_NOT_EMPTY(box))
1149706f2543Smrg            RootlessDamageBox ((WindowPtr) dst, &box);
1150706f2543Smrg    } else {
1151706f2543Smrg        pGC->ops->PolyFillArc(dst, pGC, narcsInit, parcsInit);
1152706f2543Smrg    }
1153706f2543Smrg
1154706f2543Smrg    GC_RESTORE(pGC, dst);
1155706f2543Smrg    GCOP_WRAP(pGC);
1156706f2543Smrg    RL_DEBUG_MSG("fill arc end\n");
1157706f2543Smrg}
1158706f2543Smrg
1159706f2543Smrg
1160706f2543Smrgstatic void RootlessImageText8(DrawablePtr dst, GCPtr pGC,
1161706f2543Smrg                               int x, int y, int count, char *chars)
1162706f2543Smrg{
1163706f2543Smrg    GC_SAVE(pGC);
1164706f2543Smrg    GCOP_UNWRAP(pGC);
1165706f2543Smrg    RL_DEBUG_MSG("imagetext8 start ");
1166706f2543Smrg
1167706f2543Smrg    if (count > 0) {
1168706f2543Smrg        int top, bot, Min, Max;
1169706f2543Smrg        BoxRec box;
1170706f2543Smrg
1171706f2543Smrg        top = max(FONTMAXBOUNDS(pGC->font, ascent), FONTASCENT(pGC->font));
1172706f2543Smrg        bot = max(FONTMAXBOUNDS(pGC->font, descent), FONTDESCENT(pGC->font));
1173706f2543Smrg
1174706f2543Smrg        Min = count * FONTMINBOUNDS(pGC->font, characterWidth);
1175706f2543Smrg        if (Min > 0) Min = 0;
1176706f2543Smrg        Max = count * FONTMAXBOUNDS(pGC->font, characterWidth);
1177706f2543Smrg        if (Max < 0) Max = 0;
1178706f2543Smrg
1179706f2543Smrg        /* ugh */
1180706f2543Smrg        box.x1 = dst->x + x + Min +
1181706f2543Smrg        FONTMINBOUNDS(pGC->font, leftSideBearing);
1182706f2543Smrg        box.x2 = dst->x + x + Max +
1183706f2543Smrg        FONTMAXBOUNDS(pGC->font, rightSideBearing);
1184706f2543Smrg
1185706f2543Smrg        box.y1 = dst->y + y - top;
1186706f2543Smrg        box.y2 = dst->y + y + bot;
1187706f2543Smrg
1188706f2543Smrg        RootlessStartDrawing((WindowPtr) dst);
1189706f2543Smrg
1190706f2543Smrg        if (canAccelFill(dst, pGC))
1191706f2543Smrg        {
1192706f2543Smrg            GC_UNSET_PM(pGC, dst);
1193706f2543Smrg        }
1194706f2543Smrg
1195706f2543Smrg        pGC->ops->ImageText8(dst, pGC, x, y, count, chars);
1196706f2543Smrg
1197706f2543Smrg        TRIM_BOX(box, pGC);
1198706f2543Smrg        if (BOX_NOT_EMPTY(box))
1199706f2543Smrg            RootlessDamageBox ((WindowPtr) dst, &box);
1200706f2543Smrg    } else {
1201706f2543Smrg        pGC->ops->ImageText8(dst, pGC, x, y, count, chars);
1202706f2543Smrg    }
1203706f2543Smrg
1204706f2543Smrg    GC_RESTORE(pGC, dst);
1205706f2543Smrg    GCOP_WRAP(pGC);
1206706f2543Smrg    RL_DEBUG_MSG("imagetext8 end\n");
1207706f2543Smrg}
1208706f2543Smrg
1209706f2543Smrgstatic int RootlessPolyText8(DrawablePtr dst, GCPtr pGC,
1210706f2543Smrg                             int x, int y, int count, char *chars)
1211706f2543Smrg{
1212706f2543Smrg    int width; // the result, sorta
1213706f2543Smrg
1214706f2543Smrg    GCOP_UNWRAP(pGC);
1215706f2543Smrg
1216706f2543Smrg    RL_DEBUG_MSG("polytext8 start ");
1217706f2543Smrg
1218706f2543Smrg    RootlessStartDrawing((WindowPtr) dst);
1219706f2543Smrg    width = pGC->ops->PolyText8(dst, pGC, x, y, count, chars);
1220706f2543Smrg    width -= x;
1221706f2543Smrg
1222706f2543Smrg    if (width > 0) {
1223706f2543Smrg        BoxRec box;
1224706f2543Smrg
1225706f2543Smrg        /* ugh */
1226706f2543Smrg        box.x1 = dst->x + x + FONTMINBOUNDS(pGC->font, leftSideBearing);
1227706f2543Smrg        box.x2 = dst->x + x + FONTMAXBOUNDS(pGC->font, rightSideBearing);
1228706f2543Smrg
1229706f2543Smrg        if (count > 1) {
1230706f2543Smrg            if (width > 0) box.x2 += width;
1231706f2543Smrg            else box.x1 += width;
1232706f2543Smrg        }
1233706f2543Smrg
1234706f2543Smrg        box.y1 = dst->y + y - FONTMAXBOUNDS(pGC->font, ascent);
1235706f2543Smrg        box.y2 = dst->y + y + FONTMAXBOUNDS(pGC->font, descent);
1236706f2543Smrg
1237706f2543Smrg        TRIM_BOX(box, pGC);
1238706f2543Smrg        if (BOX_NOT_EMPTY(box))
1239706f2543Smrg            RootlessDamageBox ((WindowPtr) dst, &box);
1240706f2543Smrg    }
1241706f2543Smrg
1242706f2543Smrg    GCOP_WRAP(pGC);
1243706f2543Smrg    RL_DEBUG_MSG("polytext8 end\n");
1244706f2543Smrg    return width + x;
1245706f2543Smrg}
1246706f2543Smrg
1247706f2543Smrgstatic void RootlessImageText16(DrawablePtr dst, GCPtr pGC,
1248706f2543Smrg                                int x, int y, int count, unsigned short *chars)
1249706f2543Smrg{
1250706f2543Smrg    GC_SAVE(pGC);
1251706f2543Smrg    GCOP_UNWRAP(pGC);
1252706f2543Smrg    RL_DEBUG_MSG("imagetext16 start ");
1253706f2543Smrg
1254706f2543Smrg    if (count > 0) {
1255706f2543Smrg        int top, bot, Min, Max;
1256706f2543Smrg        BoxRec box;
1257706f2543Smrg
1258706f2543Smrg        top = max(FONTMAXBOUNDS(pGC->font, ascent), FONTASCENT(pGC->font));
1259706f2543Smrg        bot = max(FONTMAXBOUNDS(pGC->font, descent), FONTDESCENT(pGC->font));
1260706f2543Smrg
1261706f2543Smrg        Min = count * FONTMINBOUNDS(pGC->font, characterWidth);
1262706f2543Smrg        if (Min > 0) Min = 0;
1263706f2543Smrg        Max = count * FONTMAXBOUNDS(pGC->font, characterWidth);
1264706f2543Smrg        if (Max < 0) Max = 0;
1265706f2543Smrg
1266706f2543Smrg        /* ugh */
1267706f2543Smrg        box.x1 = dst->x + x + Min +
1268706f2543Smrg            FONTMINBOUNDS(pGC->font, leftSideBearing);
1269706f2543Smrg        box.x2 = dst->x + x + Max +
1270706f2543Smrg            FONTMAXBOUNDS(pGC->font, rightSideBearing);
1271706f2543Smrg
1272706f2543Smrg        box.y1 = dst->y + y - top;
1273706f2543Smrg        box.y2 = dst->y + y + bot;
1274706f2543Smrg
1275706f2543Smrg        RootlessStartDrawing((WindowPtr) dst);
1276706f2543Smrg
1277706f2543Smrg        if (canAccelFill(dst, pGC))
1278706f2543Smrg        {
1279706f2543Smrg            GC_UNSET_PM(pGC, dst);
1280706f2543Smrg        }
1281706f2543Smrg
1282706f2543Smrg        pGC->ops->ImageText16(dst, pGC, x, y, count, chars);
1283706f2543Smrg
1284706f2543Smrg        TRIM_BOX(box, pGC);
1285706f2543Smrg        if (BOX_NOT_EMPTY(box))
1286706f2543Smrg            RootlessDamageBox ((WindowPtr) dst, &box);
1287706f2543Smrg    } else {
1288706f2543Smrg        pGC->ops->ImageText16(dst, pGC, x, y, count, chars);
1289706f2543Smrg    }
1290706f2543Smrg
1291706f2543Smrg    GC_RESTORE(pGC, dst);
1292706f2543Smrg    GCOP_WRAP(pGC);
1293706f2543Smrg    RL_DEBUG_MSG("imagetext16 end\n");
1294706f2543Smrg}
1295706f2543Smrg
1296706f2543Smrgstatic int RootlessPolyText16(DrawablePtr dst, GCPtr pGC,
1297706f2543Smrg                            int x, int y, int count, unsigned short *chars)
1298706f2543Smrg{
1299706f2543Smrg    int width; // the result, sorta
1300706f2543Smrg
1301706f2543Smrg    GCOP_UNWRAP(pGC);
1302706f2543Smrg
1303706f2543Smrg    RL_DEBUG_MSG("polytext16 start ");
1304706f2543Smrg
1305706f2543Smrg    RootlessStartDrawing((WindowPtr) dst);
1306706f2543Smrg    width = pGC->ops->PolyText16(dst, pGC, x, y, count, chars);
1307706f2543Smrg    width -= x;
1308706f2543Smrg
1309706f2543Smrg    if (width > 0) {
1310706f2543Smrg        BoxRec box;
1311706f2543Smrg
1312706f2543Smrg        /* ugh */
1313706f2543Smrg        box.x1 = dst->x + x + FONTMINBOUNDS(pGC->font, leftSideBearing);
1314706f2543Smrg        box.x2 = dst->x + x + FONTMAXBOUNDS(pGC->font, rightSideBearing);
1315706f2543Smrg
1316706f2543Smrg        if (count > 1) {
1317706f2543Smrg            if (width > 0) box.x2 += width;
1318706f2543Smrg            else box.x1 += width;
1319706f2543Smrg        }
1320706f2543Smrg
1321706f2543Smrg        box.y1 = dst->y + y - FONTMAXBOUNDS(pGC->font, ascent);
1322706f2543Smrg        box.y2 = dst->y + y + FONTMAXBOUNDS(pGC->font, descent);
1323706f2543Smrg
1324706f2543Smrg        TRIM_BOX(box, pGC);
1325706f2543Smrg        if (BOX_NOT_EMPTY(box))
1326706f2543Smrg            RootlessDamageBox ((WindowPtr) dst, &box);
1327706f2543Smrg    }
1328706f2543Smrg
1329706f2543Smrg    GCOP_WRAP(pGC);
1330706f2543Smrg    RL_DEBUG_MSG("polytext16 end\n");
1331706f2543Smrg    return width + x;
1332706f2543Smrg}
1333706f2543Smrg
1334706f2543Smrgstatic void RootlessImageGlyphBlt(DrawablePtr dst, GCPtr pGC,
1335706f2543Smrg                                  int x, int y, unsigned int nglyphInit,
1336706f2543Smrg                                  CharInfoPtr *ppciInit, pointer unused)
1337706f2543Smrg{
1338706f2543Smrg    GC_SAVE(pGC);
1339706f2543Smrg    GCOP_UNWRAP(pGC);
1340706f2543Smrg    RL_DEBUG_MSG("imageglyph start ");
1341706f2543Smrg
1342706f2543Smrg    if (nglyphInit > 0) {
1343706f2543Smrg        int top, bot, width = 0;
1344706f2543Smrg        BoxRec box;
1345706f2543Smrg        unsigned int nglyph = nglyphInit;
1346706f2543Smrg        CharInfoPtr *ppci = ppciInit;
1347706f2543Smrg
1348706f2543Smrg        top = max(FONTMAXBOUNDS(pGC->font, ascent), FONTASCENT(pGC->font));
1349706f2543Smrg        bot = max(FONTMAXBOUNDS(pGC->font, descent), FONTDESCENT(pGC->font));
1350706f2543Smrg
1351706f2543Smrg        box.x1 = ppci[0]->metrics.leftSideBearing;
1352706f2543Smrg        if (box.x1 > 0) box.x1 = 0;
1353706f2543Smrg        box.x2 = ppci[nglyph - 1]->metrics.rightSideBearing -
1354706f2543Smrg            ppci[nglyph - 1]->metrics.characterWidth;
1355706f2543Smrg        if (box.x2 < 0) box.x2 = 0;
1356706f2543Smrg
1357706f2543Smrg        box.x2 += dst->x + x;
1358706f2543Smrg        box.x1 += dst->x + x;
1359706f2543Smrg
1360706f2543Smrg        while (nglyph--) {
1361706f2543Smrg            width += (*ppci)->metrics.characterWidth;
1362706f2543Smrg            ppci++;
1363706f2543Smrg        }
1364706f2543Smrg
1365706f2543Smrg        if (width > 0)
1366706f2543Smrg            box.x2 += width;
1367706f2543Smrg        else
1368706f2543Smrg            box.x1 += width;
1369706f2543Smrg
1370706f2543Smrg        box.y1 = dst->y + y - top;
1371706f2543Smrg        box.y2 = dst->y + y + bot;
1372706f2543Smrg
1373706f2543Smrg        RootlessStartDrawing((WindowPtr) dst);
1374706f2543Smrg
1375706f2543Smrg        if (canAccelFill(dst, pGC))
1376706f2543Smrg        {
1377706f2543Smrg            GC_UNSET_PM(pGC, dst);
1378706f2543Smrg        }
1379706f2543Smrg
1380706f2543Smrg        pGC->ops->ImageGlyphBlt(dst, pGC, x, y, nglyphInit, ppciInit, unused);
1381706f2543Smrg
1382706f2543Smrg        TRIM_BOX(box, pGC);
1383706f2543Smrg        if (BOX_NOT_EMPTY(box))
1384706f2543Smrg            RootlessDamageBox ((WindowPtr) dst, &box);
1385706f2543Smrg    } else {
1386706f2543Smrg        pGC->ops->ImageGlyphBlt(dst, pGC, x, y, nglyphInit, ppciInit, unused);
1387706f2543Smrg    }
1388706f2543Smrg
1389706f2543Smrg    GC_RESTORE(pGC, dst);
1390706f2543Smrg    GCOP_WRAP(pGC);
1391706f2543Smrg    RL_DEBUG_MSG("imageglyph end\n");
1392706f2543Smrg}
1393706f2543Smrg
1394706f2543Smrgstatic void RootlessPolyGlyphBlt(DrawablePtr dst, GCPtr pGC,
1395706f2543Smrg                                 int x, int y, unsigned int nglyph,
1396706f2543Smrg                                 CharInfoPtr *ppci, pointer pglyphBase)
1397706f2543Smrg{
1398706f2543Smrg    GCOP_UNWRAP(pGC);
1399706f2543Smrg    RL_DEBUG_MSG("polyglyph start ");
1400706f2543Smrg
1401706f2543Smrg    RootlessStartDrawing((WindowPtr) dst);
1402706f2543Smrg    pGC->ops->PolyGlyphBlt(dst, pGC, x, y, nglyph, ppci, pglyphBase);
1403706f2543Smrg
1404706f2543Smrg    if (nglyph > 0) {
1405706f2543Smrg        BoxRec box;
1406706f2543Smrg
1407706f2543Smrg        /* ugh */
1408706f2543Smrg        box.x1 = dst->x + x + ppci[0]->metrics.leftSideBearing;
1409706f2543Smrg        box.x2 = dst->x + x + ppci[nglyph - 1]->metrics.rightSideBearing;
1410706f2543Smrg
1411706f2543Smrg        if (nglyph > 1) {
1412706f2543Smrg            int width = 0;
1413706f2543Smrg
1414706f2543Smrg            while (--nglyph) {
1415706f2543Smrg                width += (*ppci)->metrics.characterWidth;
1416706f2543Smrg                ppci++;
1417706f2543Smrg            }
1418706f2543Smrg
1419706f2543Smrg            if (width > 0) box.x2 += width;
1420706f2543Smrg            else box.x1 += width;
1421706f2543Smrg        }
1422706f2543Smrg
1423706f2543Smrg        box.y1 = dst->y + y - FONTMAXBOUNDS(pGC->font, ascent);
1424706f2543Smrg        box.y2 = dst->y + y + FONTMAXBOUNDS(pGC->font, descent);
1425706f2543Smrg
1426706f2543Smrg        TRIM_BOX(box, pGC);
1427706f2543Smrg        if (BOX_NOT_EMPTY(box))
1428706f2543Smrg            RootlessDamageBox ((WindowPtr) dst, &box);
1429706f2543Smrg    }
1430706f2543Smrg
1431706f2543Smrg    GCOP_WRAP(pGC);
1432706f2543Smrg    RL_DEBUG_MSG("polyglyph end\n");
1433706f2543Smrg}
1434706f2543Smrg
1435706f2543Smrg
1436706f2543Smrg/* changed area is in dest */
1437706f2543Smrgstatic void
1438706f2543SmrgRootlessPushPixels(GCPtr pGC, PixmapPtr pBitMap, DrawablePtr dst,
1439706f2543Smrg                   int dx, int dy, int xOrg, int yOrg)
1440706f2543Smrg{
1441706f2543Smrg    BoxRec box;
1442706f2543Smrg
1443706f2543Smrg    GCOP_UNWRAP(pGC);
1444706f2543Smrg    RL_DEBUG_MSG("push pixels start ");
1445706f2543Smrg
1446706f2543Smrg    RootlessStartDrawing((WindowPtr) dst);
1447706f2543Smrg    pGC->ops->PushPixels(pGC, pBitMap, dst, dx, dy, xOrg, yOrg);
1448706f2543Smrg
1449706f2543Smrg    box.x1 = xOrg + dst->x;
1450706f2543Smrg    box.x2 = box.x1 + dx;
1451706f2543Smrg    box.y1 = yOrg + dst->y;
1452706f2543Smrg    box.y2 = box.y1 + dy;
1453706f2543Smrg
1454706f2543Smrg    TRIM_BOX(box, pGC);
1455706f2543Smrg    if (BOX_NOT_EMPTY(box))
1456706f2543Smrg        RootlessDamageBox ((WindowPtr) dst, &box);
1457706f2543Smrg
1458706f2543Smrg    GCOP_WRAP(pGC);
1459706f2543Smrg    RL_DEBUG_MSG("push pixels end\n");
1460706f2543Smrg}
1461