Rev 1891 | Go to most recent revision | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 1891 | Rev 3931 | ||
---|---|---|---|
Line 76... | Line 76... | ||
76 | pixman_gradient_walker_t *walker, |
76 | pixman_gradient_walker_t *walker, |
77 | pixman_repeat_t repeat) |
77 | pixman_repeat_t repeat) |
78 | { |
78 | { |
79 | /* |
79 | /* |
80 | * In this function error propagation can lead to bad results: |
80 | * In this function error propagation can lead to bad results: |
81 | * - det can have an unbound error (if b*b-a*c is very small), |
81 | * - discr can have an unbound error (if b*b-a*c is very small), |
82 | * potentially making it the opposite sign of what it should have been |
82 | * potentially making it the opposite sign of what it should have been |
83 | * (thus clearing a pixel that would have been colored or vice-versa) |
83 | * (thus clearing a pixel that would have been colored or vice-versa) |
84 | * or propagating the error to sqrtdet; |
84 | * or propagating the error to sqrtdiscr; |
85 | * if det has the wrong sign or b is very small, this can lead to bad |
85 | * if discr has the wrong sign or b is very small, this can lead to bad |
86 | * results |
86 | * results |
87 | * |
87 | * |
88 | * - the algorithm used to compute the solutions of the quadratic |
88 | * - the algorithm used to compute the solutions of the quadratic |
89 | * equation is not numerically stable (but saves one division compared |
89 | * equation is not numerically stable (but saves one division compared |
90 | * to the numerically stable one); |
90 | * to the numerically stable one); |
91 | * this can be a problem if a*c is much smaller than b*b |
91 | * this can be a problem if a*c is much smaller than b*b |
92 | * |
92 | * |
93 | * - the above problems are worse if a is small (as inva becomes bigger) |
93 | * - the above problems are worse if a is small (as inva becomes bigger) |
94 | */ |
94 | */ |
95 | double det; |
95 | double discr; |
Line 96... | Line 96... | ||
96 | 96 | ||
97 | if (a == 0) |
97 | if (a == 0) |
98 | { |
98 | { |
Line 107... | Line 107... | ||
107 | if (0 <= t && t <= pixman_fixed_1) |
107 | if (0 <= t && t <= pixman_fixed_1) |
108 | return _pixman_gradient_walker_pixel (walker, t); |
108 | return _pixman_gradient_walker_pixel (walker, t); |
109 | } |
109 | } |
110 | else |
110 | else |
111 | { |
111 | { |
112 | if (t * dr > mindr) |
112 | if (t * dr >= mindr) |
113 | return _pixman_gradient_walker_pixel (walker, t); |
113 | return _pixman_gradient_walker_pixel (walker, t); |
114 | } |
114 | } |
Line 115... | Line 115... | ||
115 | 115 | ||
116 | return 0; |
116 | return 0; |
Line 117... | Line 117... | ||
117 | } |
117 | } |
118 | 118 | ||
119 | det = fdot (b, a, 0, b, -c, 0); |
119 | discr = fdot (b, a, 0, b, -c, 0); |
120 | if (det >= 0) |
120 | if (discr >= 0) |
Line 121... | Line 121... | ||
121 | { |
121 | { |
122 | double sqrtdet, t0, t1; |
122 | double sqrtdiscr, t0, t1; |
123 | 123 | ||
Line -... | Line 124... | ||
- | 124 | sqrtdiscr = sqrt (discr); |
|
- | 125 | t0 = (b + sqrtdiscr) * inva; |
|
- | 126 | t1 = (b - sqrtdiscr) * inva; |
|
- | 127 | ||
- | 128 | /* |
|
- | 129 | * The root that must be used is the biggest one that belongs |
|
- | 130 | * to the valid range ([0,1] for PIXMAN_REPEAT_NONE, any |
|
- | 131 | * solution that results in a positive radius otherwise). |
|
- | 132 | * |
|
- | 133 | * If a > 0, t0 is the biggest solution, so if it is valid, it |
|
- | 134 | * is the correct result. |
|
124 | sqrtdet = sqrt (det); |
135 | * |
125 | t0 = (b + sqrtdet) * inva; |
136 | * If a < 0, only one of the solutions can be valid, so the |
126 | t1 = (b - sqrtdet) * inva; |
137 | * order in which they are tested is not important. |
127 | 138 | */ |
|
128 | if (repeat == PIXMAN_REPEAT_NONE) |
139 | if (repeat == PIXMAN_REPEAT_NONE) |
129 | { |
140 | { |
130 | if (0 <= t0 && t0 <= pixman_fixed_1) |
141 | if (0 <= t0 && t0 <= pixman_fixed_1) |
131 | return _pixman_gradient_walker_pixel (walker, t0); |
142 | return _pixman_gradient_walker_pixel (walker, t0); |
132 | else if (0 <= t1 && t1 <= pixman_fixed_1) |
143 | else if (0 <= t1 && t1 <= pixman_fixed_1) |
133 | return _pixman_gradient_walker_pixel (walker, t1); |
144 | return _pixman_gradient_walker_pixel (walker, t1); |
134 | } |
145 | } |
135 | else |
146 | else |
136 | { |
147 | { |
137 | if (t0 * dr > mindr) |
148 | if (t0 * dr >= mindr) |
138 | return _pixman_gradient_walker_pixel (walker, t0); |
149 | return _pixman_gradient_walker_pixel (walker, t0); |
Line 139... | Line 150... | ||
139 | else if (t1 * dr > mindr) |
150 | else if (t1 * dr >= mindr) |
140 | return _pixman_gradient_walker_pixel (walker, t1); |
151 | return _pixman_gradient_walker_pixel (walker, t1); |
Line 141... | Line 152... | ||
141 | } |
152 | } |
142 | } |
153 | } |
143 | - | ||
144 | return 0; |
- | |
145 | } |
- | |
146 | - | ||
147 | static void |
- | |
148 | radial_gradient_get_scanline_32 (pixman_image_t *image, |
154 | |
149 | int x, |
155 | return 0; |
150 | int y, |
156 | } |
151 | int width, |
157 | |
152 | uint32_t * buffer, |
158 | static uint32_t * |
Line 171... | Line 177... | ||
171 | * Further limitations on the range of values for t are imposed when |
177 | * Further limitations on the range of values for t are imposed when |
172 | * the gradient is not repeated, namely t must belong to [0,1]. |
178 | * the gradient is not repeated, namely t must belong to [0,1]. |
173 | * |
179 | * |
174 | * The graphical result is the same as drawing the valid (radius > 0) |
180 | * The graphical result is the same as drawing the valid (radius > 0) |
175 | * circles with increasing t in [-inf, +inf] (or in [0,1] if the gradient |
181 | * circles with increasing t in [-inf, +inf] (or in [0,1] if the gradient |
176 | * is not repeated) using SOURCE operatior composition. |
182 | * is not repeated) using SOURCE operator composition. |
177 | * |
183 | * |
178 | * It looks like a cone pointing towards the viewer if the ending circle |
184 | * It looks like a cone pointing towards the viewer if the ending circle |
179 | * is smaller than the starting one, a cone pointing inside the page if |
185 | * is smaller than the starting one, a cone pointing inside the page if |
180 | * the starting circle is the smaller one and like a cylinder if they |
186 | * the starting circle is the smaller one and like a cylinder if they |
181 | * have the same radius. |
187 | * have the same radius. |
Line 189... | Line 195... | ||
189 | * variables: |
195 | * variables: |
190 | * |
196 | * |
191 | * cd = c₂ - c₁ |
197 | * cd = c₂ - c₁ |
192 | * pd = p - c₁ |
198 | * pd = p - c₁ |
193 | * dr = r₂ - r₁ |
199 | * dr = r₂ - r₁ |
194 | * lenght(t·cd - pd) = r₁ + t·dr |
200 | * length(t·cd - pd) = r₁ + t·dr |
195 | * |
201 | * |
196 | * which actually means |
202 | * which actually means |
197 | * |
203 | * |
198 | * hypot(t·cdx - pdx, t·cdy - pdy) = r₁ + t·dr |
204 | * hypot(t·cdx - pdx, t·cdy - pdy) = r₁ + t·dr |
199 | * |
205 | * |
Line 231... | Line 237... | ||
231 | * |
237 | * |
232 | * A < 0 <=> one of the two circles completely contains the other one |
238 | * A < 0 <=> one of the two circles completely contains the other one |
233 | * <=> for every p, the radiuses associated with the two t solutions |
239 | * <=> for every p, the radiuses associated with the two t solutions |
234 | * have opposite sign |
240 | * have opposite sign |
235 | */ |
241 | */ |
- | 242 | pixman_image_t *image = iter->image; |
|
- | 243 | int x = iter->x; |
|
- | 244 | int y = iter->y; |
|
- | 245 | int width = iter->width; |
|
- | 246 | uint32_t *buffer = iter->buffer; |
|
Line 236... | Line 247... | ||
236 | 247 | ||
237 | gradient_t *gradient = (gradient_t *)image; |
- | |
238 | source_image_t *source = (source_image_t *)image; |
248 | gradient_t *gradient = (gradient_t *)image; |
239 | radial_gradient_t *radial = (radial_gradient_t *)image; |
249 | radial_gradient_t *radial = (radial_gradient_t *)image; |
240 | uint32_t *end = buffer + width; |
250 | uint32_t *end = buffer + width; |
241 | pixman_gradient_walker_t walker; |
251 | pixman_gradient_walker_t walker; |
Line 242... | Line 252... | ||
242 | pixman_vector_t v, unit; |
252 | pixman_vector_t v, unit; |
243 | 253 | ||
244 | /* reference point is the center of the pixel */ |
254 | /* reference point is the center of the pixel */ |
245 | v.vector[0] = pixman_int_to_fixed (x) + pixman_fixed_1 / 2; |
255 | v.vector[0] = pixman_int_to_fixed (x) + pixman_fixed_1 / 2; |
Line 246... | Line 256... | ||
246 | v.vector[1] = pixman_int_to_fixed (y) + pixman_fixed_1 / 2; |
256 | v.vector[1] = pixman_int_to_fixed (y) + pixman_fixed_1 / 2; |
Line 247... | Line 257... | ||
247 | v.vector[2] = pixman_fixed_1; |
257 | v.vector[2] = pixman_fixed_1; |
248 | 258 | ||
249 | _pixman_gradient_walker_init (&walker, gradient, source->common.repeat); |
259 | _pixman_gradient_walker_init (&walker, gradient, image->common.repeat); |
250 | 260 | ||
Line 251... | Line 261... | ||
251 | if (source->common.transform) |
261 | if (image->common.transform) |
252 | { |
262 | { |
253 | if (!pixman_transform_point_3d (source->common.transform, &v)) |
263 | if (!pixman_transform_point_3d (image->common.transform, &v)) |
254 | return; |
264 | return iter->buffer; |
255 | 265 | ||
256 | unit.vector[0] = source->common.transform->matrix[0][0]; |
266 | unit.vector[0] = image->common.transform->matrix[0][0]; |
257 | unit.vector[1] = source->common.transform->matrix[1][0]; |
267 | unit.vector[1] = image->common.transform->matrix[1][0]; |
258 | unit.vector[2] = source->common.transform->matrix[2][0]; |
268 | unit.vector[2] = image->common.transform->matrix[2][0]; |
Line 323... | Line 333... | ||
323 | *buffer = radial_compute_color (radial->a, b, c, |
333 | *buffer = radial_compute_color (radial->a, b, c, |
324 | radial->inva, |
334 | radial->inva, |
325 | radial->delta.radius, |
335 | radial->delta.radius, |
326 | radial->mindr, |
336 | radial->mindr, |
327 | &walker, |
337 | &walker, |
328 | source->common.repeat); |
338 | image->common.repeat); |
329 | } |
339 | } |
Line 330... | Line 340... | ||
330 | 340 | ||
331 | b += db; |
341 | b += db; |
332 | c += dc; |
342 | c += dc; |
Line 368... | Line 378... | ||
368 | *buffer = radial_compute_color (radial->a, b, c, |
378 | *buffer = radial_compute_color (radial->a, b, c, |
369 | radial->inva, |
379 | radial->inva, |
370 | radial->delta.radius, |
380 | radial->delta.radius, |
371 | radial->mindr, |
381 | radial->mindr, |
372 | &walker, |
382 | &walker, |
373 | source->common.repeat); |
383 | image->common.repeat); |
374 | } |
384 | } |
375 | else |
385 | else |
376 | { |
386 | { |
377 | *buffer = 0; |
387 | *buffer = 0; |
378 | } |
388 | } |
Line 383... | Line 393... | ||
383 | v.vector[0] += unit.vector[0]; |
393 | v.vector[0] += unit.vector[0]; |
384 | v.vector[1] += unit.vector[1]; |
394 | v.vector[1] += unit.vector[1]; |
385 | v.vector[2] += unit.vector[2]; |
395 | v.vector[2] += unit.vector[2]; |
386 | } |
396 | } |
387 | } |
397 | } |
- | 398 | ||
- | 399 | iter->y++; |
|
- | 400 | return iter->buffer; |
|
388 | } |
401 | } |
Line 389... | Line 402... | ||
389 | 402 | ||
390 | static void |
403 | static uint32_t * |
391 | radial_gradient_property_changed (pixman_image_t *image) |
404 | radial_get_scanline_wide (pixman_iter_t *iter, const uint32_t *mask) |
- | 405 | { |
|
- | 406 | uint32_t *buffer = radial_get_scanline_narrow (iter, NULL); |
|
- | 407 | ||
- | 408 | pixman_expand_to_float ( |
|
- | 409 | (argb_t *)buffer, buffer, PIXMAN_a8r8g8b8, iter->width); |
|
- | 410 | ||
- | 411 | return buffer; |
|
- | 412 | } |
|
- | 413 | ||
- | 414 | void |
|
- | 415 | _pixman_radial_gradient_iter_init (pixman_image_t *image, pixman_iter_t *iter) |
|
- | 416 | { |
|
392 | { |
417 | if (iter->iter_flags & ITER_NARROW) |
- | 418 | iter->get_scanline = radial_get_scanline_narrow; |
|
393 | image->common.get_scanline_32 = radial_gradient_get_scanline_32; |
419 | else |
394 | image->common.get_scanline_64 = _pixman_image_get_scanline_generic_64; |
420 | iter->get_scanline = radial_get_scanline_wide; |
Line 395... | Line 421... | ||
395 | } |
421 | } |
396 | 422 | ||
397 | PIXMAN_EXPORT pixman_image_t * |
423 | PIXMAN_EXPORT pixman_image_t * |
398 | pixman_image_create_radial_gradient (pixman_point_fixed_t * inner, |
424 | pixman_image_create_radial_gradient (const pixman_point_fixed_t * inner, |
399 | pixman_point_fixed_t * outer, |
425 | const pixman_point_fixed_t * outer, |
400 | pixman_fixed_t inner_radius, |
426 | pixman_fixed_t inner_radius, |
401 | pixman_fixed_t outer_radius, |
427 | pixman_fixed_t outer_radius, |
402 | const pixman_gradient_stop_t *stops, |
428 | const pixman_gradient_stop_t *stops, |
Line 439... | Line 465... | ||
439 | if (radial->a != 0) |
465 | if (radial->a != 0) |
440 | radial->inva = 1. * pixman_fixed_1 / radial->a; |
466 | radial->inva = 1. * pixman_fixed_1 / radial->a; |
Line 441... | Line 467... | ||
441 | 467 | ||
Line 442... | Line -... | ||
442 | radial->mindr = -1. * pixman_fixed_1 * radial->c1.radius; |
- | |
443 | - | ||
444 | image->common.property_changed = radial_gradient_property_changed; |
468 | radial->mindr = -1. * pixman_fixed_1 * radial->c1.radius; |
445 | 469 | ||
446 | return image; |
- |