diff options
Diffstat (limited to 'miext/rootless/rootlessGC.c')
-rw-r--r-- | miext/rootless/rootlessGC.c | 1515 |
1 files changed, 1515 insertions, 0 deletions
diff --git a/miext/rootless/rootlessGC.c b/miext/rootless/rootlessGC.c new file mode 100644 index 000000000..8c70135a1 --- /dev/null +++ b/miext/rootless/rootlessGC.c @@ -0,0 +1,1515 @@ +/* + * Graphics Context support for generic rootless X server + */ +/* + * Copyright (c) 2001 Greg Parker. All Rights Reserved. + * Copyright (c) 2002-2003 Torrey T. Lyons. All Rights Reserved. + * Copyright (c) 2002 Apple Computer, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name(s) of the above copyright + * holders shall not be used in advertising or otherwise to promote the sale, + * use or other dealings in this Software without prior written authorization. + */ +/* $XFree86: xc/programs/Xserver/miext/rootless/rootlessGC.c,v 1.2 2003/10/24 00:33:14 torrey Exp $ */ + +#include "mi.h" +#include "scrnintstr.h" +#include "gcstruct.h" +#include "pixmapstr.h" +#include "windowstr.h" +#include "dixfontstr.h" +#include "mivalidate.h" +#include "fb.h" + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> + +#include "rootlessCommon.h" + +#if ROOTLESS_ACCEL +#include "rlAccel.h" +#endif + + +// GC functions +static void RootlessValidateGC(GCPtr pGC, unsigned long changes, + DrawablePtr pDrawable); +static void RootlessChangeGC(GCPtr pGC, unsigned long mask); +static void RootlessCopyGC(GCPtr pGCSrc, unsigned long mask, GCPtr pGCDst); +static void RootlessDestroyGC(GCPtr pGC); +static void RootlessChangeClip(GCPtr pGC, int type, pointer pvalue, + int nrects); +static void RootlessDestroyClip(GCPtr pGC); +static void RootlessCopyClip(GCPtr pgcDst, GCPtr pgcSrc); + +GCFuncs rootlessGCFuncs = { + RootlessValidateGC, + RootlessChangeGC, + RootlessCopyGC, + RootlessDestroyGC, + RootlessChangeClip, + RootlessDestroyClip, + RootlessCopyClip, +}; + +// GC operations +static void RootlessFillSpans(); +static void RootlessSetSpans(); +static void RootlessPutImage(); +static RegionPtr RootlessCopyArea(); +static RegionPtr RootlessCopyPlane(); +static void RootlessPolyPoint(); +static void RootlessPolylines(); +static void RootlessPolySegment(); +static void RootlessPolyRectangle(); +static void RootlessPolyArc(); +static void RootlessFillPolygon(); +static void RootlessPolyFillRect(); +static void RootlessPolyFillArc(); +static int RootlessPolyText8(); +static int RootlessPolyText16(); +static void RootlessImageText8(); +static void RootlessImageText16(); +static void RootlessImageGlyphBlt(); +static void RootlessPolyGlyphBlt(); +static void RootlessPushPixels(); + +static GCOps rootlessGCOps = { + RootlessFillSpans, + RootlessSetSpans, + RootlessPutImage, + RootlessCopyArea, + RootlessCopyPlane, + RootlessPolyPoint, + RootlessPolylines, + RootlessPolySegment, + RootlessPolyRectangle, + RootlessPolyArc, + RootlessFillPolygon, + RootlessPolyFillRect, + RootlessPolyFillArc, + RootlessPolyText8, + RootlessPolyText16, + RootlessImageText8, + RootlessImageText16, + RootlessImageGlyphBlt, + RootlessPolyGlyphBlt, + RootlessPushPixels +#ifdef NEED_LINEHELPER + , NULL +#endif +}; + +/* + There are two issues we must contend with when drawing. These are + controlled with ROOTLESS_PROTECT_ALPHA and ROOTLESS_ACCEL. + + If ROOTLESS_PROTECT_ALPHA is set, we have to make sure that the alpha + channel of the on screen windows is always opaque. fb makes this harder + than it would otherwise be by noticing that a planemask of 0x00ffffff + includes all bits when depth==24, and so it "optimizes" the planemask to + 0xffffffff. We work around this by temporarily setting depth=bpp while + changing the GC. + + So the normal situation (in 32 bit mode) is that the planemask is + 0x00ffffff and thus fb leaves the alpha channel alone. The rootless + implementation is responsible for setting the alpha channel opaque + initially. + + Unfortunately drawing with a planemask that doesn't have all bits set + normally causes fb to fall off its fastest paths when blitting and + filling. So we try to recognize when we can relax the planemask back to + 0xffffffff, and do that for the duration of the drawing operation, + setting the alpha channel in fg/bg pixels to opaque at the same time. We + can do this when drawing op is GXcopy. We can also do this when copying + from another window since its alpha channel must also be opaque. + + The other issue to consider is that the rootless implementation may + provide accelerated drawing functions if ROOTLESS_ACCEL is set. For some + drawing primitives we swap in rootless acceleration functions, which use + the accelerated drawing functions where possible. + + Where both alpha protection and acceleration is used, it is even a bigger + win to relax the planemask to all ones because most accelerated drawing + functions can only be used in this case. However, even if we can't set + the planemask to all ones, we can still use the accelerated + CompositePixels function for GXcopy if it is a forward copy. This is + mainly intended for copying from pixmaps to windows. The CompositePixels + operation used sets alpha to 0xFF during the copy. + + The three macros below are used to implement this, potentially accelerated + drawing ops look something like this: + + OP { + GC_SAVE(gc); + GCOP_UNWRAP(gc); + + ... + + if (can_accel_xxx(..) && otherwise-suitable) + GC_UNSET_PM(gc, dst); + + gc->funcs->OP(gc, ...); + + GC_RESTORE(gc, dst); + GCOP_WRAP(gc); + } + + */ + +#define GC_SAVE(pGC) \ + unsigned long _save_fg = (pGC)->fgPixel; \ + unsigned long _save_bg = (pGC)->bgPixel; \ + unsigned long _save_pm = (pGC)->planemask; \ + Bool _changed = FALSE + +#define GC_RESTORE(pGC, pDraw) \ + do { \ + if (_changed) { \ + unsigned int depth = (pDraw)->depth; \ + (pGC)->fgPixel = _save_fg; \ + (pGC)->bgPixel = _save_bg; \ + (pGC)->planemask = _save_pm; \ + (pDraw)->depth = (pDraw)->bitsPerPixel; \ + VALIDATE_GC(pGC, GCForeground | GCBackground | \ + GCPlaneMask, pDraw); \ + (pDraw)->depth = depth; \ + } \ + } while (0) + +#define GC_UNSET_PM(pGC, pDraw) \ + do { \ + unsigned int mask = RootlessAlphaMask ((pDraw)->bitsPerPixel); \ + if (((pGC)->planemask & mask) != mask) { \ + unsigned int depth = (pDraw)->depth; \ + (pGC)->fgPixel |= mask; \ + (pGC)->bgPixel |= mask; \ + (pGC)->planemask |= mask; \ + (pDraw)->depth = (pDraw)->bitsPerPixel; \ + VALIDATE_GC(pGC, GCForeground | \ + GCBackground | GCPlaneMask, pDraw); \ + (pDraw)->depth = depth; \ + _changed = TRUE; \ + } \ + } while (0) + +#define VALIDATE_GC(pGC, changes, pDrawable) \ + do { \ + pGC->funcs->ValidateGC(pGC, changes, pDrawable); \ + if (((WindowPtr) pDrawable)->viewable) { \ + gcrec->originalOps = pGC->ops; \ + } \ + } while(0) + +static RootlessWindowRec * +canAccelBlit (DrawablePtr pDraw, GCPtr pGC) +{ + WindowPtr pTop; + RootlessWindowRec *winRec; + unsigned int pm; + + if (pGC->alu != GXcopy) + return NULL; + + if (pDraw->type != DRAWABLE_WINDOW) + return NULL; + + pm = ~RootlessAlphaMask(pDraw->bitsPerPixel); + if ((pGC->planemask & pm) != pm) + return NULL; + + pTop = TopLevelParent((WindowPtr) pDraw); + if (pTop == NULL) + return NULL; + + winRec = WINREC(pTop); + if (winRec == NULL) + return NULL; + + return winRec; +} + +static inline RootlessWindowRec * +canAccelFill(DrawablePtr pDraw, GCPtr pGC) +{ + if (pGC->fillStyle != FillSolid) + return NULL; + + return canAccelBlit(pDraw, pGC); +} + +static unsigned int +boxBytes(DrawablePtr pDraw, BoxRec *box) +{ + unsigned int pixels; + + pixels = (box->x2 - box->x1) * (box->y2 - box->y1); + + return pixels * (pDraw->bitsPerPixel >> 3); +} + + +/* + * Screen function to create a graphics context + */ +Bool +RootlessCreateGC(GCPtr pGC) +{ + RootlessGCRec *gcrec; + RootlessScreenRec *s; + Bool result; + + SCREEN_UNWRAP(pGC->pScreen, CreateGC); + s = (RootlessScreenRec *) pGC->pScreen-> + devPrivates[rootlessScreenPrivateIndex].ptr; + result = s->CreateGC(pGC); + +#if ROOTLESS_ACCEL + pGC->ops->FillSpans = rlFillSpans; + pGC->ops->CopyArea = rlCopyArea; + pGC->ops->PolyFillRect = rlPolyFillRect; + pGC->ops->ImageGlyphBlt = rlImageGlyphBlt; +#endif + + gcrec = (RootlessGCRec *) pGC->devPrivates[rootlessGCPrivateIndex].ptr; + gcrec->originalOps = NULL; // don't wrap ops yet + gcrec->originalFuncs = pGC->funcs; + pGC->funcs = &rootlessGCFuncs; + + SCREEN_WRAP(pGC->pScreen, CreateGC); + return result; +} + + +/* + * GC funcs + * + * These wrap lower level GC funcs. + * ValidateGC wraps the GC ops iff dest is viewable. + * All the others just unwrap and call. + */ + +// GCFUNC_UNRAP assumes funcs have been wrapped and +// does not assume ops have been wrapped +#define GCFUNC_UNWRAP(pGC) \ + RootlessGCRec *gcrec = (RootlessGCRec *) \ + (pGC)->devPrivates[rootlessGCPrivateIndex].ptr; \ + (pGC)->funcs = gcrec->originalFuncs; \ + if (gcrec->originalOps) { \ + (pGC)->ops = gcrec->originalOps; \ +} + +#define GCFUNC_WRAP(pGC) \ + gcrec->originalFuncs = (pGC)->funcs; \ + (pGC)->funcs = &rootlessGCFuncs; \ + if (gcrec->originalOps) { \ + gcrec->originalOps = (pGC)->ops; \ + (pGC)->ops = &rootlessGCOps; \ +} + + +static void +RootlessValidateGC(GCPtr pGC, unsigned long changes, DrawablePtr pDrawable) +{ + GCFUNC_UNWRAP(pGC); + + gcrec->originalOps = NULL; + + if (pDrawable->type == DRAWABLE_WINDOW) + { +#ifdef ROOTLESS_PROTECT_ALPHA + unsigned int depth = pDrawable->depth; + + // We force a planemask so fb doesn't overwrite the alpha channel. + // Left to its own devices, fb will optimize away the planemask. + pDrawable->depth = pDrawable->bitsPerPixel; + pGC->planemask &= ~RootlessAlphaMask(pDrawable->bitsPerPixel); + VALIDATE_GC(pGC, changes | GCPlaneMask, pDrawable); + pDrawable->depth = depth; +#else + VALIDATE_GC(pGC, changes, pDrawable); +#endif + } else { + pGC->funcs->ValidateGC(pGC, changes, pDrawable); + } + + GCFUNC_WRAP(pGC); +} + +static void RootlessChangeGC(GCPtr pGC, unsigned long mask) +{ + GCFUNC_UNWRAP(pGC); + pGC->funcs->ChangeGC(pGC, mask); + GCFUNC_WRAP(pGC); +} + +static void RootlessCopyGC(GCPtr pGCSrc, unsigned long mask, GCPtr pGCDst) +{ + GCFUNC_UNWRAP(pGCDst); + pGCDst->funcs->CopyGC(pGCSrc, mask, pGCDst); + GCFUNC_WRAP(pGCDst); +} + +static void RootlessDestroyGC(GCPtr pGC) +{ + GCFUNC_UNWRAP(pGC); + pGC->funcs->DestroyGC(pGC); + GCFUNC_WRAP(pGC); +} + +static void RootlessChangeClip(GCPtr pGC, int type, pointer pvalue, int nrects) +{ + GCFUNC_UNWRAP(pGC); + pGC->funcs->ChangeClip(pGC, type, pvalue, nrects); + GCFUNC_WRAP(pGC); +} + +static void RootlessDestroyClip(GCPtr pGC) +{ + GCFUNC_UNWRAP(pGC); + pGC->funcs->DestroyClip(pGC); + GCFUNC_WRAP(pGC); +} + +static void RootlessCopyClip(GCPtr pgcDst, GCPtr pgcSrc) +{ + GCFUNC_UNWRAP(pgcDst); + pgcDst->funcs->CopyClip(pgcDst, pgcSrc); + GCFUNC_WRAP(pgcDst); +} + + +/* + * GC ops + * + * We can't use shadowfb because shadowfb assumes one pixmap + * and our root window is a special case. + * However, much of this code is copied from shadowfb. + */ + +// assumes both funcs and ops are wrapped +#define GCOP_UNWRAP(pGC) \ + RootlessGCRec *gcrec = (RootlessGCRec *) \ + (pGC)->devPrivates[rootlessGCPrivateIndex].ptr; \ + GCFuncs *saveFuncs = pGC->funcs; \ + (pGC)->funcs = gcrec->originalFuncs; \ + (pGC)->ops = gcrec->originalOps; + +#define GCOP_WRAP(pGC) \ + gcrec->originalOps = (pGC)->ops; \ + (pGC)->funcs = saveFuncs; \ + (pGC)->ops = &rootlessGCOps; + +/* Turn drawing on the root into a no-op */ +#define GC_IS_ROOT(pDst) ((pDst)->type == DRAWABLE_WINDOW \ + && IsRoot ((WindowPtr) (pDst))) + +#define GC_SKIP_ROOT(pDst) \ + do { \ + if (GC_IS_ROOT (pDst)) \ + return; \ + } while (0) + + +static void +RootlessFillSpans(DrawablePtr dst, GCPtr pGC, int nInit, + DDXPointPtr pptInit, int *pwidthInit, int sorted) +{ + GC_SAVE(pGC); + GCOP_UNWRAP(pGC); + GC_SKIP_ROOT(dst); + RL_DEBUG_MSG("fill spans start "); + + if (nInit <= 0) { + pGC->ops->FillSpans(dst, pGC, nInit, pptInit, pwidthInit, sorted); + } else { + DDXPointPtr ppt = pptInit; + int *pwidth = pwidthInit; + int i = nInit; + BoxRec box; + + box.x1 = ppt->x; + box.x2 = box.x1 + *pwidth; + box.y2 = box.y1 = ppt->y; + + while (--i) { + ppt++; + pwidth++; + if (box.x1 > ppt->x) + box.x1 = ppt->x; + if (box.x2 < (ppt->x + *pwidth)) + box.x2 = ppt->x + *pwidth; + if (box.y1 > ppt->y) + box.y1 = ppt->y; + else if (box.y2 < ppt->y) + box.y2 = ppt->y; + } + + box.y2++; + + RootlessStartDrawing((WindowPtr) dst); + + if (canAccelFill(dst, pGC) && + boxBytes(dst, &box) >= rootless_FillBytes_threshold) + { + GC_UNSET_PM(pGC, dst); + } + + pGC->ops->FillSpans(dst, pGC, nInit, pptInit, pwidthInit, sorted); + + TRIM_AND_TRANSLATE_BOX(box, dst, pGC); + if (BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + } + + GC_RESTORE(pGC, dst); + GCOP_WRAP(pGC); + RL_DEBUG_MSG("fill spans end\n"); +} + +static void +RootlessSetSpans(DrawablePtr dst, GCPtr pGC, char *pSrc, + DDXPointPtr pptInit, int *pwidthInit, + int nspans, int sorted) +{ + GCOP_UNWRAP(pGC); + GC_SKIP_ROOT(dst); + RL_DEBUG_MSG("set spans start "); + + if (nspans <= 0) { + pGC->ops->SetSpans(dst, pGC, pSrc, pptInit, pwidthInit, + nspans, sorted); + } else { + DDXPointPtr ppt = pptInit; + int *pwidth = pwidthInit; + int i = nspans; + BoxRec box; + + box.x1 = ppt->x; + box.x2 = box.x1 + *pwidth; + box.y2 = box.y1 = ppt->y; + + while (--i) { + ppt++; + pwidth++; + if (box.x1 > ppt->x) + box.x1 = ppt->x; + if (box.x2 < (ppt->x + *pwidth)) + box.x2 = ppt->x + *pwidth; + if (box.y1 > ppt->y) + box.y1 = ppt->y; + else if (box.y2 < ppt->y) + box.y2 = ppt->y; + } + + box.y2++; + + RootlessStartDrawing((WindowPtr) dst); + pGC->ops->SetSpans(dst, pGC, pSrc, pptInit, pwidthInit, + nspans, sorted); + + TRIM_AND_TRANSLATE_BOX(box, dst, pGC); + if (BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + } + GCOP_WRAP(pGC); + RL_DEBUG_MSG("set spans end\n"); +} + +static void +RootlessPutImage(DrawablePtr dst, GCPtr pGC, + int depth, int x, int y, int w, int h, + int leftPad, int format, char *pBits) +{ + BoxRec box; + + GCOP_UNWRAP(pGC); + GC_SKIP_ROOT(dst); + RL_DEBUG_MSG("put image start "); + + RootlessStartDrawing((WindowPtr) dst); + pGC->ops->PutImage(dst, pGC, depth, x,y,w,h, leftPad, format, pBits); + + box.x1 = x + dst->x; + box.x2 = box.x1 + w; + box.y1 = y + dst->y; + box.y2 = box.y1 + h; + + TRIM_BOX(box, pGC); + if (BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + + GCOP_WRAP(pGC); + RL_DEBUG_MSG("put image end\n"); +} + +/* changed area is *dest* rect */ +static RegionPtr +RootlessCopyArea(DrawablePtr pSrc, DrawablePtr dst, GCPtr pGC, + int srcx, int srcy, int w, int h, + int dstx, int dsty) +{ + RegionPtr result; + BoxRec box; + + GC_SAVE(pGC); + GCOP_UNWRAP(pGC); + + if (GC_IS_ROOT(dst) || GC_IS_ROOT(pSrc)) + return NULL; /* nothing exposed */ + + RL_DEBUG_MSG("copy area start (src 0x%x, dst 0x%x)", pSrc, dst); + + if (pSrc->type == DRAWABLE_WINDOW && IsFramedWindow((WindowPtr)pSrc)) { + unsigned int bytes; + + /* If both source and dest are windows, and we're doing + a simple copy operation, we can remove the alpha-protecting + planemask (since source has opaque alpha as well) */ + + bytes = w * h * (pSrc->depth >> 3); + + if (bytes >= rootless_CopyBytes_threshold && canAccelBlit(pSrc, pGC)) + { + GC_UNSET_PM(pGC, dst); + } + + RootlessStartDrawing((WindowPtr) pSrc); + } + RootlessStartDrawing((WindowPtr) dst); + result = pGC->ops->CopyArea(pSrc, dst, pGC, srcx, srcy, w, h, dstx, dsty); + + box.x1 = dstx + dst->x; + box.x2 = box.x1 + w; + box.y1 = dsty + dst->y; + box.y2 = box.y1 + h; + + TRIM_BOX(box, pGC); + if (BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + + GC_RESTORE(pGC, dst); + GCOP_WRAP(pGC); + RL_DEBUG_MSG("copy area end\n"); + return result; +} + +/* changed area is *dest* rect */ +static RegionPtr RootlessCopyPlane(DrawablePtr pSrc, DrawablePtr dst, + GCPtr pGC, int srcx, int srcy, + int w, int h, int dstx, int dsty, + unsigned long plane) +{ + RegionPtr result; + BoxRec box; + + GCOP_UNWRAP(pGC); + + if (GC_IS_ROOT(dst) || GC_IS_ROOT(pSrc)) + return NULL; /* nothing exposed */ + + RL_DEBUG_MSG("copy plane start "); + + if (pSrc->type == DRAWABLE_WINDOW && IsFramedWindow((WindowPtr)pSrc)) { + RootlessStartDrawing((WindowPtr) pSrc); + } + RootlessStartDrawing((WindowPtr) dst); + result = pGC->ops->CopyPlane(pSrc, dst, pGC, srcx, srcy, w, h, + dstx, dsty, plane); + + box.x1 = dstx + dst->x; + box.x2 = box.x1 + w; + box.y1 = dsty + dst->y; + box.y2 = box.y1 + h; + + TRIM_BOX(box, pGC); + if (BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + + GCOP_WRAP(pGC); + RL_DEBUG_MSG("copy plane end\n"); + return result; +} + +// Options for size of changed area: +// 0 = box per point +// 1 = big box around all points +// 2 = accumulate point in 20 pixel radius +#define ROOTLESS_CHANGED_AREA 1 +#define abs(a) ((a) > 0 ? (a) : -(a)) + +/* changed area is box around all points */ +static void RootlessPolyPoint(DrawablePtr dst, GCPtr pGC, + int mode, int npt, DDXPointPtr pptInit) +{ + GCOP_UNWRAP(pGC); + GC_SKIP_ROOT(dst); + RL_DEBUG_MSG("polypoint start "); + + RootlessStartDrawing((WindowPtr) dst); + pGC->ops->PolyPoint(dst, pGC, mode, npt, pptInit); + + if (npt > 0) { +#if ROOTLESS_CHANGED_AREA==0 + // box per point + BoxRec box; + + while (npt) { + box.x1 = pptInit->x; + box.y1 = pptInit->y; + box.x2 = box.x1 + 1; + box.y2 = box.y1 + 1; + + TRIM_AND_TRANSLATE_BOX(box, dst, pGC); + if (BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + + npt--; + pptInit++; + } + +#elif ROOTLESS_CHANGED_AREA==1 + // one big box + BoxRec box; + + box.x2 = box.x1 = pptInit->x; + box.y2 = box.y1 = pptInit->y; + while (--npt) { + pptInit++; + if (box.x1 > pptInit->x) + box.x1 = pptInit->x; + else if (box.x2 < pptInit->x) + box.x2 = pptInit->x; + if (box.y1 > pptInit->y) + box.y1 = pptInit->y; + else if (box.y2 < pptInit->y) + box.y2 = pptInit->y; + } + + box.x2++; + box.y2++; + + TRIM_AND_TRANSLATE_BOX(box, dst, pGC); + if (BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + +#elif ROOTLESS_CHANGED_AREA==2 + // clever(?) method: accumulate point in 20-pixel radius + BoxRec box; + int firstx, firsty; + + box.x2 = box.x1 = firstx = pptInit->x; + box.y2 = box.y1 = firsty = pptInit->y; + while (--npt) { + pptInit++; + if (abs(pptInit->x - firstx) > 20 || + abs(pptInit->y - firsty) > 20) { + box.x2++; + box.y2++; + TRIM_AND_TRANSLATE_BOX(box, dst, pGC); + if (BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + box.x2 = box.x1 = firstx = pptInit->x; + box.y2 = box.y1 = firsty = pptInit->y; + } else { + if (box.x1 > pptInit->x) box.x1 = pptInit->x; + else if (box.x2 < pptInit->x) box.x2 = pptInit->x; + if (box.y1 > pptInit->y) box.y1 = pptInit->y; + else if (box.y2 < pptInit->y) box.y2 = pptInit->y; + } + } + box.x2++; + box.y2++; + TRIM_AND_TRANSLATE_BOX(box, dst, pGC); + if (BOX_NOT_EMPTY(box)) + RootlessDamageBox((WindowPtr) dst, &box); +#endif /* ROOTLESS_CHANGED_AREA */ + } + + GCOP_WRAP(pGC); + RL_DEBUG_MSG("polypoint end\n"); +} + +#undef ROOTLESS_CHANGED_AREA + +/* changed area is box around each line */ +static void RootlessPolylines(DrawablePtr dst, GCPtr pGC, + int mode, int npt, DDXPointPtr pptInit) +{ + GCOP_UNWRAP(pGC); + GC_SKIP_ROOT(dst); + RL_DEBUG_MSG("poly lines start "); + + RootlessStartDrawing((WindowPtr) dst); + pGC->ops->Polylines(dst, pGC, mode, npt, pptInit); + + if (npt > 0) { + BoxRec box; + int extra = pGC->lineWidth >> 1; + + box.x2 = box.x1 = pptInit->x; + box.y2 = box.y1 = pptInit->y; + + if (npt > 1) { + if (pGC->joinStyle == JoinMiter) + extra = 6 * pGC->lineWidth; + else if (pGC->capStyle == CapProjecting) + extra = pGC->lineWidth; + } + + if (mode == CoordModePrevious) { + int x = box.x1; + int y = box.y1; + + while (--npt) { + pptInit++; + x += pptInit->x; + y += pptInit->y; + if (box.x1 > x) + box.x1 = x; + else if (box.x2 < x) + box.x2 = x; + if (box.y1 > y) + box.y1 = y; + else if (box.y2 < y) + box.y2 = y; + } + } else { + while (--npt) { + pptInit++; + if (box.x1 > pptInit->x) + box.x1 = pptInit->x; + else if (box.x2 < pptInit->x) + box.x2 = pptInit->x; + if (box.y1 > pptInit->y) + box.y1 = pptInit->y; + else if (box.y2 < pptInit->y) + box.y2 = pptInit->y; + } + } + + box.x2++; + box.y2++; + + if (extra) { + box.x1 -= extra; + box.x2 += extra; + box.y1 -= extra; + box.y2 += extra; + } + + TRIM_AND_TRANSLATE_BOX(box, dst, pGC); + if (BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + } + + GCOP_WRAP(pGC); + RL_DEBUG_MSG("poly lines end\n"); +} + +/* changed area is box around each line segment */ +static void RootlessPolySegment(DrawablePtr dst, GCPtr pGC, + int nseg, xSegment *pSeg) +{ + GCOP_UNWRAP(pGC); + GC_SKIP_ROOT(dst); + RL_DEBUG_MSG("poly segment start (win 0x%x)", dst); + + RootlessStartDrawing((WindowPtr) dst); + pGC->ops->PolySegment(dst, pGC, nseg, pSeg); + + if (nseg > 0) { + BoxRec box; + int extra = pGC->lineWidth; + + if (pGC->capStyle != CapProjecting) + extra >>= 1; + + if (pSeg->x2 > pSeg->x1) { + box.x1 = pSeg->x1; + box.x2 = pSeg->x2; + } else { + box.x2 = pSeg->x1; + box.x1 = pSeg->x2; + } + + if (pSeg->y2 > pSeg->y1) { + box.y1 = pSeg->y1; + box.y2 = pSeg->y2; + } else { + box.y2 = pSeg->y1; + box.y1 = pSeg->y2; + } + + while (--nseg) { + pSeg++; + if (pSeg->x2 > pSeg->x1) { + if (pSeg->x1 < box.x1) box.x1 = pSeg->x1; + if (pSeg->x2 > box.x2) box.x2 = pSeg->x2; + } else { + if (pSeg->x2 < box.x1) box.x1 = pSeg->x2; + if (pSeg->x1 > box.x2) box.x2 = pSeg->x1; + } + if (pSeg->y2 > pSeg->y1) { + if (pSeg->y1 < box.y1) box.y1 = pSeg->y1; + if (pSeg->y2 > box.y2) box.y2 = pSeg->y2; + } else { + if (pSeg->y2 < box.y1) box.y1 = pSeg->y2; + if (pSeg->y1 > box.y2) box.y2 = pSeg->y1; + } + } + + box.x2++; + box.y2++; + + if (extra) { + box.x1 -= extra; + box.x2 += extra; + box.y1 -= extra; + box.y2 += extra; + } + + TRIM_AND_TRANSLATE_BOX(box, dst, pGC); + if (BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + } + + GCOP_WRAP(pGC); + RL_DEBUG_MSG("poly segment end\n"); +} + +/* changed area is box around each line (not entire rects) */ +static void RootlessPolyRectangle(DrawablePtr dst, GCPtr pGC, + int nRects, xRectangle *pRects) +{ + GCOP_UNWRAP(pGC); + GC_SKIP_ROOT(dst); + RL_DEBUG_MSG("poly rectangle start "); + + RootlessStartDrawing((WindowPtr) dst); + pGC->ops->PolyRectangle(dst, pGC, nRects, pRects); + + if (nRects > 0) { + BoxRec box; + int offset1, offset2, offset3; + + offset2 = pGC->lineWidth; + if (!offset2) offset2 = 1; + offset1 = offset2 >> 1; + offset3 = offset2 - offset1; + + while (nRects--) { + box.x1 = pRects->x - offset1; + box.y1 = pRects->y - offset1; + box.x2 = box.x1 + pRects->width + offset2; + box.y2 = box.y1 + offset2; + TRIM_AND_TRANSLATE_BOX(box, dst, pGC); + if (BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + + box.x1 = pRects->x - offset1; + box.y1 = pRects->y + offset3; + box.x2 = box.x1 + offset2; + box.y2 = box.y1 + pRects->height - offset2; + TRIM_AND_TRANSLATE_BOX(box, dst, pGC); + if (BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + + box.x1 = pRects->x + pRects->width - offset1; + box.y1 = pRects->y + offset3; + box.x2 = box.x1 + offset2; + box.y2 = box.y1 + pRects->height - offset2; + TRIM_AND_TRANSLATE_BOX(box, dst, pGC); + if (BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + + box.x1 = pRects->x - offset1; + box.y1 = pRects->y + pRects->height - offset1; + box.x2 = box.x1 + pRects->width + offset2; + box.y2 = box.y1 + offset2; + TRIM_AND_TRANSLATE_BOX(box, dst, pGC); + if (BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + + pRects++; + } + } + + GCOP_WRAP(pGC); + RL_DEBUG_MSG("poly rectangle end\n"); +} + + +/* changed area is box around each arc (assumes all arcs are 360 degrees) */ +static void RootlessPolyArc(DrawablePtr dst, GCPtr pGC, int narcs, xArc *parcs) +{ + GCOP_UNWRAP(pGC); + GC_SKIP_ROOT(dst); + RL_DEBUG_MSG("poly arc start "); + + RootlessStartDrawing((WindowPtr) dst); + pGC->ops->PolyArc(dst, pGC, narcs, parcs); + + if (narcs > 0) { + int extra = pGC->lineWidth >> 1; + BoxRec box; + + box.x1 = parcs->x; + box.x2 = box.x1 + parcs->width; + box.y1 = parcs->y; + box.y2 = box.y1 + parcs->height; + + /* should I break these up instead ? */ + + while (--narcs) { + parcs++; + if (box.x1 > parcs->x) + box.x1 = parcs->x; + if (box.x2 < (parcs->x + parcs->width)) + box.x2 = parcs->x + parcs->width; + if (box.y1 > parcs->y) + box.y1 = parcs->y; + if (box.y2 < (parcs->y + parcs->height)) + box.y2 = parcs->y + parcs->height; + } + + if (extra) { + box.x1 -= extra; + box.x2 += extra; + box.y1 -= extra; + box.y2 += extra; + } + + box.x2++; + box.y2++; + + TRIM_AND_TRANSLATE_BOX(box, dst, pGC); + if (BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + } + + GCOP_WRAP(pGC); + RL_DEBUG_MSG("poly arc end\n"); +} + + +/* changed area is box around each poly */ +static void RootlessFillPolygon(DrawablePtr dst, GCPtr pGC, + int shape, int mode, int count, + DDXPointPtr pptInit) +{ + GC_SAVE(pGC); + GCOP_UNWRAP(pGC); + GC_SKIP_ROOT(dst); + RL_DEBUG_MSG("fill poly start (win 0x%x, fillStyle 0x%x)", dst, + pGC->fillStyle); + + if (count <= 2) { + pGC->ops->FillPolygon(dst, pGC, shape, mode, count, pptInit); + } else { + DDXPointPtr ppt = pptInit; + int i = count; + BoxRec box; + + box.x2 = box.x1 = ppt->x; + box.y2 = box.y1 = ppt->y; + + if (mode != CoordModeOrigin) { + int x = box.x1; + int y = box.y1; + + while (--i) { + ppt++; + x += ppt->x; + y += ppt->y; + if (box.x1 > x) + box.x1 = x; + else if (box.x2 < x) + box.x2 = x; + if (box.y1 > y) + box.y1 = y; + else if (box.y2 < y) + box.y2 = y; + } + } else { + while (--i) { + ppt++; + if (box.x1 > ppt->x) + box.x1 = ppt->x; + else if (box.x2 < ppt->x) + box.x2 = ppt->x; + if (box.y1 > ppt->y) + box.y1 = ppt->y; + else if (box.y2 < ppt->y) + box.y2 = ppt->y; + } + } + + box.x2++; + box.y2++; + + RootlessStartDrawing((WindowPtr) dst); + + if (canAccelFill(dst, pGC) && + boxBytes(dst, &box) >= rootless_FillBytes_threshold) + { + GC_UNSET_PM(pGC, dst); + } + + pGC->ops->FillPolygon(dst, pGC, shape, mode, count, pptInit); + + TRIM_AND_TRANSLATE_BOX(box, dst, pGC); + if (BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + } + + GC_RESTORE(pGC, dst); + GCOP_WRAP(pGC); + RL_DEBUG_MSG("fill poly end\n"); +} + +/* changed area is the rects */ +static void RootlessPolyFillRect(DrawablePtr dst, GCPtr pGC, + int nRectsInit, xRectangle *pRectsInit) +{ + GC_SAVE(pGC); + GCOP_UNWRAP(pGC); + GC_SKIP_ROOT(dst); + RL_DEBUG_MSG("fill rect start (win 0x%x, fillStyle 0x%x)", dst, + pGC->fillStyle); + + if (nRectsInit <= 0) { + pGC->ops->PolyFillRect(dst, pGC, nRectsInit, pRectsInit); + } else { + BoxRec box; + xRectangle *pRects = pRectsInit; + int nRects = nRectsInit; + + box.x1 = pRects->x; + box.x2 = box.x1 + pRects->width; + box.y1 = pRects->y; + box.y2 = box.y1 + pRects->height; + + while (--nRects) { + pRects++; + if (box.x1 > pRects->x) + box.x1 = pRects->x; + if (box.x2 < (pRects->x + pRects->width)) + box.x2 = pRects->x + pRects->width; + if (box.y1 > pRects->y) + box.y1 = pRects->y; + if (box.y2 < (pRects->y + pRects->height)) + box.y2 = pRects->y + pRects->height; + } + + RootlessStartDrawing((WindowPtr) dst); + + if (canAccelFill(dst, pGC) && + boxBytes(dst, &box) >= rootless_FillBytes_threshold) + { + GC_UNSET_PM(pGC, dst); + } + + pGC->ops->PolyFillRect(dst, pGC, nRectsInit, pRectsInit); + + TRIM_AND_TRANSLATE_BOX(box, dst, pGC); + if (BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + } + + GC_RESTORE(pGC, dst); + GCOP_WRAP(pGC); + RL_DEBUG_MSG("fill rect end\n"); +} + + +/* changed area is box around each arc (assuming arcs are all 360 degrees) */ +static void RootlessPolyFillArc(DrawablePtr dst, GCPtr pGC, + int narcsInit, xArc *parcsInit) +{ + GC_SAVE(pGC); + GCOP_UNWRAP(pGC); + GC_SKIP_ROOT(dst); + RL_DEBUG_MSG("fill arc start "); + + if (narcsInit > 0) { + BoxRec box; + int narcs = narcsInit; + xArc *parcs = parcsInit; + + box.x1 = parcs->x; + box.x2 = box.x1 + parcs->width; + box.y1 = parcs->y; + box.y2 = box.y1 + parcs->height; + + /* should I break these up instead ? */ + + while (--narcs) { + parcs++; + if (box.x1 > parcs->x) + box.x1 = parcs->x; + if (box.x2 < (parcs->x + parcs->width)) + box.x2 = parcs->x + parcs->width; + if (box.y1 > parcs->y) + box.y1 = parcs->y; + if (box.y2 < (parcs->y + parcs->height)) + box.y2 = parcs->y + parcs->height; + } + + RootlessStartDrawing((WindowPtr) dst); + + if (canAccelFill(dst, pGC) && + boxBytes(dst, &box) >= rootless_FillBytes_threshold) + { + GC_UNSET_PM(pGC, dst); + } + + pGC->ops->PolyFillArc(dst, pGC, narcsInit, parcsInit); + + TRIM_AND_TRANSLATE_BOX(box, dst, pGC); + if (BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + } else { + pGC->ops->PolyFillArc(dst, pGC, narcsInit, parcsInit); + } + + GC_RESTORE(pGC, dst); + GCOP_WRAP(pGC); + RL_DEBUG_MSG("fill arc end\n"); +} + + +static void RootlessImageText8(DrawablePtr dst, GCPtr pGC, + int x, int y, int count, char *chars) +{ + GC_SAVE(pGC); + GCOP_UNWRAP(pGC); + GC_SKIP_ROOT(dst); + RL_DEBUG_MSG("imagetext8 start "); + + if (count > 0) { + int top, bot, Min, Max; + BoxRec box; + + top = max(FONTMAXBOUNDS(pGC->font, ascent), FONTASCENT(pGC->font)); + bot = max(FONTMAXBOUNDS(pGC->font, descent), FONTDESCENT(pGC->font)); + + Min = count * FONTMINBOUNDS(pGC->font, characterWidth); + if (Min > 0) Min = 0; + Max = count * FONTMAXBOUNDS(pGC->font, characterWidth); + if (Max < 0) Max = 0; + + /* ugh */ + box.x1 = dst->x + x + Min + + FONTMINBOUNDS(pGC->font, leftSideBearing); + box.x2 = dst->x + x + Max + + FONTMAXBOUNDS(pGC->font, rightSideBearing); + + box.y1 = dst->y + y - top; + box.y2 = dst->y + y + bot; + + RootlessStartDrawing((WindowPtr) dst); + + if (canAccelFill(dst, pGC) && + boxBytes(dst, &box) >= rootless_FillBytes_threshold) + { + GC_UNSET_PM(pGC, dst); + } + + pGC->ops->ImageText8(dst, pGC, x, y, count, chars); + + TRIM_BOX(box, pGC); + if (BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + } else { + pGC->ops->ImageText8(dst, pGC, x, y, count, chars); + } + + GC_RESTORE(pGC, dst); + GCOP_WRAP(pGC); + RL_DEBUG_MSG("imagetext8 end\n"); +} + +static int RootlessPolyText8(DrawablePtr dst, GCPtr pGC, + int x, int y, int count, char *chars) +{ + int width; // the result, sorta + + GCOP_UNWRAP(pGC); + + if (GC_IS_ROOT(dst)) + return 0; + + RL_DEBUG_MSG("polytext8 start "); + + RootlessStartDrawing((WindowPtr) dst); + width = pGC->ops->PolyText8(dst, pGC, x, y, count, chars); + width -= x; + + if (width > 0) { + BoxRec box; + + /* ugh */ + box.x1 = dst->x + x + FONTMINBOUNDS(pGC->font, leftSideBearing); + box.x2 = dst->x + x + FONTMAXBOUNDS(pGC->font, rightSideBearing); + + if (count > 1) { + if (width > 0) box.x2 += width; + else box.x1 += width; + } + + box.y1 = dst->y + y - FONTMAXBOUNDS(pGC->font, ascent); + box.y2 = dst->y + y + FONTMAXBOUNDS(pGC->font, descent); + + TRIM_BOX(box, pGC); + if (BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + } + + GCOP_WRAP(pGC); + RL_DEBUG_MSG("polytext8 end\n"); + return (width + x); +} + +static void RootlessImageText16(DrawablePtr dst, GCPtr pGC, + int x, int y, int count, unsigned short *chars) +{ + GC_SAVE(pGC); + GCOP_UNWRAP(pGC); + GC_SKIP_ROOT(dst); + RL_DEBUG_MSG("imagetext16 start "); + + if (count > 0) { + int top, bot, Min, Max; + BoxRec box; + + top = max(FONTMAXBOUNDS(pGC->font, ascent), FONTASCENT(pGC->font)); + bot = max(FONTMAXBOUNDS(pGC->font, descent), FONTDESCENT(pGC->font)); + + Min = count * FONTMINBOUNDS(pGC->font, characterWidth); + if (Min > 0) Min = 0; + Max = count * FONTMAXBOUNDS(pGC->font, characterWidth); + if (Max < 0) Max = 0; + + /* ugh */ + box.x1 = dst->x + x + Min + + FONTMINBOUNDS(pGC->font, leftSideBearing); + box.x2 = dst->x + x + Max + + FONTMAXBOUNDS(pGC->font, rightSideBearing); + + box.y1 = dst->y + y - top; + box.y2 = dst->y + y + bot; + + RootlessStartDrawing((WindowPtr) dst); + + if (canAccelFill(dst, pGC) && + boxBytes(dst, &box) >= rootless_FillBytes_threshold) + { + GC_UNSET_PM(pGC, dst); + } + + pGC->ops->ImageText16(dst, pGC, x, y, count, chars); + + TRIM_BOX(box, pGC); + if (BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + } else { + pGC->ops->ImageText16(dst, pGC, x, y, count, chars); + } + + GC_RESTORE(pGC, dst); + GCOP_WRAP(pGC); + RL_DEBUG_MSG("imagetext16 end\n"); +} + +static int RootlessPolyText16(DrawablePtr dst, GCPtr pGC, + int x, int y, int count, unsigned short *chars) +{ + int width; // the result, sorta + + GCOP_UNWRAP(pGC); + + if (GC_IS_ROOT(dst)) + return 0; + + RL_DEBUG_MSG("polytext16 start "); + + RootlessStartDrawing((WindowPtr) dst); + width = pGC->ops->PolyText16(dst, pGC, x, y, count, chars); + width -= x; + + if (width > 0) { + BoxRec box; + + /* ugh */ + box.x1 = dst->x + x + FONTMINBOUNDS(pGC->font, leftSideBearing); + box.x2 = dst->x + x + FONTMAXBOUNDS(pGC->font, rightSideBearing); + + if (count > 1) { + if (width > 0) box.x2 += width; + else box.x1 += width; + } + + box.y1 = dst->y + y - FONTMAXBOUNDS(pGC->font, ascent); + box.y2 = dst->y + y + FONTMAXBOUNDS(pGC->font, descent); + + TRIM_BOX(box, pGC); + if (BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + } + + GCOP_WRAP(pGC); + RL_DEBUG_MSG("polytext16 end\n"); + return width + x; +} + +static void RootlessImageGlyphBlt(DrawablePtr dst, GCPtr pGC, + int x, int y, unsigned int nglyphInit, + CharInfoPtr *ppciInit, pointer unused) +{ + GC_SAVE(pGC); + GCOP_UNWRAP(pGC); + GC_SKIP_ROOT(dst); + RL_DEBUG_MSG("imageglyph start "); + + if (nglyphInit > 0) { + int top, bot, width = 0; + BoxRec box; + unsigned int nglyph = nglyphInit; + CharInfoPtr *ppci = ppciInit; + + top = max(FONTMAXBOUNDS(pGC->font, ascent), FONTASCENT(pGC->font)); + bot = max(FONTMAXBOUNDS(pGC->font, descent), FONTDESCENT(pGC->font)); + + box.x1 = ppci[0]->metrics.leftSideBearing; + if (box.x1 > 0) box.x1 = 0; + box.x2 = ppci[nglyph - 1]->metrics.rightSideBearing - + ppci[nglyph - 1]->metrics.characterWidth; + if (box.x2 < 0) box.x2 = 0; + + box.x2 += dst->x + x; + box.x1 += dst->x + x; + + while (nglyph--) { + width += (*ppci)->metrics.characterWidth; + ppci++; + } + + if (width > 0) + box.x2 += width; + else + box.x1 += width; + + box.y1 = dst->y + y - top; + box.y2 = dst->y + y + bot; + + RootlessStartDrawing((WindowPtr) dst); + + if (canAccelFill(dst, pGC) && + boxBytes(dst, &box) >= rootless_FillBytes_threshold) + { + GC_UNSET_PM(pGC, dst); + } + + pGC->ops->ImageGlyphBlt(dst, pGC, x, y, nglyphInit, ppciInit, unused); + + TRIM_BOX(box, pGC); + if (BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + } else { + pGC->ops->ImageGlyphBlt(dst, pGC, x, y, nglyphInit, ppciInit, unused); + } + + GC_RESTORE(pGC, dst); + GCOP_WRAP(pGC); + RL_DEBUG_MSG("imageglyph end\n"); +} + +static void RootlessPolyGlyphBlt(DrawablePtr dst, GCPtr pGC, + int x, int y, unsigned int nglyph, + CharInfoPtr *ppci, pointer pglyphBase) +{ + GCOP_UNWRAP(pGC); + GC_SKIP_ROOT(dst); + RL_DEBUG_MSG("polyglyph start "); + + RootlessStartDrawing((WindowPtr) dst); + pGC->ops->PolyGlyphBlt(dst, pGC, x, y, nglyph, ppci, pglyphBase); + + if (nglyph > 0) { + BoxRec box; + + /* ugh */ + box.x1 = dst->x + x + ppci[0]->metrics.leftSideBearing; + box.x2 = dst->x + x + ppci[nglyph - 1]->metrics.rightSideBearing; + + if (nglyph > 1) { + int width = 0; + + while (--nglyph) { + width += (*ppci)->metrics.characterWidth; + ppci++; + } + + if (width > 0) box.x2 += width; + else box.x1 += width; + } + + box.y1 = dst->y + y - FONTMAXBOUNDS(pGC->font, ascent); + box.y2 = dst->y + y + FONTMAXBOUNDS(pGC->font, descent); + + TRIM_BOX(box, pGC); + if (BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + } + + GCOP_WRAP(pGC); + RL_DEBUG_MSG("polyglyph end\n"); +} + + +/* changed area is in dest */ +static void +RootlessPushPixels(GCPtr pGC, PixmapPtr pBitMap, DrawablePtr dst, + int dx, int dy, int xOrg, int yOrg) +{ + BoxRec box; + + GCOP_UNWRAP(pGC); + GC_SKIP_ROOT(dst); + RL_DEBUG_MSG("push pixels start "); + + RootlessStartDrawing((WindowPtr) dst); + pGC->ops->PushPixels(pGC, pBitMap, dst, dx, dy, xOrg, yOrg); + + box.x1 = xOrg + dst->x; + box.x2 = box.x1 + dx; + box.y1 = yOrg + dst->y; + box.y2 = box.y1 + dy; + + TRIM_BOX(box, pGC); + if (BOX_NOT_EMPTY(box)) + RootlessDamageBox ((WindowPtr) dst, &box); + + GCOP_WRAP(pGC); + RL_DEBUG_MSG("push pixels end\n"); +} |