pixman-utils.c revision d0321353
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 */
36d0321353Smrg#define BOUND(v)        (int16_t) ((v) < INT16_MIN ? INT16_MIN : (v) > INT16_MAX ? INT16_MAX : (v))
37b4b94579Smrg
38dc259aabSmrgstatic inline pixman_bool_t
39d0321353Smrgclip_general_image (pixman_region32_t * region,
40d0321353Smrg                    pixman_region32_t * clip,
41d0321353Smrg                    int                 dx,
42d0321353Smrg                    int                 dy)
43b4b94579Smrg{
44d0321353Smrg    if (pixman_region32_n_rects (region) == 1 &&
45d0321353Smrg        pixman_region32_n_rects (clip) == 1)
46b4b94579Smrg    {
47d0321353Smrg	pixman_box32_t *  rbox = pixman_region32_rectangles (region, NULL);
48d0321353Smrg	pixman_box32_t *  cbox = pixman_region32_rectangles (clip, NULL);
49d0321353Smrg	int v;
50d0321353Smrg
51d0321353Smrg	if (rbox->x1 < (v = cbox->x1 + dx))
52d0321353Smrg	    rbox->x1 = BOUND (v);
53d0321353Smrg	if (rbox->x2 > (v = cbox->x2 + dx))
54d0321353Smrg	    rbox->x2 = BOUND (v);
55d0321353Smrg	if (rbox->y1 < (v = cbox->y1 + dy))
56d0321353Smrg	    rbox->y1 = BOUND (v);
57d0321353Smrg	if (rbox->y2 > (v = cbox->y2 + dy))
58d0321353Smrg	    rbox->y2 = BOUND (v);
59d0321353Smrg	if (rbox->x1 >= rbox->x2 ||
60d0321353Smrg	    rbox->y1 >= rbox->y2)
61317c648bSmrg	{
62d0321353Smrg	    pixman_region32_init (region);
63317c648bSmrg	}
64b4b94579Smrg    }
65d0321353Smrg    else if (!pixman_region32_not_empty (clip))
66dc259aabSmrg    {
67dc259aabSmrg	return FALSE;
68dc259aabSmrg    }
69dc259aabSmrg    else
70dc259aabSmrg    {
71dc259aabSmrg	if (dx || dy)
72d0321353Smrg	    pixman_region32_translate (region, -dx, -dy);
73d0321353Smrg	if (!pixman_region32_intersect (region, region, clip))
74dc259aabSmrg	    return FALSE;
75dc259aabSmrg	if (dx || dy)
76d0321353Smrg	    pixman_region32_translate (region, dx, dy);
77dc259aabSmrg    }
78d0321353Smrg    return pixman_region32_not_empty (region);
79b4b94579Smrg}
80b4b94579Smrg
81dc259aabSmrgstatic inline pixman_bool_t
82d0321353Smrgclip_source_image (pixman_region32_t * region,
83d0321353Smrg                   pixman_image_t *    picture,
84d0321353Smrg                   int                 dx,
85d0321353Smrg                   int                 dy)
86b4b94579Smrg{
87d0321353Smrg    /* The workaround lets certain fast paths run even when they
88d0321353Smrg     * would normally be rejected because of out-of-bounds access.
89d0321353Smrg     * We need to clip against the source geometry in that case
90dc259aabSmrg     */
91d0321353Smrg    if (!picture->common.need_workaround)
92d0321353Smrg    {
93d0321353Smrg	/* Source clips are ignored, unless they are explicitly turned on
94d0321353Smrg	 * and the clip in question was set by an X client. (Because if
95d0321353Smrg	 * the clip was not set by a client, then it is a hierarchy
96d0321353Smrg	 * clip and those should always be ignored for sources).
97d0321353Smrg	 */
98d0321353Smrg	if (!picture->common.clip_sources || !picture->common.client_clip)
99d0321353Smrg	    return TRUE;
100d0321353Smrg    }
101b4b94579Smrg
102d0321353Smrg    return clip_general_image (region,
103d0321353Smrg                               &picture->common.clip_region,
104d0321353Smrg                               dx, dy);
105b4b94579Smrg}
106b4b94579Smrg
107b4b94579Smrg/*
108dc259aabSmrg * returns FALSE if the final region is empty.  Indistinguishable from
109dc259aabSmrg * an allocation failure, but rendering ignores those anyways.
110b4b94579Smrg */
111dc259aabSmrgstatic pixman_bool_t
112d0321353Smrgpixman_compute_composite_region32 (pixman_region32_t * region,
113d0321353Smrg                                   pixman_image_t *    src_image,
114d0321353Smrg                                   pixman_image_t *    mask_image,
115d0321353Smrg                                   pixman_image_t *    dst_image,
116d0321353Smrg                                   int16_t             src_x,
117d0321353Smrg                                   int16_t             src_y,
118d0321353Smrg                                   int16_t             mask_x,
119d0321353Smrg                                   int16_t             mask_y,
120d0321353Smrg                                   int16_t             dest_x,
121d0321353Smrg                                   int16_t             dest_y,
122d0321353Smrg                                   uint16_t            width,
123d0321353Smrg                                   uint16_t            height)
124b4b94579Smrg{
125d0321353Smrg    int v;
126d0321353Smrg
127d0321353Smrg    region->extents.x1 = dest_x;
128d0321353Smrg    v = dest_x + width;
129d0321353Smrg    region->extents.x2 = BOUND (v);
130d0321353Smrg    region->extents.y1 = dest_y;
131d0321353Smrg    v = dest_y + height;
132d0321353Smrg    region->extents.y2 = BOUND (v);
133d0321353Smrg
134d0321353Smrg    region->extents.x1 = MAX (region->extents.x1, 0);
135d0321353Smrg    region->extents.y1 = MAX (region->extents.y1, 0);
136d0321353Smrg
137dc259aabSmrg    /* Some X servers rely on an old bug, where pixman would just believe the
138d0321353Smrg     * set clip_region and not clip against the destination geometry. So,
139dc259aabSmrg     * since only X servers set "source clip", we don't clip against
140d0321353Smrg     * destination geometry when that is set and when the workaround has
141d0321353Smrg     * not been explicitly disabled by
142d0321353Smrg     *
143d0321353Smrg     *      pixman_disable_out_of_bounds_workaround();
144d0321353Smrg     *
145dc259aabSmrg     */
146d0321353Smrg    if (!(dst_image->common.need_workaround))
147dc259aabSmrg    {
148d0321353Smrg	region->extents.x2 = MIN (region->extents.x2, dst_image->bits.width);
149d0321353Smrg	region->extents.y2 = MIN (region->extents.y2, dst_image->bits.height);
150dc259aabSmrg    }
151d0321353Smrg
152d0321353Smrg    region->data = 0;
153d0321353Smrg
154dc259aabSmrg    /* Check for empty operation */
155d0321353Smrg    if (region->extents.x1 >= region->extents.x2 ||
156d0321353Smrg        region->extents.y1 >= region->extents.y2)
157b4b94579Smrg    {
158d0321353Smrg	pixman_region32_init (region);
159dc259aabSmrg	return FALSE;
160dc259aabSmrg    }
161d0321353Smrg
162d0321353Smrg    if (dst_image->common.have_clip_region)
163dc259aabSmrg    {
164d0321353Smrg	if (!clip_general_image (region, &dst_image->common.clip_region, 0, 0))
165b4b94579Smrg	{
166d0321353Smrg	    pixman_region32_fini (region);
167dc259aabSmrg	    return FALSE;
168b4b94579Smrg	}
169b4b94579Smrg    }
170d0321353Smrg
171d0321353Smrg    if (dst_image->common.alpha_map && dst_image->common.alpha_map->common.have_clip_region)
172b4b94579Smrg    {
173d0321353Smrg	if (!clip_general_image (region, &dst_image->common.alpha_map->common.clip_region,
174d0321353Smrg	                         -dst_image->common.alpha_origin_x,
175d0321353Smrg	                         -dst_image->common.alpha_origin_y))
176b4b94579Smrg	{
177d0321353Smrg	    pixman_region32_fini (region);
178dc259aabSmrg	    return FALSE;
179b4b94579Smrg	}
180b4b94579Smrg    }
181d0321353Smrg
182dc259aabSmrg    /* clip against src */
183d0321353Smrg    if (src_image->common.have_clip_region)
184b4b94579Smrg    {
185d0321353Smrg	if (!clip_source_image (region, src_image, dest_x - src_x, dest_y - src_y))
186dc259aabSmrg	{
187d0321353Smrg	    pixman_region32_fini (region);
188dc259aabSmrg	    return FALSE;
189dc259aabSmrg	}
190b4b94579Smrg    }
191d0321353Smrg    if (src_image->common.alpha_map && src_image->common.alpha_map->common.have_clip_region)
192b4b94579Smrg    {
193d0321353Smrg	if (!clip_source_image (region, (pixman_image_t *)src_image->common.alpha_map,
194d0321353Smrg	                        dest_x - (src_x - src_image->common.alpha_origin_x),
195d0321353Smrg	                        dest_y - (src_y - src_image->common.alpha_origin_y)))
196b4b94579Smrg	{
197d0321353Smrg	    pixman_region32_fini (region);
198dc259aabSmrg	    return FALSE;
199b4b94579Smrg	}
200dc259aabSmrg    }
201dc259aabSmrg    /* clip against mask */
202d0321353Smrg    if (mask_image && mask_image->common.have_clip_region)
203dc259aabSmrg    {
204d0321353Smrg	if (!clip_source_image (region, mask_image, dest_x - mask_x, dest_y - mask_y))
205dc259aabSmrg	{
206d0321353Smrg	    pixman_region32_fini (region);
207dc259aabSmrg	    return FALSE;
208d0321353Smrg	}
209d0321353Smrg	if (mask_image->common.alpha_map && mask_image->common.alpha_map->common.have_clip_region)
210b4b94579Smrg	{
211d0321353Smrg	    if (!clip_source_image (region, (pixman_image_t *)mask_image->common.alpha_map,
212d0321353Smrg	                            dest_x - (mask_x - mask_image->common.alpha_origin_x),
213d0321353Smrg	                            dest_y - (mask_y - mask_image->common.alpha_origin_y)))
214dc259aabSmrg	    {
215d0321353Smrg		pixman_region32_fini (region);
216dc259aabSmrg		return FALSE;
217dc259aabSmrg	    }
218b4b94579Smrg	}
219b4b94579Smrg    }
220dc259aabSmrg
221dc259aabSmrg    return TRUE;
222b4b94579Smrg}
223b4b94579Smrg
224dc259aabSmrgPIXMAN_EXPORT pixman_bool_t
225d0321353Smrgpixman_compute_composite_region (pixman_region16_t * region,
226d0321353Smrg                                 pixman_image_t *    src_image,
227d0321353Smrg                                 pixman_image_t *    mask_image,
228d0321353Smrg                                 pixman_image_t *    dst_image,
229d0321353Smrg                                 int16_t             src_x,
230d0321353Smrg                                 int16_t             src_y,
231d0321353Smrg                                 int16_t             mask_x,
232d0321353Smrg                                 int16_t             mask_y,
233d0321353Smrg                                 int16_t             dest_x,
234d0321353Smrg                                 int16_t             dest_y,
235d0321353Smrg                                 uint16_t            width,
236d0321353Smrg                                 uint16_t            height)
237b4b94579Smrg{
238dc259aabSmrg    pixman_region32_t r32;
239dc259aabSmrg    pixman_bool_t retval;
240b4b94579Smrg
241dc259aabSmrg    pixman_region32_init (&r32);
242d0321353Smrg
243d0321353Smrg    retval = pixman_compute_composite_region32 (
244d0321353Smrg	&r32, src_image, mask_image, dst_image,
245d0321353Smrg	src_x, src_y, mask_x, mask_y, dest_x, dest_y,
246d0321353Smrg	width, height);
247dc259aabSmrg
248dc259aabSmrg    if (retval)
249b4b94579Smrg    {
250d0321353Smrg	if (!pixman_region16_copy_from_region32 (region, &r32))
251dc259aabSmrg	    retval = FALSE;
252b4b94579Smrg    }
253d0321353Smrg
254dc259aabSmrg    pixman_region32_fini (&r32);
255dc259aabSmrg    return retval;
256b4b94579Smrg}
257b4b94579Smrg
258b4b94579Smrgpixman_bool_t
259b4b94579Smrgpixman_multiply_overflows_int (unsigned int a,
260d0321353Smrg                               unsigned int b)
261b4b94579Smrg{
262b4b94579Smrg    return a >= INT32_MAX / b;
263b4b94579Smrg}
264b4b94579Smrg
265b4b94579Smrgpixman_bool_t
266b4b94579Smrgpixman_addition_overflows_int (unsigned int a,
267d0321353Smrg                               unsigned int b)
268b4b94579Smrg{
269b4b94579Smrg    return a > INT32_MAX - b;
270b4b94579Smrg}
271b4b94579Smrg
272b4b94579Smrgvoid *
273d0321353Smrgpixman_malloc_ab (unsigned int a,
274d0321353Smrg                  unsigned int b)
275b4b94579Smrg{
276b4b94579Smrg    if (a >= INT32_MAX / b)
277b4b94579Smrg	return NULL;
278b4b94579Smrg
279b4b94579Smrg    return malloc (a * b);
280b4b94579Smrg}
281b4b94579Smrg
282b4b94579Smrgvoid *
283b4b94579Smrgpixman_malloc_abc (unsigned int a,
284d0321353Smrg                   unsigned int b,
285d0321353Smrg                   unsigned int c)
286b4b94579Smrg{
287b4b94579Smrg    if (a >= INT32_MAX / b)
288b4b94579Smrg	return NULL;
289b4b94579Smrg    else if (a * b >= INT32_MAX / c)
290b4b94579Smrg	return NULL;
291b4b94579Smrg    else
292b4b94579Smrg	return malloc (a * b * c);
293b4b94579Smrg}
294b4b94579Smrg
295317c648bSmrg/*
296d0321353Smrg * Helper routine to expand a color component from 0 < n <= 8 bits to 16
297d0321353Smrg * bits by replication.
298317c648bSmrg */
299317c648bSmrgstatic inline uint64_t
300d0321353Smrgexpand16 (const uint8_t val, int nbits)
301317c648bSmrg{
302d0321353Smrg    /* Start out with the high bit of val in the high bit of result. */
303317c648bSmrg    uint16_t result = (uint16_t)val << (16 - nbits);
304317c648bSmrg
305317c648bSmrg    if (nbits == 0)
306d0321353Smrg	return 0;
307317c648bSmrg
308d0321353Smrg    /* Copy the bits in result, doubling the number of bits each time, until
309d0321353Smrg     * we fill all 16 bits.
310d0321353Smrg     */
311d0321353Smrg    while (nbits < 16)
312d0321353Smrg    {
313d0321353Smrg	result |= result >> nbits;
314d0321353Smrg	nbits *= 2;
315317c648bSmrg    }
316317c648bSmrg
317317c648bSmrg    return result;
318317c648bSmrg}
319317c648bSmrg
320317c648bSmrg/*
321317c648bSmrg * This function expands images from ARGB8 format to ARGB16.  To preserve
322317c648bSmrg * precision, it needs to know the original source format.  For example, if the
323317c648bSmrg * source was PIXMAN_x1r5g5b5 and the red component contained bits 12345, then
324317c648bSmrg * the expanded value is 12345123.  To correctly expand this to 16 bits, it
325317c648bSmrg * should be 1234512345123451 and not 1234512312345123.
326317c648bSmrg */
327317c648bSmrgvoid
328d0321353Smrgpixman_expand (uint64_t *           dst,
329d0321353Smrg               const uint32_t *     src,
330d0321353Smrg               pixman_format_code_t format,
331d0321353Smrg               int                  width)
332317c648bSmrg{
333317c648bSmrg    /*
334d0321353Smrg     * Determine the sizes of each component and the masks and shifts
335d0321353Smrg     * required to extract them from the source pixel.
336317c648bSmrg     */
337d0321353Smrg    const int a_size = PIXMAN_FORMAT_A (format),
338d0321353Smrg              r_size = PIXMAN_FORMAT_R (format),
339d0321353Smrg              g_size = PIXMAN_FORMAT_G (format),
340d0321353Smrg              b_size = PIXMAN_FORMAT_B (format);
341317c648bSmrg    const int a_shift = 32 - a_size,
342317c648bSmrg              r_shift = 24 - r_size,
343317c648bSmrg              g_shift = 16 - g_size,
344317c648bSmrg              b_shift =  8 - b_size;
345317c648bSmrg    const uint8_t a_mask = ~(~0 << a_size),
346317c648bSmrg                  r_mask = ~(~0 << r_size),
347317c648bSmrg                  g_mask = ~(~0 << g_size),
348317c648bSmrg                  b_mask = ~(~0 << b_size);
349317c648bSmrg    int i;
350317c648bSmrg
351d0321353Smrg    /* Start at the end so that we can do the expansion in place
352d0321353Smrg     * when src == dst
353d0321353Smrg     */
354317c648bSmrg    for (i = width - 1; i >= 0; i--)
355317c648bSmrg    {
356d0321353Smrg	const uint32_t pixel = src[i];
357d0321353Smrg	const uint8_t a = (pixel >> a_shift) & a_mask,
358d0321353Smrg	              r = (pixel >> r_shift) & r_mask,
359d0321353Smrg	              g = (pixel >> g_shift) & g_mask,
360d0321353Smrg	              b = (pixel >> b_shift) & b_mask;
361d0321353Smrg	const uint64_t a16 = a_size ? expand16 (a, a_size) : 0xffff,
362d0321353Smrg	               r16 = expand16 (r, r_size),
363d0321353Smrg	               g16 = expand16 (g, g_size),
364d0321353Smrg	               b16 = expand16 (b, b_size);
365d0321353Smrg
366d0321353Smrg	dst[i] = a16 << 48 | r16 << 32 | g16 << 16 | b16;
367317c648bSmrg    }
368317c648bSmrg}
369317c648bSmrg
370317c648bSmrg/*
371317c648bSmrg * Contracting is easier than expanding.  We just need to truncate the
372317c648bSmrg * components.
373317c648bSmrg */
374317c648bSmrgvoid
375d0321353Smrgpixman_contract (uint32_t *      dst,
376d0321353Smrg                 const uint64_t *src,
377d0321353Smrg                 int             width)
378317c648bSmrg{
379317c648bSmrg    int i;
380317c648bSmrg
381d0321353Smrg    /* Start at the beginning so that we can do the contraction in
382d0321353Smrg     * place when src == dst
383d0321353Smrg     */
384317c648bSmrg    for (i = 0; i < width; i++)
385317c648bSmrg    {
386d0321353Smrg	const uint8_t a = src[i] >> 56,
387d0321353Smrg	              r = src[i] >> 40,
388d0321353Smrg	              g = src[i] >> 24,
389d0321353Smrg	              b = src[i] >> 8;
390d0321353Smrg
391d0321353Smrg	dst[i] = a << 24 | r << 16 | g << 8 | b;
392317c648bSmrg    }
393317c648bSmrg}
394317c648bSmrg
395dc259aabSmrgstatic void
396dc259aabSmrgwalk_region_internal (pixman_implementation_t *imp,
397d0321353Smrg                      pixman_op_t              op,
398d0321353Smrg                      pixman_image_t *         src_image,
399d0321353Smrg                      pixman_image_t *         mask_image,
400d0321353Smrg                      pixman_image_t *         dst_image,
401d0321353Smrg                      int16_t                  src_x,
402d0321353Smrg                      int16_t                  src_y,
403d0321353Smrg                      int16_t                  mask_x,
404d0321353Smrg                      int16_t                  mask_y,
405d0321353Smrg                      int16_t                  dest_x,
406d0321353Smrg                      int16_t                  dest_y,
407d0321353Smrg                      uint16_t                 width,
408d0321353Smrg                      uint16_t                 height,
409d0321353Smrg                      pixman_bool_t            src_repeat,
410d0321353Smrg                      pixman_bool_t            mask_repeat,
411d0321353Smrg                      pixman_region32_t *      region,
412d0321353Smrg                      pixman_composite_func_t  composite_rect)
413317c648bSmrg{
414dc259aabSmrg    int n;
415317c648bSmrg    const pixman_box32_t *pbox;
416dc259aabSmrg    int w, h, w_this, h_this;
417dc259aabSmrg    int x_msk, y_msk, x_src, y_src, x_dst, y_dst;
418317c648bSmrg
419317c648bSmrg    pbox = pixman_region32_rectangles (region, &n);
420317c648bSmrg    while (n--)
421317c648bSmrg    {
422317c648bSmrg	h = pbox->y2 - pbox->y1;
423d0321353Smrg	y_src = pbox->y1 - dest_y + src_y;
424d0321353Smrg	y_msk = pbox->y1 - dest_y + mask_y;
425317c648bSmrg	y_dst = pbox->y1;
426d0321353Smrg
427317c648bSmrg	while (h)
428317c648bSmrg	{
429317c648bSmrg	    h_this = h;
430317c648bSmrg	    w = pbox->x2 - pbox->x1;
431d0321353Smrg	    x_src = pbox->x1 - dest_x + src_x;
432d0321353Smrg	    x_msk = pbox->x1 - dest_x + mask_x;
433317c648bSmrg	    x_dst = pbox->x1;
434d0321353Smrg
435d0321353Smrg	    if (mask_repeat)
436317c648bSmrg	    {
437d0321353Smrg		y_msk = MOD (y_msk, mask_image->bits.height);
438d0321353Smrg		if (h_this > mask_image->bits.height - y_msk)
439d0321353Smrg		    h_this = mask_image->bits.height - y_msk;
440317c648bSmrg	    }
441d0321353Smrg
442d0321353Smrg	    if (src_repeat)
443317c648bSmrg	    {
444d0321353Smrg		y_src = MOD (y_src, src_image->bits.height);
445d0321353Smrg		if (h_this > src_image->bits.height - y_src)
446d0321353Smrg		    h_this = src_image->bits.height - y_src;
447317c648bSmrg	    }
448d0321353Smrg
449317c648bSmrg	    while (w)
450317c648bSmrg	    {
451317c648bSmrg		w_this = w;
452d0321353Smrg
453d0321353Smrg		if (mask_repeat)
454317c648bSmrg		{
455d0321353Smrg		    x_msk = MOD (x_msk, mask_image->bits.width);
456d0321353Smrg		    if (w_this > mask_image->bits.width - x_msk)
457d0321353Smrg			w_this = mask_image->bits.width - x_msk;
458317c648bSmrg		}
459d0321353Smrg
460d0321353Smrg		if (src_repeat)
461317c648bSmrg		{
462d0321353Smrg		    x_src = MOD (x_src, src_image->bits.width);
463d0321353Smrg		    if (w_this > src_image->bits.width - x_src)
464d0321353Smrg			w_this = src_image->bits.width - x_src;
465317c648bSmrg		}
466d0321353Smrg
467d0321353Smrg		(*composite_rect) (imp, op,
468d0321353Smrg				   src_image, mask_image, dst_image,
469d0321353Smrg				   x_src, y_src, x_msk, y_msk, x_dst, y_dst,
470d0321353Smrg				   w_this, h_this);
471317c648bSmrg		w -= w_this;
472d0321353Smrg
473317c648bSmrg		x_src += w_this;
474317c648bSmrg		x_msk += w_this;
475317c648bSmrg		x_dst += w_this;
476317c648bSmrg	    }
477d0321353Smrg
478317c648bSmrg	    h -= h_this;
479317c648bSmrg	    y_src += h_this;
480317c648bSmrg	    y_msk += h_this;
481317c648bSmrg	    y_dst += h_this;
482317c648bSmrg	}
483d0321353Smrg
484317c648bSmrg	pbox++;
485317c648bSmrg    }
486317c648bSmrg}
487317c648bSmrg
488dc259aabSmrgvoid
489dc259aabSmrg_pixman_walk_composite_region (pixman_implementation_t *imp,
490d0321353Smrg                               pixman_op_t              op,
491d0321353Smrg                               pixman_image_t *         src_image,
492d0321353Smrg                               pixman_image_t *         mask_image,
493d0321353Smrg                               pixman_image_t *         dst_image,
494d0321353Smrg                               int16_t                  src_x,
495d0321353Smrg                               int16_t                  src_y,
496d0321353Smrg                               int16_t                  mask_x,
497d0321353Smrg                               int16_t                  mask_y,
498d0321353Smrg                               int16_t                  dest_x,
499d0321353Smrg                               int16_t                  dest_y,
500d0321353Smrg                               uint16_t                 width,
501d0321353Smrg                               uint16_t                 height,
502d0321353Smrg                               pixman_composite_func_t  composite_rect)
503dc259aabSmrg{
504dc259aabSmrg    pixman_region32_t region;
505d0321353Smrg
506dc259aabSmrg    pixman_region32_init (&region);
507dc259aabSmrg
508dc259aabSmrg    if (pixman_compute_composite_region32 (
509d0321353Smrg            &region, src_image, mask_image, dst_image,
510d0321353Smrg            src_x, src_y, mask_x, mask_y, dest_x, dest_y,
511d0321353Smrg            width, height))
512dc259aabSmrg    {
513dc259aabSmrg	walk_region_internal (imp, op,
514d0321353Smrg	                      src_image, mask_image, dst_image,
515d0321353Smrg	                      src_x, src_y, mask_x, mask_y, dest_x, dest_y,
516d0321353Smrg	                      width, height, FALSE, FALSE,
517d0321353Smrg	                      &region,
518d0321353Smrg	                      composite_rect);
519dc259aabSmrg
520d0321353Smrg	pixman_region32_fini (&region);
521d0321353Smrg    }
522dc259aabSmrg}
523dc259aabSmrg
524317c648bSmrgstatic pixman_bool_t
525317c648bSmrgmask_is_solid (pixman_image_t *mask)
526317c648bSmrg{
527317c648bSmrg    if (mask->type == SOLID)
528317c648bSmrg	return TRUE;
529317c648bSmrg
530317c648bSmrg    if (mask->type == BITS &&
531d0321353Smrg        mask->common.repeat == PIXMAN_REPEAT_NORMAL &&
532d0321353Smrg        mask->bits.width == 1 &&
533d0321353Smrg        mask->bits.height == 1)
534317c648bSmrg    {
535317c648bSmrg	return TRUE;
536317c648bSmrg    }
537317c648bSmrg
538317c648bSmrg    return FALSE;
539317c648bSmrg}
540317c648bSmrg
541dc259aabSmrgstatic const pixman_fast_path_t *
542dc259aabSmrgget_fast_path (const pixman_fast_path_t *fast_paths,
543d0321353Smrg               pixman_op_t               op,
544d0321353Smrg               pixman_image_t *          src_image,
545d0321353Smrg               pixman_image_t *          mask_image,
546d0321353Smrg               pixman_image_t *          dst_image,
547d0321353Smrg               pixman_bool_t             is_pixbuf)
548317c648bSmrg{
549dc259aabSmrg    const pixman_fast_path_t *info;
550317c648bSmrg
551317c648bSmrg    for (info = fast_paths; info->op != PIXMAN_OP_NONE; info++)
552317c648bSmrg    {
553dc259aabSmrg	pixman_bool_t valid_src = FALSE;
554dc259aabSmrg	pixman_bool_t valid_mask = FALSE;
555317c648bSmrg
556317c648bSmrg	if (info->op != op)
557317c648bSmrg	    continue;
558317c648bSmrg
559d0321353Smrg	if ((info->src_format == PIXMAN_solid &&
560d0321353Smrg	     _pixman_image_is_solid (src_image)) ||
561d0321353Smrg	    (src_image->type == BITS &&
562d0321353Smrg	     info->src_format == src_image->bits.format))
563317c648bSmrg	{
564317c648bSmrg	    valid_src = TRUE;
565317c648bSmrg	}
566317c648bSmrg
567317c648bSmrg	if (!valid_src)
568317c648bSmrg	    continue;
569317c648bSmrg
570d0321353Smrg	if ((info->mask_format == PIXMAN_null && !mask_image) ||
571d0321353Smrg	    (mask_image && mask_image->type == BITS &&
572d0321353Smrg	     info->mask_format == mask_image->bits.format))
573317c648bSmrg	{
574317c648bSmrg	    valid_mask = TRUE;
575317c648bSmrg
576317c648bSmrg	    if (info->flags & NEED_SOLID_MASK)
577317c648bSmrg	    {
578d0321353Smrg		if (!mask_image || !mask_is_solid (mask_image))
579317c648bSmrg		    valid_mask = FALSE;
580317c648bSmrg	    }
581317c648bSmrg
582317c648bSmrg	    if (info->flags & NEED_COMPONENT_ALPHA)
583317c648bSmrg	    {
584d0321353Smrg		if (!mask_image || !mask_image->common.component_alpha)
585317c648bSmrg		    valid_mask = FALSE;
586317c648bSmrg	    }
587317c648bSmrg	}
588317c648bSmrg
589317c648bSmrg	if (!valid_mask)
590317c648bSmrg	    continue;
591d0321353Smrg
592d0321353Smrg	if (info->dest_format != dst_image->bits.format)
593317c648bSmrg	    continue;
594317c648bSmrg
595317c648bSmrg	if ((info->flags & NEED_PIXBUF) && !is_pixbuf)
596317c648bSmrg	    continue;
597317c648bSmrg
598317c648bSmrg	return info;
599317c648bSmrg    }
600317c648bSmrg
601317c648bSmrg    return NULL;
602317c648bSmrg}
603317c648bSmrg
604d0321353Smrgstatic force_inline pixman_bool_t
605d0321353Smrgimage_covers (pixman_image_t *image,
606d0321353Smrg              pixman_box32_t *extents,
607d0321353Smrg              int             x,
608d0321353Smrg              int             y)
609dc259aabSmrg{
610d0321353Smrg    if (image->common.type == BITS &&
611d0321353Smrg	image->common.repeat == PIXMAN_REPEAT_NONE)
612dc259aabSmrg    {
613dc259aabSmrg	if (x > extents->x1 || y > extents->y1 ||
614dc259aabSmrg	    x + image->bits.width < extents->x2 ||
615dc259aabSmrg	    y + image->bits.height < extents->y2)
616dc259aabSmrg	{
617dc259aabSmrg	    return FALSE;
618dc259aabSmrg	}
619dc259aabSmrg    }
620dc259aabSmrg
621dc259aabSmrg    return TRUE;
622dc259aabSmrg}
623dc259aabSmrg
624d0321353Smrgstatic force_inline pixman_bool_t
625d0321353Smrgsources_cover (pixman_image_t *src,
626d0321353Smrg	       pixman_image_t *mask,
627d0321353Smrg	       pixman_box32_t *extents,
628d0321353Smrg	       int             src_x,
629d0321353Smrg	       int             src_y,
630d0321353Smrg	       int             mask_x,
631d0321353Smrg	       int             mask_y,
632d0321353Smrg	       int             dest_x,
633d0321353Smrg	       int             dest_y)
634d0321353Smrg{
635d0321353Smrg    if (!image_covers (src, extents, dest_x - src_x, dest_y - src_y))
636d0321353Smrg	return FALSE;
637d0321353Smrg
638d0321353Smrg    if (!mask)
639d0321353Smrg	return TRUE;
640d0321353Smrg
641d0321353Smrg    if (!image_covers (mask, extents, dest_x - mask_x, dest_y - mask_y))
642d0321353Smrg	return FALSE;
643d0321353Smrg
644d0321353Smrg    return TRUE;
645d0321353Smrg}
646d0321353Smrg
647317c648bSmrgpixman_bool_t
648dc259aabSmrg_pixman_run_fast_path (const pixman_fast_path_t *paths,
649d0321353Smrg                       pixman_implementation_t * imp,
650d0321353Smrg                       pixman_op_t               op,
651d0321353Smrg                       pixman_image_t *          src,
652d0321353Smrg                       pixman_image_t *          mask,
653d0321353Smrg                       pixman_image_t *          dest,
654d0321353Smrg                       int32_t                   src_x,
655d0321353Smrg                       int32_t                   src_y,
656d0321353Smrg                       int32_t                   mask_x,
657d0321353Smrg                       int32_t                   mask_y,
658d0321353Smrg                       int32_t                   dest_x,
659d0321353Smrg                       int32_t                   dest_y,
660d0321353Smrg                       int32_t                   width,
661d0321353Smrg                       int32_t                   height)
662317c648bSmrg{
663317c648bSmrg    pixman_composite_func_t func = NULL;
664d0321353Smrg    pixman_bool_t src_repeat =
665d0321353Smrg	src->common.repeat == PIXMAN_REPEAT_NORMAL;
666d0321353Smrg    pixman_bool_t mask_repeat =
667d0321353Smrg	mask && mask->common.repeat == PIXMAN_REPEAT_NORMAL;
668dc259aabSmrg    pixman_bool_t result;
669dc259aabSmrg
670dc259aabSmrg    if ((src->type == BITS || _pixman_image_is_solid (src)) &&
671d0321353Smrg        (!mask || mask->type == BITS)
672d0321353Smrg        && !src->common.transform && !(mask && mask->common.transform)
673d0321353Smrg	&& !src->common.alpha_map && !dest->common.alpha_map
674d0321353Smrg        && !(mask && mask->common.alpha_map)
675d0321353Smrg        && (src->common.filter != PIXMAN_FILTER_CONVOLUTION)
676d0321353Smrg        && (src->common.repeat != PIXMAN_REPEAT_PAD)
677d0321353Smrg        && (src->common.repeat != PIXMAN_REPEAT_REFLECT)
678d0321353Smrg        && (!mask || (mask->common.filter != PIXMAN_FILTER_CONVOLUTION &&
679d0321353Smrg                      mask->common.repeat != PIXMAN_REPEAT_PAD &&
680d0321353Smrg                      mask->common.repeat != PIXMAN_REPEAT_REFLECT))
681d0321353Smrg        && !src->common.read_func && !src->common.write_func
682d0321353Smrg        && !(mask && mask->common.read_func)
683d0321353Smrg        && !(mask && mask->common.write_func)
684d0321353Smrg        && !dest->common.read_func
685d0321353Smrg        && !dest->common.write_func)
686317c648bSmrg    {
687d0321353Smrg	const pixman_fast_path_t *info;
688317c648bSmrg	pixman_bool_t pixbuf;
689317c648bSmrg
690317c648bSmrg	pixbuf =
691d0321353Smrg	    src && src->type == BITS            &&
692d0321353Smrg	    mask && mask->type == BITS          &&
693d0321353Smrg	    src->bits.bits == mask->bits.bits   &&
694d0321353Smrg	    src_x == mask_x                     &&
695d0321353Smrg	    src_y == mask_y                     &&
696d0321353Smrg	    !mask->common.component_alpha       &&
697317c648bSmrg	    !mask_repeat;
698d0321353Smrg
699317c648bSmrg	info = get_fast_path (paths, op, src, mask, dest, pixbuf);
700d0321353Smrg
701317c648bSmrg	if (info)
702317c648bSmrg	{
703317c648bSmrg	    func = info->func;
704d0321353Smrg
705317c648bSmrg	    if (info->src_format == PIXMAN_solid)
706317c648bSmrg		src_repeat = FALSE;
707d0321353Smrg
708d0321353Smrg	    if (info->mask_format == PIXMAN_solid ||
709d0321353Smrg		info->flags & NEED_SOLID_MASK)
710d0321353Smrg	    {
711317c648bSmrg		mask_repeat = FALSE;
712d0321353Smrg	    }
713d0321353Smrg
714d0321353Smrg	    if ((src_repeat                     &&
715d0321353Smrg	         src->bits.width == 1           &&
716d0321353Smrg	         src->bits.height == 1) ||
717d0321353Smrg	        (mask_repeat                    &&
718d0321353Smrg	         mask->bits.width == 1          &&
719d0321353Smrg	         mask->bits.height == 1))
720317c648bSmrg	    {
721317c648bSmrg		/* If src or mask are repeating 1x1 images and src_repeat or
722317c648bSmrg		 * mask_repeat are still TRUE, it means the fast path we
723317c648bSmrg		 * selected does not actually handle repeating images.
724317c648bSmrg		 *
725317c648bSmrg		 * So rather than call the "fast path" with a zillion
726317c648bSmrg		 * 1x1 requests, we just fall back to the general code (which
727317c648bSmrg		 * does do something sensible with 1x1 repeating images).
728317c648bSmrg		 */
729317c648bSmrg		func = NULL;
730317c648bSmrg	    }
731317c648bSmrg	}
732317c648bSmrg    }
733d0321353Smrg
734dc259aabSmrg    result = FALSE;
735d0321353Smrg
736317c648bSmrg    if (func)
737317c648bSmrg    {
738dc259aabSmrg	pixman_region32_t region;
739dc259aabSmrg	pixman_region32_init (&region);
740dc259aabSmrg
741dc259aabSmrg	if (pixman_compute_composite_region32 (
742d0321353Smrg	        &region, src, mask, dest,
743d0321353Smrg	        src_x, src_y, mask_x, mask_y, dest_x, dest_y, width, height))
744dc259aabSmrg	{
745dc259aabSmrg	    pixman_box32_t *extents = pixman_region32_extents (&region);
746dc259aabSmrg
747d0321353Smrg	    if (sources_cover (
748d0321353Smrg		    src, mask, extents,
749d0321353Smrg		    src_x, src_y, mask_x, mask_y, dest_x, dest_y))
750dc259aabSmrg	    {
751dc259aabSmrg		walk_region_internal (imp, op,
752d0321353Smrg		                      src, mask, dest,
753d0321353Smrg		                      src_x, src_y, mask_x, mask_y,
754d0321353Smrg		                      dest_x, dest_y,
755d0321353Smrg		                      width, height,
756d0321353Smrg		                      src_repeat, mask_repeat,
757d0321353Smrg		                      &region,
758d0321353Smrg		                      func);
759d0321353Smrg
760dc259aabSmrg		result = TRUE;
761dc259aabSmrg	    }
762d0321353Smrg
763d0321353Smrg	    pixman_region32_fini (&region);
764dc259aabSmrg	}
765317c648bSmrg    }
766d0321353Smrg
767dc259aabSmrg    return result;
768dc259aabSmrg}
769dc259aabSmrg
770dc259aabSmrg#define N_TMP_BOXES (16)
771dc259aabSmrg
772dc259aabSmrgpixman_bool_t
773dc259aabSmrgpixman_region16_copy_from_region32 (pixman_region16_t *dst,
774d0321353Smrg                                    pixman_region32_t *src)
775dc259aabSmrg{
776dc259aabSmrg    int n_boxes, i;
777dc259aabSmrg    pixman_box32_t *boxes32;
778dc259aabSmrg    pixman_box16_t *boxes16;
779dc259aabSmrg    pixman_bool_t retval;
780d0321353Smrg
781dc259aabSmrg    boxes32 = pixman_region32_rectangles (src, &n_boxes);
782dc259aabSmrg
783dc259aabSmrg    boxes16 = pixman_malloc_ab (n_boxes, sizeof (pixman_box16_t));
784dc259aabSmrg
785dc259aabSmrg    if (!boxes16)
786dc259aabSmrg	return FALSE;
787d0321353Smrg
788dc259aabSmrg    for (i = 0; i < n_boxes; ++i)
789dc259aabSmrg    {
790dc259aabSmrg	boxes16[i].x1 = boxes32[i].x1;
791dc259aabSmrg	boxes16[i].y1 = boxes32[i].y1;
792dc259aabSmrg	boxes16[i].x2 = boxes32[i].x2;
793dc259aabSmrg	boxes16[i].y2 = boxes32[i].y2;
794dc259aabSmrg    }
795dc259aabSmrg
796dc259aabSmrg    pixman_region_fini (dst);
797dc259aabSmrg    retval = pixman_region_init_rects (dst, boxes16, n_boxes);
798dc259aabSmrg    free (boxes16);
799dc259aabSmrg    return retval;
800317c648bSmrg}
801dc259aabSmrg
802dc259aabSmrgpixman_bool_t
803dc259aabSmrgpixman_region32_copy_from_region16 (pixman_region32_t *dst,
804d0321353Smrg                                    pixman_region16_t *src)
805dc259aabSmrg{
806dc259aabSmrg    int n_boxes, i;
807dc259aabSmrg    pixman_box16_t *boxes16;
808dc259aabSmrg    pixman_box32_t *boxes32;
809dc259aabSmrg    pixman_box32_t tmp_boxes[N_TMP_BOXES];
810dc259aabSmrg    pixman_bool_t retval;
811d0321353Smrg
812dc259aabSmrg    boxes16 = pixman_region_rectangles (src, &n_boxes);
813dc259aabSmrg
814dc259aabSmrg    if (n_boxes > N_TMP_BOXES)
815dc259aabSmrg	boxes32 = pixman_malloc_ab (n_boxes, sizeof (pixman_box32_t));
816dc259aabSmrg    else
817dc259aabSmrg	boxes32 = tmp_boxes;
818d0321353Smrg
819dc259aabSmrg    if (!boxes32)
820dc259aabSmrg	return FALSE;
821d0321353Smrg
822dc259aabSmrg    for (i = 0; i < n_boxes; ++i)
823dc259aabSmrg    {
824dc259aabSmrg	boxes32[i].x1 = boxes16[i].x1;
825dc259aabSmrg	boxes32[i].y1 = boxes16[i].y1;
826dc259aabSmrg	boxes32[i].x2 = boxes16[i].x2;
827dc259aabSmrg	boxes32[i].y2 = boxes16[i].y2;
828dc259aabSmrg    }
829dc259aabSmrg
830dc259aabSmrg    pixman_region32_fini (dst);
831dc259aabSmrg    retval = pixman_region32_init_rects (dst, boxes32, n_boxes);
832dc259aabSmrg
833dc259aabSmrg    if (boxes32 != tmp_boxes)
834dc259aabSmrg	free (boxes32);
835dc259aabSmrg
836dc259aabSmrg    return retval;
837dc259aabSmrg}
838