diff options
Diffstat (limited to 'mi')
-rw-r--r-- | mi/mibank.c | 2573 | ||||
-rw-r--r-- | mi/mibank.h | 119 | ||||
-rw-r--r-- | mi/micmap.c | 674 | ||||
-rw-r--r-- | mi/micmap.h | 65 | ||||
-rw-r--r-- | mi/micoord.h | 71 | ||||
-rw-r--r-- | mi/mioverlay.c | 2078 | ||||
-rw-r--r-- | mi/mioverlay.h | 29 | ||||
-rw-r--r-- | mi/mizerclip.c | 632 |
8 files changed, 6241 insertions, 0 deletions
diff --git a/mi/mibank.c b/mi/mibank.c new file mode 100644 index 000000000..a6e1942c2 --- /dev/null +++ b/mi/mibank.c @@ -0,0 +1,2573 @@ +/* + * Copyright 1997 through 2003 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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, and + * that the name of Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * Copyright 1990,91,92,93 by Thomas Roell, Germany. + * Copyright 1991,92,93 by SGCS (Snitily Graphics Consulting Services), USA. + * + * 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, and that the name of Thomas Roell nor + * SGCS be used in advertising or publicity pertaining to distribution + * of the software without specific, written prior permission. + * Thomas Roell nor SGCS makes no representations about the suitability + * of this software for any purpose. It is provided "as is" without + * express or implied warranty. + * + * THOMAS ROELL AND SGCS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THOMAS ROELL OR SGCS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* $XFree86: xc/programs/Xserver/mi/mibank.c,v 1.13 2003/01/01 19:16:42 tsi Exp $ */ + +/* + * This thing originated from an idea of Edwin Goei and his bank switching + * code for the DEC TX board. + */ + +/* + * Heavily modified for the XFree86 Project to turn this into an mi wrapper. + * --- Marc Aurele La France (tsi@xfree86.org) + */ + +/* + * "Heavily modified", indeed! By the time this is finalized, there probably + * won't be much left of Roell's code... + * + * Miscellaneous notes: + * - Pixels with imbedded bank boundaries are required to be off-screen. There + * >might< be a way to fool the underlying framebuffer into dealing with + * partial pixels. + * - Plans to generalise this to do (hardware) colour plane switching have been + * dropped due to colour flashing concerns. + * + * TODO: + * - Allow miModifyBanking() to change BankSize and nBankDepth. + * - Re-instate shared and double banking for framebuffers whose pixmap formats + * don't describe how the server "sees" the screen. + * - Remove remaining assumptions that a pixmap's devPrivate field points + * directly to its pixel data. + */ + +/* #define NO_ALLOCA 1 */ + +#include "servermd.h" +#include "gcstruct.h" +#include "pixmapstr.h" +#include "scrnintstr.h" +#include "windowstr.h" +#include "mi.h" +#include "mibank.h" + +#define BANK_SINGLE 0 +#define BANK_SHARED 1 +#define BANK_DOUBLE 2 +#define BANK_NOBANK 3 + +typedef struct _miBankScreen +{ + miBankInfoRec BankInfo; + unsigned int nBankBPP; + unsigned int type; + + unsigned long nBitsPerBank; + unsigned long nBitsPerScanline; + unsigned long nPixelsPerScanlinePadUnit; + + PixmapPtr pScreenPixmap; + PixmapPtr pBankPixmap; + GCPtr pBankGC; + + int nBanks, maxRects; + RegionPtr *pBanks; + + pointer pbits; + + /* + * Screen Wrappers + */ + CreateScreenResourcesProcPtr CreateScreenResources; + ModifyPixmapHeaderProcPtr ModifyPixmapHeader; + CloseScreenProcPtr CloseScreen; + GetImageProcPtr GetImage; + GetSpansProcPtr GetSpans; + CreateGCProcPtr CreateGC; + PaintWindowBackgroundProcPtr PaintWindowBackground; + PaintWindowBorderProcPtr PaintWindowBorder; + CopyWindowProcPtr CopyWindow; + BSFuncRec BackingStoreFuncs; +} miBankScreenRec, *miBankScreenPtr; + +typedef struct _miBankGC +{ + GCOps *wrappedOps, *unwrappedOps; + GCFuncs *wrappedFuncs, *unwrappedFuncs; + + Bool fastCopy, fastPlane; + + RegionPtr pBankedClips[1]; +} miBankGCRec, *miBankGCPtr; + +typedef struct _miBankQueue +{ + Bool fastBlit; + unsigned short srcBankNo; + unsigned short dstBankNo; + short x; + short y; + short w; + short h; +} miBankQueue; + +/* + * CAVEAT: This banking scheme requires that the DDX store Pixmap data in the + * server's address space. + */ + +#define ModifyPixmap(_pPix, _width, _devKind, _pbits) \ + (*pScreen->ModifyPixmapHeader)((_pPix), \ + (_width), -1, -1, -1, (_devKind), (_pbits)) + +#define SET_SINGLE_BANK(_pPix, _width, _devKind, _no) \ + ModifyPixmap(_pPix, _width, _devKind, \ + (char *)pScreenPriv->BankInfo.pBankA + \ + (*pScreenPriv->BankInfo.SetSourceAndDestinationBanks)(pScreen, (_no)) - \ + (pScreenPriv->BankInfo.BankSize * (_no))) + +#define SET_SOURCE_BANK(_pPix, _width, _devKind, _no) \ + ModifyPixmap(_pPix, _width, _devKind, \ + (char *)pScreenPriv->BankInfo.pBankA + \ + (*pScreenPriv->BankInfo.SetSourceBank)(pScreen, (_no)) - \ + (pScreenPriv->BankInfo.BankSize * (_no))) + +#define SET_DESTINATION_BANK(_pPix, _width, _devKind, _no) \ + ModifyPixmap(_pPix, _width, _devKind, \ + (char *)pScreenPriv->BankInfo.pBankB + \ + (*pScreenPriv->BankInfo.SetDestinationBank)(pScreen, (_no)) - \ + (pScreenPriv->BankInfo.BankSize * (_no))) + +#define ALLOCATE_LOCAL_ARRAY(atype, ntype) \ + (atype *)ALLOCATE_LOCAL((ntype) * sizeof(atype)) + +static int miBankScreenIndex; +static int miBankGCIndex; +static unsigned long miBankGeneration = 0; + +#define BANK_SCRPRIVLVAL pScreen->devPrivates[miBankScreenIndex].ptr + +#define BANK_SCRPRIVATE ((miBankScreenPtr)(BANK_SCRPRIVLVAL)) + +#define BANK_GCPRIVLVAL(pGC) (pGC)->devPrivates[miBankGCIndex].ptr + +#define BANK_GCPRIVATE(pGC) ((miBankGCPtr)(BANK_GCPRIVLVAL(pGC))) + +#define PIXMAP_STATUS(_pPix) \ + pointer pbits = (_pPix)->devPrivate.ptr + +#define PIXMAP_SAVE(_pPix) \ + PIXMAP_STATUS(_pPix); \ + if (pbits == (pointer)pScreenPriv) \ + (_pPix)->devPrivate.ptr = pScreenPriv->pbits + +#define PIXMAP_RESTORE(_pPix) \ + (_pPix)->devPrivate.ptr = pbits + +#define BANK_SAVE \ + int width = pScreenPriv->pBankPixmap->drawable.width; \ + int devKind = pScreenPriv->pBankPixmap->devKind; \ + PIXMAP_SAVE(pScreenPriv->pBankPixmap) + +#define BANK_RESTORE \ + pScreenPriv->pBankPixmap->drawable.width = width; \ + pScreenPriv->pBankPixmap->devKind = devKind; \ + PIXMAP_RESTORE(pScreenPriv->pBankPixmap) + +#define SCREEN_STATUS \ + PIXMAP_STATUS(pScreenPriv->pScreenPixmap) + +#define SCREEN_SAVE \ + PIXMAP_SAVE(pScreenPriv->pScreenPixmap) + +#define SCREEN_RESTORE \ + PIXMAP_RESTORE(pScreenPriv->pScreenPixmap) + +#define SCREEN_INIT \ + miBankScreenPtr pScreenPriv = BANK_SCRPRIVATE + +#define SCREEN_UNWRAP(field) \ + pScreen->field = pScreenPriv->field + +#define SCREEN_WRAP(field, wrapper) \ + pScreenPriv->field = pScreen->field; \ + pScreen->field = wrapper + +#define GC_INIT(pGC) \ + miBankGCPtr pGCPriv = BANK_GCPRIVATE(pGC) + +#define GC_UNWRAP(pGC) \ + pGCPriv->unwrappedOps = (pGC)->ops; \ + pGCPriv->unwrappedFuncs = (pGC)->funcs; \ + (pGC)->ops = pGCPriv->wrappedOps; \ + (pGC)->funcs = pGCPriv->wrappedFuncs + +#define GC_WRAP(pGC) \ + pGCPriv->wrappedOps = (pGC)->ops; \ + pGCPriv->wrappedFuncs = (pGC)->funcs; \ + (pGC)->ops = pGCPriv->unwrappedOps; \ + (pGC)->funcs = pGCPriv->unwrappedFuncs + +#define IS_BANKED(pDrawable) \ + ((pbits == (pointer)pScreenPriv) && \ + (((DrawablePtr)(pDrawable))->type == DRAWABLE_WINDOW)) + +#define CLIP_SAVE \ + RegionPtr pOrigCompositeClip = pGC->pCompositeClip + +#define CLIP_RESTORE \ + pGC->pCompositeClip = pOrigCompositeClip + +#define GCOP_INIT \ + ScreenPtr pScreen = pGC->pScreen; \ + SCREEN_INIT; \ + GC_INIT(pGC) + +#define GCOP_UNWRAP \ + GC_UNWRAP(pGC) + +#define GCOP_WRAP \ + GC_WRAP(pGC) + +#define GCOP_TOP_PART \ + for (i = 0; i < pScreenPriv->nBanks; i++) \ + { \ + if (!(pGC->pCompositeClip = pGCPriv->pBankedClips[i])) \ + continue; \ + GCOP_UNWRAP; \ + SET_SINGLE_BANK(pScreenPriv->pScreenPixmap, -1, -1, i) + +#define GCOP_BOTTOM_PART \ + GCOP_WRAP; \ + } + +#define GCOP_SIMPLE(statement) \ + if (nArray > 0) \ + { \ + GCOP_INIT; \ + SCREEN_SAVE; \ + if (!IS_BANKED(pDrawable)) \ + { \ + GCOP_UNWRAP; \ + statement; \ + GCOP_WRAP; \ + } \ + else \ + { \ + int i; \ + CLIP_SAVE; \ + GCOP_TOP_PART; \ + statement; \ + GCOP_BOTTOM_PART; \ + CLIP_RESTORE; \ + } \ + SCREEN_RESTORE; \ + } + +#define GCOP_0D_ARGS mode, +#define GCOP_1D_ARGS +#define GCOP_2D_ARGS shape, mode, + +#define GCOP_COMPLEX(aop, atype) \ + if (nArray > 0) \ + { \ + GCOP_INIT; \ + SCREEN_SAVE; \ + if (!IS_BANKED(pDrawable)) \ + { \ + GCOP_UNWRAP; \ + (*pGC->ops->aop)(pDrawable, pGC, GCOP_ARGS nArray, pArray); \ + GCOP_WRAP; \ + } \ + else \ + { \ + atype *aarg = pArray, *acopy; \ + int i; \ + CLIP_SAVE; \ + if ((acopy = ALLOCATE_LOCAL_ARRAY(atype, nArray))) \ + aarg = acopy; \ + GCOP_TOP_PART; \ + if (acopy) \ + memcpy(acopy, pArray, nArray * sizeof(atype)); \ + (*pGC->ops->aop)(pDrawable, pGC, GCOP_ARGS nArray, aarg); \ + GCOP_BOTTOM_PART; \ + DEALLOCATE_LOCAL(acopy); \ + CLIP_RESTORE; \ + } \ + SCREEN_RESTORE; \ + } + +/********************* + * Utility functions * + *********************/ + +static int +miBankOf( + miBankScreenPtr pScreenPriv, + int x, + int y +) +{ + int iBank = ((x * (int)pScreenPriv->nBankBPP) + + (y * (long)pScreenPriv->nBitsPerScanline)) / + (long)pScreenPriv->nBitsPerBank; + + if (iBank < 0) + iBank = 0; + else if (iBank >= pScreenPriv->nBanks) + iBank = pScreenPriv->nBanks - 1; + + return iBank; +} + +#define FirstBankOf(_x, _y) miBankOf(pScreenPriv, (_x), (_y)) +#define LastBankOf(_x, _y) miBankOf(pScreenPriv, (_x) - 1, (_y)) + +/* Determine banking type from the BankInfoRec */ +static unsigned int +miBankDeriveType( + ScreenPtr pScreen, + miBankInfoPtr pBankInfo +) +{ + unsigned int type; + + if (pBankInfo->pBankA == pBankInfo->pBankB) + { + if (pBankInfo->SetSourceBank == pBankInfo->SetDestinationBank) + { + if (pBankInfo->SetSourceAndDestinationBanks != + pBankInfo->SetSourceBank) + return BANK_NOBANK; + + type = BANK_SINGLE; + } + else + { + if (pBankInfo->SetSourceAndDestinationBanks == + pBankInfo->SetDestinationBank) + return BANK_NOBANK; + if (pBankInfo->SetSourceAndDestinationBanks == + pBankInfo->SetSourceBank) + return BANK_NOBANK; + + type = BANK_SHARED; + } + } + else + { + if ((unsigned long)abs((char *)pBankInfo->pBankA - + (char *)pBankInfo->pBankB) < pBankInfo->BankSize) + return BANK_NOBANK; + + if (pBankInfo->SetSourceBank == pBankInfo->SetDestinationBank) + { + if (pBankInfo->SetSourceAndDestinationBanks != + pBankInfo->SetSourceBank) + return BANK_NOBANK; + } + else + { + if (pBankInfo->SetSourceAndDestinationBanks == + pBankInfo->SetDestinationBank) + return BANK_NOBANK; + } + + type = BANK_DOUBLE; + } + + /* + * Internal limitation: Currently, only single banking is supported when + * the pixmap format and the screen's pixel format are different. The + * following test is only partially successful at detecting this condition. + */ + if (pBankInfo->nBankDepth != pScreen->rootDepth) + type = BANK_SINGLE; + + return type; +} + +/* Least common multiple */ +static unsigned int +miLCM( + unsigned int x, + unsigned int y +) +{ + unsigned int m = x, n = y, o; + + while ((o = m % n)) + { + m = n; + n = o; + } + + return (x / n) * y; +} + +/****************** + * GCOps wrappers * + ******************/ + +static void +miBankFillSpans( + DrawablePtr pDrawable, + GCPtr pGC, + int nArray, + DDXPointPtr pptInit, + int *pwidthInit, + int fSorted +) +{ + GCOP_SIMPLE((*pGC->ops->FillSpans)(pDrawable, pGC, + nArray, pptInit, pwidthInit, fSorted)); +} + +static void +miBankSetSpans( + DrawablePtr pDrawable, + GCPtr pGC, + char *psrc, + DDXPointPtr ppt, + int *pwidth, + int nArray, + int fSorted +) +{ + GCOP_SIMPLE((*pGC->ops->SetSpans)(pDrawable, pGC, psrc, + ppt, pwidth, nArray, fSorted)); +} + +static void +miBankPutImage( + DrawablePtr pDrawable, + GCPtr pGC, + int depth, + int x, + int y, + int w, + int h, + int leftPad, + int format, + char *pImage +) +{ + if ((w > 0) && (h > 0)) + { + GCOP_INIT; + SCREEN_SAVE; + + if (!IS_BANKED(pDrawable)) + { + GCOP_UNWRAP; + + (*pGC->ops->PutImage)(pDrawable, pGC, depth, x, y, w, h, + leftPad, format, pImage); + + GCOP_WRAP; + } + else + { + int i, j; + + CLIP_SAVE; + + i = FirstBankOf(x + pDrawable->x, y + pDrawable->y); + j = LastBankOf(x + pDrawable->x + w, y + pDrawable->y + h); + for (; i <= j; i++) + { + if (!(pGC->pCompositeClip = pGCPriv->pBankedClips[i])) + continue; + + GCOP_UNWRAP; + + SET_SINGLE_BANK(pScreenPriv->pScreenPixmap, -1, -1, i); + + (*pGC->ops->PutImage)(pDrawable, pGC, depth, x, y, w, h, + leftPad, format, pImage); + + GCOP_WRAP; + } + + CLIP_RESTORE; + } + + SCREEN_RESTORE; + } +} + +/* + * Here the CopyArea/CopyPlane wrappers. First off, we have to clip against + * the source in order to make the minimal number of copies in case of slow + * systems. Also the exposure handling is quite tricky. Special attention + * is to be given to the way the copies are sequenced. The list of boxes after + * the source clip is used to build a workqueue, that contains the atomic + * copies (i.e. only from one bank to one bank). Doing so produces a minimal + * list of things to do. + */ +static RegionPtr +miBankCopy( + DrawablePtr pSrc, + DrawablePtr pDst, + GCPtr pGC, + int srcx, + int srcy, + int w, + int h, + int dstx, + int dsty, + unsigned long plane, + Bool SinglePlane +) +{ + int cx1, cy1, cx2, cy2; + int ns, nd, nse, nde, dx, dy, xorg = 0, yorg = 0; + int maxWidth = 0, maxHeight = 0, paddedWidth = 0; + int nBox, nBoxClipSrc, nBoxClipDst, nQueue; + BoxPtr pBox, pBoxClipSrc, pBoxClipDst; + BoxRec fastBox, ccBox; + RegionPtr ret = NULL, prgnSrcClip = NULL; + RegionRec rgnDst; + char *pImage = NULL; + miBankQueue *pQueue, *pQueueNew, *Queue; + miBankQueue *pQueueTmp, *pQueueNext, *pQueueBase; + Bool fastBlit, freeSrcClip, fastClip; + Bool fExpose = FALSE, fastExpose = FALSE; + + GCOP_INIT; + SCREEN_SAVE; + + if (!IS_BANKED(pSrc) && !IS_BANKED(pDst)) + { + GCOP_UNWRAP; + + if (SinglePlane) + ret = (*pGC->ops->CopyPlane)(pSrc, pDst, pGC, + srcx, srcy, w, h, dstx, dsty, plane); + else + ret = (*pGC->ops->CopyArea)(pSrc, pDst, pGC, + srcx, srcy, w, h, dstx, dsty); + + GCOP_WRAP; + } + else if (!IS_BANKED(pDst)) + { + fExpose = pGC->fExpose; + pGC->fExpose = FALSE; + + xorg = pSrc->x; + yorg = pSrc->y; + dx = dstx - srcx; + dy = dsty - srcy; + srcx += xorg; + srcy += yorg; + + ns = FirstBankOf(srcx, srcy); + nse = LastBankOf(srcx + w, srcy + h); + for (; ns <= nse; ns++) + { + if (!pScreenPriv->pBanks[ns]) + continue; + + nBox = REGION_NUM_RECTS(pScreenPriv->pBanks[ns]); + pBox = REGION_RECTS(pScreenPriv->pBanks[ns]); + + for (; nBox--; pBox++) + { + cx1 = max(pBox->x1, srcx); + cy1 = max(pBox->y1, srcy); + cx2 = min(pBox->x2, srcx + w); + cy2 = min(pBox->y2, srcy + h); + + if ((cx1 >= cx2) || (cy1 >= cy2)) + continue; + + GCOP_UNWRAP; + + SET_SINGLE_BANK(pScreenPriv->pScreenPixmap, -1, -1, ns); + + if (SinglePlane) + (*pGC->ops->CopyPlane)(pSrc, pDst, pGC, + cx1 - xorg, cy1 - yorg, + cx2 - cx1, cy2 - cy1, + cx1 + dx - xorg, cy1 + dy - yorg, plane); + else + (*pGC->ops->CopyArea)(pSrc, pDst, pGC, + cx1 - xorg, cy1 - yorg, + cx2 - cx1, cy2 - cy1, + cx1 + dx - xorg, cy1 + dy - yorg); + + GCOP_WRAP; + } + } + + pGC->fExpose = fExpose; + srcx -= xorg; + srcy -= yorg; + } + else if (!IS_BANKED(pSrc)) + { + CLIP_SAVE; + + if (pGC->miTranslate) + { + xorg = pDst->x; + yorg = pDst->y; + } + dx = srcx - dstx; + dy = srcy - dsty; + dstx += xorg; + dsty += yorg; + + nd = FirstBankOf(dstx, dsty); + nde = LastBankOf(dstx + w, dsty + h); + for (; nd <= nde; nd++) + { + if (!(pGC->pCompositeClip = pGCPriv->pBankedClips[nd])) + continue; + + /* + * It's faster to let the lower-level CopyArea do the clipping + * within each bank. + */ + nBox = REGION_NUM_RECTS(pScreenPriv->pBanks[nd]); + pBox = REGION_RECTS(pScreenPriv->pBanks[nd]); + + for (; nBox--; pBox++) + { + cx1 = max(pBox->x1, dstx); + cy1 = max(pBox->y1, dsty); + cx2 = min(pBox->x2, dstx + w); + cy2 = min(pBox->y2, dsty + h); + + if ((cx1 >= cx2) || (cy1 >= cy2)) + continue; + + GCOP_UNWRAP; + + SET_SINGLE_BANK(pScreenPriv->pScreenPixmap, -1, -1, nd); + + if (SinglePlane) + (*pGC->ops->CopyPlane)(pSrc, pDst, pGC, + cx1 + dx - xorg, cy1 + dy - yorg, + cx2 - cx1, cy2 - cy1, + cx1 - xorg, cy1 - yorg, plane); + else + (*pGC->ops->CopyArea)(pSrc, pDst, pGC, + cx1 + dx - xorg, cy1 + dy - yorg, + cx2 - cx1, cy2 - cy1, + cx1 - xorg, cy1 - yorg); + + GCOP_WRAP; + } + } + + CLIP_RESTORE; + } + else /* IS_BANKED(pSrc) && IS_BANKED(pDst) */ + { + CLIP_SAVE; + + fExpose = pGC->fExpose; + + fastBox.x1 = srcx + pSrc->x; + fastBox.y1 = srcy + pSrc->y; + fastBox.x2 = fastBox.x1 + w; + fastBox.y2 = fastBox.y1 + h; + + dx = dstx - fastBox.x1; + dy = dsty - fastBox.y1; + if (pGC->miTranslate) + { + xorg = pDst->x; + yorg = pDst->y; + } + + /* + * Clip against the source. Otherwise we will blit too much for SINGLE + * and SHARED banked systems. + */ + freeSrcClip = FALSE; + fastClip = FALSE; + fastExpose = FALSE; + + if (pGC->subWindowMode != IncludeInferiors) + prgnSrcClip = &((WindowPtr)pSrc)->clipList; + else if (!((WindowPtr)pSrc)->parent) + fastClip = TRUE; + else if ((pSrc == pDst) && (pGC->clientClipType == CT_NONE)) + prgnSrcClip = pGC->pCompositeClip; + else + { + prgnSrcClip = NotClippedByChildren((WindowPtr)pSrc); + freeSrcClip = TRUE; + } + + if (fastClip) + { + fastExpose = TRUE; + + /* + * Clip the source. If regions extend beyond the source size, make + * sure exposure events get sent. + */ + if (fastBox.x1 < pSrc->x) + { + fastBox.x1 = pSrc->x; + fastExpose = FALSE; + } + if (fastBox.y1 < pSrc->y) + { + fastBox.y1 = pSrc->y; + fastExpose = FALSE; + } + if (fastBox.x2 > pSrc->x + (int) pSrc->width) + { + fastBox.x2 = pSrc->x + (int) pSrc->width; + fastExpose = FALSE; + } + if (fastBox.y2 > pSrc->y + (int) pSrc->height) + { + fastBox.y2 = pSrc->y + (int) pSrc->height; + fastExpose = FALSE; + } + + nBox = 1; + pBox = &fastBox; + } + else + { + REGION_INIT(pScreen, &rgnDst, &fastBox, 1); + REGION_INTERSECT(pScreen, &rgnDst, &rgnDst, prgnSrcClip); + pBox = REGION_RECTS(&rgnDst); + nBox = REGION_NUM_RECTS(&rgnDst); + } + + /* + * fastBlit can only be TRUE if we don't need to worry about attempts + * to read partial pixels through the destination bank. + */ + if (SinglePlane) + fastBlit = pGCPriv->fastPlane; + else + fastBlit = pGCPriv->fastCopy; + + nQueue = nBox * pScreenPriv->maxRects * 2; + pQueue = Queue = ALLOCATE_LOCAL_ARRAY(miBankQueue, nQueue); + + if (Queue) + { + for (; nBox--; pBox++) + { + ns = FirstBankOf(pBox->x1, pBox->y1); + nse = LastBankOf(pBox->x2, pBox->y2); + for (; ns <= nse; ns++) + { + if (!pScreenPriv->pBanks[ns]) + continue; + + nBoxClipSrc = REGION_NUM_RECTS(pScreenPriv->pBanks[ns]); + pBoxClipSrc = REGION_RECTS(pScreenPriv->pBanks[ns]); + + for (; nBoxClipSrc--; pBoxClipSrc++) + { + cx1 = max(pBox->x1, pBoxClipSrc->x1); + cy1 = max(pBox->y1, pBoxClipSrc->y1); + cx2 = min(pBox->x2, pBoxClipSrc->x2); + cy2 = min(pBox->y2, pBoxClipSrc->y2); + + /* Check to see if the region is empty */ + if ((cx1 >= cx2) || (cy1 >= cy2)) + continue; + + /* Translate c[xy]* to destination coordinates */ + cx1 += dx + xorg; + cy1 += dy + yorg; + cx2 += dx + xorg; + cy2 += dy + yorg; + + nd = FirstBankOf(cx1, cy1); + nde = LastBankOf(cx2, cy2); + for (; nd <= nde; nd++) + { + if (!pGCPriv->pBankedClips[nd]) + continue; + + /* + * Clients can send quite large clip descriptions, + * so use the bank clips here instead. + */ + nBoxClipDst = + REGION_NUM_RECTS(pScreenPriv->pBanks[nd]); + pBoxClipDst = + REGION_RECTS(pScreenPriv->pBanks[nd]); + + for (; nBoxClipDst--; pBoxClipDst++) + { + ccBox.x1 = max(cx1, pBoxClipDst->x1); + ccBox.y1 = max(cy1, pBoxClipDst->y1); + ccBox.x2 = min(cx2, pBoxClipDst->x2); + ccBox.y2 = min(cy2, pBoxClipDst->y2); + + /* Check to see if the region is empty */ + if ((ccBox.x1 >= ccBox.x2) || + (ccBox.y1 >= ccBox.y2)) + continue; + + pQueue->srcBankNo = ns; + pQueue->dstBankNo = nd; + pQueue->x = ccBox.x1 - xorg; + pQueue->y = ccBox.y1 - yorg; + pQueue->w = ccBox.x2 - ccBox.x1; + pQueue->h = ccBox.y2 - ccBox.y1; + + if (maxWidth < pQueue->w) + maxWidth = pQueue->w; + if (maxHeight < pQueue->h) + maxHeight = pQueue->h; + + /* + * When shared banking is used and the source + * and destination banks differ, prevent + * attempts to fetch partial scanline pad units + * through the destination bank. + */ + pQueue->fastBlit = fastBlit; + if (fastBlit && + (pScreenPriv->type == BANK_SHARED) && + (ns != nd) && + ((ccBox.x1 % + pScreenPriv->nPixelsPerScanlinePadUnit) || + (ccBox.x2 % + pScreenPriv->nPixelsPerScanlinePadUnit) || + (RECT_IN_REGION(pScreen, + pGCPriv->pBankedClips[nd], &ccBox) != + rgnIN))) + pQueue->fastBlit = FALSE; + pQueue++; + } + } + } + } + } + } + + if (!fastClip) + { + REGION_UNINIT(pScreen, &rgnDst); + if (freeSrcClip) + REGION_DESTROY(pScreen, prgnSrcClip); + } + + pQueueNew = pQueue; + nQueue = pQueue - Queue; + + if (nQueue > 0) + { + BANK_SAVE; + + pQueue = Queue; + + if ((nQueue > 1) && + ((pSrc == pDst) || (pGC->subWindowMode == IncludeInferiors))) + { + if ((srcy + pSrc->y) < (dsty + yorg)) + { + /* Sort from bottom to top */ + pQueueBase = pQueueNext = pQueue + nQueue - 1; + + while (pQueueBase >= pQueue) + { + while ((pQueueNext >= pQueue) && + (pQueueBase->y == pQueueNext->y)) + pQueueNext--; + + pQueueTmp = pQueueNext + 1; + while (pQueueTmp <= pQueueBase) + *pQueueNew++ = *pQueueTmp++; + + pQueueBase = pQueueNext; + } + + pQueueNew -= nQueue; + pQueue = pQueueNew; + pQueueNew = Queue; + } + + if ((srcx + pSrc->x) < (dstx + xorg)) + { + /* Sort from right to left */ + pQueueBase = pQueueNext = pQueue; + + while (pQueueBase < pQueue + nQueue) + { + while ((pQueueNext < pQueue + nQueue) && + (pQueueNext->y == pQueueBase->y)) + pQueueNext++; + + pQueueTmp = pQueueNext; + while (pQueueTmp != pQueueBase) + *pQueueNew++ = *--pQueueTmp; + + pQueueBase = pQueueNext; + } + + pQueueNew -= nQueue; + pQueue = pQueueNew; + } + } + + paddedWidth = PixmapBytePad(maxWidth, + pScreenPriv->pScreenPixmap->drawable.depth); + pImage = (char *)ALLOCATE_LOCAL(paddedWidth * maxHeight); + + pGC->fExpose = FALSE; + + while (nQueue--) + { + pGC->pCompositeClip = pGCPriv->pBankedClips[pQueue->dstBankNo]; + + GCOP_UNWRAP; + + if (pQueue->srcBankNo == pQueue->dstBankNo) + { + SET_SINGLE_BANK(pScreenPriv->pScreenPixmap, + -1, -1, pQueue->srcBankNo); + + if (SinglePlane) + (*pGC->ops->CopyPlane)(pSrc, pDst, pGC, + pQueue->x - dx - pSrc->x, pQueue->y - dy - pSrc->y, + pQueue->w, pQueue->h, pQueue->x, pQueue->y, plane); + else + (*pGC->ops->CopyArea)(pSrc, pDst, pGC, + pQueue->x - dx - pSrc->x, pQueue->y - dy - pSrc->y, + pQueue->w, pQueue->h, pQueue->x, pQueue->y); + } + else if (pQueue->fastBlit) + { + SET_SOURCE_BANK (pScreenPriv->pBankPixmap, + pScreenPriv->pScreenPixmap->drawable.width, + pScreenPriv->pScreenPixmap->devKind, + pQueue->srcBankNo); + SET_DESTINATION_BANK(pScreenPriv->pScreenPixmap, + -1, -1, pQueue->dstBankNo); + + if (SinglePlane) + (*pGC->ops->CopyPlane)( + (DrawablePtr)pScreenPriv->pBankPixmap, pDst, pGC, + pQueue->x - dx, pQueue->y - dy, + pQueue->w, pQueue->h, pQueue->x, pQueue->y, plane); + else + (*pGC->ops->CopyArea)( + (DrawablePtr)pScreenPriv->pBankPixmap, pDst, pGC, + pQueue->x - dx, pQueue->y - dy, + pQueue->w, pQueue->h, pQueue->x, pQueue->y); + } + else if (pImage) + { + ModifyPixmap(pScreenPriv->pBankPixmap, + maxWidth, paddedWidth, pImage); + + SET_SINGLE_BANK(pScreenPriv->pScreenPixmap, + -1, -1, pQueue->srcBankNo); + + (*pScreenPriv->pBankGC->ops->CopyArea)( + pSrc, (DrawablePtr)pScreenPriv->pBankPixmap, + pScreenPriv->pBankGC, + pQueue->x - dx - pSrc->x, pQueue->y - dy - pSrc->y, + pQueue->w, pQueue->h, 0, 0); + + SET_SINGLE_BANK(pScreenPriv->pScreenPixmap, + -1, -1, pQueue->dstBankNo); + + if (SinglePlane) + (*pGC->ops->CopyPlane)( + (DrawablePtr)pScreenPriv->pBankPixmap, + pDst, pGC, 0, 0, pQueue->w, pQueue->h, + pQueue->x, pQueue->y, plane); + else + (*pGC->ops->CopyArea)( + (DrawablePtr)pScreenPriv->pBankPixmap, + pDst, pGC, 0, 0, pQueue->w, pQueue->h, + pQueue->x, pQueue->y); + } + + GCOP_WRAP; + + pQueue++; + } + + DEALLOCATE_LOCAL(pImage); + + BANK_RESTORE; + } + + CLIP_RESTORE; + + pGC->fExpose = fExpose; + + DEALLOCATE_LOCAL(Queue); + } + + SCREEN_RESTORE; + + if (!fExpose || fastExpose) + return ret; + + return miHandleExposures(pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty, 0); +} + +static RegionPtr +miBankCopyArea( + DrawablePtr pSrc, + DrawablePtr pDst, + GCPtr pGC, + int srcx, + int srcy, + int w, + int h, + int dstx, + int dsty +) +{ + return miBankCopy(pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty, 0, FALSE); +} + +static RegionPtr +miBankCopyPlane( + DrawablePtr pSrc, + DrawablePtr pDst, + GCPtr pGC, + int srcx, + int srcy, + int w, + int h, + int dstx, + int dsty, + unsigned long plane +) +{ + return + miBankCopy(pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty, plane, TRUE); +} + +static void +miBankPolyPoint( + DrawablePtr pDrawable, + GCPtr pGC, + int mode, + int nArray, + xPoint *pArray +) +{ +# define GCOP_ARGS GCOP_0D_ARGS + GCOP_COMPLEX(PolyPoint, xPoint); +# undef GCOP_ARGS +} + +static void +miBankPolylines( + DrawablePtr pDrawable, + GCPtr pGC, + int mode, + int nArray, + DDXPointPtr pArray +) +{ +# define GCOP_ARGS GCOP_0D_ARGS + GCOP_COMPLEX(Polylines, DDXPointRec); +# undef GCOP_ARGS +} + +static void +miBankPolySegment( + DrawablePtr pDrawable, + GCPtr pGC, + int nArray, + xSegment *pArray +) +{ +# define GCOP_ARGS GCOP_1D_ARGS + GCOP_COMPLEX(PolySegment, xSegment); +# undef GCOP_ARGS +} + +static void +miBankPolyRectangle( + DrawablePtr pDrawable, + GCPtr pGC, + int nArray, + xRectangle *pArray +) +{ +# define GCOP_ARGS GCOP_1D_ARGS + GCOP_COMPLEX(PolyRectangle, xRectangle); +# undef GCOP_ARGS +} + +static void +miBankPolyArc( + DrawablePtr pDrawable, + GCPtr pGC, + int nArray, + xArc *pArray +) +{ +# define GCOP_ARGS GCOP_1D_ARGS + GCOP_COMPLEX(PolyArc, xArc); +# undef GCOP_ARGS +} + +static void +miBankFillPolygon( + DrawablePtr pDrawable, + GCPtr pGC, + int shape, + int mode, + int nArray, + DDXPointRec *pArray +) +{ +# define GCOP_ARGS GCOP_2D_ARGS + GCOP_COMPLEX(FillPolygon, DDXPointRec); +# undef GCOP_ARGS +} + +static void +miBankPolyFillRect( + DrawablePtr pDrawable, + GCPtr pGC, + int nArray, + xRectangle *pArray +) +{ +# define GCOP_ARGS GCOP_1D_ARGS + GCOP_COMPLEX(PolyFillRect, xRectangle); +# undef GCOP_ARGS +} + +static void +miBankPolyFillArc( + DrawablePtr pDrawable, + GCPtr pGC, + int nArray, + xArc *pArray +) +{ +# define GCOP_ARGS GCOP_1D_ARGS + GCOP_COMPLEX(PolyFillArc, xArc); +# undef GCOP_ARGS +} + +static int +miBankPolyText8( + DrawablePtr pDrawable, + GCPtr pGC, + int x, + int y, + int nArray, + char *pchar +) +{ + int retval = x; + + GCOP_SIMPLE(retval = + (*pGC->ops->PolyText8)(pDrawable, pGC, x, y, nArray, pchar)); + + return retval; +} + +static int +miBankPolyText16( + DrawablePtr pDrawable, + GCPtr pGC, + int x, + int y, + int nArray, + unsigned short *pchar +) +{ + int retval = x; + + GCOP_SIMPLE(retval = + (*pGC->ops->PolyText16)(pDrawable, pGC, x, y, nArray, pchar)); + + return retval; +} + +static void +miBankImageText8( + DrawablePtr pDrawable, + GCPtr pGC, + int x, + int y, + int nArray, + char *pchar +) +{ + GCOP_SIMPLE((*pGC->ops->ImageText8)(pDrawable, pGC, x, y, nArray, pchar)); +} + +static void +miBankImageText16( + DrawablePtr pDrawable, + GCPtr pGC, + int x, + int y, + int nArray, + unsigned short *pchar +) +{ + GCOP_SIMPLE((*pGC->ops->ImageText16)(pDrawable, pGC, x, y, nArray, pchar)); +} + +static void +miBankImageGlyphBlt( + DrawablePtr pDrawable, + GCPtr pGC, + int x, + int y, + unsigned int nArray, + CharInfoPtr *ppci, + pointer pglyphBase +) +{ + GCOP_SIMPLE((*pGC->ops->ImageGlyphBlt)(pDrawable, pGC, + x, y, nArray, ppci, pglyphBase)); +} + +static void +miBankPolyGlyphBlt( + DrawablePtr pDrawable, + GCPtr pGC, + int x, + int y, + unsigned int nArray, + CharInfoPtr *ppci, + pointer pglyphBase +) +{ + GCOP_SIMPLE((*pGC->ops->PolyGlyphBlt)(pDrawable, pGC, + x, y, nArray, ppci, pglyphBase)); +} + +static void +miBankPushPixels( + GCPtr pGC, + PixmapPtr pBitmap, + DrawablePtr pDrawable, + int w, + int h, + int x, + int y +) +{ + if ((w > 0) && (h > 0)) + { + GCOP_INIT; + SCREEN_SAVE; + + if (!IS_BANKED(pDrawable)) + { + GCOP_UNWRAP; + + (*pGC->ops->PushPixels)(pGC, pBitmap, pDrawable, w, h, x, y); + + GCOP_WRAP; + } + else + { + int i, j; + + CLIP_SAVE; + + i = FirstBankOf(x, y); + j = LastBankOf(x + w, y + h); + for (; i <= j; i++) + { + if (!(pGC->pCompositeClip = pGCPriv->pBankedClips[i])) + continue; + + GCOP_UNWRAP; + + SET_SINGLE_BANK(pScreenPriv->pScreenPixmap, -1, -1, i); + + (*pGC->ops->PushPixels)(pGC, pBitmap, pDrawable, w, h, x, y); + + GCOP_WRAP; + } + + CLIP_RESTORE; + } + + SCREEN_RESTORE; + } +} + +static GCOps miBankGCOps = +{ + miBankFillSpans, + miBankSetSpans, + miBankPutImage, + miBankCopyArea, + miBankCopyPlane, + miBankPolyPoint, + miBankPolylines, + miBankPolySegment, + miBankPolyRectangle, + miBankPolyArc, + miBankFillPolygon, + miBankPolyFillRect, + miBankPolyFillArc, + miBankPolyText8, + miBankPolyText16, + miBankImageText8, + miBankImageText16, + miBankImageGlyphBlt, + miBankPolyGlyphBlt, + miBankPushPixels, +#ifdef NEED_LINEHELPER + NULL, /* LineHelper */ +#endif + {NULL} /* devPrivate */ +}; + +/******************** + * GCFuncs wrappers * + ********************/ + +static void +miBankValidateGC( + GCPtr pGC, + unsigned long changes, + DrawablePtr pDrawable +) +{ + GC_INIT(pGC); + GC_UNWRAP(pGC); + + (*pGC->funcs->ValidateGC)(pGC, changes, pDrawable); + + if ((changes & (GCClipXOrigin|GCClipYOrigin|GCClipMask|GCSubwindowMode)) || + (pDrawable->serialNumber != (pGC->serialNumber & DRAWABLE_SERIAL_BITS))) + { + ScreenPtr pScreen = pGC->pScreen; + RegionPtr prgnClip; + unsigned long planemask; + int i; + + SCREEN_INIT; + SCREEN_SAVE; + + if (IS_BANKED(pDrawable)) + { + for (i = 0; i < pScreenPriv->nBanks; i++) + { + if (!pScreenPriv->pBanks[i]) + continue; + + if (!(prgnClip = pGCPriv->pBankedClips[i])) + prgnClip = REGION_CREATE(pScreen, NULL, 1); + + REGION_INTERSECT(pScreen, prgnClip, + pScreenPriv->pBanks[i], pGC->pCompositeClip); + + if ((REGION_NUM_RECTS(prgnClip) <= 1) && + ((prgnClip->extents.x1 == prgnClip->extents.x2) || + (prgnClip->extents.y1 == prgnClip->extents.y2))) + { + REGION_DESTROY(pScreen, prgnClip); + pGCPriv->pBankedClips[i] = NULL; + } + else + pGCPriv->pBankedClips[i] = prgnClip; + } + + /* + * fastCopy and fastPlane can only be TRUE if we don't need to + * worry about attempts to read partial pixels through the + * destination bank. + */ + switch (pScreenPriv->type) + { + case BANK_SHARED: + pGCPriv->fastCopy = pGCPriv->fastPlane = FALSE; + + if ((pGC->alu != GXclear) && (pGC->alu != GXcopy) && + (pGC->alu != GXcopyInverted) && (pGC->alu != GXset)) + break; + + if (pScreen->rootDepth == 1) + pGCPriv->fastPlane = TRUE; + + /* This is probably paranoia */ + if ((pDrawable->depth != pScreen->rootDepth) || + (pDrawable->depth != pGC->depth)) + break; + + planemask = (1 << pGC->depth) - 1; + if ((pGC->planemask & planemask) == planemask) + pGCPriv->fastCopy = TRUE; + + break; + + case BANK_DOUBLE: + pGCPriv->fastCopy = pGCPriv->fastPlane = TRUE; + break; + + default: + pGCPriv->fastCopy = pGCPriv->fastPlane = FALSE; + break; + } + } + else + { + /* + * Here we are on a pixmap and don't need all that special clipping + * stuff, hence free it. + */ + for (i = 0; i < pScreenPriv->nBanks; i++) + { + if (!pGCPriv->pBankedClips[i]) + continue; + + REGION_DESTROY(pScreen, pGCPriv->pBankedClips[i]); + pGCPriv->pBankedClips[i] = NULL; + } + } + + SCREEN_RESTORE; + } + + GC_WRAP(pGC); +} + +static void +miBankChangeGC( + GCPtr pGC, + unsigned long mask +) +{ + GC_INIT(pGC); + GC_UNWRAP(pGC); + + (*pGC->funcs->ChangeGC)(pGC, mask); + + GC_WRAP(pGC); +} + +static void +miBankCopyGC( + GCPtr pGCSrc, + unsigned long mask, + GCPtr pGCDst +) +{ + GC_INIT(pGCDst); + GC_UNWRAP(pGCDst); + + (*pGCDst->funcs->CopyGC)(pGCSrc, mask, pGCDst); + + GC_WRAP(pGCDst); +} + +static void +miBankDestroyGC( + GCPtr pGC +) +{ + ScreenPtr pScreen = pGC->pScreen; + int i; + + SCREEN_INIT; + GC_INIT(pGC); + GC_UNWRAP(pGC); + + (*pGC->funcs->DestroyGC)(pGC); + + for (i = 0; i < pScreenPriv->nBanks; i++) + { + if (!pGCPriv->pBankedClips[i]) + continue; + + REGION_DESTROY(pScreen, pGCPriv->pBankedClips[i]); + pGCPriv->pBankedClips[i] = NULL; + } + + GC_WRAP(pGC); +} + +static void +miBankChangeClip( + GCPtr pGC, + int type, + pointer pvalue, + int nrects +) +{ + GC_INIT(pGC); + GC_UNWRAP(pGC); + + (*pGC->funcs->ChangeClip)(pGC, type, pvalue, nrects); + + GC_WRAP(pGC); +} + +static void +miBankDestroyClip( + GCPtr pGC +) +{ + GC_INIT(pGC); + GC_UNWRAP(pGC); + + (*pGC->funcs->DestroyClip)(pGC); + + GC_WRAP(pGC); +} + +static void +miBankCopyClip( + GCPtr pGCDst, + GCPtr pGCSrc +) +{ + GC_INIT(pGCDst); + GC_UNWRAP(pGCDst); + + (*pGCDst->funcs->CopyClip)(pGCDst, pGCSrc); + + GC_WRAP(pGCDst); +} + +static GCFuncs miBankGCFuncs = +{ + miBankValidateGC, + miBankChangeGC, + miBankCopyGC, + miBankDestroyGC, + miBankChangeClip, + miBankDestroyClip, + miBankCopyClip +}; + +/******************* + * Screen Wrappers * + *******************/ + +static Bool +miBankCreateScreenResources( + ScreenPtr pScreen +) +{ + Bool retval; + + SCREEN_INIT; + SCREEN_UNWRAP(CreateScreenResources); + + if ((retval = (*pScreen->CreateScreenResources)(pScreen))) + { + /* Set screen buffer address to something recognizable */ + pScreenPriv->pScreenPixmap = (*pScreen->GetScreenPixmap)(pScreen); + pScreenPriv->pbits = pScreenPriv->pScreenPixmap->devPrivate.ptr; + pScreenPriv->pScreenPixmap->devPrivate.ptr = (pointer)pScreenPriv; + + /* Get shadow pixmap; width & height of 0 means no pixmap data */ + pScreenPriv->pBankPixmap = (*pScreen->CreatePixmap)(pScreen, 0, 0, + pScreenPriv->pScreenPixmap->drawable.depth); + if (!pScreenPriv->pBankPixmap) + retval = FALSE; + } + + /* Shadow the screen */ + if (retval) + retval = (*pScreen->ModifyPixmapHeader)(pScreenPriv->pBankPixmap, + pScreenPriv->pScreenPixmap->drawable.width, + pScreenPriv->pScreenPixmap->drawable.height, + pScreenPriv->pScreenPixmap->drawable.depth, + pScreenPriv->pScreenPixmap->drawable.bitsPerPixel, + pScreenPriv->pScreenPixmap->devKind, NULL); + + /* Create shadow GC */ + if (retval) + { + pScreenPriv->pBankGC = CreateScratchGC(pScreen, + pScreenPriv->pBankPixmap->drawable.depth); + if (!pScreenPriv->pBankGC) + retval = FALSE; + } + + /* Validate shadow GC */ + if (retval) + { + pScreenPriv->pBankGC->graphicsExposures = FALSE; + pScreenPriv->pBankGC->subWindowMode = IncludeInferiors; + ValidateGC((DrawablePtr)pScreenPriv->pBankPixmap, + pScreenPriv->pBankGC); + } + + SCREEN_WRAP(CreateScreenResources, miBankCreateScreenResources); + + return retval; +} + +static Bool +miBankModifyPixmapHeader( + PixmapPtr pPixmap, + int width, + int height, + int depth, + int bitsPerPixel, + int devKind, + pointer pPixData +) +{ + Bool retval = FALSE; + + if (pPixmap) + { + ScreenPtr pScreen = pPixmap->drawable.pScreen; + + SCREEN_INIT; + PIXMAP_SAVE(pPixmap); + SCREEN_UNWRAP(ModifyPixmapHeader); + + retval = (*pScreen->ModifyPixmapHeader)(pPixmap, width, height, + depth, bitsPerPixel, devKind, pPixData); + + SCREEN_WRAP(ModifyPixmapHeader, miBankModifyPixmapHeader); + + if (pbits == (pointer)pScreenPriv) + { + pScreenPriv->pbits = pPixmap->devPrivate.ptr; + pPixmap->devPrivate.ptr = pbits; + } + } + + return retval; +} + +static Bool +miBankCloseScreen( + int nIndex, + ScreenPtr pScreen +) +{ + int i; + + SCREEN_INIT; + + /* Free shadow GC */ + FreeScratchGC(pScreenPriv->pBankGC); + + /* Free shadow pixmap */ + (*pScreen->DestroyPixmap)(pScreenPriv->pBankPixmap); + + /* Restore screen pixmap devPrivate pointer */ + pScreenPriv->pScreenPixmap->devPrivate.ptr = pScreenPriv->pbits; + + /* Delete bank clips */ + for (i = 0; i < pScreenPriv->nBanks; i++) + if (pScreenPriv->pBanks[i]) + REGION_DESTROY(pScreen, pScreenPriv->pBanks[i]); + + Xfree(pScreenPriv->pBanks); + + SCREEN_UNWRAP(CreateScreenResources); + SCREEN_UNWRAP(ModifyPixmapHeader); + SCREEN_UNWRAP(CloseScreen); + SCREEN_UNWRAP(GetImage); + SCREEN_UNWRAP(GetSpans); + SCREEN_UNWRAP(CreateGC); + SCREEN_UNWRAP(PaintWindowBackground); + SCREEN_UNWRAP(PaintWindowBorder); + SCREEN_UNWRAP(CopyWindow); + SCREEN_UNWRAP(BackingStoreFuncs); + + Xfree(pScreenPriv); + return (*pScreen->CloseScreen)(nIndex, pScreen); +} + +static void +miBankGetImage( + DrawablePtr pDrawable, + int sx, + int sy, + int w, + int h, + unsigned int format, + unsigned long planemask, + char *pImage +) +{ + if ((w > 0) && (h > 0)) + { + ScreenPtr pScreen = pDrawable->pScreen; + + SCREEN_INIT; + SCREEN_STATUS; + SCREEN_UNWRAP(GetImage); + + if (!IS_BANKED(pDrawable)) + { + (*pScreen->GetImage)(pDrawable, sx, sy, w, h, + format, planemask, pImage); + } + else + { + int paddedWidth; + char *pBankImage; + + paddedWidth = PixmapBytePad(w, + pScreenPriv->pScreenPixmap->drawable.depth); + pBankImage = (char *)ALLOCATE_LOCAL(paddedWidth * h); + + if (pBankImage) + { + BANK_SAVE; + + ModifyPixmap(pScreenPriv->pBankPixmap, w, paddedWidth, + pBankImage); + + (*pScreenPriv->pBankGC->ops->CopyArea)( + (DrawablePtr)WindowTable[pScreen->myNum], + (DrawablePtr)pScreenPriv->pBankPixmap, + pScreenPriv->pBankGC, + sx + pDrawable->x, sy + pDrawable->y, w, h, 0, 0); + + (*pScreen->GetImage)((DrawablePtr)pScreenPriv->pBankPixmap, + 0, 0, w, h, format, planemask, pImage); + + BANK_RESTORE; + + DEALLOCATE_LOCAL(pBankImage); + } + } + + SCREEN_WRAP(GetImage, miBankGetImage); + } +} + +static void +miBankGetSpans( + DrawablePtr pDrawable, + int wMax, + DDXPointPtr ppt, + int *pwidth, + int nspans, + char *pImage +) +{ + if (nspans > 0) + { + ScreenPtr pScreen = pDrawable->pScreen; + + SCREEN_INIT; + SCREEN_STATUS; + SCREEN_UNWRAP(GetSpans); + + if (!IS_BANKED(pDrawable)) + { + (*pScreen->GetSpans)(pDrawable, wMax, ppt, pwidth, nspans, pImage); + } + else + { + char *pBankImage; + int paddedWidth; + DDXPointRec pt; + + pt.x = pt.y = 0; + + paddedWidth = + PixmapBytePad(pScreenPriv->pScreenPixmap->drawable.width, + pScreenPriv->pScreenPixmap->drawable.depth); + pBankImage = (char *)ALLOCATE_LOCAL(paddedWidth); + + if (pBankImage) + { + BANK_SAVE; + + ModifyPixmap(pScreenPriv->pBankPixmap, + pScreenPriv->pScreenPixmap->drawable.width, + paddedWidth, pBankImage); + + for (; nspans--; ppt++, pwidth++) + { + if (*pwidth <= 0) + continue; + + (*pScreenPriv->pBankGC->ops->CopyArea)( + (DrawablePtr)WindowTable[pScreen->myNum], + (DrawablePtr)pScreenPriv->pBankPixmap, + pScreenPriv->pBankGC, + ppt->x, ppt->y, *pwidth, 1, 0, 0); + + (*pScreen->GetSpans)((DrawablePtr)pScreenPriv->pBankPixmap, + wMax, &pt, pwidth, 1, pImage); + + pImage = pImage + PixmapBytePad(*pwidth, pDrawable->depth); + } + + BANK_RESTORE; + + DEALLOCATE_LOCAL(pBankImage); + } + } + + SCREEN_WRAP(GetSpans, miBankGetSpans); + } +} + +static Bool +miBankCreateGC( + GCPtr pGC +) +{ + ScreenPtr pScreen = pGC->pScreen; + miBankGCPtr pGCPriv = BANK_GCPRIVATE(pGC); + Bool ret; + + SCREEN_INIT; + SCREEN_UNWRAP(CreateGC); + + if ((ret = (*pScreen->CreateGC)(pGC))) + { + pGCPriv->unwrappedOps = &miBankGCOps; + pGCPriv->unwrappedFuncs = &miBankGCFuncs; + GC_WRAP(pGC); + + memset(&pGCPriv->pBankedClips, 0, + pScreenPriv->nBanks * sizeof(pGCPriv->pBankedClips)); + } + + SCREEN_WRAP(CreateGC, miBankCreateGC); + + return ret; +} + +static void +miBankPaintWindow( + WindowPtr pWin, + RegionPtr pRegion, + int what +) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + RegionRec tmpReg; + int i; + PaintWindowProcPtr PaintWindow; + + SCREEN_INIT; + SCREEN_SAVE; + + if (what == PW_BORDER) + { + SCREEN_UNWRAP(PaintWindowBorder); + PaintWindow = pScreen->PaintWindowBorder; + } + else + { + SCREEN_UNWRAP(PaintWindowBackground); + PaintWindow = pScreen->PaintWindowBackground; + } + + if (!IS_BANKED(pWin)) + { + (*PaintWindow)(pWin, pRegion, what); + } + else + { + REGION_INIT(pScreen, &tmpReg, NullBox, 0); + + for (i = 0; i < pScreenPriv->nBanks; i++) + { + if (!pScreenPriv->pBanks[i]) + continue; + + REGION_INTERSECT(pScreen, &tmpReg, pRegion, + pScreenPriv->pBanks[i]); + + if (REGION_NIL(&tmpReg)) + continue; + + SET_SINGLE_BANK(pScreenPriv->pScreenPixmap, -1, -1, i); + + (*PaintWindow)(pWin, &tmpReg, what); + } + + REGION_UNINIT(pScreen, &tmpReg); + } + + if (what == PW_BORDER) + { + SCREEN_WRAP(PaintWindowBorder, miBankPaintWindow); + } + else + { + SCREEN_WRAP(PaintWindowBackground, miBankPaintWindow); + } + + SCREEN_RESTORE; +} + +static void +miBankCopyWindow( + WindowPtr pWindow, + DDXPointRec ptOldOrg, + RegionPtr pRgnSrc +) +{ + ScreenPtr pScreen = pWindow->drawable.pScreen; + GCPtr pGC; + int dx, dy, nBox; + DrawablePtr pDrawable = (DrawablePtr)WindowTable[pScreen->myNum]; + RegionPtr pRgnDst; + BoxPtr pBox, pBoxTmp, pBoxNext, pBoxBase, pBoxNew1, pBoxNew2; + XID subWindowMode = IncludeInferiors; + + pGC = GetScratchGC(pDrawable->depth, pScreen); + + ChangeGC(pGC, GCSubwindowMode, &subWindowMode); + ValidateGC(pDrawable, pGC); + + pRgnDst = REGION_CREATE(pScreen, NULL, 1); + + dx = ptOldOrg.x - pWindow->drawable.x; + dy = ptOldOrg.y - pWindow->drawable.y; + REGION_TRANSLATE(pScreen, pRgnSrc, -dx, -dy); + REGION_INTERSECT(pScreen, pRgnDst, &pWindow->borderClip, pRgnSrc); + + pBox = REGION_RECTS(pRgnDst); + nBox = REGION_NUM_RECTS(pRgnDst); + + pBoxNew1 = NULL; + pBoxNew2 = NULL; + + if (nBox > 1) + { + if (dy < 0) + { + /* Sort boxes from bottom to top */ + pBoxNew1 = ALLOCATE_LOCAL_ARRAY(BoxRec, nBox); + + if (pBoxNew1) + { + pBoxBase = pBoxNext = pBox + nBox - 1; + + while (pBoxBase >= pBox) + { + while ((pBoxNext >= pBox) && + (pBoxBase->y1 == pBoxNext->y1)) + pBoxNext--; + + pBoxTmp = pBoxNext + 1; + + while (pBoxTmp <= pBoxBase) + *pBoxNew1++ = *pBoxTmp++; + + pBoxBase = pBoxNext; + } + + pBoxNew1 -= nBox; + pBox = pBoxNew1; + } + } + + if (dx < 0) + { + /* Sort boxes from right to left */ + pBoxNew2 = ALLOCATE_LOCAL_ARRAY(BoxRec, nBox); + + if (pBoxNew2) + { + pBoxBase = pBoxNext = pBox; + + while (pBoxBase < pBox + nBox) + { + while ((pBoxNext < pBox + nBox) && + (pBoxNext->y1 == pBoxBase->y1)) + pBoxNext++; + + pBoxTmp = pBoxNext; + + while (pBoxTmp != pBoxBase) + *pBoxNew2++ = *--pBoxTmp; + + pBoxBase = pBoxNext; + } + + pBoxNew2 -= nBox; + pBox = pBoxNew2; + } + } + } + + while (nBox--) + { + (*pGC->ops->CopyArea)(pDrawable, pDrawable, pGC, + pBox->x1 + dx, pBox->y1 + dy, + pBox->x2 - pBox->x1, pBox->y2 - pBox->y1, + pBox->x1, pBox->y1); + + pBox++; + } + + FreeScratchGC(pGC); + + REGION_DESTROY(pScreen, pRgnDst); + + DEALLOCATE_LOCAL(pBoxNew2); + DEALLOCATE_LOCAL(pBoxNew1); +} + +/************************** + * Backing store wrappers * + **************************/ + +static void +miBankSaveAreas( + PixmapPtr pPixmap, + RegionPtr prgnSave, + int xorg, + int yorg, + WindowPtr pWin +) +{ + ScreenPtr pScreen = pPixmap->drawable.pScreen; + RegionRec rgnClipped; + int i; + + SCREEN_INIT; + SCREEN_SAVE; + SCREEN_UNWRAP(BackingStoreFuncs.SaveAreas); + + if (!IS_BANKED(pWin)) + { + (*pScreen->BackingStoreFuncs.SaveAreas)(pPixmap, prgnSave, xorg, yorg, + pWin); + } + else + { + REGION_INIT(pScreen, &rgnClipped, NullBox, 0); + REGION_TRANSLATE(pScreen, prgnSave, xorg, yorg); + + for (i = 0; i < pScreenPriv->nBanks; i++) + { + if (!pScreenPriv->pBanks[i]) + continue; + + REGION_INTERSECT(pScreen, &rgnClipped, + prgnSave, pScreenPriv->pBanks[i]); + + if (REGION_NIL(&rgnClipped)) + continue; + + SET_SINGLE_BANK(pScreenPriv->pScreenPixmap, -1, -1, i); + + REGION_TRANSLATE(pScreen, &rgnClipped, -xorg, -yorg); + + (*pScreen->BackingStoreFuncs.SaveAreas)(pPixmap, &rgnClipped, + xorg, yorg, pWin); + } + + REGION_TRANSLATE(pScreen, prgnSave, -xorg, -yorg); + REGION_UNINIT(pScreen, &rgnClipped); + } + + SCREEN_WRAP(BackingStoreFuncs.SaveAreas, miBankSaveAreas); + SCREEN_RESTORE; +} + +static void +miBankRestoreAreas( + PixmapPtr pPixmap, + RegionPtr prgnRestore, + int xorg, + int yorg, + WindowPtr pWin +) +{ + ScreenPtr pScreen = pPixmap->drawable.pScreen; + RegionRec rgnClipped; + int i; + + SCREEN_INIT; + SCREEN_SAVE; + SCREEN_UNWRAP(BackingStoreFuncs.RestoreAreas); + + if (!IS_BANKED(pWin)) + { + (*pScreen->BackingStoreFuncs.RestoreAreas)(pPixmap, prgnRestore, + xorg, yorg, pWin); + } + else + { + REGION_INIT(pScreen, &rgnClipped, NullBox, 0); + + for (i = 0; i < pScreenPriv->nBanks; i++) + { + if (!pScreenPriv->pBanks[i]) + continue; + + REGION_INTERSECT(pScreen, &rgnClipped, + prgnRestore, pScreenPriv->pBanks[i]); + + if (REGION_NIL(&rgnClipped)) + continue; + + SET_SINGLE_BANK(pScreenPriv->pScreenPixmap, -1, -1, i); + + (*pScreen->BackingStoreFuncs.RestoreAreas)(pPixmap, &rgnClipped, + xorg, yorg, pWin); + } + + REGION_UNINIT(pScreen, &rgnClipped); + } + + SCREEN_WRAP(BackingStoreFuncs.RestoreAreas, miBankRestoreAreas); + SCREEN_RESTORE; +} + +Bool +miInitializeBanking( + ScreenPtr pScreen, + unsigned int xsize, + unsigned int ysize, + unsigned int width, + miBankInfoPtr pBankInfo +) +{ + miBankScreenPtr pScreenPriv; + unsigned long nBitsPerBank, nBitsPerScanline, nPixelsPerScanlinePadUnit; + unsigned long BankBase, ServerPad; + unsigned int type, iBank, nBanks, maxRects, we, nBankBPP; + int i; + + if (!pBankInfo || !pBankInfo->BankSize) + return TRUE; /* No banking required */ + + /* Sanity checks */ + + if (!pScreen || !xsize || !ysize || (xsize > width) || + !pBankInfo->SetSourceBank || !pBankInfo->SetDestinationBank || + !pBankInfo->SetSourceAndDestinationBanks || + !pBankInfo->pBankA || !pBankInfo->pBankB || + !pBankInfo->nBankDepth) + return FALSE; + + /* + * DDX *must* have registered a pixmap format whose depth is + * pBankInfo->nBankDepth. This is not necessarily the rootDepth + * pixmap format. + */ + i = 0; + while (screenInfo.formats[i].depth != pBankInfo->nBankDepth) + if (++i >= screenInfo.numPixmapFormats) + return FALSE; + nBankBPP = screenInfo.formats[i].bitsPerPixel; + + i = 0; + while (screenInfo.formats[i].depth != pScreen->rootDepth) + if (++i >= screenInfo.numPixmapFormats) + return FALSE; + + if (nBankBPP > screenInfo.formats[i].bitsPerPixel) + return FALSE; + + /* Determine banking type */ + if ((type = miBankDeriveType(pScreen, pBankInfo)) == BANK_NOBANK) + return FALSE; + + /* Internal data */ + + nBitsPerBank = pBankInfo->BankSize * 8; + ServerPad = PixmapBytePad(1, pBankInfo->nBankDepth) * 8; + if (nBitsPerBank % ServerPad) + return FALSE; + nBitsPerScanline = PixmapBytePad(width, pBankInfo->nBankDepth) * 8; + nBanks = ((nBitsPerScanline * (ysize - 1)) + + (nBankBPP * xsize) + nBitsPerBank - 1) / nBitsPerBank; + nPixelsPerScanlinePadUnit = miLCM(ServerPad, nBankBPP) / nBankBPP; + + /* Private areas */ + + if (miBankGeneration != serverGeneration) + { + if (((miBankScreenIndex = AllocateScreenPrivateIndex()) < 0) || + ((miBankGCIndex = AllocateGCPrivateIndex()) < 0)) + return FALSE; + + miBankGeneration = serverGeneration; + } + + if (!AllocateGCPrivate(pScreen, miBankGCIndex, + (nBanks * sizeof(RegionPtr)) + + (sizeof(miBankGCRec) - sizeof(RegionPtr)))) + return FALSE; + + if (!(pScreenPriv = (miBankScreenPtr)Xcalloc(sizeof(miBankScreenRec)))) + return FALSE; + + if (!(pScreenPriv->pBanks = /* Allocate and clear */ + (RegionPtr *)Xcalloc(nBanks * sizeof(RegionPtr)))) + { + Xfree(pScreenPriv); + return FALSE; + } + + /* + * Translate banks into clipping regions which are themselves clipped + * against the screen. This also ensures that pixels with imbedded bank + * boundaries are off-screen. + */ + + BankBase = 0; + maxRects = 0; + we = 0; + for (iBank = 0; iBank < nBanks; iBank++) + { + xRectangle pRects[3], *pRect = pRects; + unsigned int xb, yb, xe, ye; + + xb = ((BankBase + nBankBPP - 1) % nBitsPerScanline) / nBankBPP; + yb = (BankBase + nBankBPP - 1) / nBitsPerScanline; + if (xb >= xsize) + { + xb = we = 0; + yb++; + } + if (yb >= ysize) + { + we = 0; + break; + } + + if (we) + break; + + BankBase += nBitsPerBank; + + we = (BankBase % nBitsPerScanline) % nBankBPP; + xe = (BankBase % nBitsPerScanline) / nBankBPP; + ye = BankBase / nBitsPerScanline; + if (xe >= xsize) + { + we = xe = 0; + ye++; + } + if (ye >= ysize) + { + we = xe = 0; + ye = ysize; + } + + if (yb == ye) + { + if (xb >= xe) + continue; + + pRect->x = xb; + pRect->y = yb; + pRect->width = xe - xb; + pRect->height = 1; + maxRects += 2; + pRect++; + } + else + { + if (xb) + { + pRect->x = xb; + pRect->y = yb++; + pRect->width = xsize - xb; + pRect->height = 1; + maxRects += 2; + pRect++; + } + + if (yb < ye) + { + pRect->x = 0; + pRect->y = yb; + pRect->width = xsize; + pRect->height = ye - yb; + maxRects += min(pRect->height, 3) + 1; + pRect++; + } + + if (xe) + { + pRect->x = 0; + pRect->y = ye; + pRect->width = xe; + pRect->height = 1; + maxRects += 2; + pRect++; + } + } + + pScreenPriv->pBanks[iBank] = + RECTS_TO_REGION(pScreen, pRect - pRects, pRects, 0); + if (!pScreenPriv->pBanks[iBank] || + REGION_NAR(pScreenPriv->pBanks[iBank])) + { + we = 1; + break; + } + } + + if (we && (iBank < nBanks)) + { + for (i = iBank; i >= 0; i--) + if (pScreenPriv->pBanks[i]) + REGION_DESTROY(pScreen, pScreenPriv->pBanks[i]); + + Xfree(pScreenPriv->pBanks); + Xfree(pScreenPriv); + + return FALSE; + } + + /* Open for business */ + + pScreenPriv->type = type; + pScreenPriv->nBanks = nBanks; + pScreenPriv->maxRects = maxRects; + pScreenPriv->nBankBPP = nBankBPP; + pScreenPriv->BankInfo = *pBankInfo; + pScreenPriv->nBitsPerBank = nBitsPerBank; + pScreenPriv->nBitsPerScanline = nBitsPerScanline; + pScreenPriv->nPixelsPerScanlinePadUnit = nPixelsPerScanlinePadUnit; + + SCREEN_WRAP(CreateScreenResources, miBankCreateScreenResources); + SCREEN_WRAP(ModifyPixmapHeader, miBankModifyPixmapHeader); + SCREEN_WRAP(CloseScreen, miBankCloseScreen); + SCREEN_WRAP(GetImage, miBankGetImage); + SCREEN_WRAP(GetSpans, miBankGetSpans); + SCREEN_WRAP(CreateGC, miBankCreateGC); + SCREEN_WRAP(PaintWindowBackground, miBankPaintWindow); + SCREEN_WRAP(PaintWindowBorder, miBankPaintWindow); + SCREEN_WRAP(CopyWindow, miBankCopyWindow); + + pScreenPriv->BackingStoreFuncs = pScreen->BackingStoreFuncs; + + pScreen->BackingStoreFuncs.SaveAreas = miBankSaveAreas; + pScreen->BackingStoreFuncs.RestoreAreas = miBankRestoreAreas; + /* ?????????????????????????????????????????????????????????????? + pScreen->BackingStoreFuncs.SetClipmaskRgn = miBankSetClipmaskRgn; + ?????????????????????????????????????????????????????????????? */ + + BANK_SCRPRIVLVAL = (pointer)pScreenPriv; + + return TRUE; +} + +/* This is used to force GC revalidation when the banking type is changed */ +/*ARGSUSED*/ +static int +miBankNewSerialNumber( + WindowPtr pWin, + pointer unused +) +{ + pWin->drawable.serialNumber = NEXT_SERIAL_NUMBER; + return WT_WALKCHILDREN; +} + +/* This entry modifies the banking interface */ +Bool +miModifyBanking( + ScreenPtr pScreen, + miBankInfoPtr pBankInfo +) +{ + unsigned int type; + + if (!pScreen) + return FALSE; + + if (miBankGeneration == serverGeneration) + { + SCREEN_INIT; + + if (pScreenPriv) + { + if (!pBankInfo || !pBankInfo->BankSize || + !pBankInfo->pBankA || !pBankInfo->pBankB || + !pBankInfo->SetSourceBank || !pBankInfo->SetDestinationBank || + !pBankInfo->SetSourceAndDestinationBanks) + return FALSE; + + /* BankSize and nBankDepth cannot, as yet, be changed */ + if ((pScreenPriv->BankInfo.BankSize != pBankInfo->BankSize) || + (pScreenPriv->BankInfo.nBankDepth != pBankInfo->nBankDepth)) + return FALSE; + + if ((type = miBankDeriveType(pScreen, pBankInfo)) == BANK_NOBANK) + return FALSE; + + /* Reset banking info */ + pScreenPriv->BankInfo = *pBankInfo; + if (type != pScreenPriv->type) + { + /* + * Banking type is changing. Revalidate all window GC's. + */ + pScreenPriv->type = type; + WalkTree(pScreen, miBankNewSerialNumber, 0); + } + + return TRUE; + } + } + + if (!pBankInfo || !pBankInfo->BankSize) + return TRUE; /* No change requested */ + + return FALSE; +} + +/* + * Given various screen attributes, determine the minimum scanline width such + * that each scanline is server and DDX padded and any pixels with imbedded + * bank boundaries are off-screen. This function returns -1 if such a width + * cannot exist. This function exists because the DDX needs to be able to + * determine this width before initializing a frame buffer. + */ +int +miScanLineWidth( + unsigned int xsize, /* pixels */ + unsigned int ysize, /* pixels */ + unsigned int width, /* pixels */ + unsigned long BankSize, /* char's */ + PixmapFormatRec *pBankFormat, + unsigned int nWidthUnit /* bits */ +) +{ + unsigned long nBitsPerBank, nBitsPerScanline, nBitsPerScanlinePadUnit; + unsigned long minBitsPerScanline, maxBitsPerScanline; + + /* Sanity checks */ + + if (!nWidthUnit || !pBankFormat) + return -1; + + nBitsPerBank = BankSize * 8; + if (nBitsPerBank % pBankFormat->scanlinePad) + return -1; + + if (xsize > width) + width = xsize; + nBitsPerScanlinePadUnit = miLCM(pBankFormat->scanlinePad, nWidthUnit); + nBitsPerScanline = + (((width * pBankFormat->bitsPerPixel) + nBitsPerScanlinePadUnit - 1) / + nBitsPerScanlinePadUnit) * nBitsPerScanlinePadUnit; + width = nBitsPerScanline / pBankFormat->bitsPerPixel; + + if (!xsize || !(nBitsPerBank % pBankFormat->bitsPerPixel)) + return (int)width; + + /* + * Scanlines will be server-pad aligned at this point. They will also be + * a multiple of nWidthUnit bits long. Ensure that pixels with imbedded + * bank boundaries are off-screen. + * + * It seems reasonable to limit total frame buffer size to 1/16 of the + * theoretical maximum address space size. On a machine with 32-bit + * addresses (to 8-bit quantities) this turns out to be 256MB. Not only + * does this provide a simple limiting condition for the loops below, but + * it also prevents unsigned long wraparounds. + */ + if (!ysize) + return -1; + + minBitsPerScanline = xsize * pBankFormat->bitsPerPixel; + if (minBitsPerScanline > nBitsPerBank) + return -1; + + if (ysize == 1) + return (int)width; + + maxBitsPerScanline = + (((unsigned long)(-1) >> 1) - minBitsPerScanline) / (ysize - 1); + while (nBitsPerScanline <= maxBitsPerScanline) + { + unsigned long BankBase, BankUnit; + + BankUnit = ((nBitsPerBank + nBitsPerScanline - 1) / nBitsPerBank) * + nBitsPerBank; + if (!(BankUnit % nBitsPerScanline)) + return (int)width; + + for (BankBase = BankUnit; ; BankBase += nBitsPerBank) + { + unsigned long x, y; + + y = BankBase / nBitsPerScanline; + if (y >= ysize) + return (int)width; + + x = BankBase % nBitsPerScanline; + if (!(x % pBankFormat->bitsPerPixel)) + continue; + + if (x < minBitsPerScanline) + { + /* + * Skip ahead certain widths by dividing the excess scanline + * amongst the y's. + */ + y *= nBitsPerScanlinePadUnit; + nBitsPerScanline += + ((x + y - 1) / y) * nBitsPerScanlinePadUnit; + width = nBitsPerScanline / pBankFormat->bitsPerPixel; + break; + } + + if (BankBase != BankUnit) + continue; + + if (!(nBitsPerScanline % x)) + return (int)width; + + BankBase = ((nBitsPerScanline - minBitsPerScanline) / + (nBitsPerScanline - x)) * BankUnit; + } + } + + return -1; +} diff --git a/mi/mibank.h b/mi/mibank.h new file mode 100644 index 000000000..c3aa69379 --- /dev/null +++ b/mi/mibank.h @@ -0,0 +1,119 @@ +/* + * Copyright 1997 through 2003 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * 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, and + * that the name of Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* $XFree86: xc/programs/Xserver/mi/mibank.h,v 1.10 2003/01/01 19:16:42 tsi Exp $ */ + +#ifndef __MIBANK_H__ +#define __MIBANK_H__ 1 + +#include "scrnintstr.h" + +/* + * Banking external interface. + */ + +/* + * This is the banking function type. The return value is normally zero. + * Non-zero returns can be used to implement the likes of scanline interleave, + * etc. + */ +typedef int miBankProc( + ScreenPtr /*pScreen*/, + unsigned int /*iBank*/ +); + +typedef miBankProc *miBankProcPtr; + +typedef struct _miBankInfo +{ + /* + * Banking refers to the use of one or more apertures (in the server's + * address space) to access various parts of a potentially larger hardware + * frame buffer. + * + * Three different banking schemes are supported: + * + * Single banking is indicated when pBankA and pBankB are equal and all + * three miBankProcPtr's point to the same function. Here, both reads and + * writes through the aperture access the same hardware location. + * + * Shared banking is indicated when pBankA and pBankB are equal but the + * source and destination functions differ. Here reads through the + * aperture do not necessarily access the same hardware location as writes. + * + * Double banking is indicated when pBankA and pBankB differ. Here two + * independent apertures are used to provide read/write access to + * potentially different hardware locations. + * + * Any other combination will result in no banking. + */ + miBankProcPtr SetSourceBank; /* Set pBankA bank number */ + miBankProcPtr SetDestinationBank; /* Set pBankB bank number */ + miBankProcPtr SetSourceAndDestinationBanks; /* Set both bank numbers */ + + pointer pBankA; /* First aperture location */ + pointer pBankB; /* First or second aperture location */ + + /* + * BankSize is in units of sizeof(char) and is the size of each bank. + */ + unsigned long BankSize; + + /* + * nBankDepth is the colour depth associated with the maximum number of a + * pixel's bits that are simultaneously accessible through the frame buffer + * aperture. + */ + unsigned int nBankDepth; +} miBankInfoRec, *miBankInfoPtr; + +Bool +miInitializeBanking( + ScreenPtr /*pScreen*/, + unsigned int /*xsize*/, + unsigned int /*ysize*/, + unsigned int /*width*/, + miBankInfoPtr /*pBankInfo*/ +); + +Bool +miModifyBanking( + ScreenPtr /*pScreen*/, + miBankInfoPtr /*pBankInfo*/ +); + +/* + * This function determines the minimum screen width, given a initial estimate + * and various screen attributes. DDX needs to determine this width before + * initializing the screen. + */ +int +miScanLineWidth( + unsigned int /*xsize*/, + unsigned int /*ysize*/, + unsigned int /*width*/, + unsigned long /*BankSize*/, + PixmapFormatRec * /*pBankFormat*/, + unsigned int /*nWidthUnit*/ +); + +#endif /* __MIBANK_H__ */ diff --git a/mi/micmap.c b/mi/micmap.c new file mode 100644 index 000000000..b3e925a09 --- /dev/null +++ b/mi/micmap.c @@ -0,0 +1,674 @@ +/* $XConsortium: cfbcmap.c,v 4.19 94/04/17 20:28:46 dpw Exp $ */ +/************************************************************ +Copyright 1987 by Sun Microsystems, Inc. Mountain View, CA. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this +software and its documentation for any purpose and without +fee is hereby granted, provided that the above copyright no- +tice appear in all copies and that both that copyright no- +tice and this permission notice appear in supporting docu- +mentation, and that the names of Sun or X Consortium +not be used in advertising or publicity pertaining to +distribution of the software without specific prior +written permission. Sun and X Consortium make no +representations about the suitability of this software for +any purpose. It is provided "as is" without any express or +implied warranty. + +SUN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT- +NESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SUN BE LI- +ABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH +THE USE OR PERFORMANCE OF THIS SOFTWARE. + +********************************************************/ +/* $XFree86: xc/programs/Xserver/mi/micmap.c,v 1.11 2001/05/29 22:24:06 dawes Exp $ */ + +/* + * This is based on cfbcmap.c. The functions here are useful independently + * of cfb, which is the reason for including them here. How "mi" these + * are may be debatable. + */ + + +#include "X.h" +#include "Xproto.h" +#include "scrnintstr.h" +#include "colormapst.h" +#include "resource.h" +#include "globals.h" +#include "micmap.h" + +ColormapPtr miInstalledMaps[MAXSCREENS]; + +static Bool miDoInitVisuals(VisualPtr *visualp, DepthPtr *depthp, int *nvisualp, + int *ndepthp, int *rootDepthp, VisualID *defaultVisp, + unsigned long sizes, int bitsPerRGB, int preferredVis); + +miInitVisualsProcPtr miInitVisualsProc = miDoInitVisuals; + +int +miListInstalledColormaps(ScreenPtr pScreen, Colormap *pmaps) +{ + /* By the time we are processing requests, we can guarantee that there + * is always a colormap installed */ + *pmaps = miInstalledMaps[pScreen->myNum]->mid; + return (1); +} + +void +miInstallColormap(ColormapPtr pmap) +{ + int index = pmap->pScreen->myNum; + ColormapPtr oldpmap = miInstalledMaps[index]; + + if(pmap != oldpmap) + { + /* Uninstall pInstalledMap. No hardware changes required, just + * notify all interested parties. */ + if(oldpmap != (ColormapPtr)None) + WalkTree(pmap->pScreen, TellLostMap, (char *)&oldpmap->mid); + /* Install pmap */ + miInstalledMaps[index] = pmap; + WalkTree(pmap->pScreen, TellGainedMap, (char *)&pmap->mid); + + } +} + +void +miUninstallColormap(ColormapPtr pmap) +{ + int index = pmap->pScreen->myNum; + ColormapPtr curpmap = miInstalledMaps[index]; + + if(pmap == curpmap) + { + if (pmap->mid != pmap->pScreen->defColormap) + { + curpmap = (ColormapPtr) LookupIDByType(pmap->pScreen->defColormap, + RT_COLORMAP); + (*pmap->pScreen->InstallColormap)(curpmap); + } + } +} + +void +miResolveColor(unsigned short *pred, unsigned short *pgreen, + unsigned short *pblue, VisualPtr pVisual) +{ + int shift = 16 - pVisual->bitsPerRGBValue; + unsigned lim = (1 << pVisual->bitsPerRGBValue) - 1; + + if ((pVisual->class | DynamicClass) == GrayScale) + { + /* rescale to gray then rgb bits */ + *pred = (30L * *pred + 59L * *pgreen + 11L * *pblue) / 100; + *pblue = *pgreen = *pred = ((*pred >> shift) * 65535) / lim; + } + else + { + /* rescale to rgb bits */ + *pred = ((*pred >> shift) * 65535) / lim; + *pgreen = ((*pgreen >> shift) * 65535) / lim; + *pblue = ((*pblue >> shift) * 65535) / lim; + } +} + +Bool +miInitializeColormap(ColormapPtr pmap) +{ + register unsigned i; + register VisualPtr pVisual; + unsigned lim, maxent, shift; + + pVisual = pmap->pVisual; + lim = (1 << pVisual->bitsPerRGBValue) - 1; + shift = 16 - pVisual->bitsPerRGBValue; + maxent = pVisual->ColormapEntries - 1; + if (pVisual->class == TrueColor) + { + unsigned limr, limg, limb; + + limr = pVisual->redMask >> pVisual->offsetRed; + limg = pVisual->greenMask >> pVisual->offsetGreen; + limb = pVisual->blueMask >> pVisual->offsetBlue; + for(i = 0; i <= maxent; i++) + { + /* rescale to [0..65535] then rgb bits */ + pmap->red[i].co.local.red = + ((((i * 65535) / limr) >> shift) * 65535) / lim; + pmap->green[i].co.local.green = + ((((i * 65535) / limg) >> shift) * 65535) / lim; + pmap->blue[i].co.local.blue = + ((((i * 65535) / limb) >> shift) * 65535) / lim; + } + } + else if (pVisual->class == StaticColor) + { + unsigned limr, limg, limb; + + limr = pVisual->redMask >> pVisual->offsetRed; + limg = pVisual->greenMask >> pVisual->offsetGreen; + limb = pVisual->blueMask >> pVisual->offsetBlue; + for(i = 0; i <= maxent; i++) + { + /* rescale to [0..65535] then rgb bits */ + pmap->red[i].co.local.red = + ((((((i & pVisual->redMask) >> pVisual->offsetRed) + * 65535) / limr) >> shift) * 65535) / lim; + pmap->red[i].co.local.green = + ((((((i & pVisual->greenMask) >> pVisual->offsetGreen) + * 65535) / limg) >> shift) * 65535) / lim; + pmap->red[i].co.local.blue = + ((((((i & pVisual->blueMask) >> pVisual->offsetBlue) + * 65535) / limb) >> shift) * 65535) / lim; + } + } + else if (pVisual->class == StaticGray) + { + for(i = 0; i <= maxent; i++) + { + /* rescale to [0..65535] then rgb bits */ + pmap->red[i].co.local.red = ((((i * 65535) / maxent) >> shift) + * 65535) / lim; + pmap->red[i].co.local.green = pmap->red[i].co.local.red; + pmap->red[i].co.local.blue = pmap->red[i].co.local.red; + } + } + return TRUE; +} + +/* When simulating DirectColor on PseudoColor hardware, multiple + entries of the colormap must be updated + */ + +#define AddElement(mask) { \ + pixel = red | green | blue; \ + for (i = 0; i < nresult; i++) \ + if (outdefs[i].pixel == pixel) \ + break; \ + if (i == nresult) \ + { \ + nresult++; \ + outdefs[i].pixel = pixel; \ + outdefs[i].flags = 0; \ + } \ + outdefs[i].flags |= (mask); \ + outdefs[i].red = pmap->red[red >> pVisual->offsetRed].co.local.red; \ + outdefs[i].green = pmap->green[green >> pVisual->offsetGreen].co.local.green; \ + outdefs[i].blue = pmap->blue[blue >> pVisual->offsetBlue].co.local.blue; \ +} + +int +miExpandDirectColors(ColormapPtr pmap, int ndef, xColorItem *indefs, + xColorItem *outdefs) +{ + register int red, green, blue; + int maxred, maxgreen, maxblue; + int stepred, stepgreen, stepblue; + VisualPtr pVisual; + register int pixel; + register int nresult; + register int i; + + pVisual = pmap->pVisual; + + stepred = 1 << pVisual->offsetRed; + stepgreen = 1 << pVisual->offsetGreen; + stepblue = 1 << pVisual->offsetBlue; + maxred = pVisual->redMask; + maxgreen = pVisual->greenMask; + maxblue = pVisual->blueMask; + nresult = 0; + for (;ndef--; indefs++) + { + if (indefs->flags & DoRed) + { + red = indefs->pixel & pVisual->redMask; + for (green = 0; green <= maxgreen; green += stepgreen) + { + for (blue = 0; blue <= maxblue; blue += stepblue) + { + AddElement (DoRed) + } + } + } + if (indefs->flags & DoGreen) + { + green = indefs->pixel & pVisual->greenMask; + for (red = 0; red <= maxred; red += stepred) + { + for (blue = 0; blue <= maxblue; blue += stepblue) + { + AddElement (DoGreen) + } + } + } + if (indefs->flags & DoBlue) + { + blue = indefs->pixel & pVisual->blueMask; + for (red = 0; red <= maxred; red += stepred) + { + for (green = 0; green <= maxgreen; green += stepgreen) + { + AddElement (DoBlue) + } + } + } + } + return nresult; +} + +Bool +miCreateDefColormap(ScreenPtr pScreen) +{ +/* + * In the following sources PC X server vendors may want to delete + * "_not_tog" from "#ifdef WIN32_not_tog" + */ +#ifdef WIN32_not_tog + /* + * these are the MS-Windows desktop colors, adjusted for X's 16-bit + * color specifications. + */ + static xColorItem citems[] = { + { 0, 0, 0, 0, 0, 0 }, + { 1, 0x8000, 0, 0, 0, 0 }, + { 2, 0, 0x8000, 0, 0, 0 }, + { 3, 0x8000, 0x8000, 0, 0, 0 }, + { 4, 0, 0, 0x8000, 0, 0 }, + { 5, 0x8000, 0, 0x8000, 0, 0 }, + { 6, 0, 0x8000, 0x8000, 0, 0 }, + { 7, 0xc000, 0xc000, 0xc000, 0, 0 }, + { 8, 0xc000, 0xdc00, 0xc000, 0, 0 }, + { 9, 0xa600, 0xca00, 0xf000, 0, 0 }, + { 246, 0xff00, 0xfb00, 0xf000, 0, 0 }, + { 247, 0xa000, 0xa000, 0xa400, 0, 0 }, + { 248, 0x8000, 0x8000, 0x8000, 0, 0 }, + { 249, 0xff00, 0, 0, 0, 0 }, + { 250, 0, 0xff00, 0, 0, 0 }, + { 251, 0xff00, 0xff00, 0, 0, 0 }, + { 252, 0, 0, 0xff00, 0, 0 }, + { 253, 0xff00, 0, 0xff00, 0, 0 }, + { 254, 0, 0xff00, 0xff00, 0, 0 }, + { 255, 0xff00, 0xff00, 0xff00, 0, 0 } + }; +#define NUM_DESKTOP_COLORS sizeof citems / sizeof citems[0] + int i; +#else + unsigned short zero = 0, ones = 0xFFFF; +#endif + Pixel wp, bp; + VisualPtr pVisual; + ColormapPtr cmap; + int alloctype; + + for (pVisual = pScreen->visuals; + pVisual->vid != pScreen->rootVisual; + pVisual++) + ; + + if (pScreen->rootDepth == 1 || (pVisual->class & DynamicClass)) + alloctype = AllocNone; + else + alloctype = AllocAll; + + if (CreateColormap(pScreen->defColormap, pScreen, pVisual, &cmap, + alloctype, 0) != Success) + return FALSE; + + if (pScreen->rootDepth > 1) { + wp = pScreen->whitePixel; + bp = pScreen->blackPixel; +#ifdef WIN32_not_tog + for (i = 0; i < NUM_DESKTOP_COLORS; i++) { + if (AllocColor (cmap, + &citems[i].red, &citems[i].green, &citems[i].blue, + &citems[i].pixel, 0) != Success) + return FALSE; + } +#else + if ((AllocColor(cmap, &ones, &ones, &ones, &wp, 0) != + Success) || + (AllocColor(cmap, &zero, &zero, &zero, &bp, 0) != + Success)) + return FALSE; + pScreen->whitePixel = wp; + pScreen->blackPixel = bp; +#endif + } + + (*pScreen->InstallColormap)(cmap); + return TRUE; +} + +/* + * Default true color bitmasks, should be overridden by + * driver + */ + +#define _RZ(d) ((d + 2) / 3) +#define _RS(d) 0 +#define _RM(d) ((1 << _RZ(d)) - 1) +#define _GZ(d) ((d - _RZ(d) + 1) / 2) +#define _GS(d) _RZ(d) +#define _GM(d) (((1 << _GZ(d)) - 1) << _GS(d)) +#define _BZ(d) (d - _RZ(d) - _GZ(d)) +#define _BS(d) (_RZ(d) + _GZ(d)) +#define _BM(d) (((1 << _BZ(d)) - 1) << _BS(d)) +#define _CE(d) (1 << _RZ(d)) + +typedef struct _miVisuals { + struct _miVisuals *next; + int depth; + int bitsPerRGB; + int visuals; + int count; + int preferredCVC; + Pixel redMask, greenMask, blueMask; +} miVisualsRec, *miVisualsPtr; + +static int miVisualPriority[] = { + PseudoColor, GrayScale, StaticColor, TrueColor, DirectColor, StaticGray +}; + +#define NUM_PRIORITY 6 + +static miVisualsPtr miVisuals; + +void +miClearVisualTypes() +{ + miVisualsPtr v; + + while ((v = miVisuals)) { + miVisuals = v->next; + xfree(v); + } +} + + +Bool +miSetVisualTypesAndMasks(int depth, int visuals, int bitsPerRGB, + int preferredCVC, + Pixel redMask, Pixel greenMask, Pixel blueMask) +{ + miVisualsPtr new, *prev, v; + int count; + + new = (miVisualsPtr) xalloc (sizeof *new); + if (!new) + return FALSE; + if (!redMask || !greenMask || !blueMask) + { + redMask = _RM(depth); + greenMask = _GM(depth); + blueMask = _BM(depth); + } + new->next = 0; + new->depth = depth; + new->visuals = visuals; + new->bitsPerRGB = bitsPerRGB; + new->preferredCVC = preferredCVC; + new->redMask = redMask; + new->greenMask = greenMask; + new->blueMask = blueMask; + count = (visuals >> 1) & 033333333333; + count = visuals - count - ((count >> 1) & 033333333333); + count = (((count + (count >> 3)) & 030707070707) % 077); /* HAKMEM 169 */ + new->count = count; + for (prev = &miVisuals; (v = *prev); prev = &v->next); + *prev = new; + return TRUE; +} + +Bool +miSetVisualTypes(int depth, int visuals, int bitsPerRGB, int preferredCVC) +{ + return miSetVisualTypesAndMasks (depth, visuals, bitsPerRGB, + preferredCVC, 0, 0, 0); +} + +int +miGetDefaultVisualMask(int depth) +{ + if (depth > MAX_PSEUDO_DEPTH) + return LARGE_VISUALS; + else if (depth >= MIN_TRUE_DEPTH) + return ALL_VISUALS; + else if (depth == 1) + return StaticGrayMask; + else + return SMALL_VISUALS; +} + +static Bool +miVisualTypesSet (int depth) +{ + miVisualsPtr visuals; + + for (visuals = miVisuals; visuals; visuals = visuals->next) + if (visuals->depth == depth) + return TRUE; + return FALSE; +} + +Bool +miSetPixmapDepths (void) +{ + int d, f; + + /* Add any unlisted depths from the pixmap formats */ + for (f = 0; f < screenInfo.numPixmapFormats; f++) + { + d = screenInfo.formats[f].depth; + if (!miVisualTypesSet (d)) + { + if (!miSetVisualTypes (d, 0, 0, -1)) + return FALSE; + } + } + return TRUE; +} + +Bool +miInitVisuals(VisualPtr *visualp, DepthPtr *depthp, int *nvisualp, + int *ndepthp, int *rootDepthp, VisualID *defaultVisp, + unsigned long sizes, int bitsPerRGB, int preferredVis) + +{ + if (miInitVisualsProc) + return miInitVisualsProc(visualp, depthp, nvisualp, ndepthp, + rootDepthp, defaultVisp, sizes, bitsPerRGB, + preferredVis); + else + return FALSE; +} + +/* + * Distance to least significant one bit + */ +static int +maskShift (Pixel p) +{ + int s; + + if (!p) return 0; + s = 0; + while (!(p & 1)) + { + s++; + p >>= 1; + } + return s; +} + +/* + * Given a list of formats for a screen, create a list + * of visuals and depths for the screen which corespond to + * the set which can be used with this version of cfb. + */ + +static Bool +miDoInitVisuals(VisualPtr *visualp, DepthPtr *depthp, int *nvisualp, + int *ndepthp, int *rootDepthp, VisualID *defaultVisp, + unsigned long sizes, int bitsPerRGB, int preferredVis) +{ + int i, j = 0, k; + VisualPtr visual; + DepthPtr depth; + VisualID *vid; + int d, b; + int f; + int ndepth, nvisual; + int nvtype; + int vtype; + miVisualsPtr visuals, nextVisuals; + int *preferredCVCs, *prefp; + + /* none specified, we'll guess from pixmap formats */ + if (!miVisuals) + { + for (f = 0; f < screenInfo.numPixmapFormats; f++) + { + d = screenInfo.formats[f].depth; + b = screenInfo.formats[f].bitsPerPixel; + if (sizes & (1 << (b - 1))) + vtype = miGetDefaultVisualMask(d); + else + vtype = 0; + if (!miSetVisualTypes (d, vtype, bitsPerRGB, -1)) + return FALSE; + } + } + nvisual = 0; + ndepth = 0; + for (visuals = miVisuals; visuals; visuals = nextVisuals) + { + nextVisuals = visuals->next; + ndepth++; + nvisual += visuals->count; + } + depth = (DepthPtr) xalloc (ndepth * sizeof (DepthRec)); + visual = (VisualPtr) xalloc (nvisual * sizeof (VisualRec)); + preferredCVCs = (int *)xalloc(ndepth * sizeof(int)); + if (!depth || !visual || !preferredCVCs) + { + xfree (depth); + xfree (visual); + xfree (preferredCVCs); + return FALSE; + } + *depthp = depth; + *visualp = visual; + *ndepthp = ndepth; + *nvisualp = nvisual; + prefp = preferredCVCs; + for (visuals = miVisuals; visuals; visuals = nextVisuals) + { + nextVisuals = visuals->next; + d = visuals->depth; + vtype = visuals->visuals; + nvtype = visuals->count; + *prefp = visuals->preferredCVC; + prefp++; + vid = NULL; + if (nvtype) + { + vid = (VisualID *) xalloc (nvtype * sizeof (VisualID)); + if (!vid) + return FALSE; + } + depth->depth = d; + depth->numVids = nvtype; + depth->vids = vid; + depth++; + for (i = 0; i < NUM_PRIORITY; i++) { + if (! (vtype & (1 << miVisualPriority[i]))) + continue; + visual->class = miVisualPriority[i]; + visual->bitsPerRGBValue = visuals->bitsPerRGB; + visual->ColormapEntries = 1 << d; + visual->nplanes = d; + visual->vid = *vid = FakeClientID (0); + switch (visual->class) { + case PseudoColor: + case GrayScale: + case StaticGray: + visual->redMask = 0; + visual->greenMask = 0; + visual->blueMask = 0; + visual->offsetRed = 0; + visual->offsetGreen = 0; + visual->offsetBlue = 0; + break; + case DirectColor: + case TrueColor: + visual->ColormapEntries = _CE(d); + /* fall through */ + case StaticColor: + visual->redMask = visuals->redMask; + visual->greenMask = visuals->greenMask; + visual->blueMask = visuals->blueMask; + visual->offsetRed = maskShift (visuals->redMask); + visual->offsetGreen = maskShift (visuals->greenMask); + visual->offsetBlue = maskShift (visuals->blueMask); + } + vid++; + visual++; + } + xfree (visuals); + } + miVisuals = NULL; + visual = *visualp; + depth = *depthp; + for (i = 0; i < ndepth; i++) + { + int prefColorVisualClass = -1; + + if (defaultColorVisualClass >= 0) + prefColorVisualClass = defaultColorVisualClass; + else if (preferredVis >= 0) + prefColorVisualClass = preferredVis; + else if (preferredCVCs[i] >= 0) + prefColorVisualClass = preferredCVCs[i]; + + if (*rootDepthp && *rootDepthp != depth[i].depth) + continue; + + for (j = 0; j < depth[i].numVids; j++) + { + for (k = 0; k < nvisual; k++) + if (visual[k].vid == depth[i].vids[j]) + break; + if (k == nvisual) + continue; + if (prefColorVisualClass < 0 || + visual[k].class == prefColorVisualClass) + break; + } + if (j != depth[i].numVids) + break; + } + if (i == ndepth) { + i = 0; + j = 0; + } + *rootDepthp = depth[i].depth; + *defaultVisp = depth[i].vids[j]; + xfree(preferredCVCs); + + return TRUE; +} + +void +miResetInitVisuals() +{ + miInitVisualsProc = miDoInitVisuals; +} + diff --git a/mi/micmap.h b/mi/micmap.h new file mode 100644 index 000000000..557ae63d5 --- /dev/null +++ b/mi/micmap.h @@ -0,0 +1,65 @@ +/* $XFree86: xc/programs/Xserver/mi/micmap.h,v 1.7 2000/09/20 00:09:15 keithp Exp $ */ + +#include "colormapst.h" + +#ifndef _MICMAP_H_ +#define _MICMAP_H_ + +extern ColormapPtr miInstalledMaps[MAXSCREENS]; + +typedef Bool (* miInitVisualsProcPtr)(VisualPtr *, DepthPtr *, int *, int *, + int *, VisualID *, unsigned long, int, + int); + +extern miInitVisualsProcPtr miInitVisualsProc; + +int miListInstalledColormaps(ScreenPtr pScreen, Colormap *pmaps); +void miInstallColormap(ColormapPtr pmap); +void miUninstallColormap(ColormapPtr pmap); + +void miResolveColor(unsigned short *, unsigned short *, unsigned short *, + VisualPtr); +Bool miInitializeColormap(ColormapPtr); +int miExpandDirectColors(ColormapPtr, int, xColorItem *, xColorItem *); +Bool miCreateDefColormap(ScreenPtr); +void miClearVisualTypes(void); +Bool miSetVisualTypes(int, int, int, int); +Bool miSetPixmapDepths(void); +Bool miSetVisualTypesAndMasks(int depth, int visuals, int bitsPerRGB, + int preferredCVC, + Pixel redMask, Pixel greenMask, Pixel blueMask); +int miGetDefaultVisualMask(int); +Bool miInitVisuals(VisualPtr *, DepthPtr *, int *, int *, int *, VisualID *, + unsigned long, int, int); +void miResetInitVisuals(void); + +void miHookInitVisuals(void (**old)(miInitVisualsProcPtr *), + void (*new)(miInitVisualsProcPtr *)); + + +#define MAX_PSEUDO_DEPTH 10 +#define MIN_TRUE_DEPTH 6 + +#define StaticGrayMask (1 << StaticGray) +#define GrayScaleMask (1 << GrayScale) +#define StaticColorMask (1 << StaticColor) +#define PseudoColorMask (1 << PseudoColor) +#define TrueColorMask (1 << TrueColor) +#define DirectColorMask (1 << DirectColor) + +#define ALL_VISUALS (StaticGrayMask|\ + GrayScaleMask|\ + StaticColorMask|\ + PseudoColorMask|\ + TrueColorMask|\ + DirectColorMask) + +#define LARGE_VISUALS (TrueColorMask|\ + DirectColorMask) + +#define SMALL_VISUALS (StaticGrayMask|\ + GrayScaleMask|\ + StaticColorMask|\ + PseudoColorMask) + +#endif /* _MICMAP_H_ */ diff --git a/mi/micoord.h b/mi/micoord.h new file mode 100644 index 000000000..f31c88c83 --- /dev/null +++ b/mi/micoord.h @@ -0,0 +1,71 @@ +/* $XFree86: xc/programs/Xserver/mi/micoord.h,v 1.5 2002/05/22 21:38:31 herrb Exp $ */ +/* + * Copyright (C) 2000 The XFree86 Project, Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * XFREE86 PROJECT 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 XFree86 Project 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 + * XFree86 Project. + * + */ + +#ifndef _MICOORD_H_ +#define _MICOORD_H_ 1 + +#include "servermd.h" + +/* Macros which handle a coordinate in a single register */ + +/* + * Most compilers will convert divisions by 65536 into shifts, if signed + * shifts exist. If your machine does arithmetic shifts and your compiler + * can't get it right, add to this line. + */ + +/* + * mips compiler - what a joke - it CSEs the 65536 constant into a reg + * forcing as to use div instead of shift. Let's be explicit. + */ + +#if defined(mips) || \ + defined(sparc) || defined(__sparc64__) || \ + defined(__alpha) || defined(__alpha__) || \ + defined(__i386__) || defined(i386) || \ + defined(__ia64__) || defined(ia64) || \ + defined(__s390x__) || defined(__s390__) || \ + defined(__x86_64__) || defined(x86_64) +#define GetHighWord(x) (((int) (x)) >> 16) +#else +#define GetHighWord(x) (((int) (x)) / 65536) +#endif + +#if IMAGE_BYTE_ORDER == MSBFirst +#define intToCoord(i,x,y) (((x) = GetHighWord(i)), ((y) = (int) ((short) (i)))) +#define coordToInt(x,y) (((x) << 16) | ((y) & 0xffff)) +#define intToX(i) (GetHighWord(i)) +#define intToY(i) ((int) ((short) i)) +#else +#define intToCoord(i,x,y) (((x) = (int) ((short) (i))), ((y) = GetHighWord(i))) +#define coordToInt(x,y) (((y) << 16) | ((x) & 0xffff)) +#define intToX(i) ((int) ((short) (i))) +#define intToY(i) (GetHighWord(i)) +#endif + +#endif /* _MICOORD_H_ */ diff --git a/mi/mioverlay.c b/mi/mioverlay.c new file mode 100644 index 000000000..9e765b206 --- /dev/null +++ b/mi/mioverlay.c @@ -0,0 +1,2078 @@ +/* $XFree86: xc/programs/Xserver/mi/mioverlay.c,v 3.14 2002/10/18 00:07:13 mvojkovi Exp $ */ + +#include "X.h" +#include "scrnintstr.h" +#include "validate.h" +#include "windowstr.h" +#include "mi.h" +#include "gcstruct.h" +#include "regionstr.h" +#include "mivalidate.h" +#include "mioverlay.h" +#include "migc.h" + +#include "globals.h" + + +typedef struct { + RegionRec exposed; + RegionRec borderExposed; + RegionPtr borderVisible; + DDXPointRec oldAbsCorner; +} miOverlayValDataRec, *miOverlayValDataPtr; + +typedef struct _TreeRec { + WindowPtr pWin; + struct _TreeRec *parent; + struct _TreeRec *firstChild; + struct _TreeRec *lastChild; + struct _TreeRec *prevSib; + struct _TreeRec *nextSib; + RegionRec borderClip; + RegionRec clipList; + unsigned visibility; + miOverlayValDataPtr valdata; +} miOverlayTreeRec, *miOverlayTreePtr; + +typedef struct { + miOverlayTreePtr tree; +} miOverlayWindowRec, *miOverlayWindowPtr; + +typedef struct { + CloseScreenProcPtr CloseScreen; + CreateWindowProcPtr CreateWindow; + DestroyWindowProcPtr DestroyWindow; + UnrealizeWindowProcPtr UnrealizeWindow; + RealizeWindowProcPtr RealizeWindow; + miOverlayTransFunc MakeTransparent; + miOverlayInOverlayFunc InOverlay; + Bool underlayMarked; + Bool copyUnderlay; +} miOverlayScreenRec, *miOverlayScreenPtr; + +static unsigned long miOverlayGeneration = 0; +int miOverlayWindowIndex = -1; +int miOverlayScreenIndex = -1; + +static void RebuildTree(WindowPtr); +static Bool HasUnderlayChildren(WindowPtr); +static void MarkUnderlayWindow(WindowPtr); +static Bool CollectUnderlayChildrenRegions(WindowPtr, RegionPtr); + +static Bool miOverlayCloseScreen(int, ScreenPtr); +static Bool miOverlayCreateWindow(WindowPtr); +static Bool miOverlayDestroyWindow(WindowPtr); +static Bool miOverlayUnrealizeWindow(WindowPtr); +static Bool miOverlayRealizeWindow(WindowPtr); +static void miOverlayMarkWindow(WindowPtr); +static void miOverlayReparentWindow(WindowPtr, WindowPtr); +static void miOverlayRestackWindow(WindowPtr, WindowPtr); +static Bool miOverlayMarkOverlappedWindows(WindowPtr, WindowPtr, WindowPtr*); +static void miOverlayMarkUnrealizedWindow(WindowPtr, WindowPtr, Bool); +static int miOverlayValidateTree(WindowPtr, WindowPtr, VTKind); +static void miOverlayHandleExposures(WindowPtr); +static void miOverlayMoveWindow(WindowPtr, int, int, WindowPtr, VTKind); +static void miOverlayWindowExposures(WindowPtr, RegionPtr, RegionPtr); +static void miOverlayResizeWindow(WindowPtr, int, int, unsigned int, + unsigned int, WindowPtr); +static void miOverlayClearToBackground(WindowPtr, int, int, int, int, Bool); + +#ifdef SHAPE +static void miOverlaySetShape(WindowPtr); +#endif +static void miOverlayChangeBorderWidth(WindowPtr, unsigned int); + +#define MIOVERLAY_GET_SCREEN_PRIVATE(pScreen) \ + ((miOverlayScreenPtr)((pScreen)->devPrivates[miOverlayScreenIndex].ptr)) +#define MIOVERLAY_GET_WINDOW_PRIVATE(pWin) \ + ((miOverlayWindowPtr)((pWin)->devPrivates[miOverlayWindowIndex].ptr)) +#define MIOVERLAY_GET_WINDOW_TREE(pWin) \ + (MIOVERLAY_GET_WINDOW_PRIVATE(pWin)->tree) + +#define IN_UNDERLAY(w) MIOVERLAY_GET_WINDOW_TREE(w) +#define IN_OVERLAY(w) !MIOVERLAY_GET_WINDOW_TREE(w) + +#define MARK_OVERLAY(w) miMarkWindow(w) +#define MARK_UNDERLAY(w) MarkUnderlayWindow(w) + +#define HasParentRelativeBorder(w) (!(w)->borderIsPixel && \ + HasBorder(w) && \ + (w)->backgroundState == ParentRelative) + +Bool +miInitOverlay( + ScreenPtr pScreen, + miOverlayInOverlayFunc inOverlayFunc, + miOverlayTransFunc transFunc +){ + miOverlayScreenPtr pScreenPriv; + + if(!inOverlayFunc || !transFunc) return FALSE; + + if(miOverlayGeneration != serverGeneration) { + if(((miOverlayScreenIndex = AllocateScreenPrivateIndex()) < 0) || + ((miOverlayWindowIndex = AllocateWindowPrivateIndex()) < 0)) + return FALSE; + + miOverlayGeneration = serverGeneration; + } + + if(!AllocateWindowPrivate(pScreen, miOverlayWindowIndex, + sizeof(miOverlayWindowRec))) + return FALSE; + + if(!(pScreenPriv = xalloc(sizeof(miOverlayScreenRec)))) + return FALSE; + + pScreen->devPrivates[miOverlayScreenIndex].ptr = (pointer)pScreenPriv; + + pScreenPriv->InOverlay = inOverlayFunc; + pScreenPriv->MakeTransparent = transFunc; + pScreenPriv->underlayMarked = FALSE; + + + pScreenPriv->CloseScreen = pScreen->CloseScreen; + pScreenPriv->CreateWindow = pScreen->CreateWindow; + pScreenPriv->DestroyWindow = pScreen->DestroyWindow; + pScreenPriv->UnrealizeWindow = pScreen->UnrealizeWindow; + pScreenPriv->RealizeWindow = pScreen->RealizeWindow; + + pScreen->CloseScreen = miOverlayCloseScreen; + pScreen->CreateWindow = miOverlayCreateWindow; + pScreen->DestroyWindow = miOverlayDestroyWindow; + pScreen->UnrealizeWindow = miOverlayUnrealizeWindow; + pScreen->RealizeWindow = miOverlayRealizeWindow; + + pScreen->ReparentWindow = miOverlayReparentWindow; + pScreen->RestackWindow = miOverlayRestackWindow; + pScreen->MarkOverlappedWindows = miOverlayMarkOverlappedWindows; + pScreen->MarkUnrealizedWindow = miOverlayMarkUnrealizedWindow; + pScreen->ValidateTree = miOverlayValidateTree; + pScreen->HandleExposures = miOverlayHandleExposures; + pScreen->MoveWindow = miOverlayMoveWindow; + pScreen->WindowExposures = miOverlayWindowExposures; + pScreen->ResizeWindow = miOverlayResizeWindow; + pScreen->MarkWindow = miOverlayMarkWindow; + pScreen->ClearToBackground = miOverlayClearToBackground; +#ifdef SHAPE + pScreen->SetShape = miOverlaySetShape; +#endif + pScreen->ChangeBorderWidth = miOverlayChangeBorderWidth; + + return TRUE; +} + + +static Bool +miOverlayCloseScreen(int i, ScreenPtr pScreen) +{ + miOverlayScreenPtr pScreenPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen); + + pScreen->CloseScreen = pScreenPriv->CloseScreen; + pScreen->CreateWindow = pScreenPriv->CreateWindow; + pScreen->DestroyWindow = pScreenPriv->DestroyWindow; + pScreen->UnrealizeWindow = pScreenPriv->UnrealizeWindow; + pScreen->RealizeWindow = pScreenPriv->RealizeWindow; + + xfree(pScreenPriv); + + return (*pScreen->CloseScreen)(i, pScreen); +} + + +static Bool +miOverlayCreateWindow(WindowPtr pWin) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + miOverlayScreenPtr pScreenPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen); + miOverlayWindowPtr pWinPriv = MIOVERLAY_GET_WINDOW_PRIVATE(pWin); + miOverlayTreePtr pTree = NULL; + Bool result = TRUE; + + pWinPriv->tree = NULL; + + if(!pWin->parent || !((*pScreenPriv->InOverlay)(pWin))) { + if(!(pTree = (miOverlayTreePtr)xcalloc(1, sizeof(miOverlayTreeRec)))) + return FALSE; + } + + if(pScreenPriv->CreateWindow) { + pScreen->CreateWindow = pScreenPriv->CreateWindow; + result = (*pScreen->CreateWindow)(pWin); + pScreen->CreateWindow = miOverlayCreateWindow; + } + + if (pTree) { + if(result) { + pTree->pWin = pWin; + pTree->visibility = VisibilityNotViewable; + pWinPriv->tree = pTree; + if(pWin->parent) { + REGION_INIT(pScreen, &(pTree->borderClip), NullBox, 1); + REGION_INIT(pScreen, &(pTree->clipList), NullBox, 1); + RebuildTree(pWin); + } else { + BoxRec fullBox; + fullBox.x1 = 0; + fullBox.y1 = 0; + fullBox.x2 = pScreen->width; + fullBox.y2 = pScreen->height; + REGION_INIT(pScreen, &(pTree->borderClip), &fullBox, 1); + REGION_INIT(pScreen, &(pTree->clipList), &fullBox, 1); + } + } else xfree(pTree); + } + + return TRUE; +} + + +static Bool +miOverlayDestroyWindow(WindowPtr pWin) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + miOverlayScreenPtr pScreenPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen); + miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin); + Bool result = TRUE; + + if (pTree) { + if(pTree->prevSib) + pTree->prevSib->nextSib = pTree->nextSib; + else if(pTree->parent) + pTree->parent->firstChild = pTree->nextSib; + + if(pTree->nextSib) + pTree->nextSib->prevSib = pTree->prevSib; + else if(pTree->parent) + pTree->parent->lastChild = pTree->prevSib; + + REGION_UNINIT(pScreen, &(pTree->borderClip)); + REGION_UNINIT(pScreen, &(pTree->clipList)); + xfree(pTree); + } + + if(pScreenPriv->DestroyWindow) { + pScreen->DestroyWindow = pScreenPriv->DestroyWindow; + result = (*pScreen->DestroyWindow)(pWin); + pScreen->DestroyWindow = miOverlayDestroyWindow; + } + + return result; +} + +static Bool +miOverlayUnrealizeWindow(WindowPtr pWin) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + miOverlayScreenPtr pScreenPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen); + miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin); + Bool result = TRUE; + + if(pTree) pTree->visibility = VisibilityNotViewable; + + if(pScreenPriv->UnrealizeWindow) { + pScreen->UnrealizeWindow = pScreenPriv->UnrealizeWindow; + result = (*pScreen->UnrealizeWindow)(pWin); + pScreen->UnrealizeWindow = miOverlayUnrealizeWindow; + } + + return result; +} + + +static Bool +miOverlayRealizeWindow(WindowPtr pWin) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + miOverlayScreenPtr pScreenPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen); + Bool result = TRUE; + + if(pScreenPriv->RealizeWindow) { + pScreen->RealizeWindow = pScreenPriv->RealizeWindow; + result = (*pScreen->RealizeWindow)(pWin); + pScreen->RealizeWindow = miOverlayRealizeWindow; + } + + /* we only need to catch the root window realization */ + + if(result && !pWin->parent && !((*pScreenPriv->InOverlay)(pWin))) + { + BoxRec box; + box.x1 = box.y1 = 0; + box.x2 = pWin->drawable.width; + box.y2 = pWin->drawable.height; + (*pScreenPriv->MakeTransparent)(pScreen, 1, &box); + } + + return result; +} + + +static void +miOverlayReparentWindow(WindowPtr pWin, WindowPtr pPriorParent) +{ + if(IN_UNDERLAY(pWin) || HasUnderlayChildren(pWin)) { + /* This could probably be more optimal */ + RebuildTree(WindowTable[pWin->drawable.pScreen->myNum]->firstChild); + } +} + +static void +miOverlayRestackWindow(WindowPtr pWin, WindowPtr oldNextSib) +{ + if(IN_UNDERLAY(pWin) || HasUnderlayChildren(pWin)) { + /* This could probably be more optimal */ + RebuildTree(pWin); + } +} + + +static Bool +miOverlayMarkOverlappedWindows( + WindowPtr pWin, + WindowPtr pFirst, + WindowPtr *pLayerWin +){ + ScreenPtr pScreen = pWin->drawable.pScreen; + WindowPtr pChild, pLast; + Bool overMarked, underMarked, doUnderlay, markAll; + miOverlayTreePtr pTree = NULL, tLast, tChild; + BoxPtr box; + + overMarked = underMarked = markAll = FALSE; + + if(pLayerWin) *pLayerWin = pWin; /* hah! */ + + doUnderlay = (IN_UNDERLAY(pWin) || HasUnderlayChildren(pWin)); + + box = REGION_EXTENTS(pScreen, &pWin->borderSize); + + if((pChild = pFirst)) { + pLast = pChild->parent->lastChild; + while (1) { + if (pChild == pWin) markAll = TRUE; + + if(doUnderlay && IN_UNDERLAY(pChild)) + pTree = MIOVERLAY_GET_WINDOW_TREE(pChild); + + if(pChild->viewable) { + if (REGION_BROKEN (pScreen, &pChild->winSize)) + SetWinSize (pChild); + if (REGION_BROKEN (pScreen, &pChild->borderSize)) + SetBorderSize (pChild); + + if (markAll || + RECT_IN_REGION(pScreen, &pChild->borderSize, box)) + { + MARK_OVERLAY(pChild); + overMarked = TRUE; + if(doUnderlay && IN_UNDERLAY(pChild)) { + MARK_UNDERLAY(pChild); + underMarked = TRUE; + } + if (pChild->firstChild) { + pChild = pChild->firstChild; + continue; + } + } + } + while (!pChild->nextSib && (pChild != pLast)) { + pChild = pChild->parent; + if(doUnderlay && IN_UNDERLAY(pChild)) + pTree = MIOVERLAY_GET_WINDOW_TREE(pChild); + } + + if(pChild == pWin) markAll = FALSE; + + if (pChild == pLast) break; + + pChild = pChild->nextSib; + } + if(overMarked) + MARK_OVERLAY(pWin->parent); + } + + if(doUnderlay && !pTree) { + if(!(pTree = MIOVERLAY_GET_WINDOW_TREE(pWin))) { + pChild = pWin->lastChild; + while(1) { + if((pTree = MIOVERLAY_GET_WINDOW_TREE(pChild))) + break; + + if(pChild->lastChild) { + pChild = pChild->lastChild; + continue; + } + + while(!pChild->prevSib) pChild = pChild->parent; + + pChild = pChild->prevSib; + } + } + } + + if(pTree && pTree->nextSib) { + tChild = pTree->parent->lastChild; + tLast = pTree->nextSib; + + while(1) { + if(tChild->pWin->viewable) { + if (REGION_BROKEN (pScreen, &tChild->pWin->winSize)) + SetWinSize (tChild->pWin); + if (REGION_BROKEN (pScreen, &tChild->pWin->borderSize)) + SetBorderSize (tChild->pWin); + + if(RECT_IN_REGION(pScreen, &(tChild->pWin->borderSize), box)) + { + MARK_UNDERLAY(tChild->pWin); + underMarked = TRUE; + } + } + + if(tChild->lastChild) { + tChild = tChild->lastChild; + continue; + } + + while(!tChild->prevSib && (tChild != tLast)) + tChild = tChild->parent; + + if(tChild == tLast) break; + + tChild = tChild->prevSib; + } + } + + if(underMarked) { + MARK_UNDERLAY(pTree->parent->pWin); + MIOVERLAY_GET_SCREEN_PRIVATE(pScreen)->underlayMarked = TRUE; + } + + return (underMarked || overMarked); +} + + +static void +miOverlayComputeClips( + WindowPtr pParent, + RegionPtr universe, + VTKind kind, + RegionPtr exposed +){ + ScreenPtr pScreen = pParent->drawable.pScreen; + int oldVis, newVis, dx, dy; + BoxRec borderSize; + RegionPtr borderVisible; + RegionRec childUniverse, childUnion; + miOverlayTreePtr tParent = MIOVERLAY_GET_WINDOW_TREE(pParent); + miOverlayTreePtr tChild; + Bool overlap; + + borderSize.x1 = pParent->drawable.x - wBorderWidth(pParent); + borderSize.y1 = pParent->drawable.y - wBorderWidth(pParent); + dx = (int) pParent->drawable.x + (int) pParent->drawable.width + + wBorderWidth(pParent); + if (dx > 32767) dx = 32767; + borderSize.x2 = dx; + dy = (int) pParent->drawable.y + (int) pParent->drawable.height + + wBorderWidth(pParent); + if (dy > 32767) dy = 32767; + borderSize.y2 = dy; + + oldVis = tParent->visibility; + switch (RECT_IN_REGION( pScreen, universe, &borderSize)) { + case rgnIN: + newVis = VisibilityUnobscured; + break; + case rgnPART: + newVis = VisibilityPartiallyObscured; +#ifdef SHAPE + { + RegionPtr pBounding; + + if ((pBounding = wBoundingShape (pParent))) { + switch (miShapedWindowIn (pScreen, universe, pBounding, + &borderSize, + pParent->drawable.x, + pParent->drawable.y)) + { + case rgnIN: + newVis = VisibilityUnobscured; + break; + case rgnOUT: + newVis = VisibilityFullyObscured; + break; + } + } + } +#endif + break; + default: + newVis = VisibilityFullyObscured; + break; + } + tParent->visibility = newVis; + + dx = pParent->drawable.x - tParent->valdata->oldAbsCorner.x; + dy = pParent->drawable.y - tParent->valdata->oldAbsCorner.y; + + switch (kind) { + case VTMap: + case VTStack: + case VTUnmap: + break; + case VTMove: + if ((oldVis == newVis) && + ((oldVis == VisibilityFullyObscured) || + (oldVis == VisibilityUnobscured))) + { + tChild = tParent; + while (1) { + if (tChild->pWin->viewable) { + if (tChild->visibility != VisibilityFullyObscured) { + REGION_TRANSLATE( pScreen, &tChild->borderClip, dx, dy); + REGION_TRANSLATE( pScreen, &tChild->clipList, dx, dy); + + tChild->pWin->drawable.serialNumber = + NEXT_SERIAL_NUMBER; + if (pScreen->ClipNotify) + (* pScreen->ClipNotify) (tChild->pWin, dx, dy); + } + if (tChild->valdata) { + REGION_INIT(pScreen, &tChild->valdata->borderExposed, + NullBox, 0); + if (HasParentRelativeBorder(tChild->pWin)){ + REGION_SUBTRACT(pScreen, + &tChild->valdata->borderExposed, + &tChild->borderClip, + &tChild->pWin->winSize); + } + REGION_INIT( pScreen, &tChild->valdata->exposed, + NullBox, 0); + } + if (tChild->firstChild) { + tChild = tChild->firstChild; + continue; + } + } + while (!tChild->nextSib && (tChild != tParent)) + tChild = tChild->parent; + if (tChild == tParent) + break; + tChild = tChild->nextSib; + } + return; + } + /* fall through */ + default: + if (dx || dy) { + REGION_TRANSLATE( pScreen, &tParent->borderClip, dx, dy); + REGION_TRANSLATE( pScreen, &tParent->clipList, dx, dy); + } + break; + case VTBroken: + REGION_EMPTY (pScreen, &tParent->borderClip); + REGION_EMPTY (pScreen, &tParent->clipList); + break; + } + + borderVisible = tParent->valdata->borderVisible; + REGION_INIT( pScreen, &tParent->valdata->borderExposed, NullBox, 0); + REGION_INIT( pScreen, &tParent->valdata->exposed, NullBox, 0); + + if (HasBorder (pParent)) { + if (borderVisible) { + REGION_SUBTRACT( pScreen, exposed, universe, borderVisible); + REGION_DESTROY( pScreen, borderVisible); + } else + REGION_SUBTRACT( pScreen, exposed, universe, &tParent->borderClip); + + if (HasParentRelativeBorder(pParent) && (dx || dy)) + REGION_SUBTRACT( pScreen, &tParent->valdata->borderExposed, + universe, &pParent->winSize); + else + REGION_SUBTRACT( pScreen, &tParent->valdata->borderExposed, + exposed, &pParent->winSize); + + REGION_COPY( pScreen, &tParent->borderClip, universe); + REGION_INTERSECT( pScreen, universe, universe, &pParent->winSize); + } + else + REGION_COPY( pScreen, &tParent->borderClip, universe); + + if ((tChild = tParent->firstChild) && pParent->mapped) { + REGION_INIT(pScreen, &childUniverse, NullBox, 0); + REGION_INIT(pScreen, &childUnion, NullBox, 0); + + for (; tChild; tChild = tChild->nextSib) { + if (tChild->pWin->viewable) + REGION_APPEND( pScreen, &childUnion, &tChild->pWin->borderSize); + } + + REGION_VALIDATE( pScreen, &childUnion, &overlap); + + for (tChild = tParent->firstChild; + tChild; + tChild = tChild->nextSib) + { + if (tChild->pWin->viewable) { + if (tChild->valdata) { + REGION_INTERSECT( pScreen, &childUniverse, universe, + &tChild->pWin->borderSize); + miOverlayComputeClips (tChild->pWin, &childUniverse, + kind, exposed); + } + if (overlap) + REGION_SUBTRACT( pScreen, universe, universe, + &tChild->pWin->borderSize); + } + } + if (!overlap) + REGION_SUBTRACT( pScreen, universe, universe, &childUnion); + REGION_UNINIT( pScreen, &childUnion); + REGION_UNINIT( pScreen, &childUniverse); + } + + if (oldVis == VisibilityFullyObscured || + oldVis == VisibilityNotViewable) + { + REGION_COPY( pScreen, &tParent->valdata->exposed, universe); + } + else if (newVis != VisibilityFullyObscured && + newVis != VisibilityNotViewable) + { + REGION_SUBTRACT( pScreen, &tParent->valdata->exposed, + universe, &tParent->clipList); + } + + /* HACK ALERT - copying contents of regions, instead of regions */ + { + RegionRec tmp; + + tmp = tParent->clipList; + tParent->clipList = *universe; + *universe = tmp; + } + + pParent->drawable.serialNumber = NEXT_SERIAL_NUMBER; + + if (pScreen->ClipNotify) + (* pScreen->ClipNotify) (pParent, dx, dy); +} + + +static void +miOverlayMarkWindow(WindowPtr pWin) +{ + miOverlayTreePtr pTree = NULL; + WindowPtr pChild, pGrandChild; + + miMarkWindow(pWin); + + /* look for UnmapValdata among immediate children */ + + if(!(pChild = pWin->firstChild)) return; + + for( ; pChild; pChild = pChild->nextSib) { + if(pChild->valdata == UnmapValData) { + if(IN_UNDERLAY(pChild)) { + pTree = MIOVERLAY_GET_WINDOW_TREE(pChild); + pTree->valdata = (miOverlayValDataPtr)UnmapValData; + continue; + } else { + if(!(pGrandChild = pChild->firstChild)) + continue; + + while(1) { + if(IN_UNDERLAY(pGrandChild)) { + pTree = MIOVERLAY_GET_WINDOW_TREE(pGrandChild); + pTree->valdata = (miOverlayValDataPtr)UnmapValData; + } else if(pGrandChild->firstChild) { + pGrandChild = pGrandChild->firstChild; + continue; + } + + while(!pGrandChild->nextSib && (pGrandChild != pChild)) + pGrandChild = pGrandChild->parent; + + if(pChild == pGrandChild) break; + + pGrandChild = pGrandChild->nextSib; + } + } + } + } + + if(pTree) { + MARK_UNDERLAY(pTree->parent->pWin); + MIOVERLAY_GET_SCREEN_PRIVATE( + pWin->drawable.pScreen)->underlayMarked = TRUE; + } +} + +static void +miOverlayMarkUnrealizedWindow( + WindowPtr pChild, + WindowPtr pWin, + Bool fromConfigure +){ + if ((pChild != pWin) || fromConfigure) { + miOverlayTreePtr pTree; + + REGION_EMPTY(pChild->drawable.pScreen, &pChild->clipList); + if (pChild->drawable.pScreen->ClipNotify) + (* pChild->drawable.pScreen->ClipNotify)(pChild, 0, 0); + REGION_EMPTY(pChild->drawable.pScreen, &pChild->borderClip); + if((pTree = MIOVERLAY_GET_WINDOW_TREE(pChild))) { + if(pTree->valdata != (miOverlayValDataPtr)UnmapValData) { + REGION_EMPTY(pChild->drawable.pScreen, &pTree->clipList); + REGION_EMPTY(pChild->drawable.pScreen, &pTree->borderClip); + } + } + } +} + + +static int +miOverlayValidateTree( + WindowPtr pParent, + WindowPtr pChild, /* first child effected */ + VTKind kind +){ + ScreenPtr pScreen = pParent->drawable.pScreen; + miOverlayScreenPtr pPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen); + RegionRec totalClip, childClip, exposed; + miOverlayTreePtr tParent, tChild, tWin; + Bool overlap; + WindowPtr newParent; + + if(!pPriv->underlayMarked) + goto SKIP_UNDERLAY; + + if (!pChild) pChild = pParent->firstChild; + + REGION_INIT(pScreen, &totalClip, NullBox, 0); + REGION_INIT(pScreen, &childClip, NullBox, 0); + REGION_INIT(pScreen, &exposed, NullBox, 0); + + newParent = pParent; + + while(IN_OVERLAY(newParent)) + newParent = newParent->parent; + + tParent = MIOVERLAY_GET_WINDOW_TREE(newParent); + + if(IN_UNDERLAY(pChild)) + tChild = MIOVERLAY_GET_WINDOW_TREE(pChild); + else + tChild = tParent->firstChild; + + if (REGION_BROKEN (pScreen, &tParent->clipList) && + !REGION_BROKEN (pScreen, &tParent->borderClip)) + { + kind = VTBroken; + REGION_COPY (pScreen, &totalClip, &tParent->borderClip); + REGION_INTERSECT (pScreen, &totalClip, &totalClip, + &tParent->pWin->winSize); + + for (tWin = tParent->firstChild; tWin != tChild; tWin = tWin->nextSib) { + if (tWin->pWin->viewable) + REGION_SUBTRACT (pScreen, &totalClip, &totalClip, + &tWin->pWin->borderSize); + } + REGION_EMPTY (pScreen, &tParent->clipList); + } else { + for(tWin = tChild; tWin; tWin = tWin->nextSib) { + if(tWin->valdata) + REGION_APPEND(pScreen, &totalClip, &tWin->borderClip); + } + REGION_VALIDATE(pScreen, &totalClip, &overlap); + } + + if(kind != VTStack) + REGION_UNION(pScreen, &totalClip, &totalClip, &tParent->clipList); + + for(tWin = tChild; tWin; tWin = tWin->nextSib) { + if(tWin->valdata) { + if(tWin->pWin->viewable) { + REGION_INTERSECT(pScreen, &childClip, &totalClip, + &tWin->pWin->borderSize); + miOverlayComputeClips(tWin->pWin, &childClip, kind, &exposed); + REGION_SUBTRACT(pScreen, &totalClip, &totalClip, + &tWin->pWin->borderSize); + } else { /* Means we are unmapping */ + REGION_EMPTY(pScreen, &tWin->clipList); + REGION_EMPTY( pScreen, &tWin->borderClip); + tWin->valdata = NULL; + } + } + } + + REGION_UNINIT(pScreen, &childClip); + + if(!((*pPriv->InOverlay)(newParent))) { + REGION_INIT(pScreen, &tParent->valdata->exposed, NullBox, 0); + REGION_INIT(pScreen, &tParent->valdata->borderExposed, NullBox, 0); + } + + switch (kind) { + case VTStack: + break; + default: + if(!((*pPriv->InOverlay)(newParent))) + REGION_SUBTRACT(pScreen, &tParent->valdata->exposed, &totalClip, + &tParent->clipList); + /* fall through */ + case VTMap: + REGION_COPY( pScreen, &tParent->clipList, &totalClip); + if(!((*pPriv->InOverlay)(newParent))) + newParent->drawable.serialNumber = NEXT_SERIAL_NUMBER; + break; + } + + REGION_UNINIT( pScreen, &totalClip); + REGION_UNINIT( pScreen, &exposed); + +SKIP_UNDERLAY: + + miValidateTree(pParent, pChild, kind); + + return 1; +} + + +static void +miOverlayHandleExposures(WindowPtr pWin) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + miOverlayScreenPtr pPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen); + WindowPtr pChild; + ValidatePtr val; + void (* WindowExposures)(WindowPtr, RegionPtr, RegionPtr); + + WindowExposures = pWin->drawable.pScreen->WindowExposures; + if(pPriv->underlayMarked) { + miOverlayTreePtr pTree; + miOverlayValDataPtr mival; + + pChild = pWin; + while(IN_OVERLAY(pChild)) + pChild = pChild->parent; + + pTree = MIOVERLAY_GET_WINDOW_TREE(pChild); + + while (1) { + if((mival = pTree->valdata)) { + if(!((*pPriv->InOverlay)(pTree->pWin))) { + if (REGION_NOTEMPTY(pScreen, &mival->borderExposed)) + (*pWin->drawable.pScreen->PaintWindowBorder)( + pTree->pWin, &mival->borderExposed, PW_BORDER); + REGION_UNINIT(pScreen, &mival->borderExposed); + + (*WindowExposures)(pTree->pWin,&mival->exposed,NullRegion); + REGION_UNINIT(pScreen, &mival->exposed); + } + xfree(mival); + pTree->valdata = NULL; + if (pTree->firstChild) { + pTree = pTree->firstChild; + continue; + } + } + while (!pTree->nextSib && (pTree->pWin != pChild)) + pTree = pTree->parent; + if (pTree->pWin == pChild) + break; + pTree = pTree->nextSib; + } + pPriv->underlayMarked = FALSE; + } + + pChild = pWin; + while (1) { + if ( (val = pChild->valdata) ) { + if(!((*pPriv->InOverlay)(pChild))) { + REGION_UNION(pScreen, &val->after.exposed, &val->after.exposed, + &val->after.borderExposed); + + if (REGION_NOTEMPTY(pScreen, &val->after.exposed)) { + (*(MIOVERLAY_GET_SCREEN_PRIVATE(pScreen)->MakeTransparent))( + pScreen, + REGION_NUM_RECTS(&val->after.exposed), + REGION_RECTS(&val->after.exposed)); + } + } else { + if (REGION_NOTEMPTY(pScreen, &val->after.borderExposed)) + (*pChild->drawable.pScreen->PaintWindowBorder)(pChild, + &val->after.borderExposed, + PW_BORDER); + (*WindowExposures)(pChild, &val->after.exposed, NullRegion); + } + REGION_UNINIT(pScreen, &val->after.borderExposed); + REGION_UNINIT(pScreen, &val->after.exposed); + xfree(val); + pChild->valdata = (ValidatePtr)NULL; + if (pChild->firstChild) + { + pChild = pChild->firstChild; + continue; + } + } + while (!pChild->nextSib && (pChild != pWin)) + pChild = pChild->parent; + if (pChild == pWin) + break; + pChild = pChild->nextSib; + } +} + + +static void +miOverlayMoveWindow( + WindowPtr pWin, + int x, + int y, + WindowPtr pNextSib, + VTKind kind +){ + ScreenPtr pScreen = pWin->drawable.pScreen; + miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin); + WindowPtr pParent, windowToValidate; + Bool WasViewable = (Bool)(pWin->viewable); + short bw; + RegionRec overReg, underReg; + DDXPointRec oldpt; +#ifdef DO_SAVE_UNDERS + Bool dosave = FALSE; +#endif + + if (!(pParent = pWin->parent)) + return ; + bw = wBorderWidth (pWin); + + oldpt.x = pWin->drawable.x; + oldpt.y = pWin->drawable.y; + if (WasViewable) { + REGION_INIT(pScreen, &overReg, NullBox, 1); + REGION_INIT(pScreen, &underReg, NullBox, 0); + if(pTree) { + REGION_COPY(pScreen, &overReg, &pWin->borderClip); + REGION_COPY(pScreen, &underReg, &pTree->borderClip); + } else { + REGION_COPY(pScreen, &overReg, &pWin->borderClip); + CollectUnderlayChildrenRegions(pWin, &underReg); + } + (*pScreen->MarkOverlappedWindows)(pWin, pWin, NULL); + } + pWin->origin.x = x + (int)bw; + pWin->origin.y = y + (int)bw; + x = pWin->drawable.x = pParent->drawable.x + x + (int)bw; + y = pWin->drawable.y = pParent->drawable.y + y + (int)bw; + + SetWinSize (pWin); + SetBorderSize (pWin); + + (*pScreen->PositionWindow)(pWin, x, y); + + windowToValidate = MoveWindowInStack(pWin, pNextSib); + + ResizeChildrenWinSize(pWin, x - oldpt.x, y - oldpt.y, 0, 0); + + if (WasViewable) { + miOverlayScreenPtr pPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen); + (*pScreen->MarkOverlappedWindows) (pWin, windowToValidate, NULL); + +#ifdef DO_SAVE_UNDERS + if (DO_SAVE_UNDERS(pWin)) + dosave = (*pScreen->ChangeSaveUnder)(pWin, windowToValidate); +#endif /* DO_SAVE_UNDERS */ + + (*pScreen->ValidateTree)(pWin->parent, NullWindow, kind); + if(REGION_NOTEMPTY(pScreen, &underReg)) { + pPriv->copyUnderlay = TRUE; + (* pWin->drawable.pScreen->CopyWindow)(pWin, oldpt, &underReg); + } + REGION_UNINIT(pScreen, &underReg); + if(REGION_NOTEMPTY(pScreen, &overReg)) { + pPriv->copyUnderlay = FALSE; + (* pWin->drawable.pScreen->CopyWindow)(pWin, oldpt, &overReg); + } + REGION_UNINIT(pScreen, &overReg); + (*pScreen->HandleExposures)(pWin->parent); + +#ifdef DO_SAVE_UNDERS + if (dosave) + (*pScreen->PostChangeSaveUnder)(pWin, windowToValidate); +#endif /* DO_SAVE_UNDERS */ + if (pScreen->PostValidateTree) + (*pScreen->PostValidateTree)(pWin->parent, NullWindow, kind); + } + if (pWin->realized) + WindowsRestructured (); +} + +#ifndef RECTLIMIT +#define RECTLIMIT 25 +#endif + +static void +miOverlayWindowExposures( + WindowPtr pWin, + register RegionPtr prgn, + RegionPtr other_exposed +){ + RegionPtr exposures = prgn; + ScreenPtr pScreen = pWin->drawable.pScreen; + + if (pWin->backStorage && prgn) + exposures = (*pScreen->RestoreAreas)(pWin, prgn); + if ((prgn && !REGION_NIL(prgn)) || + (exposures && !REGION_NIL(exposures)) || other_exposed) + { + RegionRec expRec; + int clientInterested; + + clientInterested = (pWin->eventMask|wOtherEventMasks(pWin)) & + ExposureMask; + if (other_exposed) { + if (exposures) { + REGION_UNION(pScreen, other_exposed, exposures, other_exposed); + if (exposures != prgn) + REGION_DESTROY(pScreen, exposures); + } + exposures = other_exposed; + } + if (clientInterested && exposures && + (REGION_NUM_RECTS(exposures) > RECTLIMIT)) + { + miOverlayScreenPtr pPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen); + BoxRec box; + + box = *REGION_EXTENTS(pScreen, exposures); + if (exposures == prgn) { + exposures = &expRec; + REGION_INIT(pScreen, exposures, &box, 1); + REGION_RESET(pScreen, prgn, &box); + } else { + REGION_RESET(pScreen, exposures, &box); + REGION_UNION(pScreen, prgn, prgn, exposures); + } + /* This is the only reason why we are replacing mi's version + of this file */ + + if(!((*pPriv->InOverlay)(pWin))) { + miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin); + REGION_INTERSECT(pScreen, prgn, prgn, &pTree->clipList); + } else + REGION_INTERSECT(pScreen, prgn, prgn, &pWin->clipList); + + /* need to clear out new areas of backing store, too */ + if (pWin->backStorage) + (void) (*pScreen->ClearBackingStore)( + pWin, + box.x1 - pWin->drawable.x, + box.y1 - pWin->drawable.y, + box.x2 - box.x1, + box.y2 - box.y1, + FALSE); + } + if (prgn && !REGION_NIL(prgn)) + (*pScreen->PaintWindowBackground)( + pWin, prgn, PW_BACKGROUND); + if (clientInterested && exposures && !REGION_NIL(exposures)) + miSendExposures(pWin, exposures, + pWin->drawable.x, pWin->drawable.y); + if (exposures == &expRec) { + REGION_UNINIT(pScreen, exposures); + } + else if (exposures && exposures != prgn && exposures != other_exposed) + REGION_DESTROY(pScreen, exposures); + if (prgn) + REGION_EMPTY(pScreen, prgn); + } + else if (exposures && exposures != prgn) + REGION_DESTROY(pScreen, exposures); +} + + +typedef struct { + RegionPtr over; + RegionPtr under; +} miOverlayTwoRegions; + +static int +miOverlayRecomputeExposures ( + WindowPtr pWin, + pointer value +){ + register ScreenPtr pScreen; + miOverlayTwoRegions *pValid = (miOverlayTwoRegions*)value; + miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin); + + /* This prevents warning about pScreen not being used. */ + pWin->drawable.pScreen = pScreen = pWin->drawable.pScreen; + + if (pWin->valdata) { + /* + * compute exposed regions of this window + */ + REGION_SUBTRACT(pScreen, &pWin->valdata->after.exposed, + &pWin->clipList, pValid->over); + /* + * compute exposed regions of the border + */ + REGION_SUBTRACT(pScreen, &pWin->valdata->after.borderExposed, + &pWin->borderClip, &pWin->winSize); + REGION_SUBTRACT(pScreen, &pWin->valdata->after.borderExposed, + &pWin->valdata->after.borderExposed, pValid->over); + } + + if(pTree && pTree->valdata) { + REGION_SUBTRACT(pScreen, &pTree->valdata->exposed, + &pTree->clipList, pValid->under); + REGION_SUBTRACT(pScreen, &pTree->valdata->borderExposed, + &pTree->borderClip, &pWin->winSize); + REGION_SUBTRACT(pScreen, &pTree->valdata->borderExposed, + &pTree->valdata->borderExposed, pValid->under); + } else if (!pWin->valdata) + return WT_NOMATCH; + + return WT_WALKCHILDREN; +} + +static void +miOverlayResizeWindow( + WindowPtr pWin, + int x, int y, + unsigned int w, unsigned int h, + WindowPtr pSib +){ + ScreenPtr pScreen = pWin->drawable.pScreen; + WindowPtr pParent; + miOverlayTreePtr tChild, pTree; + Bool WasViewable = (Bool)(pWin->viewable); + unsigned short width = pWin->drawable.width; + unsigned short height = pWin->drawable.height; + short oldx = pWin->drawable.x; + short oldy = pWin->drawable.y; + int bw = wBorderWidth (pWin); + short dw, dh; + DDXPointRec oldpt; + RegionPtr oldRegion = NULL, oldRegion2 = NULL; + WindowPtr pFirstChange; + register WindowPtr pChild; + RegionPtr gravitate[StaticGravity + 1]; + RegionPtr gravitate2[StaticGravity + 1]; + register unsigned g; + int nx, ny; /* destination x,y */ + int newx, newy; /* new inner window position */ + RegionPtr pRegion = NULL; + RegionPtr destClip, destClip2; + RegionPtr oldWinClip = NULL, oldWinClip2 = NULL; + RegionPtr borderVisible = NullRegion; + RegionPtr borderVisible2 = NullRegion; + RegionPtr bsExposed = NullRegion; /* backing store exposures */ + Bool shrunk = FALSE; /* shrunk in an inner dimension */ + Bool moved = FALSE; /* window position changed */ +#ifdef DO_SAVE_UNDERS + Bool dosave = FALSE; +#endif + Bool doUnderlay; + + /* if this is a root window, can't be resized */ + if (!(pParent = pWin->parent)) + return ; + + pTree = MIOVERLAY_GET_WINDOW_TREE(pWin); + doUnderlay = ((pTree) || HasUnderlayChildren(pWin)); + newx = pParent->drawable.x + x + bw; + newy = pParent->drawable.y + y + bw; + if (WasViewable) + { + /* + * save the visible region of the window + */ + oldRegion = REGION_CREATE(pScreen, NullBox, 1); + REGION_COPY(pScreen, oldRegion, &pWin->winSize); + if(doUnderlay) { + oldRegion2 = REGION_CREATE(pScreen, NullBox, 1); + REGION_COPY(pScreen, oldRegion2, &pWin->winSize); + } + + /* + * categorize child windows into regions to be moved + */ + for (g = 0; g <= StaticGravity; g++) + gravitate[g] = gravitate2[g] = NULL; + for (pChild = pWin->firstChild; pChild; pChild = pChild->nextSib) { + g = pChild->winGravity; + if (g != UnmapGravity) { + if (!gravitate[g]) + gravitate[g] = REGION_CREATE(pScreen, NullBox, 1); + REGION_UNION(pScreen, gravitate[g], + gravitate[g], &pChild->borderClip); + + if(doUnderlay) { + if (!gravitate2[g]) + gravitate2[g] = REGION_CREATE(pScreen, NullBox, 0); + + if((tChild = MIOVERLAY_GET_WINDOW_TREE(pChild))) { + REGION_UNION(pScreen, gravitate2[g], + gravitate2[g], &tChild->borderClip); + } else + CollectUnderlayChildrenRegions(pChild, gravitate2[g]); + } + } else { + UnmapWindow(pChild, TRUE); + } + } + (*pScreen->MarkOverlappedWindows)(pWin, pWin, NULL); + + + oldWinClip = oldWinClip2 = NULL; + if (pWin->bitGravity != ForgetGravity) { + oldWinClip = REGION_CREATE(pScreen, NullBox, 1); + REGION_COPY(pScreen, oldWinClip, &pWin->clipList); + if(pTree) { + oldWinClip2 = REGION_CREATE(pScreen, NullBox, 1); + REGION_COPY(pScreen, oldWinClip2, &pTree->clipList); + } + } + /* + * if the window is changing size, borderExposed + * can't be computed correctly without some help. + */ + if (pWin->drawable.height > h || pWin->drawable.width > w) + shrunk = TRUE; + + if (newx != oldx || newy != oldy) + moved = TRUE; + + if ((pWin->drawable.height != h || pWin->drawable.width != w) && + HasBorder (pWin)) + { + borderVisible = REGION_CREATE(pScreen, NullBox, 1); + if(pTree) + borderVisible2 = REGION_CREATE(pScreen, NullBox, 1); + /* for tiled borders, we punt and draw the whole thing */ + if (pWin->borderIsPixel || !moved) + { + if (shrunk || moved) + REGION_SUBTRACT(pScreen, borderVisible, + &pWin->borderClip, + &pWin->winSize); + else + REGION_COPY(pScreen, borderVisible, + &pWin->borderClip); + if(pTree) { + if (shrunk || moved) + REGION_SUBTRACT(pScreen, borderVisible, + &pTree->borderClip, + &pWin->winSize); + else + REGION_COPY(pScreen, borderVisible, + &pTree->borderClip); + } + } + } + } + pWin->origin.x = x + bw; + pWin->origin.y = y + bw; + pWin->drawable.height = h; + pWin->drawable.width = w; + + x = pWin->drawable.x = newx; + y = pWin->drawable.y = newy; + + SetWinSize (pWin); + SetBorderSize (pWin); + + dw = (int)w - (int)width; + dh = (int)h - (int)height; + ResizeChildrenWinSize(pWin, x - oldx, y - oldy, dw, dh); + + /* let the hardware adjust background and border pixmaps, if any */ + (*pScreen->PositionWindow)(pWin, x, y); + + pFirstChange = MoveWindowInStack(pWin, pSib); + + if (WasViewable) { + pRegion = REGION_CREATE(pScreen, NullBox, 1); + if (pWin->backStorage) + REGION_COPY(pScreen, pRegion, &pWin->clipList); + + (*pScreen->MarkOverlappedWindows)(pWin, pFirstChange, NULL); + + pWin->valdata->before.resized = TRUE; + pWin->valdata->before.borderVisible = borderVisible; + if(pTree) + pTree->valdata->borderVisible = borderVisible2; + +#ifdef DO_SAVE_UNDERS + if (DO_SAVE_UNDERS(pWin)) + dosave = (*pScreen->ChangeSaveUnder)(pWin, pFirstChange); +#endif /* DO_SAVE_UNDERS */ + + (*pScreen->ValidateTree)(pWin->parent, pFirstChange, VTOther); + /* + * the entire window is trashed unless bitGravity + * recovers portions of it + */ + REGION_COPY(pScreen, &pWin->valdata->after.exposed, &pWin->clipList); + if(pTree) + REGION_COPY(pScreen, &pTree->valdata->exposed, &pTree->clipList); + } + + GravityTranslate (x, y, oldx, oldy, dw, dh, pWin->bitGravity, &nx, &ny); + + if (pWin->backStorage && ((pWin->backingStore == Always) || WasViewable)) { + if (!WasViewable) + pRegion = &pWin->clipList; /* a convenient empty region */ + if (pWin->bitGravity == ForgetGravity) + bsExposed = (*pScreen->TranslateBackingStore) + (pWin, 0, 0, NullRegion, oldx, oldy); + else + bsExposed = (*pScreen->TranslateBackingStore) + (pWin, nx - x, ny - y, pRegion, oldx, oldy); + } + + if (WasViewable) { + miOverlayScreenPtr pPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen); + miOverlayTwoRegions TwoRegions; + + /* avoid the border */ + if (HasBorder (pWin)) { + int offx, offy, dx, dy; + + /* kruft to avoid double translates for each gravity */ + offx = 0; + offy = 0; + for (g = 0; g <= StaticGravity; g++) { + if (!gravitate[g] && !gravitate2[g]) + continue; + + /* align winSize to gravitate[g]. + * winSize is in new coordinates, + * gravitate[g] is still in old coordinates */ + GravityTranslate (x, y, oldx, oldy, dw, dh, g, &nx, &ny); + + dx = (oldx - nx) - offx; + dy = (oldy - ny) - offy; + if (dx || dy) { + REGION_TRANSLATE(pScreen, &pWin->winSize, dx, dy); + offx += dx; + offy += dy; + } + if(gravitate[g]) + REGION_INTERSECT(pScreen, gravitate[g], gravitate[g], + &pWin->winSize); + if(gravitate2[g]) + REGION_INTERSECT(pScreen, gravitate2[g], gravitate2[g], + &pWin->winSize); + } + /* get winSize back where it belongs */ + if (offx || offy) + REGION_TRANSLATE(pScreen, &pWin->winSize, -offx, -offy); + } + /* + * add screen bits to the appropriate bucket + */ + + if (oldWinClip2) + { + REGION_COPY(pScreen, pRegion, oldWinClip2); + REGION_TRANSLATE(pScreen, pRegion, nx - oldx, ny - oldy); + REGION_INTERSECT(pScreen, oldWinClip2, pRegion, &pTree->clipList); + + for (g = pWin->bitGravity + 1; g <= StaticGravity; g++) { + if (gravitate2[g]) + REGION_SUBTRACT(pScreen, oldWinClip2, oldWinClip2, + gravitate2[g]); + } + REGION_TRANSLATE(pScreen, oldWinClip2, oldx - nx, oldy - ny); + g = pWin->bitGravity; + if (!gravitate2[g]) + gravitate2[g] = oldWinClip2; + else { + REGION_UNION(pScreen,gravitate2[g],gravitate2[g],oldWinClip2); + REGION_DESTROY(pScreen, oldWinClip2); + } + } + + if (oldWinClip) + { + /* + * clip to new clipList + */ + REGION_COPY(pScreen, pRegion, oldWinClip); + REGION_TRANSLATE(pScreen, pRegion, nx - oldx, ny - oldy); + REGION_INTERSECT(pScreen, oldWinClip, pRegion, &pWin->clipList); + /* + * don't step on any gravity bits which will be copied after this + * region. Note -- this assumes that the regions will be copied + * in gravity order. + */ + for (g = pWin->bitGravity + 1; g <= StaticGravity; g++) { + if (gravitate[g]) + REGION_SUBTRACT(pScreen, oldWinClip, oldWinClip, + gravitate[g]); + } + REGION_TRANSLATE(pScreen, oldWinClip, oldx - nx, oldy - ny); + g = pWin->bitGravity; + if (!gravitate[g]) + gravitate[g] = oldWinClip; + else { + REGION_UNION(pScreen, gravitate[g], gravitate[g], oldWinClip); + REGION_DESTROY(pScreen, oldWinClip); + } + } + + /* + * move the bits on the screen + */ + + destClip = destClip2 = NULL; + + for (g = 0; g <= StaticGravity; g++) { + if (!gravitate[g] && !gravitate2[g]) + continue; + + GravityTranslate (x, y, oldx, oldy, dw, dh, g, &nx, &ny); + + oldpt.x = oldx + (x - nx); + oldpt.y = oldy + (y - ny); + + /* Note that gravitate[g] is *translated* by CopyWindow */ + + /* only copy the remaining useful bits */ + + if(gravitate[g]) + REGION_INTERSECT(pScreen, gravitate[g], + gravitate[g], oldRegion); + if(gravitate2[g]) + REGION_INTERSECT(pScreen, gravitate2[g], + gravitate2[g], oldRegion2); + + /* clip to not overwrite already copied areas */ + + if (destClip && gravitate[g]) { + REGION_TRANSLATE(pScreen, destClip, oldpt.x - x, oldpt.y - y); + REGION_SUBTRACT(pScreen, gravitate[g], gravitate[g], destClip); + REGION_TRANSLATE(pScreen, destClip, x - oldpt.x, y - oldpt.y); + } + if (destClip2 && gravitate2[g]) { + REGION_TRANSLATE(pScreen, destClip2, oldpt.x - x, oldpt.y - y); + REGION_SUBTRACT(pScreen,gravitate2[g],gravitate2[g],destClip2); + REGION_TRANSLATE(pScreen, destClip2, x - oldpt.x, y - oldpt.y); + } + + /* and move those bits */ + + if (oldpt.x != x || oldpt.y != y) { + if(gravitate2[g]) { + pPriv->copyUnderlay = TRUE; + (*pWin->drawable.pScreen->CopyWindow)( + pWin, oldpt, gravitate2[g]); + } + if(gravitate[g]) { + pPriv->copyUnderlay = FALSE; + (*pWin->drawable.pScreen->CopyWindow)( + pWin, oldpt, gravitate[g]); + } + } + + /* remove any overwritten bits from the remaining useful bits */ + + if(gravitate[g]) + REGION_SUBTRACT(pScreen, oldRegion, oldRegion, gravitate[g]); + if(gravitate2[g]) + REGION_SUBTRACT(pScreen, oldRegion2, oldRegion2, gravitate2[g]); + + /* + * recompute exposed regions of child windows + */ + + + for (pChild = pWin->firstChild; pChild; pChild = pChild->nextSib) { + if (pChild->winGravity != g) + continue; + + TwoRegions.over = gravitate[g]; + TwoRegions.under = gravitate2[g]; + + TraverseTree (pChild, miOverlayRecomputeExposures, + (pointer)(&TwoRegions)); + } + + /* + * remove the successfully copied regions of the + * window from its exposed region + */ + + if (g == pWin->bitGravity) { + if(gravitate[g]) + REGION_SUBTRACT(pScreen, &pWin->valdata->after.exposed, + &pWin->valdata->after.exposed, gravitate[g]); + if(gravitate2[g] && pTree) + REGION_SUBTRACT(pScreen, &pTree->valdata->exposed, + &pTree->valdata->exposed, gravitate2[g]); + } + if(gravitate[g]) { + if (!destClip) + destClip = gravitate[g]; + else { + REGION_UNION(pScreen, destClip, destClip, gravitate[g]); + REGION_DESTROY(pScreen, gravitate[g]); + } + } + if(gravitate2[g]) { + if (!destClip2) + destClip2 = gravitate2[g]; + else { + REGION_UNION(pScreen, destClip2, destClip2, gravitate2[g]); + REGION_DESTROY(pScreen, gravitate2[g]); + } + } + } + + REGION_DESTROY(pScreen, pRegion); + REGION_DESTROY(pScreen, oldRegion); + if(doUnderlay) + REGION_DESTROY(pScreen, oldRegion2); + if (destClip) + REGION_DESTROY(pScreen, destClip); + if (destClip2) + REGION_DESTROY(pScreen, destClip2); + if (bsExposed) { + RegionPtr valExposed = NullRegion; + + if (pWin->valdata) + valExposed = &pWin->valdata->after.exposed; + (*pScreen->WindowExposures) (pWin, valExposed, bsExposed); + if (valExposed) + REGION_EMPTY(pScreen, valExposed); + REGION_DESTROY(pScreen, bsExposed); + } + (*pScreen->HandleExposures)(pWin->parent); +#ifdef DO_SAVE_UNDERS + if (dosave) + (*pScreen->PostChangeSaveUnder)(pWin, pFirstChange); +#endif /* DO_SAVE_UNDERS */ + if (pScreen->PostValidateTree) + (*pScreen->PostValidateTree)(pWin->parent, pFirstChange, VTOther); + } + else if (bsExposed) { + (*pScreen->WindowExposures) (pWin, NullRegion, bsExposed); + REGION_DESTROY(pScreen, bsExposed); + } + if (pWin->realized) + WindowsRestructured (); +} + + +#ifdef SHAPE +static void +miOverlaySetShape(WindowPtr pWin) +{ + Bool WasViewable = (Bool)(pWin->viewable); + ScreenPtr pScreen = pWin->drawable.pScreen; + RegionPtr pOldClip = NULL, bsExposed; +#ifdef DO_SAVE_UNDERS + Bool dosave = FALSE; +#endif + + if (WasViewable) { + (*pScreen->MarkOverlappedWindows)(pWin, pWin, NULL); + + if (HasBorder (pWin)) { + RegionPtr borderVisible; + + borderVisible = REGION_CREATE(pScreen, NullBox, 1); + REGION_SUBTRACT(pScreen, borderVisible, + &pWin->borderClip, &pWin->winSize); + pWin->valdata->before.borderVisible = borderVisible; + pWin->valdata->before.resized = TRUE; + if(IN_UNDERLAY(pWin)) { + miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin); + RegionPtr borderVisible2; + + borderVisible2 = REGION_CREATE(pScreen, NULL, 1); + REGION_SUBTRACT(pScreen, borderVisible2, + &pTree->borderClip, &pWin->winSize); + pTree->valdata->borderVisible = borderVisible2; + } + } + } + + SetWinSize (pWin); + SetBorderSize (pWin); + + ResizeChildrenWinSize(pWin, 0, 0, 0, 0); + + if (WasViewable) { + if (pWin->backStorage) { + pOldClip = REGION_CREATE(pScreen, NullBox, 1); + REGION_COPY(pScreen, pOldClip, &pWin->clipList); + } + + (*pScreen->MarkOverlappedWindows)(pWin, pWin, NULL); + +#ifdef DO_SAVE_UNDERS + if (DO_SAVE_UNDERS(pWin)) + dosave = (*pScreen->ChangeSaveUnder)(pWin, pWin); +#endif /* DO_SAVE_UNDERS */ + + (*pScreen->ValidateTree)(pWin->parent, NullWindow, VTOther); + } + + if (pWin->backStorage && ((pWin->backingStore == Always) || WasViewable)) { + if (!WasViewable) + pOldClip = &pWin->clipList; /* a convenient empty region */ + bsExposed = (*pScreen->TranslateBackingStore) + (pWin, 0, 0, pOldClip, + pWin->drawable.x, pWin->drawable.y); + if (WasViewable) + REGION_DESTROY(pScreen, pOldClip); + if (bsExposed) + { + RegionPtr valExposed = NullRegion; + + if (pWin->valdata) + valExposed = &pWin->valdata->after.exposed; + (*pScreen->WindowExposures) (pWin, valExposed, bsExposed); + if (valExposed) + REGION_EMPTY(pScreen, valExposed); + REGION_DESTROY(pScreen, bsExposed); + } + } + if (WasViewable) { + (*pScreen->HandleExposures)(pWin->parent); +#ifdef DO_SAVE_UNDERS + if (dosave) + (*pScreen->PostChangeSaveUnder)(pWin, pWin); +#endif /* DO_SAVE_UNDERS */ + if (pScreen->PostValidateTree) + (*pScreen->PostValidateTree)(pWin->parent, NullWindow, VTOther); + } + if (pWin->realized) + WindowsRestructured (); + CheckCursorConfinement(pWin); +} +#endif + + + +static void +miOverlayChangeBorderWidth( + WindowPtr pWin, + unsigned int width +){ + WindowPtr pParent; + int oldwidth; + register ScreenPtr pScreen; + Bool WasViewable = (Bool)(pWin->viewable); + Bool HadBorder; +#ifdef DO_SAVE_UNDERS + Bool dosave = FALSE; +#endif + + oldwidth = wBorderWidth (pWin); + if (oldwidth == width) + return; + HadBorder = HasBorder(pWin); + pScreen = pWin->drawable.pScreen; + pParent = pWin->parent; + if (WasViewable && (width < oldwidth)) + (*pScreen->MarkOverlappedWindows)(pWin, pWin, NULL); + + pWin->borderWidth = width; + SetBorderSize (pWin); + + if (WasViewable) { + if (width > oldwidth) { + (*pScreen->MarkOverlappedWindows)(pWin, pWin, NULL); + + if (HadBorder) { + RegionPtr borderVisible; + borderVisible = REGION_CREATE(pScreen, NULL, 1); + REGION_SUBTRACT(pScreen, borderVisible, + &pWin->borderClip, &pWin->winSize); + pWin->valdata->before.borderVisible = borderVisible; + if(IN_UNDERLAY(pWin)) { + miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin); + RegionPtr borderVisible2; + + borderVisible2 = REGION_CREATE(pScreen, NULL, 1); + REGION_SUBTRACT(pScreen, borderVisible2, + &pTree->borderClip, &pWin->winSize); + pTree->valdata->borderVisible = borderVisible2; + } + } + } +#ifdef DO_SAVE_UNDERS + if (DO_SAVE_UNDERS(pWin)) + dosave = (*pScreen->ChangeSaveUnder)(pWin, pWin->nextSib); +#endif /* DO_SAVE_UNDERS */ + (*pScreen->ValidateTree)(pWin->parent, pWin, VTOther); + (*pScreen->HandleExposures)(pWin->parent); + +#ifdef DO_SAVE_UNDERS + if (dosave) + (*pScreen->PostChangeSaveUnder)(pWin, pWin->nextSib); +#endif /* DO_SAVE_UNDERS */ + if (pScreen->PostValidateTree) + (*pScreen->PostValidateTree)(pWin->parent, pWin, VTOther); + } + if (pWin->realized) + WindowsRestructured (); +} + +/* We need this as an addition since the xf86 common code doesn't + know about the second tree which is static to this file. */ + +void +miOverlaySetRootClip(ScreenPtr pScreen, Bool enable) +{ + WindowPtr pRoot = WindowTable[pScreen->myNum]; + miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pRoot); + + MARK_UNDERLAY(pRoot); + + if(enable) { + BoxRec box; + + box.x1 = 0; + box.y1 = 0; + box.x2 = pScreen->width; + box.y2 = pScreen->height; + + REGION_RESET(pScreen, &pTree->borderClip, &box); + } else + REGION_EMPTY(pScreen, &pTree->borderClip); + + REGION_BREAK(pScreen, &pTree->clipList); +} + +static void +miOverlayClearToBackground( + WindowPtr pWin, + int x, int y, + int w, int h, + Bool generateExposures +) +{ + miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin); + BoxRec box; + RegionRec reg; + RegionPtr pBSReg = NullRegion; + ScreenPtr pScreen = pWin->drawable.pScreen; + miOverlayScreenPtr pScreenPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen); + RegionPtr clipList; + BoxPtr extents; + int x1, y1, x2, y2; + + x1 = pWin->drawable.x + x; + y1 = pWin->drawable.y + y; + if (w) + x2 = x1 + (int) w; + else + x2 = x1 + (int) pWin->drawable.width - (int) x; + if (h) + y2 = y1 + h; + else + y2 = y1 + (int) pWin->drawable.height - (int) y; + + clipList = ((*pScreenPriv->InOverlay)(pWin)) ? &pWin->clipList : + &pTree->clipList; + + extents = REGION_EXTENTS(pScreen, clipList); + + if (x1 < extents->x1) x1 = extents->x1; + if (x2 > extents->x2) x2 = extents->x2; + if (y1 < extents->y1) y1 = extents->y1; + if (y2 > extents->y2) y2 = extents->y2; + + if (x2 <= x1 || y2 <= y1) + x2 = x1 = y2 = y1 = 0; + + box.x1 = x1; box.x2 = x2; + box.y1 = y1; box.y2 = y2; + + REGION_INIT(pScreen, ®, &box, 1); + if (pWin->backStorage) { + pBSReg = (* pScreen->ClearBackingStore)(pWin, x, y, w, h, + generateExposures); + } + + REGION_INTERSECT(pScreen, ®, ®, clipList); + if (generateExposures) + (*pScreen->WindowExposures)(pWin, ®, pBSReg); + else if (pWin->backgroundState != None) + (*pScreen->PaintWindowBackground)(pWin, ®, PW_BACKGROUND); + REGION_UNINIT(pScreen, ®); + if (pBSReg) + REGION_DESTROY(pScreen, pBSReg); +} + + +/****************************************************************/ + +/* not used */ +Bool +miOverlayGetPrivateClips( + WindowPtr pWin, + RegionPtr *borderClip, + RegionPtr *clipList +){ + miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin); + + if(pTree) { + *borderClip = &(pTree->borderClip); + *clipList = &(pTree->clipList); + return TRUE; + } + + *borderClip = *clipList = NULL; + + return FALSE; +} + +void +miOverlaySetTransFunction ( + ScreenPtr pScreen, + miOverlayTransFunc transFunc +){ + MIOVERLAY_GET_SCREEN_PRIVATE(pScreen)->MakeTransparent = transFunc; +} + +Bool +miOverlayCopyUnderlay(ScreenPtr pScreen) +{ + return MIOVERLAY_GET_SCREEN_PRIVATE(pScreen)->copyUnderlay; +} + +void +miOverlayComputeCompositeClip(GCPtr pGC, WindowPtr pWin) +{ + ScreenPtr pScreen = pGC->pScreen; + miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin); + RegionPtr pregWin; + Bool freeTmpClip, freeCompClip; + + if(!pTree) { + miComputeCompositeClip(pGC, &pWin->drawable); + return; + } + + if (pGC->subWindowMode == IncludeInferiors) { + pregWin = REGION_CREATE(pScreen, NullBox, 1); + freeTmpClip = TRUE; + if (pWin->parent || (screenIsSaved != SCREEN_SAVER_ON) || + !HasSaverWindow (pScreen->myNum)) + { + REGION_INTERSECT(pScreen,pregWin,&pTree->borderClip,&pWin->winSize); + } + } else { + pregWin = &pTree->clipList; + freeTmpClip = FALSE; + } + freeCompClip = pGC->freeCompClip; + if (pGC->clientClipType == CT_NONE) { + if (freeCompClip) + REGION_DESTROY(pScreen, pGC->pCompositeClip); + pGC->pCompositeClip = pregWin; + pGC->freeCompClip = freeTmpClip; + } else { + REGION_TRANSLATE(pScreen, pGC->clientClip, + pWin->drawable.x + pGC->clipOrg.x, + pWin->drawable.y + pGC->clipOrg.y); + + if (freeCompClip) { + REGION_INTERSECT(pGC->pScreen, pGC->pCompositeClip, + pregWin, pGC->clientClip); + if (freeTmpClip) + REGION_DESTROY(pScreen, pregWin); + } else if (freeTmpClip) { + REGION_INTERSECT(pScreen, pregWin, pregWin, pGC->clientClip); + pGC->pCompositeClip = pregWin; + } else { + pGC->pCompositeClip = REGION_CREATE(pScreen, NullBox, 0); + REGION_INTERSECT(pScreen, pGC->pCompositeClip, + pregWin, pGC->clientClip); + } + pGC->freeCompClip = TRUE; + REGION_TRANSLATE(pScreen, pGC->clientClip, + -(pWin->drawable.x + pGC->clipOrg.x), + -(pWin->drawable.y + pGC->clipOrg.y)); + } +} + +Bool +miOverlayCollectUnderlayRegions( + WindowPtr pWin, + RegionPtr *region +){ + miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin); + + if(pTree) { + *region = &pTree->borderClip; + return FALSE; + } + + *region = REGION_CREATE(pWin->drawable.pScreen, NullBox, 0); + + CollectUnderlayChildrenRegions(pWin, *region); + + return TRUE; +} + + +static miOverlayTreePtr +DoLeaf( + WindowPtr pWin, + miOverlayTreePtr parent, + miOverlayTreePtr prevSib +){ + miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin); + + pTree->parent = parent; + pTree->firstChild = NULL; + pTree->lastChild = NULL; + pTree->prevSib = prevSib; + pTree->nextSib = NULL; + + if(prevSib) + prevSib->nextSib = pTree; + + if(!parent->firstChild) + parent->firstChild = parent->lastChild = pTree; + else if(parent->lastChild == prevSib) + parent->lastChild = pTree; + + return pTree; +} + +static void +RebuildTree(WindowPtr pWin) +{ + miOverlayTreePtr parent, prevSib, tChild; + WindowPtr pChild; + + prevSib = tChild = NULL; + + pWin = pWin->parent; + + while(IN_OVERLAY(pWin)) + pWin = pWin->parent; + + parent = MIOVERLAY_GET_WINDOW_TREE(pWin); + + pChild = pWin->firstChild; + parent->firstChild = parent->lastChild = NULL; + + while(1) { + if(IN_UNDERLAY(pChild)) + prevSib = tChild = DoLeaf(pChild, parent, prevSib); + + if(pChild->firstChild) { + if(IN_UNDERLAY(pChild)) { + parent = tChild; + prevSib = NULL; + } + pChild = pChild->firstChild; + continue; + } + + while(!pChild->nextSib) { + pChild = pChild->parent; + if(pChild == pWin) return; + if(IN_UNDERLAY(pChild)) { + prevSib = tChild = MIOVERLAY_GET_WINDOW_TREE(pChild); + parent = tChild->parent; + } + } + + pChild = pChild->nextSib; + } +} + + +static Bool +HasUnderlayChildren(WindowPtr pWin) +{ + WindowPtr pChild; + + if(!(pChild = pWin->firstChild)) + return FALSE; + + while(1) { + if(IN_UNDERLAY(pChild)) + return TRUE; + + if(pChild->firstChild) { + pChild = pChild->firstChild; + continue; + } + + while(!pChild->nextSib && (pWin != pChild)) + pChild = pChild->parent; + + if(pChild == pWin) break; + + pChild = pChild->nextSib; + } + + return FALSE; +} + + +static Bool +CollectUnderlayChildrenRegions(WindowPtr pWin, RegionPtr pReg) +{ + WindowPtr pChild; + miOverlayTreePtr pTree; + Bool hasUnderlay; + + if(!(pChild = pWin->firstChild)) + return FALSE; + + hasUnderlay = FALSE; + + while(1) { + if((pTree = MIOVERLAY_GET_WINDOW_TREE(pChild))) { + REGION_APPEND(pScreen, pReg, &pTree->borderClip); + hasUnderlay = TRUE; + } else + if(pChild->firstChild) { + pChild = pChild->firstChild; + continue; + } + + while(!pChild->nextSib && (pWin != pChild)) + pChild = pChild->parent; + + if(pChild == pWin) break; + + pChild = pChild->nextSib; + } + + if(hasUnderlay) { + Bool overlap; + REGION_VALIDATE(pScreen, pReg, &overlap); + } + + return hasUnderlay; +} + + +static void +MarkUnderlayWindow(WindowPtr pWin) +{ + miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin); + + if(pTree->valdata) return; + pTree->valdata = (miOverlayValDataPtr)xnfalloc(sizeof(miOverlayValDataRec)); + pTree->valdata->oldAbsCorner.x = pWin->drawable.x; + pTree->valdata->oldAbsCorner.y = pWin->drawable.y; + pTree->valdata->borderVisible = NullRegion; +} diff --git a/mi/mioverlay.h b/mi/mioverlay.h new file mode 100644 index 000000000..6098f9c39 --- /dev/null +++ b/mi/mioverlay.h @@ -0,0 +1,29 @@ +/* $XFree86: xc/programs/Xserver/mi/mioverlay.h,v 3.4 2001/04/14 21:15:26 mvojkovi Exp $ */ + +#ifndef __MIOVERLAY_H +#define __MIOVERLAY_H + +typedef void (*miOverlayTransFunc)(ScreenPtr, int, BoxPtr); +typedef Bool (*miOverlayInOverlayFunc)(WindowPtr); + +Bool +miInitOverlay( + ScreenPtr pScreen, + miOverlayInOverlayFunc inOverlay, + miOverlayTransFunc trans +); + +Bool +miOverlayGetPrivateClips( + WindowPtr pWin, + RegionPtr *borderClip, + RegionPtr *clipList +); + +Bool miOverlayCollectUnderlayRegions(WindowPtr, RegionPtr*); +void miOverlayComputeCompositeClip(GCPtr, WindowPtr); +Bool miOverlayCopyUnderlay(ScreenPtr); +void miOverlaySetTransFunction(ScreenPtr, miOverlayTransFunc); +void miOverlaySetRootClip(ScreenPtr, Bool); + +#endif /* __MIOVERLAY_H */ diff --git a/mi/mizerclip.c b/mi/mizerclip.c new file mode 100644 index 000000000..fa1863b54 --- /dev/null +++ b/mi/mizerclip.c @@ -0,0 +1,632 @@ +/* $XFree86: xc/programs/Xserver/mi/mizerclip.c,v 1.3 2001/12/14 20:00:29 dawes Exp $ */ +/*********************************************************** + +Copyright 1987, 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. + + +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ +#include "X.h" + +#include "misc.h" +#include "scrnintstr.h" +#include "gcstruct.h" +#include "windowstr.h" +#include "pixmap.h" +#include "mi.h" +#include "miline.h" + +/* + +The bresenham error equation used in the mi/mfb/cfb line routines is: + + e = error + dx = difference in raw X coordinates + dy = difference in raw Y coordinates + M = # of steps in X direction + N = # of steps in Y direction + B = 0 to prefer diagonal steps in a given octant, + 1 to prefer axial steps in a given octant + + For X major lines: + e = 2Mdy - 2Ndx - dx - B + -2dx <= e < 0 + + For Y major lines: + e = 2Ndx - 2Mdy - dy - B + -2dy <= e < 0 + +At the start of the line, we have taken 0 X steps and 0 Y steps, +so M = 0 and N = 0: + + X major e = 2Mdy - 2Ndx - dx - B + = -dx - B + + Y major e = 2Ndx - 2Mdy - dy - B + = -dy - B + +At the end of the line, we have taken dx X steps and dy Y steps, +so M = dx and N = dy: + + X major e = 2Mdy - 2Ndx - dx - B + = 2dxdy - 2dydx - dx - B + = -dx - B + Y major e = 2Ndx - 2Mdy - dy - B + = 2dydx - 2dxdy - dy - B + = -dy - B + +Thus, the error term is the same at the start and end of the line. + +Let us consider clipping an X coordinate. There are 4 cases which +represent the two independent cases of clipping the start vs. the +end of the line and an X major vs. a Y major line. In any of these +cases, we know the number of X steps (M) and we wish to find the +number of Y steps (N). Thus, we will solve our error term equation. +If we are clipping the start of the line, we will find the smallest +N that satisfies our error term inequality. If we are clipping the +end of the line, we will find the largest number of Y steps that +satisfies the inequality. In that case, since we are representing +the Y steps as (dy - N), we will actually want to solve for the +smallest N in that equation. + +Case 1: X major, starting X coordinate moved by M steps + + -2dx <= 2Mdy - 2Ndx - dx - B < 0 + 2Ndx <= 2Mdy - dx - B + 2dx 2Ndx > 2Mdy - dx - B + 2Ndx <= 2Mdy + dx - B N > (2Mdy - dx - B) / 2dx + N <= (2Mdy + dx - B) / 2dx + +Since we are trying to find the smallest N that satisfies these +equations, we should use the > inequality to find the smallest: + + N = floor((2Mdy - dx - B) / 2dx) + 1 + = floor((2Mdy - dx - B + 2dx) / 2dx) + = floor((2Mdy + dx - B) / 2dx) + +Case 1b: X major, ending X coordinate moved to M steps + +Same derivations as Case 1, but we want the largest N that satisfies +the equations, so we use the <= inequality: + + N = floor((2Mdy + dx - B) / 2dx) + +Case 2: X major, ending X coordinate moved by M steps + + -2dx <= 2(dx - M)dy - 2(dy - N)dx - dx - B < 0 + -2dx <= 2dxdy - 2Mdy - 2dxdy + 2Ndx - dx - B < 0 + -2dx <= 2Ndx - 2Mdy - dx - B < 0 + 2Ndx >= 2Mdy + dx + B - 2dx 2Ndx < 2Mdy + dx + B + 2Ndx >= 2Mdy - dx + B N < (2Mdy + dx + B) / 2dx + N >= (2Mdy - dx + B) / 2dx + +Since we are trying to find the highest number of Y steps that +satisfies these equations, we need to find the smallest N, so +we should use the >= inequality to find the smallest: + + N = ceiling((2Mdy - dx + B) / 2dx) + = floor((2Mdy - dx + B + 2dx - 1) / 2dx) + = floor((2Mdy + dx + B - 1) / 2dx) + +Case 2b: X major, starting X coordinate moved to M steps from end + +Same derivations as Case 2, but we want the smallest number of Y +steps, so we want the highest N, so we use the < inequality: + + N = ceiling((2Mdy + dx + B) / 2dx) - 1 + = floor((2Mdy + dx + B + 2dx - 1) / 2dx) - 1 + = floor((2Mdy + dx + B + 2dx - 1 - 2dx) / 2dx) + = floor((2Mdy + dx + B - 1) / 2dx) + +Case 3: Y major, starting X coordinate moved by M steps + + -2dy <= 2Ndx - 2Mdy - dy - B < 0 + 2Ndx >= 2Mdy + dy + B - 2dy 2Ndx < 2Mdy + dy + B + 2Ndx >= 2Mdy - dy + B N < (2Mdy + dy + B) / 2dx + N >= (2Mdy - dy + B) / 2dx + +Since we are trying to find the smallest N that satisfies these +equations, we should use the >= inequality to find the smallest: + + N = ceiling((2Mdy - dy + B) / 2dx) + = floor((2Mdy - dy + B + 2dx - 1) / 2dx) + = floor((2Mdy - dy + B - 1) / 2dx) + 1 + +Case 3b: Y major, ending X coordinate moved to M steps + +Same derivations as Case 3, but we want the largest N that satisfies +the equations, so we use the < inequality: + + N = ceiling((2Mdy + dy + B) / 2dx) - 1 + = floor((2Mdy + dy + B + 2dx - 1) / 2dx) - 1 + = floor((2Mdy + dy + B + 2dx - 1 - 2dx) / 2dx) + = floor((2Mdy + dy + B - 1) / 2dx) + +Case 4: Y major, ending X coordinate moved by M steps + + -2dy <= 2(dy - N)dx - 2(dx - M)dy - dy - B < 0 + -2dy <= 2dxdy - 2Ndx - 2dxdy + 2Mdy - dy - B < 0 + -2dy <= 2Mdy - 2Ndx - dy - B < 0 + 2Ndx <= 2Mdy - dy - B + 2dy 2Ndx > 2Mdy - dy - B + 2Ndx <= 2Mdy + dy - B N > (2Mdy - dy - B) / 2dx + N <= (2Mdy + dy - B) / 2dx + +Since we are trying to find the highest number of Y steps that +satisfies these equations, we need to find the smallest N, so +we should use the > inequality to find the smallest: + + N = floor((2Mdy - dy - B) / 2dx) + 1 + +Case 4b: Y major, starting X coordinate moved to M steps from end + +Same analysis as Case 4, but we want the smallest number of Y steps +which means the largest N, so we use the <= inequality: + + N = floor((2Mdy + dy - B) / 2dx) + +Now let's try the Y coordinates, we have the same 4 cases. + +Case 5: X major, starting Y coordinate moved by N steps + + -2dx <= 2Mdy - 2Ndx - dx - B < 0 + 2Mdy >= 2Ndx + dx + B - 2dx 2Mdy < 2Ndx + dx + B + 2Mdy >= 2Ndx - dx + B M < (2Ndx + dx + B) / 2dy + M >= (2Ndx - dx + B) / 2dy + +Since we are trying to find the smallest M, we use the >= inequality: + + M = ceiling((2Ndx - dx + B) / 2dy) + = floor((2Ndx - dx + B + 2dy - 1) / 2dy) + = floor((2Ndx - dx + B - 1) / 2dy) + 1 + +Case 5b: X major, ending Y coordinate moved to N steps + +Same derivations as Case 5, but we want the largest M that satisfies +the equations, so we use the < inequality: + + M = ceiling((2Ndx + dx + B) / 2dy) - 1 + = floor((2Ndx + dx + B + 2dy - 1) / 2dy) - 1 + = floor((2Ndx + dx + B + 2dy - 1 - 2dy) / 2dy) + = floor((2Ndx + dx + B - 1) / 2dy) + +Case 6: X major, ending Y coordinate moved by N steps + + -2dx <= 2(dx - M)dy - 2(dy - N)dx - dx - B < 0 + -2dx <= 2dxdy - 2Mdy - 2dxdy + 2Ndx - dx - B < 0 + -2dx <= 2Ndx - 2Mdy - dx - B < 0 + 2Mdy <= 2Ndx - dx - B + 2dx 2Mdy > 2Ndx - dx - B + 2Mdy <= 2Ndx + dx - B M > (2Ndx - dx - B) / 2dy + M <= (2Ndx + dx - B) / 2dy + +Largest # of X steps means smallest M, so use the > inequality: + + M = floor((2Ndx - dx - B) / 2dy) + 1 + +Case 6b: X major, starting Y coordinate moved to N steps from end + +Same derivations as Case 6, but we want the smallest # of X steps +which means the largest M, so use the <= inequality: + + M = floor((2Ndx + dx - B) / 2dy) + +Case 7: Y major, starting Y coordinate moved by N steps + + -2dy <= 2Ndx - 2Mdy - dy - B < 0 + 2Mdy <= 2Ndx - dy - B + 2dy 2Mdy > 2Ndx - dy - B + 2Mdy <= 2Ndx + dy - B M > (2Ndx - dy - B) / 2dy + M <= (2Ndx + dy - B) / 2dy + +To find the smallest M, use the > inequality: + + M = floor((2Ndx - dy - B) / 2dy) + 1 + = floor((2Ndx - dy - B + 2dy) / 2dy) + = floor((2Ndx + dy - B) / 2dy) + +Case 7b: Y major, ending Y coordinate moved to N steps + +Same derivations as Case 7, but we want the largest M that satisfies +the equations, so use the <= inequality: + + M = floor((2Ndx + dy - B) / 2dy) + +Case 8: Y major, ending Y coordinate moved by N steps + + -2dy <= 2(dy - N)dx - 2(dx - M)dy - dy - B < 0 + -2dy <= 2dxdy - 2Ndx - 2dxdy + 2Mdy - dy - B < 0 + -2dy <= 2Mdy - 2Ndx - dy - B < 0 + 2Mdy >= 2Ndx + dy + B - 2dy 2Mdy < 2Ndx + dy + B + 2Mdy >= 2Ndx - dy + B M < (2Ndx + dy + B) / 2dy + M >= (2Ndx - dy + B) / 2dy + +To find the highest X steps, find the smallest M, use the >= inequality: + + M = ceiling((2Ndx - dy + B) / 2dy) + = floor((2Ndx - dy + B + 2dy - 1) / 2dy) + = floor((2Ndx + dy + B - 1) / 2dy) + +Case 8b: Y major, starting Y coordinate moved to N steps from the end + +Same derivations as Case 8, but we want to find the smallest # of X +steps which means the largest M, so we use the < inequality: + + M = ceiling((2Ndx + dy + B) / 2dy) - 1 + = floor((2Ndx + dy + B + 2dy - 1) / 2dy) - 1 + = floor((2Ndx + dy + B + 2dy - 1 - 2dy) / 2dy) + = floor((2Ndx + dy + B - 1) / 2dy) + +So, our equations are: + + 1: X major move x1 to x1+M floor((2Mdy + dx - B) / 2dx) + 1b: X major move x2 to x1+M floor((2Mdy + dx - B) / 2dx) + 2: X major move x2 to x2-M floor((2Mdy + dx + B - 1) / 2dx) + 2b: X major move x1 to x2-M floor((2Mdy + dx + B - 1) / 2dx) + + 3: Y major move x1 to x1+M floor((2Mdy - dy + B - 1) / 2dx) + 1 + 3b: Y major move x2 to x1+M floor((2Mdy + dy + B - 1) / 2dx) + 4: Y major move x2 to x2-M floor((2Mdy - dy - B) / 2dx) + 1 + 4b: Y major move x1 to x2-M floor((2Mdy + dy - B) / 2dx) + + 5: X major move y1 to y1+N floor((2Ndx - dx + B - 1) / 2dy) + 1 + 5b: X major move y2 to y1+N floor((2Ndx + dx + B - 1) / 2dy) + 6: X major move y2 to y2-N floor((2Ndx - dx - B) / 2dy) + 1 + 6b: X major move y1 to y2-N floor((2Ndx + dx - B) / 2dy) + + 7: Y major move y1 to y1+N floor((2Ndx + dy - B) / 2dy) + 7b: Y major move y2 to y1+N floor((2Ndx + dy - B) / 2dy) + 8: Y major move y2 to y2-N floor((2Ndx + dy + B - 1) / 2dy) + 8b: Y major move y1 to y2-N floor((2Ndx + dy + B - 1) / 2dy) + +We have the following constraints on all of the above terms: + + 0 < M,N <= 2^15 2^15 can be imposed by miZeroClipLine + 0 <= dx/dy <= 2^16 - 1 + 0 <= B <= 1 + +The floor in all of the above equations can be accomplished with a +simple C divide operation provided that both numerator and denominator +are positive. + +Since dx,dy >= 0 and since moving an X coordinate implies that dx != 0 +and moving a Y coordinate implies dy != 0, we know that the denominators +are all > 0. + +For all lines, (-B) and (B-1) are both either 0 or -1, depending on the +bias. Thus, we have to show that the 2MNdxy +/- dxy terms are all >= 1 +or > 0 to prove that the numerators are positive (or zero). + +For X Major lines we know that dx > 0 and since 2Mdy is >= 0 due to the +constraints, the first four equations all have numerators >= 0. + +For the second four equations, M > 0, so 2Mdy >= 2dy so (2Mdy - dy) >= dy +So (2Mdy - dy) > 0, since they are Y major lines. Also, (2Mdy + dy) >= 3dy +or (2Mdy + dy) > 0. So all of their numerators are >= 0. + +For the third set of four equations, N > 0, so 2Ndx >= 2dx so (2Ndx - dx) +>= dx > 0. Similarly (2Ndx + dx) >= 3dx > 0. So all numerators >= 0. + +For the fourth set of equations, dy > 0 and 2Ndx >= 0, so all numerators +are > 0. + +To consider overflow, consider the case of 2 * M,N * dx,dy + dx,dy. This +is bounded <= 2 * 2^15 * (2^16 - 1) + (2^16 - 1) + <= 2^16 * (2^16 - 1) + (2^16 - 1) + <= 2^32 - 2^16 + 2^16 - 1 + <= 2^32 - 1 +Since the (-B) and (B-1) terms are all 0 or -1, the maximum value of +the numerator is therefore (2^32 - 1), which does not overflow an unsigned +32 bit variable. + +*/ + +/* Bit codes for the terms of the 16 clipping equations defined below. */ + +#define T_2NDX (1 << 0) +#define T_2MDY (0) /* implicit term */ +#define T_DXNOTY (1 << 1) +#define T_DYNOTX (0) /* implicit term */ +#define T_SUBDXORY (1 << 2) +#define T_ADDDX (T_DXNOTY) /* composite term */ +#define T_SUBDX (T_DXNOTY | T_SUBDXORY) /* composite term */ +#define T_ADDDY (T_DYNOTX) /* composite term */ +#define T_SUBDY (T_DYNOTX | T_SUBDXORY) /* composite term */ +#define T_BIASSUBONE (1 << 3) +#define T_SUBBIAS (0) /* implicit term */ +#define T_DIV2DX (1 << 4) +#define T_DIV2DY (0) /* implicit term */ +#define T_ADDONE (1 << 5) + +/* Bit masks defining the 16 equations used in miZeroClipLine. */ + +#define EQN1 (T_2MDY | T_ADDDX | T_SUBBIAS | T_DIV2DX) +#define EQN1B (T_2MDY | T_ADDDX | T_SUBBIAS | T_DIV2DX) +#define EQN2 (T_2MDY | T_ADDDX | T_BIASSUBONE | T_DIV2DX) +#define EQN2B (T_2MDY | T_ADDDX | T_BIASSUBONE | T_DIV2DX) + +#define EQN3 (T_2MDY | T_SUBDY | T_BIASSUBONE | T_DIV2DX | T_ADDONE) +#define EQN3B (T_2MDY | T_ADDDY | T_BIASSUBONE | T_DIV2DX) +#define EQN4 (T_2MDY | T_SUBDY | T_SUBBIAS | T_DIV2DX | T_ADDONE) +#define EQN4B (T_2MDY | T_ADDDY | T_SUBBIAS | T_DIV2DX) + +#define EQN5 (T_2NDX | T_SUBDX | T_BIASSUBONE | T_DIV2DY | T_ADDONE) +#define EQN5B (T_2NDX | T_ADDDX | T_BIASSUBONE | T_DIV2DY) +#define EQN6 (T_2NDX | T_SUBDX | T_SUBBIAS | T_DIV2DY | T_ADDONE) +#define EQN6B (T_2NDX | T_ADDDX | T_SUBBIAS | T_DIV2DY) + +#define EQN7 (T_2NDX | T_ADDDY | T_SUBBIAS | T_DIV2DY) +#define EQN7B (T_2NDX | T_ADDDY | T_SUBBIAS | T_DIV2DY) +#define EQN8 (T_2NDX | T_ADDDY | T_BIASSUBONE | T_DIV2DY) +#define EQN8B (T_2NDX | T_ADDDY | T_BIASSUBONE | T_DIV2DY) + +/* miZeroClipLine + * + * returns: 1 for partially clipped line + * -1 for completely clipped line + * + */ +int +miZeroClipLine(xmin, ymin, xmax, ymax, + new_x1, new_y1, new_x2, new_y2, + adx, ady, + pt1_clipped, pt2_clipped, octant, bias, oc1, oc2) + int xmin, ymin, xmax, ymax; + int *new_x1, *new_y1, *new_x2, *new_y2; + int *pt1_clipped, *pt2_clipped; + unsigned int adx, ady; + int octant; + unsigned int bias; + int oc1, oc2; +{ + int swapped = 0; + int clipDone = 0; + CARD32 utmp = 0; + int clip1, clip2; + int x1, y1, x2, y2; + int x1_orig, y1_orig, x2_orig, y2_orig; + int xmajor; + int negslope = 0, anchorval = 0; + unsigned int eqn = 0; + + x1 = x1_orig = *new_x1; + y1 = y1_orig = *new_y1; + x2 = x2_orig = *new_x2; + y2 = y2_orig = *new_y2; + + clip1 = 0; + clip2 = 0; + + xmajor = IsXMajorOctant(octant); + bias = ((bias >> octant) & 1); + + while (1) + { + if ((oc1 & oc2) != 0) /* trivial reject */ + { + clipDone = -1; + clip1 = oc1; + clip2 = oc2; + break; + } + else if ((oc1 | oc2) == 0) /* trivial accept */ + { + clipDone = 1; + if (swapped) + { + SWAPINT_PAIR(x1, y1, x2, y2); + SWAPINT(clip1, clip2); + } + break; + } + else /* have to clip */ + { + /* only clip one point at a time */ + if (oc1 == 0) + { + SWAPINT_PAIR(x1, y1, x2, y2); + SWAPINT_PAIR(x1_orig, y1_orig, x2_orig, y2_orig); + SWAPINT(oc1, oc2); + SWAPINT(clip1, clip2); + swapped = !swapped; + } + + clip1 |= oc1; + if (oc1 & OUT_LEFT) + { + negslope = IsYDecreasingOctant(octant); + utmp = xmin - x1_orig; + if (utmp <= 32767) /* clip based on near endpt */ + { + if (xmajor) + eqn = (swapped) ? EQN2 : EQN1; + else + eqn = (swapped) ? EQN4 : EQN3; + anchorval = y1_orig; + } + else /* clip based on far endpt */ + { + utmp = x2_orig - xmin; + if (xmajor) + eqn = (swapped) ? EQN1B : EQN2B; + else + eqn = (swapped) ? EQN3B : EQN4B; + anchorval = y2_orig; + negslope = !negslope; + } + x1 = xmin; + } + else if (oc1 & OUT_ABOVE) + { + negslope = IsXDecreasingOctant(octant); + utmp = ymin - y1_orig; + if (utmp <= 32767) /* clip based on near endpt */ + { + if (xmajor) + eqn = (swapped) ? EQN6 : EQN5; + else + eqn = (swapped) ? EQN8 : EQN7; + anchorval = x1_orig; + } + else /* clip based on far endpt */ + { + utmp = y2_orig - ymin; + if (xmajor) + eqn = (swapped) ? EQN5B : EQN6B; + else + eqn = (swapped) ? EQN7B : EQN8B; + anchorval = x2_orig; + negslope = !negslope; + } + y1 = ymin; + } + else if (oc1 & OUT_RIGHT) + { + negslope = IsYDecreasingOctant(octant); + utmp = x1_orig - xmax; + if (utmp <= 32767) /* clip based on near endpt */ + { + if (xmajor) + eqn = (swapped) ? EQN2 : EQN1; + else + eqn = (swapped) ? EQN4 : EQN3; + anchorval = y1_orig; + } + else /* clip based on far endpt */ + { + /* + * Technically since the equations can handle + * utmp == 32768, this overflow code isn't + * needed since X11 protocol can't generate + * a line which goes more than 32768 pixels + * to the right of a clip rectangle. + */ + utmp = xmax - x2_orig; + if (xmajor) + eqn = (swapped) ? EQN1B : EQN2B; + else + eqn = (swapped) ? EQN3B : EQN4B; + anchorval = y2_orig; + negslope = !negslope; + } + x1 = xmax; + } + else if (oc1 & OUT_BELOW) + { + negslope = IsXDecreasingOctant(octant); + utmp = y1_orig - ymax; + if (utmp <= 32767) /* clip based on near endpt */ + { + if (xmajor) + eqn = (swapped) ? EQN6 : EQN5; + else + eqn = (swapped) ? EQN8 : EQN7; + anchorval = x1_orig; + } + else /* clip based on far endpt */ + { + /* + * Technically since the equations can handle + * utmp == 32768, this overflow code isn't + * needed since X11 protocol can't generate + * a line which goes more than 32768 pixels + * below the bottom of a clip rectangle. + */ + utmp = ymax - y2_orig; + if (xmajor) + eqn = (swapped) ? EQN5B : EQN6B; + else + eqn = (swapped) ? EQN7B : EQN8B; + anchorval = x2_orig; + negslope = !negslope; + } + y1 = ymax; + } + + if (swapped) + negslope = !negslope; + + utmp <<= 1; /* utmp = 2N or 2M */ + if (eqn & T_2NDX) + utmp = (utmp * adx); + else /* (eqn & T_2MDY) */ + utmp = (utmp * ady); + if (eqn & T_DXNOTY) + if (eqn & T_SUBDXORY) + utmp -= adx; + else + utmp += adx; + else /* (eqn & T_DYNOTX) */ + if (eqn & T_SUBDXORY) + utmp -= ady; + else + utmp += ady; + if (eqn & T_BIASSUBONE) + utmp += bias - 1; + else /* (eqn & T_SUBBIAS) */ + utmp -= bias; + if (eqn & T_DIV2DX) + utmp /= (adx << 1); + else /* (eqn & T_DIV2DY) */ + utmp /= (ady << 1); + if (eqn & T_ADDONE) + utmp++; + + if (negslope) + utmp = -utmp; + + if (eqn & T_2NDX) /* We are calculating X steps */ + x1 = anchorval + utmp; + else /* else, Y steps */ + y1 = anchorval + utmp; + + oc1 = 0; + MIOUTCODES(oc1, x1, y1, xmin, ymin, xmax, ymax); + } + } + + *new_x1 = x1; + *new_y1 = y1; + *new_x2 = x2; + *new_y2 = y2; + + *pt1_clipped = clip1; + *pt2_clipped = clip2; + + return clipDone; +} |