Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
1 /* -*- Mode: c; c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t; -*- */
2 /*
3 *
4 * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc.
5 * Copyright © 2000 SuSE, Inc.
6 * 2005 Lars Knoll & Zack Rusin, Trolltech
7 * Copyright © 2007 Red Hat, Inc.
8 *
9 *
10 * Permission to use, copy, modify, distribute, and sell this software and its
11 * documentation for any purpose is hereby granted without fee, provided that
12 * the above copyright notice appear in all copies and that both that
13 * copyright notice and this permission notice appear in supporting
14 * documentation, and that the name of Keith Packard not be used in
15 * advertising or publicity pertaining to distribution of the software without
16 * specific, written prior permission. Keith Packard makes no
17 * representations about the suitability of this software for any purpose. It
18 * is provided "as is" without express or implied warranty.
19 *
20 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
21 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
22 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
23 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
24 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
25 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
26 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
27 * SOFTWARE.
28 */
30 #ifdef HAVE_CONFIG_H
31 #include <config.h>
32 #endif
33 #include <stdlib.h>
34 #include <math.h>
35 #include "pixman-private.h"
37 #include "pixman-dither.h"
39 static inline pixman_fixed_32_32_t
40 dot (pixman_fixed_48_16_t x1,
41 pixman_fixed_48_16_t y1,
42 pixman_fixed_48_16_t z1,
43 pixman_fixed_48_16_t x2,
44 pixman_fixed_48_16_t y2,
45 pixman_fixed_48_16_t z2)
46 {
47 /*
48 * Exact computation, assuming that the input values can
49 * be represented as pixman_fixed_16_16_t
50 */
51 return x1 * x2 + y1 * y2 + z1 * z2;
52 }
54 static inline double
55 fdot (double x1,
56 double y1,
57 double z1,
58 double x2,
59 double y2,
60 double z2)
61 {
62 /*
63 * Error can be unbound in some special cases.
64 * Using clever dot product algorithms (for example compensated
65 * dot product) would improve this but make the code much less
66 * obvious
67 */
68 return x1 * x2 + y1 * y2 + z1 * z2;
69 }
71 static uint32_t
72 radial_compute_color (double a,
73 double b,
74 double c,
75 double inva,
76 double dr,
77 double mindr,
78 pixman_gradient_walker_t *walker,
79 pixman_repeat_t repeat)
80 {
81 /*
82 * In this function error propagation can lead to bad results:
83 * - discr can have an unbound error (if b*b-a*c is very small),
84 * potentially making it the opposite sign of what it should have been
85 * (thus clearing a pixel that would have been colored or vice-versa)
86 * or propagating the error to sqrtdiscr;
87 * if discr has the wrong sign or b is very small, this can lead to bad
88 * results
89 *
90 * - the algorithm used to compute the solutions of the quadratic
91 * equation is not numerically stable (but saves one division compared
92 * to the numerically stable one);
93 * this can be a problem if a*c is much smaller than b*b
94 *
95 * - the above problems are worse if a is small (as inva becomes bigger)
96 */
97 double discr;
99 if (a == 0)
100 {
101 double t;
103 if (b == 0)
104 return 0;
106 t = pixman_fixed_1 / 2 * c / b;
107 if (repeat == PIXMAN_REPEAT_NONE)
108 {
109 if (0 <= t && t <= pixman_fixed_1)
110 return _pixman_gradient_walker_pixel (walker, t);
111 }
112 else
113 {
114 if (t * dr >= mindr)
115 return _pixman_gradient_walker_pixel (walker, t);
116 }
118 return 0;
119 }
121 discr = fdot (b, a, 0, b, -c, 0);
122 if (discr >= 0)
123 {
124 double sqrtdiscr, t0, t1;
126 sqrtdiscr = sqrt (discr);
127 t0 = (b + sqrtdiscr) * inva;
128 t1 = (b - sqrtdiscr) * inva;
130 /*
131 * The root that must be used is the biggest one that belongs
132 * to the valid range ([0,1] for PIXMAN_REPEAT_NONE, any
133 * solution that results in a positive radius otherwise).
134 *
135 * If a > 0, t0 is the biggest solution, so if it is valid, it
136 * is the correct result.
137 *
138 * If a < 0, only one of the solutions can be valid, so the
139 * order in which they are tested is not important.
140 */
141 if (repeat == PIXMAN_REPEAT_NONE)
142 {
143 if (0 <= t0 && t0 <= pixman_fixed_1)
144 return _pixman_gradient_walker_pixel (walker, t0);
145 else if (0 <= t1 && t1 <= pixman_fixed_1)
146 return _pixman_gradient_walker_pixel (walker, t1);
147 }
148 else
149 {
150 if (t0 * dr >= mindr)
151 return _pixman_gradient_walker_pixel (walker, t0);
152 else if (t1 * dr >= mindr)
153 return _pixman_gradient_walker_pixel (walker, t1);
154 }
155 }
157 return 0;
158 }
160 static uint32_t *
161 radial_get_scanline_narrow (pixman_iter_t *iter, const uint32_t *mask)
162 {
163 /*
164 * Implementation of radial gradients following the PDF specification.
165 * See section 8.7.4.5.4 Type 3 (Radial) Shadings of the PDF Reference
166 * Manual (PDF 32000-1:2008 at the time of this writing).
167 *
168 * In the radial gradient problem we are given two circles (c₁,r₁) and
169 * (c₂,r₂) that define the gradient itself.
170 *
171 * Mathematically the gradient can be defined as the family of circles
172 *
173 * ((1-t)·c₁ + t·(c₂), (1-t)·r₁ + t·r₂)
174 *
175 * excluding those circles whose radius would be < 0. When a point
176 * belongs to more than one circle, the one with a bigger t is the only
177 * one that contributes to its color. When a point does not belong
178 * to any of the circles, it is transparent black, i.e. RGBA (0, 0, 0, 0).
179 * Further limitations on the range of values for t are imposed when
180 * the gradient is not repeated, namely t must belong to [0,1].
181 *
182 * The graphical result is the same as drawing the valid (radius > 0)
183 * circles with increasing t in [-inf, +inf] (or in [0,1] if the gradient
184 * is not repeated) using SOURCE operator composition.
185 *
186 * It looks like a cone pointing towards the viewer if the ending circle
187 * is smaller than the starting one, a cone pointing inside the page if
188 * the starting circle is the smaller one and like a cylinder if they
189 * have the same radius.
190 *
191 * What we actually do is, given the point whose color we are interested
192 * in, compute the t values for that point, solving for t in:
193 *
194 * length((1-t)·c₁ + t·(c₂) - p) = (1-t)·r₁ + t·r₂
195 *
196 * Let's rewrite it in a simpler way, by defining some auxiliary
197 * variables:
198 *
199 * cd = c₂ - c₁
200 * pd = p - c₁
201 * dr = r₂ - r₁
202 * length(t·cd - pd) = r₁ + t·dr
203 *
204 * which actually means
205 *
206 * hypot(t·cdx - pdx, t·cdy - pdy) = r₁ + t·dr
207 *
208 * or
209 *
210 * ⎷((t·cdx - pdx)² + (t·cdy - pdy)²) = r₁ + t·dr.
211 *
212 * If we impose (as stated earlier) that r₁ + t·dr >= 0, it becomes:
213 *
214 * (t·cdx - pdx)² + (t·cdy - pdy)² = (r₁ + t·dr)²
215 *
216 * where we can actually expand the squares and solve for t:
217 *
218 * t²cdx² - 2t·cdx·pdx + pdx² + t²cdy² - 2t·cdy·pdy + pdy² =
219 * = r₁² + 2·r₁·t·dr + t²·dr²
220 *
221 * (cdx² + cdy² - dr²)t² - 2(cdx·pdx + cdy·pdy + r₁·dr)t +
222 * (pdx² + pdy² - r₁²) = 0
223 *
224 * A = cdx² + cdy² - dr²
225 * B = pdx·cdx + pdy·cdy + r₁·dr
226 * C = pdx² + pdy² - r₁²
227 * At² - 2Bt + C = 0
228 *
229 * The solutions (unless the equation degenerates because of A = 0) are:
230 *
231 * t = (B ± ⎷(B² - A·C)) / A
232 *
233 * The solution we are going to prefer is the bigger one, unless the
234 * radius associated to it is negative (or it falls outside the valid t
235 * range).
236 *
237 * Additional observations (useful for optimizations):
238 * A does not depend on p
239 *
240 * A < 0 <=> one of the two circles completely contains the other one
241 * <=> for every p, the radiuses associated with the two t solutions
242 * have opposite sign
243 */
244 pixman_image_t *image = iter->image;
245 int x = iter->x;
246 int y = iter->y;
247 int width = iter->width;
248 uint32_t *buffer = iter->buffer;
250 gradient_t *gradient = (gradient_t *)image;
251 radial_gradient_t *radial = (radial_gradient_t *)image;
252 uint32_t *end = buffer + width;
253 pixman_gradient_walker_t walker;
254 pixman_vector_t v, unit;
256 /* reference point is the center of the pixel */
257 v.vector[0] = pixman_int_to_fixed (x) + pixman_fixed_1 / 2;
258 v.vector[1] = pixman_int_to_fixed (y) + pixman_fixed_1 / 2;
259 v.vector[2] = pixman_fixed_1;
261 _pixman_gradient_walker_init (&walker, gradient, image->common.repeat);
263 if (image->common.transform)
264 {
265 if (!pixman_transform_point_3d (image->common.transform, &v))
266 return iter->buffer;
268 unit.vector[0] = image->common.transform->matrix[0][0];
269 unit.vector[1] = image->common.transform->matrix[1][0];
270 unit.vector[2] = image->common.transform->matrix[2][0];
271 }
272 else
273 {
274 unit.vector[0] = pixman_fixed_1;
275 unit.vector[1] = 0;
276 unit.vector[2] = 0;
277 }
279 if (unit.vector[2] == 0 && v.vector[2] == pixman_fixed_1)
280 {
281 /*
282 * Given:
283 *
284 * t = (B ± ⎷(B² - A·C)) / A
285 *
286 * where
287 *
288 * A = cdx² + cdy² - dr²
289 * B = pdx·cdx + pdy·cdy + r₁·dr
290 * C = pdx² + pdy² - r₁²
291 * det = B² - A·C
292 *
293 * Since we have an affine transformation, we know that (pdx, pdy)
294 * increase linearly with each pixel,
295 *
296 * pdx = pdx₀ + n·ux,
297 * pdy = pdy₀ + n·uy,
298 *
299 * we can then express B, C and det through multiple differentiation.
300 */
301 pixman_fixed_32_32_t b, db, c, dc, ddc;
303 /* warning: this computation may overflow */
304 v.vector[0] -= radial->c1.x;
305 v.vector[1] -= radial->c1.y;
307 /*
308 * B and C are computed and updated exactly.
309 * If fdot was used instead of dot, in the worst case it would
310 * lose 11 bits of precision in each of the multiplication and
311 * summing up would zero out all the bit that were preserved,
312 * thus making the result 0 instead of the correct one.
313 * This would mean a worst case of unbound relative error or
314 * about 2^10 absolute error
315 */
316 b = dot (v.vector[0], v.vector[1], radial->c1.radius,
317 radial->delta.x, radial->delta.y, radial->delta.radius);
318 db = dot (unit.vector[0], unit.vector[1], 0,
319 radial->delta.x, radial->delta.y, 0);
321 c = dot (v.vector[0], v.vector[1],
322 -((pixman_fixed_48_16_t) radial->c1.radius),
323 v.vector[0], v.vector[1], radial->c1.radius);
324 dc = dot (2 * (pixman_fixed_48_16_t) v.vector[0] + unit.vector[0],
325 2 * (pixman_fixed_48_16_t) v.vector[1] + unit.vector[1],
326 0,
327 unit.vector[0], unit.vector[1], 0);
328 ddc = 2 * dot (unit.vector[0], unit.vector[1], 0,
329 unit.vector[0], unit.vector[1], 0);
331 while (buffer < end)
332 {
333 if (!mask || *mask++)
334 {
335 *buffer = radial_compute_color (radial->a, b, c,
336 radial->inva,
337 radial->delta.radius,
338 radial->mindr,
339 &walker,
340 image->common.repeat);
341 }
343 b += db;
344 c += dc;
345 dc += ddc;
346 ++buffer;
347 }
348 }
349 else
350 {
351 /* projective */
352 /* Warning:
353 * error propagation guarantees are much looser than in the affine case
354 */
355 while (buffer < end)
356 {
357 if (!mask || *mask++)
358 {
359 if (v.vector[2] != 0)
360 {
361 double pdx, pdy, invv2, b, c;
363 invv2 = 1. * pixman_fixed_1 / v.vector[2];
365 pdx = v.vector[0] * invv2 - radial->c1.x;
366 /* / pixman_fixed_1 */
368 pdy = v.vector[1] * invv2 - radial->c1.y;
369 /* / pixman_fixed_1 */
371 b = fdot (pdx, pdy, radial->c1.radius,
372 radial->delta.x, radial->delta.y,
373 radial->delta.radius);
374 /* / pixman_fixed_1 / pixman_fixed_1 */
376 c = fdot (pdx, pdy, -radial->c1.radius,
377 pdx, pdy, radial->c1.radius);
378 /* / pixman_fixed_1 / pixman_fixed_1 */
380 *buffer = radial_compute_color (radial->a, b, c,
381 radial->inva,
382 radial->delta.radius,
383 radial->mindr,
384 &walker,
385 image->common.repeat);
386 }
387 else
388 {
389 *buffer = 0;
390 }
391 }
393 ++buffer;
395 v.vector[0] += unit.vector[0];
396 v.vector[1] += unit.vector[1];
397 v.vector[2] += unit.vector[2];
398 }
399 }
401 iter->y++;
402 return iter->buffer;
403 }
405 static uint32_t *
406 radial_get_scanline_16 (pixman_iter_t *iter, const uint32_t *mask)
407 {
408 /*
409 * Implementation of radial gradients following the PDF specification.
410 * See section 8.7.4.5.4 Type 3 (Radial) Shadings of the PDF Reference
411 * Manual (PDF 32000-1:2008 at the time of this writing).
412 *
413 * In the radial gradient problem we are given two circles (c₁,r₁) and
414 * (c₂,r₂) that define the gradient itself.
415 *
416 * Mathematically the gradient can be defined as the family of circles
417 *
418 * ((1-t)·c₁ + t·(c₂), (1-t)·r₁ + t·r₂)
419 *
420 * excluding those circles whose radius would be < 0. When a point
421 * belongs to more than one circle, the one with a bigger t is the only
422 * one that contributes to its color. When a point does not belong
423 * to any of the circles, it is transparent black, i.e. RGBA (0, 0, 0, 0).
424 * Further limitations on the range of values for t are imposed when
425 * the gradient is not repeated, namely t must belong to [0,1].
426 *
427 * The graphical result is the same as drawing the valid (radius > 0)
428 * circles with increasing t in [-inf, +inf] (or in [0,1] if the gradient
429 * is not repeated) using SOURCE operator composition.
430 *
431 * It looks like a cone pointing towards the viewer if the ending circle
432 * is smaller than the starting one, a cone pointing inside the page if
433 * the starting circle is the smaller one and like a cylinder if they
434 * have the same radius.
435 *
436 * What we actually do is, given the point whose color we are interested
437 * in, compute the t values for that point, solving for t in:
438 *
439 * length((1-t)·c₁ + t·(c₂) - p) = (1-t)·r₁ + t·r₂
440 *
441 * Let's rewrite it in a simpler way, by defining some auxiliary
442 * variables:
443 *
444 * cd = c₂ - c₁
445 * pd = p - c₁
446 * dr = r₂ - r₁
447 * length(t·cd - pd) = r₁ + t·dr
448 *
449 * which actually means
450 *
451 * hypot(t·cdx - pdx, t·cdy - pdy) = r₁ + t·dr
452 *
453 * or
454 *
455 * ⎷((t·cdx - pdx)² + (t·cdy - pdy)²) = r₁ + t·dr.
456 *
457 * If we impose (as stated earlier) that r₁ + t·dr >= 0, it becomes:
458 *
459 * (t·cdx - pdx)² + (t·cdy - pdy)² = (r₁ + t·dr)²
460 *
461 * where we can actually expand the squares and solve for t:
462 *
463 * t²cdx² - 2t·cdx·pdx + pdx² + t²cdy² - 2t·cdy·pdy + pdy² =
464 * = r₁² + 2·r₁·t·dr + t²·dr²
465 *
466 * (cdx² + cdy² - dr²)t² - 2(cdx·pdx + cdy·pdy + r₁·dr)t +
467 * (pdx² + pdy² - r₁²) = 0
468 *
469 * A = cdx² + cdy² - dr²
470 * B = pdx·cdx + pdy·cdy + r₁·dr
471 * C = pdx² + pdy² - r₁²
472 * At² - 2Bt + C = 0
473 *
474 * The solutions (unless the equation degenerates because of A = 0) are:
475 *
476 * t = (B ± ⎷(B² - A·C)) / A
477 *
478 * The solution we are going to prefer is the bigger one, unless the
479 * radius associated to it is negative (or it falls outside the valid t
480 * range).
481 *
482 * Additional observations (useful for optimizations):
483 * A does not depend on p
484 *
485 * A < 0 <=> one of the two circles completely contains the other one
486 * <=> for every p, the radiuses associated with the two t solutions
487 * have opposite sign
488 */
489 pixman_image_t *image = iter->image;
490 int x = iter->x;
491 int y = iter->y;
492 int width = iter->width;
493 uint16_t *buffer = iter->buffer;
494 pixman_bool_t toggle = ((x ^ y) & 1);
496 gradient_t *gradient = (gradient_t *)image;
497 radial_gradient_t *radial = (radial_gradient_t *)image;
498 uint16_t *end = buffer + width;
499 pixman_gradient_walker_t walker;
500 pixman_vector_t v, unit;
502 /* reference point is the center of the pixel */
503 v.vector[0] = pixman_int_to_fixed (x) + pixman_fixed_1 / 2;
504 v.vector[1] = pixman_int_to_fixed (y) + pixman_fixed_1 / 2;
505 v.vector[2] = pixman_fixed_1;
507 _pixman_gradient_walker_init (&walker, gradient, image->common.repeat);
509 if (image->common.transform)
510 {
511 if (!pixman_transform_point_3d (image->common.transform, &v))
512 return iter->buffer;
514 unit.vector[0] = image->common.transform->matrix[0][0];
515 unit.vector[1] = image->common.transform->matrix[1][0];
516 unit.vector[2] = image->common.transform->matrix[2][0];
517 }
518 else
519 {
520 unit.vector[0] = pixman_fixed_1;
521 unit.vector[1] = 0;
522 unit.vector[2] = 0;
523 }
525 if (unit.vector[2] == 0 && v.vector[2] == pixman_fixed_1)
526 {
527 /*
528 * Given:
529 *
530 * t = (B ± ⎷(B² - A·C)) / A
531 *
532 * where
533 *
534 * A = cdx² + cdy² - dr²
535 * B = pdx·cdx + pdy·cdy + r₁·dr
536 * C = pdx² + pdy² - r₁²
537 * det = B² - A·C
538 *
539 * Since we have an affine transformation, we know that (pdx, pdy)
540 * increase linearly with each pixel,
541 *
542 * pdx = pdx₀ + n·ux,
543 * pdy = pdy₀ + n·uy,
544 *
545 * we can then express B, C and det through multiple differentiation.
546 */
547 pixman_fixed_32_32_t b, db, c, dc, ddc;
549 /* warning: this computation may overflow */
550 v.vector[0] -= radial->c1.x;
551 v.vector[1] -= radial->c1.y;
553 /*
554 * B and C are computed and updated exactly.
555 * If fdot was used instead of dot, in the worst case it would
556 * lose 11 bits of precision in each of the multiplication and
557 * summing up would zero out all the bit that were preserved,
558 * thus making the result 0 instead of the correct one.
559 * This would mean a worst case of unbound relative error or
560 * about 2^10 absolute error
561 */
562 b = dot (v.vector[0], v.vector[1], radial->c1.radius,
563 radial->delta.x, radial->delta.y, radial->delta.radius);
564 db = dot (unit.vector[0], unit.vector[1], 0,
565 radial->delta.x, radial->delta.y, 0);
567 c = dot (v.vector[0], v.vector[1],
568 -((pixman_fixed_48_16_t) radial->c1.radius),
569 v.vector[0], v.vector[1], radial->c1.radius);
570 dc = dot (2 * (pixman_fixed_48_16_t) v.vector[0] + unit.vector[0],
571 2 * (pixman_fixed_48_16_t) v.vector[1] + unit.vector[1],
572 0,
573 unit.vector[0], unit.vector[1], 0);
574 ddc = 2 * dot (unit.vector[0], unit.vector[1], 0,
575 unit.vector[0], unit.vector[1], 0);
577 while (buffer < end)
578 {
579 if (!mask || *mask++)
580 {
581 *buffer = dither_8888_to_0565(
582 radial_compute_color (radial->a, b, c,
583 radial->inva,
584 radial->delta.radius,
585 radial->mindr,
586 &walker,
587 image->common.repeat),
588 toggle);
589 }
591 toggle ^= 1;
592 b += db;
593 c += dc;
594 dc += ddc;
595 ++buffer;
596 }
597 }
598 else
599 {
600 /* projective */
601 /* Warning:
602 * error propagation guarantees are much looser than in the affine case
603 */
604 while (buffer < end)
605 {
606 if (!mask || *mask++)
607 {
608 if (v.vector[2] != 0)
609 {
610 double pdx, pdy, invv2, b, c;
612 invv2 = 1. * pixman_fixed_1 / v.vector[2];
614 pdx = v.vector[0] * invv2 - radial->c1.x;
615 /* / pixman_fixed_1 */
617 pdy = v.vector[1] * invv2 - radial->c1.y;
618 /* / pixman_fixed_1 */
620 b = fdot (pdx, pdy, radial->c1.radius,
621 radial->delta.x, radial->delta.y,
622 radial->delta.radius);
623 /* / pixman_fixed_1 / pixman_fixed_1 */
625 c = fdot (pdx, pdy, -radial->c1.radius,
626 pdx, pdy, radial->c1.radius);
627 /* / pixman_fixed_1 / pixman_fixed_1 */
629 *buffer = dither_8888_to_0565 (
630 radial_compute_color (radial->a, b, c,
631 radial->inva,
632 radial->delta.radius,
633 radial->mindr,
634 &walker,
635 image->common.repeat),
636 toggle);
637 }
638 else
639 {
640 *buffer = 0;
641 }
642 }
644 ++buffer;
645 toggle ^= 1;
647 v.vector[0] += unit.vector[0];
648 v.vector[1] += unit.vector[1];
649 v.vector[2] += unit.vector[2];
650 }
651 }
653 iter->y++;
654 return iter->buffer;
655 }
656 static uint32_t *
657 radial_get_scanline_wide (pixman_iter_t *iter, const uint32_t *mask)
658 {
659 uint32_t *buffer = radial_get_scanline_narrow (iter, NULL);
661 pixman_expand_to_float (
662 (argb_t *)buffer, buffer, PIXMAN_a8r8g8b8, iter->width);
664 return buffer;
665 }
667 void
668 _pixman_radial_gradient_iter_init (pixman_image_t *image, pixman_iter_t *iter)
669 {
670 if (iter->iter_flags & ITER_16)
671 iter->get_scanline = radial_get_scanline_16;
672 else if (iter->iter_flags & ITER_NARROW)
673 iter->get_scanline = radial_get_scanline_narrow;
674 else
675 iter->get_scanline = radial_get_scanline_wide;
676 }
679 PIXMAN_EXPORT pixman_image_t *
680 pixman_image_create_radial_gradient (const pixman_point_fixed_t * inner,
681 const pixman_point_fixed_t * outer,
682 pixman_fixed_t inner_radius,
683 pixman_fixed_t outer_radius,
684 const pixman_gradient_stop_t *stops,
685 int n_stops)
686 {
687 pixman_image_t *image;
688 radial_gradient_t *radial;
690 image = _pixman_image_allocate ();
692 if (!image)
693 return NULL;
695 radial = &image->radial;
697 if (!_pixman_init_gradient (&radial->common, stops, n_stops))
698 {
699 free (image);
700 return NULL;
701 }
703 image->type = RADIAL;
705 radial->c1.x = inner->x;
706 radial->c1.y = inner->y;
707 radial->c1.radius = inner_radius;
708 radial->c2.x = outer->x;
709 radial->c2.y = outer->y;
710 radial->c2.radius = outer_radius;
712 /* warning: this computations may overflow */
713 radial->delta.x = radial->c2.x - radial->c1.x;
714 radial->delta.y = radial->c2.y - radial->c1.y;
715 radial->delta.radius = radial->c2.radius - radial->c1.radius;
717 /* computed exactly, then cast to double -> every bit of the double
718 representation is correct (53 bits) */
719 radial->a = dot (radial->delta.x, radial->delta.y, -radial->delta.radius,
720 radial->delta.x, radial->delta.y, radial->delta.radius);
721 if (radial->a != 0)
722 radial->inva = 1. * pixman_fixed_1 / radial->a;
724 radial->mindr = -1. * pixman_fixed_1 * radial->c1.radius;
726 return image;
727 }