pixman-utils.c revision 317c648b
1b4b94579Smrg/*
2b4b94579Smrg * Copyright © 2000 SuSE, Inc.
3b4b94579Smrg *
4b4b94579Smrg * Permission to use, copy, modify, distribute, and sell this software and its
5b4b94579Smrg * documentation for any purpose is hereby granted without fee, provided that
6b4b94579Smrg * the above copyright notice appear in all copies and that both that
7b4b94579Smrg * copyright notice and this permission notice appear in supporting
8b4b94579Smrg * documentation, and that the name of SuSE not be used in advertising or
9b4b94579Smrg * publicity pertaining to distribution of the software without specific,
10b4b94579Smrg * written prior permission.  SuSE makes no representations about the
11b4b94579Smrg * suitability of this software for any purpose.  It is provided "as is"
12b4b94579Smrg * without express or implied warranty.
13b4b94579Smrg *
14b4b94579Smrg * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
15b4b94579Smrg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
16b4b94579Smrg * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17b4b94579Smrg * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
18b4b94579Smrg * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
19b4b94579Smrg * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20b4b94579Smrg *
21b4b94579Smrg * Author:  Keith Packard, SuSE, Inc.
22b4b94579Smrg */
23b4b94579Smrg
24b4b94579Smrg#ifdef HAVE_CONFIG_H
25b4b94579Smrg#include <config.h>
26b4b94579Smrg#endif
27b4b94579Smrg
28b4b94579Smrg#include <stdlib.h>
29b4b94579Smrg
30b4b94579Smrg#include "pixman-private.h"
31b4b94579Smrg
32b4b94579Smrg/*
33b4b94579Smrg * Compute the smallest value no less than y which is on a
34b4b94579Smrg * grid row
35b4b94579Smrg */
36b4b94579Smrg
37b4b94579SmrgPIXMAN_EXPORT pixman_fixed_t
38b4b94579Smrgpixman_sample_ceil_y (pixman_fixed_t y, int n)
39b4b94579Smrg{
40b4b94579Smrg    pixman_fixed_t   f = pixman_fixed_frac(y);
41b4b94579Smrg    pixman_fixed_t   i = pixman_fixed_floor(y);
42b4b94579Smrg
43b4b94579Smrg    f = ((f + Y_FRAC_FIRST(n)) / STEP_Y_SMALL(n)) * STEP_Y_SMALL(n) + Y_FRAC_FIRST(n);
44b4b94579Smrg    if (f > Y_FRAC_LAST(n))
45b4b94579Smrg    {
46317c648bSmrg	if (pixman_fixed_to_int(i) == 0x7fff)
47317c648bSmrg	{
48317c648bSmrg	    f = 0xffff; /* saturate */
49317c648bSmrg	} else {
50317c648bSmrg	    f = Y_FRAC_FIRST(n);
51317c648bSmrg	    i += pixman_fixed_1;
52317c648bSmrg	}
53b4b94579Smrg    }
54b4b94579Smrg    return (i | f);
55b4b94579Smrg}
56b4b94579Smrg
57b4b94579Smrg#define _div(a,b)    ((a) >= 0 ? (a) / (b) : -((-(a) + (b) - 1) / (b)))
58b4b94579Smrg
59b4b94579Smrg/*
60b4b94579Smrg * Compute the largest value no greater than y which is on a
61b4b94579Smrg * grid row
62b4b94579Smrg */
63b4b94579SmrgPIXMAN_EXPORT pixman_fixed_t
64b4b94579Smrgpixman_sample_floor_y (pixman_fixed_t y, int n)
65b4b94579Smrg{
66b4b94579Smrg    pixman_fixed_t   f = pixman_fixed_frac(y);
67b4b94579Smrg    pixman_fixed_t   i = pixman_fixed_floor (y);
68b4b94579Smrg
69b4b94579Smrg    f = _div(f - Y_FRAC_FIRST(n), STEP_Y_SMALL(n)) * STEP_Y_SMALL(n) + Y_FRAC_FIRST(n);
70b4b94579Smrg    if (f < Y_FRAC_FIRST(n))
71b4b94579Smrg    {
72317c648bSmrg	if (pixman_fixed_to_int(i) == 0x8000)
73317c648bSmrg	{
74317c648bSmrg	    f = 0; /* saturate */
75317c648bSmrg	} else {
76317c648bSmrg	    f = Y_FRAC_LAST(n);
77317c648bSmrg	    i -= pixman_fixed_1;
78317c648bSmrg	}
79b4b94579Smrg    }
80b4b94579Smrg    return (i | f);
81b4b94579Smrg}
82b4b94579Smrg
83b4b94579Smrg/*
84b4b94579Smrg * Step an edge by any amount (including negative values)
85b4b94579Smrg */
86b4b94579SmrgPIXMAN_EXPORT void
87b4b94579Smrgpixman_edge_step (pixman_edge_t *e, int n)
88b4b94579Smrg{
89b4b94579Smrg    pixman_fixed_48_16_t	ne;
90b4b94579Smrg
91b4b94579Smrg    e->x += n * e->stepx;
92b4b94579Smrg
93b4b94579Smrg    ne = e->e + n * (pixman_fixed_48_16_t) e->dx;
94b4b94579Smrg
95b4b94579Smrg    if (n >= 0)
96b4b94579Smrg    {
97b4b94579Smrg	if (ne > 0)
98b4b94579Smrg	{
99b4b94579Smrg	    int nx = (ne + e->dy - 1) / e->dy;
100b4b94579Smrg	    e->e = ne - nx * (pixman_fixed_48_16_t) e->dy;
101b4b94579Smrg	    e->x += nx * e->signdx;
102b4b94579Smrg	}
103b4b94579Smrg    }
104b4b94579Smrg    else
105b4b94579Smrg    {
106b4b94579Smrg	if (ne <= -e->dy)
107b4b94579Smrg	{
108b4b94579Smrg	    int nx = (-ne) / e->dy;
109b4b94579Smrg	    e->e = ne + nx * (pixman_fixed_48_16_t) e->dy;
110b4b94579Smrg	    e->x -= nx * e->signdx;
111b4b94579Smrg	}
112b4b94579Smrg    }
113b4b94579Smrg}
114b4b94579Smrg
115b4b94579Smrg/*
116b4b94579Smrg * A private routine to initialize the multi-step
117b4b94579Smrg * elements of an edge structure
118b4b94579Smrg */
119b4b94579Smrgstatic void
120317c648bSmrg_pixman_edge_multi_init (pixman_edge_t *e, int n, pixman_fixed_t *stepx_p, pixman_fixed_t *dx_p)
121b4b94579Smrg{
122b4b94579Smrg    pixman_fixed_t	stepx;
123b4b94579Smrg    pixman_fixed_48_16_t	ne;
124b4b94579Smrg
125b4b94579Smrg    ne = n * (pixman_fixed_48_16_t) e->dx;
126b4b94579Smrg    stepx = n * e->stepx;
127b4b94579Smrg    if (ne > 0)
128b4b94579Smrg    {
129b4b94579Smrg	int nx = ne / e->dy;
130b4b94579Smrg	ne -= nx * e->dy;
131b4b94579Smrg	stepx += nx * e->signdx;
132b4b94579Smrg    }
133b4b94579Smrg    *dx_p = ne;
134b4b94579Smrg    *stepx_p = stepx;
135b4b94579Smrg}
136b4b94579Smrg
137b4b94579Smrg/*
138b4b94579Smrg * Initialize one edge structure given the line endpoints and a
139b4b94579Smrg * starting y value
140b4b94579Smrg */
141b4b94579SmrgPIXMAN_EXPORT void
142b4b94579Smrgpixman_edge_init (pixman_edge_t	*e,
143b4b94579Smrg		  int		n,
144b4b94579Smrg		  pixman_fixed_t		y_start,
145b4b94579Smrg		  pixman_fixed_t		x_top,
146b4b94579Smrg		  pixman_fixed_t		y_top,
147b4b94579Smrg		  pixman_fixed_t		x_bot,
148b4b94579Smrg		  pixman_fixed_t		y_bot)
149b4b94579Smrg{
150b4b94579Smrg    pixman_fixed_t	dx, dy;
151b4b94579Smrg
152b4b94579Smrg    e->x = x_top;
153b4b94579Smrg    e->e = 0;
154b4b94579Smrg    dx = x_bot - x_top;
155b4b94579Smrg    dy = y_bot - y_top;
156b4b94579Smrg    e->dy = dy;
157b4b94579Smrg    e->dx = 0;
158b4b94579Smrg    if (dy)
159b4b94579Smrg    {
160b4b94579Smrg	if (dx >= 0)
161b4b94579Smrg	{
162b4b94579Smrg	    e->signdx = 1;
163b4b94579Smrg	    e->stepx = dx / dy;
164b4b94579Smrg	    e->dx = dx % dy;
165b4b94579Smrg	    e->e = -dy;
166b4b94579Smrg	}
167b4b94579Smrg	else
168b4b94579Smrg	{
169b4b94579Smrg	    e->signdx = -1;
170b4b94579Smrg	    e->stepx = -(-dx / dy);
171b4b94579Smrg	    e->dx = -dx % dy;
172b4b94579Smrg	    e->e = 0;
173b4b94579Smrg	}
174b4b94579Smrg
175317c648bSmrg	_pixman_edge_multi_init (e, STEP_Y_SMALL(n), &e->stepx_small, &e->dx_small);
176317c648bSmrg	_pixman_edge_multi_init (e, STEP_Y_BIG(n), &e->stepx_big, &e->dx_big);
177b4b94579Smrg    }
178b4b94579Smrg    pixman_edge_step (e, y_start - y_top);
179b4b94579Smrg}
180b4b94579Smrg
181b4b94579Smrg/*
182b4b94579Smrg * Initialize one edge structure given a line, starting y value
183b4b94579Smrg * and a pixel offset for the line
184b4b94579Smrg */
185b4b94579SmrgPIXMAN_EXPORT void
186b4b94579Smrgpixman_line_fixed_edge_init (pixman_edge_t *e,
187b4b94579Smrg			     int	    n,
188b4b94579Smrg			     pixman_fixed_t	    y,
189b4b94579Smrg			     const pixman_line_fixed_t *line,
190b4b94579Smrg			     int	    x_off,
191b4b94579Smrg			     int	    y_off)
192b4b94579Smrg{
193b4b94579Smrg    pixman_fixed_t	x_off_fixed = pixman_int_to_fixed(x_off);
194b4b94579Smrg    pixman_fixed_t	y_off_fixed = pixman_int_to_fixed(y_off);
195b4b94579Smrg    const pixman_point_fixed_t *top, *bot;
196b4b94579Smrg
197b4b94579Smrg    if (line->p1.y <= line->p2.y)
198b4b94579Smrg    {
199b4b94579Smrg	top = &line->p1;
200b4b94579Smrg	bot = &line->p2;
201b4b94579Smrg    }
202b4b94579Smrg    else
203b4b94579Smrg    {
204b4b94579Smrg	top = &line->p2;
205b4b94579Smrg	bot = &line->p1;
206b4b94579Smrg    }
207b4b94579Smrg    pixman_edge_init (e, n, y,
208b4b94579Smrg		    top->x + x_off_fixed,
209b4b94579Smrg		    top->y + y_off_fixed,
210b4b94579Smrg		    bot->x + x_off_fixed,
211b4b94579Smrg		    bot->y + y_off_fixed);
212b4b94579Smrg}
213b4b94579Smrg
214b4b94579Smrgpixman_bool_t
215b4b94579Smrgpixman_multiply_overflows_int (unsigned int a,
216b4b94579Smrg		               unsigned int b)
217b4b94579Smrg{
218b4b94579Smrg    return a >= INT32_MAX / b;
219b4b94579Smrg}
220b4b94579Smrg
221b4b94579Smrgpixman_bool_t
222b4b94579Smrgpixman_addition_overflows_int (unsigned int a,
223b4b94579Smrg		               unsigned int b)
224b4b94579Smrg{
225b4b94579Smrg    return a > INT32_MAX - b;
226b4b94579Smrg}
227b4b94579Smrg
228b4b94579Smrgvoid *
229b4b94579Smrgpixman_malloc_ab(unsigned int a,
230b4b94579Smrg		 unsigned int b)
231b4b94579Smrg{
232b4b94579Smrg    if (a >= INT32_MAX / b)
233b4b94579Smrg	return NULL;
234b4b94579Smrg
235b4b94579Smrg    return malloc (a * b);
236b4b94579Smrg}
237b4b94579Smrg
238b4b94579Smrgvoid *
239b4b94579Smrgpixman_malloc_abc (unsigned int a,
240b4b94579Smrg		   unsigned int b,
241b4b94579Smrg		   unsigned int c)
242b4b94579Smrg{
243b4b94579Smrg    if (a >= INT32_MAX / b)
244b4b94579Smrg	return NULL;
245b4b94579Smrg    else if (a * b >= INT32_MAX / c)
246b4b94579Smrg	return NULL;
247b4b94579Smrg    else
248b4b94579Smrg	return malloc (a * b * c);
249b4b94579Smrg}
250b4b94579Smrg
251b4b94579Smrg
252b4b94579Smrg/**
253b4b94579Smrg * pixman_version:
254b4b94579Smrg *
255b4b94579Smrg * Returns the version of the pixman library encoded in a single
256b4b94579Smrg * integer as per %PIXMAN_VERSION_ENCODE. The encoding ensures that
257b4b94579Smrg * later versions compare greater than earlier versions.
258b4b94579Smrg *
259b4b94579Smrg * A run-time comparison to check that pixman's version is greater than
260b4b94579Smrg * or equal to version X.Y.Z could be performed as follows:
261b4b94579Smrg *
262b4b94579Smrg * <informalexample><programlisting>
263b4b94579Smrg * if (pixman_version() >= PIXMAN_VERSION_ENCODE(X,Y,Z)) {...}
264b4b94579Smrg * </programlisting></informalexample>
265b4b94579Smrg *
266b4b94579Smrg * See also pixman_version_string() as well as the compile-time
267b4b94579Smrg * equivalents %PIXMAN_VERSION and %PIXMAN_VERSION_STRING.
268b4b94579Smrg *
269b4b94579Smrg * Return value: the encoded version.
270b4b94579Smrg **/
271b4b94579SmrgPIXMAN_EXPORT int
272b4b94579Smrgpixman_version (void)
273b4b94579Smrg{
274b4b94579Smrg    return PIXMAN_VERSION;
275b4b94579Smrg}
276b4b94579Smrg
277317c648bSmrg/*
278317c648bSmrg * Helper routine to expand a color component from 0 < n <= 8 bits to 16 bits by
279317c648bSmrg * replication.
280317c648bSmrg */
281317c648bSmrgstatic inline uint64_t
282317c648bSmrgexpand16(const uint8_t val, int nbits)
283317c648bSmrg{
284317c648bSmrg    // Start out with the high bit of val in the high bit of result.
285317c648bSmrg    uint16_t result = (uint16_t)val << (16 - nbits);
286317c648bSmrg
287317c648bSmrg    if (nbits == 0)
288317c648bSmrg        return 0;
289317c648bSmrg
290317c648bSmrg    // Copy the bits in result, doubling the number of bits each time, until we
291317c648bSmrg    // fill all 16 bits.
292317c648bSmrg    while (nbits < 16) {
293317c648bSmrg        result |= result >> nbits;
294317c648bSmrg        nbits *= 2;
295317c648bSmrg    }
296317c648bSmrg
297317c648bSmrg    return result;
298317c648bSmrg}
299317c648bSmrg
300317c648bSmrg/*
301317c648bSmrg * This function expands images from ARGB8 format to ARGB16.  To preserve
302317c648bSmrg * precision, it needs to know the original source format.  For example, if the
303317c648bSmrg * source was PIXMAN_x1r5g5b5 and the red component contained bits 12345, then
304317c648bSmrg * the expanded value is 12345123.  To correctly expand this to 16 bits, it
305317c648bSmrg * should be 1234512345123451 and not 1234512312345123.
306317c648bSmrg */
307317c648bSmrgvoid
308317c648bSmrgpixman_expand(uint64_t *dst, const uint32_t *src,
309317c648bSmrg	      pixman_format_code_t format, int width)
310317c648bSmrg{
311317c648bSmrg    /*
312317c648bSmrg     * Determine the sizes of each component and the masks and shifts required
313317c648bSmrg     * to extract them from the source pixel.
314317c648bSmrg     */
315317c648bSmrg    const int a_size = PIXMAN_FORMAT_A(format),
316317c648bSmrg              r_size = PIXMAN_FORMAT_R(format),
317317c648bSmrg              g_size = PIXMAN_FORMAT_G(format),
318317c648bSmrg              b_size = PIXMAN_FORMAT_B(format);
319317c648bSmrg    const int a_shift = 32 - a_size,
320317c648bSmrg              r_shift = 24 - r_size,
321317c648bSmrg              g_shift = 16 - g_size,
322317c648bSmrg              b_shift =  8 - b_size;
323317c648bSmrg    const uint8_t a_mask = ~(~0 << a_size),
324317c648bSmrg                  r_mask = ~(~0 << r_size),
325317c648bSmrg                  g_mask = ~(~0 << g_size),
326317c648bSmrg                  b_mask = ~(~0 << b_size);
327317c648bSmrg    int i;
328317c648bSmrg
329317c648bSmrg    /* Start at the end so that we can do the expansion in place when src == dst */
330317c648bSmrg    for (i = width - 1; i >= 0; i--)
331317c648bSmrg    {
332317c648bSmrg        const uint32_t pixel = src[i];
333317c648bSmrg        // Extract the components.
334317c648bSmrg        const uint8_t a = (pixel >> a_shift) & a_mask,
335317c648bSmrg                      r = (pixel >> r_shift) & r_mask,
336317c648bSmrg                      g = (pixel >> g_shift) & g_mask,
337317c648bSmrg                      b = (pixel >> b_shift) & b_mask;
338317c648bSmrg        const uint64_t a16 = a_size ? expand16(a, a_size) : 0xffff,
339317c648bSmrg                       r16 = expand16(r, r_size),
340317c648bSmrg                       g16 = expand16(g, g_size),
341317c648bSmrg                       b16 = expand16(b, b_size);
342317c648bSmrg
343317c648bSmrg        dst[i] = a16 << 48 | r16 << 32 | g16 << 16 | b16;
344317c648bSmrg    }
345317c648bSmrg}
346317c648bSmrg
347317c648bSmrg/*
348317c648bSmrg * Contracting is easier than expanding.  We just need to truncate the
349317c648bSmrg * components.
350317c648bSmrg */
351317c648bSmrgvoid
352317c648bSmrgpixman_contract(uint32_t *dst, const uint64_t *src, int width)
353317c648bSmrg{
354317c648bSmrg    int i;
355317c648bSmrg
356317c648bSmrg    /* Start at the beginning so that we can do the contraction in place when
357317c648bSmrg     * src == dst */
358317c648bSmrg    for (i = 0; i < width; i++)
359317c648bSmrg    {
360317c648bSmrg        const uint8_t a = src[i] >> 56,
361317c648bSmrg                      r = src[i] >> 40,
362317c648bSmrg                      g = src[i] >> 24,
363317c648bSmrg                      b = src[i] >> 8;
364317c648bSmrg        dst[i] = a << 24 | r << 16 | g << 8 | b;
365317c648bSmrg    }
366317c648bSmrg}
367317c648bSmrg
368b4b94579Smrg/**
369b4b94579Smrg * pixman_version_string:
370b4b94579Smrg *
371b4b94579Smrg * Returns the version of the pixman library as a human-readable string
372b4b94579Smrg * of the form "X.Y.Z".
373b4b94579Smrg *
374b4b94579Smrg * See also pixman_version() as well as the compile-time equivalents
375b4b94579Smrg * %PIXMAN_VERSION_STRING and %PIXMAN_VERSION.
376b4b94579Smrg *
377b4b94579Smrg * Return value: a string containing the version.
378b4b94579Smrg **/
379b4b94579SmrgPIXMAN_EXPORT const char*
380b4b94579Smrgpixman_version_string (void)
381b4b94579Smrg{
382b4b94579Smrg    return PIXMAN_VERSION_STRING;
383b4b94579Smrg}
384b4b94579Smrg
385b4b94579Smrg/**
386b4b94579Smrg * pixman_format_supported_destination:
387b4b94579Smrg * @format: A pixman_format_code_t format
388b4b94579Smrg *
389b4b94579Smrg * Return value: whether the provided format code is a supported
390b4b94579Smrg * format for a pixman surface used as a destination in
391b4b94579Smrg * rendering.
392b4b94579Smrg *
393b4b94579Smrg * Currently, all pixman_format_code_t values are supported
394b4b94579Smrg * except for the YUV formats.
395b4b94579Smrg **/
396b4b94579SmrgPIXMAN_EXPORT pixman_bool_t
397b4b94579Smrgpixman_format_supported_destination (pixman_format_code_t format)
398b4b94579Smrg{
399b4b94579Smrg    switch (format) {
400b4b94579Smrg    /* 32 bpp formats */
40127693ee9Sveego    case PIXMAN_a2b10g10r10:
40227693ee9Sveego    case PIXMAN_x2b10g10r10:
403b4b94579Smrg    case PIXMAN_a8r8g8b8:
404b4b94579Smrg    case PIXMAN_x8r8g8b8:
405b4b94579Smrg    case PIXMAN_a8b8g8r8:
406b4b94579Smrg    case PIXMAN_x8b8g8r8:
407317c648bSmrg    case PIXMAN_b8g8r8a8:
408317c648bSmrg    case PIXMAN_b8g8r8x8:
409b4b94579Smrg    case PIXMAN_r8g8b8:
410b4b94579Smrg    case PIXMAN_b8g8r8:
411b4b94579Smrg    case PIXMAN_r5g6b5:
412b4b94579Smrg    case PIXMAN_b5g6r5:
413b4b94579Smrg    /* 16 bpp formats */
414b4b94579Smrg    case PIXMAN_a1r5g5b5:
415b4b94579Smrg    case PIXMAN_x1r5g5b5:
416b4b94579Smrg    case PIXMAN_a1b5g5r5:
417b4b94579Smrg    case PIXMAN_x1b5g5r5:
418b4b94579Smrg    case PIXMAN_a4r4g4b4:
419b4b94579Smrg    case PIXMAN_x4r4g4b4:
420b4b94579Smrg    case PIXMAN_a4b4g4r4:
421b4b94579Smrg    case PIXMAN_x4b4g4r4:
422b4b94579Smrg    /* 8bpp formats */
423b4b94579Smrg    case PIXMAN_a8:
424b4b94579Smrg    case PIXMAN_r3g3b2:
425b4b94579Smrg    case PIXMAN_b2g3r3:
426b4b94579Smrg    case PIXMAN_a2r2g2b2:
427b4b94579Smrg    case PIXMAN_a2b2g2r2:
428b4b94579Smrg    case PIXMAN_c8:
429b4b94579Smrg    case PIXMAN_g8:
430b4b94579Smrg    case PIXMAN_x4a4:
431b4b94579Smrg    /* Collides with PIXMAN_c8
432b4b94579Smrg    case PIXMAN_x4c4:
433b4b94579Smrg    */
434b4b94579Smrg    /* Collides with PIXMAN_g8
435b4b94579Smrg    case PIXMAN_x4g4:
436b4b94579Smrg    */
437b4b94579Smrg    /* 4bpp formats */
438b4b94579Smrg    case PIXMAN_a4:
439b4b94579Smrg    case PIXMAN_r1g2b1:
440b4b94579Smrg    case PIXMAN_b1g2r1:
441b4b94579Smrg    case PIXMAN_a1r1g1b1:
442b4b94579Smrg    case PIXMAN_a1b1g1r1:
443b4b94579Smrg    case PIXMAN_c4:
444b4b94579Smrg    case PIXMAN_g4:
445b4b94579Smrg    /* 1bpp formats */
446b4b94579Smrg    case PIXMAN_a1:
447b4b94579Smrg    case PIXMAN_g1:
448b4b94579Smrg	return TRUE;
449b4b94579Smrg
450b4b94579Smrg    /* YUV formats */
451b4b94579Smrg    case PIXMAN_yuy2:
452b4b94579Smrg    case PIXMAN_yv12:
453b4b94579Smrg    default:
454b4b94579Smrg	return FALSE;
455b4b94579Smrg    }
456b4b94579Smrg}
457b4b94579Smrg
458b4b94579Smrg/**
459b4b94579Smrg * pixman_format_supported_source:
460b4b94579Smrg * @format: A pixman_format_code_t format
461b4b94579Smrg *
462b4b94579Smrg * Return value: whether the provided format code is a supported
463b4b94579Smrg * format for a pixman surface used as a source in
464b4b94579Smrg * rendering.
465b4b94579Smrg *
466b4b94579Smrg * Currently, all pixman_format_code_t values are supported.
467b4b94579Smrg **/
468b4b94579SmrgPIXMAN_EXPORT pixman_bool_t
469b4b94579Smrgpixman_format_supported_source (pixman_format_code_t format)
470b4b94579Smrg{
471b4b94579Smrg    switch (format) {
472b4b94579Smrg    /* 32 bpp formats */
47327693ee9Sveego    case PIXMAN_a2b10g10r10:
47427693ee9Sveego    case PIXMAN_x2b10g10r10:
475b4b94579Smrg    case PIXMAN_a8r8g8b8:
476b4b94579Smrg    case PIXMAN_x8r8g8b8:
477b4b94579Smrg    case PIXMAN_a8b8g8r8:
478b4b94579Smrg    case PIXMAN_x8b8g8r8:
479317c648bSmrg    case PIXMAN_b8g8r8a8:
480317c648bSmrg    case PIXMAN_b8g8r8x8:
481b4b94579Smrg    case PIXMAN_r8g8b8:
482b4b94579Smrg    case PIXMAN_b8g8r8:
483b4b94579Smrg    case PIXMAN_r5g6b5:
484b4b94579Smrg    case PIXMAN_b5g6r5:
485b4b94579Smrg    /* 16 bpp formats */
486b4b94579Smrg    case PIXMAN_a1r5g5b5:
487b4b94579Smrg    case PIXMAN_x1r5g5b5:
488b4b94579Smrg    case PIXMAN_a1b5g5r5:
489b4b94579Smrg    case PIXMAN_x1b5g5r5:
490b4b94579Smrg    case PIXMAN_a4r4g4b4:
491b4b94579Smrg    case PIXMAN_x4r4g4b4:
492b4b94579Smrg    case PIXMAN_a4b4g4r4:
493b4b94579Smrg    case PIXMAN_x4b4g4r4:
494b4b94579Smrg    /* 8bpp formats */
495b4b94579Smrg    case PIXMAN_a8:
496b4b94579Smrg    case PIXMAN_r3g3b2:
497b4b94579Smrg    case PIXMAN_b2g3r3:
498b4b94579Smrg    case PIXMAN_a2r2g2b2:
499b4b94579Smrg    case PIXMAN_a2b2g2r2:
500b4b94579Smrg    case PIXMAN_c8:
501b4b94579Smrg    case PIXMAN_g8:
502b4b94579Smrg    case PIXMAN_x4a4:
503b4b94579Smrg    /* Collides with PIXMAN_c8
504b4b94579Smrg    case PIXMAN_x4c4:
505b4b94579Smrg    */
506b4b94579Smrg    /* Collides with PIXMAN_g8
507b4b94579Smrg    case PIXMAN_x4g4:
508b4b94579Smrg    */
509b4b94579Smrg    /* 4bpp formats */
510b4b94579Smrg    case PIXMAN_a4:
511b4b94579Smrg    case PIXMAN_r1g2b1:
512b4b94579Smrg    case PIXMAN_b1g2r1:
513b4b94579Smrg    case PIXMAN_a1r1g1b1:
514b4b94579Smrg    case PIXMAN_a1b1g1r1:
515b4b94579Smrg    case PIXMAN_c4:
516b4b94579Smrg    case PIXMAN_g4:
517b4b94579Smrg    /* 1bpp formats */
518b4b94579Smrg    case PIXMAN_a1:
519b4b94579Smrg    case PIXMAN_g1:
520b4b94579Smrg    /* YUV formats */
521b4b94579Smrg    case PIXMAN_yuy2:
522b4b94579Smrg    case PIXMAN_yv12:
523b4b94579Smrg	return TRUE;
524b4b94579Smrg
525b4b94579Smrg    default:
526b4b94579Smrg	return FALSE;
527b4b94579Smrg    }
528b4b94579Smrg}
529317c648bSmrg
530317c648bSmrgvoid
531317c648bSmrg_pixman_walk_composite_region (pixman_implementation_t *imp,
532317c648bSmrg			      pixman_op_t op,
533317c648bSmrg			      pixman_image_t * pSrc,
534317c648bSmrg			      pixman_image_t * pMask,
535317c648bSmrg			      pixman_image_t * pDst,
536317c648bSmrg			      int16_t xSrc,
537317c648bSmrg			      int16_t ySrc,
538317c648bSmrg			      int16_t xMask,
539317c648bSmrg			      int16_t yMask,
540317c648bSmrg			      int16_t xDst,
541317c648bSmrg			      int16_t yDst,
542317c648bSmrg			      uint16_t width,
543317c648bSmrg			      uint16_t height,
544317c648bSmrg			      pixman_bool_t srcRepeat,
545317c648bSmrg			      pixman_bool_t maskRepeat,
546317c648bSmrg			      pixman_composite_func_t compositeRect)
547317c648bSmrg{
548317c648bSmrg    int		    n;
549317c648bSmrg    const pixman_box32_t *pbox;
550317c648bSmrg    int		    w, h, w_this, h_this;
551317c648bSmrg    int		    x_msk, y_msk, x_src, y_src, x_dst, y_dst;
552317c648bSmrg    pixman_region32_t reg;
553317c648bSmrg    pixman_region32_t *region;
554317c648bSmrg
555317c648bSmrg    pixman_region32_init (&reg);
556317c648bSmrg    if (!pixman_compute_composite_region32 (&reg, pSrc, pMask, pDst,
557317c648bSmrg					    xSrc, ySrc, xMask, yMask, xDst, yDst, width, height))
558317c648bSmrg    {
559317c648bSmrg	return;
560317c648bSmrg    }
561317c648bSmrg
562317c648bSmrg    region = &reg;
563317c648bSmrg
564317c648bSmrg    pbox = pixman_region32_rectangles (region, &n);
565317c648bSmrg    while (n--)
566317c648bSmrg    {
567317c648bSmrg	h = pbox->y2 - pbox->y1;
568317c648bSmrg	y_src = pbox->y1 - yDst + ySrc;
569317c648bSmrg	y_msk = pbox->y1 - yDst + yMask;
570317c648bSmrg	y_dst = pbox->y1;
571317c648bSmrg	while (h)
572317c648bSmrg	{
573317c648bSmrg	    h_this = h;
574317c648bSmrg	    w = pbox->x2 - pbox->x1;
575317c648bSmrg	    x_src = pbox->x1 - xDst + xSrc;
576317c648bSmrg	    x_msk = pbox->x1 - xDst + xMask;
577317c648bSmrg	    x_dst = pbox->x1;
578317c648bSmrg	    if (maskRepeat)
579317c648bSmrg	    {
580317c648bSmrg		y_msk = MOD (y_msk, pMask->bits.height);
581317c648bSmrg		if (h_this > pMask->bits.height - y_msk)
582317c648bSmrg		    h_this = pMask->bits.height - y_msk;
583317c648bSmrg	    }
584317c648bSmrg	    if (srcRepeat)
585317c648bSmrg	    {
586317c648bSmrg		y_src = MOD (y_src, pSrc->bits.height);
587317c648bSmrg		if (h_this > pSrc->bits.height - y_src)
588317c648bSmrg		    h_this = pSrc->bits.height - y_src;
589317c648bSmrg	    }
590317c648bSmrg	    while (w)
591317c648bSmrg	    {
592317c648bSmrg		w_this = w;
593317c648bSmrg		if (maskRepeat)
594317c648bSmrg		{
595317c648bSmrg		    x_msk = MOD (x_msk, pMask->bits.width);
596317c648bSmrg		    if (w_this > pMask->bits.width - x_msk)
597317c648bSmrg			w_this = pMask->bits.width - x_msk;
598317c648bSmrg		}
599317c648bSmrg		if (srcRepeat)
600317c648bSmrg		{
601317c648bSmrg		    x_src = MOD (x_src, pSrc->bits.width);
602317c648bSmrg		    if (w_this > pSrc->bits.width - x_src)
603317c648bSmrg			w_this = pSrc->bits.width - x_src;
604317c648bSmrg		}
605317c648bSmrg		(*compositeRect) (imp,
606317c648bSmrg				  op, pSrc, pMask, pDst,
607317c648bSmrg				  x_src, y_src, x_msk, y_msk, x_dst, y_dst,
608317c648bSmrg				  w_this, h_this);
609317c648bSmrg		w -= w_this;
610317c648bSmrg		x_src += w_this;
611317c648bSmrg		x_msk += w_this;
612317c648bSmrg		x_dst += w_this;
613317c648bSmrg	    }
614317c648bSmrg	    h -= h_this;
615317c648bSmrg	    y_src += h_this;
616317c648bSmrg	    y_msk += h_this;
617317c648bSmrg	    y_dst += h_this;
618317c648bSmrg	}
619317c648bSmrg	pbox++;
620317c648bSmrg    }
621317c648bSmrg    pixman_region32_fini (&reg);
622317c648bSmrg}
623317c648bSmrg
624317c648bSmrgstatic pixman_bool_t
625317c648bSmrgmask_is_solid (pixman_image_t *mask)
626317c648bSmrg{
627317c648bSmrg    if (mask->type == SOLID)
628317c648bSmrg	return TRUE;
629317c648bSmrg
630317c648bSmrg    if (mask->type == BITS &&
631317c648bSmrg	mask->common.repeat == PIXMAN_REPEAT_NORMAL &&
632317c648bSmrg	mask->bits.width == 1 &&
633317c648bSmrg	mask->bits.height == 1)
634317c648bSmrg    {
635317c648bSmrg	return TRUE;
636317c648bSmrg    }
637317c648bSmrg
638317c648bSmrg    return FALSE;
639317c648bSmrg}
640317c648bSmrg
641317c648bSmrgstatic const FastPathInfo *
642317c648bSmrgget_fast_path (const FastPathInfo *fast_paths,
643317c648bSmrg	       pixman_op_t         op,
644317c648bSmrg	       pixman_image_t     *pSrc,
645317c648bSmrg	       pixman_image_t     *pMask,
646317c648bSmrg	       pixman_image_t     *pDst,
647317c648bSmrg	       pixman_bool_t       is_pixbuf)
648317c648bSmrg{
649317c648bSmrg    const FastPathInfo *info;
650317c648bSmrg
651317c648bSmrg    for (info = fast_paths; info->op != PIXMAN_OP_NONE; info++)
652317c648bSmrg    {
653317c648bSmrg	pixman_bool_t valid_src		= FALSE;
654317c648bSmrg	pixman_bool_t valid_mask	= FALSE;
655317c648bSmrg
656317c648bSmrg	if (info->op != op)
657317c648bSmrg	    continue;
658317c648bSmrg
659317c648bSmrg	if ((info->src_format == PIXMAN_solid && pixman_image_can_get_solid (pSrc))		||
660317c648bSmrg	    (pSrc->type == BITS && info->src_format == pSrc->bits.format))
661317c648bSmrg	{
662317c648bSmrg	    valid_src = TRUE;
663317c648bSmrg	}
664317c648bSmrg
665317c648bSmrg	if (!valid_src)
666317c648bSmrg	    continue;
667317c648bSmrg
668317c648bSmrg	if ((info->mask_format == PIXMAN_null && !pMask)			||
669317c648bSmrg	    (pMask && pMask->type == BITS && info->mask_format == pMask->bits.format))
670317c648bSmrg	{
671317c648bSmrg	    valid_mask = TRUE;
672317c648bSmrg
673317c648bSmrg	    if (info->flags & NEED_SOLID_MASK)
674317c648bSmrg	    {
675317c648bSmrg		if (!pMask || !mask_is_solid (pMask))
676317c648bSmrg		    valid_mask = FALSE;
677317c648bSmrg	    }
678317c648bSmrg
679317c648bSmrg	    if (info->flags & NEED_COMPONENT_ALPHA)
680317c648bSmrg	    {
681317c648bSmrg		if (!pMask || !pMask->common.component_alpha)
682317c648bSmrg		    valid_mask = FALSE;
683317c648bSmrg	    }
684317c648bSmrg	}
685317c648bSmrg
686317c648bSmrg	if (!valid_mask)
687317c648bSmrg	    continue;
688317c648bSmrg
689317c648bSmrg	if (info->dest_format != pDst->bits.format)
690317c648bSmrg	    continue;
691317c648bSmrg
692317c648bSmrg	if ((info->flags & NEED_PIXBUF) && !is_pixbuf)
693317c648bSmrg	    continue;
694317c648bSmrg
695317c648bSmrg	return info;
696317c648bSmrg    }
697317c648bSmrg
698317c648bSmrg    return NULL;
699317c648bSmrg}
700317c648bSmrg
701317c648bSmrgpixman_bool_t
702317c648bSmrg_pixman_run_fast_path (const FastPathInfo *paths,
703317c648bSmrg		       pixman_implementation_t *imp,
704317c648bSmrg		       pixman_op_t op,
705317c648bSmrg		       pixman_image_t *src,
706317c648bSmrg		       pixman_image_t *mask,
707317c648bSmrg		       pixman_image_t *dest,
708317c648bSmrg		       int32_t src_x,
709317c648bSmrg		       int32_t src_y,
710317c648bSmrg		       int32_t mask_x,
711317c648bSmrg		       int32_t mask_y,
712317c648bSmrg		       int32_t dest_x,
713317c648bSmrg		       int32_t dest_y,
714317c648bSmrg		       int32_t width,
715317c648bSmrg		       int32_t height)
716317c648bSmrg{
717317c648bSmrg    pixman_composite_func_t func = NULL;
718317c648bSmrg    pixman_bool_t src_repeat = src->common.repeat == PIXMAN_REPEAT_NORMAL;
719317c648bSmrg    pixman_bool_t mask_repeat = mask && mask->common.repeat == PIXMAN_REPEAT_NORMAL;
720317c648bSmrg
721317c648bSmrg    if ((src->type == BITS || pixman_image_can_get_solid (src)) &&
722317c648bSmrg	(!mask || mask->type == BITS)
723317c648bSmrg        && !src->common.transform && !(mask && mask->common.transform)
724317c648bSmrg        && !(mask && mask->common.alpha_map) && !src->common.alpha_map && !dest->common.alpha_map
725317c648bSmrg        && (src->common.filter != PIXMAN_FILTER_CONVOLUTION)
726317c648bSmrg        && (src->common.repeat != PIXMAN_REPEAT_PAD)
727317c648bSmrg        && (src->common.repeat != PIXMAN_REPEAT_REFLECT)
728317c648bSmrg        && (!mask || (mask->common.filter != PIXMAN_FILTER_CONVOLUTION &&
729317c648bSmrg		      mask->common.repeat != PIXMAN_REPEAT_PAD &&
730317c648bSmrg		      mask->common.repeat != PIXMAN_REPEAT_REFLECT))
731317c648bSmrg	&& !src->common.read_func && !src->common.write_func
732317c648bSmrg	&& !(mask && mask->common.read_func)
733317c648bSmrg	&& !(mask && mask->common.write_func)
734317c648bSmrg	&& !dest->common.read_func
735317c648bSmrg	&& !dest->common.write_func)
736317c648bSmrg    {
737317c648bSmrg	const FastPathInfo *info;
738317c648bSmrg	pixman_bool_t pixbuf;
739317c648bSmrg
740317c648bSmrg	pixbuf =
741317c648bSmrg	    src && src->type == BITS		&&
742317c648bSmrg	    mask && mask->type == BITS		&&
743317c648bSmrg	    src->bits.bits == mask->bits.bits	&&
744317c648bSmrg	    src_x == mask_x			&&
745317c648bSmrg	    src_y == mask_y			&&
746317c648bSmrg	    !mask->common.component_alpha	&&
747317c648bSmrg	    !mask_repeat;
748317c648bSmrg
749317c648bSmrg	info = get_fast_path (paths, op, src, mask, dest, pixbuf);
750317c648bSmrg
751317c648bSmrg	if (info)
752317c648bSmrg	{
753317c648bSmrg	    func = info->func;
754317c648bSmrg
755317c648bSmrg	    if (info->src_format == PIXMAN_solid)
756317c648bSmrg		src_repeat = FALSE;
757317c648bSmrg
758317c648bSmrg	    if (info->mask_format == PIXMAN_solid || info->flags & NEED_SOLID_MASK)
759317c648bSmrg		mask_repeat = FALSE;
760317c648bSmrg
761317c648bSmrg	    if ((src_repeat			&&
762317c648bSmrg		 src->bits.width == 1		&&
763317c648bSmrg		 src->bits.height == 1)	||
764317c648bSmrg		(mask_repeat			&&
765317c648bSmrg		 mask->bits.width == 1		&&
766317c648bSmrg		 mask->bits.height == 1))
767317c648bSmrg	    {
768317c648bSmrg		/* If src or mask are repeating 1x1 images and src_repeat or
769317c648bSmrg		 * mask_repeat are still TRUE, it means the fast path we
770317c648bSmrg		 * selected does not actually handle repeating images.
771317c648bSmrg		 *
772317c648bSmrg		 * So rather than call the "fast path" with a zillion
773317c648bSmrg		 * 1x1 requests, we just fall back to the general code (which
774317c648bSmrg		 * does do something sensible with 1x1 repeating images).
775317c648bSmrg		 */
776317c648bSmrg		func = NULL;
777317c648bSmrg	    }
778317c648bSmrg	}
779317c648bSmrg    }
780317c648bSmrg
781317c648bSmrg    if (func)
782317c648bSmrg    {
783317c648bSmrg	_pixman_walk_composite_region (imp, op,
784317c648bSmrg				       src, mask, dest,
785317c648bSmrg				       src_x, src_y, mask_x, mask_y,
786317c648bSmrg				       dest_x, dest_y,
787317c648bSmrg				       width, height,
788317c648bSmrg				       src_repeat, mask_repeat,
789317c648bSmrg				       func);
790317c648bSmrg	return TRUE;
791317c648bSmrg    }
792317c648bSmrg
793317c648bSmrg    return FALSE;
794317c648bSmrg}
795