Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1891 serge 1
/* -*- Mode: c; c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t; -*- */
2
/*
3
 * Copyright © 2000 SuSE, Inc.
4
 * Copyright © 2007 Red Hat, Inc.
5
 * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc.
6
 *             2005 Lars Knoll & Zack Rusin, Trolltech
7
 *
8
 * Permission to use, copy, modify, distribute, and sell this software and its
9
 * documentation for any purpose is hereby granted without fee, provided that
10
 * the above copyright notice appear in all copies and that both that
11
 * copyright notice and this permission notice appear in supporting
12
 * documentation, and that the name of Keith Packard not be used in
13
 * advertising or publicity pertaining to distribution of the software without
14
 * specific, written prior permission.  Keith Packard makes no
15
 * representations about the suitability of this software for any purpose.  It
16
 * is provided "as is" without express or implied warranty.
17
 *
18
 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
19
 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
20
 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
21
 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
22
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
23
 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
24
 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
25
 * SOFTWARE.
26
 */
27
 
28
#ifdef HAVE_CONFIG_H
29
#include 
30
#endif
31
#include 
32
#include "pixman-private.h"
33
 
34
static source_image_class_t
35
linear_gradient_classify (pixman_image_t *image,
36
                          int             x,
37
                          int             y,
38
                          int             width,
39
                          int             height)
40
{
41
    source_image_t *source = (source_image_t *)image;
42
    linear_gradient_t *linear = (linear_gradient_t *)image;
43
    pixman_vector_t v;
44
    pixman_fixed_32_32_t l;
45
    pixman_fixed_48_16_t dx, dy;
46
    double inc;
47
    source_image_class_t class;
48
 
49
    class = SOURCE_IMAGE_CLASS_UNKNOWN;
50
 
51
    if (source->common.transform)
52
    {
53
	/* projective transformation */
54
	if (source->common.transform->matrix[2][0] != 0 ||
55
	    source->common.transform->matrix[2][1] != 0 ||
56
	    source->common.transform->matrix[2][2] == 0)
57
	{
58
	    return class;
59
	}
60
 
61
	v.vector[0] = source->common.transform->matrix[0][1];
62
	v.vector[1] = source->common.transform->matrix[1][1];
63
	v.vector[2] = source->common.transform->matrix[2][2];
64
    }
65
    else
66
    {
67
	v.vector[0] = 0;
68
	v.vector[1] = pixman_fixed_1;
69
	v.vector[2] = pixman_fixed_1;
70
    }
71
 
72
    dx = linear->p2.x - linear->p1.x;
73
    dy = linear->p2.y - linear->p1.y;
74
 
75
    l = dx * dx + dy * dy;
76
 
77
    if (l == 0)
78
	return class;
79
 
80
    /*
81
     * compute how much the input of the gradient walked changes
82
     * when moving vertically through the whole image
83
     */
84
    inc = height * (double) pixman_fixed_1 * pixman_fixed_1 *
85
	(dx * v.vector[0] + dy * v.vector[1]) /
86
	(v.vector[2] * (double) l);
87
 
88
    /* check that casting to integer would result in 0 */
89
    if (-1 < inc && inc < 1)
90
	class = SOURCE_IMAGE_CLASS_HORIZONTAL;
91
 
92
    return class;
93
}
94
 
95
static void
96
linear_gradient_get_scanline_32 (pixman_image_t *image,
97
                                 int             x,
98
                                 int             y,
99
                                 int             width,
100
                                 uint32_t *      buffer,
101
                                 const uint32_t *mask)
102
{
103
    pixman_vector_t v, unit;
104
    pixman_fixed_32_32_t l;
105
    pixman_fixed_48_16_t dx, dy;
106
    gradient_t *gradient = (gradient_t *)image;
107
    source_image_t *source = (source_image_t *)image;
108
    linear_gradient_t *linear = (linear_gradient_t *)image;
109
    uint32_t *end = buffer + width;
110
    pixman_gradient_walker_t walker;
111
 
112
    _pixman_gradient_walker_init (&walker, gradient, source->common.repeat);
113
 
114
    /* reference point is the center of the pixel */
115
    v.vector[0] = pixman_int_to_fixed (x) + pixman_fixed_1 / 2;
116
    v.vector[1] = pixman_int_to_fixed (y) + pixman_fixed_1 / 2;
117
    v.vector[2] = pixman_fixed_1;
118
 
119
    if (source->common.transform)
120
    {
121
	if (!pixman_transform_point_3d (source->common.transform, &v))
122
	    return;
123
 
124
	unit.vector[0] = source->common.transform->matrix[0][0];
125
	unit.vector[1] = source->common.transform->matrix[1][0];
126
	unit.vector[2] = source->common.transform->matrix[2][0];
127
    }
128
    else
129
    {
130
	unit.vector[0] = pixman_fixed_1;
131
	unit.vector[1] = 0;
132
	unit.vector[2] = 0;
133
    }
134
 
135
    dx = linear->p2.x - linear->p1.x;
136
    dy = linear->p2.y - linear->p1.y;
137
 
138
    l = dx * dx + dy * dy;
139
 
140
    if (l == 0 || unit.vector[2] == 0)
141
    {
142
	/* affine transformation only */
143
        pixman_fixed_32_32_t t, next_inc;
144
	double inc;
145
 
146
	if (l == 0 || v.vector[2] == 0)
147
	{
148
	    t = 0;
149
	    inc = 0;
150
	}
151
	else
152
	{
153
	    double invden, v2;
154
 
155
	    invden = pixman_fixed_1 * (double) pixman_fixed_1 /
156
		(l * (double) v.vector[2]);
157
	    v2 = v.vector[2] * (1. / pixman_fixed_1);
158
	    t = ((dx * v.vector[0] + dy * v.vector[1]) -
159
		 (dx * linear->p1.x + dy * linear->p1.y) * v2) * invden;
160
	    inc = (dx * unit.vector[0] + dy * unit.vector[1]) * invden;
161
	}
162
	next_inc = 0;
163
 
164
	if (((pixman_fixed_32_32_t )(inc * width)) == 0)
165
	{
166
	    register uint32_t color;
167
 
168
	    color = _pixman_gradient_walker_pixel (&walker, t);
169
	    while (buffer < end)
170
		*buffer++ = color;
171
	}
172
	else
173
	{
174
	    int i;
175
 
176
	    i = 0;
177
	    while (buffer < end)
178
	    {
179
		if (!mask || *mask++)
180
		{
181
		    *buffer = _pixman_gradient_walker_pixel (&walker,
182
							     t + next_inc);
183
		}
184
		i++;
185
		next_inc = inc * i;
186
		buffer++;
187
	    }
188
	}
189
    }
190
    else
191
    {
192
	/* projective transformation */
193
        double t;
194
 
195
	t = 0;
196
 
197
	while (buffer < end)
198
	{
199
	    if (!mask || *mask++)
200
	    {
201
	        if (v.vector[2] != 0)
202
		{
203
		    double invden, v2;
204
 
205
		    invden = pixman_fixed_1 * (double) pixman_fixed_1 /
206
			(l * (double) v.vector[2]);
207
		    v2 = v.vector[2] * (1. / pixman_fixed_1);
208
		    t = ((dx * v.vector[0] + dy * v.vector[1]) -
209
			 (dx * linear->p1.x + dy * linear->p1.y) * v2) * invden;
210
		}
211
 
212
		*buffer = _pixman_gradient_walker_pixel (&walker, t);
213
	    }
214
 
215
	    ++buffer;
216
 
217
	    v.vector[0] += unit.vector[0];
218
	    v.vector[1] += unit.vector[1];
219
	    v.vector[2] += unit.vector[2];
220
	}
221
    }
222
}
223
 
224
static void
225
linear_gradient_property_changed (pixman_image_t *image)
226
{
227
    image->common.get_scanline_32 = linear_gradient_get_scanline_32;
228
    image->common.get_scanline_64 = _pixman_image_get_scanline_generic_64;
229
}
230
 
231
PIXMAN_EXPORT pixman_image_t *
232
pixman_image_create_linear_gradient (pixman_point_fixed_t *        p1,
233
                                     pixman_point_fixed_t *        p2,
234
                                     const pixman_gradient_stop_t *stops,
235
                                     int                           n_stops)
236
{
237
    pixman_image_t *image;
238
    linear_gradient_t *linear;
239
 
240
    image = _pixman_image_allocate ();
241
 
242
    if (!image)
243
	return NULL;
244
 
245
    linear = &image->linear;
246
 
247
    if (!_pixman_init_gradient (&linear->common, stops, n_stops))
248
    {
249
	free (image);
250
	return NULL;
251
    }
252
 
253
    linear->p1 = *p1;
254
    linear->p2 = *p2;
255
 
256
    image->type = LINEAR;
257
    image->common.classify = linear_gradient_classify;
258
    image->common.property_changed = linear_gradient_property_changed;
259
 
260
    return image;
261
}
262