Home | History | Annotate | Line # | Download | only in shadowfb
      1 /*
      2    Copyright (C) 1999.  The XFree86 Project Inc.
      3 
      4    Written by Mark Vojkovich (mvojkovi (at) ucsd.edu)
      5 
      6    Pre-fb-write callbacks and RENDER support - Nolan Leake (nolan (at) vmware.com)
      7 */
      8 
      9 
     10 #ifdef HAVE_XORG_CONFIG_H
     11 #include <xorg-config.h>
     12 #endif
     13 
     14 #include <X11/X.h>
     15 #include <X11/Xproto.h>
     16 #include "misc.h"
     17 #include "pixmapstr.h"
     18 #include "input.h"
     19 #include <X11/fonts/font.h>
     20 #include "mi.h"
     21 #include "scrnintstr.h"
     22 #include "windowstr.h"
     23 #include "gcstruct.h"
     24 #include "dixfontstr.h"
     25 #include <X11/fonts/fontstruct.h>
     26 #include "xf86.h"
     27 #include "xf86str.h"
     28 #include "shadowfb.h"
     29 
     30 # include "picturestr.h"
     31 
     32 static Bool ShadowCloseScreen (int i, ScreenPtr pScreen);
     33 static void ShadowCopyWindow(
     34     WindowPtr pWin,
     35     DDXPointRec ptOldOrg,
     36     RegionPtr prgn
     37 );
     38 static Bool ShadowCreateGC(GCPtr pGC);
     39 
     40 static Bool ShadowEnterVT(int index, int flags);
     41 static void ShadowLeaveVT(int index, int flags);
     42 
     43 static void ShadowComposite(
     44     CARD8 op,
     45     PicturePtr pSrc,
     46     PicturePtr pMask,
     47     PicturePtr pDst,
     48     INT16 xSrc,
     49     INT16 ySrc,
     50     INT16 xMask,
     51     INT16 yMask,
     52     INT16 xDst,
     53     INT16 yDst,
     54     CARD16 width,
     55     CARD16 height
     56 );
     57 
     58 
     59 typedef struct {
     60   ScrnInfoPtr 				pScrn;
     61   RefreshAreaFuncPtr			preRefresh;
     62   RefreshAreaFuncPtr                    postRefresh;
     63   CloseScreenProcPtr			CloseScreen;
     64   CopyWindowProcPtr			CopyWindow;
     65   CreateGCProcPtr			CreateGC;
     66   ModifyPixmapHeaderProcPtr		ModifyPixmapHeader;
     67   CompositeProcPtr Composite;
     68   Bool				(*EnterVT)(int, int);
     69   void				(*LeaveVT)(int, int);
     70   Bool				vtSema;
     71 } ShadowScreenRec, *ShadowScreenPtr;
     72 
     73 typedef struct {
     74    GCOps   *ops;
     75    GCFuncs *funcs;
     76 } ShadowGCRec, *ShadowGCPtr;
     77 
     78 static DevPrivateKeyRec ShadowScreenKeyRec;
     79 #define ShadowScreenKey (&ShadowScreenKeyRec)
     80 
     81 static DevPrivateKeyRec ShadowGCKeyRec;
     82 #define ShadowGCKey (&ShadowGCKeyRec)
     83 
     84 #define GET_SCREEN_PRIVATE(pScreen) \
     85     (ShadowScreenPtr)dixLookupPrivate(&(pScreen)->devPrivates, ShadowScreenKey)
     86 #define GET_GC_PRIVATE(pGC) \
     87     (ShadowGCPtr)dixLookupPrivate(&(pGC)->devPrivates, ShadowGCKey)
     88 
     89 #define SHADOW_GC_FUNC_PROLOGUE(pGC)\
     90     ShadowGCPtr pGCPriv = GET_GC_PRIVATE(pGC);\
     91     (pGC)->funcs = pGCPriv->funcs;\
     92     if(pGCPriv->ops)\
     93         (pGC)->ops = pGCPriv->ops
     94 
     95 #define SHADOW_GC_FUNC_EPILOGUE(pGC)\
     96     pGCPriv->funcs = (pGC)->funcs;\
     97     (pGC)->funcs = &ShadowGCFuncs;\
     98     if(pGCPriv->ops) {\
     99         pGCPriv->ops = (pGC)->ops;\
    100         (pGC)->ops = &ShadowGCOps;\
    101     }
    102 
    103 #define SHADOW_GC_OP_PROLOGUE(pGC)\
    104     ShadowScreenPtr pPriv = GET_SCREEN_PRIVATE(pGC->pScreen); \
    105     ShadowGCPtr pGCPriv = GET_GC_PRIVATE(pGC);\
    106     GCFuncs *oldFuncs = pGC->funcs;\
    107     pGC->funcs = pGCPriv->funcs;\
    108     pGC->ops = pGCPriv->ops
    109 
    110 
    111 #define SHADOW_GC_OP_EPILOGUE(pGC)\
    112     pGCPriv->ops = pGC->ops;\
    113     pGC->funcs = oldFuncs;\
    114     pGC->ops   = &ShadowGCOps
    115 
    116 #define IS_VISIBLE(pWin) (pPriv->vtSema && \
    117     (((WindowPtr)pWin)->visibility != VisibilityFullyObscured))
    118 
    119 #define TRIM_BOX(box, pGC) { \
    120     BoxPtr extents = &pGC->pCompositeClip->extents;\
    121     if(box.x1 < extents->x1) box.x1 = extents->x1; \
    122     if(box.x2 > extents->x2) box.x2 = extents->x2; \
    123     if(box.y1 < extents->y1) box.y1 = extents->y1; \
    124     if(box.y2 > extents->y2) box.y2 = extents->y2; \
    125     }
    126 
    127 #define TRANSLATE_BOX(box, pDraw) { \
    128     box.x1 += pDraw->x; \
    129     box.x2 += pDraw->x; \
    130     box.y1 += pDraw->y; \
    131     box.y2 += pDraw->y; \
    132     }
    133 
    134 #define TRIM_AND_TRANSLATE_BOX(box, pDraw, pGC) { \
    135     TRANSLATE_BOX(box, pDraw); \
    136     TRIM_BOX(box, pGC); \
    137     }
    138 
    139 #define BOX_NOT_EMPTY(box) \
    140     (((box.x2 - box.x1) > 0) && ((box.y2 - box.y1) > 0))
    141 
    142 
    143 
    144 Bool
    145 ShadowFBInit2 (
    146     ScreenPtr		pScreen,
    147     RefreshAreaFuncPtr  preRefreshArea,
    148     RefreshAreaFuncPtr  postRefreshArea
    149 ){
    150     ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
    151     ShadowScreenPtr pPriv;
    152     PictureScreenPtr ps = GetPictureScreenIfSet(pScreen);
    153 
    154     if(!preRefreshArea && !postRefreshArea) return FALSE;
    155 
    156     if (!dixRegisterPrivateKey(&ShadowScreenKeyRec, PRIVATE_SCREEN, 0))
    157 	return FALSE;
    158 
    159     if(!dixRegisterPrivateKey(&ShadowGCKeyRec, PRIVATE_GC, sizeof(ShadowGCRec)))
    160 	return FALSE;
    161 
    162     if(!(pPriv = (ShadowScreenPtr)malloc(sizeof(ShadowScreenRec))))
    163 	return FALSE;
    164 
    165     dixSetPrivate(&pScreen->devPrivates, ShadowScreenKey, pPriv);
    166 
    167     pPriv->pScrn = pScrn;
    168     pPriv->preRefresh = preRefreshArea;
    169     pPriv->postRefresh = postRefreshArea;
    170     pPriv->vtSema = TRUE;
    171 
    172     pPriv->CloseScreen = pScreen->CloseScreen;
    173     pPriv->CopyWindow = pScreen->CopyWindow;
    174     pPriv->CreateGC = pScreen->CreateGC;
    175     pPriv->ModifyPixmapHeader = pScreen->ModifyPixmapHeader;
    176 
    177     pPriv->EnterVT = pScrn->EnterVT;
    178     pPriv->LeaveVT = pScrn->LeaveVT;
    179 
    180     pScreen->CloseScreen = ShadowCloseScreen;
    181     pScreen->CopyWindow = ShadowCopyWindow;
    182     pScreen->CreateGC = ShadowCreateGC;
    183 
    184     pScrn->EnterVT = ShadowEnterVT;
    185     pScrn->LeaveVT = ShadowLeaveVT;
    186 
    187     if(ps) {
    188       pPriv->Composite = ps->Composite;
    189       ps->Composite = ShadowComposite;
    190     }
    191 
    192     return TRUE;
    193 }
    194 
    195 Bool
    196 ShadowFBInit (
    197     ScreenPtr		pScreen,
    198     RefreshAreaFuncPtr  refreshArea
    199 ){
    200     return ShadowFBInit2(pScreen, NULL, refreshArea);
    201 }
    202 
    203 /**********************************************************/
    204 
    205 static Bool
    206 ShadowEnterVT(int index, int flags)
    207 {
    208     ScrnInfoPtr pScrn = xf86Screens[index];
    209     Bool ret;
    210     ShadowScreenPtr pPriv = GET_SCREEN_PRIVATE(pScrn->pScreen);
    211 
    212     pScrn->EnterVT = pPriv->EnterVT;
    213     ret = (*pPriv->EnterVT)(index, flags);
    214     pPriv->EnterVT = pScrn->EnterVT;
    215     pScrn->EnterVT = ShadowEnterVT;
    216     if(ret) {
    217 	pPriv->vtSema = TRUE;
    218         return TRUE;
    219     }
    220 
    221     return FALSE;
    222 }
    223 
    224 static void
    225 ShadowLeaveVT(int index, int flags)
    226 {
    227     ScrnInfoPtr pScrn = xf86Screens[index];
    228     ShadowScreenPtr pPriv = GET_SCREEN_PRIVATE(xf86Screens[index]->pScreen);
    229 
    230     pPriv->vtSema = FALSE;
    231 
    232     pScrn->LeaveVT = pPriv->LeaveVT;
    233     (*pPriv->LeaveVT)(index, flags);
    234     pPriv->LeaveVT = pScrn->LeaveVT;
    235     pScrn->LeaveVT = ShadowLeaveVT;
    236 }
    237 
    238 /**********************************************************/
    239 
    240 
    241 static Bool
    242 ShadowCloseScreen (int i, ScreenPtr pScreen)
    243 {
    244     ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
    245     ShadowScreenPtr pPriv = GET_SCREEN_PRIVATE(pScreen);
    246     PictureScreenPtr ps = GetPictureScreenIfSet(pScreen);
    247 
    248     pScreen->CloseScreen = pPriv->CloseScreen;
    249     pScreen->CopyWindow = pPriv->CopyWindow;
    250     pScreen->CreateGC = pPriv->CreateGC;
    251     pScreen->ModifyPixmapHeader = pPriv->ModifyPixmapHeader;
    252 
    253     pScrn->EnterVT = pPriv->EnterVT;
    254     pScrn->LeaveVT = pPriv->LeaveVT;
    255 
    256     if(ps) {
    257         ps->Composite = pPriv->Composite;
    258     }
    259 
    260     free((pointer)pPriv);
    261 
    262     return (*pScreen->CloseScreen) (i, pScreen);
    263 }
    264 
    265 static void
    266 ShadowCopyWindow(
    267    WindowPtr pWin,
    268    DDXPointRec ptOldOrg,
    269    RegionPtr prgn
    270 ){
    271     ScreenPtr pScreen = pWin->drawable.pScreen;
    272     ShadowScreenPtr pPriv = GET_SCREEN_PRIVATE(pScreen);
    273     int num = 0;
    274     RegionRec rgnDst;
    275 
    276     if (pPriv->vtSema) {
    277         RegionNull(&rgnDst);
    278 	RegionCopy(&rgnDst, prgn);
    279 
    280         RegionTranslate(&rgnDst,
    281                          pWin->drawable.x - ptOldOrg.x,
    282                          pWin->drawable.y - ptOldOrg.y);
    283         RegionIntersect(&rgnDst, &pWin->borderClip, &rgnDst);
    284         if ((num = RegionNumRects(&rgnDst))) {
    285             if(pPriv->preRefresh)
    286                 (*pPriv->preRefresh)(pPriv->pScrn, num, RegionRects(&rgnDst));
    287         } else {
    288             RegionUninit(&rgnDst);
    289         }
    290     }
    291 
    292     pScreen->CopyWindow = pPriv->CopyWindow;
    293     (*pScreen->CopyWindow) (pWin, ptOldOrg, prgn);
    294     pScreen->CopyWindow = ShadowCopyWindow;
    295 
    296     if (num) {
    297         if (pPriv->postRefresh)
    298             (*pPriv->postRefresh)(pPriv->pScrn, num, RegionRects(&rgnDst));
    299         RegionUninit(&rgnDst);
    300     }
    301 }
    302 
    303 static void
    304 ShadowComposite(
    305     CARD8 op,
    306     PicturePtr pSrc,
    307     PicturePtr pMask,
    308     PicturePtr pDst,
    309     INT16 xSrc,
    310     INT16 ySrc,
    311     INT16 xMask,
    312     INT16 yMask,
    313     INT16 xDst,
    314     INT16 yDst,
    315     CARD16 width,
    316     CARD16 height
    317 ){
    318     ScreenPtr pScreen = pDst->pDrawable->pScreen;
    319     ShadowScreenPtr pPriv = GET_SCREEN_PRIVATE(pScreen);
    320     PictureScreenPtr ps = GetPictureScreen(pScreen);
    321     BoxRec box;
    322     BoxPtr extents;
    323     Bool boxNotEmpty = FALSE;
    324 
    325     if (pPriv->vtSema
    326 	&& pDst->pDrawable->type == DRAWABLE_WINDOW) {
    327 
    328 	box.x1 = pDst->pDrawable->x + xDst;
    329 	box.y1 = pDst->pDrawable->y + yDst;
    330 	box.x2 = box.x1 + width;
    331 	box.y2 = box.y1 + height;
    332 
    333 	extents = &pDst->pCompositeClip->extents;
    334 	if(box.x1 < extents->x1) box.x1 = extents->x1;
    335 	if(box.x2 > extents->x2) box.x2 = extents->x2;
    336 	if(box.y1 < extents->y1) box.y1 = extents->y1;
    337 	if(box.y2 > extents->y2) box.y2 = extents->y2;
    338 
    339 	if (BOX_NOT_EMPTY(box)) {
    340 	    if (pPriv->preRefresh)
    341 		(*pPriv->preRefresh)(pPriv->pScrn, 1, &box);
    342 	    boxNotEmpty = TRUE;
    343 	}
    344     }
    345 
    346     ps->Composite = pPriv->Composite;
    347     (*ps->Composite)(op, pSrc, pMask, pDst, xSrc, ySrc,
    348 		     xMask, yMask, xDst, yDst, width, height);
    349     ps->Composite = ShadowComposite;
    350 
    351     if (pPriv->postRefresh && boxNotEmpty) {
    352         (*pPriv->postRefresh)(pPriv->pScrn, 1, &box);
    353     }
    354 }
    355 
    356 /**********************************************************/
    357 
    358 static void ShadowValidateGC(GCPtr, unsigned long, DrawablePtr);
    359 static void ShadowChangeGC(GCPtr, unsigned long);
    360 static void ShadowCopyGC(GCPtr, unsigned long, GCPtr);
    361 static void ShadowDestroyGC(GCPtr);
    362 static void ShadowChangeClip(GCPtr, int, pointer, int);
    363 static void ShadowDestroyClip(GCPtr);
    364 static void ShadowCopyClip(GCPtr, GCPtr);
    365 
    366 GCFuncs ShadowGCFuncs = {
    367     ShadowValidateGC, ShadowChangeGC, ShadowCopyGC, ShadowDestroyGC,
    368     ShadowChangeClip, ShadowDestroyClip, ShadowCopyClip
    369 };
    370 
    371 
    372 extern GCOps ShadowGCOps;
    373 
    374 static Bool
    375 ShadowCreateGC(GCPtr pGC)
    376 {
    377     ScreenPtr pScreen = pGC->pScreen;
    378     ShadowScreenPtr pPriv = GET_SCREEN_PRIVATE(pScreen);
    379     ShadowGCPtr pGCPriv = GET_GC_PRIVATE(pGC);
    380     Bool ret;
    381 
    382     pScreen->CreateGC = pPriv->CreateGC;
    383     if((ret = (*pScreen->CreateGC) (pGC))) {
    384 	pGCPriv->ops = NULL;
    385 	pGCPriv->funcs = pGC->funcs;
    386 	pGC->funcs = &ShadowGCFuncs;
    387     }
    388     pScreen->CreateGC = ShadowCreateGC;
    389 
    390     return ret;
    391 }
    392 
    393 
    394 static void
    395 ShadowValidateGC(
    396    GCPtr         pGC,
    397    unsigned long changes,
    398    DrawablePtr   pDraw
    399 ){
    400     SHADOW_GC_FUNC_PROLOGUE (pGC);
    401     (*pGC->funcs->ValidateGC)(pGC, changes, pDraw);
    402     if(pDraw->type == DRAWABLE_WINDOW)
    403 	pGCPriv->ops = pGC->ops;  /* just so it's not NULL */
    404     else
    405 	pGCPriv->ops = NULL;
    406     SHADOW_GC_FUNC_EPILOGUE (pGC);
    407 }
    408 
    409 
    410 static void
    411 ShadowDestroyGC(GCPtr pGC)
    412 {
    413     SHADOW_GC_FUNC_PROLOGUE (pGC);
    414     (*pGC->funcs->DestroyGC)(pGC);
    415     SHADOW_GC_FUNC_EPILOGUE (pGC);
    416 }
    417 
    418 static void
    419 ShadowChangeGC (
    420     GCPtr	    pGC,
    421     unsigned long   mask
    422 ){
    423     SHADOW_GC_FUNC_PROLOGUE (pGC);
    424     (*pGC->funcs->ChangeGC) (pGC, mask);
    425     SHADOW_GC_FUNC_EPILOGUE (pGC);
    426 }
    427 
    428 static void
    429 ShadowCopyGC (
    430     GCPtr	    pGCSrc,
    431     unsigned long   mask,
    432     GCPtr	    pGCDst
    433 ){
    434     SHADOW_GC_FUNC_PROLOGUE (pGCDst);
    435     (*pGCDst->funcs->CopyGC) (pGCSrc, mask, pGCDst);
    436     SHADOW_GC_FUNC_EPILOGUE (pGCDst);
    437 }
    438 
    439 static void
    440 ShadowChangeClip (
    441     GCPtr   pGC,
    442     int		type,
    443     pointer	pvalue,
    444     int		nrects
    445 ){
    446     SHADOW_GC_FUNC_PROLOGUE (pGC);
    447     (*pGC->funcs->ChangeClip) (pGC, type, pvalue, nrects);
    448     SHADOW_GC_FUNC_EPILOGUE (pGC);
    449 }
    450 
    451 static void
    452 ShadowCopyClip(GCPtr pgcDst, GCPtr pgcSrc)
    453 {
    454     SHADOW_GC_FUNC_PROLOGUE (pgcDst);
    455     (* pgcDst->funcs->CopyClip)(pgcDst, pgcSrc);
    456     SHADOW_GC_FUNC_EPILOGUE (pgcDst);
    457 }
    458 
    459 static void
    460 ShadowDestroyClip(GCPtr pGC)
    461 {
    462     SHADOW_GC_FUNC_PROLOGUE (pGC);
    463     (* pGC->funcs->DestroyClip)(pGC);
    464     SHADOW_GC_FUNC_EPILOGUE (pGC);
    465 }
    466 
    467 
    468 
    469 
    470 /**********************************************************/
    471 
    472 
    473 static void
    474 ShadowFillSpans(
    475     DrawablePtr pDraw,
    476     GC		*pGC,
    477     int		nInit,
    478     DDXPointPtr pptInit,
    479     int 	*pwidthInit,
    480     int 	fSorted
    481 ){
    482     SHADOW_GC_OP_PROLOGUE(pGC);
    483 
    484     if(IS_VISIBLE(pDraw) && nInit) {
    485 	DDXPointPtr ppt = pptInit;
    486 	int *pwidth = pwidthInit;
    487 	int i = nInit;
    488 	BoxRec box;
    489         Bool boxNotEmpty = FALSE;
    490 
    491 	box.x1 = ppt->x;
    492 	box.x2 = box.x1 + *pwidth;
    493 	box.y2 = box.y1 = ppt->y;
    494 
    495 	while(--i) {
    496 	   ppt++;
    497 	   pwidth++;
    498 	   if(box.x1 > ppt->x) box.x1 = ppt->x;
    499 	   if(box.x2 < (ppt->x + *pwidth))
    500 		box.x2 = ppt->x + *pwidth;
    501 	   if(box.y1 > ppt->y) box.y1 = ppt->y;
    502 	   else if(box.y2 < ppt->y) box.y2 = ppt->y;
    503 	}
    504 
    505 	box.y2++;
    506 
    507         if(!pGC->miTranslate) {
    508            TRANSLATE_BOX(box, pDraw);
    509         }
    510         TRIM_BOX(box, pGC);
    511 
    512 	if(BOX_NOT_EMPTY(box)) {
    513             if(pPriv->preRefresh)
    514                 (*pPriv->preRefresh)(pPriv->pScrn, 1, &box);
    515             boxNotEmpty = TRUE;
    516         }
    517 
    518 	(*pGC->ops->FillSpans)(pDraw, pGC, nInit, pptInit, pwidthInit, fSorted);
    519 
    520         if(boxNotEmpty && pPriv->postRefresh)
    521 	   (*pPriv->postRefresh)(pPriv->pScrn, 1, &box);
    522     } else
    523 	(*pGC->ops->FillSpans)(pDraw, pGC, nInit, pptInit, pwidthInit, fSorted);
    524 
    525     SHADOW_GC_OP_EPILOGUE(pGC);
    526 }
    527 
    528 static void
    529 ShadowSetSpans(
    530     DrawablePtr		pDraw,
    531     GCPtr		pGC,
    532     char		*pcharsrc,
    533     DDXPointPtr 	pptInit,
    534     int			*pwidthInit,
    535     int			nspans,
    536     int			fSorted
    537 ){
    538     SHADOW_GC_OP_PROLOGUE(pGC);
    539 
    540     if(IS_VISIBLE(pDraw) && nspans) {
    541 	DDXPointPtr ppt = pptInit;
    542 	int *pwidth = pwidthInit;
    543 	int i = nspans;
    544 	BoxRec box;
    545         Bool boxNotEmpty = FALSE;
    546 
    547 	box.x1 = ppt->x;
    548 	box.x2 = box.x1 + *pwidth;
    549 	box.y2 = box.y1 = ppt->y;
    550 
    551 	while(--i) {
    552 	   ppt++;
    553 	   pwidth++;
    554 	   if(box.x1 > ppt->x) box.x1 = ppt->x;
    555 	   if(box.x2 < (ppt->x + *pwidth))
    556 		box.x2 = ppt->x + *pwidth;
    557 	   if(box.y1 > ppt->y) box.y1 = ppt->y;
    558 	   else if(box.y2 < ppt->y) box.y2 = ppt->y;
    559 	}
    560 
    561 	box.y2++;
    562 
    563         if(!pGC->miTranslate) {
    564            TRANSLATE_BOX(box, pDraw);
    565         }
    566         TRIM_BOX(box, pGC);
    567 
    568 	if(BOX_NOT_EMPTY(box)) {
    569            if(pPriv->preRefresh)
    570 	      (*pPriv->preRefresh)(pPriv->pScrn, 1, &box);
    571            boxNotEmpty = TRUE;
    572         }
    573 
    574 	(*pGC->ops->SetSpans)(pDraw, pGC, pcharsrc, pptInit,
    575 				pwidthInit, nspans, fSorted);
    576 
    577 	if(boxNotEmpty && pPriv->postRefresh)
    578 	   (*pPriv->postRefresh)(pPriv->pScrn, 1, &box);
    579     } else
    580 	(*pGC->ops->SetSpans)(pDraw, pGC, pcharsrc, pptInit,
    581 				pwidthInit, nspans, fSorted);
    582 
    583     SHADOW_GC_OP_EPILOGUE(pGC);
    584 }
    585 
    586 static void
    587 ShadowPutImage(
    588     DrawablePtr pDraw,
    589     GCPtr	pGC,
    590     int		depth,
    591     int x, int y, int w, int h,
    592     int		leftPad,
    593     int		format,
    594     char 	*pImage
    595 ){
    596     BoxRec box;
    597     Bool boxNotEmpty = FALSE;
    598 
    599     SHADOW_GC_OP_PROLOGUE(pGC);
    600 
    601     if(IS_VISIBLE(pDraw)) {
    602 	box.x1 = x + pDraw->x;
    603 	box.x2 = box.x1 + w;
    604 	box.y1 = y + pDraw->y;
    605 	box.y2 = box.y1 + h;
    606 
    607 	TRIM_BOX(box, pGC);
    608 	if(BOX_NOT_EMPTY(box)) {
    609            if(pPriv->preRefresh)
    610 	      (*pPriv->preRefresh)(pPriv->pScrn, 1, &box);
    611            boxNotEmpty = TRUE;
    612         }
    613     }
    614 
    615     (*pGC->ops->PutImage)(pDraw, pGC, depth, x, y, w, h,
    616 		leftPad, format, pImage);
    617 
    618     if(boxNotEmpty && pPriv->postRefresh)
    619         (*pPriv->postRefresh)(pPriv->pScrn, 1, &box);
    620 
    621     SHADOW_GC_OP_EPILOGUE(pGC);
    622 
    623 }
    624 
    625 static RegionPtr
    626 ShadowCopyArea(
    627     DrawablePtr pSrc,
    628     DrawablePtr pDst,
    629     GC *pGC,
    630     int srcx, int srcy,
    631     int width, int height,
    632     int dstx, int dsty
    633 ){
    634     RegionPtr ret;
    635     BoxRec box;
    636     Bool boxNotEmpty = FALSE;
    637 
    638     SHADOW_GC_OP_PROLOGUE(pGC);
    639 
    640     if(IS_VISIBLE(pDst)) {
    641 	box.x1 = dstx + pDst->x;
    642 	box.x2 = box.x1 + width;
    643 	box.y1 = dsty + pDst->y;
    644 	box.y2 = box.y1 + height;
    645 
    646 	TRIM_BOX(box, pGC);
    647 	if(BOX_NOT_EMPTY(box)) {
    648            if(pPriv->preRefresh)
    649 	      (*pPriv->preRefresh)(pPriv->pScrn, 1, &box);
    650            boxNotEmpty = TRUE;
    651         }
    652     }
    653 
    654     ret = (*pGC->ops->CopyArea)(pSrc, pDst,
    655             pGC, srcx, srcy, width, height, dstx, dsty);
    656 
    657     if(boxNotEmpty && pPriv->postRefresh)
    658         (*pPriv->postRefresh)(pPriv->pScrn, 1, &box);
    659 
    660     SHADOW_GC_OP_EPILOGUE(pGC);
    661 
    662     return ret;
    663 }
    664 
    665 static RegionPtr
    666 ShadowCopyPlane(
    667     DrawablePtr	pSrc,
    668     DrawablePtr	pDst,
    669     GCPtr pGC,
    670     int	srcx, int srcy,
    671     int	width, int height,
    672     int	dstx, int dsty,
    673     unsigned long bitPlane
    674 ){
    675     RegionPtr ret;
    676     BoxRec box;
    677     Bool boxNotEmpty = FALSE;
    678 
    679     SHADOW_GC_OP_PROLOGUE(pGC);
    680 
    681     if(IS_VISIBLE(pDst)) {
    682 	box.x1 = dstx + pDst->x;
    683 	box.x2 = box.x1 + width;
    684 	box.y1 = dsty + pDst->y;
    685 	box.y2 = box.y1 + height;
    686 
    687 	TRIM_BOX(box, pGC);
    688 	if(BOX_NOT_EMPTY(box)) {
    689            if(pPriv->preRefresh)
    690 	      (*pPriv->preRefresh)(pPriv->pScrn, 1, &box);
    691            boxNotEmpty = TRUE;
    692         }
    693     }
    694 
    695     ret = (*pGC->ops->CopyPlane)(pSrc, pDst,
    696 	       pGC, srcx, srcy, width, height, dstx, dsty, bitPlane);
    697 
    698     if(boxNotEmpty && pPriv->postRefresh)
    699         (*pPriv->postRefresh)(pPriv->pScrn, 1, &box);
    700 
    701     SHADOW_GC_OP_EPILOGUE(pGC);
    702 
    703     return ret;
    704 }
    705 
    706 static void
    707 ShadowPolyPoint(
    708     DrawablePtr pDraw,
    709     GCPtr pGC,
    710     int mode,
    711     int nptInit,
    712     xPoint *pptInit
    713 ){
    714     BoxRec box;
    715     Bool boxNotEmpty = FALSE;
    716 
    717     SHADOW_GC_OP_PROLOGUE(pGC);
    718 
    719     if(IS_VISIBLE(pDraw) && nptInit) {
    720         xPoint *ppt = pptInit;
    721         int npt = nptInit;
    722 
    723 	box.x2 = box.x1 = pptInit->x;
    724 	box.y2 = box.y1 = pptInit->y;
    725 
    726 	/* this could be slow if the points were spread out */
    727 
    728 	while(--npt) {
    729 	   ppt++;
    730 	   if(box.x1 > ppt->x) box.x1 = ppt->x;
    731 	   else if(box.x2 < ppt->x) box.x2 = ppt->x;
    732 	   if(box.y1 > ppt->y) box.y1 = ppt->y;
    733 	   else if(box.y2 < ppt->y) box.y2 = ppt->y;
    734 	}
    735 
    736 	box.x2++;
    737 	box.y2++;
    738 
    739 	TRIM_AND_TRANSLATE_BOX(box, pDraw, pGC);
    740 	if(BOX_NOT_EMPTY(box)) {
    741            if(pPriv->preRefresh)
    742 	      (*pPriv->preRefresh)(pPriv->pScrn, 1, &box);
    743            boxNotEmpty = TRUE;
    744         }
    745     }
    746 
    747     (*pGC->ops->PolyPoint)(pDraw, pGC, mode, nptInit, pptInit);
    748 
    749     if(boxNotEmpty && pPriv->postRefresh)
    750         (*pPriv->postRefresh)(pPriv->pScrn, 1, &box);
    751 
    752     SHADOW_GC_OP_EPILOGUE(pGC);
    753 }
    754 
    755 static void
    756 ShadowPolylines(
    757     DrawablePtr pDraw,
    758     GCPtr	pGC,
    759     int		mode,
    760     int		nptInit,
    761     DDXPointPtr pptInit
    762 ){
    763     BoxRec box;
    764     Bool boxNotEmpty = FALSE;
    765 
    766     SHADOW_GC_OP_PROLOGUE(pGC);
    767 
    768     if(IS_VISIBLE(pDraw) && nptInit) {
    769         DDXPointPtr ppt = pptInit;
    770         int npt = nptInit;
    771 	int extra = pGC->lineWidth >> 1;
    772 
    773 	box.x2 = box.x1 = pptInit->x;
    774 	box.y2 = box.y1 = pptInit->y;
    775 
    776 	if(npt > 1) {
    777 	   if(pGC->joinStyle == JoinMiter)
    778 		extra = 6 * pGC->lineWidth;
    779 	   else if(pGC->capStyle == CapProjecting)
    780 		extra = pGC->lineWidth;
    781         }
    782 
    783 	if(mode == CoordModePrevious) {
    784 	   int x = box.x1;
    785 	   int y = box.y1;
    786 	   while(--npt) {
    787 		ppt++;
    788 		x += ppt->x;
    789 		y += ppt->y;
    790 		if(box.x1 > x) box.x1 = x;
    791 		else if(box.x2 < x) box.x2 = x;
    792 		if(box.y1 > y) box.y1 = y;
    793 		else if(box.y2 < y) box.y2 = y;
    794 	    }
    795 	} else {
    796 	   while(--npt) {
    797 		ppt++;
    798 		if(box.x1 > ppt->x) box.x1 = ppt->x;
    799 		else if(box.x2 < ppt->x) box.x2 = ppt->x;
    800 		if(box.y1 > ppt->y) box.y1 = ppt->y;
    801 		else if(box.y2 < ppt->y) box.y2 = ppt->y;
    802 	    }
    803 	}
    804 
    805 	box.x2++;
    806 	box.y2++;
    807 
    808 	if(extra) {
    809 	   box.x1 -= extra;
    810 	   box.x2 += extra;
    811 	   box.y1 -= extra;
    812 	   box.y2 += extra;
    813         }
    814 
    815 	TRIM_AND_TRANSLATE_BOX(box, pDraw, pGC);
    816 	if(BOX_NOT_EMPTY(box)) {
    817            if(pPriv->preRefresh)
    818 	      (*pPriv->preRefresh)(pPriv->pScrn, 1, &box);
    819            boxNotEmpty = TRUE;
    820         }
    821     }
    822 
    823     (*pGC->ops->Polylines)(pDraw, pGC, mode, nptInit, pptInit);
    824 
    825     if(boxNotEmpty && pPriv->postRefresh)
    826        (*pPriv->postRefresh)(pPriv->pScrn, 1, &box);
    827 
    828     SHADOW_GC_OP_EPILOGUE(pGC);
    829 }
    830 
    831 static void
    832 ShadowPolySegment(
    833     DrawablePtr	pDraw,
    834     GCPtr	pGC,
    835     int		nsegInit,
    836     xSegment	*pSegInit
    837 ){
    838     BoxRec box;
    839     Bool boxNotEmpty = FALSE;
    840 
    841     SHADOW_GC_OP_PROLOGUE(pGC);
    842 
    843     if(IS_VISIBLE(pDraw) && nsegInit) {
    844 	int extra = pGC->lineWidth;
    845         xSegment *pSeg = pSegInit;
    846         int nseg = nsegInit;
    847 
    848         if(pGC->capStyle != CapProjecting)
    849 	   extra >>= 1;
    850 
    851 	if(pSeg->x2 > pSeg->x1) {
    852 	    box.x1 = pSeg->x1;
    853 	    box.x2 = pSeg->x2;
    854 	} else {
    855 	    box.x2 = pSeg->x1;
    856 	    box.x1 = pSeg->x2;
    857 	}
    858 
    859 	if(pSeg->y2 > pSeg->y1) {
    860 	    box.y1 = pSeg->y1;
    861 	    box.y2 = pSeg->y2;
    862 	} else {
    863 	    box.y2 = pSeg->y1;
    864 	    box.y1 = pSeg->y2;
    865 	}
    866 
    867 	while(--nseg) {
    868 	    pSeg++;
    869 	    if(pSeg->x2 > pSeg->x1) {
    870 		if(pSeg->x1 < box.x1) box.x1 = pSeg->x1;
    871 		if(pSeg->x2 > box.x2) box.x2 = pSeg->x2;
    872 	    } else {
    873 		if(pSeg->x2 < box.x1) box.x1 = pSeg->x2;
    874 		if(pSeg->x1 > box.x2) box.x2 = pSeg->x1;
    875 	    }
    876 	    if(pSeg->y2 > pSeg->y1) {
    877 		if(pSeg->y1 < box.y1) box.y1 = pSeg->y1;
    878 		if(pSeg->y2 > box.y2) box.y2 = pSeg->y2;
    879 	    } else {
    880 		if(pSeg->y2 < box.y1) box.y1 = pSeg->y2;
    881 		if(pSeg->y1 > box.y2) box.y2 = pSeg->y1;
    882 	    }
    883 	}
    884 
    885 	box.x2++;
    886 	box.y2++;
    887 
    888 	if(extra) {
    889 	   box.x1 -= extra;
    890 	   box.x2 += extra;
    891 	   box.y1 -= extra;
    892 	   box.y2 += extra;
    893         }
    894 
    895 	TRIM_AND_TRANSLATE_BOX(box, pDraw, pGC);
    896 	if(BOX_NOT_EMPTY(box)) {
    897            if(pPriv->preRefresh)
    898               (*pPriv->preRefresh)(pPriv->pScrn, 1, &box);
    899            boxNotEmpty = TRUE;
    900         }
    901     }
    902 
    903     (*pGC->ops->PolySegment)(pDraw, pGC, nsegInit, pSegInit);
    904 
    905     if(boxNotEmpty && pPriv->postRefresh)
    906        (*pPriv->postRefresh)(pPriv->pScrn, 1, &box);
    907 
    908     SHADOW_GC_OP_EPILOGUE(pGC);
    909 }
    910 
    911 static void
    912 ShadowPolyRectangle(
    913     DrawablePtr  pDraw,
    914     GCPtr        pGC,
    915     int	         nRectsInit,
    916     xRectangle  *pRectsInit
    917 ){
    918     BoxRec box;
    919     BoxPtr pBoxInit = NULL;
    920     Bool boxNotEmpty = FALSE;
    921     int num = 0;
    922 
    923     SHADOW_GC_OP_PROLOGUE(pGC);
    924 
    925     if(IS_VISIBLE(pDraw) && nRectsInit) {
    926         xRectangle *pRects = pRectsInit;
    927         int nRects = nRectsInit;
    928 
    929 	if(nRects >= 32) {
    930 	    int extra = pGC->lineWidth >> 1;
    931 
    932 	    box.x1 = pRects->x;
    933 	    box.x2 = box.x1 + pRects->width;
    934 	    box.y1 = pRects->y;
    935 	    box.y2 = box.y1 + pRects->height;
    936 
    937 	    while(--nRects) {
    938 		pRects++;
    939 		if(box.x1 > pRects->x) box.x1 = pRects->x;
    940 		if(box.x2 < (pRects->x + pRects->width))
    941 			box.x2 = pRects->x + pRects->width;
    942 		if(box.y1 > pRects->y) box.y1 = pRects->y;
    943 		if(box.y2 < (pRects->y + pRects->height))
    944 			box.y2 = pRects->y + pRects->height;
    945 	    }
    946 
    947 	    if(extra) {
    948 		box.x1 -= extra;
    949 		box.x2 += extra;
    950 		box.y1 -= extra;
    951 		box.y2 += extra;
    952 	    }
    953 
    954 	    box.x2++;
    955 	    box.y2++;
    956 
    957 	    TRIM_AND_TRANSLATE_BOX(box, pDraw, pGC);
    958 	    if(BOX_NOT_EMPTY(box)) {
    959                 if(pPriv->preRefresh)
    960                    (*pPriv->preRefresh)(pPriv->pScrn, 1, &box);
    961                 boxNotEmpty = TRUE;
    962             }
    963 	} else {
    964 	    BoxPtr pbox;
    965 	    int offset1, offset2, offset3;
    966 
    967 	    offset2 = pGC->lineWidth;
    968 	    if(!offset2) offset2 = 1;
    969 	    offset1 = offset2 >> 1;
    970 	    offset3 = offset2 - offset1;
    971 
    972 	    pBoxInit = (BoxPtr)malloc(nRects * 4 * sizeof(BoxRec));
    973 	    pbox = pBoxInit;
    974 
    975 	    while(nRects--) {
    976 		pbox->x1 = pRects->x - offset1;
    977 		pbox->y1 = pRects->y - offset1;
    978 		pbox->x2 = pbox->x1 + pRects->width + offset2;
    979 		pbox->y2 = pbox->y1 + offset2;
    980 		TRIM_AND_TRANSLATE_BOX((*pbox), pDraw, pGC);
    981 		if(BOX_NOT_EMPTY((*pbox))) {
    982 		   num++;
    983 		   pbox++;
    984 		}
    985 
    986 		pbox->x1 = pRects->x - offset1;
    987 		pbox->y1 = pRects->y + offset3;
    988 		pbox->x2 = pbox->x1 + offset2;
    989 		pbox->y2 = pbox->y1 + pRects->height - offset2;
    990 		TRIM_AND_TRANSLATE_BOX((*pbox), pDraw, pGC);
    991 		if(BOX_NOT_EMPTY((*pbox))) {
    992 		   num++;
    993 		   pbox++;
    994 		}
    995 
    996 		pbox->x1 = pRects->x + pRects->width - offset1;
    997 		pbox->y1 = pRects->y + offset3;
    998 		pbox->x2 = pbox->x1 + offset2;
    999 		pbox->y2 = pbox->y1 + pRects->height - offset2;
   1000 		TRIM_AND_TRANSLATE_BOX((*pbox), pDraw, pGC);
   1001 		if(BOX_NOT_EMPTY((*pbox))) {
   1002 		   num++;
   1003 		   pbox++;
   1004 		}
   1005 
   1006 		pbox->x1 = pRects->x - offset1;
   1007 		pbox->y1 = pRects->y + pRects->height - offset1;
   1008 		pbox->x2 = pbox->x1 + pRects->width + offset2;
   1009 		pbox->y2 = pbox->y1 + offset2;
   1010 		TRIM_AND_TRANSLATE_BOX((*pbox), pDraw, pGC);
   1011 		if(BOX_NOT_EMPTY((*pbox))) {
   1012 		   num++;
   1013 		   pbox++;
   1014 		}
   1015 
   1016 		pRects++;
   1017 	    }
   1018 
   1019 	    if(num) {
   1020                 if(pPriv->preRefresh)
   1021                     (*pPriv->preRefresh)(pPriv->pScrn, num, pBoxInit);
   1022             } else {
   1023                 free(pBoxInit);
   1024             }
   1025 	}
   1026     }
   1027 
   1028     (*pGC->ops->PolyRectangle)(pDraw, pGC, nRectsInit, pRectsInit);
   1029 
   1030     if(boxNotEmpty && pPriv->postRefresh) {
   1031        (*pPriv->postRefresh)(pPriv->pScrn, 1, &box);
   1032     } else if(num) {
   1033        if(pPriv->postRefresh)
   1034           (*pPriv->postRefresh)(pPriv->pScrn, num, pBoxInit);
   1035        free(pBoxInit);
   1036     }
   1037 
   1038     SHADOW_GC_OP_EPILOGUE(pGC);
   1039 
   1040 }
   1041 
   1042 static void
   1043 ShadowPolyArc(
   1044     DrawablePtr	pDraw,
   1045     GCPtr	pGC,
   1046     int		narcsInit,
   1047     xArc	*parcsInit
   1048 ){
   1049     BoxRec box;
   1050     Bool boxNotEmpty = FALSE;
   1051 
   1052     SHADOW_GC_OP_PROLOGUE(pGC);
   1053 
   1054     if(IS_VISIBLE(pDraw) && narcsInit) {
   1055         int narcs = narcsInit;
   1056         xArc *parcs = parcsInit;
   1057         int extra = pGC->lineWidth >> 1;
   1058 
   1059 	box.x1 = parcs->x;
   1060 	box.x2 = box.x1 + parcs->width;
   1061 	box.y1 = parcs->y;
   1062 	box.y2 = box.y1 + parcs->height;
   1063 
   1064 	/* should I break these up instead ? */
   1065 
   1066 	while(--narcs) {
   1067 	   parcs++;
   1068 	   if(box.x1 > parcs->x) box.x1 = parcs->x;
   1069 	   if(box.x2 < (parcs->x + parcs->width))
   1070 		box.x2 = parcs->x + parcs->width;
   1071 	   if(box.y1 > parcs->y) box.y1 = parcs->y;
   1072 	   if(box.y2 < (parcs->y + parcs->height))
   1073 		box.y2 = parcs->y + parcs->height;
   1074         }
   1075 
   1076 	if(extra) {
   1077 	   box.x1 -= extra;
   1078 	   box.x2 += extra;
   1079 	   box.y1 -= extra;
   1080 	   box.y2 += extra;
   1081         }
   1082 
   1083 	box.x2++;
   1084 	box.y2++;
   1085 
   1086 	TRIM_AND_TRANSLATE_BOX(box, pDraw, pGC);
   1087 	if(BOX_NOT_EMPTY(box)) {
   1088            if(pPriv->preRefresh)
   1089               (*pPriv->preRefresh)(pPriv->pScrn, 1, &box);
   1090            boxNotEmpty = TRUE;
   1091         }
   1092     }
   1093 
   1094     (*pGC->ops->PolyArc)(pDraw, pGC, narcsInit, parcsInit);
   1095 
   1096     if(boxNotEmpty && pPriv->postRefresh)
   1097        (*pPriv->postRefresh)(pPriv->pScrn, 1, &box);
   1098 
   1099     SHADOW_GC_OP_EPILOGUE(pGC);
   1100 
   1101 }
   1102 
   1103 static void
   1104 ShadowFillPolygon(
   1105     DrawablePtr	pDraw,
   1106     GCPtr	pGC,
   1107     int		shape,
   1108     int		mode,
   1109     int		count,
   1110     DDXPointPtr	pptInit
   1111 ){
   1112     SHADOW_GC_OP_PROLOGUE(pGC);
   1113 
   1114     if(IS_VISIBLE(pDraw) && (count > 2)) {
   1115 	DDXPointPtr ppt = pptInit;
   1116 	int i = count;
   1117 	BoxRec box;
   1118         Bool boxNotEmpty = FALSE;
   1119 
   1120 	box.x2 = box.x1 = ppt->x;
   1121 	box.y2 = box.y1 = ppt->y;
   1122 
   1123 	if(mode != CoordModeOrigin) {
   1124 	   int x = box.x1;
   1125 	   int y = box.y1;
   1126 	   while(--i) {
   1127 		ppt++;
   1128 		x += ppt->x;
   1129 		y += ppt->y;
   1130 		if(box.x1 > x) box.x1 = x;
   1131 		else if(box.x2 < x) box.x2 = x;
   1132 		if(box.y1 > y) box.y1 = y;
   1133 		else if(box.y2 < y) box.y2 = y;
   1134 	    }
   1135 	} else {
   1136 	   while(--i) {
   1137 		ppt++;
   1138 		if(box.x1 > ppt->x) box.x1 = ppt->x;
   1139 		else if(box.x2 < ppt->x) box.x2 = ppt->x;
   1140 		if(box.y1 > ppt->y) box.y1 = ppt->y;
   1141 		else if(box.y2 < ppt->y) box.y2 = ppt->y;
   1142 	    }
   1143 	}
   1144 
   1145 	box.x2++;
   1146 	box.y2++;
   1147 
   1148 	TRIM_AND_TRANSLATE_BOX(box, pDraw, pGC);
   1149 	if(BOX_NOT_EMPTY(box)) {
   1150            if(pPriv->preRefresh)
   1151               (*pPriv->preRefresh)(pPriv->pScrn, 1, &box);
   1152            boxNotEmpty = TRUE;
   1153         }
   1154 
   1155 	(*pGC->ops->FillPolygon)(pDraw, pGC, shape, mode, count, pptInit);
   1156 
   1157         if(boxNotEmpty && pPriv->postRefresh)
   1158            (*pPriv->postRefresh)(pPriv->pScrn, 1, &box);
   1159     } else
   1160 	(*pGC->ops->FillPolygon)(pDraw, pGC, shape, mode, count, pptInit);
   1161 
   1162     SHADOW_GC_OP_EPILOGUE(pGC);
   1163 }
   1164 
   1165 
   1166 static void
   1167 ShadowPolyFillRect(
   1168     DrawablePtr	pDraw,
   1169     GCPtr	pGC,
   1170     int		nRectsInit,
   1171     xRectangle	*pRectsInit
   1172 ){
   1173     SHADOW_GC_OP_PROLOGUE(pGC);
   1174 
   1175     if(IS_VISIBLE(pDraw) && nRectsInit) {
   1176 	BoxRec box;
   1177         Bool boxNotEmpty = FALSE;
   1178 	xRectangle *pRects = pRectsInit;
   1179 	int nRects = nRectsInit;
   1180 
   1181 	box.x1 = pRects->x;
   1182 	box.x2 = box.x1 + pRects->width;
   1183 	box.y1 = pRects->y;
   1184 	box.y2 = box.y1 + pRects->height;
   1185 
   1186 	while(--nRects) {
   1187 	    pRects++;
   1188 	    if(box.x1 > pRects->x) box.x1 = pRects->x;
   1189 	    if(box.x2 < (pRects->x + pRects->width))
   1190 		box.x2 = pRects->x + pRects->width;
   1191 	    if(box.y1 > pRects->y) box.y1 = pRects->y;
   1192 	    if(box.y2 < (pRects->y + pRects->height))
   1193 		box.y2 = pRects->y + pRects->height;
   1194 	}
   1195 
   1196 	/* cfb messes with the pRectsInit so we have to do our
   1197 	   calculations first */
   1198 
   1199 	TRIM_AND_TRANSLATE_BOX(box, pDraw, pGC);
   1200 	if(BOX_NOT_EMPTY(box)) {
   1201             if(pPriv->preRefresh)
   1202                 (*pPriv->preRefresh)(pPriv->pScrn, 1, &box);
   1203             boxNotEmpty = TRUE;
   1204         }
   1205 
   1206 	(*pGC->ops->PolyFillRect)(pDraw, pGC, nRectsInit, pRectsInit);
   1207 
   1208         if(boxNotEmpty && pPriv->postRefresh)
   1209             (*pPriv->postRefresh)(pPriv->pScrn, 1, &box);
   1210     } else
   1211 	(*pGC->ops->PolyFillRect)(pDraw, pGC, nRectsInit, pRectsInit);
   1212 
   1213     SHADOW_GC_OP_EPILOGUE(pGC);
   1214 }
   1215 
   1216 
   1217 static void
   1218 ShadowPolyFillArc(
   1219     DrawablePtr	pDraw,
   1220     GCPtr	pGC,
   1221     int		narcsInit,
   1222     xArc	*parcsInit
   1223 ){
   1224     BoxRec box;
   1225     Bool boxNotEmpty = FALSE;
   1226 
   1227     SHADOW_GC_OP_PROLOGUE(pGC);
   1228 
   1229     if(IS_VISIBLE(pDraw) && narcsInit) {
   1230         xArc *parcs = parcsInit;
   1231         int narcs = narcsInit;
   1232 
   1233 	box.x1 = parcs->x;
   1234 	box.x2 = box.x1 + parcs->width;
   1235 	box.y1 = parcs->y;
   1236 	box.y2 = box.y1 + parcs->height;
   1237 
   1238 	/* should I break these up instead ? */
   1239 
   1240 	while(--narcs) {
   1241 	   parcs++;
   1242 	   if(box.x1 > parcs->x) box.x1 = parcs->x;
   1243 	   if(box.x2 < (parcs->x + parcs->width))
   1244 		box.x2 = parcs->x + parcs->width;
   1245 	   if(box.y1 > parcs->y) box.y1 = parcs->y;
   1246 	   if(box.y2 < (parcs->y + parcs->height))
   1247 		box.y2 = parcs->y + parcs->height;
   1248         }
   1249 
   1250 	TRIM_AND_TRANSLATE_BOX(box, pDraw, pGC);
   1251 	if(BOX_NOT_EMPTY(box)) {
   1252            if(pPriv->preRefresh)
   1253               (*pPriv->preRefresh)(pPriv->pScrn, 1, &box);
   1254            boxNotEmpty = TRUE;
   1255         }
   1256     }
   1257 
   1258     (*pGC->ops->PolyFillArc)(pDraw, pGC, narcsInit, parcsInit);
   1259 
   1260     if(boxNotEmpty && pPriv->postRefresh)
   1261        (*pPriv->postRefresh)(pPriv->pScrn, 1, &box);
   1262 
   1263     SHADOW_GC_OP_EPILOGUE(pGC);
   1264 }
   1265 
   1266 static void
   1267 ShadowTextExtent(FontPtr pFont, int count, char* chars,
   1268                  FontEncoding fontEncoding, BoxPtr box)
   1269 {
   1270     unsigned long n, i;
   1271     int w;
   1272     CharInfoPtr charinfo[255];	/* encoding only has 1 byte for count */
   1273 
   1274     GetGlyphs(pFont, (unsigned long)count, (unsigned char *)chars,
   1275 	      fontEncoding, &n, charinfo);
   1276     w = 0;
   1277     for (i=0; i < n; i++) {
   1278         w += charinfo[i]->metrics.characterWidth;
   1279     }
   1280     if (i) {
   1281     	w += charinfo[i - 1]->metrics.rightSideBearing;
   1282     }
   1283 
   1284     box->x1 = 0;
   1285     if (n) {
   1286 	if (charinfo[0]->metrics.leftSideBearing < 0) {
   1287             box->x1 = charinfo[0]->metrics.leftSideBearing;
   1288         }
   1289     }
   1290     box->x2 = w;
   1291     box->y1 = -FONTMAXBOUNDS(pFont,ascent);
   1292     box->y2 = FONTMAXBOUNDS(pFont,descent);
   1293 }
   1294 
   1295 
   1296 
   1297 static void
   1298 ShadowFontToBox(BoxPtr BB, DrawablePtr pDrawable, GCPtr pGC, int x, int y,
   1299                 int count, char *chars, int wide)
   1300 {
   1301     FontPtr pFont;
   1302 
   1303     pFont = pGC->font;
   1304     if (pFont->info.constantWidth) {
   1305         int ascent, descent, left, right = 0;
   1306 
   1307 	ascent = max(pFont->info.fontAscent, pFont->info.maxbounds.ascent);
   1308 	descent = max(pFont->info.fontDescent, pFont->info.maxbounds.descent);
   1309 	left = pFont->info.maxbounds.leftSideBearing;
   1310 	if (count > 0) {
   1311 	    right = (count - 1) * pFont->info.maxbounds.characterWidth;
   1312 	}
   1313 	right += pFont->info.maxbounds.rightSideBearing;
   1314 	BB->x1 =
   1315 	    max(pDrawable->x + x - left,
   1316 		RegionExtents(&((WindowPtr) pDrawable)->winSize)->x1);
   1317 	BB->y1 =
   1318 	    max(pDrawable->y + y - ascent,
   1319 		RegionExtents(&((WindowPtr) pDrawable)->winSize)->y1);
   1320 	BB->x2 =
   1321 	    min(pDrawable->x + x + right,
   1322 		RegionExtents(&((WindowPtr) pDrawable)->winSize)->x2);
   1323 	BB->y2 =
   1324 	    min(pDrawable->y + y + descent,
   1325 		RegionExtents(&((WindowPtr) pDrawable)->winSize)->y2);
   1326     } else {
   1327     	ShadowTextExtent(pFont, count, chars, wide ? (FONTLASTROW(pFont) == 0)
   1328                          ? Linear16Bit : TwoD16Bit : Linear8Bit, BB);
   1329 	BB->x1 =
   1330 	    max(pDrawable->x + x + BB->x1,
   1331 		RegionExtents(&((WindowPtr) pDrawable)->winSize)->x1);
   1332 	BB->y1 =
   1333 	    max(pDrawable->y + y + BB->y1,
   1334 		RegionExtents(&((WindowPtr) pDrawable)->winSize)->y1);
   1335 	BB->x2 =
   1336 	    min(pDrawable->x + x + BB->x2,
   1337 		RegionExtents(&((WindowPtr) pDrawable)->winSize)->x2);
   1338 	BB->y2 =
   1339 	    min(pDrawable->y + y + BB->y2,
   1340 		RegionExtents(&((WindowPtr) pDrawable)->winSize)->y2);
   1341     }
   1342 }
   1343 
   1344 static int
   1345 ShadowPolyText8(
   1346     DrawablePtr pDraw,
   1347     GCPtr	pGC,
   1348     int		x,
   1349     int 	y,
   1350     int 	count,
   1351     char	*chars
   1352 ){
   1353     int width;
   1354     BoxRec box;
   1355     Bool boxNotEmpty = FALSE;
   1356 
   1357     SHADOW_GC_OP_PROLOGUE(pGC);
   1358 
   1359     if(IS_VISIBLE(pDraw)) {
   1360         ShadowFontToBox(&box, pDraw, pGC, x, y, count, chars, 0);
   1361 
   1362         TRIM_BOX(box, pGC);
   1363         if(BOX_NOT_EMPTY(box)) {
   1364            if(pPriv->preRefresh)
   1365               (*pPriv->preRefresh)(pPriv->pScrn, 1, &box);
   1366            boxNotEmpty = TRUE;
   1367         }
   1368     }
   1369 
   1370     width = (*pGC->ops->PolyText8)(pDraw, pGC, x, y, count, chars);
   1371 
   1372     if(boxNotEmpty && pPriv->postRefresh)
   1373        (*pPriv->postRefresh)(pPriv->pScrn, 1, &box);
   1374 
   1375     SHADOW_GC_OP_EPILOGUE(pGC);
   1376 
   1377     return width;
   1378 }
   1379 
   1380 static int
   1381 ShadowPolyText16(
   1382     DrawablePtr pDraw,
   1383     GCPtr	pGC,
   1384     int		x,
   1385     int		y,
   1386     int 	count,
   1387     unsigned short *chars
   1388 ){
   1389     int width;
   1390     BoxRec box;
   1391     Bool boxNotEmpty = FALSE;
   1392 
   1393     SHADOW_GC_OP_PROLOGUE(pGC);
   1394 
   1395     if(IS_VISIBLE(pDraw)) {
   1396         ShadowFontToBox(&box, pDraw, pGC, x, y, count, (char*)chars, 1);
   1397 
   1398         TRIM_BOX(box, pGC);
   1399         if(BOX_NOT_EMPTY(box)) {
   1400            if(pPriv->preRefresh)
   1401               (*pPriv->preRefresh)(pPriv->pScrn, 1, &box);
   1402            boxNotEmpty = TRUE;
   1403         }
   1404     }
   1405 
   1406     width = (*pGC->ops->PolyText16)(pDraw, pGC, x, y, count, chars);
   1407 
   1408     if(boxNotEmpty && pPriv->postRefresh)
   1409        (*pPriv->postRefresh)(pPriv->pScrn, 1, &box);
   1410 
   1411     SHADOW_GC_OP_EPILOGUE(pGC);
   1412 
   1413     return width;
   1414 }
   1415 
   1416 static void
   1417 ShadowImageText8(
   1418     DrawablePtr pDraw,
   1419     GCPtr	pGC,
   1420     int		x,
   1421     int		y,
   1422     int 	count,
   1423     char	*chars
   1424 ){
   1425     BoxRec box;
   1426     Bool boxNotEmpty = FALSE;
   1427     SHADOW_GC_OP_PROLOGUE(pGC);
   1428 
   1429     if(IS_VISIBLE(pDraw) && count) {
   1430 	int top, bot, Min, Max;
   1431 
   1432 	top = max(FONTMAXBOUNDS(pGC->font, ascent), FONTASCENT(pGC->font));
   1433 	bot = max(FONTMAXBOUNDS(pGC->font, descent), FONTDESCENT(pGC->font));
   1434 
   1435 	Min = count * FONTMINBOUNDS(pGC->font, characterWidth);
   1436 	if(Min > 0) Min = 0;
   1437 	Max = count * FONTMAXBOUNDS(pGC->font, characterWidth);
   1438 	if(Max < 0) Max = 0;
   1439 
   1440 	/* ugh */
   1441 	box.x1 = pDraw->x + x + Min +
   1442 		FONTMINBOUNDS(pGC->font, leftSideBearing);
   1443 	box.x2 = pDraw->x + x + Max +
   1444 		FONTMAXBOUNDS(pGC->font, rightSideBearing);
   1445 
   1446 	box.y1 = pDraw->y + y - top;
   1447 	box.y2 = pDraw->y + y + bot;
   1448 
   1449 	TRIM_BOX(box, pGC);
   1450 	if(BOX_NOT_EMPTY(box)) {
   1451             if(pPriv->preRefresh)
   1452                (*pPriv->preRefresh)(pPriv->pScrn, 1, &box);
   1453             boxNotEmpty = TRUE;
   1454         }
   1455     }
   1456 
   1457     (*pGC->ops->ImageText8)(pDraw, pGC, x, y, count, chars);
   1458 
   1459     if(boxNotEmpty && pPriv->postRefresh)
   1460         (*pPriv->postRefresh)(pPriv->pScrn, 1, &box);
   1461 
   1462     SHADOW_GC_OP_EPILOGUE(pGC);
   1463 }
   1464 static void
   1465 ShadowImageText16(
   1466     DrawablePtr pDraw,
   1467     GCPtr	pGC,
   1468     int		x,
   1469     int		y,
   1470     int 	count,
   1471     unsigned short *chars
   1472 ){
   1473     BoxRec box;
   1474     Bool boxNotEmpty = FALSE;
   1475     SHADOW_GC_OP_PROLOGUE(pGC);
   1476 
   1477     if(IS_VISIBLE(pDraw) && count) {
   1478 	int top, bot, Min, Max;
   1479 
   1480 	top = max(FONTMAXBOUNDS(pGC->font, ascent), FONTASCENT(pGC->font));
   1481 	bot = max(FONTMAXBOUNDS(pGC->font, descent), FONTDESCENT(pGC->font));
   1482 
   1483 	Min = count * FONTMINBOUNDS(pGC->font, characterWidth);
   1484 	if(Min > 0) Min = 0;
   1485 	Max = count * FONTMAXBOUNDS(pGC->font, characterWidth);
   1486 	if(Max < 0) Max = 0;
   1487 
   1488 	/* ugh */
   1489 	box.x1 = pDraw->x + x + Min +
   1490 		FONTMINBOUNDS(pGC->font, leftSideBearing);
   1491 	box.x2 = pDraw->x + x + Max +
   1492 		FONTMAXBOUNDS(pGC->font, rightSideBearing);
   1493 
   1494 	box.y1 = pDraw->y + y - top;
   1495 	box.y2 = pDraw->y + y + bot;
   1496 
   1497 	TRIM_BOX(box, pGC);
   1498 	if(BOX_NOT_EMPTY(box)) {
   1499            if(pPriv->preRefresh)
   1500               (*pPriv->preRefresh)(pPriv->pScrn, 1, &box);
   1501            boxNotEmpty = TRUE;
   1502         }
   1503     }
   1504 
   1505     (*pGC->ops->ImageText16)(pDraw, pGC, x, y, count, chars);
   1506 
   1507     if(boxNotEmpty && pPriv->postRefresh)
   1508        (*pPriv->postRefresh)(pPriv->pScrn, 1, &box);
   1509 
   1510     SHADOW_GC_OP_EPILOGUE(pGC);
   1511 }
   1512 
   1513 
   1514 static void
   1515 ShadowImageGlyphBlt(
   1516     DrawablePtr pDraw,
   1517     GCPtr pGC,
   1518     int x, int y,
   1519     unsigned int nglyphInit,
   1520     CharInfoPtr *ppciInit,
   1521     pointer pglyphBase
   1522 ){
   1523     BoxRec box;
   1524     Bool boxNotEmpty = FALSE;
   1525     SHADOW_GC_OP_PROLOGUE(pGC);
   1526 
   1527     if(IS_VISIBLE(pDraw) && nglyphInit) {
   1528         CharInfoPtr *ppci = ppciInit;
   1529         unsigned int nglyph = nglyphInit;
   1530 	int top, bot, width = 0;
   1531 
   1532 	top = max(FONTMAXBOUNDS(pGC->font, ascent), FONTASCENT(pGC->font));
   1533 	bot = max(FONTMAXBOUNDS(pGC->font, descent), FONTDESCENT(pGC->font));
   1534 
   1535 	box.x1 = ppci[0]->metrics.leftSideBearing;
   1536 	if(box.x1 > 0) box.x1 = 0;
   1537 	box.x2 = ppci[nglyph - 1]->metrics.rightSideBearing -
   1538 		ppci[nglyph - 1]->metrics.characterWidth;
   1539 	if(box.x2 < 0) box.x2 = 0;
   1540 
   1541 	box.x2 += pDraw->x + x;
   1542 	box.x1 += pDraw->x + x;
   1543 
   1544 	while(nglyph--) {
   1545 	    width += (*ppci)->metrics.characterWidth;
   1546 	    ppci++;
   1547 	}
   1548 
   1549 	if(width > 0)
   1550 	   box.x2 += width;
   1551 	else
   1552 	   box.x1 += width;
   1553 
   1554 	box.y1 = pDraw->y + y - top;
   1555 	box.y2 = pDraw->y + y + bot;
   1556 
   1557 	TRIM_BOX(box, pGC);
   1558 	if(BOX_NOT_EMPTY(box)) {
   1559            if(pPriv->preRefresh)
   1560               (*pPriv->preRefresh)(pPriv->pScrn, 1, &box);
   1561            boxNotEmpty = TRUE;
   1562         }
   1563     }
   1564 
   1565     (*pGC->ops->ImageGlyphBlt)(pDraw, pGC, x, y, nglyphInit,
   1566 					ppciInit, pglyphBase);
   1567 
   1568     if(boxNotEmpty && pPriv->postRefresh)
   1569        (*pPriv->postRefresh)(pPriv->pScrn, 1, &box);
   1570 
   1571     SHADOW_GC_OP_EPILOGUE(pGC);
   1572 }
   1573 
   1574 static void
   1575 ShadowPolyGlyphBlt(
   1576     DrawablePtr pDraw,
   1577     GCPtr pGC,
   1578     int x, int y,
   1579     unsigned int nglyphInit,
   1580     CharInfoPtr *ppciInit,
   1581     pointer pglyphBase
   1582 ){
   1583     BoxRec box;
   1584     Bool boxNotEmpty = FALSE;
   1585 
   1586     SHADOW_GC_OP_PROLOGUE(pGC);
   1587 
   1588     if(IS_VISIBLE(pDraw) && nglyphInit) {
   1589         CharInfoPtr *ppci = ppciInit;
   1590         unsigned int nglyph = nglyphInit;
   1591 
   1592 	/* ugh */
   1593 	box.x1 = pDraw->x + x + ppci[0]->metrics.leftSideBearing;
   1594 	box.x2 = pDraw->x + x + ppci[nglyph - 1]->metrics.rightSideBearing;
   1595 
   1596 	if(nglyph > 1) {
   1597 	    int width = 0;
   1598 
   1599 	    while(--nglyph) {
   1600 		width += (*ppci)->metrics.characterWidth;
   1601 		ppci++;
   1602 	    }
   1603 
   1604 	    if(width > 0) box.x2 += width;
   1605 	    else box.x1 += width;
   1606 	}
   1607 
   1608 	box.y1 = pDraw->y + y - FONTMAXBOUNDS(pGC->font, ascent);
   1609 	box.y2 = pDraw->y + y + FONTMAXBOUNDS(pGC->font, descent);
   1610 
   1611 	TRIM_BOX(box, pGC);
   1612 	if(BOX_NOT_EMPTY(box)) {
   1613            if(pPriv->preRefresh)
   1614               (*pPriv->preRefresh)(pPriv->pScrn, 1, &box);
   1615            boxNotEmpty = TRUE;
   1616         }
   1617     }
   1618 
   1619     (*pGC->ops->PolyGlyphBlt)(pDraw, pGC, x, y, nglyphInit,
   1620 				ppciInit, pglyphBase);
   1621 
   1622     if(boxNotEmpty && pPriv->postRefresh)
   1623        (*pPriv->postRefresh)(pPriv->pScrn, 1, &box);
   1624 
   1625     SHADOW_GC_OP_EPILOGUE(pGC);
   1626 }
   1627 
   1628 static void
   1629 ShadowPushPixels(
   1630     GCPtr	pGC,
   1631     PixmapPtr	pBitMap,
   1632     DrawablePtr pDraw,
   1633     int	dx, int dy, int xOrg, int yOrg
   1634 ){
   1635     BoxRec box;
   1636     Bool boxNotEmpty = FALSE;
   1637 
   1638     SHADOW_GC_OP_PROLOGUE(pGC);
   1639 
   1640     if(IS_VISIBLE(pDraw)) {
   1641 	box.x1 = xOrg;
   1642 	box.y1 = yOrg;
   1643 
   1644         if(!pGC->miTranslate) {
   1645            box.x1 += pDraw->x;
   1646            box.y1 += pDraw->y;
   1647         }
   1648 
   1649 	box.x2 = box.x1 + dx;
   1650 	box.y2 = box.y1 + dy;
   1651 
   1652 	TRIM_BOX(box, pGC);
   1653 	if(BOX_NOT_EMPTY(box)) {
   1654            if(pPriv->preRefresh)
   1655               (*pPriv->preRefresh)(pPriv->pScrn, 1, &box);
   1656            boxNotEmpty = TRUE;
   1657         }
   1658     }
   1659 
   1660     (*pGC->ops->PushPixels)(pGC, pBitMap, pDraw, dx, dy, xOrg, yOrg);
   1661 
   1662     if(boxNotEmpty && pPriv->postRefresh)
   1663        (*pPriv->postRefresh)(pPriv->pScrn, 1, &box);
   1664 
   1665     SHADOW_GC_OP_EPILOGUE(pGC);
   1666 }
   1667 
   1668 
   1669 GCOps ShadowGCOps = {
   1670     ShadowFillSpans, ShadowSetSpans,
   1671     ShadowPutImage, ShadowCopyArea,
   1672     ShadowCopyPlane, ShadowPolyPoint,
   1673     ShadowPolylines, ShadowPolySegment,
   1674     ShadowPolyRectangle, ShadowPolyArc,
   1675     ShadowFillPolygon, ShadowPolyFillRect,
   1676     ShadowPolyFillArc, ShadowPolyText8,
   1677     ShadowPolyText16, ShadowImageText8,
   1678     ShadowImageText16, ShadowImageGlyphBlt,
   1679     ShadowPolyGlyphBlt, ShadowPushPixels,
   1680 };
   1681 
   1682