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