pixman-utils.c revision dc259aab
1b4b94579Smrg/*
2b4b94579Smrg * Copyright © 2000 SuSE, Inc.
3dc259aabSmrg * Copyright © 1999 Keith Packard
4b4b94579Smrg *
5b4b94579Smrg * Permission to use, copy, modify, distribute, and sell this software and its
6b4b94579Smrg * documentation for any purpose is hereby granted without fee, provided that
7b4b94579Smrg * the above copyright notice appear in all copies and that both that
8b4b94579Smrg * copyright notice and this permission notice appear in supporting
9b4b94579Smrg * documentation, and that the name of SuSE not be used in advertising or
10b4b94579Smrg * publicity pertaining to distribution of the software without specific,
11b4b94579Smrg * written prior permission.  SuSE makes no representations about the
12b4b94579Smrg * suitability of this software for any purpose.  It is provided "as is"
13b4b94579Smrg * without express or implied warranty.
14b4b94579Smrg *
15b4b94579Smrg * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
16b4b94579Smrg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
17b4b94579Smrg * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
18b4b94579Smrg * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
19b4b94579Smrg * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
20b4b94579Smrg * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21b4b94579Smrg *
22b4b94579Smrg * Author:  Keith Packard, SuSE, Inc.
23b4b94579Smrg */
24b4b94579Smrg
25b4b94579Smrg#ifdef HAVE_CONFIG_H
26b4b94579Smrg#include <config.h>
27b4b94579Smrg#endif
28dc259aabSmrg#include <stdio.h>
29b4b94579Smrg#include <stdlib.h>
30b4b94579Smrg
31b4b94579Smrg#include "pixman-private.h"
32b4b94579Smrg
33b4b94579Smrg/*
34dc259aabSmrg * Computing composite region
35b4b94579Smrg */
36dc259aabSmrg#define BOUND(v)	(int16_t) ((v) < INT16_MIN ? INT16_MIN : (v) > INT16_MAX ? INT16_MAX : (v))
37b4b94579Smrg
38dc259aabSmrgstatic inline pixman_bool_t
39dc259aabSmrgmiClipPictureReg (pixman_region32_t *	pRegion,
40dc259aabSmrg		  pixman_region32_t *	pClip,
41dc259aabSmrg		  int		dx,
42dc259aabSmrg		  int		dy)
43b4b94579Smrg{
44dc259aabSmrg    if (pixman_region32_n_rects(pRegion) == 1 &&
45dc259aabSmrg	pixman_region32_n_rects(pClip) == 1)
46b4b94579Smrg    {
47dc259aabSmrg	pixman_box32_t *  pRbox = pixman_region32_rectangles(pRegion, NULL);
48dc259aabSmrg	pixman_box32_t *  pCbox = pixman_region32_rectangles(pClip, NULL);
49dc259aabSmrg	int	v;
50dc259aabSmrg
51dc259aabSmrg	if (pRbox->x1 < (v = pCbox->x1 + dx))
52dc259aabSmrg	    pRbox->x1 = BOUND(v);
53dc259aabSmrg	if (pRbox->x2 > (v = pCbox->x2 + dx))
54dc259aabSmrg	    pRbox->x2 = BOUND(v);
55dc259aabSmrg	if (pRbox->y1 < (v = pCbox->y1 + dy))
56dc259aabSmrg	    pRbox->y1 = BOUND(v);
57dc259aabSmrg	if (pRbox->y2 > (v = pCbox->y2 + dy))
58dc259aabSmrg	    pRbox->y2 = BOUND(v);
59dc259aabSmrg	if (pRbox->x1 >= pRbox->x2 ||
60dc259aabSmrg	    pRbox->y1 >= pRbox->y2)
61317c648bSmrg	{
62dc259aabSmrg	    pixman_region32_init (pRegion);
63317c648bSmrg	}
64b4b94579Smrg    }
65dc259aabSmrg    else if (!pixman_region32_not_empty (pClip))
66dc259aabSmrg    {
67dc259aabSmrg	return FALSE;
68dc259aabSmrg    }
69dc259aabSmrg    else
70dc259aabSmrg    {
71dc259aabSmrg	if (dx || dy)
72dc259aabSmrg	    pixman_region32_translate (pRegion, -dx, -dy);
73dc259aabSmrg	if (!pixman_region32_intersect (pRegion, pRegion, pClip))
74dc259aabSmrg	    return FALSE;
75dc259aabSmrg	if (dx || dy)
76dc259aabSmrg	    pixman_region32_translate(pRegion, dx, dy);
77dc259aabSmrg    }
78dc259aabSmrg    return pixman_region32_not_empty(pRegion);
79b4b94579Smrg}
80b4b94579Smrg
81b4b94579Smrg
82dc259aabSmrgstatic inline pixman_bool_t
83dc259aabSmrgmiClipPictureSrc (pixman_region32_t *	pRegion,
84dc259aabSmrg		  pixman_image_t *	pPicture,
85dc259aabSmrg		  int		dx,
86dc259aabSmrg		  int		dy)
87b4b94579Smrg{
88dc259aabSmrg    /* Source clips are ignored, unless they are explicitly turned on
89dc259aabSmrg     * and the clip in question was set by an X client
90dc259aabSmrg     */
91dc259aabSmrg    if (!pPicture->common.clip_sources || !pPicture->common.client_clip)
92dc259aabSmrg	return TRUE;
93b4b94579Smrg
94dc259aabSmrg    return miClipPictureReg (pRegion,
95dc259aabSmrg			     &pPicture->common.clip_region,
96dc259aabSmrg			     dx, dy);
97b4b94579Smrg}
98b4b94579Smrg
99b4b94579Smrg/*
100dc259aabSmrg * returns FALSE if the final region is empty.  Indistinguishable from
101dc259aabSmrg * an allocation failure, but rendering ignores those anyways.
102b4b94579Smrg */
103dc259aabSmrgstatic pixman_bool_t
104dc259aabSmrgpixman_compute_composite_region32 (pixman_region32_t *	pRegion,
105dc259aabSmrg				   pixman_image_t *	pSrc,
106dc259aabSmrg				   pixman_image_t *	pMask,
107dc259aabSmrg				   pixman_image_t *	pDst,
108dc259aabSmrg				   int16_t		xSrc,
109dc259aabSmrg				   int16_t		ySrc,
110dc259aabSmrg				   int16_t		xMask,
111dc259aabSmrg				   int16_t		yMask,
112dc259aabSmrg				   int16_t		xDst,
113dc259aabSmrg				   int16_t		yDst,
114dc259aabSmrg				   uint16_t		width,
115dc259aabSmrg				   uint16_t		height)
116b4b94579Smrg{
117dc259aabSmrg    int		v;
118dc259aabSmrg
119dc259aabSmrg    pRegion->extents.x1 = xDst;
120dc259aabSmrg    v = xDst + width;
121dc259aabSmrg    pRegion->extents.x2 = BOUND(v);
122dc259aabSmrg    pRegion->extents.y1 = yDst;
123dc259aabSmrg    v = yDst + height;
124dc259aabSmrg    pRegion->extents.y2 = BOUND(v);
125dc259aabSmrg
126dc259aabSmrg    pRegion->extents.x1 = MAX (pRegion->extents.x1, 0);
127dc259aabSmrg    pRegion->extents.y1 = MAX (pRegion->extents.y1, 0);
128dc259aabSmrg
129dc259aabSmrg    /* Some X servers rely on an old bug, where pixman would just believe the
130dc259aabSmrg     * set clip_region and not clip against the destination geometry. So,
131dc259aabSmrg     * since only X servers set "source clip", we don't clip against
132dc259aabSmrg     * destination geometry when that is set.
133dc259aabSmrg     */
134dc259aabSmrg    if (!pDst->common.clip_sources)
135dc259aabSmrg    {
136dc259aabSmrg	pRegion->extents.x2 = MIN (pRegion->extents.x2, pDst->bits.width);
137dc259aabSmrg	pRegion->extents.y2 = MIN (pRegion->extents.y2, pDst->bits.height);
138dc259aabSmrg    }
139dc259aabSmrg
140dc259aabSmrg    pRegion->data = 0;
141dc259aabSmrg
142dc259aabSmrg    /* Check for empty operation */
143dc259aabSmrg    if (pRegion->extents.x1 >= pRegion->extents.x2 ||
144dc259aabSmrg	pRegion->extents.y1 >= pRegion->extents.y2)
145b4b94579Smrg    {
146dc259aabSmrg	pixman_region32_init (pRegion);
147dc259aabSmrg	return FALSE;
148dc259aabSmrg    }
149dc259aabSmrg
150dc259aabSmrg    if (pDst->common.have_clip_region)
151dc259aabSmrg    {
152dc259aabSmrg	if (!miClipPictureReg (pRegion, &pDst->common.clip_region, 0, 0))
153b4b94579Smrg	{
154dc259aabSmrg	    pixman_region32_fini (pRegion);
155dc259aabSmrg	    return FALSE;
156b4b94579Smrg	}
157b4b94579Smrg    }
158dc259aabSmrg
159dc259aabSmrg    if (pDst->common.alpha_map && pDst->common.alpha_map->common.have_clip_region)
160b4b94579Smrg    {
161dc259aabSmrg	if (!miClipPictureReg (pRegion, &pDst->common.alpha_map->common.clip_region,
162dc259aabSmrg			       -pDst->common.alpha_origin_x,
163dc259aabSmrg			       -pDst->common.alpha_origin_y))
164b4b94579Smrg	{
165dc259aabSmrg	    pixman_region32_fini (pRegion);
166dc259aabSmrg	    return FALSE;
167b4b94579Smrg	}
168b4b94579Smrg    }
169dc259aabSmrg
170dc259aabSmrg    /* clip against src */
171dc259aabSmrg    if (pSrc->common.have_clip_region)
172b4b94579Smrg    {
173dc259aabSmrg	if (!miClipPictureSrc (pRegion, pSrc, xDst - xSrc, yDst - ySrc))
174dc259aabSmrg	{
175dc259aabSmrg	    pixman_region32_fini (pRegion);
176dc259aabSmrg	    return FALSE;
177dc259aabSmrg	}
178b4b94579Smrg    }
179dc259aabSmrg    if (pSrc->common.alpha_map && pSrc->common.alpha_map->common.have_clip_region)
180b4b94579Smrg    {
181dc259aabSmrg	if (!miClipPictureSrc (pRegion, (pixman_image_t *)pSrc->common.alpha_map,
182dc259aabSmrg			       xDst - (xSrc - pSrc->common.alpha_origin_x),
183dc259aabSmrg			       yDst - (ySrc - pSrc->common.alpha_origin_y)))
184b4b94579Smrg	{
185dc259aabSmrg	    pixman_region32_fini (pRegion);
186dc259aabSmrg	    return FALSE;
187b4b94579Smrg	}
188dc259aabSmrg    }
189dc259aabSmrg    /* clip against mask */
190dc259aabSmrg    if (pMask && pMask->common.have_clip_region)
191dc259aabSmrg    {
192dc259aabSmrg	if (!miClipPictureSrc (pRegion, pMask, xDst - xMask, yDst - yMask))
193dc259aabSmrg	{
194dc259aabSmrg	    pixman_region32_fini (pRegion);
195dc259aabSmrg	    return FALSE;
196dc259aabSmrg	}
197dc259aabSmrg	if (pMask->common.alpha_map && pMask->common.alpha_map->common.have_clip_region)
198b4b94579Smrg	{
199dc259aabSmrg	    if (!miClipPictureSrc (pRegion, (pixman_image_t *)pMask->common.alpha_map,
200dc259aabSmrg				   xDst - (xMask - pMask->common.alpha_origin_x),
201dc259aabSmrg				   yDst - (yMask - pMask->common.alpha_origin_y)))
202dc259aabSmrg	    {
203dc259aabSmrg		pixman_region32_fini (pRegion);
204dc259aabSmrg		return FALSE;
205dc259aabSmrg	    }
206b4b94579Smrg	}
207b4b94579Smrg    }
208dc259aabSmrg
209dc259aabSmrg    return TRUE;
210b4b94579Smrg}
211b4b94579Smrg
212dc259aabSmrgPIXMAN_EXPORT pixman_bool_t
213dc259aabSmrgpixman_compute_composite_region (pixman_region16_t *	pRegion,
214dc259aabSmrg				 pixman_image_t *	pSrc,
215dc259aabSmrg				 pixman_image_t *	pMask,
216dc259aabSmrg				 pixman_image_t *	pDst,
217dc259aabSmrg				 int16_t		xSrc,
218dc259aabSmrg				 int16_t		ySrc,
219dc259aabSmrg				 int16_t		xMask,
220dc259aabSmrg				 int16_t		yMask,
221dc259aabSmrg				 int16_t		xDst,
222dc259aabSmrg				 int16_t		yDst,
223dc259aabSmrg				 uint16_t	width,
224dc259aabSmrg				 uint16_t	height)
225b4b94579Smrg{
226dc259aabSmrg    pixman_region32_t r32;
227dc259aabSmrg    pixman_bool_t retval;
228b4b94579Smrg
229dc259aabSmrg    pixman_region32_init (&r32);
230dc259aabSmrg
231dc259aabSmrg    retval = pixman_compute_composite_region32 (&r32, pSrc, pMask, pDst,
232dc259aabSmrg						xSrc, ySrc, xMask, yMask, xDst, yDst,
233dc259aabSmrg						width, height);
234dc259aabSmrg
235dc259aabSmrg    if (retval)
236b4b94579Smrg    {
237dc259aabSmrg	if (!pixman_region16_copy_from_region32 (pRegion, &r32))
238dc259aabSmrg	    retval = FALSE;
239b4b94579Smrg    }
240dc259aabSmrg
241dc259aabSmrg    pixman_region32_fini (&r32);
242dc259aabSmrg    return retval;
243b4b94579Smrg}
244b4b94579Smrg
245b4b94579Smrgpixman_bool_t
246b4b94579Smrgpixman_multiply_overflows_int (unsigned int a,
247b4b94579Smrg		               unsigned int b)
248b4b94579Smrg{
249b4b94579Smrg    return a >= INT32_MAX / b;
250b4b94579Smrg}
251b4b94579Smrg
252b4b94579Smrgpixman_bool_t
253b4b94579Smrgpixman_addition_overflows_int (unsigned int a,
254b4b94579Smrg		               unsigned int b)
255b4b94579Smrg{
256b4b94579Smrg    return a > INT32_MAX - b;
257b4b94579Smrg}
258b4b94579Smrg
259b4b94579Smrgvoid *
260b4b94579Smrgpixman_malloc_ab(unsigned int a,
261b4b94579Smrg		 unsigned int b)
262b4b94579Smrg{
263b4b94579Smrg    if (a >= INT32_MAX / b)
264b4b94579Smrg	return NULL;
265b4b94579Smrg
266b4b94579Smrg    return malloc (a * b);
267b4b94579Smrg}
268b4b94579Smrg
269b4b94579Smrgvoid *
270b4b94579Smrgpixman_malloc_abc (unsigned int a,
271b4b94579Smrg		   unsigned int b,
272b4b94579Smrg		   unsigned int c)
273b4b94579Smrg{
274b4b94579Smrg    if (a >= INT32_MAX / b)
275b4b94579Smrg	return NULL;
276b4b94579Smrg    else if (a * b >= INT32_MAX / c)
277b4b94579Smrg	return NULL;
278b4b94579Smrg    else
279b4b94579Smrg	return malloc (a * b * c);
280b4b94579Smrg}
281b4b94579Smrg
282317c648bSmrg/*
283317c648bSmrg * Helper routine to expand a color component from 0 < n <= 8 bits to 16 bits by
284317c648bSmrg * replication.
285317c648bSmrg */
286317c648bSmrgstatic inline uint64_t
287317c648bSmrgexpand16(const uint8_t val, int nbits)
288317c648bSmrg{
289317c648bSmrg    // Start out with the high bit of val in the high bit of result.
290317c648bSmrg    uint16_t result = (uint16_t)val << (16 - nbits);
291317c648bSmrg
292317c648bSmrg    if (nbits == 0)
293317c648bSmrg        return 0;
294317c648bSmrg
295317c648bSmrg    // Copy the bits in result, doubling the number of bits each time, until we
296317c648bSmrg    // fill all 16 bits.
297317c648bSmrg    while (nbits < 16) {
298317c648bSmrg        result |= result >> nbits;
299317c648bSmrg        nbits *= 2;
300317c648bSmrg    }
301317c648bSmrg
302317c648bSmrg    return result;
303317c648bSmrg}
304317c648bSmrg
305317c648bSmrg/*
306317c648bSmrg * This function expands images from ARGB8 format to ARGB16.  To preserve
307317c648bSmrg * precision, it needs to know the original source format.  For example, if the
308317c648bSmrg * source was PIXMAN_x1r5g5b5 and the red component contained bits 12345, then
309317c648bSmrg * the expanded value is 12345123.  To correctly expand this to 16 bits, it
310317c648bSmrg * should be 1234512345123451 and not 1234512312345123.
311317c648bSmrg */
312317c648bSmrgvoid
313317c648bSmrgpixman_expand(uint64_t *dst, const uint32_t *src,
314317c648bSmrg	      pixman_format_code_t format, int width)
315317c648bSmrg{
316317c648bSmrg    /*
317317c648bSmrg     * Determine the sizes of each component and the masks and shifts required
318317c648bSmrg     * to extract them from the source pixel.
319317c648bSmrg     */
320317c648bSmrg    const int a_size = PIXMAN_FORMAT_A(format),
321317c648bSmrg              r_size = PIXMAN_FORMAT_R(format),
322317c648bSmrg              g_size = PIXMAN_FORMAT_G(format),
323317c648bSmrg              b_size = PIXMAN_FORMAT_B(format);
324317c648bSmrg    const int a_shift = 32 - a_size,
325317c648bSmrg              r_shift = 24 - r_size,
326317c648bSmrg              g_shift = 16 - g_size,
327317c648bSmrg              b_shift =  8 - b_size;
328317c648bSmrg    const uint8_t a_mask = ~(~0 << a_size),
329317c648bSmrg                  r_mask = ~(~0 << r_size),
330317c648bSmrg                  g_mask = ~(~0 << g_size),
331317c648bSmrg                  b_mask = ~(~0 << b_size);
332317c648bSmrg    int i;
333317c648bSmrg
334317c648bSmrg    /* Start at the end so that we can do the expansion in place when src == dst */
335317c648bSmrg    for (i = width - 1; i >= 0; i--)
336317c648bSmrg    {
337317c648bSmrg        const uint32_t pixel = src[i];
338317c648bSmrg        // Extract the components.
339317c648bSmrg        const uint8_t a = (pixel >> a_shift) & a_mask,
340317c648bSmrg                      r = (pixel >> r_shift) & r_mask,
341317c648bSmrg                      g = (pixel >> g_shift) & g_mask,
342317c648bSmrg                      b = (pixel >> b_shift) & b_mask;
343317c648bSmrg        const uint64_t a16 = a_size ? expand16(a, a_size) : 0xffff,
344317c648bSmrg                       r16 = expand16(r, r_size),
345317c648bSmrg                       g16 = expand16(g, g_size),
346317c648bSmrg                       b16 = expand16(b, b_size);
347317c648bSmrg
348317c648bSmrg        dst[i] = a16 << 48 | r16 << 32 | g16 << 16 | b16;
349317c648bSmrg    }
350317c648bSmrg}
351317c648bSmrg
352317c648bSmrg/*
353317c648bSmrg * Contracting is easier than expanding.  We just need to truncate the
354317c648bSmrg * components.
355317c648bSmrg */
356317c648bSmrgvoid
357317c648bSmrgpixman_contract(uint32_t *dst, const uint64_t *src, int width)
358317c648bSmrg{
359317c648bSmrg    int i;
360317c648bSmrg
361317c648bSmrg    /* Start at the beginning so that we can do the contraction in place when
362317c648bSmrg     * src == dst */
363317c648bSmrg    for (i = 0; i < width; i++)
364317c648bSmrg    {
365317c648bSmrg        const uint8_t a = src[i] >> 56,
366317c648bSmrg                      r = src[i] >> 40,
367317c648bSmrg                      g = src[i] >> 24,
368317c648bSmrg                      b = src[i] >> 8;
369317c648bSmrg        dst[i] = a << 24 | r << 16 | g << 8 | b;
370317c648bSmrg    }
371317c648bSmrg}
372317c648bSmrg
373dc259aabSmrgstatic void
374dc259aabSmrgwalk_region_internal (pixman_implementation_t *imp,
375dc259aabSmrg		      pixman_op_t op,
376dc259aabSmrg		      pixman_image_t * pSrc,
377dc259aabSmrg		      pixman_image_t * pMask,
378dc259aabSmrg		      pixman_image_t * pDst,
379dc259aabSmrg		      int16_t xSrc,
380dc259aabSmrg		      int16_t ySrc,
381dc259aabSmrg		      int16_t xMask,
382dc259aabSmrg		      int16_t yMask,
383dc259aabSmrg		      int16_t xDst,
384dc259aabSmrg		      int16_t yDst,
385dc259aabSmrg		      uint16_t width,
386dc259aabSmrg		      uint16_t height,
387dc259aabSmrg		      pixman_bool_t srcRepeat,
388dc259aabSmrg		      pixman_bool_t maskRepeat,
389dc259aabSmrg		      pixman_region32_t *region,
390dc259aabSmrg		      pixman_composite_func_t compositeRect)
391317c648bSmrg{
392dc259aabSmrg    int n;
393317c648bSmrg    const pixman_box32_t *pbox;
394dc259aabSmrg    int w, h, w_this, h_this;
395dc259aabSmrg    int x_msk, y_msk, x_src, y_src, x_dst, y_dst;
396317c648bSmrg
397317c648bSmrg    pbox = pixman_region32_rectangles (region, &n);
398317c648bSmrg    while (n--)
399317c648bSmrg    {
400317c648bSmrg	h = pbox->y2 - pbox->y1;
401317c648bSmrg	y_src = pbox->y1 - yDst + ySrc;
402317c648bSmrg	y_msk = pbox->y1 - yDst + yMask;
403317c648bSmrg	y_dst = pbox->y1;
404317c648bSmrg	while (h)
405317c648bSmrg	{
406317c648bSmrg	    h_this = h;
407317c648bSmrg	    w = pbox->x2 - pbox->x1;
408317c648bSmrg	    x_src = pbox->x1 - xDst + xSrc;
409317c648bSmrg	    x_msk = pbox->x1 - xDst + xMask;
410317c648bSmrg	    x_dst = pbox->x1;
411dc259aabSmrg
412317c648bSmrg	    if (maskRepeat)
413317c648bSmrg	    {
414317c648bSmrg		y_msk = MOD (y_msk, pMask->bits.height);
415317c648bSmrg		if (h_this > pMask->bits.height - y_msk)
416317c648bSmrg		    h_this = pMask->bits.height - y_msk;
417317c648bSmrg	    }
418317c648bSmrg	    if (srcRepeat)
419317c648bSmrg	    {
420317c648bSmrg		y_src = MOD (y_src, pSrc->bits.height);
421317c648bSmrg		if (h_this > pSrc->bits.height - y_src)
422317c648bSmrg		    h_this = pSrc->bits.height - y_src;
423317c648bSmrg	    }
424317c648bSmrg	    while (w)
425317c648bSmrg	    {
426317c648bSmrg		w_this = w;
427317c648bSmrg		if (maskRepeat)
428317c648bSmrg		{
429317c648bSmrg		    x_msk = MOD (x_msk, pMask->bits.width);
430317c648bSmrg		    if (w_this > pMask->bits.width - x_msk)
431317c648bSmrg			w_this = pMask->bits.width - x_msk;
432317c648bSmrg		}
433317c648bSmrg		if (srcRepeat)
434317c648bSmrg		{
435317c648bSmrg		    x_src = MOD (x_src, pSrc->bits.width);
436317c648bSmrg		    if (w_this > pSrc->bits.width - x_src)
437317c648bSmrg			w_this = pSrc->bits.width - x_src;
438317c648bSmrg		}
439317c648bSmrg		(*compositeRect) (imp,
440317c648bSmrg				  op, pSrc, pMask, pDst,
441317c648bSmrg				  x_src, y_src, x_msk, y_msk, x_dst, y_dst,
442317c648bSmrg				  w_this, h_this);
443317c648bSmrg		w -= w_this;
444317c648bSmrg		x_src += w_this;
445317c648bSmrg		x_msk += w_this;
446317c648bSmrg		x_dst += w_this;
447317c648bSmrg	    }
448317c648bSmrg	    h -= h_this;
449317c648bSmrg	    y_src += h_this;
450317c648bSmrg	    y_msk += h_this;
451317c648bSmrg	    y_dst += h_this;
452317c648bSmrg	}
453317c648bSmrg	pbox++;
454317c648bSmrg    }
455317c648bSmrg}
456317c648bSmrg
457dc259aabSmrgvoid
458dc259aabSmrg_pixman_walk_composite_region (pixman_implementation_t *imp,
459dc259aabSmrg			       pixman_op_t op,
460dc259aabSmrg			       pixman_image_t * pSrc,
461dc259aabSmrg			       pixman_image_t * pMask,
462dc259aabSmrg			       pixman_image_t * pDst,
463dc259aabSmrg			       int16_t xSrc,
464dc259aabSmrg			       int16_t ySrc,
465dc259aabSmrg			       int16_t xMask,
466dc259aabSmrg			       int16_t yMask,
467dc259aabSmrg			       int16_t xDst,
468dc259aabSmrg			       int16_t yDst,
469dc259aabSmrg			       uint16_t width,
470dc259aabSmrg			       uint16_t height,
471dc259aabSmrg			       pixman_composite_func_t compositeRect)
472dc259aabSmrg{
473dc259aabSmrg    pixman_region32_t region;
474dc259aabSmrg
475dc259aabSmrg    pixman_region32_init (&region);
476dc259aabSmrg
477dc259aabSmrg    if (pixman_compute_composite_region32 (
478dc259aabSmrg	    &region, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask, xDst, yDst, width, height))
479dc259aabSmrg    {
480dc259aabSmrg	walk_region_internal (imp, op,
481dc259aabSmrg			      pSrc, pMask, pDst,
482dc259aabSmrg			      xSrc, ySrc, xMask, yMask, xDst, yDst,
483dc259aabSmrg			      width, height, FALSE, FALSE,
484dc259aabSmrg			      &region,
485dc259aabSmrg			      compositeRect);
486dc259aabSmrg    }
487dc259aabSmrg
488dc259aabSmrg    pixman_region32_fini (&region);
489dc259aabSmrg}
490dc259aabSmrg
491dc259aabSmrg
492317c648bSmrgstatic pixman_bool_t
493317c648bSmrgmask_is_solid (pixman_image_t *mask)
494317c648bSmrg{
495317c648bSmrg    if (mask->type == SOLID)
496317c648bSmrg	return TRUE;
497317c648bSmrg
498317c648bSmrg    if (mask->type == BITS &&
499317c648bSmrg	mask->common.repeat == PIXMAN_REPEAT_NORMAL &&
500317c648bSmrg	mask->bits.width == 1 &&
501317c648bSmrg	mask->bits.height == 1)
502317c648bSmrg    {
503317c648bSmrg	return TRUE;
504317c648bSmrg    }
505317c648bSmrg
506317c648bSmrg    return FALSE;
507317c648bSmrg}
508317c648bSmrg
509dc259aabSmrgstatic const pixman_fast_path_t *
510dc259aabSmrgget_fast_path (const pixman_fast_path_t *fast_paths,
511317c648bSmrg	       pixman_op_t         op,
512317c648bSmrg	       pixman_image_t     *pSrc,
513317c648bSmrg	       pixman_image_t     *pMask,
514317c648bSmrg	       pixman_image_t     *pDst,
515317c648bSmrg	       pixman_bool_t       is_pixbuf)
516317c648bSmrg{
517dc259aabSmrg    const pixman_fast_path_t *info;
518317c648bSmrg
519317c648bSmrg    for (info = fast_paths; info->op != PIXMAN_OP_NONE; info++)
520317c648bSmrg    {
521dc259aabSmrg	pixman_bool_t valid_src = FALSE;
522dc259aabSmrg	pixman_bool_t valid_mask = FALSE;
523317c648bSmrg
524317c648bSmrg	if (info->op != op)
525317c648bSmrg	    continue;
526317c648bSmrg
527dc259aabSmrg	if ((info->src_format == PIXMAN_solid && _pixman_image_is_solid (pSrc)) ||
528317c648bSmrg	    (pSrc->type == BITS && info->src_format == pSrc->bits.format))
529317c648bSmrg	{
530317c648bSmrg	    valid_src = TRUE;
531317c648bSmrg	}
532317c648bSmrg
533317c648bSmrg	if (!valid_src)
534317c648bSmrg	    continue;
535317c648bSmrg
536dc259aabSmrg	if ((info->mask_format == PIXMAN_null && !pMask) ||
537317c648bSmrg	    (pMask && pMask->type == BITS && info->mask_format == pMask->bits.format))
538317c648bSmrg	{
539317c648bSmrg	    valid_mask = TRUE;
540317c648bSmrg
541317c648bSmrg	    if (info->flags & NEED_SOLID_MASK)
542317c648bSmrg	    {
543317c648bSmrg		if (!pMask || !mask_is_solid (pMask))
544317c648bSmrg		    valid_mask = FALSE;
545317c648bSmrg	    }
546317c648bSmrg
547317c648bSmrg	    if (info->flags & NEED_COMPONENT_ALPHA)
548317c648bSmrg	    {
549317c648bSmrg		if (!pMask || !pMask->common.component_alpha)
550317c648bSmrg		    valid_mask = FALSE;
551317c648bSmrg	    }
552317c648bSmrg	}
553317c648bSmrg
554317c648bSmrg	if (!valid_mask)
555317c648bSmrg	    continue;
556317c648bSmrg
557317c648bSmrg	if (info->dest_format != pDst->bits.format)
558317c648bSmrg	    continue;
559317c648bSmrg
560317c648bSmrg	if ((info->flags & NEED_PIXBUF) && !is_pixbuf)
561317c648bSmrg	    continue;
562317c648bSmrg
563317c648bSmrg	return info;
564317c648bSmrg    }
565317c648bSmrg
566317c648bSmrg    return NULL;
567317c648bSmrg}
568317c648bSmrg
569dc259aabSmrgstatic inline pixman_bool_t
570dc259aabSmrgimage_covers (pixman_image_t *image, pixman_box32_t *extents, int x, int y)
571dc259aabSmrg{
572dc259aabSmrg    if (image->common.type == BITS && image->common.repeat == PIXMAN_REPEAT_NONE)
573dc259aabSmrg    {
574dc259aabSmrg	if (x > extents->x1 || y > extents->y1 ||
575dc259aabSmrg	    x + image->bits.width < extents->x2 ||
576dc259aabSmrg	    y + image->bits.height < extents->y2)
577dc259aabSmrg	{
578dc259aabSmrg	    return FALSE;
579dc259aabSmrg	}
580dc259aabSmrg    }
581dc259aabSmrg
582dc259aabSmrg    return TRUE;
583dc259aabSmrg}
584dc259aabSmrg
585317c648bSmrgpixman_bool_t
586dc259aabSmrg_pixman_run_fast_path (const pixman_fast_path_t *paths,
587317c648bSmrg		       pixman_implementation_t *imp,
588317c648bSmrg		       pixman_op_t op,
589317c648bSmrg		       pixman_image_t *src,
590317c648bSmrg		       pixman_image_t *mask,
591317c648bSmrg		       pixman_image_t *dest,
592317c648bSmrg		       int32_t src_x,
593317c648bSmrg		       int32_t src_y,
594317c648bSmrg		       int32_t mask_x,
595317c648bSmrg		       int32_t mask_y,
596317c648bSmrg		       int32_t dest_x,
597317c648bSmrg		       int32_t dest_y,
598317c648bSmrg		       int32_t width,
599317c648bSmrg		       int32_t height)
600317c648bSmrg{
601317c648bSmrg    pixman_composite_func_t func = NULL;
602317c648bSmrg    pixman_bool_t src_repeat = src->common.repeat == PIXMAN_REPEAT_NORMAL;
603317c648bSmrg    pixman_bool_t mask_repeat = mask && mask->common.repeat == PIXMAN_REPEAT_NORMAL;
604dc259aabSmrg    pixman_bool_t result;
605dc259aabSmrg
606dc259aabSmrg    if ((src->type == BITS || _pixman_image_is_solid (src)) &&
607317c648bSmrg	(!mask || mask->type == BITS)
608dc259aabSmrg	&& !src->common.transform && !(mask && mask->common.transform)
609dc259aabSmrg	&& !(mask && mask->common.alpha_map) && !src->common.alpha_map && !dest->common.alpha_map
610dc259aabSmrg	&& (src->common.filter != PIXMAN_FILTER_CONVOLUTION)
611dc259aabSmrg	&& (src->common.repeat != PIXMAN_REPEAT_PAD)
612dc259aabSmrg	&& (src->common.repeat != PIXMAN_REPEAT_REFLECT)
613dc259aabSmrg	&& (!mask || (mask->common.filter != PIXMAN_FILTER_CONVOLUTION &&
614317c648bSmrg		      mask->common.repeat != PIXMAN_REPEAT_PAD &&
615317c648bSmrg		      mask->common.repeat != PIXMAN_REPEAT_REFLECT))
616317c648bSmrg	&& !src->common.read_func && !src->common.write_func
617317c648bSmrg	&& !(mask && mask->common.read_func)
618317c648bSmrg	&& !(mask && mask->common.write_func)
619317c648bSmrg	&& !dest->common.read_func
620317c648bSmrg	&& !dest->common.write_func)
621317c648bSmrg    {
622dc259aabSmrg	const pixman_fast_path_t *info;
623317c648bSmrg	pixman_bool_t pixbuf;
624317c648bSmrg
625317c648bSmrg	pixbuf =
626317c648bSmrg	    src && src->type == BITS		&&
627317c648bSmrg	    mask && mask->type == BITS		&&
628317c648bSmrg	    src->bits.bits == mask->bits.bits	&&
629317c648bSmrg	    src_x == mask_x			&&
630317c648bSmrg	    src_y == mask_y			&&
631317c648bSmrg	    !mask->common.component_alpha	&&
632317c648bSmrg	    !mask_repeat;
633317c648bSmrg
634317c648bSmrg	info = get_fast_path (paths, op, src, mask, dest, pixbuf);
635dc259aabSmrg
636317c648bSmrg	if (info)
637317c648bSmrg	{
638317c648bSmrg	    func = info->func;
639dc259aabSmrg
640317c648bSmrg	    if (info->src_format == PIXMAN_solid)
641317c648bSmrg		src_repeat = FALSE;
642dc259aabSmrg
643317c648bSmrg	    if (info->mask_format == PIXMAN_solid || info->flags & NEED_SOLID_MASK)
644317c648bSmrg		mask_repeat = FALSE;
645dc259aabSmrg
646317c648bSmrg	    if ((src_repeat			&&
647317c648bSmrg		 src->bits.width == 1		&&
648317c648bSmrg		 src->bits.height == 1)	||
649317c648bSmrg		(mask_repeat			&&
650317c648bSmrg		 mask->bits.width == 1		&&
651317c648bSmrg		 mask->bits.height == 1))
652317c648bSmrg	    {
653317c648bSmrg		/* If src or mask are repeating 1x1 images and src_repeat or
654317c648bSmrg		 * mask_repeat are still TRUE, it means the fast path we
655317c648bSmrg		 * selected does not actually handle repeating images.
656317c648bSmrg		 *
657317c648bSmrg		 * So rather than call the "fast path" with a zillion
658317c648bSmrg		 * 1x1 requests, we just fall back to the general code (which
659317c648bSmrg		 * does do something sensible with 1x1 repeating images).
660317c648bSmrg		 */
661317c648bSmrg		func = NULL;
662317c648bSmrg	    }
663317c648bSmrg	}
664317c648bSmrg    }
665dc259aabSmrg
666dc259aabSmrg    result = FALSE;
667dc259aabSmrg
668317c648bSmrg    if (func)
669317c648bSmrg    {
670dc259aabSmrg	pixman_region32_t region;
671dc259aabSmrg	pixman_region32_init (&region);
672dc259aabSmrg
673dc259aabSmrg	if (pixman_compute_composite_region32 (
674dc259aabSmrg		&region, src, mask, dest, src_x, src_y, mask_x, mask_y, dest_x, dest_y, width, height))
675dc259aabSmrg	{
676dc259aabSmrg	    pixman_box32_t *extents = pixman_region32_extents (&region);
677dc259aabSmrg
678dc259aabSmrg	    if (image_covers (src, extents, dest_x - src_x, dest_y - src_y)   &&
679dc259aabSmrg		(!mask || image_covers (mask, extents, dest_x - mask_x, dest_y - mask_y)))
680dc259aabSmrg	    {
681dc259aabSmrg		walk_region_internal (imp, op,
682dc259aabSmrg				      src, mask, dest,
683dc259aabSmrg				      src_x, src_y, mask_x, mask_y,
684dc259aabSmrg				      dest_x, dest_y,
685dc259aabSmrg				      width, height,
686dc259aabSmrg				      src_repeat, mask_repeat,
687dc259aabSmrg				      &region,
688dc259aabSmrg				      func);
689dc259aabSmrg
690dc259aabSmrg		result = TRUE;
691dc259aabSmrg	    }
692dc259aabSmrg	}
693dc259aabSmrg
694dc259aabSmrg	pixman_region32_fini (&region);
695317c648bSmrg    }
696317c648bSmrg
697dc259aabSmrg    return result;
698dc259aabSmrg}
699dc259aabSmrg
700dc259aabSmrg#define N_TMP_BOXES (16)
701dc259aabSmrg
702dc259aabSmrgpixman_bool_t
703dc259aabSmrgpixman_region16_copy_from_region32 (pixman_region16_t *dst,
704dc259aabSmrg				    pixman_region32_t *src)
705dc259aabSmrg{
706dc259aabSmrg    int n_boxes, i;
707dc259aabSmrg    pixman_box32_t *boxes32;
708dc259aabSmrg    pixman_box16_t *boxes16;
709dc259aabSmrg    pixman_bool_t retval;
710dc259aabSmrg
711dc259aabSmrg    boxes32 = pixman_region32_rectangles (src, &n_boxes);
712dc259aabSmrg
713dc259aabSmrg    boxes16 = pixman_malloc_ab (n_boxes, sizeof (pixman_box16_t));
714dc259aabSmrg
715dc259aabSmrg    if (!boxes16)
716dc259aabSmrg	return FALSE;
717dc259aabSmrg
718dc259aabSmrg    for (i = 0; i < n_boxes; ++i)
719dc259aabSmrg    {
720dc259aabSmrg	boxes16[i].x1 = boxes32[i].x1;
721dc259aabSmrg	boxes16[i].y1 = boxes32[i].y1;
722dc259aabSmrg	boxes16[i].x2 = boxes32[i].x2;
723dc259aabSmrg	boxes16[i].y2 = boxes32[i].y2;
724dc259aabSmrg    }
725dc259aabSmrg
726dc259aabSmrg    pixman_region_fini (dst);
727dc259aabSmrg    retval = pixman_region_init_rects (dst, boxes16, n_boxes);
728dc259aabSmrg    free (boxes16);
729dc259aabSmrg    return retval;
730317c648bSmrg}
731dc259aabSmrg
732dc259aabSmrgpixman_bool_t
733dc259aabSmrgpixman_region32_copy_from_region16 (pixman_region32_t *dst,
734dc259aabSmrg				    pixman_region16_t *src)
735dc259aabSmrg{
736dc259aabSmrg    int n_boxes, i;
737dc259aabSmrg    pixman_box16_t *boxes16;
738dc259aabSmrg    pixman_box32_t *boxes32;
739dc259aabSmrg    pixman_box32_t tmp_boxes[N_TMP_BOXES];
740dc259aabSmrg    pixman_bool_t retval;
741dc259aabSmrg
742dc259aabSmrg    boxes16 = pixman_region_rectangles (src, &n_boxes);
743dc259aabSmrg
744dc259aabSmrg    if (n_boxes > N_TMP_BOXES)
745dc259aabSmrg	boxes32 = pixman_malloc_ab (n_boxes, sizeof (pixman_box32_t));
746dc259aabSmrg    else
747dc259aabSmrg	boxes32 = tmp_boxes;
748dc259aabSmrg
749dc259aabSmrg    if (!boxes32)
750dc259aabSmrg	return FALSE;
751dc259aabSmrg
752dc259aabSmrg    for (i = 0; i < n_boxes; ++i)
753dc259aabSmrg    {
754dc259aabSmrg	boxes32[i].x1 = boxes16[i].x1;
755dc259aabSmrg	boxes32[i].y1 = boxes16[i].y1;
756dc259aabSmrg	boxes32[i].x2 = boxes16[i].x2;
757dc259aabSmrg	boxes32[i].y2 = boxes16[i].y2;
758dc259aabSmrg    }
759dc259aabSmrg
760dc259aabSmrg    pixman_region32_fini (dst);
761dc259aabSmrg    retval = pixman_region32_init_rects (dst, boxes32, n_boxes);
762dc259aabSmrg
763dc259aabSmrg    if (boxes32 != tmp_boxes)
764dc259aabSmrg	free (boxes32);
765dc259aabSmrg
766dc259aabSmrg    return retval;
767dc259aabSmrg}
768dc259aabSmrg
769