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