1488 lines
		
	
	
		
			42 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			1488 lines
		
	
	
		
			42 KiB
		
	
	
	
		
			C
		
	
	
	
| /*
 | |
|  * 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, void *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, void *unused);
 | |
| static void RootlessPolyGlyphBlt(DrawablePtr dst, GCPtr pGC, int x, int y,
 | |
|                                  unsigned int nglyph, CharInfoPtr * ppci,
 | |
|                                  void *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, void *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); \
 | |
|     const 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, void *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, void *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");
 | |
| }
 |