Add packaging files for Tizen
[profile/ivi/pixman.git] / pixman / pixman-utils.c
1 /*
2  * Copyright © 2000 SuSE, Inc.
3  * Copyright © 1999 Keith Packard
4  *
5  * Permission to use, copy, modify, distribute, and sell this software and its
6  * documentation for any purpose is hereby granted without fee, provided that
7  * the above copyright notice appear in all copies and that both that
8  * copyright notice and this permission notice appear in supporting
9  * documentation, and that the name of SuSE not be used in advertising or
10  * publicity pertaining to distribution of the software without specific,
11  * written prior permission.  SuSE makes no representations about the
12  * suitability of this software for any purpose.  It is provided "as is"
13  * without express or implied warranty.
14  *
15  * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
17  * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
18  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
19  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
20  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21  *
22  * Author:  Keith Packard, SuSE, Inc.
23  */
24
25 #ifdef HAVE_CONFIG_H
26 #include <config.h>
27 #endif
28 #include <stdio.h>
29 #include <stdlib.h>
30
31 #include "pixman-private.h"
32
33 #define N_CACHED_FAST_PATHS 8
34
35 typedef struct
36 {
37     struct
38     {
39         pixman_implementation_t *       imp;
40         pixman_fast_path_t              fast_path;
41     } cache [N_CACHED_FAST_PATHS];
42 } cache_t;
43
44 PIXMAN_DEFINE_THREAD_LOCAL (cache_t, fast_path_cache);
45
46 pixman_bool_t
47 _pixman_lookup_composite_function (pixman_implementation_t     *toplevel,
48                                    pixman_op_t                  op,
49                                    pixman_format_code_t         src_format,
50                                    uint32_t                     src_flags,
51                                    pixman_format_code_t         mask_format,
52                                    uint32_t                     mask_flags,
53                                    pixman_format_code_t         dest_format,
54                                    uint32_t                     dest_flags,
55                                    pixman_implementation_t    **out_imp,
56                                    pixman_composite_func_t     *out_func)
57 {
58     pixman_implementation_t *imp;
59     cache_t *cache;
60     int i;
61
62     /* Check cache for fast paths */
63     cache = PIXMAN_GET_THREAD_LOCAL (fast_path_cache);
64
65     for (i = 0; i < N_CACHED_FAST_PATHS; ++i)
66     {
67         const pixman_fast_path_t *info = &(cache->cache[i].fast_path);
68
69         /* Note that we check for equality here, not whether
70          * the cached fast path matches. This is to prevent
71          * us from selecting an overly general fast path
72          * when a more specific one would work.
73          */
74         if (info->op == op                      &&
75             info->src_format == src_format      &&
76             info->mask_format == mask_format    &&
77             info->dest_format == dest_format    &&
78             info->src_flags == src_flags        &&
79             info->mask_flags == mask_flags      &&
80             info->dest_flags == dest_flags      &&
81             info->func)
82         {
83             *out_imp = cache->cache[i].imp;
84             *out_func = cache->cache[i].fast_path.func;
85
86             goto update_cache;
87         }
88     }
89
90     for (imp = toplevel; imp != NULL; imp = imp->delegate)
91     {
92         const pixman_fast_path_t *info = imp->fast_paths;
93
94         while (info->op != PIXMAN_OP_NONE)
95         {
96             if ((info->op == op || info->op == PIXMAN_OP_any)           &&
97                 /* Formats */
98                 ((info->src_format == src_format) ||
99                  (info->src_format == PIXMAN_any))                      &&
100                 ((info->mask_format == mask_format) ||
101                  (info->mask_format == PIXMAN_any))                     &&
102                 ((info->dest_format == dest_format) ||
103                  (info->dest_format == PIXMAN_any))                     &&
104                 /* Flags */
105                 (info->src_flags & src_flags) == info->src_flags        &&
106                 (info->mask_flags & mask_flags) == info->mask_flags     &&
107                 (info->dest_flags & dest_flags) == info->dest_flags)
108             {
109                 *out_imp = imp;
110                 *out_func = info->func;
111
112                 /* Set i to the last spot in the cache so that the
113                  * move-to-front code below will work
114                  */
115                 i = N_CACHED_FAST_PATHS - 1;
116
117                 goto update_cache;
118             }
119
120             ++info;
121         }
122     }
123     return FALSE;
124
125 update_cache:
126     if (i)
127     {
128         while (i--)
129             cache->cache[i + 1] = cache->cache[i];
130
131         cache->cache[0].imp = *out_imp;
132         cache->cache[0].fast_path.op = op;
133         cache->cache[0].fast_path.src_format = src_format;
134         cache->cache[0].fast_path.src_flags = src_flags;
135         cache->cache[0].fast_path.mask_format = mask_format;
136         cache->cache[0].fast_path.mask_flags = mask_flags;
137         cache->cache[0].fast_path.dest_format = dest_format;
138         cache->cache[0].fast_path.dest_flags = dest_flags;
139         cache->cache[0].fast_path.func = *out_func;
140     }
141
142     return TRUE;
143 }
144
145 pixman_bool_t
146 _pixman_multiply_overflows_size (size_t a, size_t b)
147 {
148     return a >= SIZE_MAX / b;
149 }
150
151 pixman_bool_t
152 _pixman_multiply_overflows_int (unsigned int a, unsigned int b)
153 {
154     return a >= INT32_MAX / b;
155 }
156
157 pixman_bool_t
158 _pixman_addition_overflows_int (unsigned int a, unsigned int b)
159 {
160     return a > INT32_MAX - b;
161 }
162
163 void *
164 pixman_malloc_ab (unsigned int a,
165                   unsigned int b)
166 {
167     if (a >= INT32_MAX / b)
168         return NULL;
169
170     return malloc (a * b);
171 }
172
173 void *
174 pixman_malloc_abc (unsigned int a,
175                    unsigned int b,
176                    unsigned int c)
177 {
178     if (a >= INT32_MAX / b)
179         return NULL;
180     else if (a * b >= INT32_MAX / c)
181         return NULL;
182     else
183         return malloc (a * b * c);
184 }
185
186 /*
187  * This function expands images from ARGB8 format to ARGB16.  To preserve
188  * precision, it needs to know the original source format.  For example, if the
189  * source was PIXMAN_x1r5g5b5 and the red component contained bits 12345, then
190  * the expanded value is 12345123.  To correctly expand this to 16 bits, it
191  * should be 1234512345123451 and not 1234512312345123.
192  */
193 void
194 pixman_expand (uint64_t *           dst,
195                const uint32_t *     src,
196                pixman_format_code_t format,
197                int                  width)
198 {
199     /*
200      * Determine the sizes of each component and the masks and shifts
201      * required to extract them from the source pixel.
202      */
203     const int a_size = PIXMAN_FORMAT_A (format),
204               r_size = PIXMAN_FORMAT_R (format),
205               g_size = PIXMAN_FORMAT_G (format),
206               b_size = PIXMAN_FORMAT_B (format);
207     const int a_shift = 32 - a_size,
208               r_shift = 24 - r_size,
209               g_shift = 16 - g_size,
210               b_shift =  8 - b_size;
211     const uint8_t a_mask = ~(~0 << a_size),
212                   r_mask = ~(~0 << r_size),
213                   g_mask = ~(~0 << g_size),
214                   b_mask = ~(~0 << b_size);
215     int i;
216
217     /* Start at the end so that we can do the expansion in place
218      * when src == dst
219      */
220     for (i = width - 1; i >= 0; i--)
221     {
222         const uint32_t pixel = src[i];
223         uint8_t a, r, g, b;
224         uint64_t a16, r16, g16, b16;
225
226         if (a_size)
227         {
228             a = (pixel >> a_shift) & a_mask;
229             a16 = unorm_to_unorm (a, a_size, 16);
230         }
231         else
232         {
233             a16 = 0xffff;
234         }
235
236         if (r_size)
237         {
238             r = (pixel >> r_shift) & r_mask;
239             g = (pixel >> g_shift) & g_mask;
240             b = (pixel >> b_shift) & b_mask;
241             r16 = unorm_to_unorm (r, r_size, 16);
242             g16 = unorm_to_unorm (g, g_size, 16);
243             b16 = unorm_to_unorm (b, b_size, 16);
244         }
245         else
246         {
247             r16 = g16 = b16 = 0;
248         }
249         
250         dst[i] = a16 << 48 | r16 << 32 | g16 << 16 | b16;
251     }
252 }
253
254 /*
255  * Contracting is easier than expanding.  We just need to truncate the
256  * components.
257  */
258 void
259 pixman_contract (uint32_t *      dst,
260                  const uint64_t *src,
261                  int             width)
262 {
263     int i;
264
265     /* Start at the beginning so that we can do the contraction in
266      * place when src == dst
267      */
268     for (i = 0; i < width; i++)
269     {
270         const uint8_t a = src[i] >> 56,
271                       r = src[i] >> 40,
272                       g = src[i] >> 24,
273                       b = src[i] >> 8;
274
275         dst[i] = a << 24 | r << 16 | g << 8 | b;
276     }
277 }
278
279 uint32_t *
280 _pixman_iter_get_scanline_noop (pixman_iter_t *iter, const uint32_t *mask)
281 {
282     return iter->buffer;
283 }
284
285 #define N_TMP_BOXES (16)
286
287 pixman_bool_t
288 pixman_region16_copy_from_region32 (pixman_region16_t *dst,
289                                     pixman_region32_t *src)
290 {
291     int n_boxes, i;
292     pixman_box32_t *boxes32;
293     pixman_box16_t *boxes16;
294     pixman_bool_t retval;
295
296     boxes32 = pixman_region32_rectangles (src, &n_boxes);
297
298     boxes16 = pixman_malloc_ab (n_boxes, sizeof (pixman_box16_t));
299
300     if (!boxes16)
301         return FALSE;
302
303     for (i = 0; i < n_boxes; ++i)
304     {
305         boxes16[i].x1 = boxes32[i].x1;
306         boxes16[i].y1 = boxes32[i].y1;
307         boxes16[i].x2 = boxes32[i].x2;
308         boxes16[i].y2 = boxes32[i].y2;
309     }
310
311     pixman_region_fini (dst);
312     retval = pixman_region_init_rects (dst, boxes16, n_boxes);
313     free (boxes16);
314     return retval;
315 }
316
317 pixman_bool_t
318 pixman_region32_copy_from_region16 (pixman_region32_t *dst,
319                                     pixman_region16_t *src)
320 {
321     int n_boxes, i;
322     pixman_box16_t *boxes16;
323     pixman_box32_t *boxes32;
324     pixman_box32_t tmp_boxes[N_TMP_BOXES];
325     pixman_bool_t retval;
326
327     boxes16 = pixman_region_rectangles (src, &n_boxes);
328
329     if (n_boxes > N_TMP_BOXES)
330         boxes32 = pixman_malloc_ab (n_boxes, sizeof (pixman_box32_t));
331     else
332         boxes32 = tmp_boxes;
333
334     if (!boxes32)
335         return FALSE;
336
337     for (i = 0; i < n_boxes; ++i)
338     {
339         boxes32[i].x1 = boxes16[i].x1;
340         boxes32[i].y1 = boxes16[i].y1;
341         boxes32[i].x2 = boxes16[i].x2;
342         boxes32[i].y2 = boxes16[i].y2;
343     }
344
345     pixman_region32_fini (dst);
346     retval = pixman_region32_init_rects (dst, boxes32, n_boxes);
347
348     if (boxes32 != tmp_boxes)
349         free (boxes32);
350
351     return retval;
352 }
353
354 #ifdef DEBUG
355
356 void
357 _pixman_log_error (const char *function, const char *message)
358 {
359     static int n_messages = 0;
360
361     if (n_messages < 10)
362     {
363         fprintf (stderr,
364                  "*** BUG ***\n"
365                  "In %s: %s\n"
366                  "Set a breakpoint on '_pixman_log_error' to debug\n\n",
367                  function, message);
368
369         n_messages++;
370     }
371 }
372
373 #endif