1/*
2   Copyright (C) 1999.  The XFree86 Project Inc.
3
4   Written by Mark Vojkovich (mvojkovi@ucsd.edu)
5
6   Pre-fb-write callbacks and RENDER support - Nolan Leake (nolan@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
32static Bool ShadowCloseScreen (int i, ScreenPtr pScreen);
33static void ShadowCopyWindow(
34    WindowPtr pWin,
35    DDXPointRec ptOldOrg,
36    RegionPtr prgn
37);
38static Bool ShadowCreateGC(GCPtr pGC);
39
40static Bool ShadowEnterVT(int index, int flags);
41static void ShadowLeaveVT(int index, int flags);
42
43static 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
59typedef 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
73typedef struct {
74   GCOps   *ops;
75   GCFuncs *funcs;
76} ShadowGCRec, *ShadowGCPtr;
77
78static DevPrivateKeyRec ShadowScreenKeyRec;
79#define ShadowScreenKey (&ShadowScreenKeyRec)
80
81static 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
144Bool
145ShadowFBInit2 (
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
195Bool
196ShadowFBInit (
197    ScreenPtr		pScreen,
198    RefreshAreaFuncPtr  refreshArea
199){
200    return ShadowFBInit2(pScreen, NULL, refreshArea);
201}
202
203/**********************************************************/
204
205static Bool
206ShadowEnterVT(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
224static void
225ShadowLeaveVT(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
241static Bool
242ShadowCloseScreen (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
265static void
266ShadowCopyWindow(
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
303static void
304ShadowComposite(
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
358static void ShadowValidateGC(GCPtr, unsigned long, DrawablePtr);
359static void ShadowChangeGC(GCPtr, unsigned long);
360static void ShadowCopyGC(GCPtr, unsigned long, GCPtr);
361static void ShadowDestroyGC(GCPtr);
362static void ShadowChangeClip(GCPtr, int, pointer, int);
363static void ShadowDestroyClip(GCPtr);
364static void ShadowCopyClip(GCPtr, GCPtr);
365
366GCFuncs ShadowGCFuncs = {
367    ShadowValidateGC, ShadowChangeGC, ShadowCopyGC, ShadowDestroyGC,
368    ShadowChangeClip, ShadowDestroyClip, ShadowCopyClip
369};
370
371
372extern GCOps ShadowGCOps;
373
374static Bool
375ShadowCreateGC(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
394static void
395ShadowValidateGC(
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
410static void
411ShadowDestroyGC(GCPtr pGC)
412{
413    SHADOW_GC_FUNC_PROLOGUE (pGC);
414    (*pGC->funcs->DestroyGC)(pGC);
415    SHADOW_GC_FUNC_EPILOGUE (pGC);
416}
417
418static void
419ShadowChangeGC (
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
428static void
429ShadowCopyGC (
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
439static void
440ShadowChangeClip (
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
451static void
452ShadowCopyClip(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
459static void
460ShadowDestroyClip(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
473static void
474ShadowFillSpans(
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
528static void
529ShadowSetSpans(
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
586static void
587ShadowPutImage(
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
625static RegionPtr
626ShadowCopyArea(
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
665static RegionPtr
666ShadowCopyPlane(
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
706static void
707ShadowPolyPoint(
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
755static void
756ShadowPolylines(
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
831static void
832ShadowPolySegment(
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
911static void
912ShadowPolyRectangle(
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
1042static void
1043ShadowPolyArc(
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
1103static void
1104ShadowFillPolygon(
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
1166static void
1167ShadowPolyFillRect(
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
1217static void
1218ShadowPolyFillArc(
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
1266static void
1267ShadowTextExtent(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
1297static void
1298ShadowFontToBox(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
1344static int
1345ShadowPolyText8(
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
1380static int
1381ShadowPolyText16(
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
1416static void
1417ShadowImageText8(
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}
1464static void
1465ShadowImageText16(
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
1514static void
1515ShadowImageGlyphBlt(
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
1574static void
1575ShadowPolyGlyphBlt(
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
1628static void
1629ShadowPushPixels(
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
1669GCOps 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