Subversion Repositories Kolibri OS

Rev

Rev 1891 | Go to most recent revision | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 1891 Rev 3931
1
/* -*- Mode: c; c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t; -*- */
1
/* -*- Mode: c; c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t; -*- */
2
/*
2
/*
3
 *
3
 *
4
 * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc.
4
 * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc.
5
 * Copyright © 2000 SuSE, Inc.
5
 * Copyright © 2000 SuSE, Inc.
6
 *             2005 Lars Knoll & Zack Rusin, Trolltech
6
 *             2005 Lars Knoll & Zack Rusin, Trolltech
7
 * Copyright © 2007 Red Hat, Inc.
7
 * Copyright © 2007 Red Hat, Inc.
8
 *
8
 *
9
 *
9
 *
10
 * Permission to use, copy, modify, distribute, and sell this software and its
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
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
12
 * the above copyright notice appear in all copies and that both that
13
 * copyright notice and this permission notice appear in supporting
13
 * copyright notice and this permission notice appear in supporting
14
 * documentation, and that the name of Keith Packard not be used in
14
 * documentation, and that the name of Keith Packard not be used in
15
 * advertising or publicity pertaining to distribution of the software without
15
 * advertising or publicity pertaining to distribution of the software without
16
 * specific, written prior permission.  Keith Packard makes no
16
 * specific, written prior permission.  Keith Packard makes no
17
 * representations about the suitability of this software for any purpose.  It
17
 * representations about the suitability of this software for any purpose.  It
18
 * is provided "as is" without express or implied warranty.
18
 * is provided "as is" without express or implied warranty.
19
 *
19
 *
20
 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
20
 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
21
 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
21
 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
22
 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
22
 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
23
 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
23
 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
24
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
24
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
25
 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
25
 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
26
 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
26
 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
27
 * SOFTWARE.
27
 * SOFTWARE.
28
 */
28
 */
29
 
29
 
30
#ifdef HAVE_CONFIG_H
30
#ifdef HAVE_CONFIG_H
31
#include 
31
#include 
32
#endif
32
#endif
33
#include 
33
#include 
34
#include 
34
#include 
35
#include "pixman-private.h"
35
#include "pixman-private.h"
36
 
36
 
37
static inline pixman_fixed_32_32_t
37
static inline pixman_fixed_32_32_t
38
dot (pixman_fixed_48_16_t x1,
38
dot (pixman_fixed_48_16_t x1,
39
     pixman_fixed_48_16_t y1,
39
     pixman_fixed_48_16_t y1,
40
     pixman_fixed_48_16_t z1,
40
     pixman_fixed_48_16_t z1,
41
     pixman_fixed_48_16_t x2,
41
     pixman_fixed_48_16_t x2,
42
     pixman_fixed_48_16_t y2,
42
     pixman_fixed_48_16_t y2,
43
     pixman_fixed_48_16_t z2)
43
     pixman_fixed_48_16_t z2)
44
{
44
{
45
    /*
45
    /*
46
     * Exact computation, assuming that the input values can
46
     * Exact computation, assuming that the input values can
47
     * be represented as pixman_fixed_16_16_t
47
     * be represented as pixman_fixed_16_16_t
48
     */
48
     */
49
    return x1 * x2 + y1 * y2 + z1 * z2;
49
    return x1 * x2 + y1 * y2 + z1 * z2;
50
}
50
}
51
 
51
 
52
static inline double
52
static inline double
53
fdot (double x1,
53
fdot (double x1,
54
      double y1,
54
      double y1,
55
      double z1,
55
      double z1,
56
      double x2,
56
      double x2,
57
      double y2,
57
      double y2,
58
      double z2)
58
      double z2)
59
{
59
{
60
    /*
60
    /*
61
     * Error can be unbound in some special cases.
61
     * Error can be unbound in some special cases.
62
     * Using clever dot product algorithms (for example compensated
62
     * Using clever dot product algorithms (for example compensated
63
     * dot product) would improve this but make the code much less
63
     * dot product) would improve this but make the code much less
64
     * obvious
64
     * obvious
65
     */
65
     */
66
    return x1 * x2 + y1 * y2 + z1 * z2;
66
    return x1 * x2 + y1 * y2 + z1 * z2;
67
}
67
}
68
 
68
 
69
static uint32_t
69
static uint32_t
70
radial_compute_color (double                    a,
70
radial_compute_color (double                    a,
71
		      double                    b,
71
		      double                    b,
72
		      double                    c,
72
		      double                    c,
73
		      double                    inva,
73
		      double                    inva,
74
		      double                    dr,
74
		      double                    dr,
75
		      double                    mindr,
75
		      double                    mindr,
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;
96
 
96
 
97
    if (a == 0)
97
    if (a == 0)
98
    {
98
    {
99
	double t;
99
	double t;
100
 
100
 
101
	if (b == 0)
101
	if (b == 0)
102
	    return 0;
102
	    return 0;
103
 
103
 
104
	t = pixman_fixed_1 / 2 * c / b;
104
	t = pixman_fixed_1 / 2 * c / b;
105
	if (repeat == PIXMAN_REPEAT_NONE)
105
	if (repeat == PIXMAN_REPEAT_NONE)
106
	{
106
	{
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
	}
115
 
115
 
116
	return 0;
116
	return 0;
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)
121
    {
121
    {
122
	double sqrtdet, t0, t1;
122
	double sqrtdiscr, t0, t1;
123
 
123
 
124
	sqrtdet = sqrt (det);
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.
-
 
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);
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);
141
	}
152
	}
142
    }
153
    }
143
 
154
 
144
    return 0;
155
    return 0;
145
}
156
}
146
 
157
 
147
static void
158
static uint32_t *
148
radial_gradient_get_scanline_32 (pixman_image_t *image,
-
 
149
                                 int             x,
-
 
150
                                 int             y,
-
 
151
                                 int             width,
-
 
152
                                 uint32_t *      buffer,
-
 
153
                                 const uint32_t *mask)
159
radial_get_scanline_narrow (pixman_iter_t *iter, const uint32_t *mask)
154
{
160
{
155
    /*
161
    /*
156
     * Implementation of radial gradients following the PDF specification.
162
     * Implementation of radial gradients following the PDF specification.
157
     * See section 8.7.4.5.4 Type 3 (Radial) Shadings of the PDF Reference
163
     * See section 8.7.4.5.4 Type 3 (Radial) Shadings of the PDF Reference
158
     * Manual (PDF 32000-1:2008 at the time of this writing).
164
     * Manual (PDF 32000-1:2008 at the time of this writing).
159
     * 
165
     *
160
     * In the radial gradient problem we are given two circles (c₁,r₁) and
166
     * In the radial gradient problem we are given two circles (c₁,r₁) and
161
     * (c₂,r₂) that define the gradient itself.
167
     * (c₂,r₂) that define the gradient itself.
162
     *
168
     *
163
     * Mathematically the gradient can be defined as the family of circles
169
     * Mathematically the gradient can be defined as the family of circles
164
     *
170
     *
165
     *     ((1-t)·c₁ + t·(c₂), (1-t)·r₁ + t·r₂)
171
     *     ((1-t)·c₁ + t·(c₂), (1-t)·r₁ + t·r₂)
166
     *
172
     *
167
     * excluding those circles whose radius would be < 0. When a point
173
     * excluding those circles whose radius would be < 0. When a point
168
     * belongs to more than one circle, the one with a bigger t is the only
174
     * belongs to more than one circle, the one with a bigger t is the only
169
     * one that contributes to its color. When a point does not belong
175
     * one that contributes to its color. When a point does not belong
170
     * to any of the circles, it is transparent black, i.e. RGBA (0, 0, 0, 0).
176
     * to any of the circles, it is transparent black, i.e. RGBA (0, 0, 0, 0).
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.
182
     *
188
     *
183
     * What we actually do is, given the point whose color we are interested
189
     * What we actually do is, given the point whose color we are interested
184
     * in, compute the t values for that point, solving for t in:
190
     * in, compute the t values for that point, solving for t in:
185
     *
191
     *
186
     *     length((1-t)·c₁ + t·(c₂) - p) = (1-t)·r₁ + t·r₂
192
     *     length((1-t)·c₁ + t·(c₂) - p) = (1-t)·r₁ + t·r₂
187
     * 
193
     *
188
     * Let's rewrite it in a simpler way, by defining some auxiliary
194
     * Let's rewrite it in a simpler way, by defining some auxiliary
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
     *
200
     * or
206
     * or
201
     *
207
     *
202
     *     ⎷((t·cdx - pdx)² + (t·cdy - pdy)²) = r₁ + t·dr.
208
     *     ⎷((t·cdx - pdx)² + (t·cdy - pdy)²) = r₁ + t·dr.
203
     *
209
     *
204
     * If we impose (as stated earlier) that r₁ + t·dr >= 0, it becomes:
210
     * If we impose (as stated earlier) that r₁ + t·dr >= 0, it becomes:
205
     *
211
     *
206
     *     (t·cdx - pdx)² + (t·cdy - pdy)² = (r₁ + t·dr)²
212
     *     (t·cdx - pdx)² + (t·cdy - pdy)² = (r₁ + t·dr)²
207
     *
213
     *
208
     * where we can actually expand the squares and solve for t:
214
     * where we can actually expand the squares and solve for t:
209
     *
215
     *
210
     *     t²cdx² - 2t·cdx·pdx + pdx² + t²cdy² - 2t·cdy·pdy + pdy² =
216
     *     t²cdx² - 2t·cdx·pdx + pdx² + t²cdy² - 2t·cdy·pdy + pdy² =
211
     *       = r₁² + 2·r₁·t·dr + t²·dr²
217
     *       = r₁² + 2·r₁·t·dr + t²·dr²
212
     *
218
     *
213
     *     (cdx² + cdy² - dr²)t² - 2(cdx·pdx + cdy·pdy + r₁·dr)t +
219
     *     (cdx² + cdy² - dr²)t² - 2(cdx·pdx + cdy·pdy + r₁·dr)t +
214
     *         (pdx² + pdy² - r₁²) = 0
220
     *         (pdx² + pdy² - r₁²) = 0
215
     *
221
     *
216
     *     A = cdx² + cdy² - dr²
222
     *     A = cdx² + cdy² - dr²
217
     *     B = pdx·cdx + pdy·cdy + r₁·dr
223
     *     B = pdx·cdx + pdy·cdy + r₁·dr
218
     *     C = pdx² + pdy² - r₁²
224
     *     C = pdx² + pdy² - r₁²
219
     *     At² - 2Bt + C = 0
225
     *     At² - 2Bt + C = 0
220
     * 
226
     *
221
     * The solutions (unless the equation degenerates because of A = 0) are:
227
     * The solutions (unless the equation degenerates because of A = 0) are:
222
     *
228
     *
223
     *     t = (B ± ⎷(B² - A·C)) / A
229
     *     t = (B ± ⎷(B² - A·C)) / A
224
     *
230
     *
225
     * The solution we are going to prefer is the bigger one, unless the
231
     * The solution we are going to prefer is the bigger one, unless the
226
     * radius associated to it is negative (or it falls outside the valid t
232
     * radius associated to it is negative (or it falls outside the valid t
227
     * range).
233
     * range).
228
     *
234
     *
229
     * Additional observations (useful for optimizations):
235
     * Additional observations (useful for optimizations):
230
     * A does not depend on p
236
     * A does not depend on p
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;
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;
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;
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;
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
 
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];
259
    }
269
    }
260
    else
270
    else
261
    {
271
    {
262
	unit.vector[0] = pixman_fixed_1;
272
	unit.vector[0] = pixman_fixed_1;
263
	unit.vector[1] = 0;
273
	unit.vector[1] = 0;
264
	unit.vector[2] = 0;
274
	unit.vector[2] = 0;
265
    }
275
    }
266
 
276
 
267
    if (unit.vector[2] == 0 && v.vector[2] == pixman_fixed_1)
277
    if (unit.vector[2] == 0 && v.vector[2] == pixman_fixed_1)
268
    {
278
    {
269
	/*
279
	/*
270
	 * Given:
280
	 * Given:
271
	 *
281
	 *
272
	 * t = (B ± ⎷(B² - A·C)) / A
282
	 * t = (B ± ⎷(B² - A·C)) / A
273
	 *
283
	 *
274
	 * where
284
	 * where
275
	 *
285
	 *
276
	 * A = cdx² + cdy² - dr²
286
	 * A = cdx² + cdy² - dr²
277
	 * B = pdx·cdx + pdy·cdy + r₁·dr
287
	 * B = pdx·cdx + pdy·cdy + r₁·dr
278
	 * C = pdx² + pdy² - r₁²
288
	 * C = pdx² + pdy² - r₁²
279
	 * det = B² - A·C
289
	 * det = B² - A·C
280
	 *
290
	 *
281
	 * Since we have an affine transformation, we know that (pdx, pdy)
291
	 * Since we have an affine transformation, we know that (pdx, pdy)
282
	 * increase linearly with each pixel,
292
	 * increase linearly with each pixel,
283
	 *
293
	 *
284
	 * pdx = pdx₀ + n·ux,
294
	 * pdx = pdx₀ + n·ux,
285
	 * pdy = pdy₀ + n·uy,
295
	 * pdy = pdy₀ + n·uy,
286
	 *
296
	 *
287
	 * we can then express B, C and det through multiple differentiation.
297
	 * we can then express B, C and det through multiple differentiation.
288
	 */
298
	 */
289
	pixman_fixed_32_32_t b, db, c, dc, ddc;
299
	pixman_fixed_32_32_t b, db, c, dc, ddc;
290
 
300
 
291
	/* warning: this computation may overflow */
301
	/* warning: this computation may overflow */
292
	v.vector[0] -= radial->c1.x;
302
	v.vector[0] -= radial->c1.x;
293
	v.vector[1] -= radial->c1.y;
303
	v.vector[1] -= radial->c1.y;
294
 
304
 
295
	/*
305
	/*
296
	 * B and C are computed and updated exactly.
306
	 * B and C are computed and updated exactly.
297
	 * If fdot was used instead of dot, in the worst case it would
307
	 * If fdot was used instead of dot, in the worst case it would
298
	 * lose 11 bits of precision in each of the multiplication and
308
	 * lose 11 bits of precision in each of the multiplication and
299
	 * summing up would zero out all the bit that were preserved,
309
	 * summing up would zero out all the bit that were preserved,
300
	 * thus making the result 0 instead of the correct one.
310
	 * thus making the result 0 instead of the correct one.
301
	 * This would mean a worst case of unbound relative error or
311
	 * This would mean a worst case of unbound relative error or
302
	 * about 2^10 absolute error
312
	 * about 2^10 absolute error
303
	 */
313
	 */
304
	b = dot (v.vector[0], v.vector[1], radial->c1.radius,
314
	b = dot (v.vector[0], v.vector[1], radial->c1.radius,
305
		 radial->delta.x, radial->delta.y, radial->delta.radius);
315
		 radial->delta.x, radial->delta.y, radial->delta.radius);
306
	db = dot (unit.vector[0], unit.vector[1], 0,
316
	db = dot (unit.vector[0], unit.vector[1], 0,
307
		  radial->delta.x, radial->delta.y, 0);
317
		  radial->delta.x, radial->delta.y, 0);
308
 
318
 
309
	c = dot (v.vector[0], v.vector[1],
319
	c = dot (v.vector[0], v.vector[1],
310
		 -((pixman_fixed_48_16_t) radial->c1.radius),
320
		 -((pixman_fixed_48_16_t) radial->c1.radius),
311
		 v.vector[0], v.vector[1], radial->c1.radius);
321
		 v.vector[0], v.vector[1], radial->c1.radius);
312
	dc = dot (2 * (pixman_fixed_48_16_t) v.vector[0] + unit.vector[0],
322
	dc = dot (2 * (pixman_fixed_48_16_t) v.vector[0] + unit.vector[0],
313
		  2 * (pixman_fixed_48_16_t) v.vector[1] + unit.vector[1],
323
		  2 * (pixman_fixed_48_16_t) v.vector[1] + unit.vector[1],
314
		  0,
324
		  0,
315
		  unit.vector[0], unit.vector[1], 0);
325
		  unit.vector[0], unit.vector[1], 0);
316
	ddc = 2 * dot (unit.vector[0], unit.vector[1], 0,
326
	ddc = 2 * dot (unit.vector[0], unit.vector[1], 0,
317
		       unit.vector[0], unit.vector[1], 0);
327
		       unit.vector[0], unit.vector[1], 0);
318
 
328
 
319
	while (buffer < end)
329
	while (buffer < end)
320
	{
330
	{
321
	    if (!mask || *mask++)
331
	    if (!mask || *mask++)
322
	    {
332
	    {
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
	    }
330
 
340
 
331
	    b += db;
341
	    b += db;
332
	    c += dc;
342
	    c += dc;
333
	    dc += ddc;
343
	    dc += ddc;
334
	    ++buffer;
344
	    ++buffer;
335
	}
345
	}
336
    }
346
    }
337
    else
347
    else
338
    {
348
    {
339
	/* projective */
349
	/* projective */
340
	/* Warning:
350
	/* Warning:
341
	 * error propagation guarantees are much looser than in the affine case
351
	 * error propagation guarantees are much looser than in the affine case
342
	 */
352
	 */
343
	while (buffer < end)
353
	while (buffer < end)
344
	{
354
	{
345
	    if (!mask || *mask++)
355
	    if (!mask || *mask++)
346
	    {
356
	    {
347
		if (v.vector[2] != 0)
357
		if (v.vector[2] != 0)
348
		{
358
		{
349
		    double pdx, pdy, invv2, b, c;
359
		    double pdx, pdy, invv2, b, c;
350
 
360
 
351
		    invv2 = 1. * pixman_fixed_1 / v.vector[2];
361
		    invv2 = 1. * pixman_fixed_1 / v.vector[2];
352
 
362
 
353
		    pdx = v.vector[0] * invv2 - radial->c1.x;
363
		    pdx = v.vector[0] * invv2 - radial->c1.x;
354
		    /*    / pixman_fixed_1 */
364
		    /*    / pixman_fixed_1 */
355
 
365
 
356
		    pdy = v.vector[1] * invv2 - radial->c1.y;
366
		    pdy = v.vector[1] * invv2 - radial->c1.y;
357
		    /*    / pixman_fixed_1 */
367
		    /*    / pixman_fixed_1 */
358
 
368
 
359
		    b = fdot (pdx, pdy, radial->c1.radius,
369
		    b = fdot (pdx, pdy, radial->c1.radius,
360
			      radial->delta.x, radial->delta.y,
370
			      radial->delta.x, radial->delta.y,
361
			      radial->delta.radius);
371
			      radial->delta.radius);
362
		    /*  / pixman_fixed_1 / pixman_fixed_1 */
372
		    /*  / pixman_fixed_1 / pixman_fixed_1 */
363
 
373
 
364
		    c = fdot (pdx, pdy, -radial->c1.radius,
374
		    c = fdot (pdx, pdy, -radial->c1.radius,
365
			      pdx, pdy, radial->c1.radius);
375
			      pdx, pdy, radial->c1.radius);
366
		    /*  / pixman_fixed_1 / pixman_fixed_1 */
376
		    /*  / pixman_fixed_1 / pixman_fixed_1 */
367
 
377
 
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
		}
379
	    }
389
	    }
380
	    
390
 
381
	    ++buffer;
391
	    ++buffer;
382
 
392
 
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
}
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;
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,
403
                                     int                           n_stops)
429
                                     int                           n_stops)
404
{
430
{
405
    pixman_image_t *image;
431
    pixman_image_t *image;
406
    radial_gradient_t *radial;
432
    radial_gradient_t *radial;
407
 
433
 
408
    image = _pixman_image_allocate ();
434
    image = _pixman_image_allocate ();
409
 
435
 
410
    if (!image)
436
    if (!image)
411
	return NULL;
437
	return NULL;
412
 
438
 
413
    radial = &image->radial;
439
    radial = &image->radial;
414
 
440
 
415
    if (!_pixman_init_gradient (&radial->common, stops, n_stops))
441
    if (!_pixman_init_gradient (&radial->common, stops, n_stops))
416
    {
442
    {
417
	free (image);
443
	free (image);
418
	return NULL;
444
	return NULL;
419
    }
445
    }
420
 
446
 
421
    image->type = RADIAL;
447
    image->type = RADIAL;
422
 
448
 
423
    radial->c1.x = inner->x;
449
    radial->c1.x = inner->x;
424
    radial->c1.y = inner->y;
450
    radial->c1.y = inner->y;
425
    radial->c1.radius = inner_radius;
451
    radial->c1.radius = inner_radius;
426
    radial->c2.x = outer->x;
452
    radial->c2.x = outer->x;
427
    radial->c2.y = outer->y;
453
    radial->c2.y = outer->y;
428
    radial->c2.radius = outer_radius;
454
    radial->c2.radius = outer_radius;
429
 
455
 
430
    /* warning: this computations may overflow */
456
    /* warning: this computations may overflow */
431
    radial->delta.x = radial->c2.x - radial->c1.x;
457
    radial->delta.x = radial->c2.x - radial->c1.x;
432
    radial->delta.y = radial->c2.y - radial->c1.y;
458
    radial->delta.y = radial->c2.y - radial->c1.y;
433
    radial->delta.radius = radial->c2.radius - radial->c1.radius;
459
    radial->delta.radius = radial->c2.radius - radial->c1.radius;
434
 
460
 
435
    /* computed exactly, then cast to double -> every bit of the double
461
    /* computed exactly, then cast to double -> every bit of the double
436
       representation is correct (53 bits) */
462
       representation is correct (53 bits) */
437
    radial->a = dot (radial->delta.x, radial->delta.y, -radial->delta.radius,
463
    radial->a = dot (radial->delta.x, radial->delta.y, -radial->delta.radius,
438
		     radial->delta.x, radial->delta.y, radial->delta.radius);
464
		     radial->delta.x, radial->delta.y, radial->delta.radius);
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;
441
 
467
 
442
    radial->mindr = -1. * pixman_fixed_1 * radial->c1.radius;
468
    radial->mindr = -1. * pixman_fixed_1 * radial->c1.radius;
443
 
-
 
444
    image->common.property_changed = radial_gradient_property_changed;
-
 
445
 
469
 
446
    return image;
470
    return image;
447
}
-
 
-
 
471
}