Subversion Repositories Kolibri OS

Rev

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;
-