105b261ecSmrg/*
205b261ecSmrg * Graphics Context support for generic rootless X server
305b261ecSmrg */
405b261ecSmrg/*
505b261ecSmrg * Copyright (c) 2001 Greg Parker. All Rights Reserved.
605b261ecSmrg * Copyright (c) 2002-2003 Torrey T. Lyons. All Rights Reserved.
705b261ecSmrg * Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
805b261ecSmrg *
905b261ecSmrg * Permission is hereby granted, free of charge, to any person obtaining a
1005b261ecSmrg * copy of this software and associated documentation files (the "Software"),
1105b261ecSmrg * to deal in the Software without restriction, including without limitation
1205b261ecSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
1305b261ecSmrg * and/or sell copies of the Software, and to permit persons to whom the
1405b261ecSmrg * Software is furnished to do so, subject to the following conditions:
1505b261ecSmrg *
1605b261ecSmrg * The above copyright notice and this permission notice shall be included in
1705b261ecSmrg * all copies or substantial portions of the Software.
1805b261ecSmrg *
1905b261ecSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2005b261ecSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2105b261ecSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
2205b261ecSmrg * THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
2305b261ecSmrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
2405b261ecSmrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
2505b261ecSmrg * DEALINGS IN THE SOFTWARE.
2605b261ecSmrg *
2705b261ecSmrg * Except as contained in this notice, the name(s) of the above copyright
2805b261ecSmrg * holders shall not be used in advertising or otherwise to promote the sale,
2905b261ecSmrg * use or other dealings in this Software without prior written authorization.
3005b261ecSmrg */
3105b261ecSmrg
3205b261ecSmrg#ifdef HAVE_DIX_CONFIG_H
3305b261ecSmrg#include <dix-config.h>
3405b261ecSmrg#endif
3505b261ecSmrg
3635c4bbdfSmrg#include <stddef.h>             /* For NULL */
3705b261ecSmrg#include "mi.h"
3805b261ecSmrg#include "scrnintstr.h"
3905b261ecSmrg#include "gcstruct.h"
4005b261ecSmrg#include "pixmapstr.h"
4105b261ecSmrg#include "windowstr.h"
4205b261ecSmrg#include "dixfontstr.h"
4305b261ecSmrg#include "mivalidate.h"
4405b261ecSmrg#include "fb.h"
4505b261ecSmrg
4605b261ecSmrg#include <sys/types.h>
4705b261ecSmrg#include <sys/stat.h>
4805b261ecSmrg#include <fcntl.h>
4905b261ecSmrg
5005b261ecSmrg#include "rootlessCommon.h"
5105b261ecSmrg
5205b261ecSmrg// GC functions
5305b261ecSmrgstatic void RootlessValidateGC(GCPtr pGC, unsigned long changes,
5405b261ecSmrg                               DrawablePtr pDrawable);
5505b261ecSmrgstatic void RootlessChangeGC(GCPtr pGC, unsigned long mask);
5605b261ecSmrgstatic void RootlessCopyGC(GCPtr pGCSrc, unsigned long mask, GCPtr pGCDst);
5705b261ecSmrgstatic void RootlessDestroyGC(GCPtr pGC);
5835c4bbdfSmrgstatic void RootlessChangeClip(GCPtr pGC, int type, void *pvalue, int nrects);
5905b261ecSmrgstatic void RootlessDestroyClip(GCPtr pGC);
6005b261ecSmrgstatic void RootlessCopyClip(GCPtr pgcDst, GCPtr pgcSrc);
6105b261ecSmrg
624642e01fSmrgBool RootlessCreateGC(GCPtr pGC);
634642e01fSmrg
6405b261ecSmrgGCFuncs rootlessGCFuncs = {
6505b261ecSmrg    RootlessValidateGC,
6605b261ecSmrg    RootlessChangeGC,
6705b261ecSmrg    RootlessCopyGC,
6805b261ecSmrg    RootlessDestroyGC,
6905b261ecSmrg    RootlessChangeClip,
7005b261ecSmrg    RootlessDestroyClip,
7105b261ecSmrg    RootlessCopyClip,
7205b261ecSmrg};
7305b261ecSmrg
7405b261ecSmrg// GC operations
754642e01fSmrgstatic void RootlessFillSpans(DrawablePtr dst, GCPtr pGC, int nInit,
7635c4bbdfSmrg                              DDXPointPtr pptInit, int *pwidthInit, int sorted);
774642e01fSmrgstatic void RootlessSetSpans(DrawablePtr dst, GCPtr pGC, char *pSrc,
7835c4bbdfSmrg                             DDXPointPtr pptInit, int *pwidthInit,
7935c4bbdfSmrg                             int nspans, int sorted);
804642e01fSmrgstatic void RootlessPutImage(DrawablePtr dst, GCPtr pGC,
8135c4bbdfSmrg                             int depth, int x, int y, int w, int h,
8235c4bbdfSmrg                             int leftPad, int format, char *pBits);
834642e01fSmrgstatic RegionPtr RootlessCopyArea(DrawablePtr pSrc, DrawablePtr dst, GCPtr pGC,
8435c4bbdfSmrg                                  int srcx, int srcy, int w, int h,
8535c4bbdfSmrg                                  int dstx, int dsty);
864642e01fSmrgstatic RegionPtr RootlessCopyPlane(DrawablePtr pSrc, DrawablePtr dst,
874642e01fSmrg                                   GCPtr pGC, int srcx, int srcy,
884642e01fSmrg                                   int w, int h, int dstx, int dsty,
894642e01fSmrg                                   unsigned long plane);
904642e01fSmrgstatic void RootlessPolyPoint(DrawablePtr dst, GCPtr pGC,
914642e01fSmrg                              int mode, int npt, DDXPointPtr pptInit);
924642e01fSmrgstatic void RootlessPolylines(DrawablePtr dst, GCPtr pGC,
934642e01fSmrg                              int mode, int npt, DDXPointPtr pptInit);
944642e01fSmrgstatic void RootlessPolySegment(DrawablePtr dst, GCPtr pGC,
9535c4bbdfSmrg                                int nseg, xSegment * pSeg);
964642e01fSmrgstatic void RootlessPolyRectangle(DrawablePtr dst, GCPtr pGC,
974642e01fSmrg                                  int nRects, xRectangle *pRects);
9835c4bbdfSmrgstatic void RootlessPolyArc(DrawablePtr dst, GCPtr pGC, int narcs,
9935c4bbdfSmrg                            xArc * parcs);
10035c4bbdfSmrgstatic void RootlessFillPolygon(DrawablePtr dst, GCPtr pGC, int shape, int mode,
10135c4bbdfSmrg                                int count, DDXPointPtr pptInit);
10235c4bbdfSmrgstatic void RootlessPolyFillRect(DrawablePtr dst, GCPtr pGC, int nRectsInit,
10335c4bbdfSmrg                                 xRectangle *pRectsInit);
10435c4bbdfSmrgstatic void RootlessPolyFillArc(DrawablePtr dst, GCPtr pGC, int narcsInit,
10535c4bbdfSmrg                                xArc * parcsInit);
10635c4bbdfSmrgstatic int RootlessPolyText8(DrawablePtr dst, GCPtr pGC, int x, int y,
10735c4bbdfSmrg                             int count, char *chars);
10835c4bbdfSmrgstatic int RootlessPolyText16(DrawablePtr dst, GCPtr pGC, int x, int y,
10935c4bbdfSmrg                              int count, unsigned short *chars);
11035c4bbdfSmrgstatic void RootlessImageText8(DrawablePtr dst, GCPtr pGC, int x, int y,
11135c4bbdfSmrg                               int count, char *chars);
11235c4bbdfSmrgstatic void RootlessImageText16(DrawablePtr dst, GCPtr pGC, int x, int y,
11335c4bbdfSmrg                                int count, unsigned short *chars);
11435c4bbdfSmrgstatic void RootlessImageGlyphBlt(DrawablePtr dst, GCPtr pGC, int x, int y,
11535c4bbdfSmrg                                  unsigned int nglyphInit,
11635c4bbdfSmrg                                  CharInfoPtr * ppciInit, void *unused);
11735c4bbdfSmrgstatic void RootlessPolyGlyphBlt(DrawablePtr dst, GCPtr pGC, int x, int y,
11835c4bbdfSmrg                                 unsigned int nglyph, CharInfoPtr * ppci,
11935c4bbdfSmrg                                 void *pglyphBase);
1204642e01fSmrgstatic void RootlessPushPixels(GCPtr pGC, PixmapPtr pBitMap, DrawablePtr dst,
12135c4bbdfSmrg                               int dx, int dy, int xOrg, int yOrg);
12205b261ecSmrg
12305b261ecSmrgstatic GCOps rootlessGCOps = {
12405b261ecSmrg    RootlessFillSpans,
12505b261ecSmrg    RootlessSetSpans,
12605b261ecSmrg    RootlessPutImage,
12705b261ecSmrg    RootlessCopyArea,
12805b261ecSmrg    RootlessCopyPlane,
12905b261ecSmrg    RootlessPolyPoint,
13005b261ecSmrg    RootlessPolylines,
13105b261ecSmrg    RootlessPolySegment,
13205b261ecSmrg    RootlessPolyRectangle,
13305b261ecSmrg    RootlessPolyArc,
13405b261ecSmrg    RootlessFillPolygon,
13505b261ecSmrg    RootlessPolyFillRect,
13605b261ecSmrg    RootlessPolyFillArc,
13705b261ecSmrg    RootlessPolyText8,
13805b261ecSmrg    RootlessPolyText16,
13905b261ecSmrg    RootlessImageText8,
14005b261ecSmrg    RootlessImageText16,
14105b261ecSmrg    RootlessImageGlyphBlt,
14205b261ecSmrg    RootlessPolyGlyphBlt,
14305b261ecSmrg    RootlessPushPixels
14405b261ecSmrg};
14505b261ecSmrg
14605b261ecSmrg/*
14705b261ecSmrg   If ROOTLESS_PROTECT_ALPHA is set, we have to make sure that the alpha
14805b261ecSmrg   channel of the on screen windows is always opaque. fb makes this harder
14905b261ecSmrg   than it would otherwise be by noticing that a planemask of 0x00ffffff
15005b261ecSmrg   includes all bits when depth==24, and so it "optimizes" the planemask to
15105b261ecSmrg   0xffffffff. We work around this by temporarily setting depth=bpp while
15205b261ecSmrg   changing the GC.
15305b261ecSmrg
15405b261ecSmrg   So the normal situation (in 32 bit mode) is that the planemask is
15505b261ecSmrg   0x00ffffff and thus fb leaves the alpha channel alone. The rootless
15605b261ecSmrg   implementation is responsible for setting the alpha channel opaque
15705b261ecSmrg   initially.
15805b261ecSmrg
15905b261ecSmrg   Unfortunately drawing with a planemask that doesn't have all bits set
16005b261ecSmrg   normally causes fb to fall off its fastest paths when blitting and
16105b261ecSmrg   filling.  So we try to recognize when we can relax the planemask back to
16205b261ecSmrg   0xffffffff, and do that for the duration of the drawing operation,
16305b261ecSmrg   setting the alpha channel in fg/bg pixels to opaque at the same time. We
16405b261ecSmrg   can do this when drawing op is GXcopy. We can also do this when copying
16505b261ecSmrg   from another window since its alpha channel must also be opaque.
16605b261ecSmrg
1679ace9065Smrg   The three macros below are used to implement this. Drawing ops that can
1689ace9065Smrg   potentially have their planemask relaxed look like:
16905b261ecSmrg
17005b261ecSmrg   OP {
17105b261ecSmrg       GC_SAVE(gc);
17205b261ecSmrg       GCOP_UNWRAP(gc);
17305b261ecSmrg
17405b261ecSmrg       ...
17505b261ecSmrg
17605b261ecSmrg       if (canAccelxxx(..) && otherwise-suitable)
17705b261ecSmrg            GC_UNSET_PM(gc, dst);
17805b261ecSmrg
17905b261ecSmrg       gc->funcs->OP(gc, ...);
18005b261ecSmrg
18105b261ecSmrg       GC_RESTORE(gc, dst);
18205b261ecSmrg       GCOP_WRAP(gc);
18305b261ecSmrg   }
18405b261ecSmrg
18505b261ecSmrg */
18605b261ecSmrg
18705b261ecSmrg#define GC_SAVE(pGC) 				\
18805b261ecSmrg    unsigned long _save_fg = (pGC)->fgPixel;	\
18905b261ecSmrg    unsigned long _save_bg = (pGC)->bgPixel;	\
19005b261ecSmrg    unsigned long _save_pm = (pGC)->planemask;	\
19105b261ecSmrg    Bool _changed = FALSE
19205b261ecSmrg
19305b261ecSmrg#define GC_RESTORE(pGC, pDraw)					\
19405b261ecSmrg    do {							\
19505b261ecSmrg        if (_changed) {						\
19605b261ecSmrg            unsigned int depth = (pDraw)->depth;		\
19705b261ecSmrg            (pGC)->fgPixel = _save_fg;				\
19805b261ecSmrg            (pGC)->bgPixel = _save_bg;				\
19905b261ecSmrg            (pGC)->planemask = _save_pm;			\
20005b261ecSmrg            (pDraw)->depth = (pDraw)->bitsPerPixel;		\
20105b261ecSmrg            VALIDATE_GC(pGC, GCForeground | GCBackground |	\
20205b261ecSmrg                        GCPlaneMask, pDraw);			\
20305b261ecSmrg            (pDraw)->depth = depth;				\
20405b261ecSmrg        }							\
20505b261ecSmrg    } while (0)
20605b261ecSmrg
20705b261ecSmrg#define GC_UNSET_PM(pGC, pDraw)						\
20805b261ecSmrg    do {								\
20905b261ecSmrg        unsigned int mask = RootlessAlphaMask ((pDraw)->bitsPerPixel);	\
21005b261ecSmrg        if (((pGC)->planemask & mask) != mask) {			\
21105b261ecSmrg            unsigned int depth = (pDraw)->depth;			\
21205b261ecSmrg            (pGC)->fgPixel |= mask;					\
21305b261ecSmrg            (pGC)->bgPixel |= mask;					\
21405b261ecSmrg            (pGC)->planemask |= mask;					\
21505b261ecSmrg            (pDraw)->depth = (pDraw)->bitsPerPixel;			\
21605b261ecSmrg            VALIDATE_GC(pGC, GCForeground |				\
21705b261ecSmrg                        GCBackground | GCPlaneMask, pDraw);		\
21805b261ecSmrg            (pDraw)->depth = depth;					\
21905b261ecSmrg            _changed = TRUE;						\
22005b261ecSmrg        }								\
22105b261ecSmrg    } while (0)
22205b261ecSmrg
22305b261ecSmrg#define VALIDATE_GC(pGC, changes, pDrawable)				\
22405b261ecSmrg    do {								\
22505b261ecSmrg        pGC->funcs->ValidateGC(pGC, changes, pDrawable);		\
22605b261ecSmrg        if (((WindowPtr) pDrawable)->viewable) {			\
22705b261ecSmrg            gcrec->originalOps = pGC->ops;				\
22805b261ecSmrg        }								\
22905b261ecSmrg    } while(0)
23005b261ecSmrg
23105b261ecSmrgstatic RootlessWindowRec *
23235c4bbdfSmrgcanAccelBlit(DrawablePtr pDraw, GCPtr pGC)
23305b261ecSmrg{
23405b261ecSmrg    WindowPtr pTop;
23505b261ecSmrg    RootlessWindowRec *winRec;
23605b261ecSmrg    unsigned int pm;
23705b261ecSmrg
23805b261ecSmrg    if (pGC->alu != GXcopy)
23905b261ecSmrg        return NULL;
24005b261ecSmrg
24105b261ecSmrg    if (pDraw->type != DRAWABLE_WINDOW)
24205b261ecSmrg        return NULL;
24305b261ecSmrg
24405b261ecSmrg    pm = ~RootlessAlphaMask(pDraw->bitsPerPixel);
24505b261ecSmrg    if ((pGC->planemask & pm) != pm)
24605b261ecSmrg        return NULL;
24705b261ecSmrg
24805b261ecSmrg    pTop = TopLevelParent((WindowPtr) pDraw);
24905b261ecSmrg    if (pTop == NULL)
25005b261ecSmrg        return NULL;
25105b261ecSmrg
25205b261ecSmrg    winRec = WINREC(pTop);
25305b261ecSmrg    if (winRec == NULL)
25405b261ecSmrg        return NULL;
25505b261ecSmrg
25605b261ecSmrg    return winRec;
25705b261ecSmrg}
25805b261ecSmrg
25905b261ecSmrgstatic inline RootlessWindowRec *
26005b261ecSmrgcanAccelFill(DrawablePtr pDraw, GCPtr pGC)
26105b261ecSmrg{
26205b261ecSmrg    if (pGC->fillStyle != FillSolid)
26305b261ecSmrg        return NULL;
26405b261ecSmrg
26505b261ecSmrg    return canAccelBlit(pDraw, pGC);
26605b261ecSmrg}
26705b261ecSmrg
26805b261ecSmrg/*
26905b261ecSmrg * Screen function to create a graphics context
27005b261ecSmrg */
27105b261ecSmrgBool
27205b261ecSmrgRootlessCreateGC(GCPtr pGC)
27305b261ecSmrg{
27405b261ecSmrg    RootlessGCRec *gcrec;
27505b261ecSmrg    RootlessScreenRec *s;
27605b261ecSmrg    Bool result;
27705b261ecSmrg
27805b261ecSmrg    SCREEN_UNWRAP(pGC->pScreen, CreateGC);
2794642e01fSmrg    s = SCREENREC(pGC->pScreen);
28005b261ecSmrg    result = s->CreateGC(pGC);
28105b261ecSmrg
2824642e01fSmrg    gcrec = (RootlessGCRec *)
28335c4bbdfSmrg        dixLookupPrivate(&pGC->devPrivates, rootlessGCPrivateKey);
28435c4bbdfSmrg    gcrec->originalOps = NULL;  // don't wrap ops yet
28505b261ecSmrg    gcrec->originalFuncs = pGC->funcs;
28605b261ecSmrg    pGC->funcs = &rootlessGCFuncs;
28705b261ecSmrg
28805b261ecSmrg    SCREEN_WRAP(pGC->pScreen, CreateGC);
28905b261ecSmrg    return result;
29005b261ecSmrg}
29105b261ecSmrg
29205b261ecSmrg/*
29305b261ecSmrg * GC funcs
29405b261ecSmrg *
29505b261ecSmrg * These wrap lower level GC funcs.
29605b261ecSmrg * ValidateGC wraps the GC ops iff dest is viewable.
29705b261ecSmrg * All the others just unwrap and call.
29805b261ecSmrg */
29905b261ecSmrg
30035c4bbdfSmrg// GCFUNC_UNRAP assumes funcs have been wrapped and
30105b261ecSmrg// does not assume ops have been wrapped
30205b261ecSmrg#define GCFUNC_UNWRAP(pGC) \
30305b261ecSmrg    RootlessGCRec *gcrec = (RootlessGCRec *) \
3044642e01fSmrg	dixLookupPrivate(&(pGC)->devPrivates, rootlessGCPrivateKey); \
30505b261ecSmrg    (pGC)->funcs = gcrec->originalFuncs; \
30605b261ecSmrg    if (gcrec->originalOps) { \
30705b261ecSmrg        (pGC)->ops = gcrec->originalOps; \
30805b261ecSmrg}
30905b261ecSmrg
31005b261ecSmrg#define GCFUNC_WRAP(pGC) \
31105b261ecSmrg    gcrec->originalFuncs = (pGC)->funcs; \
31205b261ecSmrg    (pGC)->funcs = &rootlessGCFuncs; \
31305b261ecSmrg    if (gcrec->originalOps) { \
31405b261ecSmrg        gcrec->originalOps = (pGC)->ops; \
31505b261ecSmrg        (pGC)->ops = &rootlessGCOps; \
31605b261ecSmrg}
31705b261ecSmrg
31805b261ecSmrgstatic void
31905b261ecSmrgRootlessValidateGC(GCPtr pGC, unsigned long changes, DrawablePtr pDrawable)
32005b261ecSmrg{
32105b261ecSmrg    GCFUNC_UNWRAP(pGC);
32205b261ecSmrg
32305b261ecSmrg    gcrec->originalOps = NULL;
32405b261ecSmrg
32535c4bbdfSmrg    if (pDrawable->type == DRAWABLE_WINDOW) {
32605b261ecSmrg#ifdef ROOTLESS_PROTECT_ALPHA
32705b261ecSmrg        unsigned int depth = pDrawable->depth;
32805b261ecSmrg
32905b261ecSmrg        // We force a planemask so fb doesn't overwrite the alpha channel.
33005b261ecSmrg        // Left to its own devices, fb will optimize away the planemask.
33105b261ecSmrg        pDrawable->depth = pDrawable->bitsPerPixel;
33205b261ecSmrg        pGC->planemask &= ~RootlessAlphaMask(pDrawable->bitsPerPixel);
33305b261ecSmrg        VALIDATE_GC(pGC, changes | GCPlaneMask, pDrawable);
33405b261ecSmrg        pDrawable->depth = depth;
33505b261ecSmrg#else
33605b261ecSmrg        VALIDATE_GC(pGC, changes, pDrawable);
33705b261ecSmrg#endif
33835c4bbdfSmrg    }
33935c4bbdfSmrg    else {
34005b261ecSmrg        pGC->funcs->ValidateGC(pGC, changes, pDrawable);
34105b261ecSmrg    }
34205b261ecSmrg
34305b261ecSmrg    GCFUNC_WRAP(pGC);
34405b261ecSmrg}
34505b261ecSmrg
34635c4bbdfSmrgstatic void
34735c4bbdfSmrgRootlessChangeGC(GCPtr pGC, unsigned long mask)
34805b261ecSmrg{
34905b261ecSmrg    GCFUNC_UNWRAP(pGC);
35005b261ecSmrg    pGC->funcs->ChangeGC(pGC, mask);
35105b261ecSmrg    GCFUNC_WRAP(pGC);
35205b261ecSmrg}
35305b261ecSmrg
35435c4bbdfSmrgstatic void
35535c4bbdfSmrgRootlessCopyGC(GCPtr pGCSrc, unsigned long mask, GCPtr pGCDst)
35605b261ecSmrg{
35705b261ecSmrg    GCFUNC_UNWRAP(pGCDst);
35805b261ecSmrg    pGCDst->funcs->CopyGC(pGCSrc, mask, pGCDst);
35905b261ecSmrg    GCFUNC_WRAP(pGCDst);
36005b261ecSmrg}
36105b261ecSmrg
36235c4bbdfSmrgstatic void
36335c4bbdfSmrgRootlessDestroyGC(GCPtr pGC)
36405b261ecSmrg{
36505b261ecSmrg    GCFUNC_UNWRAP(pGC);
36605b261ecSmrg    pGC->funcs->DestroyGC(pGC);
36705b261ecSmrg    GCFUNC_WRAP(pGC);
36805b261ecSmrg}
36905b261ecSmrg
37035c4bbdfSmrgstatic void
37135c4bbdfSmrgRootlessChangeClip(GCPtr pGC, int type, void *pvalue, int nrects)
37205b261ecSmrg{
37305b261ecSmrg    GCFUNC_UNWRAP(pGC);
37405b261ecSmrg    pGC->funcs->ChangeClip(pGC, type, pvalue, nrects);
37505b261ecSmrg    GCFUNC_WRAP(pGC);
37605b261ecSmrg}
37705b261ecSmrg
37835c4bbdfSmrgstatic void
37935c4bbdfSmrgRootlessDestroyClip(GCPtr pGC)
38005b261ecSmrg{
38105b261ecSmrg    GCFUNC_UNWRAP(pGC);
38205b261ecSmrg    pGC->funcs->DestroyClip(pGC);
38305b261ecSmrg    GCFUNC_WRAP(pGC);
38405b261ecSmrg}
38505b261ecSmrg
38635c4bbdfSmrgstatic void
38735c4bbdfSmrgRootlessCopyClip(GCPtr pgcDst, GCPtr pgcSrc)
38805b261ecSmrg{
38905b261ecSmrg    GCFUNC_UNWRAP(pgcDst);
39005b261ecSmrg    pgcDst->funcs->CopyClip(pgcDst, pgcSrc);
39105b261ecSmrg    GCFUNC_WRAP(pgcDst);
39205b261ecSmrg}
39305b261ecSmrg
39405b261ecSmrg/*
39505b261ecSmrg * GC ops
39605b261ecSmrg *
39705b261ecSmrg * We can't use shadowfb because shadowfb assumes one pixmap
39805b261ecSmrg * and our root window is a special case.
39905b261ecSmrg * However, much of this code is copied from shadowfb.
40005b261ecSmrg */
40105b261ecSmrg
40205b261ecSmrg// assumes both funcs and ops are wrapped
40305b261ecSmrg#define GCOP_UNWRAP(pGC) \
40405b261ecSmrg    RootlessGCRec *gcrec = (RootlessGCRec *) \
4054642e01fSmrg        dixLookupPrivate(&(pGC)->devPrivates, rootlessGCPrivateKey); \
40635c4bbdfSmrg    const GCFuncs *saveFuncs = pGC->funcs; \
40705b261ecSmrg    (pGC)->funcs = gcrec->originalFuncs; \
40805b261ecSmrg    (pGC)->ops = gcrec->originalOps;
40905b261ecSmrg
41005b261ecSmrg#define GCOP_WRAP(pGC) \
41105b261ecSmrg    gcrec->originalOps = (pGC)->ops; \
41205b261ecSmrg    (pGC)->funcs = saveFuncs; \
41305b261ecSmrg    (pGC)->ops = &rootlessGCOps;
41405b261ecSmrg
41505b261ecSmrgstatic void
41605b261ecSmrgRootlessFillSpans(DrawablePtr dst, GCPtr pGC, int nInit,
41705b261ecSmrg                  DDXPointPtr pptInit, int *pwidthInit, int sorted)
41805b261ecSmrg{
41905b261ecSmrg    GC_SAVE(pGC);
42005b261ecSmrg    GCOP_UNWRAP(pGC);
42105b261ecSmrg    RL_DEBUG_MSG("fill spans start ");
42205b261ecSmrg
42305b261ecSmrg    if (nInit <= 0) {
42405b261ecSmrg        pGC->ops->FillSpans(dst, pGC, nInit, pptInit, pwidthInit, sorted);
42535c4bbdfSmrg    }
42635c4bbdfSmrg    else {
42705b261ecSmrg        DDXPointPtr ppt = pptInit;
42805b261ecSmrg        int *pwidth = pwidthInit;
42905b261ecSmrg        int i = nInit;
43005b261ecSmrg        BoxRec box;
43105b261ecSmrg
43205b261ecSmrg        box.x1 = ppt->x;
43305b261ecSmrg        box.x2 = box.x1 + *pwidth;
43405b261ecSmrg        box.y2 = box.y1 = ppt->y;
43505b261ecSmrg
43605b261ecSmrg        while (--i) {
43705b261ecSmrg            ppt++;
43805b261ecSmrg            pwidth++;
43905b261ecSmrg            if (box.x1 > ppt->x)
44005b261ecSmrg                box.x1 = ppt->x;
44105b261ecSmrg            if (box.x2 < (ppt->x + *pwidth))
44205b261ecSmrg                box.x2 = ppt->x + *pwidth;
44305b261ecSmrg            if (box.y1 > ppt->y)
44405b261ecSmrg                box.y1 = ppt->y;
44505b261ecSmrg            else if (box.y2 < ppt->y)
44605b261ecSmrg                box.y2 = ppt->y;
44705b261ecSmrg        }
44805b261ecSmrg
44905b261ecSmrg        box.y2++;
45005b261ecSmrg
45105b261ecSmrg        RootlessStartDrawing((WindowPtr) dst);
45205b261ecSmrg
45335c4bbdfSmrg        if (canAccelFill(dst, pGC)) {
45405b261ecSmrg            GC_UNSET_PM(pGC, dst);
45505b261ecSmrg        }
45605b261ecSmrg
45705b261ecSmrg        pGC->ops->FillSpans(dst, pGC, nInit, pptInit, pwidthInit, sorted);
45805b261ecSmrg
45905b261ecSmrg        TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
46005b261ecSmrg        if (BOX_NOT_EMPTY(box))
46135c4bbdfSmrg            RootlessDamageBox((WindowPtr) dst, &box);
46205b261ecSmrg    }
46305b261ecSmrg
46405b261ecSmrg    GC_RESTORE(pGC, dst);
46505b261ecSmrg    GCOP_WRAP(pGC);
46605b261ecSmrg    RL_DEBUG_MSG("fill spans end\n");
46705b261ecSmrg}
46805b261ecSmrg
46905b261ecSmrgstatic void
47005b261ecSmrgRootlessSetSpans(DrawablePtr dst, GCPtr pGC, char *pSrc,
47135c4bbdfSmrg                 DDXPointPtr pptInit, int *pwidthInit, int nspans, int sorted)
47205b261ecSmrg{
47305b261ecSmrg    GCOP_UNWRAP(pGC);
47405b261ecSmrg    RL_DEBUG_MSG("set spans start ");
47505b261ecSmrg
47605b261ecSmrg    if (nspans <= 0) {
47735c4bbdfSmrg        pGC->ops->SetSpans(dst, pGC, pSrc, pptInit, pwidthInit, nspans, sorted);
47835c4bbdfSmrg    }
47935c4bbdfSmrg    else {
48005b261ecSmrg        DDXPointPtr ppt = pptInit;
48105b261ecSmrg        int *pwidth = pwidthInit;
48205b261ecSmrg        int i = nspans;
48305b261ecSmrg        BoxRec box;
48405b261ecSmrg
48505b261ecSmrg        box.x1 = ppt->x;
48605b261ecSmrg        box.x2 = box.x1 + *pwidth;
48705b261ecSmrg        box.y2 = box.y1 = ppt->y;
48805b261ecSmrg
48905b261ecSmrg        while (--i) {
49005b261ecSmrg            ppt++;
49105b261ecSmrg            pwidth++;
49205b261ecSmrg            if (box.x1 > ppt->x)
49305b261ecSmrg                box.x1 = ppt->x;
49405b261ecSmrg            if (box.x2 < (ppt->x + *pwidth))
49505b261ecSmrg                box.x2 = ppt->x + *pwidth;
49605b261ecSmrg            if (box.y1 > ppt->y)
49705b261ecSmrg                box.y1 = ppt->y;
49805b261ecSmrg            else if (box.y2 < ppt->y)
49905b261ecSmrg                box.y2 = ppt->y;
50005b261ecSmrg        }
50105b261ecSmrg
50205b261ecSmrg        box.y2++;
50305b261ecSmrg
50405b261ecSmrg        RootlessStartDrawing((WindowPtr) dst);
50535c4bbdfSmrg        pGC->ops->SetSpans(dst, pGC, pSrc, pptInit, pwidthInit, nspans, sorted);
50605b261ecSmrg
50705b261ecSmrg        TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
50805b261ecSmrg        if (BOX_NOT_EMPTY(box))
50935c4bbdfSmrg            RootlessDamageBox((WindowPtr) dst, &box);
51005b261ecSmrg    }
51105b261ecSmrg    GCOP_WRAP(pGC);
51205b261ecSmrg    RL_DEBUG_MSG("set spans end\n");
51305b261ecSmrg}
51405b261ecSmrg
51505b261ecSmrgstatic void
51605b261ecSmrgRootlessPutImage(DrawablePtr dst, GCPtr pGC,
51705b261ecSmrg                 int depth, int x, int y, int w, int h,
51805b261ecSmrg                 int leftPad, int format, char *pBits)
51905b261ecSmrg{
52005b261ecSmrg    BoxRec box;
52105b261ecSmrg
52205b261ecSmrg    GCOP_UNWRAP(pGC);
52305b261ecSmrg    RL_DEBUG_MSG("put image start ");
52405b261ecSmrg
52505b261ecSmrg    RootlessStartDrawing((WindowPtr) dst);
52635c4bbdfSmrg    pGC->ops->PutImage(dst, pGC, depth, x, y, w, h, leftPad, format, pBits);
52705b261ecSmrg
52805b261ecSmrg    box.x1 = x + dst->x;
52905b261ecSmrg    box.x2 = box.x1 + w;
53005b261ecSmrg    box.y1 = y + dst->y;
53105b261ecSmrg    box.y2 = box.y1 + h;
53205b261ecSmrg
53305b261ecSmrg    TRIM_BOX(box, pGC);
53405b261ecSmrg    if (BOX_NOT_EMPTY(box))
53535c4bbdfSmrg        RootlessDamageBox((WindowPtr) dst, &box);
53605b261ecSmrg
53705b261ecSmrg    GCOP_WRAP(pGC);
53805b261ecSmrg    RL_DEBUG_MSG("put image end\n");
53905b261ecSmrg}
54005b261ecSmrg
54105b261ecSmrg/* changed area is *dest* rect */
54205b261ecSmrgstatic RegionPtr
54305b261ecSmrgRootlessCopyArea(DrawablePtr pSrc, DrawablePtr dst, GCPtr pGC,
54435c4bbdfSmrg                 int srcx, int srcy, int w, int h, int dstx, int dsty)
54505b261ecSmrg{
54605b261ecSmrg    RegionPtr result;
54705b261ecSmrg    BoxRec box;
54805b261ecSmrg
54905b261ecSmrg    GC_SAVE(pGC);
55005b261ecSmrg    GCOP_UNWRAP(pGC);
55105b261ecSmrg
55205b261ecSmrg    RL_DEBUG_MSG("copy area start (src 0x%x, dst 0x%x)", pSrc, dst);
55305b261ecSmrg
55435c4bbdfSmrg    if (pSrc->type == DRAWABLE_WINDOW && IsFramedWindow((WindowPtr) pSrc)) {
55505b261ecSmrg        /* If both source and dest are windows, and we're doing
55605b261ecSmrg           a simple copy operation, we can remove the alpha-protecting
55705b261ecSmrg           planemask (since source has opaque alpha as well) */
55805b261ecSmrg
55935c4bbdfSmrg        if (canAccelBlit(pSrc, pGC)) {
56005b261ecSmrg            GC_UNSET_PM(pGC, dst);
56105b261ecSmrg        }
56205b261ecSmrg
56305b261ecSmrg        RootlessStartDrawing((WindowPtr) pSrc);
56405b261ecSmrg    }
56505b261ecSmrg    RootlessStartDrawing((WindowPtr) dst);
56605b261ecSmrg    result = pGC->ops->CopyArea(pSrc, dst, pGC, srcx, srcy, w, h, dstx, dsty);
56705b261ecSmrg
56805b261ecSmrg    box.x1 = dstx + dst->x;
56905b261ecSmrg    box.x2 = box.x1 + w;
57005b261ecSmrg    box.y1 = dsty + dst->y;
57105b261ecSmrg    box.y2 = box.y1 + h;
57205b261ecSmrg
57305b261ecSmrg    TRIM_BOX(box, pGC);
57405b261ecSmrg    if (BOX_NOT_EMPTY(box))
57535c4bbdfSmrg        RootlessDamageBox((WindowPtr) dst, &box);
57605b261ecSmrg
57705b261ecSmrg    GC_RESTORE(pGC, dst);
57805b261ecSmrg    GCOP_WRAP(pGC);
57905b261ecSmrg    RL_DEBUG_MSG("copy area end\n");
58005b261ecSmrg    return result;
58105b261ecSmrg}
58205b261ecSmrg
58305b261ecSmrg/* changed area is *dest* rect */
58435c4bbdfSmrgstatic RegionPtr
58535c4bbdfSmrgRootlessCopyPlane(DrawablePtr pSrc, DrawablePtr dst,
58635c4bbdfSmrg                  GCPtr pGC, int srcx, int srcy,
58735c4bbdfSmrg                  int w, int h, int dstx, int dsty, unsigned long plane)
58805b261ecSmrg{
58905b261ecSmrg    RegionPtr result;
59005b261ecSmrg    BoxRec box;
59105b261ecSmrg
59205b261ecSmrg    GCOP_UNWRAP(pGC);
59305b261ecSmrg
59405b261ecSmrg    RL_DEBUG_MSG("copy plane start ");
59505b261ecSmrg
59635c4bbdfSmrg    if (pSrc->type == DRAWABLE_WINDOW && IsFramedWindow((WindowPtr) pSrc)) {
59705b261ecSmrg        RootlessStartDrawing((WindowPtr) pSrc);
59805b261ecSmrg    }
59905b261ecSmrg    RootlessStartDrawing((WindowPtr) dst);
60005b261ecSmrg    result = pGC->ops->CopyPlane(pSrc, dst, pGC, srcx, srcy, w, h,
60105b261ecSmrg                                 dstx, dsty, plane);
60205b261ecSmrg
60305b261ecSmrg    box.x1 = dstx + dst->x;
60405b261ecSmrg    box.x2 = box.x1 + w;
60505b261ecSmrg    box.y1 = dsty + dst->y;
60605b261ecSmrg    box.y2 = box.y1 + h;
60705b261ecSmrg
60805b261ecSmrg    TRIM_BOX(box, pGC);
60905b261ecSmrg    if (BOX_NOT_EMPTY(box))
61035c4bbdfSmrg        RootlessDamageBox((WindowPtr) dst, &box);
61105b261ecSmrg
61205b261ecSmrg    GCOP_WRAP(pGC);
61305b261ecSmrg    RL_DEBUG_MSG("copy plane end\n");
61405b261ecSmrg    return result;
61505b261ecSmrg}
61605b261ecSmrg
61705b261ecSmrg// Options for size of changed area:
61805b261ecSmrg//  0 = box per point
61905b261ecSmrg//  1 = big box around all points
62005b261ecSmrg//  2 = accumulate point in 20 pixel radius
62105b261ecSmrg#define ROOTLESS_CHANGED_AREA 1
62205b261ecSmrg#define abs(a) ((a) > 0 ? (a) : -(a))
62305b261ecSmrg
62405b261ecSmrg/* changed area is box around all points */
62535c4bbdfSmrgstatic void
62635c4bbdfSmrgRootlessPolyPoint(DrawablePtr dst, GCPtr pGC,
62735c4bbdfSmrg                  int mode, int npt, DDXPointPtr pptInit)
62805b261ecSmrg{
62905b261ecSmrg    GCOP_UNWRAP(pGC);
63005b261ecSmrg    RL_DEBUG_MSG("polypoint start ");
63105b261ecSmrg
63205b261ecSmrg    RootlessStartDrawing((WindowPtr) dst);
63305b261ecSmrg    pGC->ops->PolyPoint(dst, pGC, mode, npt, pptInit);
63405b261ecSmrg
63505b261ecSmrg    if (npt > 0) {
63605b261ecSmrg#if ROOTLESS_CHANGED_AREA==0
63705b261ecSmrg        // box per point
63805b261ecSmrg        BoxRec box;
63905b261ecSmrg
64005b261ecSmrg        while (npt) {
64105b261ecSmrg            box.x1 = pptInit->x;
64205b261ecSmrg            box.y1 = pptInit->y;
64305b261ecSmrg            box.x2 = box.x1 + 1;
64405b261ecSmrg            box.y2 = box.y1 + 1;
64505b261ecSmrg
64605b261ecSmrg            TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
64705b261ecSmrg            if (BOX_NOT_EMPTY(box))
64835c4bbdfSmrg                RootlessDamageBox((WindowPtr) dst, &box);
64905b261ecSmrg
65005b261ecSmrg            npt--;
65105b261ecSmrg            pptInit++;
65205b261ecSmrg        }
65305b261ecSmrg
65405b261ecSmrg#elif ROOTLESS_CHANGED_AREA==1
65505b261ecSmrg        // one big box
65605b261ecSmrg        BoxRec box;
65705b261ecSmrg
65805b261ecSmrg        box.x2 = box.x1 = pptInit->x;
65905b261ecSmrg        box.y2 = box.y1 = pptInit->y;
66005b261ecSmrg        while (--npt) {
66105b261ecSmrg            pptInit++;
66205b261ecSmrg            if (box.x1 > pptInit->x)
66305b261ecSmrg                box.x1 = pptInit->x;
66405b261ecSmrg            else if (box.x2 < pptInit->x)
66505b261ecSmrg                box.x2 = pptInit->x;
66605b261ecSmrg            if (box.y1 > pptInit->y)
66705b261ecSmrg                box.y1 = pptInit->y;
66805b261ecSmrg            else if (box.y2 < pptInit->y)
66905b261ecSmrg                box.y2 = pptInit->y;
67005b261ecSmrg        }
67105b261ecSmrg
67205b261ecSmrg        box.x2++;
67305b261ecSmrg        box.y2++;
67405b261ecSmrg
67505b261ecSmrg        TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
67605b261ecSmrg        if (BOX_NOT_EMPTY(box))
67735c4bbdfSmrg            RootlessDamageBox((WindowPtr) dst, &box);
67805b261ecSmrg
67905b261ecSmrg#elif ROOTLESS_CHANGED_AREA==2
68005b261ecSmrg        // clever(?) method: accumulate point in 20-pixel radius
68105b261ecSmrg        BoxRec box;
68205b261ecSmrg        int firstx, firsty;
68305b261ecSmrg
68405b261ecSmrg        box.x2 = box.x1 = firstx = pptInit->x;
68505b261ecSmrg        box.y2 = box.y1 = firsty = pptInit->y;
68605b261ecSmrg        while (--npt) {
68705b261ecSmrg            pptInit++;
68835c4bbdfSmrg            if (abs(pptInit->x - firstx) > 20 || abs(pptInit->y - firsty) > 20) {
68905b261ecSmrg                box.x2++;
69005b261ecSmrg                box.y2++;
69105b261ecSmrg                TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
69205b261ecSmrg                if (BOX_NOT_EMPTY(box))
69335c4bbdfSmrg                    RootlessDamageBox((WindowPtr) dst, &box);
69405b261ecSmrg                box.x2 = box.x1 = firstx = pptInit->x;
69505b261ecSmrg                box.y2 = box.y1 = firsty = pptInit->y;
69635c4bbdfSmrg            }
69735c4bbdfSmrg            else {
69835c4bbdfSmrg                if (box.x1 > pptInit->x)
69935c4bbdfSmrg                    box.x1 = pptInit->x;
70035c4bbdfSmrg                else if (box.x2 < pptInit->x)
70135c4bbdfSmrg                    box.x2 = pptInit->x;
70235c4bbdfSmrg                if (box.y1 > pptInit->y)
70335c4bbdfSmrg                    box.y1 = pptInit->y;
70435c4bbdfSmrg                else if (box.y2 < pptInit->y)
70535c4bbdfSmrg                    box.y2 = pptInit->y;
70605b261ecSmrg            }
70705b261ecSmrg        }
70805b261ecSmrg        box.x2++;
70905b261ecSmrg        box.y2++;
71005b261ecSmrg        TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
71105b261ecSmrg        if (BOX_NOT_EMPTY(box))
71205b261ecSmrg            RootlessDamageBox((WindowPtr) dst, &box);
71335c4bbdfSmrg#endif                          /* ROOTLESS_CHANGED_AREA */
71405b261ecSmrg    }
71505b261ecSmrg
71605b261ecSmrg    GCOP_WRAP(pGC);
71705b261ecSmrg    RL_DEBUG_MSG("polypoint end\n");
71805b261ecSmrg}
71905b261ecSmrg
72005b261ecSmrg#undef ROOTLESS_CHANGED_AREA
72105b261ecSmrg
72205b261ecSmrg/* changed area is box around each line */
72335c4bbdfSmrgstatic void
72435c4bbdfSmrgRootlessPolylines(DrawablePtr dst, GCPtr pGC,
72535c4bbdfSmrg                  int mode, int npt, DDXPointPtr pptInit)
72605b261ecSmrg{
72705b261ecSmrg    GCOP_UNWRAP(pGC);
72805b261ecSmrg    RL_DEBUG_MSG("poly lines start ");
72905b261ecSmrg
73005b261ecSmrg    RootlessStartDrawing((WindowPtr) dst);
73105b261ecSmrg    pGC->ops->Polylines(dst, pGC, mode, npt, pptInit);
73205b261ecSmrg
73305b261ecSmrg    if (npt > 0) {
73405b261ecSmrg        BoxRec box;
73505b261ecSmrg        int extra = pGC->lineWidth >> 1;
73605b261ecSmrg
73705b261ecSmrg        box.x2 = box.x1 = pptInit->x;
73805b261ecSmrg        box.y2 = box.y1 = pptInit->y;
73905b261ecSmrg
74005b261ecSmrg        if (npt > 1) {
74105b261ecSmrg            if (pGC->joinStyle == JoinMiter)
74205b261ecSmrg                extra = 6 * pGC->lineWidth;
74305b261ecSmrg            else if (pGC->capStyle == CapProjecting)
74405b261ecSmrg                extra = pGC->lineWidth;
74505b261ecSmrg        }
74605b261ecSmrg
74705b261ecSmrg        if (mode == CoordModePrevious) {
74805b261ecSmrg            int x = box.x1;
74905b261ecSmrg            int y = box.y1;
75005b261ecSmrg
75105b261ecSmrg            while (--npt) {
75205b261ecSmrg                pptInit++;
75305b261ecSmrg                x += pptInit->x;
75405b261ecSmrg                y += pptInit->y;
75505b261ecSmrg                if (box.x1 > x)
75605b261ecSmrg                    box.x1 = x;
75705b261ecSmrg                else if (box.x2 < x)
75805b261ecSmrg                    box.x2 = x;
75905b261ecSmrg                if (box.y1 > y)
76005b261ecSmrg                    box.y1 = y;
76105b261ecSmrg                else if (box.y2 < y)
76205b261ecSmrg                    box.y2 = y;
76305b261ecSmrg            }
76435c4bbdfSmrg        }
76535c4bbdfSmrg        else {
76605b261ecSmrg            while (--npt) {
76705b261ecSmrg                pptInit++;
76805b261ecSmrg                if (box.x1 > pptInit->x)
76905b261ecSmrg                    box.x1 = pptInit->x;
77005b261ecSmrg                else if (box.x2 < pptInit->x)
77105b261ecSmrg                    box.x2 = pptInit->x;
77205b261ecSmrg                if (box.y1 > pptInit->y)
77305b261ecSmrg                    box.y1 = pptInit->y;
77405b261ecSmrg                else if (box.y2 < pptInit->y)
77505b261ecSmrg                    box.y2 = pptInit->y;
77605b261ecSmrg            }
77705b261ecSmrg        }
77805b261ecSmrg
77905b261ecSmrg        box.x2++;
78005b261ecSmrg        box.y2++;
78105b261ecSmrg
78205b261ecSmrg        if (extra) {
78305b261ecSmrg            box.x1 -= extra;
78405b261ecSmrg            box.x2 += extra;
78505b261ecSmrg            box.y1 -= extra;
78605b261ecSmrg            box.y2 += extra;
78705b261ecSmrg        }
78805b261ecSmrg
78905b261ecSmrg        TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
79005b261ecSmrg        if (BOX_NOT_EMPTY(box))
79135c4bbdfSmrg            RootlessDamageBox((WindowPtr) dst, &box);
79205b261ecSmrg    }
79305b261ecSmrg
79405b261ecSmrg    GCOP_WRAP(pGC);
79505b261ecSmrg    RL_DEBUG_MSG("poly lines end\n");
79605b261ecSmrg}
79705b261ecSmrg
79805b261ecSmrg/* changed area is box around each line segment */
79935c4bbdfSmrgstatic void
80035c4bbdfSmrgRootlessPolySegment(DrawablePtr dst, GCPtr pGC, int nseg, xSegment * pSeg)
80105b261ecSmrg{
80205b261ecSmrg    GCOP_UNWRAP(pGC);
80305b261ecSmrg    RL_DEBUG_MSG("poly segment start (win 0x%x)", dst);
80405b261ecSmrg
80505b261ecSmrg    RootlessStartDrawing((WindowPtr) dst);
80605b261ecSmrg    pGC->ops->PolySegment(dst, pGC, nseg, pSeg);
80705b261ecSmrg
80805b261ecSmrg    if (nseg > 0) {
80905b261ecSmrg        BoxRec box;
81005b261ecSmrg        int extra = pGC->lineWidth;
81105b261ecSmrg
81205b261ecSmrg        if (pGC->capStyle != CapProjecting)
81335c4bbdfSmrg            extra >>= 1;
81405b261ecSmrg
81505b261ecSmrg        if (pSeg->x2 > pSeg->x1) {
81605b261ecSmrg            box.x1 = pSeg->x1;
81705b261ecSmrg            box.x2 = pSeg->x2;
81835c4bbdfSmrg        }
81935c4bbdfSmrg        else {
82005b261ecSmrg            box.x2 = pSeg->x1;
82105b261ecSmrg            box.x1 = pSeg->x2;
82205b261ecSmrg        }
82305b261ecSmrg
82405b261ecSmrg        if (pSeg->y2 > pSeg->y1) {
82505b261ecSmrg            box.y1 = pSeg->y1;
82605b261ecSmrg            box.y2 = pSeg->y2;
82735c4bbdfSmrg        }
82835c4bbdfSmrg        else {
82905b261ecSmrg            box.y2 = pSeg->y1;
83005b261ecSmrg            box.y1 = pSeg->y2;
83105b261ecSmrg        }
83205b261ecSmrg
83305b261ecSmrg        while (--nseg) {
83405b261ecSmrg            pSeg++;
83505b261ecSmrg            if (pSeg->x2 > pSeg->x1) {
83635c4bbdfSmrg                if (pSeg->x1 < box.x1)
83735c4bbdfSmrg                    box.x1 = pSeg->x1;
83835c4bbdfSmrg                if (pSeg->x2 > box.x2)
83935c4bbdfSmrg                    box.x2 = pSeg->x2;
84035c4bbdfSmrg            }
84135c4bbdfSmrg            else {
84235c4bbdfSmrg                if (pSeg->x2 < box.x1)
84335c4bbdfSmrg                    box.x1 = pSeg->x2;
84435c4bbdfSmrg                if (pSeg->x1 > box.x2)
84535c4bbdfSmrg                    box.x2 = pSeg->x1;
84605b261ecSmrg            }
84705b261ecSmrg            if (pSeg->y2 > pSeg->y1) {
84835c4bbdfSmrg                if (pSeg->y1 < box.y1)
84935c4bbdfSmrg                    box.y1 = pSeg->y1;
85035c4bbdfSmrg                if (pSeg->y2 > box.y2)
85135c4bbdfSmrg                    box.y2 = pSeg->y2;
85235c4bbdfSmrg            }
85335c4bbdfSmrg            else {
85435c4bbdfSmrg                if (pSeg->y2 < box.y1)
85535c4bbdfSmrg                    box.y1 = pSeg->y2;
85635c4bbdfSmrg                if (pSeg->y1 > box.y2)
85735c4bbdfSmrg                    box.y2 = pSeg->y1;
85805b261ecSmrg            }
85905b261ecSmrg        }
86005b261ecSmrg
86105b261ecSmrg        box.x2++;
86205b261ecSmrg        box.y2++;
86305b261ecSmrg
86405b261ecSmrg        if (extra) {
86505b261ecSmrg            box.x1 -= extra;
86605b261ecSmrg            box.x2 += extra;
86705b261ecSmrg            box.y1 -= extra;
86805b261ecSmrg            box.y2 += extra;
86905b261ecSmrg        }
87005b261ecSmrg
87105b261ecSmrg        TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
87205b261ecSmrg        if (BOX_NOT_EMPTY(box))
87335c4bbdfSmrg            RootlessDamageBox((WindowPtr) dst, &box);
87405b261ecSmrg    }
87505b261ecSmrg
87605b261ecSmrg    GCOP_WRAP(pGC);
87705b261ecSmrg    RL_DEBUG_MSG("poly segment end\n");
87805b261ecSmrg}
87905b261ecSmrg
88005b261ecSmrg/* changed area is box around each line (not entire rects) */
88135c4bbdfSmrgstatic void
88235c4bbdfSmrgRootlessPolyRectangle(DrawablePtr dst, GCPtr pGC,
88335c4bbdfSmrg                      int nRects, xRectangle *pRects)
88405b261ecSmrg{
88505b261ecSmrg    GCOP_UNWRAP(pGC);
88605b261ecSmrg    RL_DEBUG_MSG("poly rectangle start ");
88705b261ecSmrg
88805b261ecSmrg    RootlessStartDrawing((WindowPtr) dst);
88905b261ecSmrg    pGC->ops->PolyRectangle(dst, pGC, nRects, pRects);
89005b261ecSmrg
89105b261ecSmrg    if (nRects > 0) {
89205b261ecSmrg        BoxRec box;
89305b261ecSmrg        int offset1, offset2, offset3;
89405b261ecSmrg
89505b261ecSmrg        offset2 = pGC->lineWidth;
89635c4bbdfSmrg        if (!offset2)
89735c4bbdfSmrg            offset2 = 1;
89805b261ecSmrg        offset1 = offset2 >> 1;
89905b261ecSmrg        offset3 = offset2 - offset1;
90005b261ecSmrg
90105b261ecSmrg        while (nRects--) {
90205b261ecSmrg            box.x1 = pRects->x - offset1;
90305b261ecSmrg            box.y1 = pRects->y - offset1;
90405b261ecSmrg            box.x2 = box.x1 + pRects->width + offset2;
90505b261ecSmrg            box.y2 = box.y1 + offset2;
90605b261ecSmrg            TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
90705b261ecSmrg            if (BOX_NOT_EMPTY(box))
90835c4bbdfSmrg                RootlessDamageBox((WindowPtr) dst, &box);
90905b261ecSmrg
91005b261ecSmrg            box.x1 = pRects->x - offset1;
91105b261ecSmrg            box.y1 = pRects->y + offset3;
91205b261ecSmrg            box.x2 = box.x1 + offset2;
91305b261ecSmrg            box.y2 = box.y1 + pRects->height - offset2;
91405b261ecSmrg            TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
91505b261ecSmrg            if (BOX_NOT_EMPTY(box))
91635c4bbdfSmrg                RootlessDamageBox((WindowPtr) dst, &box);
91705b261ecSmrg
91805b261ecSmrg            box.x1 = pRects->x + pRects->width - offset1;
91905b261ecSmrg            box.y1 = pRects->y + offset3;
92005b261ecSmrg            box.x2 = box.x1 + offset2;
92105b261ecSmrg            box.y2 = box.y1 + pRects->height - offset2;
92205b261ecSmrg            TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
92305b261ecSmrg            if (BOX_NOT_EMPTY(box))
92435c4bbdfSmrg                RootlessDamageBox((WindowPtr) dst, &box);
92505b261ecSmrg
92605b261ecSmrg            box.x1 = pRects->x - offset1;
92705b261ecSmrg            box.y1 = pRects->y + pRects->height - offset1;
92805b261ecSmrg            box.x2 = box.x1 + pRects->width + offset2;
92905b261ecSmrg            box.y2 = box.y1 + offset2;
93005b261ecSmrg            TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
93105b261ecSmrg            if (BOX_NOT_EMPTY(box))
93235c4bbdfSmrg                RootlessDamageBox((WindowPtr) dst, &box);
93305b261ecSmrg
93405b261ecSmrg            pRects++;
93505b261ecSmrg        }
93605b261ecSmrg    }
93705b261ecSmrg
93805b261ecSmrg    GCOP_WRAP(pGC);
93905b261ecSmrg    RL_DEBUG_MSG("poly rectangle end\n");
94005b261ecSmrg}
94105b261ecSmrg
94205b261ecSmrg/* changed area is box around each arc (assumes all arcs are 360 degrees) */
94335c4bbdfSmrgstatic void
94435c4bbdfSmrgRootlessPolyArc(DrawablePtr dst, GCPtr pGC, int narcs, xArc * parcs)
94505b261ecSmrg{
94605b261ecSmrg    GCOP_UNWRAP(pGC);
94705b261ecSmrg    RL_DEBUG_MSG("poly arc start ");
94805b261ecSmrg
94905b261ecSmrg    RootlessStartDrawing((WindowPtr) dst);
95005b261ecSmrg    pGC->ops->PolyArc(dst, pGC, narcs, parcs);
95105b261ecSmrg
95205b261ecSmrg    if (narcs > 0) {
95305b261ecSmrg        int extra = pGC->lineWidth >> 1;
95405b261ecSmrg        BoxRec box;
95505b261ecSmrg
95605b261ecSmrg        box.x1 = parcs->x;
95705b261ecSmrg        box.x2 = box.x1 + parcs->width;
95805b261ecSmrg        box.y1 = parcs->y;
95905b261ecSmrg        box.y2 = box.y1 + parcs->height;
96005b261ecSmrg
96105b261ecSmrg        /* should I break these up instead ? */
96205b261ecSmrg
96305b261ecSmrg        while (--narcs) {
96405b261ecSmrg            parcs++;
96505b261ecSmrg            if (box.x1 > parcs->x)
96605b261ecSmrg                box.x1 = parcs->x;
96705b261ecSmrg            if (box.x2 < (parcs->x + parcs->width))
96805b261ecSmrg                box.x2 = parcs->x + parcs->width;
96905b261ecSmrg            if (box.y1 > parcs->y)
97005b261ecSmrg                box.y1 = parcs->y;
97105b261ecSmrg            if (box.y2 < (parcs->y + parcs->height))
97205b261ecSmrg                box.y2 = parcs->y + parcs->height;
97305b261ecSmrg        }
97405b261ecSmrg
97505b261ecSmrg        if (extra) {
97605b261ecSmrg            box.x1 -= extra;
97705b261ecSmrg            box.x2 += extra;
97805b261ecSmrg            box.y1 -= extra;
97905b261ecSmrg            box.y2 += extra;
98005b261ecSmrg        }
98105b261ecSmrg
98205b261ecSmrg        box.x2++;
98305b261ecSmrg        box.y2++;
98405b261ecSmrg
98505b261ecSmrg        TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
98605b261ecSmrg        if (BOX_NOT_EMPTY(box))
98735c4bbdfSmrg            RootlessDamageBox((WindowPtr) dst, &box);
98805b261ecSmrg    }
98905b261ecSmrg
99005b261ecSmrg    GCOP_WRAP(pGC);
99105b261ecSmrg    RL_DEBUG_MSG("poly arc end\n");
99205b261ecSmrg}
99305b261ecSmrg
99405b261ecSmrg/* changed area is box around each poly */
99535c4bbdfSmrgstatic void
99635c4bbdfSmrgRootlessFillPolygon(DrawablePtr dst, GCPtr pGC,
99735c4bbdfSmrg                    int shape, int mode, int count, DDXPointPtr pptInit)
99805b261ecSmrg{
99905b261ecSmrg    GC_SAVE(pGC);
100005b261ecSmrg    GCOP_UNWRAP(pGC);
100105b261ecSmrg    RL_DEBUG_MSG("fill poly start (win 0x%x, fillStyle 0x%x)", dst,
100205b261ecSmrg                 pGC->fillStyle);
100305b261ecSmrg
100405b261ecSmrg    if (count <= 2) {
100505b261ecSmrg        pGC->ops->FillPolygon(dst, pGC, shape, mode, count, pptInit);
100635c4bbdfSmrg    }
100735c4bbdfSmrg    else {
100805b261ecSmrg        DDXPointPtr ppt = pptInit;
100905b261ecSmrg        int i = count;
101005b261ecSmrg        BoxRec box;
101105b261ecSmrg
101205b261ecSmrg        box.x2 = box.x1 = ppt->x;
101305b261ecSmrg        box.y2 = box.y1 = ppt->y;
101405b261ecSmrg
101505b261ecSmrg        if (mode != CoordModeOrigin) {
101605b261ecSmrg            int x = box.x1;
101705b261ecSmrg            int y = box.y1;
101805b261ecSmrg
101905b261ecSmrg            while (--i) {
102005b261ecSmrg                ppt++;
102105b261ecSmrg                x += ppt->x;
102205b261ecSmrg                y += ppt->y;
102305b261ecSmrg                if (box.x1 > x)
102405b261ecSmrg                    box.x1 = x;
102505b261ecSmrg                else if (box.x2 < x)
102605b261ecSmrg                    box.x2 = x;
102705b261ecSmrg                if (box.y1 > y)
102805b261ecSmrg                    box.y1 = y;
102905b261ecSmrg                else if (box.y2 < y)
103005b261ecSmrg                    box.y2 = y;
103105b261ecSmrg            }
103235c4bbdfSmrg        }
103335c4bbdfSmrg        else {
103405b261ecSmrg            while (--i) {
103505b261ecSmrg                ppt++;
103605b261ecSmrg                if (box.x1 > ppt->x)
103705b261ecSmrg                    box.x1 = ppt->x;
103805b261ecSmrg                else if (box.x2 < ppt->x)
103905b261ecSmrg                    box.x2 = ppt->x;
104005b261ecSmrg                if (box.y1 > ppt->y)
104105b261ecSmrg                    box.y1 = ppt->y;
104205b261ecSmrg                else if (box.y2 < ppt->y)
104305b261ecSmrg                    box.y2 = ppt->y;
104405b261ecSmrg            }
104505b261ecSmrg        }
104605b261ecSmrg
104705b261ecSmrg        box.x2++;
104805b261ecSmrg        box.y2++;
104905b261ecSmrg
105005b261ecSmrg        RootlessStartDrawing((WindowPtr) dst);
105105b261ecSmrg
105235c4bbdfSmrg        if (canAccelFill(dst, pGC)) {
105305b261ecSmrg            GC_UNSET_PM(pGC, dst);
105405b261ecSmrg        }
105505b261ecSmrg
105605b261ecSmrg        pGC->ops->FillPolygon(dst, pGC, shape, mode, count, pptInit);
105705b261ecSmrg
105805b261ecSmrg        TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
105905b261ecSmrg        if (BOX_NOT_EMPTY(box))
106035c4bbdfSmrg            RootlessDamageBox((WindowPtr) dst, &box);
106105b261ecSmrg    }
106205b261ecSmrg
106305b261ecSmrg    GC_RESTORE(pGC, dst);
106405b261ecSmrg    GCOP_WRAP(pGC);
106505b261ecSmrg    RL_DEBUG_MSG("fill poly end\n");
106605b261ecSmrg}
106705b261ecSmrg
106805b261ecSmrg/* changed area is the rects */
106935c4bbdfSmrgstatic void
107035c4bbdfSmrgRootlessPolyFillRect(DrawablePtr dst, GCPtr pGC,
107135c4bbdfSmrg                     int nRectsInit, xRectangle *pRectsInit)
107205b261ecSmrg{
107305b261ecSmrg    GC_SAVE(pGC);
107405b261ecSmrg    GCOP_UNWRAP(pGC);
107505b261ecSmrg    RL_DEBUG_MSG("fill rect start (win 0x%x, fillStyle 0x%x)", dst,
107605b261ecSmrg                 pGC->fillStyle);
107705b261ecSmrg
107805b261ecSmrg    if (nRectsInit <= 0) {
107905b261ecSmrg        pGC->ops->PolyFillRect(dst, pGC, nRectsInit, pRectsInit);
108035c4bbdfSmrg    }
108135c4bbdfSmrg    else {
108205b261ecSmrg        BoxRec box;
108305b261ecSmrg        xRectangle *pRects = pRectsInit;
108405b261ecSmrg        int nRects = nRectsInit;
108505b261ecSmrg
108605b261ecSmrg        box.x1 = pRects->x;
108705b261ecSmrg        box.x2 = box.x1 + pRects->width;
108805b261ecSmrg        box.y1 = pRects->y;
108905b261ecSmrg        box.y2 = box.y1 + pRects->height;
109005b261ecSmrg
109105b261ecSmrg        while (--nRects) {
109205b261ecSmrg            pRects++;
109305b261ecSmrg            if (box.x1 > pRects->x)
109405b261ecSmrg                box.x1 = pRects->x;
109505b261ecSmrg            if (box.x2 < (pRects->x + pRects->width))
109605b261ecSmrg                box.x2 = pRects->x + pRects->width;
109705b261ecSmrg            if (box.y1 > pRects->y)
109805b261ecSmrg                box.y1 = pRects->y;
109905b261ecSmrg            if (box.y2 < (pRects->y + pRects->height))
110005b261ecSmrg                box.y2 = pRects->y + pRects->height;
110105b261ecSmrg        }
110205b261ecSmrg
110305b261ecSmrg        RootlessStartDrawing((WindowPtr) dst);
110435c4bbdfSmrg
110535c4bbdfSmrg        if (canAccelFill(dst, pGC)) {
110605b261ecSmrg            GC_UNSET_PM(pGC, dst);
110705b261ecSmrg        }
110805b261ecSmrg
110935c4bbdfSmrg        pGC->ops->PolyFillRect(dst, pGC, nRectsInit, pRectsInit);
111005b261ecSmrg
111105b261ecSmrg        TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
111205b261ecSmrg        if (BOX_NOT_EMPTY(box))
111335c4bbdfSmrg            RootlessDamageBox((WindowPtr) dst, &box);
111405b261ecSmrg    }
111505b261ecSmrg
111605b261ecSmrg    GC_RESTORE(pGC, dst);
111705b261ecSmrg    GCOP_WRAP(pGC);
111805b261ecSmrg    RL_DEBUG_MSG("fill rect end\n");
111905b261ecSmrg}
112005b261ecSmrg
112105b261ecSmrg/* changed area is box around each arc (assuming arcs are all 360 degrees) */
112235c4bbdfSmrgstatic void
112335c4bbdfSmrgRootlessPolyFillArc(DrawablePtr dst, GCPtr pGC, int narcsInit, xArc * parcsInit)
112405b261ecSmrg{
112505b261ecSmrg    GC_SAVE(pGC);
112605b261ecSmrg    GCOP_UNWRAP(pGC);
112705b261ecSmrg    RL_DEBUG_MSG("fill arc start ");
112805b261ecSmrg
112905b261ecSmrg    if (narcsInit > 0) {
113005b261ecSmrg        BoxRec box;
113105b261ecSmrg        int narcs = narcsInit;
113205b261ecSmrg        xArc *parcs = parcsInit;
113305b261ecSmrg
113405b261ecSmrg        box.x1 = parcs->x;
113505b261ecSmrg        box.x2 = box.x1 + parcs->width;
113605b261ecSmrg        box.y1 = parcs->y;
113705b261ecSmrg        box.y2 = box.y1 + parcs->height;
113805b261ecSmrg
113905b261ecSmrg        /* should I break these up instead ? */
114005b261ecSmrg
114105b261ecSmrg        while (--narcs) {
114205b261ecSmrg            parcs++;
114305b261ecSmrg            if (box.x1 > parcs->x)
114405b261ecSmrg                box.x1 = parcs->x;
114505b261ecSmrg            if (box.x2 < (parcs->x + parcs->width))
114605b261ecSmrg                box.x2 = parcs->x + parcs->width;
114705b261ecSmrg            if (box.y1 > parcs->y)
114805b261ecSmrg                box.y1 = parcs->y;
114905b261ecSmrg            if (box.y2 < (parcs->y + parcs->height))
115005b261ecSmrg                box.y2 = parcs->y + parcs->height;
115105b261ecSmrg        }
115205b261ecSmrg
115305b261ecSmrg        RootlessStartDrawing((WindowPtr) dst);
115405b261ecSmrg
115535c4bbdfSmrg        if (canAccelFill(dst, pGC)) {
115605b261ecSmrg            GC_UNSET_PM(pGC, dst);
115705b261ecSmrg        }
115805b261ecSmrg
115905b261ecSmrg        pGC->ops->PolyFillArc(dst, pGC, narcsInit, parcsInit);
116005b261ecSmrg
116105b261ecSmrg        TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
116205b261ecSmrg        if (BOX_NOT_EMPTY(box))
116335c4bbdfSmrg            RootlessDamageBox((WindowPtr) dst, &box);
116435c4bbdfSmrg    }
116535c4bbdfSmrg    else {
116605b261ecSmrg        pGC->ops->PolyFillArc(dst, pGC, narcsInit, parcsInit);
116705b261ecSmrg    }
116805b261ecSmrg
116905b261ecSmrg    GC_RESTORE(pGC, dst);
117005b261ecSmrg    GCOP_WRAP(pGC);
117105b261ecSmrg    RL_DEBUG_MSG("fill arc end\n");
117205b261ecSmrg}
117305b261ecSmrg
117435c4bbdfSmrgstatic void
117535c4bbdfSmrgRootlessImageText8(DrawablePtr dst, GCPtr pGC,
117635c4bbdfSmrg                   int x, int y, int count, char *chars)
117705b261ecSmrg{
117805b261ecSmrg    GC_SAVE(pGC);
117905b261ecSmrg    GCOP_UNWRAP(pGC);
118005b261ecSmrg    RL_DEBUG_MSG("imagetext8 start ");
118105b261ecSmrg
118205b261ecSmrg    if (count > 0) {
118305b261ecSmrg        int top, bot, Min, Max;
118405b261ecSmrg        BoxRec box;
118505b261ecSmrg
118605b261ecSmrg        top = max(FONTMAXBOUNDS(pGC->font, ascent), FONTASCENT(pGC->font));
118705b261ecSmrg        bot = max(FONTMAXBOUNDS(pGC->font, descent), FONTDESCENT(pGC->font));
118805b261ecSmrg
118905b261ecSmrg        Min = count * FONTMINBOUNDS(pGC->font, characterWidth);
119035c4bbdfSmrg        if (Min > 0)
119135c4bbdfSmrg            Min = 0;
119205b261ecSmrg        Max = count * FONTMAXBOUNDS(pGC->font, characterWidth);
119335c4bbdfSmrg        if (Max < 0)
119435c4bbdfSmrg            Max = 0;
119505b261ecSmrg
119605b261ecSmrg        /* ugh */
119735c4bbdfSmrg        box.x1 = dst->x + x + Min + FONTMINBOUNDS(pGC->font, leftSideBearing);
119835c4bbdfSmrg        box.x2 = dst->x + x + Max + FONTMAXBOUNDS(pGC->font, rightSideBearing);
119905b261ecSmrg
120005b261ecSmrg        box.y1 = dst->y + y - top;
120105b261ecSmrg        box.y2 = dst->y + y + bot;
120205b261ecSmrg
120305b261ecSmrg        RootlessStartDrawing((WindowPtr) dst);
120405b261ecSmrg
120535c4bbdfSmrg        if (canAccelFill(dst, pGC)) {
120605b261ecSmrg            GC_UNSET_PM(pGC, dst);
120705b261ecSmrg        }
120805b261ecSmrg
120905b261ecSmrg        pGC->ops->ImageText8(dst, pGC, x, y, count, chars);
121005b261ecSmrg
121105b261ecSmrg        TRIM_BOX(box, pGC);
121205b261ecSmrg        if (BOX_NOT_EMPTY(box))
121335c4bbdfSmrg            RootlessDamageBox((WindowPtr) dst, &box);
121435c4bbdfSmrg    }
121535c4bbdfSmrg    else {
121605b261ecSmrg        pGC->ops->ImageText8(dst, pGC, x, y, count, chars);
121705b261ecSmrg    }
121805b261ecSmrg
121905b261ecSmrg    GC_RESTORE(pGC, dst);
122005b261ecSmrg    GCOP_WRAP(pGC);
122105b261ecSmrg    RL_DEBUG_MSG("imagetext8 end\n");
122205b261ecSmrg}
122305b261ecSmrg
122435c4bbdfSmrgstatic int
122535c4bbdfSmrgRootlessPolyText8(DrawablePtr dst, GCPtr pGC,
122635c4bbdfSmrg                  int x, int y, int count, char *chars)
122705b261ecSmrg{
122835c4bbdfSmrg    int width;                  // the result, sorta
122905b261ecSmrg
123005b261ecSmrg    GCOP_UNWRAP(pGC);
123105b261ecSmrg
123205b261ecSmrg    RL_DEBUG_MSG("polytext8 start ");
123305b261ecSmrg
123405b261ecSmrg    RootlessStartDrawing((WindowPtr) dst);
123505b261ecSmrg    width = pGC->ops->PolyText8(dst, pGC, x, y, count, chars);
123605b261ecSmrg    width -= x;
123705b261ecSmrg
123805b261ecSmrg    if (width > 0) {
123905b261ecSmrg        BoxRec box;
124005b261ecSmrg
124105b261ecSmrg        /* ugh */
124205b261ecSmrg        box.x1 = dst->x + x + FONTMINBOUNDS(pGC->font, leftSideBearing);
124305b261ecSmrg        box.x2 = dst->x + x + FONTMAXBOUNDS(pGC->font, rightSideBearing);
124405b261ecSmrg
124505b261ecSmrg        if (count > 1) {
1246ed6184dfSmrg            box.x2 += width;
124705b261ecSmrg        }
124805b261ecSmrg
124905b261ecSmrg        box.y1 = dst->y + y - FONTMAXBOUNDS(pGC->font, ascent);
125005b261ecSmrg        box.y2 = dst->y + y + FONTMAXBOUNDS(pGC->font, descent);
125105b261ecSmrg
125205b261ecSmrg        TRIM_BOX(box, pGC);
125305b261ecSmrg        if (BOX_NOT_EMPTY(box))
125435c4bbdfSmrg            RootlessDamageBox((WindowPtr) dst, &box);
125505b261ecSmrg    }
125605b261ecSmrg
125705b261ecSmrg    GCOP_WRAP(pGC);
125805b261ecSmrg    RL_DEBUG_MSG("polytext8 end\n");
12596747b715Smrg    return width + x;
126005b261ecSmrg}
126105b261ecSmrg
126235c4bbdfSmrgstatic void
126335c4bbdfSmrgRootlessImageText16(DrawablePtr dst, GCPtr pGC,
126435c4bbdfSmrg                    int x, int y, int count, unsigned short *chars)
126505b261ecSmrg{
126605b261ecSmrg    GC_SAVE(pGC);
126705b261ecSmrg    GCOP_UNWRAP(pGC);
126805b261ecSmrg    RL_DEBUG_MSG("imagetext16 start ");
126905b261ecSmrg
127005b261ecSmrg    if (count > 0) {
127105b261ecSmrg        int top, bot, Min, Max;
127205b261ecSmrg        BoxRec box;
127305b261ecSmrg
127405b261ecSmrg        top = max(FONTMAXBOUNDS(pGC->font, ascent), FONTASCENT(pGC->font));
127505b261ecSmrg        bot = max(FONTMAXBOUNDS(pGC->font, descent), FONTDESCENT(pGC->font));
127605b261ecSmrg
127705b261ecSmrg        Min = count * FONTMINBOUNDS(pGC->font, characterWidth);
127835c4bbdfSmrg        if (Min > 0)
127935c4bbdfSmrg            Min = 0;
128005b261ecSmrg        Max = count * FONTMAXBOUNDS(pGC->font, characterWidth);
128135c4bbdfSmrg        if (Max < 0)
128235c4bbdfSmrg            Max = 0;
128305b261ecSmrg
128405b261ecSmrg        /* ugh */
128535c4bbdfSmrg        box.x1 = dst->x + x + Min + FONTMINBOUNDS(pGC->font, leftSideBearing);
128635c4bbdfSmrg        box.x2 = dst->x + x + Max + FONTMAXBOUNDS(pGC->font, rightSideBearing);
128705b261ecSmrg
128805b261ecSmrg        box.y1 = dst->y + y - top;
128905b261ecSmrg        box.y2 = dst->y + y + bot;
129005b261ecSmrg
129105b261ecSmrg        RootlessStartDrawing((WindowPtr) dst);
129205b261ecSmrg
129335c4bbdfSmrg        if (canAccelFill(dst, pGC)) {
129405b261ecSmrg            GC_UNSET_PM(pGC, dst);
129505b261ecSmrg        }
129605b261ecSmrg
129705b261ecSmrg        pGC->ops->ImageText16(dst, pGC, x, y, count, chars);
129805b261ecSmrg
129905b261ecSmrg        TRIM_BOX(box, pGC);
130005b261ecSmrg        if (BOX_NOT_EMPTY(box))
130135c4bbdfSmrg            RootlessDamageBox((WindowPtr) dst, &box);
130235c4bbdfSmrg    }
130335c4bbdfSmrg    else {
130405b261ecSmrg        pGC->ops->ImageText16(dst, pGC, x, y, count, chars);
130505b261ecSmrg    }
130605b261ecSmrg
130705b261ecSmrg    GC_RESTORE(pGC, dst);
130805b261ecSmrg    GCOP_WRAP(pGC);
130905b261ecSmrg    RL_DEBUG_MSG("imagetext16 end\n");
131005b261ecSmrg}
131105b261ecSmrg
131235c4bbdfSmrgstatic int
131335c4bbdfSmrgRootlessPolyText16(DrawablePtr dst, GCPtr pGC,
131435c4bbdfSmrg                   int x, int y, int count, unsigned short *chars)
131505b261ecSmrg{
131635c4bbdfSmrg    int width;                  // the result, sorta
131705b261ecSmrg
131805b261ecSmrg    GCOP_UNWRAP(pGC);
131905b261ecSmrg
132005b261ecSmrg    RL_DEBUG_MSG("polytext16 start ");
132105b261ecSmrg
132205b261ecSmrg    RootlessStartDrawing((WindowPtr) dst);
132305b261ecSmrg    width = pGC->ops->PolyText16(dst, pGC, x, y, count, chars);
132405b261ecSmrg    width -= x;
132505b261ecSmrg
132605b261ecSmrg    if (width > 0) {
132705b261ecSmrg        BoxRec box;
132805b261ecSmrg
132905b261ecSmrg        /* ugh */
133005b261ecSmrg        box.x1 = dst->x + x + FONTMINBOUNDS(pGC->font, leftSideBearing);
133105b261ecSmrg        box.x2 = dst->x + x + FONTMAXBOUNDS(pGC->font, rightSideBearing);
133205b261ecSmrg
133305b261ecSmrg        if (count > 1) {
1334ed6184dfSmrg            box.x2 += width;
133505b261ecSmrg        }
133605b261ecSmrg
133705b261ecSmrg        box.y1 = dst->y + y - FONTMAXBOUNDS(pGC->font, ascent);
133805b261ecSmrg        box.y2 = dst->y + y + FONTMAXBOUNDS(pGC->font, descent);
133905b261ecSmrg
134005b261ecSmrg        TRIM_BOX(box, pGC);
134105b261ecSmrg        if (BOX_NOT_EMPTY(box))
134235c4bbdfSmrg            RootlessDamageBox((WindowPtr) dst, &box);
134305b261ecSmrg    }
134405b261ecSmrg
134505b261ecSmrg    GCOP_WRAP(pGC);
134605b261ecSmrg    RL_DEBUG_MSG("polytext16 end\n");
134705b261ecSmrg    return width + x;
134805b261ecSmrg}
134905b261ecSmrg
135035c4bbdfSmrgstatic void
135135c4bbdfSmrgRootlessImageGlyphBlt(DrawablePtr dst, GCPtr pGC,
135235c4bbdfSmrg                      int x, int y, unsigned int nglyphInit,
135335c4bbdfSmrg                      CharInfoPtr * ppciInit, void *unused)
135405b261ecSmrg{
135505b261ecSmrg    GC_SAVE(pGC);
135605b261ecSmrg    GCOP_UNWRAP(pGC);
135705b261ecSmrg    RL_DEBUG_MSG("imageglyph start ");
135805b261ecSmrg
135905b261ecSmrg    if (nglyphInit > 0) {
136005b261ecSmrg        int top, bot, width = 0;
136105b261ecSmrg        BoxRec box;
136205b261ecSmrg        unsigned int nglyph = nglyphInit;
136305b261ecSmrg        CharInfoPtr *ppci = ppciInit;
136405b261ecSmrg
136505b261ecSmrg        top = max(FONTMAXBOUNDS(pGC->font, ascent), FONTASCENT(pGC->font));
136605b261ecSmrg        bot = max(FONTMAXBOUNDS(pGC->font, descent), FONTDESCENT(pGC->font));
136705b261ecSmrg
136805b261ecSmrg        box.x1 = ppci[0]->metrics.leftSideBearing;
136935c4bbdfSmrg        if (box.x1 > 0)
137035c4bbdfSmrg            box.x1 = 0;
137105b261ecSmrg        box.x2 = ppci[nglyph - 1]->metrics.rightSideBearing -
137205b261ecSmrg            ppci[nglyph - 1]->metrics.characterWidth;
137335c4bbdfSmrg        if (box.x2 < 0)
137435c4bbdfSmrg            box.x2 = 0;
137505b261ecSmrg
137605b261ecSmrg        box.x2 += dst->x + x;
137705b261ecSmrg        box.x1 += dst->x + x;
137805b261ecSmrg
137905b261ecSmrg        while (nglyph--) {
138005b261ecSmrg            width += (*ppci)->metrics.characterWidth;
138105b261ecSmrg            ppci++;
138205b261ecSmrg        }
138305b261ecSmrg
138405b261ecSmrg        if (width > 0)
138505b261ecSmrg            box.x2 += width;
138605b261ecSmrg        else
138705b261ecSmrg            box.x1 += width;
138805b261ecSmrg
138905b261ecSmrg        box.y1 = dst->y + y - top;
139005b261ecSmrg        box.y2 = dst->y + y + bot;
139105b261ecSmrg
139205b261ecSmrg        RootlessStartDrawing((WindowPtr) dst);
139305b261ecSmrg
139435c4bbdfSmrg        if (canAccelFill(dst, pGC)) {
139505b261ecSmrg            GC_UNSET_PM(pGC, dst);
139605b261ecSmrg        }
139705b261ecSmrg
139805b261ecSmrg        pGC->ops->ImageGlyphBlt(dst, pGC, x, y, nglyphInit, ppciInit, unused);
139905b261ecSmrg
140005b261ecSmrg        TRIM_BOX(box, pGC);
140105b261ecSmrg        if (BOX_NOT_EMPTY(box))
140235c4bbdfSmrg            RootlessDamageBox((WindowPtr) dst, &box);
140335c4bbdfSmrg    }
140435c4bbdfSmrg    else {
140505b261ecSmrg        pGC->ops->ImageGlyphBlt(dst, pGC, x, y, nglyphInit, ppciInit, unused);
140605b261ecSmrg    }
140705b261ecSmrg
140805b261ecSmrg    GC_RESTORE(pGC, dst);
140905b261ecSmrg    GCOP_WRAP(pGC);
141005b261ecSmrg    RL_DEBUG_MSG("imageglyph end\n");
141105b261ecSmrg}
141205b261ecSmrg
141335c4bbdfSmrgstatic void
141435c4bbdfSmrgRootlessPolyGlyphBlt(DrawablePtr dst, GCPtr pGC,
141535c4bbdfSmrg                     int x, int y, unsigned int nglyph,
141635c4bbdfSmrg                     CharInfoPtr * ppci, void *pglyphBase)
141705b261ecSmrg{
141805b261ecSmrg    GCOP_UNWRAP(pGC);
141905b261ecSmrg    RL_DEBUG_MSG("polyglyph start ");
142005b261ecSmrg
142105b261ecSmrg    RootlessStartDrawing((WindowPtr) dst);
142205b261ecSmrg    pGC->ops->PolyGlyphBlt(dst, pGC, x, y, nglyph, ppci, pglyphBase);
142305b261ecSmrg
142405b261ecSmrg    if (nglyph > 0) {
142505b261ecSmrg        BoxRec box;
142605b261ecSmrg
142705b261ecSmrg        /* ugh */
142805b261ecSmrg        box.x1 = dst->x + x + ppci[0]->metrics.leftSideBearing;
142905b261ecSmrg        box.x2 = dst->x + x + ppci[nglyph - 1]->metrics.rightSideBearing;
143005b261ecSmrg
143105b261ecSmrg        if (nglyph > 1) {
143205b261ecSmrg            int width = 0;
143305b261ecSmrg
143405b261ecSmrg            while (--nglyph) {
143505b261ecSmrg                width += (*ppci)->metrics.characterWidth;
143605b261ecSmrg                ppci++;
143705b261ecSmrg            }
143805b261ecSmrg
143935c4bbdfSmrg            if (width > 0)
144035c4bbdfSmrg                box.x2 += width;
144135c4bbdfSmrg            else
144235c4bbdfSmrg                box.x1 += width;
144305b261ecSmrg        }
144405b261ecSmrg
144505b261ecSmrg        box.y1 = dst->y + y - FONTMAXBOUNDS(pGC->font, ascent);
144605b261ecSmrg        box.y2 = dst->y + y + FONTMAXBOUNDS(pGC->font, descent);
144705b261ecSmrg
144805b261ecSmrg        TRIM_BOX(box, pGC);
144905b261ecSmrg        if (BOX_NOT_EMPTY(box))
145035c4bbdfSmrg            RootlessDamageBox((WindowPtr) dst, &box);
145105b261ecSmrg    }
145205b261ecSmrg
145305b261ecSmrg    GCOP_WRAP(pGC);
145405b261ecSmrg    RL_DEBUG_MSG("polyglyph end\n");
145505b261ecSmrg}
145605b261ecSmrg
145705b261ecSmrg/* changed area is in dest */
145805b261ecSmrgstatic void
145905b261ecSmrgRootlessPushPixels(GCPtr pGC, PixmapPtr pBitMap, DrawablePtr dst,
146005b261ecSmrg                   int dx, int dy, int xOrg, int yOrg)
146105b261ecSmrg{
146205b261ecSmrg    BoxRec box;
146305b261ecSmrg
146405b261ecSmrg    GCOP_UNWRAP(pGC);
146505b261ecSmrg    RL_DEBUG_MSG("push pixels start ");
146605b261ecSmrg
146705b261ecSmrg    RootlessStartDrawing((WindowPtr) dst);
146805b261ecSmrg    pGC->ops->PushPixels(pGC, pBitMap, dst, dx, dy, xOrg, yOrg);
146905b261ecSmrg
147005b261ecSmrg    box.x1 = xOrg + dst->x;
147105b261ecSmrg    box.x2 = box.x1 + dx;
147205b261ecSmrg    box.y1 = yOrg + dst->y;
147305b261ecSmrg    box.y2 = box.y1 + dy;
147405b261ecSmrg
147505b261ecSmrg    TRIM_BOX(box, pGC);
147605b261ecSmrg    if (BOX_NOT_EMPTY(box))
147735c4bbdfSmrg        RootlessDamageBox((WindowPtr) dst, &box);
147805b261ecSmrg
147905b261ecSmrg    GCOP_WRAP(pGC);
148005b261ecSmrg    RL_DEBUG_MSG("push pixels end\n");
148105b261ecSmrg}
1482