/src/cairo/subprojects/pixman-0.44.2/pixman/pixman-trap.c
Line | Count | Source (jump to first uncovered line) |
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 <pixman-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 | 6 | { |
40 | 6 | pixman_fixed_t f = pixman_fixed_frac (y); |
41 | 6 | pixman_fixed_t i = pixman_fixed_floor (y); |
42 | | |
43 | 6 | f = DIV (f - Y_FRAC_FIRST (n) + (STEP_Y_SMALL (n) - pixman_fixed_e), STEP_Y_SMALL (n)) * STEP_Y_SMALL (n) + |
44 | 6 | Y_FRAC_FIRST (n); |
45 | | |
46 | 6 | if (f > Y_FRAC_LAST (n)) |
47 | 0 | { |
48 | 0 | if (pixman_fixed_to_int (i) == 0x7fff) |
49 | 0 | { |
50 | 0 | f = 0xffff; /* saturate */ |
51 | 0 | } |
52 | 0 | else |
53 | 0 | { |
54 | 0 | f = Y_FRAC_FIRST (n); |
55 | 0 | i += pixman_fixed_1; |
56 | 0 | } |
57 | 0 | } |
58 | 6 | return (i | f); |
59 | 6 | } |
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 | 6 | { |
69 | 6 | pixman_fixed_t f = pixman_fixed_frac (y); |
70 | 6 | pixman_fixed_t i = pixman_fixed_floor (y); |
71 | | |
72 | 6 | f = DIV (f - pixman_fixed_e - Y_FRAC_FIRST (n), STEP_Y_SMALL (n)) * STEP_Y_SMALL (n) + |
73 | 6 | Y_FRAC_FIRST (n); |
74 | | |
75 | 6 | if (f < Y_FRAC_FIRST (n)) |
76 | 0 | { |
77 | 0 | if (pixman_fixed_to_int (i) == 0xffff8000) |
78 | 0 | { |
79 | 0 | f = 0; /* saturate */ |
80 | 0 | } |
81 | 0 | else |
82 | 0 | { |
83 | 0 | f = Y_FRAC_LAST (n); |
84 | 0 | i -= pixman_fixed_1; |
85 | 0 | } |
86 | 0 | } |
87 | 6 | return (i | f); |
88 | 6 | } |
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 | 12 | { |
97 | 12 | pixman_fixed_48_16_t ne; |
98 | | |
99 | 12 | e->x += n * e->stepx; |
100 | | |
101 | 12 | ne = e->e + n * (pixman_fixed_48_16_t) e->dx; |
102 | | |
103 | 12 | if (n >= 0) |
104 | 12 | { |
105 | 12 | if (ne > 0) |
106 | 10 | { |
107 | 10 | int nx = (ne + e->dy - 1) / e->dy; |
108 | 10 | e->e = ne - nx * (pixman_fixed_48_16_t) e->dy; |
109 | 10 | e->x += nx * e->signdx; |
110 | 10 | } |
111 | 12 | } |
112 | 0 | else |
113 | 0 | { |
114 | 0 | if (ne <= -e->dy) |
115 | 0 | { |
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 | 0 | } |
120 | 0 | } |
121 | 12 | } |
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 | 24 | { |
133 | 24 | pixman_fixed_t stepx; |
134 | 24 | pixman_fixed_48_16_t ne; |
135 | | |
136 | 24 | ne = n * (pixman_fixed_48_16_t) e->dx; |
137 | 24 | stepx = n * e->stepx; |
138 | | |
139 | 24 | if (ne > 0) |
140 | 20 | { |
141 | 20 | int nx = ne / e->dy; |
142 | 20 | ne -= nx * (pixman_fixed_48_16_t)e->dy; |
143 | 20 | stepx += nx * e->signdx; |
144 | 20 | } |
145 | | |
146 | 24 | *dx_p = ne; |
147 | 24 | *stepx_p = stepx; |
148 | 24 | } |
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 | 12 | { |
163 | 12 | pixman_fixed_t dx, dy; |
164 | | |
165 | 12 | e->x = x_top; |
166 | 12 | e->e = 0; |
167 | 12 | dx = x_bot - x_top; |
168 | 12 | dy = y_bot - y_top; |
169 | 12 | e->dy = dy; |
170 | 12 | e->dx = 0; |
171 | | |
172 | 12 | if (dy) |
173 | 12 | { |
174 | 12 | if (dx >= 0) |
175 | 10 | { |
176 | 10 | e->signdx = 1; |
177 | 10 | e->stepx = dx / dy; |
178 | 10 | e->dx = dx % dy; |
179 | 10 | e->e = -dy; |
180 | 10 | } |
181 | 2 | else |
182 | 2 | { |
183 | 2 | e->signdx = -1; |
184 | 2 | e->stepx = -(-dx / dy); |
185 | 2 | e->dx = -dx % dy; |
186 | 2 | e->e = 0; |
187 | 2 | } |
188 | | |
189 | 12 | _pixman_edge_multi_init (e, STEP_Y_SMALL (n), |
190 | 12 | &e->stepx_small, &e->dx_small); |
191 | | |
192 | 12 | _pixman_edge_multi_init (e, STEP_Y_BIG (n), |
193 | 12 | &e->stepx_big, &e->dx_big); |
194 | 12 | } |
195 | 12 | pixman_edge_step (e, y_start - y_top); |
196 | 12 | } |
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 | 12 | { |
210 | 12 | pixman_fixed_t x_off_fixed = pixman_int_to_fixed (x_off); |
211 | 12 | pixman_fixed_t y_off_fixed = pixman_int_to_fixed (y_off); |
212 | 12 | const pixman_point_fixed_t *top, *bot; |
213 | | |
214 | 12 | if (line->p1.y <= line->p2.y) |
215 | 12 | { |
216 | 12 | top = &line->p1; |
217 | 12 | bot = &line->p2; |
218 | 12 | } |
219 | 0 | else |
220 | 0 | { |
221 | 0 | top = &line->p2; |
222 | 0 | bot = &line->p1; |
223 | 0 | } |
224 | | |
225 | 12 | pixman_edge_init (e, n, y, |
226 | 12 | top->x + x_off_fixed, |
227 | 12 | top->y + y_off_fixed, |
228 | 12 | bot->x + x_off_fixed, |
229 | 12 | bot->y + y_off_fixed); |
230 | 12 | } |
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 | | const pixman_trap_t *traps) |
238 | 0 | { |
239 | 0 | int bpp; |
240 | 0 | int height; |
241 | |
|
242 | 0 | pixman_fixed_t x_off_fixed; |
243 | 0 | pixman_fixed_t y_off_fixed; |
244 | 0 | pixman_edge_t l, r; |
245 | 0 | 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 | 0 | { |
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 | 0 | { |
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 | 0 | } |
284 | |
|
285 | 0 | traps++; |
286 | 0 | } |
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 | | 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 | 0 | { |
324 | 0 | int i; |
325 | |
|
326 | | #if 0 |
327 | | dump_image (image, "before"); |
328 | | #endif |
329 | |
|
330 | 0 | for (i = 0; i < ntraps; ++i) |
331 | 0 | { |
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 | 0 | } |
339 | |
|
340 | | #if 0 |
341 | | dump_image (image, "after"); |
342 | | #endif |
343 | 0 | } |
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 | 6 | { |
351 | 6 | int bpp; |
352 | 6 | int height; |
353 | | |
354 | 6 | pixman_fixed_t y_off_fixed; |
355 | 6 | pixman_edge_t l, r; |
356 | 6 | pixman_fixed_t t, b; |
357 | | |
358 | 6 | return_if_fail (image->type == BITS); |
359 | | |
360 | 6 | _pixman_image_validate (image); |
361 | | |
362 | 6 | if (!pixman_trapezoid_valid (trap)) |
363 | 0 | return; |
364 | | |
365 | 6 | height = image->bits.height; |
366 | 6 | bpp = PIXMAN_FORMAT_BPP (image->bits.format); |
367 | | |
368 | 6 | y_off_fixed = pixman_int_to_fixed (y_off); |
369 | | |
370 | 6 | t = trap->top + y_off_fixed; |
371 | 6 | if (t < 0) |
372 | 0 | t = 0; |
373 | 6 | t = pixman_sample_ceil_y (t, bpp); |
374 | | |
375 | 6 | b = trap->bottom + y_off_fixed; |
376 | 6 | if (pixman_fixed_to_int (b) >= height) |
377 | 0 | b = pixman_int_to_fixed (height) - 1; |
378 | 6 | b = pixman_sample_floor_y (b, bpp); |
379 | | |
380 | 6 | if (b >= t) |
381 | 6 | { |
382 | | /* initialize edge walkers */ |
383 | 6 | pixman_line_fixed_edge_init (&l, bpp, t, &trap->left, x_off, y_off); |
384 | 6 | pixman_line_fixed_edge_init (&r, bpp, t, &trap->right, x_off, y_off); |
385 | | |
386 | 6 | pixman_rasterize_edges (image, &l, &r, t, b); |
387 | 6 | } |
388 | 6 | } |
389 | | |
390 | | static const pixman_bool_t zero_src_has_no_effect[PIXMAN_N_OPERATORS] = |
391 | | { |
392 | | FALSE, /* Clear 0 0 */ |
393 | | FALSE, /* Src 1 0 */ |
394 | | TRUE, /* Dst 0 1 */ |
395 | | TRUE, /* Over 1 1-Aa */ |
396 | | TRUE, /* OverReverse 1-Ab 1 */ |
397 | | FALSE, /* In Ab 0 */ |
398 | | FALSE, /* InReverse 0 Aa */ |
399 | | FALSE, /* Out 1-Ab 0 */ |
400 | | TRUE, /* OutReverse 0 1-Aa */ |
401 | | TRUE, /* Atop Ab 1-Aa */ |
402 | | FALSE, /* AtopReverse 1-Ab Aa */ |
403 | | TRUE, /* Xor 1-Ab 1-Aa */ |
404 | | TRUE, /* Add 1 1 */ |
405 | | }; |
406 | | |
407 | | static pixman_bool_t |
408 | | get_trap_extents (pixman_op_t op, pixman_image_t *dest, |
409 | | const pixman_trapezoid_t *traps, int n_traps, |
410 | | pixman_box32_t *box) |
411 | 0 | { |
412 | 0 | int i; |
413 | | |
414 | | /* When the operator is such that a zero source has an |
415 | | * effect on the underlying image, we have to |
416 | | * composite across the entire destination |
417 | | */ |
418 | 0 | if (!zero_src_has_no_effect [op]) |
419 | 0 | { |
420 | 0 | box->x1 = 0; |
421 | 0 | box->y1 = 0; |
422 | 0 | box->x2 = dest->bits.width; |
423 | 0 | box->y2 = dest->bits.height; |
424 | 0 | return TRUE; |
425 | 0 | } |
426 | | |
427 | 0 | box->x1 = INT32_MAX; |
428 | 0 | box->y1 = INT32_MAX; |
429 | 0 | box->x2 = INT32_MIN; |
430 | 0 | box->y2 = INT32_MIN; |
431 | | |
432 | 0 | for (i = 0; i < n_traps; ++i) |
433 | 0 | { |
434 | 0 | const pixman_trapezoid_t *trap = &(traps[i]); |
435 | 0 | int y1, y2; |
436 | | |
437 | 0 | if (!pixman_trapezoid_valid (trap)) |
438 | 0 | continue; |
439 | | |
440 | 0 | y1 = pixman_fixed_to_int (trap->top); |
441 | 0 | if (y1 < box->y1) |
442 | 0 | box->y1 = y1; |
443 | | |
444 | 0 | y2 = pixman_fixed_to_int (pixman_fixed_ceil (trap->bottom)); |
445 | 0 | if (y2 > box->y2) |
446 | 0 | box->y2 = y2; |
447 | | |
448 | 0 | #define EXTEND_MIN(x) \ |
449 | 0 | if (pixman_fixed_to_int ((x)) < box->x1) \ |
450 | 0 | box->x1 = pixman_fixed_to_int ((x)); |
451 | 0 | #define EXTEND_MAX(x) \ |
452 | 0 | if (pixman_fixed_to_int (pixman_fixed_ceil ((x))) > box->x2) \ |
453 | 0 | box->x2 = pixman_fixed_to_int (pixman_fixed_ceil ((x))); |
454 | | |
455 | 0 | #define EXTEND(x) \ |
456 | 0 | EXTEND_MIN(x); \ |
457 | 0 | EXTEND_MAX(x); |
458 | | |
459 | 0 | EXTEND(trap->left.p1.x); |
460 | 0 | EXTEND(trap->left.p2.x); |
461 | 0 | EXTEND(trap->right.p1.x); |
462 | 0 | EXTEND(trap->right.p2.x); |
463 | 0 | } |
464 | | |
465 | 0 | if (box->x1 >= box->x2 || box->y1 >= box->y2) |
466 | 0 | return FALSE; |
467 | | |
468 | 0 | return TRUE; |
469 | 0 | } |
470 | | |
471 | | /* |
472 | | * pixman_composite_trapezoids() |
473 | | * |
474 | | * All the trapezoids are conceptually rendered to an infinitely big image. |
475 | | * The (0, 0) coordinates of this image are then aligned with the (x, y) |
476 | | * coordinates of the source image, and then both images are aligned with |
477 | | * the (x, y) coordinates of the destination. Then these three images are |
478 | | * composited across the entire destination. |
479 | | */ |
480 | | PIXMAN_EXPORT void |
481 | | pixman_composite_trapezoids (pixman_op_t op, |
482 | | pixman_image_t * src, |
483 | | pixman_image_t * dst, |
484 | | pixman_format_code_t mask_format, |
485 | | int x_src, |
486 | | int y_src, |
487 | | int x_dst, |
488 | | int y_dst, |
489 | | int n_traps, |
490 | | const pixman_trapezoid_t * traps) |
491 | 0 | { |
492 | 0 | int i; |
493 | |
|
494 | 0 | return_if_fail (PIXMAN_FORMAT_TYPE (mask_format) == PIXMAN_TYPE_A); |
495 | | |
496 | 0 | if (n_traps <= 0) |
497 | 0 | return; |
498 | | |
499 | 0 | _pixman_image_validate (src); |
500 | 0 | _pixman_image_validate (dst); |
501 | |
|
502 | 0 | if (op == PIXMAN_OP_ADD && |
503 | 0 | (src->common.flags & FAST_PATH_IS_OPAQUE) && |
504 | 0 | (mask_format == dst->common.extended_format_code) && |
505 | 0 | !(dst->common.have_clip_region)) |
506 | 0 | { |
507 | 0 | for (i = 0; i < n_traps; ++i) |
508 | 0 | { |
509 | 0 | const pixman_trapezoid_t *trap = &(traps[i]); |
510 | | |
511 | 0 | if (!pixman_trapezoid_valid (trap)) |
512 | 0 | continue; |
513 | | |
514 | 0 | pixman_rasterize_trapezoid (dst, trap, x_dst, y_dst); |
515 | 0 | } |
516 | 0 | } |
517 | 0 | else |
518 | 0 | { |
519 | 0 | pixman_image_t *tmp; |
520 | 0 | pixman_box32_t box; |
521 | 0 | int i; |
522 | |
|
523 | 0 | if (!get_trap_extents (op, dst, traps, n_traps, &box)) |
524 | 0 | return; |
525 | | |
526 | 0 | if (!(tmp = pixman_image_create_bits ( |
527 | 0 | mask_format, box.x2 - box.x1, box.y2 - box.y1, NULL, -1))) |
528 | 0 | return; |
529 | | |
530 | 0 | for (i = 0; i < n_traps; ++i) |
531 | 0 | { |
532 | 0 | const pixman_trapezoid_t *trap = &(traps[i]); |
533 | | |
534 | 0 | if (!pixman_trapezoid_valid (trap)) |
535 | 0 | continue; |
536 | | |
537 | 0 | pixman_rasterize_trapezoid (tmp, trap, - box.x1, - box.y1); |
538 | 0 | } |
539 | | |
540 | 0 | pixman_image_composite (op, src, tmp, dst, |
541 | 0 | x_src + box.x1, y_src + box.y1, |
542 | 0 | 0, 0, |
543 | 0 | x_dst + box.x1, y_dst + box.y1, |
544 | 0 | box.x2 - box.x1, box.y2 - box.y1); |
545 | | |
546 | 0 | pixman_image_unref (tmp); |
547 | 0 | } |
548 | 0 | } |
549 | | |
550 | | static int |
551 | | greater_y (const pixman_point_fixed_t *a, const pixman_point_fixed_t *b) |
552 | 0 | { |
553 | 0 | if (a->y == b->y) |
554 | 0 | return a->x > b->x; |
555 | 0 | return a->y > b->y; |
556 | 0 | } |
557 | | |
558 | | /* |
559 | | * Note that the definition of this function is a bit odd because |
560 | | * of the X coordinate space (y increasing downwards). |
561 | | */ |
562 | | static int |
563 | | clockwise (const pixman_point_fixed_t *ref, |
564 | | const pixman_point_fixed_t *a, |
565 | | const pixman_point_fixed_t *b) |
566 | 0 | { |
567 | 0 | pixman_point_fixed_t ad, bd; |
568 | |
|
569 | 0 | ad.x = a->x - ref->x; |
570 | 0 | ad.y = a->y - ref->y; |
571 | 0 | bd.x = b->x - ref->x; |
572 | 0 | bd.y = b->y - ref->y; |
573 | |
|
574 | 0 | return ((pixman_fixed_32_32_t) bd.y * ad.x - |
575 | 0 | (pixman_fixed_32_32_t) ad.y * bd.x) < 0; |
576 | 0 | } |
577 | | |
578 | | static void |
579 | | triangle_to_trapezoids (const pixman_triangle_t *tri, pixman_trapezoid_t *traps) |
580 | 0 | { |
581 | 0 | const pixman_point_fixed_t *top, *left, *right, *tmp; |
582 | |
|
583 | 0 | top = &tri->p1; |
584 | 0 | left = &tri->p2; |
585 | 0 | right = &tri->p3; |
586 | |
|
587 | 0 | if (greater_y (top, left)) |
588 | 0 | { |
589 | 0 | tmp = left; |
590 | 0 | left = top; |
591 | 0 | top = tmp; |
592 | 0 | } |
593 | |
|
594 | 0 | if (greater_y (top, right)) |
595 | 0 | { |
596 | 0 | tmp = right; |
597 | 0 | right = top; |
598 | 0 | top = tmp; |
599 | 0 | } |
600 | |
|
601 | 0 | if (clockwise (top, right, left)) |
602 | 0 | { |
603 | 0 | tmp = right; |
604 | 0 | right = left; |
605 | 0 | left = tmp; |
606 | 0 | } |
607 | | |
608 | | /* |
609 | | * Two cases: |
610 | | * |
611 | | * + + |
612 | | * / \ / \ |
613 | | * / \ / \ |
614 | | * / + + \ |
615 | | * / -- -- \ |
616 | | * / -- -- \ |
617 | | * / --- --- \ |
618 | | * +-- --+ |
619 | | */ |
620 | |
|
621 | 0 | traps->top = top->y; |
622 | 0 | traps->left.p1 = *top; |
623 | 0 | traps->left.p2 = *left; |
624 | 0 | traps->right.p1 = *top; |
625 | 0 | traps->right.p2 = *right; |
626 | |
|
627 | 0 | if (right->y < left->y) |
628 | 0 | traps->bottom = right->y; |
629 | 0 | else |
630 | 0 | traps->bottom = left->y; |
631 | |
|
632 | 0 | traps++; |
633 | |
|
634 | 0 | *traps = *(traps - 1); |
635 | | |
636 | 0 | if (right->y < left->y) |
637 | 0 | { |
638 | 0 | traps->top = right->y; |
639 | 0 | traps->bottom = left->y; |
640 | 0 | traps->right.p1 = *right; |
641 | 0 | traps->right.p2 = *left; |
642 | 0 | } |
643 | 0 | else |
644 | 0 | { |
645 | 0 | traps->top = left->y; |
646 | 0 | traps->bottom = right->y; |
647 | 0 | traps->left.p1 = *left; |
648 | 0 | traps->left.p2 = *right; |
649 | 0 | } |
650 | 0 | } |
651 | | |
652 | | static pixman_trapezoid_t * |
653 | | convert_triangles (int n_tris, const pixman_triangle_t *tris) |
654 | 0 | { |
655 | 0 | pixman_trapezoid_t *traps; |
656 | 0 | int i; |
657 | |
|
658 | 0 | if (n_tris <= 0) |
659 | 0 | return NULL; |
660 | | |
661 | 0 | traps = pixman_malloc_ab (n_tris, 2 * sizeof (pixman_trapezoid_t)); |
662 | 0 | if (!traps) |
663 | 0 | return NULL; |
664 | | |
665 | 0 | for (i = 0; i < n_tris; ++i) |
666 | 0 | triangle_to_trapezoids (&(tris[i]), traps + 2 * i); |
667 | |
|
668 | 0 | return traps; |
669 | 0 | } |
670 | | |
671 | | PIXMAN_EXPORT void |
672 | | pixman_composite_triangles (pixman_op_t op, |
673 | | pixman_image_t * src, |
674 | | pixman_image_t * dst, |
675 | | pixman_format_code_t mask_format, |
676 | | int x_src, |
677 | | int y_src, |
678 | | int x_dst, |
679 | | int y_dst, |
680 | | int n_tris, |
681 | | const pixman_triangle_t * tris) |
682 | 0 | { |
683 | 0 | pixman_trapezoid_t *traps; |
684 | |
|
685 | 0 | if ((traps = convert_triangles (n_tris, tris))) |
686 | 0 | { |
687 | 0 | pixman_composite_trapezoids (op, src, dst, mask_format, |
688 | 0 | x_src, y_src, x_dst, y_dst, |
689 | 0 | n_tris * 2, traps); |
690 | | |
691 | 0 | free (traps); |
692 | 0 | } |
693 | 0 | } |
694 | | |
695 | | PIXMAN_EXPORT void |
696 | | pixman_add_triangles (pixman_image_t *image, |
697 | | int32_t x_off, |
698 | | int32_t y_off, |
699 | | int n_tris, |
700 | | const pixman_triangle_t *tris) |
701 | 0 | { |
702 | 0 | pixman_trapezoid_t *traps; |
703 | |
|
704 | 0 | if ((traps = convert_triangles (n_tris, tris))) |
705 | 0 | { |
706 | 0 | pixman_add_trapezoids (image, x_off, y_off, |
707 | 0 | n_tris * 2, traps); |
708 | |
|
709 | 0 | free (traps); |
710 | 0 | } |
711 | 0 | } |