rootlessGC.c revision 4642e01f
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
3605b261ecSmrg#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
5305b261ecSmrg// GC functions
5405b261ecSmrgstatic void RootlessValidateGC(GCPtr pGC, unsigned long changes,
5505b261ecSmrg                               DrawablePtr pDrawable);
5605b261ecSmrgstatic void RootlessChangeGC(GCPtr pGC, unsigned long mask);
5705b261ecSmrgstatic void RootlessCopyGC(GCPtr pGCSrc, unsigned long mask, GCPtr pGCDst);
5805b261ecSmrgstatic void RootlessDestroyGC(GCPtr pGC);
5905b261ecSmrgstatic void RootlessChangeClip(GCPtr pGC, int type, pointer pvalue,
6005b261ecSmrg                               int nrects);
6105b261ecSmrgstatic void RootlessDestroyClip(GCPtr pGC);
6205b261ecSmrgstatic void RootlessCopyClip(GCPtr pgcDst, GCPtr pgcSrc);
6305b261ecSmrg
644642e01fSmrgBool RootlessCreateGC(GCPtr pGC);
654642e01fSmrg
6605b261ecSmrgGCFuncs rootlessGCFuncs = {
6705b261ecSmrg    RootlessValidateGC,
6805b261ecSmrg    RootlessChangeGC,
6905b261ecSmrg    RootlessCopyGC,
7005b261ecSmrg    RootlessDestroyGC,
7105b261ecSmrg    RootlessChangeClip,
7205b261ecSmrg    RootlessDestroyClip,
7305b261ecSmrg    RootlessCopyClip,
7405b261ecSmrg};
7505b261ecSmrg
7605b261ecSmrg// GC operations
774642e01fSmrgstatic void RootlessFillSpans(DrawablePtr dst, GCPtr pGC, int nInit,
784642e01fSmrg			      DDXPointPtr pptInit, int *pwidthInit,
794642e01fSmrg			      int sorted);
804642e01fSmrgstatic void RootlessSetSpans(DrawablePtr dst, GCPtr pGC, char *pSrc,
814642e01fSmrg			     DDXPointPtr pptInit, int *pwidthInit,
824642e01fSmrg			     int nspans, int sorted);
834642e01fSmrgstatic void RootlessPutImage(DrawablePtr dst, GCPtr pGC,
844642e01fSmrg			     int depth, int x, int y, int w, int h,
854642e01fSmrg			     int leftPad, int format, char *pBits);
864642e01fSmrgstatic RegionPtr RootlessCopyArea(DrawablePtr pSrc, DrawablePtr dst, GCPtr pGC,
874642e01fSmrg				  int srcx, int srcy, int w, int h,
884642e01fSmrg				  int dstx, int dsty);
894642e01fSmrgstatic RegionPtr RootlessCopyPlane(DrawablePtr pSrc, DrawablePtr dst,
904642e01fSmrg                                   GCPtr pGC, int srcx, int srcy,
914642e01fSmrg                                   int w, int h, int dstx, int dsty,
924642e01fSmrg                                   unsigned long plane);
934642e01fSmrgstatic void RootlessPolyPoint(DrawablePtr dst, GCPtr pGC,
944642e01fSmrg                              int mode, int npt, DDXPointPtr pptInit);
954642e01fSmrgstatic void RootlessPolylines(DrawablePtr dst, GCPtr pGC,
964642e01fSmrg                              int mode, int npt, DDXPointPtr pptInit);
974642e01fSmrgstatic void RootlessPolySegment(DrawablePtr dst, GCPtr pGC,
984642e01fSmrg                                int nseg, xSegment *pSeg);
994642e01fSmrgstatic void RootlessPolyRectangle(DrawablePtr dst, GCPtr pGC,
1004642e01fSmrg                                  int nRects, xRectangle *pRects);
1014642e01fSmrgstatic void RootlessPolyArc(DrawablePtr dst, GCPtr pGC, int narcs, xArc *parcs);
1024642e01fSmrgstatic void RootlessFillPolygon(DrawablePtr dst, GCPtr pGC,
1034642e01fSmrg                                int shape, int mode, int count,
1044642e01fSmrg                                DDXPointPtr pptInit);
1054642e01fSmrgstatic void RootlessPolyFillRect(DrawablePtr dst, GCPtr pGC,
1064642e01fSmrg                                 int nRectsInit, xRectangle *pRectsInit);
1074642e01fSmrgstatic void RootlessPolyFillArc(DrawablePtr dst, GCPtr pGC,
1084642e01fSmrg                                int narcsInit, xArc *parcsInit);
1094642e01fSmrgstatic int RootlessPolyText8(DrawablePtr dst, GCPtr pGC,
1104642e01fSmrg			     int x, int y, int count, char *chars);
1114642e01fSmrgstatic int RootlessPolyText16(DrawablePtr dst, GCPtr pGC,
1124642e01fSmrg			      int x, int y, int count, unsigned short *chars);
1134642e01fSmrgstatic void RootlessImageText8(DrawablePtr dst, GCPtr pGC,
1144642e01fSmrg                               int x, int y, int count, char *chars);
1154642e01fSmrgstatic void RootlessImageText16(DrawablePtr dst, GCPtr pGC,
1164642e01fSmrg                                int x, int y, int count, unsigned short *chars);
1174642e01fSmrgstatic void RootlessImageGlyphBlt(DrawablePtr dst, GCPtr pGC,
1184642e01fSmrg                                  int x, int y, unsigned int nglyphInit,
1194642e01fSmrg                                  CharInfoPtr *ppciInit, pointer unused);
1204642e01fSmrgstatic void RootlessPolyGlyphBlt(DrawablePtr dst, GCPtr pGC,
1214642e01fSmrg                                 int x, int y, unsigned int nglyph,
1224642e01fSmrg                                 CharInfoPtr *ppci, pointer pglyphBase);
1234642e01fSmrgstatic void RootlessPushPixels(GCPtr pGC, PixmapPtr pBitMap, DrawablePtr dst,
1244642e01fSmrg			       int dx, int dy, int xOrg, int yOrg);
1254642e01fSmrg
12605b261ecSmrg
12705b261ecSmrgstatic GCOps rootlessGCOps = {
12805b261ecSmrg    RootlessFillSpans,
12905b261ecSmrg    RootlessSetSpans,
13005b261ecSmrg    RootlessPutImage,
13105b261ecSmrg    RootlessCopyArea,
13205b261ecSmrg    RootlessCopyPlane,
13305b261ecSmrg    RootlessPolyPoint,
13405b261ecSmrg    RootlessPolylines,
13505b261ecSmrg    RootlessPolySegment,
13605b261ecSmrg    RootlessPolyRectangle,
13705b261ecSmrg    RootlessPolyArc,
13805b261ecSmrg    RootlessFillPolygon,
13905b261ecSmrg    RootlessPolyFillRect,
14005b261ecSmrg    RootlessPolyFillArc,
14105b261ecSmrg    RootlessPolyText8,
14205b261ecSmrg    RootlessPolyText16,
14305b261ecSmrg    RootlessImageText8,
14405b261ecSmrg    RootlessImageText16,
14505b261ecSmrg    RootlessImageGlyphBlt,
14605b261ecSmrg    RootlessPolyGlyphBlt,
14705b261ecSmrg    RootlessPushPixels
14805b261ecSmrg};
14905b261ecSmrg
15005b261ecSmrg/*
15105b261ecSmrg   There are two issues we must contend with when drawing. These are
1524642e01fSmrg   controlled with ROOTLESS_PROTECT_ALPHA and RootlessAccelInit().
15305b261ecSmrg
15405b261ecSmrg   If ROOTLESS_PROTECT_ALPHA is set, we have to make sure that the alpha
15505b261ecSmrg   channel of the on screen windows is always opaque. fb makes this harder
15605b261ecSmrg   than it would otherwise be by noticing that a planemask of 0x00ffffff
15705b261ecSmrg   includes all bits when depth==24, and so it "optimizes" the planemask to
15805b261ecSmrg   0xffffffff. We work around this by temporarily setting depth=bpp while
15905b261ecSmrg   changing the GC.
16005b261ecSmrg
16105b261ecSmrg   So the normal situation (in 32 bit mode) is that the planemask is
16205b261ecSmrg   0x00ffffff and thus fb leaves the alpha channel alone. The rootless
16305b261ecSmrg   implementation is responsible for setting the alpha channel opaque
16405b261ecSmrg   initially.
16505b261ecSmrg
16605b261ecSmrg   Unfortunately drawing with a planemask that doesn't have all bits set
16705b261ecSmrg   normally causes fb to fall off its fastest paths when blitting and
16805b261ecSmrg   filling.  So we try to recognize when we can relax the planemask back to
16905b261ecSmrg   0xffffffff, and do that for the duration of the drawing operation,
17005b261ecSmrg   setting the alpha channel in fg/bg pixels to opaque at the same time. We
17105b261ecSmrg   can do this when drawing op is GXcopy. We can also do this when copying
17205b261ecSmrg   from another window since its alpha channel must also be opaque.
17305b261ecSmrg
17405b261ecSmrg   The other issue to consider is that the rootless implementation may
1754642e01fSmrg   provide accelerated drawing functions if RootlessAccelInit() is called.For
1764642e01fSmrg   some drawing primitives we swap in rootless acceleration functions, which
1774642e01fSmrg   use the accelerated drawing functions where possible.
17805b261ecSmrg
17905b261ecSmrg   Where both alpha protection and acceleration is used, it is even a bigger
18005b261ecSmrg   win to relax the planemask to all ones because most accelerated drawing
18105b261ecSmrg   functions can only be used in this case. However, even if we can't set
18205b261ecSmrg   the planemask to all ones, we can still use the accelerated
18305b261ecSmrg   CompositePixels function for GXcopy if it is a forward copy. This is
18405b261ecSmrg   mainly intended for copying from pixmaps to windows. The CompositePixels
18505b261ecSmrg   operation used sets alpha to 0xFF during the copy.
18605b261ecSmrg
18705b261ecSmrg   The three macros below are used to implement this, potentially accelerated
18805b261ecSmrg   drawing ops look something like this:
18905b261ecSmrg
19005b261ecSmrg   OP {
19105b261ecSmrg       GC_SAVE(gc);
19205b261ecSmrg       GCOP_UNWRAP(gc);
19305b261ecSmrg
19405b261ecSmrg       ...
19505b261ecSmrg
19605b261ecSmrg       if (canAccelxxx(..) && otherwise-suitable)
19705b261ecSmrg            GC_UNSET_PM(gc, dst);
19805b261ecSmrg
19905b261ecSmrg       gc->funcs->OP(gc, ...);
20005b261ecSmrg
20105b261ecSmrg       GC_RESTORE(gc, dst);
20205b261ecSmrg       GCOP_WRAP(gc);
20305b261ecSmrg   }
20405b261ecSmrg
20505b261ecSmrg */
20605b261ecSmrg
20705b261ecSmrg#define GC_SAVE(pGC) 				\
20805b261ecSmrg    unsigned long _save_fg = (pGC)->fgPixel;	\
20905b261ecSmrg    unsigned long _save_bg = (pGC)->bgPixel;	\
21005b261ecSmrg    unsigned long _save_pm = (pGC)->planemask;	\
21105b261ecSmrg    Bool _changed = FALSE
21205b261ecSmrg
21305b261ecSmrg#define GC_RESTORE(pGC, pDraw)					\
21405b261ecSmrg    do {							\
21505b261ecSmrg        if (_changed) {						\
21605b261ecSmrg            unsigned int depth = (pDraw)->depth;		\
21705b261ecSmrg            (pGC)->fgPixel = _save_fg;				\
21805b261ecSmrg            (pGC)->bgPixel = _save_bg;				\
21905b261ecSmrg            (pGC)->planemask = _save_pm;			\
22005b261ecSmrg            (pDraw)->depth = (pDraw)->bitsPerPixel;		\
22105b261ecSmrg            VALIDATE_GC(pGC, GCForeground | GCBackground |	\
22205b261ecSmrg                        GCPlaneMask, pDraw);			\
22305b261ecSmrg            (pDraw)->depth = depth;				\
22405b261ecSmrg        }							\
22505b261ecSmrg    } while (0)
22605b261ecSmrg
22705b261ecSmrg#define GC_UNSET_PM(pGC, pDraw)						\
22805b261ecSmrg    do {								\
22905b261ecSmrg        unsigned int mask = RootlessAlphaMask ((pDraw)->bitsPerPixel);	\
23005b261ecSmrg        if (((pGC)->planemask & mask) != mask) {			\
23105b261ecSmrg            unsigned int depth = (pDraw)->depth;			\
23205b261ecSmrg            (pGC)->fgPixel |= mask;					\
23305b261ecSmrg            (pGC)->bgPixel |= mask;					\
23405b261ecSmrg            (pGC)->planemask |= mask;					\
23505b261ecSmrg            (pDraw)->depth = (pDraw)->bitsPerPixel;			\
23605b261ecSmrg            VALIDATE_GC(pGC, GCForeground |				\
23705b261ecSmrg                        GCBackground | GCPlaneMask, pDraw);		\
23805b261ecSmrg            (pDraw)->depth = depth;					\
23905b261ecSmrg            _changed = TRUE;						\
24005b261ecSmrg        }								\
24105b261ecSmrg    } while (0)
24205b261ecSmrg
24305b261ecSmrg#define VALIDATE_GC(pGC, changes, pDrawable)				\
24405b261ecSmrg    do {								\
24505b261ecSmrg        pGC->funcs->ValidateGC(pGC, changes, pDrawable);		\
24605b261ecSmrg        if (((WindowPtr) pDrawable)->viewable) {			\
24705b261ecSmrg            gcrec->originalOps = pGC->ops;				\
24805b261ecSmrg        }								\
24905b261ecSmrg    } while(0)
25005b261ecSmrg
25105b261ecSmrgstatic RootlessWindowRec *
25205b261ecSmrgcanAccelBlit (DrawablePtr pDraw, GCPtr pGC)
25305b261ecSmrg{
25405b261ecSmrg    WindowPtr pTop;
25505b261ecSmrg    RootlessWindowRec *winRec;
25605b261ecSmrg    unsigned int pm;
25705b261ecSmrg
25805b261ecSmrg    if (pGC->alu != GXcopy)
25905b261ecSmrg        return NULL;
26005b261ecSmrg
26105b261ecSmrg    if (pDraw->type != DRAWABLE_WINDOW)
26205b261ecSmrg        return NULL;
26305b261ecSmrg
26405b261ecSmrg    pm = ~RootlessAlphaMask(pDraw->bitsPerPixel);
26505b261ecSmrg    if ((pGC->planemask & pm) != pm)
26605b261ecSmrg        return NULL;
26705b261ecSmrg
26805b261ecSmrg    pTop = TopLevelParent((WindowPtr) pDraw);
26905b261ecSmrg    if (pTop == NULL)
27005b261ecSmrg        return NULL;
27105b261ecSmrg
27205b261ecSmrg    winRec = WINREC(pTop);
27305b261ecSmrg    if (winRec == NULL)
27405b261ecSmrg        return NULL;
27505b261ecSmrg
27605b261ecSmrg    return winRec;
27705b261ecSmrg}
27805b261ecSmrg
27905b261ecSmrgstatic inline RootlessWindowRec *
28005b261ecSmrgcanAccelFill(DrawablePtr pDraw, GCPtr pGC)
28105b261ecSmrg{
28205b261ecSmrg    if (pGC->fillStyle != FillSolid)
28305b261ecSmrg        return NULL;
28405b261ecSmrg
28505b261ecSmrg    return canAccelBlit(pDraw, pGC);
28605b261ecSmrg}
28705b261ecSmrg
28805b261ecSmrgstatic unsigned int
28905b261ecSmrgboxBytes(DrawablePtr pDraw, BoxRec *box)
29005b261ecSmrg{
29105b261ecSmrg    unsigned int pixels;
29205b261ecSmrg
29305b261ecSmrg    pixels = (box->x2 - box->x1) * (box->y2 - box->y1);
29405b261ecSmrg
29505b261ecSmrg    return pixels * (pDraw->bitsPerPixel >> 3);
29605b261ecSmrg}
29705b261ecSmrg
29805b261ecSmrg
29905b261ecSmrg/*
30005b261ecSmrg * Screen function to create a graphics context
30105b261ecSmrg */
30205b261ecSmrgBool
30305b261ecSmrgRootlessCreateGC(GCPtr pGC)
30405b261ecSmrg{
30505b261ecSmrg    RootlessGCRec *gcrec;
30605b261ecSmrg    RootlessScreenRec *s;
30705b261ecSmrg    Bool result;
30805b261ecSmrg
30905b261ecSmrg    SCREEN_UNWRAP(pGC->pScreen, CreateGC);
3104642e01fSmrg    s = SCREENREC(pGC->pScreen);
31105b261ecSmrg    result = s->CreateGC(pGC);
31205b261ecSmrg
3134642e01fSmrg    gcrec = (RootlessGCRec *)
3144642e01fSmrg	dixLookupPrivate(&pGC->devPrivates, rootlessGCPrivateKey);
31505b261ecSmrg    gcrec->originalOps = NULL; // don't wrap ops yet
31605b261ecSmrg    gcrec->originalFuncs = pGC->funcs;
31705b261ecSmrg    pGC->funcs = &rootlessGCFuncs;
31805b261ecSmrg
31905b261ecSmrg    SCREEN_WRAP(pGC->pScreen, CreateGC);
32005b261ecSmrg    return result;
32105b261ecSmrg}
32205b261ecSmrg
32305b261ecSmrg
32405b261ecSmrg/*
32505b261ecSmrg * GC funcs
32605b261ecSmrg *
32705b261ecSmrg * These wrap lower level GC funcs.
32805b261ecSmrg * ValidateGC wraps the GC ops iff dest is viewable.
32905b261ecSmrg * All the others just unwrap and call.
33005b261ecSmrg */
33105b261ecSmrg
33205b261ecSmrg// GCFUNC_UNRAP assumes funcs have been wrapped and
33305b261ecSmrg// does not assume ops have been wrapped
33405b261ecSmrg#define GCFUNC_UNWRAP(pGC) \
33505b261ecSmrg    RootlessGCRec *gcrec = (RootlessGCRec *) \
3364642e01fSmrg	dixLookupPrivate(&(pGC)->devPrivates, rootlessGCPrivateKey); \
33705b261ecSmrg    (pGC)->funcs = gcrec->originalFuncs; \
33805b261ecSmrg    if (gcrec->originalOps) { \
33905b261ecSmrg        (pGC)->ops = gcrec->originalOps; \
34005b261ecSmrg}
34105b261ecSmrg
34205b261ecSmrg#define GCFUNC_WRAP(pGC) \
34305b261ecSmrg    gcrec->originalFuncs = (pGC)->funcs; \
34405b261ecSmrg    (pGC)->funcs = &rootlessGCFuncs; \
34505b261ecSmrg    if (gcrec->originalOps) { \
34605b261ecSmrg        gcrec->originalOps = (pGC)->ops; \
34705b261ecSmrg        (pGC)->ops = &rootlessGCOps; \
34805b261ecSmrg}
34905b261ecSmrg
35005b261ecSmrg
35105b261ecSmrgstatic void
35205b261ecSmrgRootlessValidateGC(GCPtr pGC, unsigned long changes, DrawablePtr pDrawable)
35305b261ecSmrg{
35405b261ecSmrg    GCFUNC_UNWRAP(pGC);
35505b261ecSmrg
35605b261ecSmrg    gcrec->originalOps = NULL;
35705b261ecSmrg
35805b261ecSmrg    if (pDrawable->type == DRAWABLE_WINDOW)
35905b261ecSmrg    {
36005b261ecSmrg#ifdef ROOTLESS_PROTECT_ALPHA
36105b261ecSmrg        unsigned int depth = pDrawable->depth;
36205b261ecSmrg
36305b261ecSmrg        // We force a planemask so fb doesn't overwrite the alpha channel.
36405b261ecSmrg        // Left to its own devices, fb will optimize away the planemask.
36505b261ecSmrg        pDrawable->depth = pDrawable->bitsPerPixel;
36605b261ecSmrg        pGC->planemask &= ~RootlessAlphaMask(pDrawable->bitsPerPixel);
36705b261ecSmrg        VALIDATE_GC(pGC, changes | GCPlaneMask, pDrawable);
36805b261ecSmrg        pDrawable->depth = depth;
36905b261ecSmrg#else
37005b261ecSmrg        VALIDATE_GC(pGC, changes, pDrawable);
37105b261ecSmrg#endif
37205b261ecSmrg    } else {
37305b261ecSmrg        pGC->funcs->ValidateGC(pGC, changes, pDrawable);
37405b261ecSmrg    }
37505b261ecSmrg
37605b261ecSmrg    GCFUNC_WRAP(pGC);
37705b261ecSmrg}
37805b261ecSmrg
37905b261ecSmrgstatic void RootlessChangeGC(GCPtr pGC, unsigned long mask)
38005b261ecSmrg{
38105b261ecSmrg    GCFUNC_UNWRAP(pGC);
38205b261ecSmrg    pGC->funcs->ChangeGC(pGC, mask);
38305b261ecSmrg    GCFUNC_WRAP(pGC);
38405b261ecSmrg}
38505b261ecSmrg
38605b261ecSmrgstatic void RootlessCopyGC(GCPtr pGCSrc, unsigned long mask, GCPtr pGCDst)
38705b261ecSmrg{
38805b261ecSmrg    GCFUNC_UNWRAP(pGCDst);
38905b261ecSmrg    pGCDst->funcs->CopyGC(pGCSrc, mask, pGCDst);
39005b261ecSmrg    GCFUNC_WRAP(pGCDst);
39105b261ecSmrg}
39205b261ecSmrg
39305b261ecSmrgstatic void RootlessDestroyGC(GCPtr pGC)
39405b261ecSmrg{
39505b261ecSmrg    GCFUNC_UNWRAP(pGC);
39605b261ecSmrg    pGC->funcs->DestroyGC(pGC);
39705b261ecSmrg    GCFUNC_WRAP(pGC);
39805b261ecSmrg}
39905b261ecSmrg
40005b261ecSmrgstatic void RootlessChangeClip(GCPtr pGC, int type, pointer pvalue, int nrects)
40105b261ecSmrg{
40205b261ecSmrg    GCFUNC_UNWRAP(pGC);
40305b261ecSmrg    pGC->funcs->ChangeClip(pGC, type, pvalue, nrects);
40405b261ecSmrg    GCFUNC_WRAP(pGC);
40505b261ecSmrg}
40605b261ecSmrg
40705b261ecSmrgstatic void RootlessDestroyClip(GCPtr pGC)
40805b261ecSmrg{
40905b261ecSmrg    GCFUNC_UNWRAP(pGC);
41005b261ecSmrg    pGC->funcs->DestroyClip(pGC);
41105b261ecSmrg    GCFUNC_WRAP(pGC);
41205b261ecSmrg}
41305b261ecSmrg
41405b261ecSmrgstatic void RootlessCopyClip(GCPtr pgcDst, GCPtr pgcSrc)
41505b261ecSmrg{
41605b261ecSmrg    GCFUNC_UNWRAP(pgcDst);
41705b261ecSmrg    pgcDst->funcs->CopyClip(pgcDst, pgcSrc);
41805b261ecSmrg    GCFUNC_WRAP(pgcDst);
41905b261ecSmrg}
42005b261ecSmrg
42105b261ecSmrg
42205b261ecSmrg/*
42305b261ecSmrg * GC ops
42405b261ecSmrg *
42505b261ecSmrg * We can't use shadowfb because shadowfb assumes one pixmap
42605b261ecSmrg * and our root window is a special case.
42705b261ecSmrg * However, much of this code is copied from shadowfb.
42805b261ecSmrg */
42905b261ecSmrg
43005b261ecSmrg// assumes both funcs and ops are wrapped
43105b261ecSmrg#define GCOP_UNWRAP(pGC) \
43205b261ecSmrg    RootlessGCRec *gcrec = (RootlessGCRec *) \
4334642e01fSmrg        dixLookupPrivate(&(pGC)->devPrivates, rootlessGCPrivateKey); \
43405b261ecSmrg    GCFuncs *saveFuncs = pGC->funcs; \
43505b261ecSmrg    (pGC)->funcs = gcrec->originalFuncs; \
43605b261ecSmrg    (pGC)->ops = gcrec->originalOps;
43705b261ecSmrg
43805b261ecSmrg#define GCOP_WRAP(pGC) \
43905b261ecSmrg    gcrec->originalOps = (pGC)->ops; \
44005b261ecSmrg    (pGC)->funcs = saveFuncs; \
44105b261ecSmrg    (pGC)->ops = &rootlessGCOps;
44205b261ecSmrg
44305b261ecSmrg/* Turn drawing on the root into a no-op */
44405b261ecSmrg#define GC_IS_ROOT(pDst) ((pDst)->type == DRAWABLE_WINDOW \
44505b261ecSmrg                            && IsRoot ((WindowPtr) (pDst)))
44605b261ecSmrg
4474642e01fSmrg#define GC_SKIP_ROOT(pDst, pGC)			\
44805b261ecSmrg    do {					\
4494642e01fSmrg        if (GC_IS_ROOT (pDst)) {		\
4504642e01fSmrg            GCOP_WRAP(pGC);			\
45105b261ecSmrg            return;				\
4524642e01fSmrg        }					\
45305b261ecSmrg    } while (0)
45405b261ecSmrg
45505b261ecSmrg
45605b261ecSmrgstatic void
45705b261ecSmrgRootlessFillSpans(DrawablePtr dst, GCPtr pGC, int nInit,
45805b261ecSmrg                  DDXPointPtr pptInit, int *pwidthInit, int sorted)
45905b261ecSmrg{
46005b261ecSmrg    GC_SAVE(pGC);
46105b261ecSmrg    GCOP_UNWRAP(pGC);
4624642e01fSmrg    GC_SKIP_ROOT(dst, pGC);
46305b261ecSmrg    RL_DEBUG_MSG("fill spans start ");
46405b261ecSmrg
46505b261ecSmrg    if (nInit <= 0) {
46605b261ecSmrg        pGC->ops->FillSpans(dst, pGC, nInit, pptInit, pwidthInit, sorted);
46705b261ecSmrg    } else {
46805b261ecSmrg        DDXPointPtr ppt = pptInit;
46905b261ecSmrg        int *pwidth = pwidthInit;
47005b261ecSmrg        int i = nInit;
47105b261ecSmrg        BoxRec box;
47205b261ecSmrg
47305b261ecSmrg        box.x1 = ppt->x;
47405b261ecSmrg        box.x2 = box.x1 + *pwidth;
47505b261ecSmrg        box.y2 = box.y1 = ppt->y;
47605b261ecSmrg
47705b261ecSmrg        while (--i) {
47805b261ecSmrg            ppt++;
47905b261ecSmrg            pwidth++;
48005b261ecSmrg            if (box.x1 > ppt->x)
48105b261ecSmrg                box.x1 = ppt->x;
48205b261ecSmrg            if (box.x2 < (ppt->x + *pwidth))
48305b261ecSmrg                box.x2 = ppt->x + *pwidth;
48405b261ecSmrg            if (box.y1 > ppt->y)
48505b261ecSmrg                box.y1 = ppt->y;
48605b261ecSmrg            else if (box.y2 < ppt->y)
48705b261ecSmrg                box.y2 = ppt->y;
48805b261ecSmrg        }
48905b261ecSmrg
49005b261ecSmrg        box.y2++;
49105b261ecSmrg
49205b261ecSmrg        RootlessStartDrawing((WindowPtr) dst);
49305b261ecSmrg
49405b261ecSmrg        if (canAccelFill(dst, pGC) &&
49505b261ecSmrg            boxBytes(dst, &box) >= rootless_FillBytes_threshold)
49605b261ecSmrg        {
49705b261ecSmrg            GC_UNSET_PM(pGC, dst);
49805b261ecSmrg        }
49905b261ecSmrg
50005b261ecSmrg        pGC->ops->FillSpans(dst, pGC, nInit, pptInit, pwidthInit, sorted);
50105b261ecSmrg
50205b261ecSmrg        TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
50305b261ecSmrg        if (BOX_NOT_EMPTY(box))
50405b261ecSmrg            RootlessDamageBox ((WindowPtr) dst, &box);
50505b261ecSmrg    }
50605b261ecSmrg
50705b261ecSmrg    GC_RESTORE(pGC, dst);
50805b261ecSmrg    GCOP_WRAP(pGC);
50905b261ecSmrg    RL_DEBUG_MSG("fill spans end\n");
51005b261ecSmrg}
51105b261ecSmrg
51205b261ecSmrgstatic void
51305b261ecSmrgRootlessSetSpans(DrawablePtr dst, GCPtr pGC, char *pSrc,
51405b261ecSmrg                 DDXPointPtr pptInit, int *pwidthInit,
51505b261ecSmrg                 int nspans, int sorted)
51605b261ecSmrg{
51705b261ecSmrg    GCOP_UNWRAP(pGC);
5184642e01fSmrg    GC_SKIP_ROOT(dst, pGC);
51905b261ecSmrg    RL_DEBUG_MSG("set spans start ");
52005b261ecSmrg
52105b261ecSmrg    if (nspans <= 0) {
52205b261ecSmrg        pGC->ops->SetSpans(dst, pGC, pSrc, pptInit, pwidthInit,
52305b261ecSmrg                           nspans, sorted);
52405b261ecSmrg    } else {
52505b261ecSmrg        DDXPointPtr ppt = pptInit;
52605b261ecSmrg        int *pwidth = pwidthInit;
52705b261ecSmrg        int i = nspans;
52805b261ecSmrg        BoxRec box;
52905b261ecSmrg
53005b261ecSmrg        box.x1 = ppt->x;
53105b261ecSmrg        box.x2 = box.x1 + *pwidth;
53205b261ecSmrg        box.y2 = box.y1 = ppt->y;
53305b261ecSmrg
53405b261ecSmrg        while (--i) {
53505b261ecSmrg            ppt++;
53605b261ecSmrg            pwidth++;
53705b261ecSmrg            if (box.x1 > ppt->x)
53805b261ecSmrg                box.x1 = ppt->x;
53905b261ecSmrg            if (box.x2 < (ppt->x + *pwidth))
54005b261ecSmrg                box.x2 = ppt->x + *pwidth;
54105b261ecSmrg            if (box.y1 > ppt->y)
54205b261ecSmrg                box.y1 = ppt->y;
54305b261ecSmrg            else if (box.y2 < ppt->y)
54405b261ecSmrg                box.y2 = ppt->y;
54505b261ecSmrg        }
54605b261ecSmrg
54705b261ecSmrg        box.y2++;
54805b261ecSmrg
54905b261ecSmrg        RootlessStartDrawing((WindowPtr) dst);
55005b261ecSmrg        pGC->ops->SetSpans(dst, pGC, pSrc, pptInit, pwidthInit,
55105b261ecSmrg                           nspans, sorted);
55205b261ecSmrg
55305b261ecSmrg        TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
55405b261ecSmrg        if (BOX_NOT_EMPTY(box))
55505b261ecSmrg            RootlessDamageBox ((WindowPtr) dst, &box);
55605b261ecSmrg    }
55705b261ecSmrg    GCOP_WRAP(pGC);
55805b261ecSmrg    RL_DEBUG_MSG("set spans end\n");
55905b261ecSmrg}
56005b261ecSmrg
56105b261ecSmrgstatic void
56205b261ecSmrgRootlessPutImage(DrawablePtr dst, GCPtr pGC,
56305b261ecSmrg                 int depth, int x, int y, int w, int h,
56405b261ecSmrg                 int leftPad, int format, char *pBits)
56505b261ecSmrg{
56605b261ecSmrg    BoxRec box;
56705b261ecSmrg
56805b261ecSmrg    GCOP_UNWRAP(pGC);
5694642e01fSmrg    GC_SKIP_ROOT(dst, pGC);
57005b261ecSmrg    RL_DEBUG_MSG("put image start ");
57105b261ecSmrg
57205b261ecSmrg    RootlessStartDrawing((WindowPtr) dst);
57305b261ecSmrg    pGC->ops->PutImage(dst, pGC, depth, x,y,w,h, leftPad, format, pBits);
57405b261ecSmrg
57505b261ecSmrg    box.x1 = x + dst->x;
57605b261ecSmrg    box.x2 = box.x1 + w;
57705b261ecSmrg    box.y1 = y + dst->y;
57805b261ecSmrg    box.y2 = box.y1 + h;
57905b261ecSmrg
58005b261ecSmrg    TRIM_BOX(box, pGC);
58105b261ecSmrg    if (BOX_NOT_EMPTY(box))
58205b261ecSmrg        RootlessDamageBox ((WindowPtr) dst, &box);
58305b261ecSmrg
58405b261ecSmrg    GCOP_WRAP(pGC);
58505b261ecSmrg    RL_DEBUG_MSG("put image end\n");
58605b261ecSmrg}
58705b261ecSmrg
58805b261ecSmrg/* changed area is *dest* rect */
58905b261ecSmrgstatic RegionPtr
59005b261ecSmrgRootlessCopyArea(DrawablePtr pSrc, DrawablePtr dst, GCPtr pGC,
59105b261ecSmrg                 int srcx, int srcy, int w, int h,
59205b261ecSmrg                 int dstx, int dsty)
59305b261ecSmrg{
59405b261ecSmrg    RegionPtr result;
59505b261ecSmrg    BoxRec box;
59605b261ecSmrg
59705b261ecSmrg    GC_SAVE(pGC);
59805b261ecSmrg    GCOP_UNWRAP(pGC);
59905b261ecSmrg
60005b261ecSmrg    if (GC_IS_ROOT(dst) || GC_IS_ROOT(pSrc))
6014642e01fSmrg    {
6024642e01fSmrg        GCOP_WRAP(pGC);
60305b261ecSmrg        return NULL;			/* nothing exposed */
6044642e01fSmrg    }
60505b261ecSmrg
60605b261ecSmrg    RL_DEBUG_MSG("copy area start (src 0x%x, dst 0x%x)", pSrc, dst);
60705b261ecSmrg
60805b261ecSmrg    if (pSrc->type == DRAWABLE_WINDOW && IsFramedWindow((WindowPtr)pSrc)) {
60905b261ecSmrg        unsigned int bytes;
61005b261ecSmrg
61105b261ecSmrg        /* If both source and dest are windows, and we're doing
61205b261ecSmrg           a simple copy operation, we can remove the alpha-protecting
61305b261ecSmrg           planemask (since source has opaque alpha as well) */
61405b261ecSmrg
61505b261ecSmrg        bytes = w * h * (pSrc->depth >> 3);
61605b261ecSmrg
61705b261ecSmrg        if (bytes >= rootless_CopyBytes_threshold && canAccelBlit(pSrc, pGC))
61805b261ecSmrg        {
61905b261ecSmrg            GC_UNSET_PM(pGC, dst);
62005b261ecSmrg        }
62105b261ecSmrg
62205b261ecSmrg        RootlessStartDrawing((WindowPtr) pSrc);
62305b261ecSmrg    }
62405b261ecSmrg    RootlessStartDrawing((WindowPtr) dst);
62505b261ecSmrg    result = pGC->ops->CopyArea(pSrc, dst, pGC, srcx, srcy, w, h, dstx, dsty);
62605b261ecSmrg
62705b261ecSmrg    box.x1 = dstx + dst->x;
62805b261ecSmrg    box.x2 = box.x1 + w;
62905b261ecSmrg    box.y1 = dsty + dst->y;
63005b261ecSmrg    box.y2 = box.y1 + h;
63105b261ecSmrg
63205b261ecSmrg    TRIM_BOX(box, pGC);
63305b261ecSmrg    if (BOX_NOT_EMPTY(box))
63405b261ecSmrg        RootlessDamageBox ((WindowPtr) dst, &box);
63505b261ecSmrg
63605b261ecSmrg    GC_RESTORE(pGC, dst);
63705b261ecSmrg    GCOP_WRAP(pGC);
63805b261ecSmrg    RL_DEBUG_MSG("copy area end\n");
63905b261ecSmrg    return result;
64005b261ecSmrg}
64105b261ecSmrg
64205b261ecSmrg/* changed area is *dest* rect */
64305b261ecSmrgstatic RegionPtr RootlessCopyPlane(DrawablePtr pSrc, DrawablePtr dst,
64405b261ecSmrg                                   GCPtr pGC, int srcx, int srcy,
64505b261ecSmrg                                   int w, int h, int dstx, int dsty,
64605b261ecSmrg                                   unsigned long plane)
64705b261ecSmrg{
64805b261ecSmrg    RegionPtr result;
64905b261ecSmrg    BoxRec box;
65005b261ecSmrg
65105b261ecSmrg    GCOP_UNWRAP(pGC);
65205b261ecSmrg
65305b261ecSmrg    if (GC_IS_ROOT(dst) || GC_IS_ROOT(pSrc))
6544642e01fSmrg    {
6554642e01fSmrg        GCOP_WRAP(pGC);
65605b261ecSmrg        return NULL;			/* nothing exposed */
6574642e01fSmrg    }
65805b261ecSmrg
65905b261ecSmrg    RL_DEBUG_MSG("copy plane start ");
66005b261ecSmrg
66105b261ecSmrg    if (pSrc->type == DRAWABLE_WINDOW && IsFramedWindow((WindowPtr)pSrc)) {
66205b261ecSmrg        RootlessStartDrawing((WindowPtr) pSrc);
66305b261ecSmrg    }
66405b261ecSmrg    RootlessStartDrawing((WindowPtr) dst);
66505b261ecSmrg    result = pGC->ops->CopyPlane(pSrc, dst, pGC, srcx, srcy, w, h,
66605b261ecSmrg                                 dstx, dsty, plane);
66705b261ecSmrg
66805b261ecSmrg    box.x1 = dstx + dst->x;
66905b261ecSmrg    box.x2 = box.x1 + w;
67005b261ecSmrg    box.y1 = dsty + dst->y;
67105b261ecSmrg    box.y2 = box.y1 + h;
67205b261ecSmrg
67305b261ecSmrg    TRIM_BOX(box, pGC);
67405b261ecSmrg    if (BOX_NOT_EMPTY(box))
67505b261ecSmrg        RootlessDamageBox ((WindowPtr) dst, &box);
67605b261ecSmrg
67705b261ecSmrg    GCOP_WRAP(pGC);
67805b261ecSmrg    RL_DEBUG_MSG("copy plane end\n");
67905b261ecSmrg    return result;
68005b261ecSmrg}
68105b261ecSmrg
68205b261ecSmrg// Options for size of changed area:
68305b261ecSmrg//  0 = box per point
68405b261ecSmrg//  1 = big box around all points
68505b261ecSmrg//  2 = accumulate point in 20 pixel radius
68605b261ecSmrg#define ROOTLESS_CHANGED_AREA 1
68705b261ecSmrg#define abs(a) ((a) > 0 ? (a) : -(a))
68805b261ecSmrg
68905b261ecSmrg/* changed area is box around all points */
69005b261ecSmrgstatic void RootlessPolyPoint(DrawablePtr dst, GCPtr pGC,
69105b261ecSmrg                              int mode, int npt, DDXPointPtr pptInit)
69205b261ecSmrg{
69305b261ecSmrg    GCOP_UNWRAP(pGC);
6944642e01fSmrg    GC_SKIP_ROOT(dst, pGC);
69505b261ecSmrg    RL_DEBUG_MSG("polypoint start ");
69605b261ecSmrg
69705b261ecSmrg    RootlessStartDrawing((WindowPtr) dst);
69805b261ecSmrg    pGC->ops->PolyPoint(dst, pGC, mode, npt, pptInit);
69905b261ecSmrg
70005b261ecSmrg    if (npt > 0) {
70105b261ecSmrg#if ROOTLESS_CHANGED_AREA==0
70205b261ecSmrg        // box per point
70305b261ecSmrg        BoxRec box;
70405b261ecSmrg
70505b261ecSmrg        while (npt) {
70605b261ecSmrg            box.x1 = pptInit->x;
70705b261ecSmrg            box.y1 = pptInit->y;
70805b261ecSmrg            box.x2 = box.x1 + 1;
70905b261ecSmrg            box.y2 = box.y1 + 1;
71005b261ecSmrg
71105b261ecSmrg            TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
71205b261ecSmrg            if (BOX_NOT_EMPTY(box))
71305b261ecSmrg                RootlessDamageBox ((WindowPtr) dst, &box);
71405b261ecSmrg
71505b261ecSmrg            npt--;
71605b261ecSmrg            pptInit++;
71705b261ecSmrg        }
71805b261ecSmrg
71905b261ecSmrg#elif ROOTLESS_CHANGED_AREA==1
72005b261ecSmrg        // one big box
72105b261ecSmrg        BoxRec box;
72205b261ecSmrg
72305b261ecSmrg        box.x2 = box.x1 = pptInit->x;
72405b261ecSmrg        box.y2 = box.y1 = pptInit->y;
72505b261ecSmrg        while (--npt) {
72605b261ecSmrg            pptInit++;
72705b261ecSmrg            if (box.x1 > pptInit->x)
72805b261ecSmrg                box.x1 = pptInit->x;
72905b261ecSmrg            else if (box.x2 < pptInit->x)
73005b261ecSmrg                box.x2 = pptInit->x;
73105b261ecSmrg            if (box.y1 > pptInit->y)
73205b261ecSmrg                box.y1 = pptInit->y;
73305b261ecSmrg            else if (box.y2 < pptInit->y)
73405b261ecSmrg                box.y2 = pptInit->y;
73505b261ecSmrg        }
73605b261ecSmrg
73705b261ecSmrg        box.x2++;
73805b261ecSmrg        box.y2++;
73905b261ecSmrg
74005b261ecSmrg        TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
74105b261ecSmrg        if (BOX_NOT_EMPTY(box))
74205b261ecSmrg            RootlessDamageBox ((WindowPtr) dst, &box);
74305b261ecSmrg
74405b261ecSmrg#elif ROOTLESS_CHANGED_AREA==2
74505b261ecSmrg        // clever(?) method: accumulate point in 20-pixel radius
74605b261ecSmrg        BoxRec box;
74705b261ecSmrg        int firstx, firsty;
74805b261ecSmrg
74905b261ecSmrg        box.x2 = box.x1 = firstx = pptInit->x;
75005b261ecSmrg        box.y2 = box.y1 = firsty = pptInit->y;
75105b261ecSmrg        while (--npt) {
75205b261ecSmrg            pptInit++;
75305b261ecSmrg            if (abs(pptInit->x - firstx) > 20 ||
75405b261ecSmrg                abs(pptInit->y - firsty) > 20) {
75505b261ecSmrg                box.x2++;
75605b261ecSmrg                box.y2++;
75705b261ecSmrg                TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
75805b261ecSmrg                if (BOX_NOT_EMPTY(box))
75905b261ecSmrg                    RootlessDamageBox ((WindowPtr) dst, &box);
76005b261ecSmrg                box.x2 = box.x1 = firstx = pptInit->x;
76105b261ecSmrg                box.y2 = box.y1 = firsty = pptInit->y;
76205b261ecSmrg            } else {
76305b261ecSmrg                if (box.x1 > pptInit->x) box.x1 = pptInit->x;
76405b261ecSmrg                else if (box.x2 < pptInit->x) box.x2 = pptInit->x;
76505b261ecSmrg                if (box.y1 > pptInit->y) box.y1 = pptInit->y;
76605b261ecSmrg                else if (box.y2 < pptInit->y) box.y2 = pptInit->y;
76705b261ecSmrg            }
76805b261ecSmrg        }
76905b261ecSmrg        box.x2++;
77005b261ecSmrg        box.y2++;
77105b261ecSmrg        TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
77205b261ecSmrg        if (BOX_NOT_EMPTY(box))
77305b261ecSmrg            RootlessDamageBox((WindowPtr) dst, &box);
77405b261ecSmrg#endif  /* ROOTLESS_CHANGED_AREA */
77505b261ecSmrg    }
77605b261ecSmrg
77705b261ecSmrg    GCOP_WRAP(pGC);
77805b261ecSmrg    RL_DEBUG_MSG("polypoint end\n");
77905b261ecSmrg}
78005b261ecSmrg
78105b261ecSmrg#undef ROOTLESS_CHANGED_AREA
78205b261ecSmrg
78305b261ecSmrg/* changed area is box around each line */
78405b261ecSmrgstatic void RootlessPolylines(DrawablePtr dst, GCPtr pGC,
78505b261ecSmrg                              int mode, int npt, DDXPointPtr pptInit)
78605b261ecSmrg{
78705b261ecSmrg    GCOP_UNWRAP(pGC);
7884642e01fSmrg    GC_SKIP_ROOT(dst, pGC);
78905b261ecSmrg    RL_DEBUG_MSG("poly lines start ");
79005b261ecSmrg
79105b261ecSmrg    RootlessStartDrawing((WindowPtr) dst);
79205b261ecSmrg    pGC->ops->Polylines(dst, pGC, mode, npt, pptInit);
79305b261ecSmrg
79405b261ecSmrg    if (npt > 0) {
79505b261ecSmrg        BoxRec box;
79605b261ecSmrg        int extra = pGC->lineWidth >> 1;
79705b261ecSmrg
79805b261ecSmrg        box.x2 = box.x1 = pptInit->x;
79905b261ecSmrg        box.y2 = box.y1 = pptInit->y;
80005b261ecSmrg
80105b261ecSmrg        if (npt > 1) {
80205b261ecSmrg            if (pGC->joinStyle == JoinMiter)
80305b261ecSmrg                extra = 6 * pGC->lineWidth;
80405b261ecSmrg            else if (pGC->capStyle == CapProjecting)
80505b261ecSmrg                extra = pGC->lineWidth;
80605b261ecSmrg        }
80705b261ecSmrg
80805b261ecSmrg        if (mode == CoordModePrevious) {
80905b261ecSmrg            int x = box.x1;
81005b261ecSmrg            int y = box.y1;
81105b261ecSmrg
81205b261ecSmrg            while (--npt) {
81305b261ecSmrg                pptInit++;
81405b261ecSmrg                x += pptInit->x;
81505b261ecSmrg                y += pptInit->y;
81605b261ecSmrg                if (box.x1 > x)
81705b261ecSmrg                    box.x1 = x;
81805b261ecSmrg                else if (box.x2 < x)
81905b261ecSmrg                    box.x2 = x;
82005b261ecSmrg                if (box.y1 > y)
82105b261ecSmrg                    box.y1 = y;
82205b261ecSmrg                else if (box.y2 < y)
82305b261ecSmrg                    box.y2 = y;
82405b261ecSmrg            }
82505b261ecSmrg        } else {
82605b261ecSmrg            while (--npt) {
82705b261ecSmrg                pptInit++;
82805b261ecSmrg                if (box.x1 > pptInit->x)
82905b261ecSmrg                    box.x1 = pptInit->x;
83005b261ecSmrg                else if (box.x2 < pptInit->x)
83105b261ecSmrg                    box.x2 = pptInit->x;
83205b261ecSmrg                if (box.y1 > pptInit->y)
83305b261ecSmrg                    box.y1 = pptInit->y;
83405b261ecSmrg                else if (box.y2 < pptInit->y)
83505b261ecSmrg                    box.y2 = pptInit->y;
83605b261ecSmrg            }
83705b261ecSmrg        }
83805b261ecSmrg
83905b261ecSmrg        box.x2++;
84005b261ecSmrg        box.y2++;
84105b261ecSmrg
84205b261ecSmrg        if (extra) {
84305b261ecSmrg            box.x1 -= extra;
84405b261ecSmrg            box.x2 += extra;
84505b261ecSmrg            box.y1 -= extra;
84605b261ecSmrg            box.y2 += extra;
84705b261ecSmrg        }
84805b261ecSmrg
84905b261ecSmrg        TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
85005b261ecSmrg        if (BOX_NOT_EMPTY(box))
85105b261ecSmrg            RootlessDamageBox ((WindowPtr) dst, &box);
85205b261ecSmrg    }
85305b261ecSmrg
85405b261ecSmrg    GCOP_WRAP(pGC);
85505b261ecSmrg    RL_DEBUG_MSG("poly lines end\n");
85605b261ecSmrg}
85705b261ecSmrg
85805b261ecSmrg/* changed area is box around each line segment */
85905b261ecSmrgstatic void RootlessPolySegment(DrawablePtr dst, GCPtr pGC,
86005b261ecSmrg                                int nseg, xSegment *pSeg)
86105b261ecSmrg{
86205b261ecSmrg    GCOP_UNWRAP(pGC);
8634642e01fSmrg    GC_SKIP_ROOT(dst, pGC);
86405b261ecSmrg    RL_DEBUG_MSG("poly segment start (win 0x%x)", dst);
86505b261ecSmrg
86605b261ecSmrg    RootlessStartDrawing((WindowPtr) dst);
86705b261ecSmrg    pGC->ops->PolySegment(dst, pGC, nseg, pSeg);
86805b261ecSmrg
86905b261ecSmrg    if (nseg > 0) {
87005b261ecSmrg        BoxRec box;
87105b261ecSmrg        int extra = pGC->lineWidth;
87205b261ecSmrg
87305b261ecSmrg        if (pGC->capStyle != CapProjecting)
87405b261ecSmrg        extra >>= 1;
87505b261ecSmrg
87605b261ecSmrg        if (pSeg->x2 > pSeg->x1) {
87705b261ecSmrg            box.x1 = pSeg->x1;
87805b261ecSmrg            box.x2 = pSeg->x2;
87905b261ecSmrg        } else {
88005b261ecSmrg            box.x2 = pSeg->x1;
88105b261ecSmrg            box.x1 = pSeg->x2;
88205b261ecSmrg        }
88305b261ecSmrg
88405b261ecSmrg        if (pSeg->y2 > pSeg->y1) {
88505b261ecSmrg            box.y1 = pSeg->y1;
88605b261ecSmrg            box.y2 = pSeg->y2;
88705b261ecSmrg        } else {
88805b261ecSmrg            box.y2 = pSeg->y1;
88905b261ecSmrg            box.y1 = pSeg->y2;
89005b261ecSmrg        }
89105b261ecSmrg
89205b261ecSmrg        while (--nseg) {
89305b261ecSmrg            pSeg++;
89405b261ecSmrg            if (pSeg->x2 > pSeg->x1) {
89505b261ecSmrg                if (pSeg->x1 < box.x1) box.x1 = pSeg->x1;
89605b261ecSmrg                if (pSeg->x2 > box.x2) box.x2 = pSeg->x2;
89705b261ecSmrg            } else {
89805b261ecSmrg                if (pSeg->x2 < box.x1) box.x1 = pSeg->x2;
89905b261ecSmrg                if (pSeg->x1 > box.x2) box.x2 = pSeg->x1;
90005b261ecSmrg            }
90105b261ecSmrg            if (pSeg->y2 > pSeg->y1) {
90205b261ecSmrg                if (pSeg->y1 < box.y1) box.y1 = pSeg->y1;
90305b261ecSmrg                if (pSeg->y2 > box.y2) box.y2 = pSeg->y2;
90405b261ecSmrg            } else {
90505b261ecSmrg                if (pSeg->y2 < box.y1) box.y1 = pSeg->y2;
90605b261ecSmrg                if (pSeg->y1 > box.y2) box.y2 = pSeg->y1;
90705b261ecSmrg            }
90805b261ecSmrg        }
90905b261ecSmrg
91005b261ecSmrg        box.x2++;
91105b261ecSmrg        box.y2++;
91205b261ecSmrg
91305b261ecSmrg        if (extra) {
91405b261ecSmrg            box.x1 -= extra;
91505b261ecSmrg            box.x2 += extra;
91605b261ecSmrg            box.y1 -= extra;
91705b261ecSmrg            box.y2 += extra;
91805b261ecSmrg        }
91905b261ecSmrg
92005b261ecSmrg        TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
92105b261ecSmrg        if (BOX_NOT_EMPTY(box))
92205b261ecSmrg            RootlessDamageBox ((WindowPtr) dst, &box);
92305b261ecSmrg    }
92405b261ecSmrg
92505b261ecSmrg    GCOP_WRAP(pGC);
92605b261ecSmrg    RL_DEBUG_MSG("poly segment end\n");
92705b261ecSmrg}
92805b261ecSmrg
92905b261ecSmrg/* changed area is box around each line (not entire rects) */
93005b261ecSmrgstatic void RootlessPolyRectangle(DrawablePtr dst, GCPtr pGC,
93105b261ecSmrg                                  int nRects, xRectangle *pRects)
93205b261ecSmrg{
93305b261ecSmrg    GCOP_UNWRAP(pGC);
9344642e01fSmrg    GC_SKIP_ROOT(dst, pGC);
93505b261ecSmrg    RL_DEBUG_MSG("poly rectangle start ");
93605b261ecSmrg
93705b261ecSmrg    RootlessStartDrawing((WindowPtr) dst);
93805b261ecSmrg    pGC->ops->PolyRectangle(dst, pGC, nRects, pRects);
93905b261ecSmrg
94005b261ecSmrg    if (nRects > 0) {
94105b261ecSmrg        BoxRec box;
94205b261ecSmrg        int offset1, offset2, offset3;
94305b261ecSmrg
94405b261ecSmrg        offset2 = pGC->lineWidth;
94505b261ecSmrg        if (!offset2) offset2 = 1;
94605b261ecSmrg        offset1 = offset2 >> 1;
94705b261ecSmrg        offset3 = offset2 - offset1;
94805b261ecSmrg
94905b261ecSmrg        while (nRects--) {
95005b261ecSmrg            box.x1 = pRects->x - offset1;
95105b261ecSmrg            box.y1 = pRects->y - offset1;
95205b261ecSmrg            box.x2 = box.x1 + pRects->width + offset2;
95305b261ecSmrg            box.y2 = box.y1 + offset2;
95405b261ecSmrg            TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
95505b261ecSmrg            if (BOX_NOT_EMPTY(box))
95605b261ecSmrg                RootlessDamageBox ((WindowPtr) dst, &box);
95705b261ecSmrg
95805b261ecSmrg            box.x1 = pRects->x - offset1;
95905b261ecSmrg            box.y1 = pRects->y + offset3;
96005b261ecSmrg            box.x2 = box.x1 + offset2;
96105b261ecSmrg            box.y2 = box.y1 + pRects->height - offset2;
96205b261ecSmrg            TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
96305b261ecSmrg            if (BOX_NOT_EMPTY(box))
96405b261ecSmrg                RootlessDamageBox ((WindowPtr) dst, &box);
96505b261ecSmrg
96605b261ecSmrg            box.x1 = pRects->x + pRects->width - offset1;
96705b261ecSmrg            box.y1 = pRects->y + offset3;
96805b261ecSmrg            box.x2 = box.x1 + offset2;
96905b261ecSmrg            box.y2 = box.y1 + pRects->height - offset2;
97005b261ecSmrg            TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
97105b261ecSmrg            if (BOX_NOT_EMPTY(box))
97205b261ecSmrg                RootlessDamageBox ((WindowPtr) dst, &box);
97305b261ecSmrg
97405b261ecSmrg            box.x1 = pRects->x - offset1;
97505b261ecSmrg            box.y1 = pRects->y + pRects->height - offset1;
97605b261ecSmrg            box.x2 = box.x1 + pRects->width + offset2;
97705b261ecSmrg            box.y2 = box.y1 + offset2;
97805b261ecSmrg            TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
97905b261ecSmrg            if (BOX_NOT_EMPTY(box))
98005b261ecSmrg                RootlessDamageBox ((WindowPtr) dst, &box);
98105b261ecSmrg
98205b261ecSmrg            pRects++;
98305b261ecSmrg        }
98405b261ecSmrg    }
98505b261ecSmrg
98605b261ecSmrg    GCOP_WRAP(pGC);
98705b261ecSmrg    RL_DEBUG_MSG("poly rectangle end\n");
98805b261ecSmrg}
98905b261ecSmrg
99005b261ecSmrg
99105b261ecSmrg/* changed area is box around each arc (assumes all arcs are 360 degrees) */
99205b261ecSmrgstatic void RootlessPolyArc(DrawablePtr dst, GCPtr pGC, int narcs, xArc *parcs)
99305b261ecSmrg{
99405b261ecSmrg    GCOP_UNWRAP(pGC);
9954642e01fSmrg    GC_SKIP_ROOT(dst, pGC);
99605b261ecSmrg    RL_DEBUG_MSG("poly arc start ");
99705b261ecSmrg
99805b261ecSmrg    RootlessStartDrawing((WindowPtr) dst);
99905b261ecSmrg    pGC->ops->PolyArc(dst, pGC, narcs, parcs);
100005b261ecSmrg
100105b261ecSmrg    if (narcs > 0) {
100205b261ecSmrg        int extra = pGC->lineWidth >> 1;
100305b261ecSmrg        BoxRec box;
100405b261ecSmrg
100505b261ecSmrg        box.x1 = parcs->x;
100605b261ecSmrg        box.x2 = box.x1 + parcs->width;
100705b261ecSmrg        box.y1 = parcs->y;
100805b261ecSmrg        box.y2 = box.y1 + parcs->height;
100905b261ecSmrg
101005b261ecSmrg        /* should I break these up instead ? */
101105b261ecSmrg
101205b261ecSmrg        while (--narcs) {
101305b261ecSmrg            parcs++;
101405b261ecSmrg            if (box.x1 > parcs->x)
101505b261ecSmrg                box.x1 = parcs->x;
101605b261ecSmrg            if (box.x2 < (parcs->x + parcs->width))
101705b261ecSmrg                box.x2 = parcs->x + parcs->width;
101805b261ecSmrg            if (box.y1 > parcs->y)
101905b261ecSmrg                box.y1 = parcs->y;
102005b261ecSmrg            if (box.y2 < (parcs->y + parcs->height))
102105b261ecSmrg                box.y2 = parcs->y + parcs->height;
102205b261ecSmrg        }
102305b261ecSmrg
102405b261ecSmrg        if (extra) {
102505b261ecSmrg            box.x1 -= extra;
102605b261ecSmrg            box.x2 += extra;
102705b261ecSmrg            box.y1 -= extra;
102805b261ecSmrg            box.y2 += extra;
102905b261ecSmrg        }
103005b261ecSmrg
103105b261ecSmrg        box.x2++;
103205b261ecSmrg        box.y2++;
103305b261ecSmrg
103405b261ecSmrg        TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
103505b261ecSmrg        if (BOX_NOT_EMPTY(box))
103605b261ecSmrg            RootlessDamageBox ((WindowPtr) dst, &box);
103705b261ecSmrg    }
103805b261ecSmrg
103905b261ecSmrg    GCOP_WRAP(pGC);
104005b261ecSmrg    RL_DEBUG_MSG("poly arc end\n");
104105b261ecSmrg}
104205b261ecSmrg
104305b261ecSmrg
104405b261ecSmrg/* changed area is box around each poly */
104505b261ecSmrgstatic void RootlessFillPolygon(DrawablePtr dst, GCPtr pGC,
104605b261ecSmrg                                int shape, int mode, int count,
104705b261ecSmrg                                DDXPointPtr pptInit)
104805b261ecSmrg{
104905b261ecSmrg    GC_SAVE(pGC);
105005b261ecSmrg    GCOP_UNWRAP(pGC);
10514642e01fSmrg    GC_SKIP_ROOT(dst, pGC);
105205b261ecSmrg    RL_DEBUG_MSG("fill poly start (win 0x%x, fillStyle 0x%x)", dst,
105305b261ecSmrg                 pGC->fillStyle);
105405b261ecSmrg
105505b261ecSmrg    if (count <= 2) {
105605b261ecSmrg        pGC->ops->FillPolygon(dst, pGC, shape, mode, count, pptInit);
105705b261ecSmrg    } else {
105805b261ecSmrg        DDXPointPtr ppt = pptInit;
105905b261ecSmrg        int i = count;
106005b261ecSmrg        BoxRec box;
106105b261ecSmrg
106205b261ecSmrg        box.x2 = box.x1 = ppt->x;
106305b261ecSmrg        box.y2 = box.y1 = ppt->y;
106405b261ecSmrg
106505b261ecSmrg        if (mode != CoordModeOrigin) {
106605b261ecSmrg            int x = box.x1;
106705b261ecSmrg            int y = box.y1;
106805b261ecSmrg
106905b261ecSmrg            while (--i) {
107005b261ecSmrg                ppt++;
107105b261ecSmrg                x += ppt->x;
107205b261ecSmrg                y += ppt->y;
107305b261ecSmrg                if (box.x1 > x)
107405b261ecSmrg                    box.x1 = x;
107505b261ecSmrg                else if (box.x2 < x)
107605b261ecSmrg                    box.x2 = x;
107705b261ecSmrg                if (box.y1 > y)
107805b261ecSmrg                    box.y1 = y;
107905b261ecSmrg                else if (box.y2 < y)
108005b261ecSmrg                    box.y2 = y;
108105b261ecSmrg            }
108205b261ecSmrg        } else {
108305b261ecSmrg            while (--i) {
108405b261ecSmrg                ppt++;
108505b261ecSmrg                if (box.x1 > ppt->x)
108605b261ecSmrg                    box.x1 = ppt->x;
108705b261ecSmrg                else if (box.x2 < ppt->x)
108805b261ecSmrg                    box.x2 = ppt->x;
108905b261ecSmrg                if (box.y1 > ppt->y)
109005b261ecSmrg                    box.y1 = ppt->y;
109105b261ecSmrg                else if (box.y2 < ppt->y)
109205b261ecSmrg                    box.y2 = ppt->y;
109305b261ecSmrg            }
109405b261ecSmrg        }
109505b261ecSmrg
109605b261ecSmrg        box.x2++;
109705b261ecSmrg        box.y2++;
109805b261ecSmrg
109905b261ecSmrg        RootlessStartDrawing((WindowPtr) dst);
110005b261ecSmrg
110105b261ecSmrg        if (canAccelFill(dst, pGC) &&
110205b261ecSmrg            boxBytes(dst, &box) >= rootless_FillBytes_threshold)
110305b261ecSmrg        {
110405b261ecSmrg            GC_UNSET_PM(pGC, dst);
110505b261ecSmrg        }
110605b261ecSmrg
110705b261ecSmrg        pGC->ops->FillPolygon(dst, pGC, shape, mode, count, pptInit);
110805b261ecSmrg
110905b261ecSmrg        TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
111005b261ecSmrg        if (BOX_NOT_EMPTY(box))
111105b261ecSmrg            RootlessDamageBox ((WindowPtr) dst, &box);
111205b261ecSmrg    }
111305b261ecSmrg
111405b261ecSmrg    GC_RESTORE(pGC, dst);
111505b261ecSmrg    GCOP_WRAP(pGC);
111605b261ecSmrg    RL_DEBUG_MSG("fill poly end\n");
111705b261ecSmrg}
111805b261ecSmrg
111905b261ecSmrg/* changed area is the rects */
112005b261ecSmrgstatic void RootlessPolyFillRect(DrawablePtr dst, GCPtr pGC,
112105b261ecSmrg                                 int nRectsInit, xRectangle *pRectsInit)
112205b261ecSmrg{
112305b261ecSmrg    GC_SAVE(pGC);
112405b261ecSmrg    GCOP_UNWRAP(pGC);
11254642e01fSmrg    GC_SKIP_ROOT(dst, pGC);
112605b261ecSmrg    RL_DEBUG_MSG("fill rect start (win 0x%x, fillStyle 0x%x)", dst,
112705b261ecSmrg                 pGC->fillStyle);
112805b261ecSmrg
112905b261ecSmrg    if (nRectsInit <= 0) {
113005b261ecSmrg        pGC->ops->PolyFillRect(dst, pGC, nRectsInit, pRectsInit);
113105b261ecSmrg    } else {
113205b261ecSmrg        BoxRec box;
113305b261ecSmrg        xRectangle *pRects = pRectsInit;
113405b261ecSmrg        int nRects = nRectsInit;
113505b261ecSmrg
113605b261ecSmrg        box.x1 = pRects->x;
113705b261ecSmrg        box.x2 = box.x1 + pRects->width;
113805b261ecSmrg        box.y1 = pRects->y;
113905b261ecSmrg        box.y2 = box.y1 + pRects->height;
114005b261ecSmrg
114105b261ecSmrg        while (--nRects) {
114205b261ecSmrg            pRects++;
114305b261ecSmrg            if (box.x1 > pRects->x)
114405b261ecSmrg                box.x1 = pRects->x;
114505b261ecSmrg            if (box.x2 < (pRects->x + pRects->width))
114605b261ecSmrg                box.x2 = pRects->x + pRects->width;
114705b261ecSmrg            if (box.y1 > pRects->y)
114805b261ecSmrg                box.y1 = pRects->y;
114905b261ecSmrg            if (box.y2 < (pRects->y + pRects->height))
115005b261ecSmrg                box.y2 = pRects->y + pRects->height;
115105b261ecSmrg        }
115205b261ecSmrg
115305b261ecSmrg        RootlessStartDrawing((WindowPtr) dst);
115405b261ecSmrg
115505b261ecSmrg        if (canAccelFill(dst, pGC) &&
115605b261ecSmrg            boxBytes(dst, &box) >= rootless_FillBytes_threshold)
115705b261ecSmrg        {
115805b261ecSmrg            GC_UNSET_PM(pGC, dst);
115905b261ecSmrg        }
116005b261ecSmrg
116105b261ecSmrg       pGC->ops->PolyFillRect(dst, pGC, nRectsInit, pRectsInit);
116205b261ecSmrg
116305b261ecSmrg        TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
116405b261ecSmrg        if (BOX_NOT_EMPTY(box))
116505b261ecSmrg            RootlessDamageBox ((WindowPtr) dst, &box);
116605b261ecSmrg    }
116705b261ecSmrg
116805b261ecSmrg    GC_RESTORE(pGC, dst);
116905b261ecSmrg    GCOP_WRAP(pGC);
117005b261ecSmrg    RL_DEBUG_MSG("fill rect end\n");
117105b261ecSmrg}
117205b261ecSmrg
117305b261ecSmrg
117405b261ecSmrg/* changed area is box around each arc (assuming arcs are all 360 degrees) */
117505b261ecSmrgstatic void RootlessPolyFillArc(DrawablePtr dst, GCPtr pGC,
117605b261ecSmrg                                int narcsInit, xArc *parcsInit)
117705b261ecSmrg{
117805b261ecSmrg    GC_SAVE(pGC);
117905b261ecSmrg    GCOP_UNWRAP(pGC);
11804642e01fSmrg    GC_SKIP_ROOT(dst, pGC);
118105b261ecSmrg    RL_DEBUG_MSG("fill arc start ");
118205b261ecSmrg
118305b261ecSmrg    if (narcsInit > 0) {
118405b261ecSmrg        BoxRec box;
118505b261ecSmrg        int narcs = narcsInit;
118605b261ecSmrg        xArc *parcs = parcsInit;
118705b261ecSmrg
118805b261ecSmrg        box.x1 = parcs->x;
118905b261ecSmrg        box.x2 = box.x1 + parcs->width;
119005b261ecSmrg        box.y1 = parcs->y;
119105b261ecSmrg        box.y2 = box.y1 + parcs->height;
119205b261ecSmrg
119305b261ecSmrg        /* should I break these up instead ? */
119405b261ecSmrg
119505b261ecSmrg        while (--narcs) {
119605b261ecSmrg            parcs++;
119705b261ecSmrg            if (box.x1 > parcs->x)
119805b261ecSmrg                box.x1 = parcs->x;
119905b261ecSmrg            if (box.x2 < (parcs->x + parcs->width))
120005b261ecSmrg                box.x2 = parcs->x + parcs->width;
120105b261ecSmrg            if (box.y1 > parcs->y)
120205b261ecSmrg                box.y1 = parcs->y;
120305b261ecSmrg            if (box.y2 < (parcs->y + parcs->height))
120405b261ecSmrg                box.y2 = parcs->y + parcs->height;
120505b261ecSmrg        }
120605b261ecSmrg
120705b261ecSmrg        RootlessStartDrawing((WindowPtr) dst);
120805b261ecSmrg
120905b261ecSmrg        if (canAccelFill(dst, pGC) &&
121005b261ecSmrg            boxBytes(dst, &box) >= rootless_FillBytes_threshold)
121105b261ecSmrg        {
121205b261ecSmrg            GC_UNSET_PM(pGC, dst);
121305b261ecSmrg        }
121405b261ecSmrg
121505b261ecSmrg        pGC->ops->PolyFillArc(dst, pGC, narcsInit, parcsInit);
121605b261ecSmrg
121705b261ecSmrg        TRIM_AND_TRANSLATE_BOX(box, dst, pGC);
121805b261ecSmrg        if (BOX_NOT_EMPTY(box))
121905b261ecSmrg            RootlessDamageBox ((WindowPtr) dst, &box);
122005b261ecSmrg    } else {
122105b261ecSmrg        pGC->ops->PolyFillArc(dst, pGC, narcsInit, parcsInit);
122205b261ecSmrg    }
122305b261ecSmrg
122405b261ecSmrg    GC_RESTORE(pGC, dst);
122505b261ecSmrg    GCOP_WRAP(pGC);
122605b261ecSmrg    RL_DEBUG_MSG("fill arc end\n");
122705b261ecSmrg}
122805b261ecSmrg
122905b261ecSmrg
123005b261ecSmrgstatic void RootlessImageText8(DrawablePtr dst, GCPtr pGC,
123105b261ecSmrg                               int x, int y, int count, char *chars)
123205b261ecSmrg{
123305b261ecSmrg    GC_SAVE(pGC);
123405b261ecSmrg    GCOP_UNWRAP(pGC);
12354642e01fSmrg    GC_SKIP_ROOT(dst, pGC);
123605b261ecSmrg    RL_DEBUG_MSG("imagetext8 start ");
123705b261ecSmrg
123805b261ecSmrg    if (count > 0) {
123905b261ecSmrg        int top, bot, Min, Max;
124005b261ecSmrg        BoxRec box;
124105b261ecSmrg
124205b261ecSmrg        top = max(FONTMAXBOUNDS(pGC->font, ascent), FONTASCENT(pGC->font));
124305b261ecSmrg        bot = max(FONTMAXBOUNDS(pGC->font, descent), FONTDESCENT(pGC->font));
124405b261ecSmrg
124505b261ecSmrg        Min = count * FONTMINBOUNDS(pGC->font, characterWidth);
124605b261ecSmrg        if (Min > 0) Min = 0;
124705b261ecSmrg        Max = count * FONTMAXBOUNDS(pGC->font, characterWidth);
124805b261ecSmrg        if (Max < 0) Max = 0;
124905b261ecSmrg
125005b261ecSmrg        /* ugh */
125105b261ecSmrg        box.x1 = dst->x + x + Min +
125205b261ecSmrg        FONTMINBOUNDS(pGC->font, leftSideBearing);
125305b261ecSmrg        box.x2 = dst->x + x + Max +
125405b261ecSmrg        FONTMAXBOUNDS(pGC->font, rightSideBearing);
125505b261ecSmrg
125605b261ecSmrg        box.y1 = dst->y + y - top;
125705b261ecSmrg        box.y2 = dst->y + y + bot;
125805b261ecSmrg
125905b261ecSmrg        RootlessStartDrawing((WindowPtr) dst);
126005b261ecSmrg
126105b261ecSmrg        if (canAccelFill(dst, pGC) &&
126205b261ecSmrg            boxBytes(dst, &box) >= rootless_FillBytes_threshold)
126305b261ecSmrg        {
126405b261ecSmrg            GC_UNSET_PM(pGC, dst);
126505b261ecSmrg        }
126605b261ecSmrg
126705b261ecSmrg        pGC->ops->ImageText8(dst, pGC, x, y, count, chars);
126805b261ecSmrg
126905b261ecSmrg        TRIM_BOX(box, pGC);
127005b261ecSmrg        if (BOX_NOT_EMPTY(box))
127105b261ecSmrg            RootlessDamageBox ((WindowPtr) dst, &box);
127205b261ecSmrg    } else {
127305b261ecSmrg        pGC->ops->ImageText8(dst, pGC, x, y, count, chars);
127405b261ecSmrg    }
127505b261ecSmrg
127605b261ecSmrg    GC_RESTORE(pGC, dst);
127705b261ecSmrg    GCOP_WRAP(pGC);
127805b261ecSmrg    RL_DEBUG_MSG("imagetext8 end\n");
127905b261ecSmrg}
128005b261ecSmrg
128105b261ecSmrgstatic int RootlessPolyText8(DrawablePtr dst, GCPtr pGC,
128205b261ecSmrg                             int x, int y, int count, char *chars)
128305b261ecSmrg{
128405b261ecSmrg    int width; // the result, sorta
128505b261ecSmrg
128605b261ecSmrg    GCOP_UNWRAP(pGC);
128705b261ecSmrg
128805b261ecSmrg    if (GC_IS_ROOT(dst))
12894642e01fSmrg    {
12904642e01fSmrg        GCOP_WRAP(pGC);
129105b261ecSmrg        return 0;
12924642e01fSmrg    }
129305b261ecSmrg
129405b261ecSmrg    RL_DEBUG_MSG("polytext8 start ");
129505b261ecSmrg
129605b261ecSmrg    RootlessStartDrawing((WindowPtr) dst);
129705b261ecSmrg    width = pGC->ops->PolyText8(dst, pGC, x, y, count, chars);
129805b261ecSmrg    width -= x;
129905b261ecSmrg
130005b261ecSmrg    if (width > 0) {
130105b261ecSmrg        BoxRec box;
130205b261ecSmrg
130305b261ecSmrg        /* ugh */
130405b261ecSmrg        box.x1 = dst->x + x + FONTMINBOUNDS(pGC->font, leftSideBearing);
130505b261ecSmrg        box.x2 = dst->x + x + FONTMAXBOUNDS(pGC->font, rightSideBearing);
130605b261ecSmrg
130705b261ecSmrg        if (count > 1) {
130805b261ecSmrg            if (width > 0) box.x2 += width;
130905b261ecSmrg            else box.x1 += width;
131005b261ecSmrg        }
131105b261ecSmrg
131205b261ecSmrg        box.y1 = dst->y + y - FONTMAXBOUNDS(pGC->font, ascent);
131305b261ecSmrg        box.y2 = dst->y + y + FONTMAXBOUNDS(pGC->font, descent);
131405b261ecSmrg
131505b261ecSmrg        TRIM_BOX(box, pGC);
131605b261ecSmrg        if (BOX_NOT_EMPTY(box))
131705b261ecSmrg            RootlessDamageBox ((WindowPtr) dst, &box);
131805b261ecSmrg    }
131905b261ecSmrg
132005b261ecSmrg    GCOP_WRAP(pGC);
132105b261ecSmrg    RL_DEBUG_MSG("polytext8 end\n");
132205b261ecSmrg    return (width + x);
132305b261ecSmrg}
132405b261ecSmrg
132505b261ecSmrgstatic void RootlessImageText16(DrawablePtr dst, GCPtr pGC,
132605b261ecSmrg                                int x, int y, int count, unsigned short *chars)
132705b261ecSmrg{
132805b261ecSmrg    GC_SAVE(pGC);
132905b261ecSmrg    GCOP_UNWRAP(pGC);
13304642e01fSmrg    GC_SKIP_ROOT(dst, pGC);
133105b261ecSmrg    RL_DEBUG_MSG("imagetext16 start ");
133205b261ecSmrg
133305b261ecSmrg    if (count > 0) {
133405b261ecSmrg        int top, bot, Min, Max;
133505b261ecSmrg        BoxRec box;
133605b261ecSmrg
133705b261ecSmrg        top = max(FONTMAXBOUNDS(pGC->font, ascent), FONTASCENT(pGC->font));
133805b261ecSmrg        bot = max(FONTMAXBOUNDS(pGC->font, descent), FONTDESCENT(pGC->font));
133905b261ecSmrg
134005b261ecSmrg        Min = count * FONTMINBOUNDS(pGC->font, characterWidth);
134105b261ecSmrg        if (Min > 0) Min = 0;
134205b261ecSmrg        Max = count * FONTMAXBOUNDS(pGC->font, characterWidth);
134305b261ecSmrg        if (Max < 0) Max = 0;
134405b261ecSmrg
134505b261ecSmrg        /* ugh */
134605b261ecSmrg        box.x1 = dst->x + x + Min +
134705b261ecSmrg            FONTMINBOUNDS(pGC->font, leftSideBearing);
134805b261ecSmrg        box.x2 = dst->x + x + Max +
134905b261ecSmrg            FONTMAXBOUNDS(pGC->font, rightSideBearing);
135005b261ecSmrg
135105b261ecSmrg        box.y1 = dst->y + y - top;
135205b261ecSmrg        box.y2 = dst->y + y + bot;
135305b261ecSmrg
135405b261ecSmrg        RootlessStartDrawing((WindowPtr) dst);
135505b261ecSmrg
135605b261ecSmrg        if (canAccelFill(dst, pGC) &&
135705b261ecSmrg            boxBytes(dst, &box) >= rootless_FillBytes_threshold)
135805b261ecSmrg        {
135905b261ecSmrg            GC_UNSET_PM(pGC, dst);
136005b261ecSmrg        }
136105b261ecSmrg
136205b261ecSmrg        pGC->ops->ImageText16(dst, pGC, x, y, count, chars);
136305b261ecSmrg
136405b261ecSmrg        TRIM_BOX(box, pGC);
136505b261ecSmrg        if (BOX_NOT_EMPTY(box))
136605b261ecSmrg            RootlessDamageBox ((WindowPtr) dst, &box);
136705b261ecSmrg    } else {
136805b261ecSmrg        pGC->ops->ImageText16(dst, pGC, x, y, count, chars);
136905b261ecSmrg    }
137005b261ecSmrg
137105b261ecSmrg    GC_RESTORE(pGC, dst);
137205b261ecSmrg    GCOP_WRAP(pGC);
137305b261ecSmrg    RL_DEBUG_MSG("imagetext16 end\n");
137405b261ecSmrg}
137505b261ecSmrg
137605b261ecSmrgstatic int RootlessPolyText16(DrawablePtr dst, GCPtr pGC,
137705b261ecSmrg                            int x, int y, int count, unsigned short *chars)
137805b261ecSmrg{
137905b261ecSmrg    int width; // the result, sorta
138005b261ecSmrg
138105b261ecSmrg    GCOP_UNWRAP(pGC);
138205b261ecSmrg
138305b261ecSmrg    if (GC_IS_ROOT(dst))
13844642e01fSmrg    {
13854642e01fSmrg        GCOP_WRAP(pGC);
138605b261ecSmrg        return 0;
13874642e01fSmrg    }
138805b261ecSmrg
138905b261ecSmrg    RL_DEBUG_MSG("polytext16 start ");
139005b261ecSmrg
139105b261ecSmrg    RootlessStartDrawing((WindowPtr) dst);
139205b261ecSmrg    width = pGC->ops->PolyText16(dst, pGC, x, y, count, chars);
139305b261ecSmrg    width -= x;
139405b261ecSmrg
139505b261ecSmrg    if (width > 0) {
139605b261ecSmrg        BoxRec box;
139705b261ecSmrg
139805b261ecSmrg        /* ugh */
139905b261ecSmrg        box.x1 = dst->x + x + FONTMINBOUNDS(pGC->font, leftSideBearing);
140005b261ecSmrg        box.x2 = dst->x + x + FONTMAXBOUNDS(pGC->font, rightSideBearing);
140105b261ecSmrg
140205b261ecSmrg        if (count > 1) {
140305b261ecSmrg            if (width > 0) box.x2 += width;
140405b261ecSmrg            else box.x1 += width;
140505b261ecSmrg        }
140605b261ecSmrg
140705b261ecSmrg        box.y1 = dst->y + y - FONTMAXBOUNDS(pGC->font, ascent);
140805b261ecSmrg        box.y2 = dst->y + y + FONTMAXBOUNDS(pGC->font, descent);
140905b261ecSmrg
141005b261ecSmrg        TRIM_BOX(box, pGC);
141105b261ecSmrg        if (BOX_NOT_EMPTY(box))
141205b261ecSmrg            RootlessDamageBox ((WindowPtr) dst, &box);
141305b261ecSmrg    }
141405b261ecSmrg
141505b261ecSmrg    GCOP_WRAP(pGC);
141605b261ecSmrg    RL_DEBUG_MSG("polytext16 end\n");
141705b261ecSmrg    return width + x;
141805b261ecSmrg}
141905b261ecSmrg
142005b261ecSmrgstatic void RootlessImageGlyphBlt(DrawablePtr dst, GCPtr pGC,
142105b261ecSmrg                                  int x, int y, unsigned int nglyphInit,
142205b261ecSmrg                                  CharInfoPtr *ppciInit, pointer unused)
142305b261ecSmrg{
142405b261ecSmrg    GC_SAVE(pGC);
142505b261ecSmrg    GCOP_UNWRAP(pGC);
14264642e01fSmrg    GC_SKIP_ROOT(dst, pGC);
142705b261ecSmrg    RL_DEBUG_MSG("imageglyph start ");
142805b261ecSmrg
142905b261ecSmrg    if (nglyphInit > 0) {
143005b261ecSmrg        int top, bot, width = 0;
143105b261ecSmrg        BoxRec box;
143205b261ecSmrg        unsigned int nglyph = nglyphInit;
143305b261ecSmrg        CharInfoPtr *ppci = ppciInit;
143405b261ecSmrg
143505b261ecSmrg        top = max(FONTMAXBOUNDS(pGC->font, ascent), FONTASCENT(pGC->font));
143605b261ecSmrg        bot = max(FONTMAXBOUNDS(pGC->font, descent), FONTDESCENT(pGC->font));
143705b261ecSmrg
143805b261ecSmrg        box.x1 = ppci[0]->metrics.leftSideBearing;
143905b261ecSmrg        if (box.x1 > 0) box.x1 = 0;
144005b261ecSmrg        box.x2 = ppci[nglyph - 1]->metrics.rightSideBearing -
144105b261ecSmrg            ppci[nglyph - 1]->metrics.characterWidth;
144205b261ecSmrg        if (box.x2 < 0) box.x2 = 0;
144305b261ecSmrg
144405b261ecSmrg        box.x2 += dst->x + x;
144505b261ecSmrg        box.x1 += dst->x + x;
144605b261ecSmrg
144705b261ecSmrg        while (nglyph--) {
144805b261ecSmrg            width += (*ppci)->metrics.characterWidth;
144905b261ecSmrg            ppci++;
145005b261ecSmrg        }
145105b261ecSmrg
145205b261ecSmrg        if (width > 0)
145305b261ecSmrg            box.x2 += width;
145405b261ecSmrg        else
145505b261ecSmrg            box.x1 += width;
145605b261ecSmrg
145705b261ecSmrg        box.y1 = dst->y + y - top;
145805b261ecSmrg        box.y2 = dst->y + y + bot;
145905b261ecSmrg
146005b261ecSmrg        RootlessStartDrawing((WindowPtr) dst);
146105b261ecSmrg
146205b261ecSmrg        if (canAccelFill(dst, pGC) &&
146305b261ecSmrg            boxBytes(dst, &box) >= rootless_FillBytes_threshold)
146405b261ecSmrg        {
146505b261ecSmrg            GC_UNSET_PM(pGC, dst);
146605b261ecSmrg        }
146705b261ecSmrg
146805b261ecSmrg        pGC->ops->ImageGlyphBlt(dst, pGC, x, y, nglyphInit, ppciInit, unused);
146905b261ecSmrg
147005b261ecSmrg        TRIM_BOX(box, pGC);
147105b261ecSmrg        if (BOX_NOT_EMPTY(box))
147205b261ecSmrg            RootlessDamageBox ((WindowPtr) dst, &box);
147305b261ecSmrg    } else {
147405b261ecSmrg        pGC->ops->ImageGlyphBlt(dst, pGC, x, y, nglyphInit, ppciInit, unused);
147505b261ecSmrg    }
147605b261ecSmrg
147705b261ecSmrg    GC_RESTORE(pGC, dst);
147805b261ecSmrg    GCOP_WRAP(pGC);
147905b261ecSmrg    RL_DEBUG_MSG("imageglyph end\n");
148005b261ecSmrg}
148105b261ecSmrg
148205b261ecSmrgstatic void RootlessPolyGlyphBlt(DrawablePtr dst, GCPtr pGC,
148305b261ecSmrg                                 int x, int y, unsigned int nglyph,
148405b261ecSmrg                                 CharInfoPtr *ppci, pointer pglyphBase)
148505b261ecSmrg{
148605b261ecSmrg    GCOP_UNWRAP(pGC);
14874642e01fSmrg    GC_SKIP_ROOT(dst, pGC);
148805b261ecSmrg    RL_DEBUG_MSG("polyglyph start ");
148905b261ecSmrg
149005b261ecSmrg    RootlessStartDrawing((WindowPtr) dst);
149105b261ecSmrg    pGC->ops->PolyGlyphBlt(dst, pGC, x, y, nglyph, ppci, pglyphBase);
149205b261ecSmrg
149305b261ecSmrg    if (nglyph > 0) {
149405b261ecSmrg        BoxRec box;
149505b261ecSmrg
149605b261ecSmrg        /* ugh */
149705b261ecSmrg        box.x1 = dst->x + x + ppci[0]->metrics.leftSideBearing;
149805b261ecSmrg        box.x2 = dst->x + x + ppci[nglyph - 1]->metrics.rightSideBearing;
149905b261ecSmrg
150005b261ecSmrg        if (nglyph > 1) {
150105b261ecSmrg            int width = 0;
150205b261ecSmrg
150305b261ecSmrg            while (--nglyph) {
150405b261ecSmrg                width += (*ppci)->metrics.characterWidth;
150505b261ecSmrg                ppci++;
150605b261ecSmrg            }
150705b261ecSmrg
150805b261ecSmrg            if (width > 0) box.x2 += width;
150905b261ecSmrg            else box.x1 += width;
151005b261ecSmrg        }
151105b261ecSmrg
151205b261ecSmrg        box.y1 = dst->y + y - FONTMAXBOUNDS(pGC->font, ascent);
151305b261ecSmrg        box.y2 = dst->y + y + FONTMAXBOUNDS(pGC->font, descent);
151405b261ecSmrg
151505b261ecSmrg        TRIM_BOX(box, pGC);
151605b261ecSmrg        if (BOX_NOT_EMPTY(box))
151705b261ecSmrg            RootlessDamageBox ((WindowPtr) dst, &box);
151805b261ecSmrg    }
151905b261ecSmrg
152005b261ecSmrg    GCOP_WRAP(pGC);
152105b261ecSmrg    RL_DEBUG_MSG("polyglyph end\n");
152205b261ecSmrg}
152305b261ecSmrg
152405b261ecSmrg
152505b261ecSmrg/* changed area is in dest */
152605b261ecSmrgstatic void
152705b261ecSmrgRootlessPushPixels(GCPtr pGC, PixmapPtr pBitMap, DrawablePtr dst,
152805b261ecSmrg                   int dx, int dy, int xOrg, int yOrg)
152905b261ecSmrg{
153005b261ecSmrg    BoxRec box;
153105b261ecSmrg
153205b261ecSmrg    GCOP_UNWRAP(pGC);
15334642e01fSmrg    GC_SKIP_ROOT(dst, pGC);
153405b261ecSmrg    RL_DEBUG_MSG("push pixels start ");
153505b261ecSmrg
153605b261ecSmrg    RootlessStartDrawing((WindowPtr) dst);
153705b261ecSmrg    pGC->ops->PushPixels(pGC, pBitMap, dst, dx, dy, xOrg, yOrg);
153805b261ecSmrg
153905b261ecSmrg    box.x1 = xOrg + dst->x;
154005b261ecSmrg    box.x2 = box.x1 + dx;
154105b261ecSmrg    box.y1 = yOrg + dst->y;
154205b261ecSmrg    box.y2 = box.y1 + dy;
154305b261ecSmrg
154405b261ecSmrg    TRIM_BOX(box, pGC);
154505b261ecSmrg    if (BOX_NOT_EMPTY(box))
154605b261ecSmrg        RootlessDamageBox ((WindowPtr) dst, &box);
154705b261ecSmrg
154805b261ecSmrg    GCOP_WRAP(pGC);
154905b261ecSmrg    RL_DEBUG_MSG("push pixels end\n");
155005b261ecSmrg}
1551