aboutsummaryrefslogtreecommitdiff
path: root/xorg-server/miext/rootless/rootlessGC.c
diff options
context:
space:
mode:
Diffstat (limited to 'xorg-server/miext/rootless/rootlessGC.c')
-rw-r--r--xorg-server/miext/rootless/rootlessGC.c2947
1 files changed, 1487 insertions, 1460 deletions
diff --git a/xorg-server/miext/rootless/rootlessGC.c b/xorg-server/miext/rootless/rootlessGC.c
index 21a3bd806..932899591 100644
--- a/xorg-server/miext/rootless/rootlessGC.c
+++ b/xorg-server/miext/rootless/rootlessGC.c
@@ -1,1460 +1,1487 @@
-/*
- * 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.
- */
-
-#ifdef HAVE_DIX_CONFIG_H
-#include <dix-config.h>
-#endif
-
-#include <stddef.h> /* For NULL */
-#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"
-
-
-// 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);
-
-Bool RootlessCreateGC(GCPtr pGC);
-
-GCFuncs rootlessGCFuncs = {
- RootlessValidateGC,
- RootlessChangeGC,
- RootlessCopyGC,
- RootlessDestroyGC,
- RootlessChangeClip,
- RootlessDestroyClip,
- RootlessCopyClip,
-};
-
-// GC operations
-static void RootlessFillSpans(DrawablePtr dst, GCPtr pGC, int nInit,
- DDXPointPtr pptInit, int *pwidthInit,
- int sorted);
-static void RootlessSetSpans(DrawablePtr dst, GCPtr pGC, char *pSrc,
- DDXPointPtr pptInit, int *pwidthInit,
- int nspans, int sorted);
-static void RootlessPutImage(DrawablePtr dst, GCPtr pGC,
- int depth, int x, int y, int w, int h,
- int leftPad, int format, char *pBits);
-static RegionPtr RootlessCopyArea(DrawablePtr pSrc, DrawablePtr dst, GCPtr pGC,
- int srcx, int srcy, int w, int h,
- int dstx, int dsty);
-static RegionPtr RootlessCopyPlane(DrawablePtr pSrc, DrawablePtr dst,
- GCPtr pGC, int srcx, int srcy,
- int w, int h, int dstx, int dsty,
- unsigned long plane);
-static void RootlessPolyPoint(DrawablePtr dst, GCPtr pGC,
- int mode, int npt, DDXPointPtr pptInit);
-static void RootlessPolylines(DrawablePtr dst, GCPtr pGC,
- int mode, int npt, DDXPointPtr pptInit);
-static void RootlessPolySegment(DrawablePtr dst, GCPtr pGC,
- int nseg, xSegment *pSeg);
-static void RootlessPolyRectangle(DrawablePtr dst, GCPtr pGC,
- int nRects, xRectangle *pRects);
-static void RootlessPolyArc(DrawablePtr dst, GCPtr pGC, int narcs, xArc *parcs);
-static void RootlessFillPolygon(DrawablePtr dst, GCPtr pGC,
- int shape, int mode, int count,
- DDXPointPtr pptInit);
-static void RootlessPolyFillRect(DrawablePtr dst, GCPtr pGC,
- int nRectsInit, xRectangle *pRectsInit);
-static void RootlessPolyFillArc(DrawablePtr dst, GCPtr pGC,
- int narcsInit, xArc *parcsInit);
-static int RootlessPolyText8(DrawablePtr dst, GCPtr pGC,
- int x, int y, int count, char *chars);
-static int RootlessPolyText16(DrawablePtr dst, GCPtr pGC,
- int x, int y, int count, unsigned short *chars);
-static void RootlessImageText8(DrawablePtr dst, GCPtr pGC,
- int x, int y, int count, char *chars);
-static void RootlessImageText16(DrawablePtr dst, GCPtr pGC,
- int x, int y, int count, unsigned short *chars);
-static void RootlessImageGlyphBlt(DrawablePtr dst, GCPtr pGC,
- int x, int y, unsigned int nglyphInit,
- CharInfoPtr *ppciInit, pointer unused);
-static void RootlessPolyGlyphBlt(DrawablePtr dst, GCPtr pGC,
- int x, int y, unsigned int nglyph,
- CharInfoPtr *ppci, pointer pglyphBase);
-static void RootlessPushPixels(GCPtr pGC, PixmapPtr pBitMap, DrawablePtr dst,
- int dx, int dy, int xOrg, int yOrg);
-
-
-static GCOps rootlessGCOps = {
- RootlessFillSpans,
- RootlessSetSpans,
- RootlessPutImage,
- RootlessCopyArea,
- RootlessCopyPlane,
- RootlessPolyPoint,
- RootlessPolylines,
- RootlessPolySegment,
- RootlessPolyRectangle,
- RootlessPolyArc,
- RootlessFillPolygon,
- RootlessPolyFillRect,
- RootlessPolyFillArc,
- RootlessPolyText8,
- RootlessPolyText16,
- RootlessImageText8,
- RootlessImageText16,
- RootlessImageGlyphBlt,
- RootlessPolyGlyphBlt,
- RootlessPushPixels
-};
-
-/*
- 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 three macros below are used to implement this. Drawing ops that can
- potentially have their planemask relaxed look like:
-
- OP {
- GC_SAVE(gc);
- GCOP_UNWRAP(gc);
-
- ...
-
- if (canAccelxxx(..) && 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);
-}
-
-
-/*
- * Screen function to create a graphics context
- */
-Bool
-RootlessCreateGC(GCPtr pGC)
-{
- RootlessGCRec *gcrec;
- RootlessScreenRec *s;
- Bool result;
-
- SCREEN_UNWRAP(pGC->pScreen, CreateGC);
- s = SCREENREC(pGC->pScreen);
- result = s->CreateGC(pGC);
-
- gcrec = (RootlessGCRec *)
- dixLookupPrivate(&pGC->devPrivates, rootlessGCPrivateKey);
- 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 *) \
- dixLookupPrivate(&(pGC)->devPrivates, rootlessGCPrivateKey); \
- (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 *) \
- dixLookupPrivate(&(pGC)->devPrivates, rootlessGCPrivateKey); \
- 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;
-
-static void
-RootlessFillSpans(DrawablePtr dst, GCPtr pGC, int nInit,
- DDXPointPtr pptInit, int *pwidthInit, int sorted)
-{
- GC_SAVE(pGC);
- GCOP_UNWRAP(pGC);
- 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))
- {
- 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);
- 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);
- 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);
-
- RL_DEBUG_MSG("copy area start (src 0x%x, dst 0x%x)", pSrc, dst);
-
- if (pSrc->type == DRAWABLE_WINDOW && IsFramedWindow((WindowPtr)pSrc)) {
- /* 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) */
-
- if (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);
-
- 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);
- 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);
- 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);
- 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);
- 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);
- 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);
- 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))
- {
- 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);
- 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))
- {
- 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);
- 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))
- {
- 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);
- 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))
- {
- 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);
-
- 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);
- 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))
- {
- 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);
-
- 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);
- 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))
- {
- 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);
- 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);
- 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");
-}
+/*
+ * 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.
+ */
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include <stddef.h> /* For NULL */
+#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"
+
+// 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);
+
+Bool RootlessCreateGC(GCPtr pGC);
+
+GCFuncs rootlessGCFuncs = {
+ RootlessValidateGC,
+ RootlessChangeGC,
+ RootlessCopyGC,
+ RootlessDestroyGC,
+ RootlessChangeClip,
+ RootlessDestroyClip,
+ RootlessCopyClip,
+};
+
+// GC operations
+static void RootlessFillSpans(DrawablePtr dst, GCPtr pGC, int nInit,
+ DDXPointPtr pptInit, int *pwidthInit, int sorted);
+static void RootlessSetSpans(DrawablePtr dst, GCPtr pGC, char *pSrc,
+ DDXPointPtr pptInit, int *pwidthInit,
+ int nspans, int sorted);
+static void RootlessPutImage(DrawablePtr dst, GCPtr pGC,
+ int depth, int x, int y, int w, int h,
+ int leftPad, int format, char *pBits);
+static RegionPtr RootlessCopyArea(DrawablePtr pSrc, DrawablePtr dst, GCPtr pGC,
+ int srcx, int srcy, int w, int h,
+ int dstx, int dsty);
+static RegionPtr RootlessCopyPlane(DrawablePtr pSrc, DrawablePtr dst,
+ GCPtr pGC, int srcx, int srcy,
+ int w, int h, int dstx, int dsty,
+ unsigned long plane);
+static void RootlessPolyPoint(DrawablePtr dst, GCPtr pGC,
+ int mode, int npt, DDXPointPtr pptInit);
+static void RootlessPolylines(DrawablePtr dst, GCPtr pGC,
+ int mode, int npt, DDXPointPtr pptInit);
+static void RootlessPolySegment(DrawablePtr dst, GCPtr pGC,
+ int nseg, xSegment * pSeg);
+static void RootlessPolyRectangle(DrawablePtr dst, GCPtr pGC,
+ int nRects, xRectangle *pRects);
+static void RootlessPolyArc(DrawablePtr dst, GCPtr pGC, int narcs,
+ xArc * parcs);
+static void RootlessFillPolygon(DrawablePtr dst, GCPtr pGC, int shape, int mode,
+ int count, DDXPointPtr pptInit);
+static void RootlessPolyFillRect(DrawablePtr dst, GCPtr pGC, int nRectsInit,
+ xRectangle *pRectsInit);
+static void RootlessPolyFillArc(DrawablePtr dst, GCPtr pGC, int narcsInit,
+ xArc * parcsInit);
+static int RootlessPolyText8(DrawablePtr dst, GCPtr pGC, int x, int y,
+ int count, char *chars);
+static int RootlessPolyText16(DrawablePtr dst, GCPtr pGC, int x, int y,
+ int count, unsigned short *chars);
+static void RootlessImageText8(DrawablePtr dst, GCPtr pGC, int x, int y,
+ int count, char *chars);
+static void RootlessImageText16(DrawablePtr dst, GCPtr pGC, int x, int y,
+ int count, unsigned short *chars);
+static void RootlessImageGlyphBlt(DrawablePtr dst, GCPtr pGC, int x, int y,
+ unsigned int nglyphInit,
+ CharInfoPtr * ppciInit, pointer unused);
+static void RootlessPolyGlyphBlt(DrawablePtr dst, GCPtr pGC, int x, int y,
+ unsigned int nglyph, CharInfoPtr * ppci,
+ pointer pglyphBase);
+static void RootlessPushPixels(GCPtr pGC, PixmapPtr pBitMap, DrawablePtr dst,
+ int dx, int dy, int xOrg, int yOrg);
+
+static GCOps rootlessGCOps = {
+ RootlessFillSpans,
+ RootlessSetSpans,
+ RootlessPutImage,
+ RootlessCopyArea,
+ RootlessCopyPlane,
+ RootlessPolyPoint,
+ RootlessPolylines,
+ RootlessPolySegment,
+ RootlessPolyRectangle,
+ RootlessPolyArc,
+ RootlessFillPolygon,
+ RootlessPolyFillRect,
+ RootlessPolyFillArc,
+ RootlessPolyText8,
+ RootlessPolyText16,
+ RootlessImageText8,
+ RootlessImageText16,
+ RootlessImageGlyphBlt,
+ RootlessPolyGlyphBlt,
+ RootlessPushPixels
+};
+
+/*
+ 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 three macros below are used to implement this. Drawing ops that can
+ potentially have their planemask relaxed look like:
+
+ OP {
+ GC_SAVE(gc);
+ GCOP_UNWRAP(gc);
+
+ ...
+
+ if (canAccelxxx(..) && 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);
+}
+
+/*
+ * Screen function to create a graphics context
+ */
+Bool
+RootlessCreateGC(GCPtr pGC)
+{
+ RootlessGCRec *gcrec;
+ RootlessScreenRec *s;
+ Bool result;
+
+ SCREEN_UNWRAP(pGC->pScreen, CreateGC);
+ s = SCREENREC(pGC->pScreen);
+ result = s->CreateGC(pGC);
+
+ gcrec = (RootlessGCRec *)
+ dixLookupPrivate(&pGC->devPrivates, rootlessGCPrivateKey);
+ 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 *) \
+ dixLookupPrivate(&(pGC)->devPrivates, rootlessGCPrivateKey); \
+ (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 *) \
+ dixLookupPrivate(&(pGC)->devPrivates, rootlessGCPrivateKey); \
+ 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;
+
+static void
+RootlessFillSpans(DrawablePtr dst, GCPtr pGC, int nInit,
+ DDXPointPtr pptInit, int *pwidthInit, int sorted)
+{
+ GC_SAVE(pGC);
+ GCOP_UNWRAP(pGC);
+ 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)) {
+ 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);
+ 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);
+ 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);
+
+ RL_DEBUG_MSG("copy area start (src 0x%x, dst 0x%x)", pSrc, dst);
+
+ if (pSrc->type == DRAWABLE_WINDOW && IsFramedWindow((WindowPtr) pSrc)) {
+ /* 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) */
+
+ if (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);
+
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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)) {
+ 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);
+ 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)) {
+ 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);
+ 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)) {
+ 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);
+ 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)) {
+ 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);
+
+ 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);
+ 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)) {
+ 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);
+
+ 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);
+ 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)) {
+ 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);
+ 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);
+ 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");
+}