1/*
2 * Copyright © 2003 Keith Packard
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation, and that the name of Keith Packard not be used in
9 * advertising or publicity pertaining to distribution of the software without
10 * specific, written prior permission.  Keith Packard makes no
11 * representations about the suitability of this software for any purpose.  It
12 * is provided "as is" without express or implied warranty.
13 *
14 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
20 * PERFORMANCE OF THIS SOFTWARE.
21 */
22
23#ifdef HAVE_DIX_CONFIG_H
24#include <dix-config.h>
25#endif
26
27#include <stdlib.h>
28#include "uxa-priv.h"
29
30#include    <dixfontstr.h>
31#include    <gcstruct.h>
32#include    <picturestr.h>
33#include    <scrnintstr.h>
34#include    <windowstr.h>
35#include    <X11/X.h>
36#include    <X11/fonts/font.h>
37#include    <X11/fonts/fontstruct.h>
38#ifdef HAVE_XFONT2
39#include    <X11/fonts/libxfont2.h>
40#else
41#include    <X11/fonts/fontutil.h>
42#endif
43
44#include    "uxa-damage.h"
45
46typedef struct _damageGCPriv {
47    GCOps   *ops;
48    GCFuncs *funcs;
49} DamageGCPrivRec, *DamageGCPrivPtr;
50
51#define DAMAGE_VALIDATE_ENABLE 0
52#define DAMAGE_DEBUG_ENABLE 0
53#if DAMAGE_DEBUG_ENABLE
54#define DAMAGE_DEBUG(x)	ErrorF x
55#else
56#define DAMAGE_DEBUG(x)
57#endif
58
59#define TRIM_BOX(box, pGC) if (pGC->pCompositeClip) {			\
60	BoxPtr extents = &pGC->pCompositeClip->extents;			\
61	if(box.x1 < extents->x1) box.x1 = extents->x1;			\
62	if(box.x2 > extents->x2) box.x2 = extents->x2;			\
63	if(box.y1 < extents->y1) box.y1 = extents->y1;			\
64	if(box.y2 > extents->y2) box.y2 = extents->y2;			\
65    }
66
67#define TRANSLATE_BOX(box, pDrawable) {					\
68	box.x1 += pDrawable->x;						\
69	box.x2 += pDrawable->x;						\
70	box.y1 += pDrawable->y;						\
71	box.y2 += pDrawable->y;						\
72    }
73
74#define TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC) {			\
75	TRANSLATE_BOX(box, pDrawable);					\
76	TRIM_BOX(box, pGC);						\
77    }
78
79#define BOX_NOT_EMPTY(box)						\
80    (((box.x2 - box.x1) > 0) && ((box.y2 - box.y1) > 0))
81
82#define checkGCDamage(g)	((!g->pCompositeClip ||			\
83				  REGION_NOTEMPTY(d->pScreen,		\
84						  g->pCompositeClip)))
85
86#define TRIM_PICTURE_BOX(box, pDst) {					\
87	BoxPtr extents = &pDst->pCompositeClip->extents;		\
88	if(box.x1 < extents->x1) box.x1 = extents->x1;			\
89	if(box.x2 > extents->x2) box.x2 = extents->x2;			\
90	if(box.y1 < extents->y1) box.y1 = extents->y1;			\
91	if(box.y2 > extents->y2) box.y2 = extents->y2;			\
92    }
93
94#define checkPictureDamage(p)	(REGION_NOTEMPTY(pScreen, p->pCompositeClip))
95
96static void
97trim_region (RegionPtr   pRegion,
98	     DrawablePtr pDrawable,
99	     int         subWindowMode)
100{
101    RegionRec       pixClip;
102    int		    draw_x = 0;
103    int		    draw_y = 0;
104#ifdef COMPOSITE
105    int             screen_x = 0, screen_y = 0;
106#endif
107
108    /* short circuit for empty regions */
109    if (!REGION_NOTEMPTY(pScreen, pRegion))
110        return;
111
112#ifdef COMPOSITE
113    /*
114     * When drawing to a pixmap which is storing window contents,
115     * the region presented is in pixmap relative coordinates which
116     * need to be converted to screen relative coordinates
117     */
118    if (pDrawable->type != DRAWABLE_WINDOW)
119    {
120        screen_x = ((PixmapPtr) pDrawable)->screen_x - pDrawable->x;
121        screen_y = ((PixmapPtr) pDrawable)->screen_y - pDrawable->y;
122    }
123    if (screen_x || screen_y)
124        REGION_TRANSLATE (pScreen, pRegion, screen_x, screen_y);
125#endif
126
127    /* Clip against any children */
128    if (pDrawable->type == DRAWABLE_WINDOW &&
129        ((WindowPtr)(pDrawable))->backingStore == NotUseful)
130    {
131        if (subWindowMode == ClipByChildren)
132        {
133            REGION_INTERSECT(pScreen, pRegion, pRegion,
134                             &((WindowPtr)(pDrawable))->clipList);
135        }
136        else if (subWindowMode == IncludeInferiors)
137        {
138	    RegionPtr pTempRegion =
139                NotClippedByChildren((WindowPtr)(pDrawable));
140            REGION_INTERSECT(pScreen, pRegion, pRegion, pTempRegion);
141            REGION_DESTROY(pScreen, pTempRegion);
142        }
143        /* If subWindowMode is set to an invalid value, don't perform
144         * any drawable-based clipping. */
145    }
146
147    /* Clip against border or pixmap bounds */
148    if (pDrawable->type == DRAWABLE_WINDOW)
149    {
150	REGION_INTERSECT (pScreen, pRegion, pRegion,
151			  &((WindowPtr)(pDrawable))->borderClip);
152    }
153    else
154    {
155	BoxRec  box;
156
157	draw_x = pDrawable->x;
158	draw_y = pDrawable->y;
159#ifdef COMPOSITE
160	/*
161	 * Need to move everyone to screen coordinates
162	 * XXX what about off-screen pixmaps with non-zero x/y?
163	 */
164	if (!WindowDrawable(pDrawable->type))
165	{
166	    draw_x += ((PixmapPtr) pDrawable)->screen_x;
167	    draw_y += ((PixmapPtr) pDrawable)->screen_y;
168	}
169#endif
170
171	box.x1 = draw_x;
172	box.y1 = draw_y;
173	box.x2 = draw_x + pDrawable->width;
174	box.y2 = draw_y + pDrawable->height;
175
176	REGION_INIT(pScreen, &pixClip, &box, 1);
177	REGION_INTERSECT (pScreen, pRegion, pRegion, &pixClip);
178	REGION_UNINIT(pScreen, &pixClip);
179    }
180
181    /*
182     * Move region to target coordinate space
183     */
184    if (draw_x || draw_y)
185	REGION_TRANSLATE (pScreen, pRegion, -draw_x, -draw_y);
186
187    /* Now do something with the damage */
188}
189
190static void
191add_region (RegionPtr	existing,
192	    RegionPtr	new,
193	    DrawablePtr pDrawable,
194	    int         subWindowMode)
195{
196    trim_region (new, pDrawable, subWindowMode);
197
198    REGION_UNION (pDrawable->pScreen, existing, existing, new);
199}
200
201static void
202add_box (RegionPtr   existing,
203	 BoxPtr	     box,
204	 DrawablePtr drawable,
205	 int	     subwindow_mode)
206{
207    RegionRec   region;
208
209    REGION_INIT (pDrawable->pScreen, &region, box, 1);
210
211    add_region (existing, &region, drawable, subwindow_mode);
212
213    REGION_UNINIT (pDrawable->pScreen, &region);
214}
215
216
217void
218uxa_damage_composite (RegionPtr  region,
219		      CARD8      op,
220		      PicturePtr pSrc,
221		      PicturePtr pMask,
222		      PicturePtr pDst,
223		      INT16      xSrc,
224		      INT16      ySrc,
225		      INT16      xMask,
226		      INT16      yMask,
227		      INT16      xDst,
228		      INT16      yDst,
229		      CARD16     width,
230		      CARD16     height)
231{
232    if (checkPictureDamage (pDst))
233    {
234	BoxRec	box;
235
236	box.x1 = xDst + pDst->pDrawable->x;
237	box.y1 = yDst + pDst->pDrawable->y;
238	box.x2 = box.x1 + width;
239	box.y2 = box.y1 + height;
240
241	TRIM_PICTURE_BOX(box, pDst);
242
243	if (BOX_NOT_EMPTY(box))
244	    add_box (region, &box, pDst->pDrawable, pDst->subWindowMode);
245    }
246}
247
248void
249uxa_damage_glyphs (RegionPtr		region,
250		   CARD8		op,
251		   PicturePtr	pSrc,
252		   PicturePtr	pDst,
253		   PictFormatPtr	maskFormat,
254		   INT16		xSrc,
255		   INT16		ySrc,
256		   int		nlist,
257		   GlyphListPtr	list,
258		   GlyphPtr	       *glyphs)
259{
260    if (checkPictureDamage (pDst))
261    {
262	int		nlistTmp = nlist;
263	GlyphListPtr	listTmp = list;
264	GlyphPtr	*glyphsTmp = glyphs;
265	int		x, y;
266	int		n;
267	GlyphPtr	glyph;
268	BoxRec		box;
269	int		x1, y1, x2, y2;
270
271	box.x1 = 32767;
272	box.y1 = 32767;
273	box.x2 = -32767;
274	box.y2 = -32767;
275	x = pDst->pDrawable->x;
276	y = pDst->pDrawable->y;
277	while (nlistTmp--)
278	{
279	    x += listTmp->xOff;
280	    y += listTmp->yOff;
281	    n = listTmp->len;
282	    while (n--)
283	    {
284		glyph = *glyphsTmp++;
285		x1 = x - glyph->info.x;
286		y1 = y - glyph->info.y;
287		x2 = x1 + glyph->info.width;
288		y2 = y1 + glyph->info.height;
289		if (x1 < box.x1)
290		    box.x1 = x1;
291		if (y1 < box.y1)
292		    box.y1 = y1;
293		if (x2 > box.x2)
294		    box.x2 = x2;
295		if (y2 > box.y2)
296		    box.y2 = y2;
297		x += glyph->info.xOff;
298		y += glyph->info.yOff;
299	    }
300	    listTmp++;
301	}
302	TRIM_PICTURE_BOX (box, pDst);
303	if (BOX_NOT_EMPTY(box))
304	    add_box (region, &box, pDst->pDrawable, pDst->subWindowMode);
305    }
306}
307
308void
309uxa_damage_add_traps (RegionPtr   region,
310		      PicturePtr  pPicture,
311		      INT16	    x_off,
312		      INT16	    y_off,
313		      int	    ntrap,
314		      xTrap	    *traps)
315{
316    if (checkPictureDamage (pPicture))
317    {
318	BoxRec	box;
319	int	i;
320	int	x, y;
321	xTrap	*t = traps;
322
323	box.x1 = 32767;
324	box.y1 = 32767;
325	box.x2 = -32767;
326	box.y2 = -32767;
327	x = pPicture->pDrawable->x + x_off;
328	y = pPicture->pDrawable->y + y_off;
329	for (i = 0; i < ntrap; i++)
330	{
331	    pixman_fixed_t   l = min (t->top.l, t->bot.l);
332	    pixman_fixed_t   r = max (t->top.r, t->bot.r);
333	    int	    x1 = x + pixman_fixed_to_int (l);
334	    int	    x2 = x + pixman_fixed_to_int (pixman_fixed_ceil (r));
335	    int	    y1 = y + pixman_fixed_to_int (t->top.y);
336	    int	    y2 = y + pixman_fixed_to_int (pixman_fixed_ceil (t->bot.y));
337
338	    if (x1 < box.x1)
339		box.x1 = x1;
340	    if (x2 > box.x2)
341		box.x2 = x2;
342	    if (y1 < box.y1)
343		box.y1 = y1;
344	    if (y2 > box.y2)
345		box.y2 = y2;
346	}
347	TRIM_PICTURE_BOX (box, pPicture);
348	if (BOX_NOT_EMPTY(box))
349	    add_box (region, &box, pPicture->pDrawable, pPicture->subWindowMode);
350    }
351}
352
353/**********************************************************/
354
355
356void
357uxa_damage_fill_spans (RegionPtr   region,
358		       DrawablePtr pDrawable,
359		       GC	    *pGC,
360		       int	     npt,
361		       DDXPointPtr ppt,
362		       int	    *pwidth,
363		       int	     fSorted)
364{
365    if (npt && checkGCDamage (pGC))
366    {
367	int	    nptTmp = npt;
368	DDXPointPtr pptTmp = ppt;
369	int	    *pwidthTmp = pwidth;
370	BoxRec	    box;
371
372	box.x1 = pptTmp->x;
373	box.x2 = box.x1 + *pwidthTmp;
374	box.y2 = box.y1 = pptTmp->y;
375
376	while(--nptTmp)
377	{
378	    pptTmp++;
379	    pwidthTmp++;
380	    if(box.x1 > pptTmp->x) box.x1 = pptTmp->x;
381	    if(box.x2 < (pptTmp->x + *pwidthTmp))
382		box.x2 = pptTmp->x + *pwidthTmp;
383	    if(box.y1 > pptTmp->y) box.y1 = pptTmp->y;
384	    else if(box.y2 < pptTmp->y) box.y2 = pptTmp->y;
385	}
386
387	box.y2++;
388
389        if(!pGC->miTranslate) {
390	    TRANSLATE_BOX(box, pDrawable);
391        }
392        TRIM_BOX(box, pGC);
393
394	if(BOX_NOT_EMPTY(box))
395	    add_box (region, &box, pDrawable, pGC->subWindowMode);
396    }
397}
398
399void
400uxa_damage_set_spans (RegionPtr    region,
401		      DrawablePtr  pDrawable,
402		      GCPtr	     pGC,
403		      char	    *pcharsrc,
404		      DDXPointPtr  ppt,
405		      int	    *pwidth,
406		      int	     npt,
407		      int	     fSorted)
408{
409    if (npt && checkGCDamage (pGC))
410    {
411	DDXPointPtr pptTmp = ppt;
412	int	    *pwidthTmp = pwidth;
413	int	    nptTmp = npt;
414	BoxRec	    box;
415
416	box.x1 = pptTmp->x;
417	box.x2 = box.x1 + *pwidthTmp;
418	box.y2 = box.y1 = pptTmp->y;
419
420	while(--nptTmp)
421	{
422	    pptTmp++;
423	    pwidthTmp++;
424	    if(box.x1 > pptTmp->x) box.x1 = pptTmp->x;
425	    if(box.x2 < (pptTmp->x + *pwidthTmp))
426		box.x2 = pptTmp->x + *pwidthTmp;
427	    if(box.y1 > pptTmp->y) box.y1 = pptTmp->y;
428	    else if(box.y2 < pptTmp->y) box.y2 = pptTmp->y;
429	}
430
431	box.y2++;
432
433        if(!pGC->miTranslate) {
434	    TRANSLATE_BOX(box, pDrawable);
435        }
436        TRIM_BOX(box, pGC);
437
438	if(BOX_NOT_EMPTY(box))
439	    add_box (region, &box, pDrawable, pGC->subWindowMode);
440    }
441}
442
443void
444uxa_damage_put_image (RegionPtr    region,
445		      DrawablePtr  pDrawable,
446		      GCPtr	     pGC,
447		      int	     depth,
448		      int	     x,
449		      int	     y,
450		      int	     w,
451		      int	     h,
452		      int	     leftPad,
453		      int	     format,
454		      char	    *pImage)
455{
456    if (checkGCDamage (pGC))
457    {
458	BoxRec box;
459
460	box.x1 = x + pDrawable->x;
461	box.x2 = box.x1 + w;
462	box.y1 = y + pDrawable->y;
463	box.y2 = box.y1 + h;
464
465	TRIM_BOX(box, pGC);
466	if(BOX_NOT_EMPTY(box))
467	    add_box (region, &box, pDrawable, pGC->subWindowMode);
468    }
469}
470
471void
472uxa_damage_copy_area(RegionPtr    region,
473		     DrawablePtr  pSrc,
474		     DrawablePtr  pDst,
475		     GC	         *pGC,
476		     int	  srcx,
477		     int	  srcy,
478		     int	    width,
479		     int	    height,
480		     int	    dstx,
481		     int	    dsty)
482{
483    if (checkGCDamage (pGC))
484    {
485	BoxRec box;
486
487	box.x1 = dstx + pDst->x;
488	box.x2 = box.x1 + width;
489	box.y1 = dsty + pDst->y;
490	box.y2 = box.y1 + height;
491
492	TRIM_BOX(box, pGC);
493	if(BOX_NOT_EMPTY(box))
494	    add_box (region, &box, pDst, pGC->subWindowMode);
495    }
496}
497
498void
499uxa_damage_copy_plane (RegionPtr	region,
500		       DrawablePtr	pSrc,
501		       DrawablePtr	pDst,
502		       GCPtr		pGC,
503		       int		srcx,
504		       int		srcy,
505		       int		width,
506		       int		height,
507		       int		dstx,
508		       int		dsty,
509		       unsigned long	bitPlane)
510{
511    if (checkGCDamage (pGC))
512    {
513	BoxRec box;
514
515	box.x1 = dstx + pDst->x;
516	box.x2 = box.x1 + width;
517	box.y1 = dsty + pDst->y;
518	box.y2 = box.y1 + height;
519
520	TRIM_BOX(box, pGC);
521	if(BOX_NOT_EMPTY(box))
522	    add_box (region, &box, pDst, pGC->subWindowMode);
523    }
524}
525
526void
527uxa_damage_poly_point (RegionPtr   region,
528		       DrawablePtr pDrawable,
529		       GCPtr	    pGC,
530		       int	    mode,
531		       int	    npt,
532		       xPoint	    *ppt)
533{
534    if (npt && checkGCDamage (pGC))
535    {
536	BoxRec	box;
537	int	nptTmp = npt;
538	xPoint	*pptTmp = ppt;
539
540	box.x2 = box.x1 = pptTmp->x;
541	box.y2 = box.y1 = pptTmp->y;
542
543	/* this could be slow if the points were spread out */
544
545	while(--nptTmp)
546	{
547	    pptTmp++;
548	    if(box.x1 > pptTmp->x) box.x1 = pptTmp->x;
549	    else if(box.x2 < pptTmp->x) box.x2 = pptTmp->x;
550	    if(box.y1 > pptTmp->y) box.y1 = pptTmp->y;
551	    else if(box.y2 < pptTmp->y) box.y2 = pptTmp->y;
552	}
553
554	box.x2++;
555	box.y2++;
556
557	TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC);
558	if(BOX_NOT_EMPTY(box))
559	    add_box (region, &box, pDrawable, pGC->subWindowMode);
560    }
561}
562
563void
564uxa_damage_poly_lines (RegionPtr  region,
565		       DrawablePtr pDrawable,
566		       GCPtr	    pGC,
567		       int	    mode,
568		       int	    npt,
569		       DDXPointPtr ppt)
570{
571    if (npt && checkGCDamage (pGC))
572    {
573	int	    nptTmp = npt;
574	DDXPointPtr pptTmp = ppt;
575	BoxRec	    box;
576	int	    extra = pGC->lineWidth >> 1;
577
578	box.x2 = box.x1 = pptTmp->x;
579	box.y2 = box.y1 = pptTmp->y;
580
581	if(nptTmp > 1)
582	{
583	    if(pGC->joinStyle == JoinMiter)
584		extra = 6 * pGC->lineWidth;
585	    else if(pGC->capStyle == CapProjecting)
586		extra = pGC->lineWidth;
587        }
588
589	if(mode == CoordModePrevious)
590	{
591	    int x = box.x1;
592	    int y = box.y1;
593	    while(--nptTmp)
594	    {
595		pptTmp++;
596		x += pptTmp->x;
597		y += pptTmp->y;
598		if(box.x1 > x) box.x1 = x;
599		else if(box.x2 < x) box.x2 = x;
600		if(box.y1 > y) box.y1 = y;
601		else if(box.y2 < y) box.y2 = y;
602	    }
603	}
604	else
605	{
606	    while(--nptTmp)
607	    {
608		pptTmp++;
609		if(box.x1 > pptTmp->x) box.x1 = pptTmp->x;
610		else if(box.x2 < pptTmp->x) box.x2 = pptTmp->x;
611		if(box.y1 > pptTmp->y) box.y1 = pptTmp->y;
612		else if(box.y2 < pptTmp->y) box.y2 = pptTmp->y;
613	    }
614	}
615
616	box.x2++;
617	box.y2++;
618
619	if(extra)
620	{
621	    box.x1 -= extra;
622	    box.x2 += extra;
623	    box.y1 -= extra;
624	    box.y2 += extra;
625        }
626
627	TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC);
628	if(BOX_NOT_EMPTY(box))
629	    add_box (region, &box, pDrawable, pGC->subWindowMode);
630    }
631}
632
633void
634uxa_damage_poly_segment (RegionPtr    region,
635			 DrawablePtr	pDrawable,
636			 GCPtr	pGC,
637			 int		nSeg,
638			 xSegment	*pSeg)
639{
640    if (nSeg && checkGCDamage (pGC))
641    {
642	BoxRec	    box;
643	int	    extra = pGC->lineWidth;
644	int	    nsegTmp = nSeg;
645	xSegment    *pSegTmp = pSeg;
646
647        if(pGC->capStyle != CapProjecting)
648	    extra >>= 1;
649
650	if(pSegTmp->x2 > pSegTmp->x1) {
651	    box.x1 = pSegTmp->x1;
652	    box.x2 = pSegTmp->x2;
653	} else {
654	    box.x2 = pSegTmp->x1;
655	    box.x1 = pSegTmp->x2;
656	}
657
658	if(pSegTmp->y2 > pSegTmp->y1) {
659	    box.y1 = pSegTmp->y1;
660	    box.y2 = pSegTmp->y2;
661	} else {
662	    box.y2 = pSegTmp->y1;
663	    box.y1 = pSegTmp->y2;
664	}
665
666	while(--nsegTmp)
667	{
668	    pSegTmp++;
669	    if(pSegTmp->x2 > pSegTmp->x1)
670	    {
671		if(pSegTmp->x1 < box.x1) box.x1 = pSegTmp->x1;
672		if(pSegTmp->x2 > box.x2) box.x2 = pSegTmp->x2;
673	    }
674	    else
675	    {
676		if(pSegTmp->x2 < box.x1) box.x1 = pSegTmp->x2;
677		if(pSegTmp->x1 > box.x2) box.x2 = pSegTmp->x1;
678	    }
679	    if(pSegTmp->y2 > pSegTmp->y1)
680	    {
681		if(pSegTmp->y1 < box.y1) box.y1 = pSegTmp->y1;
682		if(pSegTmp->y2 > box.y2) box.y2 = pSegTmp->y2;
683	    }
684	    else
685	    {
686		if(pSegTmp->y2 < box.y1) box.y1 = pSegTmp->y2;
687		if(pSegTmp->y1 > box.y2) box.y2 = pSegTmp->y1;
688	    }
689	}
690
691	box.x2++;
692	box.y2++;
693
694	if(extra)
695	{
696	    box.x1 -= extra;
697	    box.x2 += extra;
698	    box.y1 -= extra;
699	    box.y2 += extra;
700        }
701
702	TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC);
703	if(BOX_NOT_EMPTY(box))
704	    add_box (region, &box, pDrawable, pGC->subWindowMode);
705    }
706}
707
708void
709uxa_damage_poly_rectangle (RegionPtr    region,
710			   DrawablePtr  pDrawable,
711			   GCPtr        pGC,
712			   int	  nRects,
713			   xRectangle  *pRects)
714{
715    if (nRects && checkGCDamage (pGC))
716    {
717	BoxRec	    box;
718	int	    offset1, offset2, offset3;
719	int	    nRectsTmp = nRects;
720	xRectangle  *pRectsTmp = pRects;
721
722	offset2 = pGC->lineWidth;
723	if(!offset2) offset2 = 1;
724	offset1 = offset2 >> 1;
725	offset3 = offset2 - offset1;
726
727	while(nRectsTmp--)
728	{
729	    box.x1 = pRectsTmp->x - offset1;
730	    box.y1 = pRectsTmp->y - offset1;
731	    box.x2 = box.x1 + pRectsTmp->width + offset2;
732	    box.y2 = box.y1 + offset2;
733	    TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC);
734	    if(BOX_NOT_EMPTY(box))
735		add_box (region, &box, pDrawable, pGC->subWindowMode);
736
737	    box.x1 = pRectsTmp->x - offset1;
738	    box.y1 = pRectsTmp->y + offset3;
739	    box.x2 = box.x1 + offset2;
740	    box.y2 = box.y1 + pRectsTmp->height - offset2;
741	    TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC);
742	    if(BOX_NOT_EMPTY(box))
743		add_box (region, &box, pDrawable, pGC->subWindowMode);
744
745	    box.x1 = pRectsTmp->x + pRectsTmp->width - offset1;
746	    box.y1 = pRectsTmp->y + offset3;
747	    box.x2 = box.x1 + offset2;
748	    box.y2 = box.y1 + pRectsTmp->height - offset2;
749	    TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC);
750	    if(BOX_NOT_EMPTY(box))
751		add_box (region, &box, pDrawable, pGC->subWindowMode);
752
753	    box.x1 = pRectsTmp->x - offset1;
754	    box.y1 = pRectsTmp->y + pRectsTmp->height - offset1;
755	    box.x2 = box.x1 + pRectsTmp->width + offset2;
756	    box.y2 = box.y1 + offset2;
757	    TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC);
758	    if(BOX_NOT_EMPTY(box))
759		add_box (region, &box, pDrawable, pGC->subWindowMode);
760
761	    pRectsTmp++;
762	}
763    }
764}
765
766void
767uxa_damage_poly_arc (RegionPtr    region,
768		     DrawablePtr  pDrawable,
769		     GCPtr	    pGC,
770		     int	    nArcs,
771		     xArc	    *pArcs)
772{
773    if (nArcs && checkGCDamage (pGC))
774    {
775	int	extra = pGC->lineWidth >> 1;
776	BoxRec	box;
777	int	nArcsTmp = nArcs;
778	xArc	*pArcsTmp = pArcs;
779
780	box.x1 = pArcsTmp->x;
781	box.x2 = box.x1 + pArcsTmp->width;
782	box.y1 = pArcsTmp->y;
783	box.y2 = box.y1 + pArcsTmp->height;
784
785	while(--nArcsTmp)
786	{
787	    pArcsTmp++;
788	    if(box.x1 > pArcsTmp->x)
789		box.x1 = pArcsTmp->x;
790	    if(box.x2 < (pArcsTmp->x + pArcsTmp->width))
791		box.x2 = pArcsTmp->x + pArcsTmp->width;
792	    if(box.y1 > pArcsTmp->y)
793		box.y1 = pArcsTmp->y;
794	    if(box.y2 < (pArcsTmp->y + pArcsTmp->height))
795		box.y2 = pArcsTmp->y + pArcsTmp->height;
796        }
797
798	if(extra)
799	{
800	    box.x1 -= extra;
801	    box.x2 += extra;
802	    box.y1 -= extra;
803	    box.y2 += extra;
804        }
805
806	box.x2++;
807	box.y2++;
808
809	TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC);
810	if(BOX_NOT_EMPTY(box))
811	    add_box (region, &box, pDrawable, pGC->subWindowMode);
812    }
813}
814
815void
816uxa_damage_fill_polygon (RegionPtr     region,
817			 DrawablePtr	pDrawable,
818			 GCPtr		pGC,
819			 int		shape,
820			 int		mode,
821			 int		npt,
822			 DDXPointPtr	ppt)
823{
824    if (npt > 2 && checkGCDamage (pGC))
825    {
826	DDXPointPtr pptTmp = ppt;
827	int	    nptTmp = npt;
828	BoxRec	    box;
829
830	box.x2 = box.x1 = pptTmp->x;
831	box.y2 = box.y1 = pptTmp->y;
832
833	if(mode != CoordModeOrigin)
834	{
835	    int x = box.x1;
836	    int y = box.y1;
837	    while(--nptTmp)
838	    {
839		pptTmp++;
840		x += pptTmp->x;
841		y += pptTmp->y;
842		if(box.x1 > x) box.x1 = x;
843		else if(box.x2 < x) box.x2 = x;
844		if(box.y1 > y) box.y1 = y;
845		else if(box.y2 < y) box.y2 = y;
846	    }
847	}
848	else
849	{
850	    while(--nptTmp)
851	    {
852		pptTmp++;
853		if(box.x1 > pptTmp->x) box.x1 = pptTmp->x;
854		else if(box.x2 < pptTmp->x) box.x2 = pptTmp->x;
855		if(box.y1 > pptTmp->y) box.y1 = pptTmp->y;
856		else if(box.y2 < pptTmp->y) box.y2 = pptTmp->y;
857	    }
858	}
859
860	box.x2++;
861	box.y2++;
862
863	TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC);
864	if(BOX_NOT_EMPTY(box))
865	    add_box (region, &box, pDrawable, pGC->subWindowMode);
866    }
867}
868
869
870void
871uxa_damage_poly_fill_rect (RegionPtr   region,
872			   DrawablePtr	pDrawable,
873			   GCPtr	pGC,
874			   int		nRects,
875			   xRectangle	*pRects)
876{
877    if (nRects && checkGCDamage (pGC))
878    {
879	int i;
880
881	for (i = 0; i < nRects; ++i)
882	{
883	    xRectangle *rect = &(pRects[i]);
884	    BoxRec box;
885
886	    box.x1 = rect->x;
887	    box.x2 = rect->x + rect->width;
888	    box.y1 = rect->y;
889	    box.y2 = rect->y + rect->height;
890
891	    TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC);
892	    if(BOX_NOT_EMPTY(box))
893		add_box (region, &box, pDrawable, pGC->subWindowMode);
894	}
895    }
896}
897
898
899void
900uxa_damage_poly_fill_arc (RegionPtr    region,
901			  DrawablePtr	pDrawable,
902			  GCPtr		pGC,
903			  int		nArcs,
904			  xArc		*pArcs)
905{
906    if (nArcs && checkGCDamage (pGC))
907    {
908	BoxRec	box;
909	int	nArcsTmp = nArcs;
910	xArc	*pArcsTmp = pArcs;
911
912	box.x1 = pArcsTmp->x;
913	box.x2 = box.x1 + pArcsTmp->width;
914	box.y1 = pArcsTmp->y;
915	box.y2 = box.y1 + pArcsTmp->height;
916
917	while(--nArcsTmp)
918	{
919	    pArcsTmp++;
920	    if(box.x1 > pArcsTmp->x)
921		box.x1 = pArcsTmp->x;
922	    if(box.x2 < (pArcsTmp->x + pArcsTmp->width))
923		box.x2 = pArcsTmp->x + pArcsTmp->width;
924	    if(box.y1 > pArcsTmp->y)
925		box.y1 = pArcsTmp->y;
926	    if(box.y2 < (pArcsTmp->y + pArcsTmp->height))
927		box.y2 = pArcsTmp->y + pArcsTmp->height;
928        }
929
930	TRIM_AND_TRANSLATE_BOX(box, pDrawable, pGC);
931	if(BOX_NOT_EMPTY(box))
932	    add_box (region, &box, pDrawable, pGC->subWindowMode);
933    }
934}
935
936/*
937 * general Poly/Image text function.  Extract glyph information,
938 * compute bounding box and remove cursor if it is overlapped.
939 */
940
941void
942uxa_damage_chars (RegionPtr	region,
943		  DrawablePtr	pDrawable,
944		  FontPtr	font,
945		  int		x,
946		  int		y,
947		  unsigned int	n,
948		  CharInfoPtr	*charinfo,
949		  Bool		imageblt,
950		  int		subWindowMode)
951{
952    ExtentInfoRec   extents;
953    BoxRec	    box;
954
955#ifdef HAVE_XFONT2
956    xfont2_query_glyph_extents(font, charinfo, n, &extents);
957#else
958    QueryGlyphExtents(font, charinfo, n, &extents);
959#endif
960    if (imageblt)
961    {
962	if (extents.overallWidth > extents.overallRight)
963	    extents.overallRight = extents.overallWidth;
964	if (extents.overallWidth < extents.overallLeft)
965	    extents.overallLeft = extents.overallWidth;
966	if (extents.overallLeft > 0)
967	    extents.overallLeft = 0;
968	if (extents.fontAscent > extents.overallAscent)
969	    extents.overallAscent = extents.fontAscent;
970	if (extents.fontDescent > extents.overallDescent)
971	    extents.overallDescent = extents.fontDescent;
972    }
973    box.x1 = x + extents.overallLeft;
974    box.y1 = y - extents.overallAscent;
975    box.x2 = x + extents.overallRight;
976    box.y2 = y + extents.overallDescent;
977    add_box (region, &box, pDrawable, subWindowMode);
978}
979
980/*
981 * values for textType:
982 */
983#define TT_POLY8   0
984#define TT_IMAGE8  1
985#define TT_POLY16  2
986#define TT_IMAGE16 3
987
988int
989uxa_damage_text (RegionPtr	region,
990		 DrawablePtr	    pDrawable,
991		 GCPtr	    pGC,
992		 int		    x,
993		 int		    y,
994		 unsigned long   count,
995		 char	    *chars,
996		 FontEncoding    fontEncoding,
997		 Bool	    textType)
998{
999    CharInfoPtr	    *charinfo;
1000    CharInfoPtr	    *info;
1001    unsigned long   i;
1002    unsigned int    n;
1003    int		    w;
1004    Bool	    imageblt;
1005
1006    imageblt = (textType == TT_IMAGE8) || (textType == TT_IMAGE16);
1007
1008    charinfo = malloc(count * sizeof(CharInfoPtr));
1009    if (!charinfo)
1010	return x;
1011
1012    GetGlyphs(pGC->font, count, (unsigned char *)chars,
1013	      fontEncoding, &i, charinfo);
1014    n = (unsigned int)i;
1015    w = 0;
1016    if (!imageblt)
1017	for (info = charinfo; i--; info++)
1018	    w += (*info)->metrics.characterWidth;
1019
1020    if (n != 0) {
1021	uxa_damage_chars (region,
1022			  pDrawable, pGC->font, x + pDrawable->x, y + pDrawable->y, n,
1023			  charinfo, imageblt, pGC->subWindowMode);
1024    }
1025    free(charinfo);
1026    return x + w;
1027}
1028
1029int
1030uxa_damage_poly_text_8(RegionPtr	region,
1031		       DrawablePtr pDrawable,
1032		       GCPtr	    pGC,
1033		       int	    x,
1034		       int	    y,
1035		       int	    count,
1036		       char	    *chars)
1037{
1038    if (checkGCDamage (pGC))
1039	x = uxa_damage_text (region,
1040			     pDrawable, pGC, x, y, (unsigned long) count, chars,
1041			     Linear8Bit, TT_POLY8);
1042    return x;
1043}
1044
1045int
1046uxa_damage_poly_text_16 (RegionPtr	region,
1047			 DrawablePtr	pDrawable,
1048			 GCPtr		pGC,
1049			 int		x,
1050			 int		y,
1051			 int		count,
1052			 unsigned short	*chars)
1053{
1054    if (checkGCDamage (pGC))
1055	x = uxa_damage_text (region,
1056			     pDrawable, pGC, x, y, (unsigned long) count, (char *) chars,
1057			     FONTLASTROW(pGC->font) == 0 ? Linear16Bit : TwoD16Bit,
1058			     TT_POLY16);
1059
1060    return x;
1061}
1062
1063void
1064uxa_damage_image_text_8(RegionPtr	region,
1065			DrawablePtr	pDrawable,
1066			GCPtr		pGC,
1067			int		x,
1068			int		y,
1069			int		count,
1070			char		*chars)
1071{
1072    if (checkGCDamage (pGC))
1073	uxa_damage_text (region,
1074			 pDrawable, pGC, x, y, (unsigned long) count, chars,
1075			 Linear8Bit, TT_IMAGE8);
1076}
1077
1078void
1079uxa_damage_image_text_16 (RegionPtr	region,
1080			  DrawablePtr	pDrawable,
1081			  GCPtr		pGC,
1082			  int		x,
1083			  int		y,
1084			  int		count,
1085			  unsigned short *chars)
1086{
1087    if (checkGCDamage (pGC))
1088	uxa_damage_text (region,
1089			 pDrawable, pGC, x, y, (unsigned long) count, (char *) chars,
1090			 FONTLASTROW(pGC->font) == 0 ? Linear16Bit : TwoD16Bit,
1091			 TT_IMAGE16);
1092}
1093
1094
1095void
1096uxa_damage_image_glyph_blt(RegionPtr	region,
1097			   DrawablePtr	    pDrawable,
1098			   GCPtr	    pGC,
1099			   int		    x,
1100			   int		    y,
1101			   unsigned int    nglyph,
1102			   CharInfoPtr	    *ppci,
1103			   pointer	    pglyphBase)
1104{
1105    uxa_damage_chars (region,
1106		      pDrawable, pGC->font, x + pDrawable->x, y + pDrawable->y,
1107		      nglyph, ppci, TRUE, pGC->subWindowMode);
1108}
1109
1110void
1111uxa_damage_poly_glyph_blt(RegionPtr	region,
1112			  DrawablePtr	pDrawable,
1113			  GCPtr	pGC,
1114			  int		x,
1115			  int		y,
1116			  unsigned int	nglyph,
1117			  CharInfoPtr	*ppci,
1118			  pointer	pglyphBase)
1119{
1120    uxa_damage_chars (region,
1121		      pDrawable, pGC->font, x + pDrawable->x, y + pDrawable->y,
1122		      nglyph, ppci, FALSE, pGC->subWindowMode);
1123}
1124
1125void
1126uxa_damage_push_pixels (RegionPtr	region,
1127			GCPtr		pGC,
1128			PixmapPtr	pBitMap,
1129			DrawablePtr	pDrawable,
1130			int		dx,
1131			int		dy,
1132			int		xOrg,
1133			int		yOrg)
1134{
1135    if(checkGCDamage (pGC))
1136    {
1137	BoxRec box;
1138
1139        box.x1 = xOrg;
1140        box.y1 = yOrg;
1141
1142        if(!pGC->miTranslate) {
1143	    box.x1 += pDrawable->x;
1144	    box.y1 += pDrawable->y;
1145        }
1146
1147	box.x2 = box.x1 + dx;
1148	box.y2 = box.y1 + dy;
1149
1150	TRIM_BOX(box, pGC);
1151	if(BOX_NOT_EMPTY(box))
1152	    add_box (region, &box, pDrawable, pGC->subWindowMode);
1153    }
1154}
1155
1156void
1157uxa_damage_copy_window(RegionPtr	region,
1158		       WindowPtr	pWindow,
1159		       DDXPointRec	ptOldOrg,
1160		       RegionPtr	prgnSrc)
1161{
1162#if 0
1163    ScreenPtr pScreen = pWindow->drawable.pScreen;
1164    damageScrPriv(pScreen);
1165    int dx = pWindow->drawable.x - ptOldOrg.x;
1166    int dy = pWindow->drawable.y - ptOldOrg.y;
1167
1168    /*
1169     * The region comes in source relative, but the damage occurs
1170     * at the destination location.  Translate back and forth.
1171     */
1172    REGION_TRANSLATE (pScreen, prgnSrc, dx, dy);
1173    damageRegionAppend (&pWindow->drawable, prgnSrc, FALSE, -1);
1174    REGION_TRANSLATE (pScreen, prgnSrc, -dx, -dy);
1175#endif
1176
1177    /* FIXME */
1178}
1179