/* * 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. */ /* $XFree86$ */ # 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" #ifdef RENDER # include "mipict.h" #endif /* * screen wrappers */ static int miSpriteScreenIndex; static unsigned long miSpriteGeneration = 0; static Bool miSpriteCloseScreen(int i, ScreenPtr pScreen); static void miSpriteGetImage(DrawablePtr pDrawable, int sx, int sy, int w, int h, unsigned int format, unsigned long planemask, char *pdstLine); static void miSpriteGetSpans(DrawablePtr pDrawable, int wMax, DDXPointPtr ppt, int *pwidth, int nspans, char *pdstStart); static void miSpriteSourceValidate(DrawablePtr pDrawable, int x, int y, int width, int height); static Bool miSpriteCreateGC(GCPtr pGC); static void miSpriteBlockHandler(int i, pointer blockData, pointer pTimeout, pointer pReadMask); static void miSpriteInstallColormap(ColormapPtr pMap); static void miSpriteStoreColors(ColormapPtr pMap, int ndef, xColorItem *pdef); static void miSpritePaintWindowBackground(WindowPtr pWin, RegionPtr pRegion, int what); static void miSpritePaintWindowBorder(WindowPtr pWin, RegionPtr pRegion, int what); static void miSpriteCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr pRegion); static void miSpriteClearToBackground(WindowPtr pWin, int x, int y, int w, int h, Bool generateExposures); #ifdef RENDER static void miSpriteComposite(CARD8 op, PicturePtr pSrc, PicturePtr pMask, PicturePtr pDst, INT16 xSrc, INT16 ySrc, INT16 xMask, INT16 yMask, INT16 xDst, INT16 yDst, CARD16 width, CARD16 height); static void miSpriteGlyphs(CARD8 op, PicturePtr pSrc, PicturePtr pDst, PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, int nlist, GlyphListPtr list, GlyphPtr *glyphs); #endif static void miSpriteSaveDoomedAreas(WindowPtr pWin, RegionPtr pObscured, int dx, int dy); static RegionPtr miSpriteRestoreAreas(WindowPtr pWin, RegionPtr pRgnExposed); static void miSpriteComputeSaved(ScreenPtr pScreen); #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(GCPtr pGC, unsigned long stateChanges, DrawablePtr pDrawable); static void miSpriteCopyGC(GCPtr pGCSrc, unsigned long mask, GCPtr pGCDst); static void miSpriteDestroyGC(GCPtr pGC); static void miSpriteChangeGC(GCPtr pGC, unsigned long mask); static void miSpriteChangeClip(GCPtr pGC, int type, pointer pvalue, int nrects); static void miSpriteDestroyClip(GCPtr pGC); static void miSpriteCopyClip(GCPtr pgcDst, GCPtr pgcSrc); 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(DrawablePtr pDrawable, GCPtr pGC, int nInit, DDXPointPtr pptInit, int *pwidthInit, int fSorted); static void miSpriteSetSpans(DrawablePtr pDrawable, GCPtr pGC, char *psrc, DDXPointPtr ppt, int *pwidth, int nspans, int fSorted); static void miSpritePutImage(DrawablePtr pDrawable, GCPtr pGC, int depth, int x, int y, int w, int h, int leftPad, int format, char *pBits); static RegionPtr miSpriteCopyArea(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC, int srcx, int srcy, int w, int h, int dstx, int dsty); static RegionPtr miSpriteCopyPlane(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC, int srcx, int srcy, int w, int h, int dstx, int dsty, unsigned long plane); static void miSpritePolyPoint(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt, xPoint *pptInit); static void miSpritePolylines(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt, DDXPointPtr pptInit); static void miSpritePolySegment(DrawablePtr pDrawable, GCPtr pGC, int nseg, xSegment *pSegs); static void miSpritePolyRectangle(DrawablePtr pDrawable, GCPtr pGC, int nrects, xRectangle *pRects); static void miSpritePolyArc(DrawablePtr pDrawable, GCPtr pGC, int narcs, xArc *parcs); static void miSpriteFillPolygon(DrawablePtr pDrawable, GCPtr pGC, int shape, int mode, int count, DDXPointPtr pPts); static void miSpritePolyFillRect(DrawablePtr pDrawable, GCPtr pGC, int nrectFill, xRectangle *prectInit); static void miSpritePolyFillArc(DrawablePtr pDrawable, GCPtr pGC, int narcs, xArc *parcs); static int miSpritePolyText8(DrawablePtr pDrawable, GCPtr pGC, int x, int y, int count, char *chars); static int miSpritePolyText16(DrawablePtr pDrawable, GCPtr pGC, int x, int y, int count, unsigned short *chars); static void miSpriteImageText8(DrawablePtr pDrawable, GCPtr pGC, int x, int y, int count, char *chars); static void miSpriteImageText16(DrawablePtr pDrawable, GCPtr pGC, int x, int y, int count, unsigned short *chars); static void miSpriteImageGlyphBlt(DrawablePtr pDrawable, GCPtr pGC, int x, int y, unsigned int nglyph, CharInfoPtr *ppci, pointer pglyphBase); static void miSpritePolyGlyphBlt(DrawablePtr pDrawable, GCPtr pGC, int x, int y, unsigned int nglyph, CharInfoPtr *ppci, pointer pglyphBase); static void miSpritePushPixels(GCPtr pGC, PixmapPtr pBitMap, DrawablePtr pDst, int w, int h, int x, int y); #ifdef NEED_LINEHELPER static void miSpriteLineHelper(void); #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 : ( \ (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(ScreenPtr pScreen, CursorPtr pCursor); static Bool miSpriteUnrealizeCursor(ScreenPtr pScreen, CursorPtr pCursor); static void miSpriteSetCursor(ScreenPtr pScreen, CursorPtr pCursor, int x, int y); static void miSpriteMoveCursor(ScreenPtr pScreen, int x, int y); miPointerSpriteFuncRec miSpritePointerFuncs = { miSpriteRealizeCursor, miSpriteUnrealizeCursor, miSpriteSetCursor, miSpriteMoveCursor, }; /* * other misc functions */ static void miSpriteRemoveCursor(ScreenPtr pScreen); static void miSpriteRestoreCursor(ScreenPtr pScreen); /* * 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; #ifdef RENDER PictureScreenPtr ps = GetPictureScreenIfSet(pScreen); #endif 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; #ifdef RENDER if (ps) { pPriv->Composite = ps->Composite; pPriv->Glyphs = ps->Glyphs; } #endif 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; #ifdef RENDER if (ps) { ps->Composite = miSpriteComposite; ps->Glyphs = miSpriteGlyphs; } #endif return TRUE; } /* * Screen wrappers */ /* * CloseScreen wrapper -- unwrap everything, free the private data * and call the wrapped function */ static Bool miSpriteCloseScreen (i, pScreen) int i; ScreenPtr pScreen; { miSpriteScreenPtr pScreenPriv; #ifdef RENDER PictureScreenPtr ps = GetPictureScreenIfSet(pScreen); #endif 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; #ifdef RENDER if (ps) { ps->Composite = pScreenPriv->Composite; ps->Glyphs = pScreenPriv->Glyphs; } #endif 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; pointer 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 (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; int x,y; int 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; unsigned long 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 leftPad; 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 ( DrawablePtr pDraw, FontPtr font, int x, int 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 ( DrawablePtr pDraw, GCPtr pGC, int x, int 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; 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: (*pGC->ops->PolyText8)(pDraw, pGC, x, y, (int)count, chars); break; case TT_IMAGE8: (*pGC->ops->ImageText8)(pDraw, pGC, x, y, (int)count, chars); break; case TT_POLY16: (*pGC->ops->PolyText16)(pDraw, pGC, x, y, (int)count, (unsigned short *)chars); break; case TT_IMAGE16: (*pGC->ops->ImageText16)(pDraw, pGC, x, y, (int)count, (unsigned short *)chars); break; } #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. */ if (imageblt) { (*pGC->ops->ImageGlyphBlt)(pDraw, pGC, x, y, n, charinfo, FONTGLYPHS(pGC->font)); } else { (*pGC->ops->PolyGlyphBlt)(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 #ifdef RENDER # define mod(a,b) ((b) == 1 ? 0 : (a) >= 0 ? (a) % (b) : (b) - (-a) % (b)) static void miSpritePictureOverlap (PicturePtr pPict, INT16 x, INT16 y, CARD16 w, CARD16 h) { if (pPict->pDrawable->type == DRAWABLE_WINDOW) { WindowPtr pWin = (WindowPtr) (pPict->pDrawable); miSpriteScreenPtr pScreenPriv = (miSpriteScreenPtr) pPict->pDrawable->pScreen->devPrivates[miSpriteScreenIndex].ptr; if (GC_CHECK(pWin)) { if (pPict->repeat) { x = mod(x,pWin->drawable.width); y = mod(y,pWin->drawable.height); } if (ORG_OVERLAP (&pScreenPriv->saved, pWin->drawable.x, pWin->drawable.y, x, y, w, h)) miSpriteRemoveCursor (pWin->drawable.pScreen); } } } #define PICTURE_PROLOGUE(ps, pScreenPriv, field) \ ps->field = pScreenPriv->field #define PICTURE_EPILOGUE(ps, field, wrap) \ ps->field = wrap static void miSpriteComposite(CARD8 op, PicturePtr pSrc, PicturePtr pMask, PicturePtr pDst, INT16 xSrc, INT16 ySrc, INT16 xMask, INT16 yMask, INT16 xDst, INT16 yDst, CARD16 width, CARD16 height) { ScreenPtr pScreen = pDst->pDrawable->pScreen; PictureScreenPtr ps = GetPictureScreen(pScreen); miSpriteScreenPtr pScreenPriv; pScreenPriv = (miSpriteScreenPtr) pScreen->devPrivates[miSpriteScreenIndex].ptr; PICTURE_PROLOGUE(ps, pScreenPriv, Composite); miSpritePictureOverlap (pSrc, xSrc, ySrc, width, height); if (pMask) miSpritePictureOverlap (pMask, xMask, yMask, width, height); miSpritePictureOverlap (pDst, xDst, yDst, width, height); (*ps->Composite) (op, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask, xDst, yDst, width, height); PICTURE_EPILOGUE(ps, Composite, miSpriteComposite); } static void miSpriteGlyphs(CARD8 op, PicturePtr pSrc, PicturePtr pDst, PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, int nlist, GlyphListPtr list, GlyphPtr *glyphs) { ScreenPtr pScreen = pDst->pDrawable->pScreen; PictureScreenPtr ps = GetPictureScreen(pScreen); miSpriteScreenPtr pScreenPriv; pScreenPriv = (miSpriteScreenPtr) pScreen->devPrivates[miSpriteScreenIndex].ptr; PICTURE_PROLOGUE(ps, pScreenPriv, Glyphs); if (pSrc->pDrawable->type == DRAWABLE_WINDOW) { WindowPtr pSrcWin = (WindowPtr) (pSrc->pDrawable); if (GC_CHECK(pSrcWin)) miSpriteRemoveCursor (pScreen); } if (pDst->pDrawable->type == DRAWABLE_WINDOW) { WindowPtr pDstWin = (WindowPtr) (pDst->pDrawable); if (GC_CHECK(pDstWin)) { BoxRec extents; miGlyphExtents (nlist, list, glyphs, &extents); if (BOX_OVERLAP(&pScreenPriv->saved, extents.x1 + pDstWin->drawable.x, extents.y1 + pDstWin->drawable.y, extents.x2 + pDstWin->drawable.x, extents.y2 + pDstWin->drawable.y)) { miSpriteRemoveCursor (pScreen); } } } (*ps->Glyphs) (op, pSrc, pDst, maskFormat, xSrc, ySrc, nlist, list, glyphs); PICTURE_EPILOGUE (ps, Glyphs, miSpriteGlyphs); } #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; int x; int y; { miSpriteScreenPtr pScreenPriv; pScreenPriv = (miSpriteScreenPtr) pScreen->devPrivates[miSpriteScreenIndex].ptr; if (!pCursor) { pScreenPriv->shouldBeUp = FALSE; if (pScreenPriv->isUp) miSpriteRemoveCursor (pScreen); pScreenPriv->pCursor = 0; return; } pScreenPriv->shouldBeUp = TRUE; if (pScreenPriv->x == x && pScreenPriv->y == y && pScreenPriv->pCursor == pCursor && !pScreenPriv->checkPixels) { 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; }