remove SWFDEC_IS_AS_VALUE check
[swfdec.git] / swfdec / swfdec_color.c
blob7bc86549dee86674300c7b41c2cbf47033fd264d
1 /* Swfdec
2 * Copyright (C) 2003-2006 David Schleef <ds@schleef.org>
3 * 2005-2006 Eric Anholt <eric@anholt.net>
4 * 2006-2007 Benjamin Otte <otte@gnome.org>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301 USA
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
26 #include <math.h>
27 #include "swfdec_color.h"
28 #include "swfdec_debug.h"
30 SwfdecColor
31 swfdec_color_apply_morph (SwfdecColor start, SwfdecColor end, guint ratio)
33 guint r, g, b, a;
34 guint start_ratio, end_ratio;
36 g_assert (ratio < 65536);
37 if (ratio == 0)
38 return start;
39 if (ratio == 65535)
40 return end;
41 start_ratio = 65535 - ratio;
42 end_ratio = ratio;
43 r = (SWFDEC_COLOR_RED (start) * start_ratio + SWFDEC_COLOR_RED (end) * end_ratio) / 65535;
44 g = (SWFDEC_COLOR_GREEN (start) * start_ratio + SWFDEC_COLOR_GREEN (end) * end_ratio) / 65535;
45 b = (SWFDEC_COLOR_BLUE (start) * start_ratio + SWFDEC_COLOR_BLUE (end) * end_ratio) / 65535;
46 a = (SWFDEC_COLOR_ALPHA (start) * start_ratio + SWFDEC_COLOR_ALPHA (end) * end_ratio) / 65535;
48 return SWFDEC_COLOR_COMBINE (r, g, b, a);
51 void
52 swfdec_color_set_source (cairo_t *cr, SwfdecColor color)
54 cairo_set_source_rgba (cr,
55 SWFDEC_COLOR_RED (color) / 255.0, SWFDEC_COLOR_GREEN (color) / 255.0,
56 SWFDEC_COLOR_BLUE (color) / 255.0, SWFDEC_COLOR_ALPHA (color) / 255.0);
59 SwfdecColor
60 swfdec_color_apply_transform_premultiplied (SwfdecColor in,
61 const SwfdecColorTransform * trans)
63 int r, g, b, a, aold;
65 if (trans->mask)
66 return SWFDEC_COLOR_COMBINE (0, 0, 0, 255);
68 aold = SWFDEC_COLOR_ALPHA (in);
69 if (aold == 0)
70 return 0;
72 r = SWFDEC_COLOR_RED (in);
73 g = SWFDEC_COLOR_GREEN (in);
74 b = SWFDEC_COLOR_BLUE (in);
76 a = (aold * trans->aa >> 8) + trans->ab;
77 a = CLAMP (a, 0, 255);
79 r = (r * trans->ra * a / aold >> 8) + trans->rb * a / 255;
80 r = CLAMP (r, 0, a);
81 g = (g * trans->ga * a / aold >> 8) + trans->gb * a / 255;
82 g = CLAMP (g, 0, a);
83 b = (b * trans->ba * a / aold >> 8) + trans->bb * a / 255;
84 b = CLAMP (b, 0, a);
86 return SWFDEC_COLOR_COMBINE (r, g, b, a);
89 SwfdecColor
90 swfdec_color_apply_transform (SwfdecColor in, const SwfdecColorTransform * trans)
92 int r, g, b, a;
94 if (trans->mask)
95 return SWFDEC_COLOR_COMBINE (0, 0, 0, 255);
97 r = SWFDEC_COLOR_RED (in);
98 g = SWFDEC_COLOR_GREEN (in);
99 b = SWFDEC_COLOR_BLUE (in);
100 a = SWFDEC_COLOR_ALPHA (in);
102 SWFDEC_LOG ("in rgba %d,%d,%d,%d", r, g, b, a);
104 r = (r * trans->ra >> 8) + trans->rb;
105 g = (g * trans->ga >> 8) + trans->gb;
106 b = (b * trans->ba >> 8) + trans->bb;
107 a = (a * trans->aa >> 8) + trans->ab;
109 r = CLAMP (r, 0, 255);
110 g = CLAMP (g, 0, 255);
111 b = CLAMP (b, 0, 255);
112 a = CLAMP (a, 0, 255);
114 SWFDEC_LOG ("out rgba %d,%d,%d,%d", r, g, b, a);
116 return SWFDEC_COLOR_COMBINE (r, g, b, a);
120 * swfdec_color_transform_init_identity:
121 * @trans: a #SwfdecColorTransform
123 * Initializes the color transform so it doesn't transform any colors.
125 void
126 swfdec_color_transform_init_identity (SwfdecColorTransform * trans)
128 g_return_if_fail (trans != NULL);
130 trans->mask = FALSE;
131 trans->ra = 256;
132 trans->ga = 256;
133 trans->ba = 256;
134 trans->aa = 256;
135 trans->rb = 0;
136 trans->gb = 0;
137 trans->bb = 0;
138 trans->ab = 0;
141 void
142 swfdec_color_transform_init_mask (SwfdecColorTransform *trans)
144 g_return_if_fail (trans != NULL);
146 trans->mask = TRUE;
147 /* don't init the other values so valgrind complains when they get accessed */
151 * swfdec_color_transform_init_color:
152 * @trans: a #SwfdecColorTransform
153 * @color: a #SwfdecColor to transform to
155 * Initializes this color transform so it results in exactly @color no matter
156 * the input.
158 void
159 swfdec_color_transform_init_color (SwfdecColorTransform *trans, SwfdecColor color)
161 trans->mask = FALSE;
162 trans->ra = 0;
163 trans->rb = SWFDEC_COLOR_RED (color);
164 trans->ga = 0;
165 trans->gb = SWFDEC_COLOR_GREEN (color);
166 trans->ba = 0;
167 trans->bb = SWFDEC_COLOR_BLUE (color);
168 trans->aa = 0;
169 trans->ab = SWFDEC_COLOR_ALPHA (color);
172 gboolean
173 swfdec_color_transform_is_identity (const SwfdecColorTransform * trans)
175 return trans->mask == FALSE &&
176 trans->ra == 256 && trans->ga == 256 && trans->ba == 256 && trans->aa == 256 &&
177 trans->rb == 0 && trans->gb == 0 && trans->bb == 0 && trans->ab == 0;
181 * swfdec_color_transform_is_alpha:
182 * @trans: a color transform
184 * Checks if the color transform is an alpha transform. Note that the identity
185 * transform is not considered an alpha transform.
187 * Returns: %TRUE if the color transform is an alpha transform
189 gboolean
190 swfdec_color_transform_is_alpha (const SwfdecColorTransform * trans)
192 return trans->mask == FALSE &&
193 trans->ra == 256 && trans->ga == 256 && trans->ba == 256 && trans->aa != 256 &&
194 trans->rb == 0 && trans->gb == 0 && trans->bb == 0 && trans->ab == 0;
198 * swfdec_color_transform_chain:
199 * @dest: #SwfdecColorTransform to take the result
200 * @last: a #SwfdecColorTransform
201 * @first: a #SwfdecColorTransform
203 * Computes a color transform that has the same effect as if the color
204 * transforms @first and @last would have been applied one after another.
206 void
207 swfdec_color_transform_chain (SwfdecColorTransform *dest,
208 const SwfdecColorTransform *last, const SwfdecColorTransform *first)
210 g_return_if_fail (dest != NULL);
211 g_return_if_fail (last != NULL);
212 g_return_if_fail (first != NULL);
213 g_return_if_fail (!last->mask);
215 if (first->mask) {
216 swfdec_color_transform_init_mask (dest);
217 return;
219 dest->mask = FALSE;
220 dest->ra = last->ra * first->ra >> 8;
221 dest->rb = (last->ra * first->rb >> 8) + last->rb;
222 dest->ga = last->ga * first->ga >> 8;
223 dest->gb = (last->ga * first->gb >> 8) + last->gb;
224 dest->ba = last->ba * first->ba >> 8;
225 dest->bb = (last->ba * first->bb >> 8) + last->bb;
226 dest->aa = last->aa * first->aa >> 8;
227 dest->ab = (last->aa * first->ab >> 8) + last->ab;
230 void
231 swfdec_matrix_ensure_invertible (cairo_matrix_t *matrix, cairo_matrix_t *inverse)
233 cairo_matrix_t tmp;
235 g_return_if_fail (matrix != NULL);
237 if (inverse == NULL)
238 inverse = &tmp;
240 g_assert (isfinite (matrix->xx) && isfinite (matrix->yx) && isfinite (matrix->xy) && isfinite (matrix->yy));
241 *inverse = *matrix;
242 while (cairo_matrix_invert (inverse)) {
243 SWFDEC_INFO ("matrix not invertible, adding epsilon to smallest member");
244 /* add epsilon at point closest to zero */
245 #define EPSILON (1.0 / SWFDEC_FIXED_SCALE_FACTOR)
246 if (ABS (matrix->xx) <= ABS (matrix->xy) &&
247 ABS (matrix->xx) <= ABS (matrix->yx) &&
248 ABS (matrix->xx) <= ABS (matrix->yy))
249 matrix->xx += (matrix->xx >= 0) ? EPSILON : -EPSILON;
250 else if (ABS (matrix->yy) <= ABS (matrix->xy) &&
251 ABS (matrix->yy) <= ABS (matrix->yx))
252 matrix->yy += (matrix->yy >= 0) ? EPSILON : -EPSILON;
253 else if (ABS (matrix->xy) <= ABS (matrix->yx))
254 matrix->xy += (matrix->xy >= 0) ? EPSILON : -EPSILON;
255 else
256 matrix->yx += (matrix->yx >= 0) ? EPSILON : -EPSILON;
257 *inverse = *matrix;
261 double
262 swfdec_matrix_get_xscale (const cairo_matrix_t *matrix)
264 double alpha;
266 if (matrix->xx) {
267 alpha = atan2 (matrix->yx, matrix->xx);
268 alpha = cos (alpha);
269 return matrix->xx / alpha * 100;
270 } else {
271 return matrix->yx * 100;
275 double
276 swfdec_matrix_get_yscale (const cairo_matrix_t *matrix)
278 double alpha;
280 if (matrix->yy) {
281 alpha = atan2 (matrix->xy, matrix->yy);
282 alpha = cos (alpha);
283 return matrix->yy / alpha * 100;
284 } else {
285 return matrix->xy * 100;
289 double
290 swfdec_matrix_get_rotation (const cairo_matrix_t *matrix)
292 return atan2 (matrix->yx, matrix->xx) * 180 / G_PI;
295 void
296 swfdec_matrix_morph (cairo_matrix_t *dest, const cairo_matrix_t *start,
297 const cairo_matrix_t *end, guint ratio)
299 guint inv_ratio = 65535 - ratio;
300 g_assert (ratio < 65536);
302 if (ratio == 0) {
303 *dest = *start;
304 return;
306 if (ratio == 65535) {
307 *dest = *end;
308 return;
310 dest->xx = (start->xx * inv_ratio + end->xx * ratio) / 65535;
311 dest->xy = (start->xy * inv_ratio + end->xy * ratio) / 65535;
312 dest->yy = (start->yy * inv_ratio + end->yy * ratio) / 65535;
313 dest->yx = (start->yx * inv_ratio + end->yx * ratio) / 65535;
314 dest->x0 = (start->x0 * inv_ratio + end->x0 * ratio) / 65535;
315 dest->y0 = (start->y0 * inv_ratio + end->y0 * ratio) / 65535;