mmx: fix formats in commented code
[profile/ivi/pixman.git] / pixman / pixman-trap.c
1 /*
2  * Copyright © 2002 Keith Packard, member of The XFree86 Project, Inc.
3  * Copyright © 2004 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 Keith Packard not be used in
10  * advertising or publicity pertaining to distribution of the software without
11  * specific, written prior permission.  Keith Packard makes no
12  * representations about the suitability of this software for any purpose.  It
13  * is provided "as is" without express or implied warranty.
14  *
15  * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
17  * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
18  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
19  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
20  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
21  * PERFORMANCE OF THIS SOFTWARE.
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include "pixman-private.h"
31
32 /*
33  * Compute the smallest value greater than or equal to y which is on a
34  * grid row.
35  */
36
37 PIXMAN_EXPORT pixman_fixed_t
38 pixman_sample_ceil_y (pixman_fixed_t y, int n)
39 {
40     pixman_fixed_t f = pixman_fixed_frac (y);
41     pixman_fixed_t i = pixman_fixed_floor (y);
42
43     f = DIV (f - Y_FRAC_FIRST (n) + (STEP_Y_SMALL (n) - pixman_fixed_e), STEP_Y_SMALL (n)) * STEP_Y_SMALL (n) +
44         Y_FRAC_FIRST (n);
45     
46     if (f > Y_FRAC_LAST (n))
47     {
48         if (pixman_fixed_to_int (i) == 0x7fff)
49         {
50             f = 0xffff; /* saturate */
51         }
52         else
53         {
54             f = Y_FRAC_FIRST (n);
55             i += pixman_fixed_1;
56         }
57     }
58     return (i | f);
59 }
60
61 /*
62  * Compute the largest value strictly less than y which is on a
63  * grid row.
64  */
65 PIXMAN_EXPORT pixman_fixed_t
66 pixman_sample_floor_y (pixman_fixed_t y,
67                        int            n)
68 {
69     pixman_fixed_t f = pixman_fixed_frac (y);
70     pixman_fixed_t i = pixman_fixed_floor (y);
71
72     f = DIV (f - pixman_fixed_e - Y_FRAC_FIRST (n), STEP_Y_SMALL (n)) * STEP_Y_SMALL (n) +
73         Y_FRAC_FIRST (n);
74
75     if (f < Y_FRAC_FIRST (n))
76     {
77         if (pixman_fixed_to_int (i) == 0x8000)
78         {
79             f = 0; /* saturate */
80         }
81         else
82         {
83             f = Y_FRAC_LAST (n);
84             i -= pixman_fixed_1;
85         }
86     }
87     return (i | f);
88 }
89
90 /*
91  * Step an edge by any amount (including negative values)
92  */
93 PIXMAN_EXPORT void
94 pixman_edge_step (pixman_edge_t *e,
95                   int            n)
96 {
97     pixman_fixed_48_16_t ne;
98
99     e->x += n * e->stepx;
100
101     ne = e->e + n * (pixman_fixed_48_16_t) e->dx;
102
103     if (n >= 0)
104     {
105         if (ne > 0)
106         {
107             int nx = (ne + e->dy - 1) / e->dy;
108             e->e = ne - nx * (pixman_fixed_48_16_t) e->dy;
109             e->x += nx * e->signdx;
110         }
111     }
112     else
113     {
114         if (ne <= -e->dy)
115         {
116             int nx = (-ne) / e->dy;
117             e->e = ne + nx * (pixman_fixed_48_16_t) e->dy;
118             e->x -= nx * e->signdx;
119         }
120     }
121 }
122
123 /*
124  * A private routine to initialize the multi-step
125  * elements of an edge structure
126  */
127 static void
128 _pixman_edge_multi_init (pixman_edge_t * e,
129                          int             n,
130                          pixman_fixed_t *stepx_p,
131                          pixman_fixed_t *dx_p)
132 {
133     pixman_fixed_t stepx;
134     pixman_fixed_48_16_t ne;
135
136     ne = n * (pixman_fixed_48_16_t) e->dx;
137     stepx = n * e->stepx;
138
139     if (ne > 0)
140     {
141         int nx = ne / e->dy;
142         ne -= nx * e->dy;
143         stepx += nx * e->signdx;
144     }
145
146     *dx_p = ne;
147     *stepx_p = stepx;
148 }
149
150 /*
151  * Initialize one edge structure given the line endpoints and a
152  * starting y value
153  */
154 PIXMAN_EXPORT void
155 pixman_edge_init (pixman_edge_t *e,
156                   int            n,
157                   pixman_fixed_t y_start,
158                   pixman_fixed_t x_top,
159                   pixman_fixed_t y_top,
160                   pixman_fixed_t x_bot,
161                   pixman_fixed_t y_bot)
162 {
163     pixman_fixed_t dx, dy;
164
165     e->x = x_top;
166     e->e = 0;
167     dx = x_bot - x_top;
168     dy = y_bot - y_top;
169     e->dy = dy;
170     e->dx = 0;
171
172     if (dy)
173     {
174         if (dx >= 0)
175         {
176             e->signdx = 1;
177             e->stepx = dx / dy;
178             e->dx = dx % dy;
179             e->e = -dy;
180         }
181         else
182         {
183             e->signdx = -1;
184             e->stepx = -(-dx / dy);
185             e->dx = -dx % dy;
186             e->e = 0;
187         }
188
189         _pixman_edge_multi_init (e, STEP_Y_SMALL (n),
190                                  &e->stepx_small, &e->dx_small);
191
192         _pixman_edge_multi_init (e, STEP_Y_BIG (n),
193                                  &e->stepx_big, &e->dx_big);
194     }
195     pixman_edge_step (e, y_start - y_top);
196 }
197
198 /*
199  * Initialize one edge structure given a line, starting y value
200  * and a pixel offset for the line
201  */
202 PIXMAN_EXPORT void
203 pixman_line_fixed_edge_init (pixman_edge_t *            e,
204                              int                        n,
205                              pixman_fixed_t             y,
206                              const pixman_line_fixed_t *line,
207                              int                        x_off,
208                              int                        y_off)
209 {
210     pixman_fixed_t x_off_fixed = pixman_int_to_fixed (x_off);
211     pixman_fixed_t y_off_fixed = pixman_int_to_fixed (y_off);
212     const pixman_point_fixed_t *top, *bot;
213
214     if (line->p1.y <= line->p2.y)
215     {
216         top = &line->p1;
217         bot = &line->p2;
218     }
219     else
220     {
221         top = &line->p2;
222         bot = &line->p1;
223     }
224     
225     pixman_edge_init (e, n, y,
226                       top->x + x_off_fixed,
227                       top->y + y_off_fixed,
228                       bot->x + x_off_fixed,
229                       bot->y + y_off_fixed);
230 }
231
232 PIXMAN_EXPORT void
233 pixman_add_traps (pixman_image_t * image,
234                   int16_t          x_off,
235                   int16_t          y_off,
236                   int              ntrap,
237                   pixman_trap_t *  traps)
238 {
239     int bpp;
240     int height;
241
242     pixman_fixed_t x_off_fixed;
243     pixman_fixed_t y_off_fixed;
244     pixman_edge_t l, r;
245     pixman_fixed_t t, b;
246
247     _pixman_image_validate (image);
248     
249     height = image->bits.height;
250     bpp = PIXMAN_FORMAT_BPP (image->bits.format);
251
252     x_off_fixed = pixman_int_to_fixed (x_off);
253     y_off_fixed = pixman_int_to_fixed (y_off);
254
255     while (ntrap--)
256     {
257         t = traps->top.y + y_off_fixed;
258         if (t < 0)
259             t = 0;
260         t = pixman_sample_ceil_y (t, bpp);
261
262         b = traps->bot.y + y_off_fixed;
263         if (pixman_fixed_to_int (b) >= height)
264             b = pixman_int_to_fixed (height) - 1;
265         b = pixman_sample_floor_y (b, bpp);
266
267         if (b >= t)
268         {
269             /* initialize edge walkers */
270             pixman_edge_init (&l, bpp, t,
271                               traps->top.l + x_off_fixed,
272                               traps->top.y + y_off_fixed,
273                               traps->bot.l + x_off_fixed,
274                               traps->bot.y + y_off_fixed);
275
276             pixman_edge_init (&r, bpp, t,
277                               traps->top.r + x_off_fixed,
278                               traps->top.y + y_off_fixed,
279                               traps->bot.r + x_off_fixed,
280                               traps->bot.y + y_off_fixed);
281
282             pixman_rasterize_edges (image, &l, &r, t, b);
283         }
284
285         traps++;
286     }
287 }
288
289 #if 0
290 static void
291 dump_image (pixman_image_t *image,
292             const char *    title)
293 {
294     int i, j;
295
296     if (!image->type == BITS)
297         printf ("%s is not a regular image\n", title);
298
299     if (!image->bits.format == PIXMAN_a8)
300         printf ("%s is not an alpha mask\n", title);
301
302     printf ("\n\n\n%s: \n", title);
303
304     for (i = 0; i < image->bits.height; ++i)
305     {
306         uint8_t *line =
307             (uint8_t *)&(image->bits.bits[i * image->bits.rowstride]);
308
309         for (j = 0; j < image->bits.width; ++j)
310             printf ("%c", line[j] ? '#' : ' ');
311
312         printf ("\n");
313     }
314 }
315 #endif
316
317 PIXMAN_EXPORT void
318 pixman_add_trapezoids (pixman_image_t *          image,
319                        int16_t                   x_off,
320                        int                       y_off,
321                        int                       ntraps,
322                        const pixman_trapezoid_t *traps)
323 {
324     int i;
325
326 #if 0
327     dump_image (image, "before");
328 #endif
329
330     for (i = 0; i < ntraps; ++i)
331     {
332         const pixman_trapezoid_t *trap = &(traps[i]);
333
334         if (!pixman_trapezoid_valid (trap))
335             continue;
336
337         pixman_rasterize_trapezoid (image, trap, x_off, y_off);
338     }
339
340 #if 0
341     dump_image (image, "after");
342 #endif
343 }
344
345 PIXMAN_EXPORT void
346 pixman_rasterize_trapezoid (pixman_image_t *          image,
347                             const pixman_trapezoid_t *trap,
348                             int                       x_off,
349                             int                       y_off)
350 {
351     int bpp;
352     int height;
353
354     pixman_fixed_t y_off_fixed;
355     pixman_edge_t l, r;
356     pixman_fixed_t t, b;
357
358     return_if_fail (image->type == BITS);
359
360     _pixman_image_validate (image);
361     
362     if (!pixman_trapezoid_valid (trap))
363         return;
364
365     height = image->bits.height;
366     bpp = PIXMAN_FORMAT_BPP (image->bits.format);
367
368     y_off_fixed = pixman_int_to_fixed (y_off);
369
370     t = trap->top + y_off_fixed;
371     if (t < 0)
372         t = 0;
373     t = pixman_sample_ceil_y (t, bpp);
374
375     b = trap->bottom + y_off_fixed;
376     if (pixman_fixed_to_int (b) >= height)
377         b = pixman_int_to_fixed (height) - 1;
378     b = pixman_sample_floor_y (b, bpp);
379     
380     if (b >= t)
381     {
382         /* initialize edge walkers */
383         pixman_line_fixed_edge_init (&l, bpp, t, &trap->left, x_off, y_off);
384         pixman_line_fixed_edge_init (&r, bpp, t, &trap->right, x_off, y_off);
385
386         pixman_rasterize_edges (image, &l, &r, t, b);
387     }
388 }
389
390 /*
391  * pixman_composite_trapezoids()
392  *
393  * All the trapezoids are conceptually rendered to an infinitely big image.
394  * The (0, 0) coordinates of this image are then aligned with the (x, y)
395  * coordinates of the source image, and then both images are aligned with
396  * the (x, y) coordinates of the destination. Then, in principle, compositing
397  * of these three images takes place across the entire destination.
398  *
399  * FIXME: However, there is currently a bug, where we restrict this compositing
400  * to the bounding box of the trapezoids. This is incorrect for operators such
401  * as SRC and IN where blank source pixels do have an effect on the destination.
402  */
403 PIXMAN_EXPORT void
404 pixman_composite_trapezoids (pixman_op_t                op,
405                              pixman_image_t *           src,
406                              pixman_image_t *           dst,
407                              pixman_format_code_t       mask_format,
408                              int                        x_src,
409                              int                        y_src,
410                              int                        x_dst,
411                              int                        y_dst,
412                              int                        n_traps,
413                              const pixman_trapezoid_t * traps)
414 {
415     int i;
416
417     if (n_traps <= 0)
418         return;
419
420     _pixman_image_validate (src);
421     _pixman_image_validate (dst);
422
423     if (op == PIXMAN_OP_ADD &&
424         (src->common.flags & FAST_PATH_IS_OPAQUE)               &&
425         (mask_format == dst->common.extended_format_code)       &&
426         !(dst->common.have_clip_region))
427     {
428         for (i = 0; i < n_traps; ++i)
429         {
430             const pixman_trapezoid_t *trap = &(traps[i]);
431             
432             if (!pixman_trapezoid_valid (trap))
433                 continue;
434             
435             pixman_rasterize_trapezoid (dst, trap, x_dst, y_dst);
436         }
437     }
438     else
439     {
440         pixman_image_t *tmp;
441         pixman_box32_t box;
442         
443         box.x1 = INT32_MAX;
444         box.y1 = INT32_MAX;
445         box.x2 = INT32_MIN;
446         box.y2 = INT32_MIN;
447         
448         for (i = 0; i < n_traps; ++i)
449         {
450             const pixman_trapezoid_t *trap = &(traps[i]);
451             int y1, y2;
452             
453             if (!pixman_trapezoid_valid (trap))
454                 continue;
455             
456             y1 = pixman_fixed_to_int (trap->top);
457             if (y1 < box.y1)
458                 box.y1 = y1;
459             
460             y2 = pixman_fixed_to_int (pixman_fixed_ceil (trap->bottom));
461             if (y2 > box.y2)
462                 box.y2 = y2;
463             
464 #define EXTEND_MIN(x)                                                   \
465             if (pixman_fixed_to_int ((x)) < box.x1)                     \
466                 box.x1 = pixman_fixed_to_int ((x));
467 #define EXTEND_MAX(x)                                                   \
468             if (pixman_fixed_to_int (pixman_fixed_ceil ((x))) > box.x2) \
469                 box.x2 = pixman_fixed_to_int (pixman_fixed_ceil ((x)));
470             
471 #define EXTEND(x)                                                       \
472             EXTEND_MIN(x);                                              \
473             EXTEND_MAX(x);
474             
475             EXTEND(trap->left.p1.x);
476             EXTEND(trap->left.p2.x);
477             EXTEND(trap->right.p1.x);
478             EXTEND(trap->right.p2.x);
479         }
480         
481         if (box.x1 >= box.x2 || box.y1 >= box.y2)
482             return;
483         
484         tmp = pixman_image_create_bits (
485             mask_format, box.x2 - box.x1, box.y2 - box.y1, NULL, -1);
486         
487         for (i = 0; i < n_traps; ++i)
488         {
489             const pixman_trapezoid_t *trap = &(traps[i]);
490             
491             if (!pixman_trapezoid_valid (trap))
492                 continue;
493             
494             pixman_rasterize_trapezoid (tmp, trap, - box.x1, - box.y1);
495         }
496         
497         pixman_image_composite (op, src, tmp, dst,
498                                 x_src + box.x1, y_src + box.y1,
499                                 0, 0,
500                                 x_dst + box.x1, y_dst + box.y1,
501                                 box.x2 - box.x1, box.y2 - box.y1);
502         
503         pixman_image_unref (tmp);
504     }
505 }
506
507 static int
508 greater_y (const pixman_point_fixed_t *a, const pixman_point_fixed_t *b)
509 {
510     if (a->y == b->y)
511         return a->x > b->x;
512     return a->y > b->y;
513 }
514
515 /*
516  * Note that the definition of this function is a bit odd because
517  * of the X coordinate space (y increasing downwards).
518  */
519 static int
520 clockwise (const pixman_point_fixed_t *ref,
521            const pixman_point_fixed_t *a,
522            const pixman_point_fixed_t *b)
523 {
524     pixman_point_fixed_t        ad, bd;
525
526     ad.x = a->x - ref->x;
527     ad.y = a->y - ref->y;
528     bd.x = b->x - ref->x;
529     bd.y = b->y - ref->y;
530
531     return ((pixman_fixed_32_32_t) bd.y * ad.x -
532             (pixman_fixed_32_32_t) ad.y * bd.x) < 0;
533 }
534
535 static void
536 triangle_to_trapezoids (const pixman_triangle_t *tri, pixman_trapezoid_t *traps)
537 {
538     const pixman_point_fixed_t *top, *left, *right, *tmp;
539
540     top = &tri->p1;
541     left = &tri->p2;
542     right = &tri->p3;
543
544     if (greater_y (top, left))
545     {
546         tmp = left;
547         left = top;
548         top = tmp;
549     }
550
551     if (greater_y (top, right))
552     {
553         tmp = right;
554         right = top;
555         top = tmp;
556     }
557
558     if (clockwise (top, right, left))
559     {
560         tmp = right;
561         right = left;
562         left = tmp;
563     }
564     
565     /*
566      * Two cases:
567      *
568      *          +               +
569      *         / \             / \
570      *        /   \           /   \
571      *       /     +         +     \
572      *      /    --           --    \
573      *     /   --               --   \
574      *    / ---                   --- \
575      *   +--                         --+
576      */
577
578     traps->top = top->y;
579     traps->left.p1 = *top;
580     traps->left.p2 = *left;
581     traps->right.p1 = *top;
582     traps->right.p2 = *right;
583
584     if (right->y < left->y)
585         traps->bottom = right->y;
586     else
587         traps->bottom = left->y;
588
589     traps++;
590
591     *traps = *(traps - 1);
592     
593     if (right->y < left->y)
594     {
595         traps->top = right->y;
596         traps->bottom = left->y;
597         traps->right.p1 = *right;
598         traps->right.p2 = *left;
599     }
600     else
601     {
602         traps->top = left->y;
603         traps->bottom = right->y;
604         traps->left.p1 = *left;
605         traps->left.p2 = *right;
606     }
607 }
608
609 static pixman_trapezoid_t *
610 convert_triangles (int n_tris, const pixman_triangle_t *tris)
611 {
612     pixman_trapezoid_t *traps;
613     int i;
614
615     if (n_tris <= 0)
616         return NULL;
617     
618     traps = pixman_malloc_ab (n_tris, 2 * sizeof (pixman_trapezoid_t));
619     if (!traps)
620         return NULL;
621
622     for (i = 0; i < n_tris; ++i)
623         triangle_to_trapezoids (&(tris[i]), traps + 2 * i);
624
625     return traps;
626 }
627
628 PIXMAN_EXPORT void
629 pixman_composite_triangles (pixman_op_t                 op,
630                             pixman_image_t *            src,
631                             pixman_image_t *            dst,
632                             pixman_format_code_t        mask_format,
633                             int                         x_src,
634                             int                         y_src,
635                             int                         x_dst,
636                             int                         y_dst,
637                             int                         n_tris,
638                             const pixman_triangle_t *   tris)
639 {
640     pixman_trapezoid_t *traps;
641
642     if ((traps = convert_triangles (n_tris, tris)))
643     {
644         pixman_composite_trapezoids (op, src, dst, mask_format,
645                                      x_src, y_src, x_dst, y_dst,
646                                      n_tris * 2, traps);
647         
648         free (traps);
649     }
650 }
651
652 PIXMAN_EXPORT void
653 pixman_add_triangles (pixman_image_t          *image,
654                       int32_t                  x_off,
655                       int32_t                  y_off,
656                       int                      n_tris,
657                       const pixman_triangle_t *tris)
658 {
659     pixman_trapezoid_t *traps;
660
661     if ((traps = convert_triangles (n_tris, tris)))
662     {
663         pixman_add_trapezoids (image, x_off, y_off,
664                                n_tris * 2, traps);
665
666         free (traps);
667     }
668 }