diff options
Diffstat (limited to 'mi/misprite.c')
-rw-r--r-- | mi/misprite.c | 2067 |
1 files changed, 2067 insertions, 0 deletions
diff --git a/mi/misprite.c b/mi/misprite.c new file mode 100644 index 000000000..2fc6da8dd --- /dev/null +++ b/mi/misprite.c @@ -0,0 +1,2067 @@ +/* + * misprite.c + * + * machine independent software sprite routines + */ + +/* $Xorg: misprite.c,v 1.4 2001/02/09 02:05:22 xorgcvs Exp $ */ + +/* + +Copyright 1989, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +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 +OPEN GROUP 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 of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. +*/ + +# include "X.h" +# include "Xproto.h" +# include "misc.h" +# include "pixmapstr.h" +# include "input.h" +# include "mi.h" +# include "cursorstr.h" +# include "font.h" +# include "scrnintstr.h" +# include "colormapst.h" +# include "windowstr.h" +# include "gcstruct.h" +# include "mipointer.h" +# include "mispritest.h" +# include "dixfontstr.h" +# include "fontstruct.h" + +/* + * screen wrappers + */ + +static int miSpriteScreenIndex; +static unsigned long miSpriteGeneration = 0; + +static Bool miSpriteCloseScreen(); +static void miSpriteGetImage(); +static void miSpriteGetSpans(); +static void miSpriteSourceValidate(); +static Bool miSpriteCreateGC(); +static void miSpriteBlockHandler(); +static void miSpriteInstallColormap(); +static void miSpriteStoreColors(); + +static void miSpritePaintWindowBackground(); +static void miSpritePaintWindowBorder(); +static void miSpriteCopyWindow(); +static void miSpriteClearToBackground(); + +static void miSpriteSaveDoomedAreas(); +static RegionPtr miSpriteRestoreAreas(); +static void miSpriteComputeSaved(); + +#define SCREEN_PROLOGUE(pScreen, field)\ + ((pScreen)->field = \ + ((miSpriteScreenPtr) (pScreen)->devPrivates[miSpriteScreenIndex].ptr)->field) + +#define SCREEN_EPILOGUE(pScreen, field, wrapper)\ + ((pScreen)->field = wrapper) + +/* + * GC func wrappers + */ + +static int miSpriteGCIndex; + +static void miSpriteValidateGC (), miSpriteCopyGC (); +static void miSpriteDestroyGC(), miSpriteChangeGC(); +static void miSpriteChangeClip(), miSpriteDestroyClip(); +static void miSpriteCopyClip(); + +static GCFuncs miSpriteGCFuncs = { + miSpriteValidateGC, + miSpriteChangeGC, + miSpriteCopyGC, + miSpriteDestroyGC, + miSpriteChangeClip, + miSpriteDestroyClip, + miSpriteCopyClip, +}; + +#define GC_FUNC_PROLOGUE(pGC) \ + miSpriteGCPtr pGCPriv = \ + (miSpriteGCPtr) (pGC)->devPrivates[miSpriteGCIndex].ptr;\ + (pGC)->funcs = pGCPriv->wrapFuncs; \ + if (pGCPriv->wrapOps) \ + (pGC)->ops = pGCPriv->wrapOps; + +#define GC_FUNC_EPILOGUE(pGC) \ + pGCPriv->wrapFuncs = (pGC)->funcs; \ + (pGC)->funcs = &miSpriteGCFuncs; \ + if (pGCPriv->wrapOps) \ + { \ + pGCPriv->wrapOps = (pGC)->ops; \ + (pGC)->ops = &miSpriteGCOps; \ + } + +/* + * GC op wrappers + */ + +static void miSpriteFillSpans(), miSpriteSetSpans(); +static void miSpritePutImage(); +static RegionPtr miSpriteCopyArea(), miSpriteCopyPlane(); +static void miSpritePolyPoint(), miSpritePolylines(); +static void miSpritePolySegment(), miSpritePolyRectangle(); +static void miSpritePolyArc(), miSpriteFillPolygon(); +static void miSpritePolyFillRect(), miSpritePolyFillArc(); +static int miSpritePolyText8(), miSpritePolyText16(); +static void miSpriteImageText8(), miSpriteImageText16(); +static void miSpriteImageGlyphBlt(), miSpritePolyGlyphBlt(); +static void miSpritePushPixels(); +#ifdef NEED_LINEHELPER +static void miSpriteLineHelper(); +#endif + +static GCOps miSpriteGCOps = { + miSpriteFillSpans, miSpriteSetSpans, miSpritePutImage, + miSpriteCopyArea, miSpriteCopyPlane, miSpritePolyPoint, + miSpritePolylines, miSpritePolySegment, miSpritePolyRectangle, + miSpritePolyArc, miSpriteFillPolygon, miSpritePolyFillRect, + miSpritePolyFillArc, miSpritePolyText8, miSpritePolyText16, + miSpriteImageText8, miSpriteImageText16, miSpriteImageGlyphBlt, + miSpritePolyGlyphBlt, miSpritePushPixels +#ifdef NEED_LINEHELPER + , miSpriteLineHelper +#endif +}; + +/* + * testing only -- remove cursor for every draw. Eventually, + * each draw operation will perform a bounding box check against + * the saved cursor area + */ + +#define GC_SETUP_CHEAP(pDrawable) \ + miSpriteScreenPtr pScreenPriv = (miSpriteScreenPtr) \ + (pDrawable)->pScreen->devPrivates[miSpriteScreenIndex].ptr; \ + +#define GC_SETUP(pDrawable, pGC) \ + GC_SETUP_CHEAP(pDrawable) \ + miSpriteGCPtr pGCPrivate = (miSpriteGCPtr) \ + (pGC)->devPrivates[miSpriteGCIndex].ptr; \ + GCFuncs *oldFuncs = pGC->funcs; + +#define GC_SETUP_AND_CHECK(pDrawable, pGC) \ + GC_SETUP(pDrawable, pGC); \ + if (GC_CHECK((WindowPtr)pDrawable)) \ + miSpriteRemoveCursor (pDrawable->pScreen); + +#define GC_CHECK(pWin) \ + (pScreenPriv->isUp && \ + (pScreenPriv->pCacheWin == pWin ? \ + pScreenPriv->isInCacheWin : ( \ + ((int) (pScreenPriv->pCacheWin = (pWin))) , \ + (pScreenPriv->isInCacheWin = \ + (pWin)->drawable.x < pScreenPriv->saved.x2 && \ + pScreenPriv->saved.x1 < (pWin)->drawable.x + \ + (int) (pWin)->drawable.width && \ + (pWin)->drawable.y < pScreenPriv->saved.y2 && \ + pScreenPriv->saved.y1 < (pWin)->drawable.y + \ + (int) (pWin)->drawable.height &&\ + RECT_IN_REGION((pWin)->drawable.pScreen, &(pWin)->borderClip, \ + &pScreenPriv->saved) != rgnOUT)))) + +#define GC_OP_PROLOGUE(pGC) { \ + (pGC)->funcs = pGCPrivate->wrapFuncs; \ + (pGC)->ops = pGCPrivate->wrapOps; \ + } + +#define GC_OP_EPILOGUE(pGC) { \ + pGCPrivate->wrapOps = (pGC)->ops; \ + (pGC)->funcs = oldFuncs; \ + (pGC)->ops = &miSpriteGCOps; \ + } + +/* + * pointer-sprite method table + */ + +static Bool miSpriteRealizeCursor (), miSpriteUnrealizeCursor (); +static void miSpriteSetCursor (), miSpriteMoveCursor (); + +miPointerSpriteFuncRec miSpritePointerFuncs = { + miSpriteRealizeCursor, + miSpriteUnrealizeCursor, + miSpriteSetCursor, + miSpriteMoveCursor, +}; + +/* + * other misc functions + */ + +static void miSpriteRemoveCursor (), miSpriteRestoreCursor(); + +/* + * miSpriteInitialize -- called from device-dependent screen + * initialization proc after all of the function pointers have + * been stored in the screen structure. + */ + +Bool +miSpriteInitialize (pScreen, cursorFuncs, screenFuncs) + ScreenPtr pScreen; + miSpriteCursorFuncPtr cursorFuncs; + miPointerScreenFuncPtr screenFuncs; +{ + miSpriteScreenPtr pPriv; + VisualPtr pVisual; + + if (miSpriteGeneration != serverGeneration) + { + miSpriteScreenIndex = AllocateScreenPrivateIndex (); + if (miSpriteScreenIndex < 0) + return FALSE; + miSpriteGeneration = serverGeneration; + miSpriteGCIndex = AllocateGCPrivateIndex (); + } + if (!AllocateGCPrivate(pScreen, miSpriteGCIndex, sizeof(miSpriteGCRec))) + return FALSE; + pPriv = (miSpriteScreenPtr) xalloc (sizeof (miSpriteScreenRec)); + if (!pPriv) + return FALSE; + if (!miPointerInitialize (pScreen, &miSpritePointerFuncs, screenFuncs,TRUE)) + { + xfree ((pointer) pPriv); + return FALSE; + } + for (pVisual = pScreen->visuals; + pVisual->vid != pScreen->rootVisual; + pVisual++) + ; + pPriv->pVisual = pVisual; + pPriv->CloseScreen = pScreen->CloseScreen; + pPriv->GetImage = pScreen->GetImage; + pPriv->GetSpans = pScreen->GetSpans; + pPriv->SourceValidate = pScreen->SourceValidate; + pPriv->CreateGC = pScreen->CreateGC; + pPriv->BlockHandler = pScreen->BlockHandler; + pPriv->InstallColormap = pScreen->InstallColormap; + pPriv->StoreColors = pScreen->StoreColors; + + pPriv->PaintWindowBackground = pScreen->PaintWindowBackground; + pPriv->PaintWindowBorder = pScreen->PaintWindowBorder; + pPriv->CopyWindow = pScreen->CopyWindow; + pPriv->ClearToBackground = pScreen->ClearToBackground; + + pPriv->SaveDoomedAreas = pScreen->SaveDoomedAreas; + pPriv->RestoreAreas = pScreen->RestoreAreas; + + pPriv->pCursor = NULL; + pPriv->x = 0; + pPriv->y = 0; + pPriv->isUp = FALSE; + pPriv->shouldBeUp = FALSE; + pPriv->pCacheWin = NullWindow; + pPriv->isInCacheWin = FALSE; + pPriv->checkPixels = TRUE; + pPriv->pInstalledMap = NULL; + pPriv->pColormap = NULL; + pPriv->funcs = cursorFuncs; + pPriv->colors[SOURCE_COLOR].red = 0; + pPriv->colors[SOURCE_COLOR].green = 0; + pPriv->colors[SOURCE_COLOR].blue = 0; + pPriv->colors[MASK_COLOR].red = 0; + pPriv->colors[MASK_COLOR].green = 0; + pPriv->colors[MASK_COLOR].blue = 0; + pScreen->devPrivates[miSpriteScreenIndex].ptr = (pointer) pPriv; + pScreen->CloseScreen = miSpriteCloseScreen; + pScreen->GetImage = miSpriteGetImage; + pScreen->GetSpans = miSpriteGetSpans; + pScreen->SourceValidate = miSpriteSourceValidate; + pScreen->CreateGC = miSpriteCreateGC; + pScreen->BlockHandler = miSpriteBlockHandler; + pScreen->InstallColormap = miSpriteInstallColormap; + pScreen->StoreColors = miSpriteStoreColors; + + pScreen->PaintWindowBackground = miSpritePaintWindowBackground; + pScreen->PaintWindowBorder = miSpritePaintWindowBorder; + pScreen->CopyWindow = miSpriteCopyWindow; + pScreen->ClearToBackground = miSpriteClearToBackground; + + pScreen->SaveDoomedAreas = miSpriteSaveDoomedAreas; + pScreen->RestoreAreas = miSpriteRestoreAreas; + + return TRUE; +} + +/* + * Screen wrappers + */ + +/* + * CloseScreen wrapper -- unwrap everything, free the private data + * and call the wrapped function + */ + +static Bool +miSpriteCloseScreen (i, pScreen) + ScreenPtr pScreen; +{ + miSpriteScreenPtr pScreenPriv; + + pScreenPriv = (miSpriteScreenPtr) pScreen->devPrivates[miSpriteScreenIndex].ptr; + + pScreen->CloseScreen = pScreenPriv->CloseScreen; + pScreen->GetImage = pScreenPriv->GetImage; + pScreen->GetSpans = pScreenPriv->GetSpans; + pScreen->SourceValidate = pScreenPriv->SourceValidate; + pScreen->CreateGC = pScreenPriv->CreateGC; + pScreen->BlockHandler = pScreenPriv->BlockHandler; + pScreen->InstallColormap = pScreenPriv->InstallColormap; + pScreen->StoreColors = pScreenPriv->StoreColors; + + pScreen->PaintWindowBackground = pScreenPriv->PaintWindowBackground; + pScreen->PaintWindowBorder = pScreenPriv->PaintWindowBorder; + pScreen->CopyWindow = pScreenPriv->CopyWindow; + pScreen->ClearToBackground = pScreenPriv->ClearToBackground; + + pScreen->SaveDoomedAreas = pScreenPriv->SaveDoomedAreas; + pScreen->RestoreAreas = pScreenPriv->RestoreAreas; + + xfree ((pointer) pScreenPriv); + + return (*pScreen->CloseScreen) (i, pScreen); +} + +static void +miSpriteGetImage (pDrawable, sx, sy, w, h, format, planemask, pdstLine) + DrawablePtr pDrawable; + int sx, sy, w, h; + unsigned int format; + unsigned long planemask; + char *pdstLine; +{ + ScreenPtr pScreen = pDrawable->pScreen; + miSpriteScreenPtr pScreenPriv; + + SCREEN_PROLOGUE (pScreen, GetImage); + + pScreenPriv = (miSpriteScreenPtr) pScreen->devPrivates[miSpriteScreenIndex].ptr; + + if (pDrawable->type == DRAWABLE_WINDOW && + pScreenPriv->isUp && + ORG_OVERLAP(&pScreenPriv->saved,pDrawable->x,pDrawable->y, sx, sy, w, h)) + { + miSpriteRemoveCursor (pScreen); + } + + (*pScreen->GetImage) (pDrawable, sx, sy, w, h, + format, planemask, pdstLine); + + SCREEN_EPILOGUE (pScreen, GetImage, miSpriteGetImage); +} + +static void +miSpriteGetSpans (pDrawable, wMax, ppt, pwidth, nspans, pdstStart) + DrawablePtr pDrawable; + int wMax; + DDXPointPtr ppt; + int *pwidth; + int nspans; + char *pdstStart; +{ + ScreenPtr pScreen = pDrawable->pScreen; + miSpriteScreenPtr pScreenPriv; + + SCREEN_PROLOGUE (pScreen, GetSpans); + + pScreenPriv = (miSpriteScreenPtr) pScreen->devPrivates[miSpriteScreenIndex].ptr; + + if (pDrawable->type == DRAWABLE_WINDOW && pScreenPriv->isUp) + { + register DDXPointPtr pts; + register int *widths; + register int nPts; + register int xorg, + yorg; + + xorg = pDrawable->x; + yorg = pDrawable->y; + + for (pts = ppt, widths = pwidth, nPts = nspans; + nPts--; + pts++, widths++) + { + if (SPN_OVERLAP(&pScreenPriv->saved,pts->y+yorg, + pts->x+xorg,*widths)) + { + miSpriteRemoveCursor (pScreen); + break; + } + } + } + + (*pScreen->GetSpans) (pDrawable, wMax, ppt, pwidth, nspans, pdstStart); + + SCREEN_EPILOGUE (pScreen, GetSpans, miSpriteGetSpans); +} + +static void +miSpriteSourceValidate (pDrawable, x, y, width, height) + DrawablePtr pDrawable; + int x, y, width, height; +{ + ScreenPtr pScreen = pDrawable->pScreen; + miSpriteScreenPtr pScreenPriv; + + SCREEN_PROLOGUE (pScreen, SourceValidate); + + pScreenPriv = (miSpriteScreenPtr) pScreen->devPrivates[miSpriteScreenIndex].ptr; + + if (pDrawable->type == DRAWABLE_WINDOW && pScreenPriv->isUp && + ORG_OVERLAP(&pScreenPriv->saved, pDrawable->x, pDrawable->y, + x, y, width, height)) + { + miSpriteRemoveCursor (pScreen); + } + + if (pScreen->SourceValidate) + (*pScreen->SourceValidate) (pDrawable, x, y, width, height); + + SCREEN_EPILOGUE (pScreen, SourceValidate, miSpriteSourceValidate); +} + +static Bool +miSpriteCreateGC (pGC) + GCPtr pGC; +{ + ScreenPtr pScreen = pGC->pScreen; + Bool ret; + miSpriteGCPtr pPriv; + + SCREEN_PROLOGUE (pScreen, CreateGC); + + pPriv = (miSpriteGCPtr)pGC->devPrivates[miSpriteGCIndex].ptr; + + ret = (*pScreen->CreateGC) (pGC); + + pPriv->wrapOps = NULL; + pPriv->wrapFuncs = pGC->funcs; + pGC->funcs = &miSpriteGCFuncs; + + SCREEN_EPILOGUE (pScreen, CreateGC, miSpriteCreateGC); + + return ret; +} + +static void +miSpriteBlockHandler (i, blockData, pTimeout, pReadmask) + int i; + pointer blockData; + OSTimePtr pTimeout; + pointer pReadmask; +{ + ScreenPtr pScreen = screenInfo.screens[i]; + miSpriteScreenPtr pPriv; + + pPriv = (miSpriteScreenPtr) pScreen->devPrivates[miSpriteScreenIndex].ptr; + + SCREEN_PROLOGUE(pScreen, BlockHandler); + + (*pScreen->BlockHandler) (i, blockData, pTimeout, pReadmask); + + SCREEN_EPILOGUE(pScreen, BlockHandler, miSpriteBlockHandler); + + if (!pPriv->isUp && pPriv->shouldBeUp) + miSpriteRestoreCursor (pScreen); +} + +static void +miSpriteInstallColormap (pMap) + ColormapPtr pMap; +{ + ScreenPtr pScreen = pMap->pScreen; + miSpriteScreenPtr pPriv; + + pPriv = (miSpriteScreenPtr) pScreen->devPrivates[miSpriteScreenIndex].ptr; + + SCREEN_PROLOGUE(pScreen, InstallColormap); + + (*pScreen->InstallColormap) (pMap); + + SCREEN_EPILOGUE(pScreen, InstallColormap, miSpriteInstallColormap); + + pPriv->pInstalledMap = pMap; + if (pPriv->pColormap != pMap) + { + pPriv->checkPixels = TRUE; + if (pPriv->isUp) + miSpriteRemoveCursor (pScreen); + } +} + +static void +miSpriteStoreColors (pMap, ndef, pdef) + ColormapPtr pMap; + int ndef; + xColorItem *pdef; +{ + ScreenPtr pScreen = pMap->pScreen; + miSpriteScreenPtr pPriv; + int i; + int updated; + VisualPtr pVisual; + + pPriv = (miSpriteScreenPtr) pScreen->devPrivates[miSpriteScreenIndex].ptr; + + SCREEN_PROLOGUE(pScreen, StoreColors); + + (*pScreen->StoreColors) (pMap, ndef, pdef); + + SCREEN_EPILOGUE(pScreen, StoreColors, miSpriteStoreColors); + + if (pPriv->pColormap == pMap) + { + updated = 0; + pVisual = pMap->pVisual; + if (pVisual->class == DirectColor) + { + /* Direct color - match on any of the subfields */ + +#define MaskMatch(a,b,mask) ((a) & (pVisual->mask) == (b) & (pVisual->mask)) + +#define UpdateDAC(plane,dac,mask) {\ + if (MaskMatch (pPriv->colors[plane].pixel,pdef[i].pixel,mask)) {\ + pPriv->colors[plane].dac = pdef[i].dac; \ + updated = 1; \ + } \ +} + +#define CheckDirect(plane) \ + UpdateDAC(plane,red,redMask) \ + UpdateDAC(plane,green,greenMask) \ + UpdateDAC(plane,blue,blueMask) + + for (i = 0; i < ndef; i++) + { + CheckDirect (SOURCE_COLOR) + CheckDirect (MASK_COLOR) + } + } + else + { + /* PseudoColor/GrayScale - match on exact pixel */ + for (i = 0; i < ndef; i++) + { + if (pdef[i].pixel == pPriv->colors[SOURCE_COLOR].pixel) + { + pPriv->colors[SOURCE_COLOR] = pdef[i]; + if (++updated == 2) + break; + } + if (pdef[i].pixel == pPriv->colors[MASK_COLOR].pixel) + { + pPriv->colors[MASK_COLOR] = pdef[i]; + if (++updated == 2) + break; + } + } + } + if (updated) + { + pPriv->checkPixels = TRUE; + if (pPriv->isUp) + miSpriteRemoveCursor (pScreen); + } + } +} + +static void +miSpriteFindColors (pScreen) + ScreenPtr pScreen; +{ + miSpriteScreenPtr pScreenPriv = (miSpriteScreenPtr) + pScreen->devPrivates[miSpriteScreenIndex].ptr; + CursorPtr pCursor; + xColorItem *sourceColor, *maskColor; + + pCursor = pScreenPriv->pCursor; + sourceColor = &pScreenPriv->colors[SOURCE_COLOR]; + maskColor = &pScreenPriv->colors[MASK_COLOR]; + if (pScreenPriv->pColormap != pScreenPriv->pInstalledMap || + !(pCursor->foreRed == sourceColor->red && + pCursor->foreGreen == sourceColor->green && + pCursor->foreBlue == sourceColor->blue && + pCursor->backRed == maskColor->red && + pCursor->backGreen == maskColor->green && + pCursor->backBlue == maskColor->blue)) + { + pScreenPriv->pColormap = pScreenPriv->pInstalledMap; + sourceColor->red = pCursor->foreRed; + sourceColor->green = pCursor->foreGreen; + sourceColor->blue = pCursor->foreBlue; + FakeAllocColor (pScreenPriv->pColormap, sourceColor); + maskColor->red = pCursor->backRed; + maskColor->green = pCursor->backGreen; + maskColor->blue = pCursor->backBlue; + FakeAllocColor (pScreenPriv->pColormap, maskColor); + /* "free" the pixels right away, don't let this confuse you */ + FakeFreeColor(pScreenPriv->pColormap, sourceColor->pixel); + FakeFreeColor(pScreenPriv->pColormap, maskColor->pixel); + } + pScreenPriv->checkPixels = FALSE; +} + +/* + * BackingStore wrappers + */ + +static void +miSpriteSaveDoomedAreas (pWin, pObscured, dx, dy) + WindowPtr pWin; + RegionPtr pObscured; + int dx, dy; +{ + ScreenPtr pScreen; + miSpriteScreenPtr pScreenPriv; + BoxRec cursorBox; + + pScreen = pWin->drawable.pScreen; + + SCREEN_PROLOGUE (pScreen, SaveDoomedAreas); + + pScreenPriv = (miSpriteScreenPtr) pScreen->devPrivates[miSpriteScreenIndex].ptr; + if (pScreenPriv->isUp) + { + cursorBox = pScreenPriv->saved; + + if (dx || dy) + { + cursorBox.x1 += dx; + cursorBox.y1 += dy; + cursorBox.x2 += dx; + cursorBox.y2 += dy; + } + if (RECT_IN_REGION( pScreen, pObscured, &cursorBox) != rgnOUT) + miSpriteRemoveCursor (pScreen); + } + + (*pScreen->SaveDoomedAreas) (pWin, pObscured, dx, dy); + + SCREEN_EPILOGUE (pScreen, SaveDoomedAreas, miSpriteSaveDoomedAreas); +} + +static RegionPtr +miSpriteRestoreAreas (pWin, prgnExposed) + WindowPtr pWin; + RegionPtr prgnExposed; +{ + ScreenPtr pScreen; + miSpriteScreenPtr pScreenPriv; + RegionPtr result; + + pScreen = pWin->drawable.pScreen; + + SCREEN_PROLOGUE (pScreen, RestoreAreas); + + pScreenPriv = (miSpriteScreenPtr) pScreen->devPrivates[miSpriteScreenIndex].ptr; + if (pScreenPriv->isUp) + { + if (RECT_IN_REGION( pScreen, prgnExposed, &pScreenPriv->saved) != rgnOUT) + miSpriteRemoveCursor (pScreen); + } + + result = (*pScreen->RestoreAreas) (pWin, prgnExposed); + + SCREEN_EPILOGUE (pScreen, RestoreAreas, miSpriteRestoreAreas); + + return result; +} + +/* + * Window wrappers + */ + +static void +miSpritePaintWindowBackground (pWin, pRegion, what) + WindowPtr pWin; + RegionPtr pRegion; + int what; +{ + ScreenPtr pScreen; + miSpriteScreenPtr pScreenPriv; + + pScreen = pWin->drawable.pScreen; + + SCREEN_PROLOGUE (pScreen, PaintWindowBackground); + + pScreenPriv = (miSpriteScreenPtr) pScreen->devPrivates[miSpriteScreenIndex].ptr; + if (pScreenPriv->isUp) + { + /* + * If the cursor is on the same screen as the window, check the + * region to paint for the cursor and remove it as necessary + */ + if (RECT_IN_REGION( pScreen, pRegion, &pScreenPriv->saved) != rgnOUT) + miSpriteRemoveCursor (pScreen); + } + + (*pScreen->PaintWindowBackground) (pWin, pRegion, what); + + SCREEN_EPILOGUE (pScreen, PaintWindowBackground, miSpritePaintWindowBackground); +} + +static void +miSpritePaintWindowBorder (pWin, pRegion, what) + WindowPtr pWin; + RegionPtr pRegion; + int what; +{ + ScreenPtr pScreen; + miSpriteScreenPtr pScreenPriv; + + pScreen = pWin->drawable.pScreen; + + SCREEN_PROLOGUE (pScreen, PaintWindowBorder); + + pScreenPriv = (miSpriteScreenPtr) pScreen->devPrivates[miSpriteScreenIndex].ptr; + if (pScreenPriv->isUp) + { + /* + * If the cursor is on the same screen as the window, check the + * region to paint for the cursor and remove it as necessary + */ + if (RECT_IN_REGION( pScreen, pRegion, &pScreenPriv->saved) != rgnOUT) + miSpriteRemoveCursor (pScreen); + } + + (*pScreen->PaintWindowBorder) (pWin, pRegion, what); + + SCREEN_EPILOGUE (pScreen, PaintWindowBorder, miSpritePaintWindowBorder); +} + +static void +miSpriteCopyWindow (pWin, ptOldOrg, pRegion) + WindowPtr pWin; + DDXPointRec ptOldOrg; + RegionPtr pRegion; +{ + ScreenPtr pScreen; + miSpriteScreenPtr pScreenPriv; + BoxRec cursorBox; + int dx, dy; + + pScreen = pWin->drawable.pScreen; + + SCREEN_PROLOGUE (pScreen, CopyWindow); + + pScreenPriv = (miSpriteScreenPtr) pScreen->devPrivates[miSpriteScreenIndex].ptr; + if (pScreenPriv->isUp) + { + /* + * check both the source and the destination areas. The given + * region is source relative, so offset the cursor box by + * the delta position + */ + cursorBox = pScreenPriv->saved; + dx = pWin->drawable.x - ptOldOrg.x; + dy = pWin->drawable.y - ptOldOrg.y; + cursorBox.x1 -= dx; + cursorBox.x2 -= dx; + cursorBox.y1 -= dy; + cursorBox.y2 -= dy; + if (RECT_IN_REGION( pScreen, pRegion, &pScreenPriv->saved) != rgnOUT || + RECT_IN_REGION( pScreen, pRegion, &cursorBox) != rgnOUT) + miSpriteRemoveCursor (pScreen); + } + + (*pScreen->CopyWindow) (pWin, ptOldOrg, pRegion); + + SCREEN_EPILOGUE (pScreen, CopyWindow, miSpriteCopyWindow); +} + +static void +miSpriteClearToBackground (pWin, x, y, w, h, generateExposures) + WindowPtr pWin; + short x,y; + unsigned short w,h; + Bool generateExposures; +{ + ScreenPtr pScreen; + miSpriteScreenPtr pScreenPriv; + int realw, realh; + + pScreen = pWin->drawable.pScreen; + + SCREEN_PROLOGUE (pScreen, ClearToBackground); + + pScreenPriv = (miSpriteScreenPtr) pScreen->devPrivates[miSpriteScreenIndex].ptr; + if (GC_CHECK(pWin)) + { + if (!(realw = w)) + realw = (int) pWin->drawable.width - x; + if (!(realh = h)) + realh = (int) pWin->drawable.height - y; + if (ORG_OVERLAP(&pScreenPriv->saved, pWin->drawable.x, pWin->drawable.y, + x, y, realw, realh)) + { + miSpriteRemoveCursor (pScreen); + } + } + + (*pScreen->ClearToBackground) (pWin, x, y, w, h, generateExposures); + + SCREEN_EPILOGUE (pScreen, ClearToBackground, miSpriteClearToBackground); +} + +/* + * GC Func wrappers + */ + +static void +miSpriteValidateGC (pGC, changes, pDrawable) + GCPtr pGC; + Mask changes; + DrawablePtr pDrawable; +{ + GC_FUNC_PROLOGUE (pGC); + + (*pGC->funcs->ValidateGC) (pGC, changes, pDrawable); + + pGCPriv->wrapOps = NULL; + if (pDrawable->type == DRAWABLE_WINDOW && ((WindowPtr) pDrawable)->viewable) + { + WindowPtr pWin; + RegionPtr pRegion; + + pWin = (WindowPtr) pDrawable; + pRegion = &pWin->clipList; + if (pGC->subWindowMode == IncludeInferiors) + pRegion = &pWin->borderClip; + if (REGION_NOTEMPTY(pDrawable->pScreen, pRegion)) + pGCPriv->wrapOps = pGC->ops; + } + + GC_FUNC_EPILOGUE (pGC); +} + +static void +miSpriteChangeGC (pGC, mask) + GCPtr pGC; + unsigned long mask; +{ + GC_FUNC_PROLOGUE (pGC); + + (*pGC->funcs->ChangeGC) (pGC, mask); + + GC_FUNC_EPILOGUE (pGC); +} + +static void +miSpriteCopyGC (pGCSrc, mask, pGCDst) + GCPtr pGCSrc, pGCDst; + unsigned long mask; +{ + GC_FUNC_PROLOGUE (pGCDst); + + (*pGCDst->funcs->CopyGC) (pGCSrc, mask, pGCDst); + + GC_FUNC_EPILOGUE (pGCDst); +} + +static void +miSpriteDestroyGC (pGC) + GCPtr pGC; +{ + GC_FUNC_PROLOGUE (pGC); + + (*pGC->funcs->DestroyGC) (pGC); + + GC_FUNC_EPILOGUE (pGC); +} + +static void +miSpriteChangeClip (pGC, type, pvalue, nrects) + GCPtr pGC; + int type; + pointer pvalue; + int nrects; +{ + GC_FUNC_PROLOGUE (pGC); + + (*pGC->funcs->ChangeClip) (pGC, type, pvalue, nrects); + + GC_FUNC_EPILOGUE (pGC); +} + +static void +miSpriteCopyClip(pgcDst, pgcSrc) + GCPtr pgcDst, pgcSrc; +{ + GC_FUNC_PROLOGUE (pgcDst); + + (* pgcDst->funcs->CopyClip)(pgcDst, pgcSrc); + + GC_FUNC_EPILOGUE (pgcDst); +} + +static void +miSpriteDestroyClip(pGC) + GCPtr pGC; +{ + GC_FUNC_PROLOGUE (pGC); + + (* pGC->funcs->DestroyClip)(pGC); + + GC_FUNC_EPILOGUE (pGC); +} + +/* + * GC Op wrappers + */ + +static void +miSpriteFillSpans(pDrawable, pGC, nInit, pptInit, pwidthInit, fSorted) + DrawablePtr pDrawable; + GCPtr pGC; + int nInit; /* number of spans to fill */ + DDXPointPtr pptInit; /* pointer to list of start points */ + int *pwidthInit; /* pointer to list of n widths */ + int fSorted; +{ + GC_SETUP(pDrawable, pGC); + + if (GC_CHECK((WindowPtr) pDrawable)) + { + register DDXPointPtr pts; + register int *widths; + register int nPts; + + for (pts = pptInit, widths = pwidthInit, nPts = nInit; + nPts--; + pts++, widths++) + { + if (SPN_OVERLAP(&pScreenPriv->saved,pts->y,pts->x,*widths)) + { + miSpriteRemoveCursor (pDrawable->pScreen); + break; + } + } + } + + GC_OP_PROLOGUE (pGC); + + (*pGC->ops->FillSpans) (pDrawable, pGC, nInit, pptInit, pwidthInit, fSorted); + + GC_OP_EPILOGUE (pGC); +} + +static void +miSpriteSetSpans(pDrawable, pGC, psrc, ppt, pwidth, nspans, fSorted) + DrawablePtr pDrawable; + GCPtr pGC; + char *psrc; + register DDXPointPtr ppt; + int *pwidth; + int nspans; + int fSorted; +{ + GC_SETUP(pDrawable, pGC); + + if (GC_CHECK((WindowPtr) pDrawable)) + { + register DDXPointPtr pts; + register int *widths; + register int nPts; + + for (pts = ppt, widths = pwidth, nPts = nspans; + nPts--; + pts++, widths++) + { + if (SPN_OVERLAP(&pScreenPriv->saved,pts->y,pts->x,*widths)) + { + miSpriteRemoveCursor(pDrawable->pScreen); + break; + } + } + } + + GC_OP_PROLOGUE (pGC); + + (*pGC->ops->SetSpans) (pDrawable, pGC, psrc, ppt, pwidth, nspans, fSorted); + + GC_OP_EPILOGUE (pGC); +} + +static void +miSpritePutImage(pDrawable, pGC, depth, x, y, w, h, leftPad, format, pBits) + DrawablePtr pDrawable; + GCPtr pGC; + int depth; + int x; + int y; + int w; + int h; + int format; + char *pBits; +{ + GC_SETUP(pDrawable, pGC); + + if (GC_CHECK((WindowPtr) pDrawable)) + { + if (ORG_OVERLAP(&pScreenPriv->saved,pDrawable->x,pDrawable->y, + x,y,w,h)) + { + miSpriteRemoveCursor (pDrawable->pScreen); + } + } + + GC_OP_PROLOGUE (pGC); + + (*pGC->ops->PutImage) (pDrawable, pGC, depth, x, y, w, h, leftPad, format, pBits); + + GC_OP_EPILOGUE (pGC); +} + +static RegionPtr +miSpriteCopyArea (pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty) + DrawablePtr pSrc; + DrawablePtr pDst; + GCPtr pGC; + int srcx; + int srcy; + int w; + int h; + int dstx; + int dsty; +{ + RegionPtr rgn; + + GC_SETUP(pDst, pGC); + + /* check destination/source overlap. */ + if (GC_CHECK((WindowPtr) pDst) && + (ORG_OVERLAP(&pScreenPriv->saved,pDst->x,pDst->y,dstx,dsty,w,h) || + ((pDst == pSrc) && + ORG_OVERLAP(&pScreenPriv->saved,pSrc->x,pSrc->y,srcx,srcy,w,h)))) + { + miSpriteRemoveCursor (pDst->pScreen); + } + + GC_OP_PROLOGUE (pGC); + + rgn = (*pGC->ops->CopyArea) (pSrc, pDst, pGC, srcx, srcy, w, h, + dstx, dsty); + + GC_OP_EPILOGUE (pGC); + + return rgn; +} + +static RegionPtr +miSpriteCopyPlane (pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty, plane) + DrawablePtr pSrc; + DrawablePtr pDst; + register GCPtr pGC; + int srcx, + srcy; + int w, + h; + int dstx, + dsty; + unsigned long plane; +{ + RegionPtr rgn; + + GC_SETUP(pDst, pGC); + + /* + * check destination/source for overlap. + */ + if (GC_CHECK((WindowPtr) pDst) && + (ORG_OVERLAP(&pScreenPriv->saved,pDst->x,pDst->y,dstx,dsty,w,h) || + ((pDst == pSrc) && + ORG_OVERLAP(&pScreenPriv->saved,pSrc->x,pSrc->y,srcx,srcy,w,h)))) + { + miSpriteRemoveCursor (pDst->pScreen); + } + + GC_OP_PROLOGUE (pGC); + + rgn = (*pGC->ops->CopyPlane) (pSrc, pDst, pGC, srcx, srcy, w, h, + dstx, dsty, plane); + + GC_OP_EPILOGUE (pGC); + + return rgn; +} + +static void +miSpritePolyPoint (pDrawable, pGC, mode, npt, pptInit) + DrawablePtr pDrawable; + GCPtr pGC; + int mode; /* Origin or Previous */ + int npt; + xPoint *pptInit; +{ + xPoint t; + int n; + BoxRec cursor; + register xPoint *pts; + + GC_SETUP (pDrawable, pGC); + + if (npt && GC_CHECK((WindowPtr) pDrawable)) + { + cursor.x1 = pScreenPriv->saved.x1 - pDrawable->x; + cursor.y1 = pScreenPriv->saved.y1 - pDrawable->y; + cursor.x2 = pScreenPriv->saved.x2 - pDrawable->x; + cursor.y2 = pScreenPriv->saved.y2 - pDrawable->y; + + if (mode == CoordModePrevious) + { + t.x = 0; + t.y = 0; + for (pts = pptInit, n = npt; n--; pts++) + { + t.x += pts->x; + t.y += pts->y; + if (cursor.x1 <= t.x && t.x <= cursor.x2 && + cursor.y1 <= t.y && t.y <= cursor.y2) + { + miSpriteRemoveCursor (pDrawable->pScreen); + break; + } + } + } + else + { + for (pts = pptInit, n = npt; n--; pts++) + { + if (cursor.x1 <= pts->x && pts->x <= cursor.x2 && + cursor.y1 <= pts->y && pts->y <= cursor.y2) + { + miSpriteRemoveCursor (pDrawable->pScreen); + break; + } + } + } + } + + GC_OP_PROLOGUE (pGC); + + (*pGC->ops->PolyPoint) (pDrawable, pGC, mode, npt, pptInit); + + GC_OP_EPILOGUE (pGC); +} + +static void +miSpritePolylines (pDrawable, pGC, mode, npt, pptInit) + DrawablePtr pDrawable; + GCPtr pGC; + int mode; + int npt; + DDXPointPtr pptInit; +{ + BoxPtr cursor; + register DDXPointPtr pts; + int n; + int x, y, x1, y1, x2, y2; + int lw; + int extra; + + GC_SETUP (pDrawable, pGC); + + if (npt && GC_CHECK((WindowPtr) pDrawable)) + { + cursor = &pScreenPriv->saved; + lw = pGC->lineWidth; + x = pptInit->x + pDrawable->x; + y = pptInit->y + pDrawable->y; + + if (npt == 1) + { + extra = lw >> 1; + if (LINE_OVERLAP(cursor, x, y, x, y, extra)) + miSpriteRemoveCursor (pDrawable->pScreen); + } + else + { + extra = lw >> 1; + /* + * mitered joins can project quite a way from + * the line end; the 11 degree miter limit limits + * this extension to 10.43 * lw / 2, rounded up + * and converted to int yields 6 * lw + */ + if (pGC->joinStyle == JoinMiter) + extra = 6 * lw; + else if (pGC->capStyle == CapProjecting) + extra = lw; + for (pts = pptInit + 1, n = npt - 1; n--; pts++) + { + x1 = x; + y1 = y; + if (mode == CoordModeOrigin) + { + x2 = pDrawable->x + pts->x; + y2 = pDrawable->y + pts->y; + } + else + { + x2 = x + pts->x; + y2 = y + pts->y; + } + x = x2; + y = y2; + LINE_SORT(x1, y1, x2, y2); + if (LINE_OVERLAP(cursor, x1, y1, x2, y2, extra)) + { + miSpriteRemoveCursor (pDrawable->pScreen); + break; + } + } + } + } + GC_OP_PROLOGUE (pGC); + + (*pGC->ops->Polylines) (pDrawable, pGC, mode, npt, pptInit); + + GC_OP_EPILOGUE (pGC); +} + +static void +miSpritePolySegment(pDrawable, pGC, nseg, pSegs) + DrawablePtr pDrawable; + GCPtr pGC; + int nseg; + xSegment *pSegs; +{ + int n; + register xSegment *segs; + BoxPtr cursor; + int x1, y1, x2, y2; + int extra; + + GC_SETUP(pDrawable, pGC); + + if (nseg && GC_CHECK((WindowPtr) pDrawable)) + { + cursor = &pScreenPriv->saved; + extra = pGC->lineWidth >> 1; + if (pGC->capStyle == CapProjecting) + extra = pGC->lineWidth; + for (segs = pSegs, n = nseg; n--; segs++) + { + x1 = segs->x1 + pDrawable->x; + y1 = segs->y1 + pDrawable->y; + x2 = segs->x2 + pDrawable->x; + y2 = segs->y2 + pDrawable->y; + LINE_SORT(x1, y1, x2, y2); + if (LINE_OVERLAP(cursor, x1, y1, x2, y2, extra)) + { + miSpriteRemoveCursor (pDrawable->pScreen); + break; + } + } + } + + GC_OP_PROLOGUE (pGC); + + (*pGC->ops->PolySegment) (pDrawable, pGC, nseg, pSegs); + + GC_OP_EPILOGUE (pGC); +} + +static void +miSpritePolyRectangle(pDrawable, pGC, nrects, pRects) + DrawablePtr pDrawable; + GCPtr pGC; + int nrects; + xRectangle *pRects; +{ + register xRectangle *rects; + BoxPtr cursor; + int lw; + int n; + int x1, y1, x2, y2; + + GC_SETUP (pDrawable, pGC); + + if (GC_CHECK((WindowPtr) pDrawable)) + { + lw = pGC->lineWidth >> 1; + cursor = &pScreenPriv->saved; + for (rects = pRects, n = nrects; n--; rects++) + { + x1 = rects->x + pDrawable->x; + y1 = rects->y + pDrawable->y; + x2 = x1 + (int)rects->width; + y2 = y1 + (int)rects->height; + if (LINE_OVERLAP(cursor, x1, y1, x2, y1, lw) || + LINE_OVERLAP(cursor, x2, y1, x2, y2, lw) || + LINE_OVERLAP(cursor, x1, y2, x2, y2, lw) || + LINE_OVERLAP(cursor, x1, y1, x1, y2, lw)) + { + miSpriteRemoveCursor (pDrawable->pScreen); + break; + } + } + } + + GC_OP_PROLOGUE (pGC); + + (*pGC->ops->PolyRectangle) (pDrawable, pGC, nrects, pRects); + + GC_OP_EPILOGUE (pGC); +} + +static void +miSpritePolyArc(pDrawable, pGC, narcs, parcs) + DrawablePtr pDrawable; + register GCPtr pGC; + int narcs; + xArc *parcs; +{ + BoxPtr cursor; + int lw; + int n; + register xArc *arcs; + + GC_SETUP (pDrawable, pGC); + + if (GC_CHECK((WindowPtr) pDrawable)) + { + lw = pGC->lineWidth >> 1; + cursor = &pScreenPriv->saved; + for (arcs = parcs, n = narcs; n--; arcs++) + { + if (ORG_OVERLAP (cursor, pDrawable->x, pDrawable->y, + arcs->x - lw, arcs->y - lw, + (int) arcs->width + pGC->lineWidth, + (int) arcs->height + pGC->lineWidth)) + { + miSpriteRemoveCursor (pDrawable->pScreen); + break; + } + } + } + + GC_OP_PROLOGUE (pGC); + + (*pGC->ops->PolyArc) (pDrawable, pGC, narcs, parcs); + + GC_OP_EPILOGUE (pGC); +} + +static void +miSpriteFillPolygon(pDrawable, pGC, shape, mode, count, pPts) + register DrawablePtr pDrawable; + register GCPtr pGC; + int shape, mode; + int count; + DDXPointPtr pPts; +{ + int x, y, minx, miny, maxx, maxy; + register DDXPointPtr pts; + int n; + + GC_SETUP (pDrawable, pGC); + + if (count && GC_CHECK((WindowPtr) pDrawable)) + { + x = pDrawable->x; + y = pDrawable->y; + pts = pPts; + minx = maxx = pts->x; + miny = maxy = pts->y; + pts++; + n = count - 1; + + if (mode == CoordModeOrigin) + { + for (; n--; pts++) + { + if (pts->x < minx) + minx = pts->x; + else if (pts->x > maxx) + maxx = pts->x; + if (pts->y < miny) + miny = pts->y; + else if (pts->y > maxy) + maxy = pts->y; + } + minx += x; + miny += y; + maxx += x; + maxy += y; + } + else + { + x += minx; + y += miny; + minx = maxx = x; + miny = maxy = y; + for (; n--; pts++) + { + x += pts->x; + y += pts->y; + if (x < minx) + minx = x; + else if (x > maxx) + maxx = x; + if (y < miny) + miny = y; + else if (y > maxy) + maxy = y; + } + } + if (BOX_OVERLAP(&pScreenPriv->saved,minx,miny,maxx,maxy)) + miSpriteRemoveCursor (pDrawable->pScreen); + } + + GC_OP_PROLOGUE (pGC); + + (*pGC->ops->FillPolygon) (pDrawable, pGC, shape, mode, count, pPts); + + GC_OP_EPILOGUE (pGC); +} + +static void +miSpritePolyFillRect(pDrawable, pGC, nrectFill, prectInit) + DrawablePtr pDrawable; + GCPtr pGC; + int nrectFill; /* number of rectangles to fill */ + xRectangle *prectInit; /* Pointer to first rectangle to fill */ +{ + GC_SETUP(pDrawable, pGC); + + if (GC_CHECK((WindowPtr) pDrawable)) + { + register int nRect; + register xRectangle *pRect; + register int xorg, yorg; + + xorg = pDrawable->x; + yorg = pDrawable->y; + + for (nRect = nrectFill, pRect = prectInit; nRect--; pRect++) { + if (ORGRECT_OVERLAP(&pScreenPriv->saved,xorg,yorg,pRect)){ + miSpriteRemoveCursor(pDrawable->pScreen); + break; + } + } + } + + GC_OP_PROLOGUE (pGC); + + (*pGC->ops->PolyFillRect) (pDrawable, pGC, nrectFill, prectInit); + + GC_OP_EPILOGUE (pGC); +} + +static void +miSpritePolyFillArc(pDrawable, pGC, narcs, parcs) + DrawablePtr pDrawable; + GCPtr pGC; + int narcs; + xArc *parcs; +{ + GC_SETUP(pDrawable, pGC); + + if (GC_CHECK((WindowPtr) pDrawable)) + { + register int n; + BoxPtr cursor; + register xArc *arcs; + + cursor = &pScreenPriv->saved; + + for (arcs = parcs, n = narcs; n--; arcs++) + { + if (ORG_OVERLAP(cursor, pDrawable->x, pDrawable->y, + arcs->x, arcs->y, + (int) arcs->width, (int) arcs->height)) + { + miSpriteRemoveCursor (pDrawable->pScreen); + break; + } + } + } + + GC_OP_PROLOGUE (pGC); + + (*pGC->ops->PolyFillArc) (pDrawable, pGC, narcs, parcs); + + GC_OP_EPILOGUE (pGC); +} + +/* + * general Poly/Image text function. Extract glyph information, + * compute bounding box and remove cursor if it is overlapped. + */ + +static Bool +miSpriteTextOverlap (pDraw, font, x, y, n, charinfo, imageblt, w, cursorBox) + DrawablePtr pDraw; + FontPtr font; + int x, y; + unsigned int n; + CharInfoPtr *charinfo; + Bool imageblt; + unsigned int w; + BoxPtr cursorBox; +{ + ExtentInfoRec extents; + + x += pDraw->x; + y += pDraw->y; + + if (FONTMINBOUNDS(font,characterWidth) >= 0) + { + /* compute an approximate (but covering) bounding box */ + if (!imageblt || (charinfo[0]->metrics.leftSideBearing < 0)) + extents.overallLeft = charinfo[0]->metrics.leftSideBearing; + else + extents.overallLeft = 0; + if (w) + extents.overallRight = w - charinfo[n-1]->metrics.characterWidth; + else + extents.overallRight = FONTMAXBOUNDS(font,characterWidth) + * (n - 1); + if (imageblt && (charinfo[n-1]->metrics.characterWidth > + charinfo[n-1]->metrics.rightSideBearing)) + extents.overallRight += charinfo[n-1]->metrics.characterWidth; + else + extents.overallRight += charinfo[n-1]->metrics.rightSideBearing; + if (imageblt && FONTASCENT(font) > FONTMAXBOUNDS(font,ascent)) + extents.overallAscent = FONTASCENT(font); + else + extents.overallAscent = FONTMAXBOUNDS(font, ascent); + if (imageblt && FONTDESCENT(font) > FONTMAXBOUNDS(font,descent)) + extents.overallDescent = FONTDESCENT(font); + else + extents.overallDescent = FONTMAXBOUNDS(font,descent); + if (!BOX_OVERLAP(cursorBox, + x + extents.overallLeft, + y - extents.overallAscent, + x + extents.overallRight, + y + extents.overallDescent)) + return FALSE; + else if (imageblt && w) + return TRUE; + /* if it does overlap, fall through and compute exactly, because + * taking down the cursor is expensive enough to make this worth it + */ + } + QueryGlyphExtents(font, charinfo, n, &extents); + if (imageblt) + { + if (extents.overallWidth > extents.overallRight) + extents.overallRight = extents.overallWidth; + if (extents.overallWidth < extents.overallLeft) + extents.overallLeft = extents.overallWidth; + if (extents.overallLeft > 0) + extents.overallLeft = 0; + if (extents.fontAscent > extents.overallAscent) + extents.overallAscent = extents.fontAscent; + if (extents.fontDescent > extents.overallDescent) + extents.overallDescent = extents.fontDescent; + } + return (BOX_OVERLAP(cursorBox, + x + extents.overallLeft, + y - extents.overallAscent, + x + extents.overallRight, + y + extents.overallDescent)); +} + +/* + * values for textType: + */ +#define TT_POLY8 0 +#define TT_IMAGE8 1 +#define TT_POLY16 2 +#define TT_IMAGE16 3 + +static int +miSpriteText (pDraw, pGC, x, y, count, chars, fontEncoding, textType, cursorBox) + DrawablePtr pDraw; + GCPtr pGC; + int x, + y; + unsigned long count; + char *chars; + FontEncoding fontEncoding; + Bool textType; + BoxPtr cursorBox; +{ + CharInfoPtr *charinfo; + register CharInfoPtr *info; + unsigned long i; + unsigned int n; + int w; + void (*drawFunc)(); + + Bool imageblt; + + imageblt = (textType == TT_IMAGE8) || (textType == TT_IMAGE16); + + charinfo = (CharInfoPtr *) ALLOCATE_LOCAL(count * sizeof(CharInfoPtr)); + if (!charinfo) + return x; + + GetGlyphs(pGC->font, count, (unsigned char *)chars, + fontEncoding, &i, charinfo); + n = (unsigned int)i; + w = 0; + if (!imageblt) + for (info = charinfo; i--; info++) + w += (*info)->metrics.characterWidth; + + if (n != 0) { + if (miSpriteTextOverlap(pDraw, pGC->font, x, y, n, charinfo, imageblt, w, cursorBox)) + miSpriteRemoveCursor(pDraw->pScreen); + +#ifdef AVOID_GLYPHBLT + /* + * On displays like Apollos, which do not optimize the GlyphBlt functions because they + * convert fonts to their internal form in RealizeFont and optimize text directly, we + * want to invoke the text functions here, not the GlyphBlt functions. + */ + switch (textType) + { + case TT_POLY8: + drawFunc = (void (*)())pGC->ops->PolyText8; + break; + case TT_IMAGE8: + drawFunc = pGC->ops->ImageText8; + break; + case TT_POLY16: + drawFunc = (void (*)())pGC->ops->PolyText16; + break; + case TT_IMAGE16: + drawFunc = pGC->ops->ImageText16; + break; + } + (*drawFunc) (pDraw, pGC, x, y, (int) count, chars); +#else /* don't AVOID_GLYPHBLT */ + /* + * On the other hand, if the device does use GlyphBlt ultimately to do text, we + * don't want to slow it down by invoking the text functions and having them call + * GetGlyphs all over again, so we go directly to the GlyphBlt functions here. + */ + drawFunc = imageblt ? pGC->ops->ImageGlyphBlt : pGC->ops->PolyGlyphBlt; + (*drawFunc) (pDraw, pGC, x, y, n, charinfo, FONTGLYPHS(pGC->font)); +#endif /* AVOID_GLYPHBLT */ + } + DEALLOCATE_LOCAL(charinfo); + return x + w; +} + +static int +miSpritePolyText8(pDrawable, pGC, x, y, count, chars) + DrawablePtr pDrawable; + GCPtr pGC; + int x, y; + int count; + char *chars; +{ + int ret; + + GC_SETUP (pDrawable, pGC); + + GC_OP_PROLOGUE (pGC); + + if (GC_CHECK((WindowPtr) pDrawable)) + ret = miSpriteText (pDrawable, pGC, x, y, (unsigned long)count, chars, + Linear8Bit, TT_POLY8, &pScreenPriv->saved); + else + ret = (*pGC->ops->PolyText8) (pDrawable, pGC, x, y, count, chars); + + GC_OP_EPILOGUE (pGC); + return ret; +} + +static int +miSpritePolyText16(pDrawable, pGC, x, y, count, chars) + DrawablePtr pDrawable; + GCPtr pGC; + int x, y; + int count; + unsigned short *chars; +{ + int ret; + + GC_SETUP(pDrawable, pGC); + + GC_OP_PROLOGUE (pGC); + + if (GC_CHECK((WindowPtr) pDrawable)) + ret = miSpriteText (pDrawable, pGC, x, y, (unsigned long)count, + (char *)chars, + FONTLASTROW(pGC->font) == 0 ? + Linear16Bit : TwoD16Bit, TT_POLY16, &pScreenPriv->saved); + else + ret = (*pGC->ops->PolyText16) (pDrawable, pGC, x, y, count, chars); + + GC_OP_EPILOGUE (pGC); + return ret; +} + +static void +miSpriteImageText8(pDrawable, pGC, x, y, count, chars) + DrawablePtr pDrawable; + GCPtr pGC; + int x, y; + int count; + char *chars; +{ + GC_SETUP(pDrawable, pGC); + + GC_OP_PROLOGUE (pGC); + + if (GC_CHECK((WindowPtr) pDrawable)) + (void) miSpriteText (pDrawable, pGC, x, y, (unsigned long)count, + chars, Linear8Bit, TT_IMAGE8, &pScreenPriv->saved); + else + (*pGC->ops->ImageText8) (pDrawable, pGC, x, y, count, chars); + + GC_OP_EPILOGUE (pGC); +} + +static void +miSpriteImageText16(pDrawable, pGC, x, y, count, chars) + DrawablePtr pDrawable; + GCPtr pGC; + int x, y; + int count; + unsigned short *chars; +{ + GC_SETUP(pDrawable, pGC); + + GC_OP_PROLOGUE (pGC); + + if (GC_CHECK((WindowPtr) pDrawable)) + (void) miSpriteText (pDrawable, pGC, x, y, (unsigned long)count, + (char *)chars, + FONTLASTROW(pGC->font) == 0 ? + Linear16Bit : TwoD16Bit, TT_IMAGE16, &pScreenPriv->saved); + else + (*pGC->ops->ImageText16) (pDrawable, pGC, x, y, count, chars); + + GC_OP_EPILOGUE (pGC); +} + +static void +miSpriteImageGlyphBlt(pDrawable, pGC, x, y, nglyph, ppci, pglyphBase) + DrawablePtr pDrawable; + GCPtr pGC; + int x, y; + unsigned int nglyph; + CharInfoPtr *ppci; /* array of character info */ + pointer pglyphBase; /* start of array of glyphs */ +{ + GC_SETUP(pDrawable, pGC); + + GC_OP_PROLOGUE (pGC); + + if (GC_CHECK((WindowPtr) pDrawable) && + miSpriteTextOverlap (pDrawable, pGC->font, x, y, nglyph, ppci, TRUE, 0, &pScreenPriv->saved)) + { + miSpriteRemoveCursor(pDrawable->pScreen); + } + (*pGC->ops->ImageGlyphBlt) (pDrawable, pGC, x, y, nglyph, ppci, pglyphBase); + + GC_OP_EPILOGUE (pGC); +} + +static void +miSpritePolyGlyphBlt(pDrawable, pGC, x, y, nglyph, ppci, pglyphBase) + DrawablePtr pDrawable; + GCPtr pGC; + int x, y; + unsigned int nglyph; + CharInfoPtr *ppci; /* array of character info */ + pointer pglyphBase; /* start of array of glyphs */ +{ + GC_SETUP (pDrawable, pGC); + + GC_OP_PROLOGUE (pGC); + + if (GC_CHECK((WindowPtr) pDrawable) && + miSpriteTextOverlap (pDrawable, pGC->font, x, y, nglyph, ppci, FALSE, 0, &pScreenPriv->saved)) + { + miSpriteRemoveCursor(pDrawable->pScreen); + } + (*pGC->ops->PolyGlyphBlt) (pDrawable, pGC, x, y, nglyph, ppci, pglyphBase); + + GC_OP_EPILOGUE (pGC); +} + +static void +miSpritePushPixels(pGC, pBitMap, pDrawable, w, h, x, y) + GCPtr pGC; + PixmapPtr pBitMap; + DrawablePtr pDrawable; + int w, h, x, y; +{ + GC_SETUP(pDrawable, pGC); + + if (GC_CHECK((WindowPtr) pDrawable) && + ORG_OVERLAP(&pScreenPriv->saved,pDrawable->x,pDrawable->y,x,y,w,h)) + { + miSpriteRemoveCursor (pDrawable->pScreen); + } + + GC_OP_PROLOGUE (pGC); + + (*pGC->ops->PushPixels) (pGC, pBitMap, pDrawable, w, h, x, y); + + GC_OP_EPILOGUE (pGC); +} + +#ifdef NEED_LINEHELPER +/* + * I don't expect this routine will ever be called, as the GC + * will have been unwrapped for the line drawing + */ + +static void +miSpriteLineHelper() +{ + FatalError("miSpriteLineHelper called\n"); +} +#endif + +/* + * miPointer interface routines + */ + +#define SPRITE_PAD 8 + +static Bool +miSpriteRealizeCursor (pScreen, pCursor) + ScreenPtr pScreen; + CursorPtr pCursor; +{ + miSpriteScreenPtr pScreenPriv; + + pScreenPriv = (miSpriteScreenPtr) pScreen->devPrivates[miSpriteScreenIndex].ptr; + if (pCursor == pScreenPriv->pCursor) + pScreenPriv->checkPixels = TRUE; + return (*pScreenPriv->funcs->RealizeCursor) (pScreen, pCursor); +} + +static Bool +miSpriteUnrealizeCursor (pScreen, pCursor) + ScreenPtr pScreen; + CursorPtr pCursor; +{ + miSpriteScreenPtr pScreenPriv; + + pScreenPriv = (miSpriteScreenPtr) pScreen->devPrivates[miSpriteScreenIndex].ptr; + return (*pScreenPriv->funcs->UnrealizeCursor) (pScreen, pCursor); +} + +static void +miSpriteSetCursor (pScreen, pCursor, x, y) + ScreenPtr pScreen; + CursorPtr pCursor; +{ + miSpriteScreenPtr pScreenPriv; + + pScreenPriv = (miSpriteScreenPtr) pScreen->devPrivates[miSpriteScreenIndex].ptr; + pScreenPriv->shouldBeUp = TRUE; + if (pScreenPriv->x == x && + pScreenPriv->y == y && + pScreenPriv->pCursor == pCursor && + !pScreenPriv->checkPixels) + { + return; + } + if (!pCursor) + { + pScreenPriv->shouldBeUp = FALSE; + if (pScreenPriv->isUp) + miSpriteRemoveCursor (pScreen); + pScreenPriv->pCursor = 0; + return; + } + pScreenPriv->x = x; + pScreenPriv->y = y; + pScreenPriv->pCacheWin = NullWindow; + if (pScreenPriv->checkPixels || pScreenPriv->pCursor != pCursor) + { + pScreenPriv->pCursor = pCursor; + miSpriteFindColors (pScreen); + } + if (pScreenPriv->isUp) { + int sx, sy; + /* + * check to see if the old saved region + * encloses the new sprite, in which case we use + * the flicker-free MoveCursor primitive. + */ + sx = pScreenPriv->x - (int)pCursor->bits->xhot; + sy = pScreenPriv->y - (int)pCursor->bits->yhot; + if (sx + (int) pCursor->bits->width >= pScreenPriv->saved.x1 && + sx < pScreenPriv->saved.x2 && + sy + (int) pCursor->bits->height >= pScreenPriv->saved.y1 && + sy < pScreenPriv->saved.y2 && + (int) pCursor->bits->width + (2 * SPRITE_PAD) == + pScreenPriv->saved.x2 - pScreenPriv->saved.x1 && + (int) pCursor->bits->height + (2 * SPRITE_PAD) == + pScreenPriv->saved.y2 - pScreenPriv->saved.y1 + ) + { + pScreenPriv->isUp = FALSE; + if (!(sx >= pScreenPriv->saved.x1 && + sx + (int)pCursor->bits->width < pScreenPriv->saved.x2 && + sy >= pScreenPriv->saved.y1 && + sy + (int)pCursor->bits->height < pScreenPriv->saved.y2)) + { + int oldx1, oldy1, dx, dy; + + oldx1 = pScreenPriv->saved.x1; + oldy1 = pScreenPriv->saved.y1; + dx = oldx1 - (sx - SPRITE_PAD); + dy = oldy1 - (sy - SPRITE_PAD); + pScreenPriv->saved.x1 -= dx; + pScreenPriv->saved.y1 -= dy; + pScreenPriv->saved.x2 -= dx; + pScreenPriv->saved.y2 -= dy; + (void) (*pScreenPriv->funcs->ChangeSave) (pScreen, + pScreenPriv->saved.x1, + pScreenPriv->saved.y1, + pScreenPriv->saved.x2 - pScreenPriv->saved.x1, + pScreenPriv->saved.y2 - pScreenPriv->saved.y1, + dx, dy); + } + (void) (*pScreenPriv->funcs->MoveCursor) (pScreen, pCursor, + pScreenPriv->saved.x1, + pScreenPriv->saved.y1, + pScreenPriv->saved.x2 - pScreenPriv->saved.x1, + pScreenPriv->saved.y2 - pScreenPriv->saved.y1, + sx - pScreenPriv->saved.x1, + sy - pScreenPriv->saved.y1, + pScreenPriv->colors[SOURCE_COLOR].pixel, + pScreenPriv->colors[MASK_COLOR].pixel); + pScreenPriv->isUp = TRUE; + } + else + { + miSpriteRemoveCursor (pScreen); + } + } + if (!pScreenPriv->isUp && pScreenPriv->pCursor) + miSpriteRestoreCursor (pScreen); +} + +static void +miSpriteMoveCursor (pScreen, x, y) + ScreenPtr pScreen; + int x, y; +{ + miSpriteScreenPtr pScreenPriv; + + pScreenPriv = (miSpriteScreenPtr) pScreen->devPrivates[miSpriteScreenIndex].ptr; + miSpriteSetCursor (pScreen, pScreenPriv->pCursor, x, y); +} + +/* + * undraw/draw cursor + */ + +static void +miSpriteRemoveCursor (pScreen) + ScreenPtr pScreen; +{ + miSpriteScreenPtr pScreenPriv; + + pScreenPriv = (miSpriteScreenPtr) pScreen->devPrivates[miSpriteScreenIndex].ptr; + pScreenPriv->isUp = FALSE; + pScreenPriv->pCacheWin = NullWindow; + if (!(*pScreenPriv->funcs->RestoreUnderCursor) (pScreen, + pScreenPriv->saved.x1, + pScreenPriv->saved.y1, + pScreenPriv->saved.x2 - pScreenPriv->saved.x1, + pScreenPriv->saved.y2 - pScreenPriv->saved.y1)) + { + pScreenPriv->isUp = TRUE; + } +} + +/* + * Called from the block handler, restores the cursor + * before waiting for something to do. + */ + +static void +miSpriteRestoreCursor (pScreen) + ScreenPtr pScreen; +{ + miSpriteScreenPtr pScreenPriv; + int x, y; + CursorPtr pCursor; + + miSpriteComputeSaved (pScreen); + pScreenPriv = (miSpriteScreenPtr) pScreen->devPrivates[miSpriteScreenIndex].ptr; + pCursor = pScreenPriv->pCursor; + x = pScreenPriv->x - (int)pCursor->bits->xhot; + y = pScreenPriv->y - (int)pCursor->bits->yhot; + if ((*pScreenPriv->funcs->SaveUnderCursor) (pScreen, + pScreenPriv->saved.x1, + pScreenPriv->saved.y1, + pScreenPriv->saved.x2 - pScreenPriv->saved.x1, + pScreenPriv->saved.y2 - pScreenPriv->saved.y1)) + { + if (pScreenPriv->checkPixels) + miSpriteFindColors (pScreen); + if ((*pScreenPriv->funcs->PutUpCursor) (pScreen, pCursor, x, y, + pScreenPriv->colors[SOURCE_COLOR].pixel, + pScreenPriv->colors[MASK_COLOR].pixel)) + pScreenPriv->isUp = TRUE; + } +} + +/* + * compute the desired area of the screen to save + */ + +static void +miSpriteComputeSaved (pScreen) + ScreenPtr pScreen; +{ + miSpriteScreenPtr pScreenPriv; + int x, y, w, h; + int wpad, hpad; + CursorPtr pCursor; + + pScreenPriv = (miSpriteScreenPtr) pScreen->devPrivates[miSpriteScreenIndex].ptr; + pCursor = pScreenPriv->pCursor; + x = pScreenPriv->x - (int)pCursor->bits->xhot; + y = pScreenPriv->y - (int)pCursor->bits->yhot; + w = pCursor->bits->width; + h = pCursor->bits->height; + wpad = SPRITE_PAD; + hpad = SPRITE_PAD; + pScreenPriv->saved.x1 = x - wpad; + pScreenPriv->saved.y1 = y - hpad; + pScreenPriv->saved.x2 = pScreenPriv->saved.x1 + w + wpad * 2; + pScreenPriv->saved.y2 = pScreenPriv->saved.y1 + h + hpad * 2; +} |