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 0 : pixman_sample_ceil_y (pixman_fixed_t y, int n)
39 : {
40 0 : pixman_fixed_t f = pixman_fixed_frac (y);
41 0 : pixman_fixed_t i = pixman_fixed_floor (y);
42 :
43 0 : f = DIV (f - Y_FRAC_FIRST (n) + (STEP_Y_SMALL (n) - pixman_fixed_e), STEP_Y_SMALL (n)) * STEP_Y_SMALL (n) +
44 0 : Y_FRAC_FIRST (n);
45 :
46 0 : if (f > Y_FRAC_LAST (n))
47 : {
48 0 : if (pixman_fixed_to_int (i) == 0x7fff)
49 : {
50 0 : f = 0xffff; /* saturate */
51 : }
52 : else
53 : {
54 0 : f = Y_FRAC_FIRST (n);
55 0 : i += pixman_fixed_1;
56 : }
57 : }
58 0 : 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 0 : pixman_sample_floor_y (pixman_fixed_t y,
67 : int n)
68 : {
69 0 : pixman_fixed_t f = pixman_fixed_frac (y);
70 0 : pixman_fixed_t i = pixman_fixed_floor (y);
71 :
72 0 : f = DIV (f - pixman_fixed_e - Y_FRAC_FIRST (n), STEP_Y_SMALL (n)) * STEP_Y_SMALL (n) +
73 0 : Y_FRAC_FIRST (n);
74 :
75 0 : if (f < Y_FRAC_FIRST (n))
76 : {
77 0 : if (pixman_fixed_to_int (i) == 0x8000)
78 : {
79 0 : f = 0; /* saturate */
80 : }
81 : else
82 : {
83 0 : f = Y_FRAC_LAST (n);
84 0 : i -= pixman_fixed_1;
85 : }
86 : }
87 0 : return (i | f);
88 : }
89 :
90 : /*
91 : * Step an edge by any amount (including negative values)
92 : */
93 : PIXMAN_EXPORT void
94 0 : pixman_edge_step (pixman_edge_t *e,
95 : int n)
96 : {
97 : pixman_fixed_48_16_t ne;
98 :
99 0 : e->x += n * e->stepx;
100 :
101 0 : ne = e->e + n * (pixman_fixed_48_16_t) e->dx;
102 :
103 0 : if (n >= 0)
104 : {
105 0 : if (ne > 0)
106 : {
107 0 : int nx = (ne + e->dy - 1) / e->dy;
108 0 : e->e = ne - nx * (pixman_fixed_48_16_t) e->dy;
109 0 : e->x += nx * e->signdx;
110 : }
111 : }
112 : else
113 : {
114 0 : if (ne <= -e->dy)
115 : {
116 0 : int nx = (-ne) / e->dy;
117 0 : e->e = ne + nx * (pixman_fixed_48_16_t) e->dy;
118 0 : e->x -= nx * e->signdx;
119 : }
120 : }
121 0 : }
122 :
123 : /*
124 : * A private routine to initialize the multi-step
125 : * elements of an edge structure
126 : */
127 : static void
128 0 : _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 0 : ne = n * (pixman_fixed_48_16_t) e->dx;
137 0 : stepx = n * e->stepx;
138 :
139 0 : if (ne > 0)
140 : {
141 0 : int nx = ne / e->dy;
142 0 : ne -= nx * e->dy;
143 0 : stepx += nx * e->signdx;
144 : }
145 :
146 0 : *dx_p = ne;
147 0 : *stepx_p = stepx;
148 0 : }
149 :
150 : /*
151 : * Initialize one edge structure given the line endpoints and a
152 : * starting y value
153 : */
154 : PIXMAN_EXPORT void
155 0 : 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 0 : e->x = x_top;
166 0 : e->e = 0;
167 0 : dx = x_bot - x_top;
168 0 : dy = y_bot - y_top;
169 0 : e->dy = dy;
170 0 : e->dx = 0;
171 :
172 0 : if (dy)
173 : {
174 0 : if (dx >= 0)
175 : {
176 0 : e->signdx = 1;
177 0 : e->stepx = dx / dy;
178 0 : e->dx = dx % dy;
179 0 : e->e = -dy;
180 : }
181 : else
182 : {
183 0 : e->signdx = -1;
184 0 : e->stepx = -(-dx / dy);
185 0 : e->dx = -dx % dy;
186 0 : e->e = 0;
187 : }
188 :
189 0 : _pixman_edge_multi_init (e, STEP_Y_SMALL (n),
190 : &e->stepx_small, &e->dx_small);
191 :
192 0 : _pixman_edge_multi_init (e, STEP_Y_BIG (n),
193 : &e->stepx_big, &e->dx_big);
194 : }
195 0 : pixman_edge_step (e, y_start - y_top);
196 0 : }
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 0 : 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 0 : pixman_fixed_t x_off_fixed = pixman_int_to_fixed (x_off);
211 0 : pixman_fixed_t y_off_fixed = pixman_int_to_fixed (y_off);
212 : const pixman_point_fixed_t *top, *bot;
213 :
214 0 : if (line->p1.y <= line->p2.y)
215 : {
216 0 : top = &line->p1;
217 0 : bot = &line->p2;
218 : }
219 : else
220 : {
221 0 : top = &line->p2;
222 0 : bot = &line->p1;
223 : }
224 :
225 0 : pixman_edge_init (e, n, y,
226 0 : top->x + x_off_fixed,
227 0 : top->y + y_off_fixed,
228 0 : bot->x + x_off_fixed,
229 0 : bot->y + y_off_fixed);
230 0 : }
231 :
232 : PIXMAN_EXPORT void
233 0 : 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 0 : _pixman_image_validate (image);
248 :
249 0 : height = image->bits.height;
250 0 : bpp = PIXMAN_FORMAT_BPP (image->bits.format);
251 :
252 0 : x_off_fixed = pixman_int_to_fixed (x_off);
253 0 : y_off_fixed = pixman_int_to_fixed (y_off);
254 :
255 0 : while (ntrap--)
256 : {
257 0 : t = traps->top.y + y_off_fixed;
258 0 : if (t < 0)
259 0 : t = 0;
260 0 : t = pixman_sample_ceil_y (t, bpp);
261 :
262 0 : b = traps->bot.y + y_off_fixed;
263 0 : if (pixman_fixed_to_int (b) >= height)
264 0 : b = pixman_int_to_fixed (height) - 1;
265 0 : b = pixman_sample_floor_y (b, bpp);
266 :
267 0 : if (b >= t)
268 : {
269 : /* initialize edge walkers */
270 0 : pixman_edge_init (&l, bpp, t,
271 0 : traps->top.l + x_off_fixed,
272 0 : traps->top.y + y_off_fixed,
273 0 : traps->bot.l + x_off_fixed,
274 0 : traps->bot.y + y_off_fixed);
275 :
276 0 : pixman_edge_init (&r, bpp, t,
277 0 : traps->top.r + x_off_fixed,
278 0 : traps->top.y + y_off_fixed,
279 0 : traps->bot.r + x_off_fixed,
280 0 : traps->bot.y + y_off_fixed);
281 :
282 0 : pixman_rasterize_edges (image, &l, &r, t, b);
283 : }
284 :
285 0 : traps++;
286 : }
287 0 : }
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 0 : 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 0 : for (i = 0; i < ntraps; ++i)
331 : {
332 0 : const pixman_trapezoid_t *trap = &(traps[i]);
333 :
334 0 : if (!pixman_trapezoid_valid (trap))
335 0 : continue;
336 :
337 0 : pixman_rasterize_trapezoid (image, trap, x_off, y_off);
338 : }
339 :
340 : #if 0
341 : dump_image (image, "after");
342 : #endif
343 0 : }
344 :
345 : PIXMAN_EXPORT void
346 0 : 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 0 : return_if_fail (image->type == BITS);
359 :
360 0 : _pixman_image_validate (image);
361 :
362 0 : if (!pixman_trapezoid_valid (trap))
363 0 : return;
364 :
365 0 : height = image->bits.height;
366 0 : bpp = PIXMAN_FORMAT_BPP (image->bits.format);
367 :
368 0 : y_off_fixed = pixman_int_to_fixed (y_off);
369 :
370 0 : t = trap->top + y_off_fixed;
371 0 : if (t < 0)
372 0 : t = 0;
373 0 : t = pixman_sample_ceil_y (t, bpp);
374 :
375 0 : b = trap->bottom + y_off_fixed;
376 0 : if (pixman_fixed_to_int (b) >= height)
377 0 : b = pixman_int_to_fixed (height) - 1;
378 0 : b = pixman_sample_floor_y (b, bpp);
379 :
380 0 : if (b >= t)
381 : {
382 : /* initialize edge walkers */
383 0 : pixman_line_fixed_edge_init (&l, bpp, t, &trap->left, x_off, y_off);
384 0 : pixman_line_fixed_edge_init (&r, bpp, t, &trap->right, x_off, y_off);
385 :
386 0 : 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 0 : 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 0 : if (n_traps <= 0)
418 0 : return;
419 :
420 0 : _pixman_image_validate (src);
421 0 : _pixman_image_validate (dst);
422 :
423 0 : if (op == PIXMAN_OP_ADD &&
424 0 : (src->common.flags & FAST_PATH_IS_OPAQUE) &&
425 0 : (mask_format == dst->common.extended_format_code) &&
426 0 : !(dst->common.have_clip_region))
427 : {
428 0 : for (i = 0; i < n_traps; ++i)
429 : {
430 0 : const pixman_trapezoid_t *trap = &(traps[i]);
431 :
432 0 : if (!pixman_trapezoid_valid (trap))
433 0 : continue;
434 :
435 0 : 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 0 : box.x1 = INT32_MAX;
444 0 : box.y1 = INT32_MAX;
445 0 : box.x2 = INT32_MIN;
446 0 : box.y2 = INT32_MIN;
447 :
448 0 : for (i = 0; i < n_traps; ++i)
449 : {
450 0 : const pixman_trapezoid_t *trap = &(traps[i]);
451 : int y1, y2;
452 :
453 0 : if (!pixman_trapezoid_valid (trap))
454 0 : continue;
455 :
456 0 : y1 = pixman_fixed_to_int (trap->top);
457 0 : if (y1 < box.y1)
458 0 : box.y1 = y1;
459 :
460 0 : y2 = pixman_fixed_to_int (pixman_fixed_ceil (trap->bottom));
461 0 : if (y2 > box.y2)
462 0 : 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 0 : EXTEND(trap->left.p1.x);
476 0 : EXTEND(trap->left.p2.x);
477 0 : EXTEND(trap->right.p1.x);
478 0 : EXTEND(trap->right.p2.x);
479 : }
480 :
481 0 : if (box.x1 >= box.x2 || box.y1 >= box.y2)
482 0 : return;
483 :
484 0 : tmp = pixman_image_create_bits (
485 0 : mask_format, box.x2 - box.x1, box.y2 - box.y1, NULL, -1);
486 :
487 0 : for (i = 0; i < n_traps; ++i)
488 : {
489 0 : const pixman_trapezoid_t *trap = &(traps[i]);
490 :
491 0 : if (!pixman_trapezoid_valid (trap))
492 0 : continue;
493 :
494 0 : pixman_rasterize_trapezoid (tmp, trap, - box.x1, - box.y1);
495 : }
496 :
497 0 : pixman_image_composite (op, src, tmp, dst,
498 0 : x_src + box.x1, y_src + box.y1,
499 : 0, 0,
500 0 : x_dst + box.x1, y_dst + box.y1,
501 0 : box.x2 - box.x1, box.y2 - box.y1);
502 :
503 0 : pixman_image_unref (tmp);
504 : }
505 : }
506 :
507 : static int
508 0 : greater_y (const pixman_point_fixed_t *a, const pixman_point_fixed_t *b)
509 : {
510 0 : if (a->y == b->y)
511 0 : return a->x > b->x;
512 0 : 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 0 : 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 0 : ad.x = a->x - ref->x;
527 0 : ad.y = a->y - ref->y;
528 0 : bd.x = b->x - ref->x;
529 0 : bd.y = b->y - ref->y;
530 :
531 0 : return ((pixman_fixed_32_32_t) bd.y * ad.x -
532 0 : (pixman_fixed_32_32_t) ad.y * bd.x) < 0;
533 : }
534 :
535 : static void
536 0 : 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 0 : top = &tri->p1;
541 0 : left = &tri->p2;
542 0 : right = &tri->p3;
543 :
544 0 : if (greater_y (top, left))
545 : {
546 0 : tmp = left;
547 0 : left = top;
548 0 : top = tmp;
549 : }
550 :
551 0 : if (greater_y (top, right))
552 : {
553 0 : tmp = right;
554 0 : right = top;
555 0 : top = tmp;
556 : }
557 :
558 0 : if (clockwise (top, right, left))
559 : {
560 0 : tmp = right;
561 0 : right = left;
562 0 : left = tmp;
563 : }
564 :
565 : /*
566 : * Two cases:
567 : *
568 : * + +
569 : * / \ / \
570 : * / \ / \
571 : * / + + \
572 : * / -- -- \
573 : * / -- -- \
574 : * / --- --- \
575 : * +-- --+
576 : */
577 :
578 0 : traps->top = top->y;
579 0 : traps->left.p1 = *top;
580 0 : traps->left.p2 = *left;
581 0 : traps->right.p1 = *top;
582 0 : traps->right.p2 = *right;
583 :
584 0 : if (right->y < left->y)
585 0 : traps->bottom = right->y;
586 : else
587 0 : traps->bottom = left->y;
588 :
589 0 : traps++;
590 :
591 0 : *traps = *(traps - 1);
592 :
593 0 : if (right->y < left->y)
594 : {
595 0 : traps->top = right->y;
596 0 : traps->bottom = left->y;
597 0 : traps->right.p1 = *right;
598 0 : traps->right.p2 = *left;
599 : }
600 : else
601 : {
602 0 : traps->top = left->y;
603 0 : traps->bottom = right->y;
604 0 : traps->left.p1 = *left;
605 0 : traps->left.p2 = *right;
606 : }
607 0 : }
608 :
609 : static pixman_trapezoid_t *
610 0 : convert_triangles (int n_tris, const pixman_triangle_t *tris)
611 : {
612 : pixman_trapezoid_t *traps;
613 : int i;
614 :
615 0 : if (n_tris <= 0)
616 0 : return NULL;
617 :
618 0 : traps = pixman_malloc_ab (n_tris, 2 * sizeof (pixman_trapezoid_t));
619 0 : if (!traps)
620 0 : return NULL;
621 :
622 0 : for (i = 0; i < n_tris; ++i)
623 0 : triangle_to_trapezoids (&(tris[i]), traps + 2 * i);
624 :
625 0 : return traps;
626 : }
627 :
628 : PIXMAN_EXPORT void
629 0 : 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 0 : if ((traps = convert_triangles (n_tris, tris)))
643 : {
644 0 : pixman_composite_trapezoids (op, src, dst, mask_format,
645 : x_src, y_src, x_dst, y_dst,
646 : n_tris * 2, traps);
647 :
648 0 : free (traps);
649 : }
650 0 : }
651 :
652 : PIXMAN_EXPORT void
653 0 : 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 0 : if ((traps = convert_triangles (n_tris, tris)))
662 : {
663 0 : pixman_add_trapezoids (image, x_off, y_off,
664 : n_tris * 2, traps);
665 :
666 0 : free (traps);
667 : }
668 0 : }
|