pixman-utils.c revision 953d7d37
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
33b4b94579Smrgpixman_bool_t
34b4b94579Smrgpixman_multiply_overflows_int (unsigned int a,
35d0321353Smrg                               unsigned int b)
36b4b94579Smrg{
37b4b94579Smrg    return a >= INT32_MAX / b;
38b4b94579Smrg}
39b4b94579Smrg
40b4b94579Smrgpixman_bool_t
41b4b94579Smrgpixman_addition_overflows_int (unsigned int a,
42d0321353Smrg                               unsigned int b)
43b4b94579Smrg{
44b4b94579Smrg    return a > INT32_MAX - b;
45b4b94579Smrg}
46b4b94579Smrg
47b4b94579Smrgvoid *
48d0321353Smrgpixman_malloc_ab (unsigned int a,
49d0321353Smrg                  unsigned int b)
50b4b94579Smrg{
51b4b94579Smrg    if (a >= INT32_MAX / b)
52b4b94579Smrg	return NULL;
53b4b94579Smrg
54b4b94579Smrg    return malloc (a * b);
55b4b94579Smrg}
56b4b94579Smrg
57b4b94579Smrgvoid *
58b4b94579Smrgpixman_malloc_abc (unsigned int a,
59d0321353Smrg                   unsigned int b,
60d0321353Smrg                   unsigned int c)
61b4b94579Smrg{
62b4b94579Smrg    if (a >= INT32_MAX / b)
63b4b94579Smrg	return NULL;
64b4b94579Smrg    else if (a * b >= INT32_MAX / c)
65b4b94579Smrg	return NULL;
66b4b94579Smrg    else
67b4b94579Smrg	return malloc (a * b * c);
68b4b94579Smrg}
69b4b94579Smrg
70317c648bSmrg/*
71d0321353Smrg * Helper routine to expand a color component from 0 < n <= 8 bits to 16
72d0321353Smrg * bits by replication.
73317c648bSmrg */
74317c648bSmrgstatic inline uint64_t
75d0321353Smrgexpand16 (const uint8_t val, int nbits)
76317c648bSmrg{
77d0321353Smrg    /* Start out with the high bit of val in the high bit of result. */
78317c648bSmrg    uint16_t result = (uint16_t)val << (16 - nbits);
79317c648bSmrg
80317c648bSmrg    if (nbits == 0)
81d0321353Smrg	return 0;
82317c648bSmrg
83d0321353Smrg    /* Copy the bits in result, doubling the number of bits each time, until
84d0321353Smrg     * we fill all 16 bits.
85d0321353Smrg     */
86d0321353Smrg    while (nbits < 16)
87d0321353Smrg    {
88d0321353Smrg	result |= result >> nbits;
89d0321353Smrg	nbits *= 2;
90317c648bSmrg    }
91317c648bSmrg
92317c648bSmrg    return result;
93317c648bSmrg}
94317c648bSmrg
95317c648bSmrg/*
96317c648bSmrg * This function expands images from ARGB8 format to ARGB16.  To preserve
97317c648bSmrg * precision, it needs to know the original source format.  For example, if the
98317c648bSmrg * source was PIXMAN_x1r5g5b5 and the red component contained bits 12345, then
99317c648bSmrg * the expanded value is 12345123.  To correctly expand this to 16 bits, it
100317c648bSmrg * should be 1234512345123451 and not 1234512312345123.
101317c648bSmrg */
102317c648bSmrgvoid
103d0321353Smrgpixman_expand (uint64_t *           dst,
104d0321353Smrg               const uint32_t *     src,
105d0321353Smrg               pixman_format_code_t format,
106d0321353Smrg               int                  width)
107317c648bSmrg{
108317c648bSmrg    /*
109d0321353Smrg     * Determine the sizes of each component and the masks and shifts
110d0321353Smrg     * required to extract them from the source pixel.
111317c648bSmrg     */
112d0321353Smrg    const int a_size = PIXMAN_FORMAT_A (format),
113d0321353Smrg              r_size = PIXMAN_FORMAT_R (format),
114d0321353Smrg              g_size = PIXMAN_FORMAT_G (format),
115d0321353Smrg              b_size = PIXMAN_FORMAT_B (format);
116317c648bSmrg    const int a_shift = 32 - a_size,
117317c648bSmrg              r_shift = 24 - r_size,
118317c648bSmrg              g_shift = 16 - g_size,
119317c648bSmrg              b_shift =  8 - b_size;
120317c648bSmrg    const uint8_t a_mask = ~(~0 << a_size),
121317c648bSmrg                  r_mask = ~(~0 << r_size),
122317c648bSmrg                  g_mask = ~(~0 << g_size),
123317c648bSmrg                  b_mask = ~(~0 << b_size);
124317c648bSmrg    int i;
125317c648bSmrg
126d0321353Smrg    /* Start at the end so that we can do the expansion in place
127d0321353Smrg     * when src == dst
128d0321353Smrg     */
129317c648bSmrg    for (i = width - 1; i >= 0; i--)
130317c648bSmrg    {
131d0321353Smrg	const uint32_t pixel = src[i];
132d0321353Smrg	const uint8_t a = (pixel >> a_shift) & a_mask,
133d0321353Smrg	              r = (pixel >> r_shift) & r_mask,
134d0321353Smrg	              g = (pixel >> g_shift) & g_mask,
135d0321353Smrg	              b = (pixel >> b_shift) & b_mask;
136d0321353Smrg	const uint64_t a16 = a_size ? expand16 (a, a_size) : 0xffff,
137d0321353Smrg	               r16 = expand16 (r, r_size),
138d0321353Smrg	               g16 = expand16 (g, g_size),
139d0321353Smrg	               b16 = expand16 (b, b_size);
140d0321353Smrg
141d0321353Smrg	dst[i] = a16 << 48 | r16 << 32 | g16 << 16 | b16;
142317c648bSmrg    }
143317c648bSmrg}
144317c648bSmrg
145317c648bSmrg/*
146317c648bSmrg * Contracting is easier than expanding.  We just need to truncate the
147317c648bSmrg * components.
148317c648bSmrg */
149317c648bSmrgvoid
150d0321353Smrgpixman_contract (uint32_t *      dst,
151d0321353Smrg                 const uint64_t *src,
152d0321353Smrg                 int             width)
153317c648bSmrg{
154317c648bSmrg    int i;
155317c648bSmrg
156d0321353Smrg    /* Start at the beginning so that we can do the contraction in
157d0321353Smrg     * place when src == dst
158d0321353Smrg     */
159317c648bSmrg    for (i = 0; i < width; i++)
160317c648bSmrg    {
161d0321353Smrg	const uint8_t a = src[i] >> 56,
162d0321353Smrg	              r = src[i] >> 40,
163d0321353Smrg	              g = src[i] >> 24,
164d0321353Smrg	              b = src[i] >> 8;
165d0321353Smrg
166d0321353Smrg	dst[i] = a << 24 | r << 16 | g << 8 | b;
167317c648bSmrg    }
168317c648bSmrg}
169317c648bSmrg
170953d7d37Smrguint32_t *
171953d7d37Smrg_pixman_iter_get_scanline_noop (pixman_iter_t *iter, const uint32_t *mask)
172953d7d37Smrg{
173953d7d37Smrg    return iter->buffer;
174953d7d37Smrg}
175953d7d37Smrg
176dc259aabSmrg#define N_TMP_BOXES (16)
177dc259aabSmrg
178dc259aabSmrgpixman_bool_t
179dc259aabSmrgpixman_region16_copy_from_region32 (pixman_region16_t *dst,
180d0321353Smrg                                    pixman_region32_t *src)
181dc259aabSmrg{
182dc259aabSmrg    int n_boxes, i;
183dc259aabSmrg    pixman_box32_t *boxes32;
184dc259aabSmrg    pixman_box16_t *boxes16;
185dc259aabSmrg    pixman_bool_t retval;
186d0321353Smrg
187dc259aabSmrg    boxes32 = pixman_region32_rectangles (src, &n_boxes);
188dc259aabSmrg
189dc259aabSmrg    boxes16 = pixman_malloc_ab (n_boxes, sizeof (pixman_box16_t));
190dc259aabSmrg
191dc259aabSmrg    if (!boxes16)
192dc259aabSmrg	return FALSE;
193d0321353Smrg
194dc259aabSmrg    for (i = 0; i < n_boxes; ++i)
195dc259aabSmrg    {
196dc259aabSmrg	boxes16[i].x1 = boxes32[i].x1;
197dc259aabSmrg	boxes16[i].y1 = boxes32[i].y1;
198dc259aabSmrg	boxes16[i].x2 = boxes32[i].x2;
199dc259aabSmrg	boxes16[i].y2 = boxes32[i].y2;
200dc259aabSmrg    }
201dc259aabSmrg
202dc259aabSmrg    pixman_region_fini (dst);
203dc259aabSmrg    retval = pixman_region_init_rects (dst, boxes16, n_boxes);
204dc259aabSmrg    free (boxes16);
205dc259aabSmrg    return retval;
206317c648bSmrg}
207dc259aabSmrg
208dc259aabSmrgpixman_bool_t
209dc259aabSmrgpixman_region32_copy_from_region16 (pixman_region32_t *dst,
210d0321353Smrg                                    pixman_region16_t *src)
211dc259aabSmrg{
212dc259aabSmrg    int n_boxes, i;
213dc259aabSmrg    pixman_box16_t *boxes16;
214dc259aabSmrg    pixman_box32_t *boxes32;
215dc259aabSmrg    pixman_box32_t tmp_boxes[N_TMP_BOXES];
216dc259aabSmrg    pixman_bool_t retval;
217d0321353Smrg
218dc259aabSmrg    boxes16 = pixman_region_rectangles (src, &n_boxes);
219dc259aabSmrg
220dc259aabSmrg    if (n_boxes > N_TMP_BOXES)
221dc259aabSmrg	boxes32 = pixman_malloc_ab (n_boxes, sizeof (pixman_box32_t));
222dc259aabSmrg    else
223dc259aabSmrg	boxes32 = tmp_boxes;
224d0321353Smrg
225dc259aabSmrg    if (!boxes32)
226dc259aabSmrg	return FALSE;
227d0321353Smrg
228dc259aabSmrg    for (i = 0; i < n_boxes; ++i)
229dc259aabSmrg    {
230dc259aabSmrg	boxes32[i].x1 = boxes16[i].x1;
231dc259aabSmrg	boxes32[i].y1 = boxes16[i].y1;
232dc259aabSmrg	boxes32[i].x2 = boxes16[i].x2;
233dc259aabSmrg	boxes32[i].y2 = boxes16[i].y2;
234dc259aabSmrg    }
235dc259aabSmrg
236dc259aabSmrg    pixman_region32_fini (dst);
237dc259aabSmrg    retval = pixman_region32_init_rects (dst, boxes32, n_boxes);
238dc259aabSmrg
239dc259aabSmrg    if (boxes32 != tmp_boxes)
240dc259aabSmrg	free (boxes32);
241dc259aabSmrg
242dc259aabSmrg    return retval;
243dc259aabSmrg}
244952204abSmrg
245952204abSmrg#ifdef DEBUG
246952204abSmrg
247952204abSmrgvoid
248952204abSmrg_pixman_log_error (const char *function, const char *message)
249952204abSmrg{
250952204abSmrg    static int n_messages = 0;
251952204abSmrg
252952204abSmrg    if (n_messages < 10)
253952204abSmrg    {
254952204abSmrg	fprintf (stderr,
255952204abSmrg		 "*** BUG ***\n"
256952204abSmrg		 "In %s: %s\n"
257952204abSmrg		 "Set a breakpoint on '_pixman_log_error' to debug\n\n",
258952204abSmrg                 function, message);
259952204abSmrg
260952204abSmrg	n_messages++;
261952204abSmrg    }
262952204abSmrg}
263952204abSmrg
264952204abSmrg#endif
265