pixman-utils.c revision 952204ab
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
170dc259aabSmrg#define N_TMP_BOXES (16)
171dc259aabSmrg
172dc259aabSmrgpixman_bool_t
173dc259aabSmrgpixman_region16_copy_from_region32 (pixman_region16_t *dst,
174d0321353Smrg                                    pixman_region32_t *src)
175dc259aabSmrg{
176dc259aabSmrg    int n_boxes, i;
177dc259aabSmrg    pixman_box32_t *boxes32;
178dc259aabSmrg    pixman_box16_t *boxes16;
179dc259aabSmrg    pixman_bool_t retval;
180d0321353Smrg
181dc259aabSmrg    boxes32 = pixman_region32_rectangles (src, &n_boxes);
182dc259aabSmrg
183dc259aabSmrg    boxes16 = pixman_malloc_ab (n_boxes, sizeof (pixman_box16_t));
184dc259aabSmrg
185dc259aabSmrg    if (!boxes16)
186dc259aabSmrg	return FALSE;
187d0321353Smrg
188dc259aabSmrg    for (i = 0; i < n_boxes; ++i)
189dc259aabSmrg    {
190dc259aabSmrg	boxes16[i].x1 = boxes32[i].x1;
191dc259aabSmrg	boxes16[i].y1 = boxes32[i].y1;
192dc259aabSmrg	boxes16[i].x2 = boxes32[i].x2;
193dc259aabSmrg	boxes16[i].y2 = boxes32[i].y2;
194dc259aabSmrg    }
195dc259aabSmrg
196dc259aabSmrg    pixman_region_fini (dst);
197dc259aabSmrg    retval = pixman_region_init_rects (dst, boxes16, n_boxes);
198dc259aabSmrg    free (boxes16);
199dc259aabSmrg    return retval;
200317c648bSmrg}
201dc259aabSmrg
202dc259aabSmrgpixman_bool_t
203dc259aabSmrgpixman_region32_copy_from_region16 (pixman_region32_t *dst,
204d0321353Smrg                                    pixman_region16_t *src)
205dc259aabSmrg{
206dc259aabSmrg    int n_boxes, i;
207dc259aabSmrg    pixman_box16_t *boxes16;
208dc259aabSmrg    pixman_box32_t *boxes32;
209dc259aabSmrg    pixman_box32_t tmp_boxes[N_TMP_BOXES];
210dc259aabSmrg    pixman_bool_t retval;
211d0321353Smrg
212dc259aabSmrg    boxes16 = pixman_region_rectangles (src, &n_boxes);
213dc259aabSmrg
214dc259aabSmrg    if (n_boxes > N_TMP_BOXES)
215dc259aabSmrg	boxes32 = pixman_malloc_ab (n_boxes, sizeof (pixman_box32_t));
216dc259aabSmrg    else
217dc259aabSmrg	boxes32 = tmp_boxes;
218d0321353Smrg
219dc259aabSmrg    if (!boxes32)
220dc259aabSmrg	return FALSE;
221d0321353Smrg
222dc259aabSmrg    for (i = 0; i < n_boxes; ++i)
223dc259aabSmrg    {
224dc259aabSmrg	boxes32[i].x1 = boxes16[i].x1;
225dc259aabSmrg	boxes32[i].y1 = boxes16[i].y1;
226dc259aabSmrg	boxes32[i].x2 = boxes16[i].x2;
227dc259aabSmrg	boxes32[i].y2 = boxes16[i].y2;
228dc259aabSmrg    }
229dc259aabSmrg
230dc259aabSmrg    pixman_region32_fini (dst);
231dc259aabSmrg    retval = pixman_region32_init_rects (dst, boxes32, n_boxes);
232dc259aabSmrg
233dc259aabSmrg    if (boxes32 != tmp_boxes)
234dc259aabSmrg	free (boxes32);
235dc259aabSmrg
236dc259aabSmrg    return retval;
237dc259aabSmrg}
238952204abSmrg
239952204abSmrg#ifdef DEBUG
240952204abSmrg
241952204abSmrgvoid
242952204abSmrg_pixman_log_error (const char *function, const char *message)
243952204abSmrg{
244952204abSmrg    static int n_messages = 0;
245952204abSmrg
246952204abSmrg    if (n_messages < 10)
247952204abSmrg    {
248952204abSmrg	fprintf (stderr,
249952204abSmrg		 "*** BUG ***\n"
250952204abSmrg		 "In %s: %s\n"
251952204abSmrg		 "Set a breakpoint on '_pixman_log_error' to debug\n\n",
252952204abSmrg                 function, message);
253952204abSmrg
254952204abSmrg	n_messages++;
255952204abSmrg    }
256952204abSmrg}
257952204abSmrg
258952204abSmrg#endif
259