fix jsut committed crasher by rewriting startDrag action
[swfdec.git] / libswfdec / swfdec_pattern.c
blobae74a93bdfcbbf1967a0e1a28622f6a41b8bbc3b
1 /* Swfdec
2 * Copyright (C) 2006-2007 Benjamin Otte <otte@gnome.org>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301 USA
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
24 #include <math.h>
26 #include "swfdec_pattern.h"
27 #include "swfdec_bits.h"
28 #include "swfdec_color.h"
29 #include "swfdec_debug.h"
30 #include "swfdec_decoder.h"
31 #include "swfdec_image.h"
32 #include "swfdec_stroke.h"
34 /*** PATTERN ***/
36 G_DEFINE_ABSTRACT_TYPE (SwfdecPattern, swfdec_pattern, G_TYPE_OBJECT);
38 static void
39 swfdec_pattern_class_init (SwfdecPatternClass *klass)
43 static void
44 swfdec_pattern_init (SwfdecPattern *pattern)
46 cairo_matrix_init_identity (&pattern->start_transform);
47 cairo_matrix_init_identity (&pattern->end_transform);
50 /*** COLOR PATTERN ***/
52 typedef struct _SwfdecColorPattern SwfdecColorPattern;
53 typedef struct _SwfdecColorPatternClass SwfdecColorPatternClass;
55 #define SWFDEC_TYPE_COLOR_PATTERN (swfdec_color_pattern_get_type())
56 #define SWFDEC_IS_COLOR_PATTERN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SWFDEC_TYPE_COLOR_PATTERN))
57 #define SWFDEC_IS_COLOR_PATTERN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SWFDEC_TYPE_COLOR_PATTERN))
58 #define SWFDEC_COLOR_PATTERN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SWFDEC_TYPE_COLOR_PATTERN, SwfdecColorPattern))
59 #define SWFDEC_COLOR_PATTERN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SWFDEC_TYPE_COLOR_PATTERN, SwfdecColorPatternClass))
60 #define SWFDEC_COLOR_PATTERN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SWFDEC_TYPE_COLOR_PATTERN, SwfdecColorPatternClass))
62 struct _SwfdecColorPattern
64 SwfdecPattern pattern;
66 SwfdecColor start_color; /* color to paint with at the beginning */
67 SwfdecColor end_color; /* color to paint with in the end */
70 struct _SwfdecColorPatternClass
72 SwfdecPatternClass pattern_class;
75 GType swfdec_color_pattern_get_type (void);
76 G_DEFINE_TYPE (SwfdecColorPattern, swfdec_color_pattern, SWFDEC_TYPE_PATTERN);
78 static cairo_pattern_t *
79 swfdec_color_pattern_get_pattern (SwfdecPattern *pat,
80 const SwfdecColorTransform *trans, guint ratio)
82 SwfdecColorPattern *pattern = SWFDEC_COLOR_PATTERN (pat);
83 SwfdecColor color;
85 color = swfdec_color_apply_morph (pattern->start_color, pattern->end_color, ratio);
86 color = swfdec_color_apply_transform (color, trans);
87 return cairo_pattern_create_rgba (
88 SWFDEC_COLOR_R (color) / 255.0, SWFDEC_COLOR_G (color) / 255.0,
89 SWFDEC_COLOR_B (color) / 255.0, SWFDEC_COLOR_A (color) / 255.0);
92 static void
93 swfdec_color_pattern_class_init (SwfdecColorPatternClass *klass)
95 SWFDEC_PATTERN_CLASS (klass)->get_pattern = swfdec_color_pattern_get_pattern;
98 static void
99 swfdec_color_pattern_init (SwfdecColorPattern *pattern)
103 /*** IMAGE PATTERN ***/
105 typedef struct _SwfdecImagePattern SwfdecImagePattern;
106 typedef struct _SwfdecImagePatternClass SwfdecImagePatternClass;
108 #define SWFDEC_TYPE_IMAGE_PATTERN (swfdec_image_pattern_get_type())
109 #define SWFDEC_IS_IMAGE_PATTERN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SWFDEC_TYPE_IMAGE_PATTERN))
110 #define SWFDEC_IS_IMAGE_PATTERN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SWFDEC_TYPE_IMAGE_PATTERN))
111 #define SWFDEC_IMAGE_PATTERN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SWFDEC_TYPE_IMAGE_PATTERN, SwfdecImagePattern))
112 #define SWFDEC_IMAGE_PATTERN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SWFDEC_TYPE_IMAGE_PATTERN, SwfdecImagePatternClass))
113 #define SWFDEC_IMAGE_PATTERN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SWFDEC_TYPE_IMAGE_PATTERN, SwfdecImagePatternClass))
115 struct _SwfdecImagePattern
117 SwfdecPattern pattern;
119 SwfdecImage * image; /* image to paint */
120 cairo_extend_t extend;
121 cairo_filter_t filter;
124 struct _SwfdecImagePatternClass
126 SwfdecPatternClass pattern_class;
129 GType swfdec_image_pattern_get_type (void);
130 G_DEFINE_TYPE (SwfdecImagePattern, swfdec_image_pattern, SWFDEC_TYPE_PATTERN);
132 static cairo_pattern_t *
133 swfdec_image_pattern_get_pattern (SwfdecPattern *pat,
134 const SwfdecColorTransform *trans, guint ratio)
136 SwfdecImagePattern *image = SWFDEC_IMAGE_PATTERN (pat);
137 cairo_pattern_t *pattern;
138 cairo_matrix_t mat;
139 cairo_surface_t *surface;
141 surface = swfdec_image_create_surface_transformed (image->image, trans);
142 if (surface == NULL)
143 return NULL;
144 pattern = cairo_pattern_create_for_surface (surface);
145 cairo_surface_destroy (surface);
146 swfdec_matrix_morph (&mat, &pat->start_transform, &pat->end_transform, ratio);
147 cairo_pattern_set_matrix (pattern, &mat);
148 cairo_pattern_set_extend (pattern, image->extend);
149 cairo_pattern_set_filter (pattern, image->filter);
150 return pattern;
153 static void
154 swfdec_image_pattern_class_init (SwfdecImagePatternClass *klass)
156 SWFDEC_PATTERN_CLASS (klass)->get_pattern = swfdec_image_pattern_get_pattern;
159 static void
160 swfdec_image_pattern_init (SwfdecImagePattern *pattern)
164 /*** GRADIENT PATTERN ***/
166 typedef struct _SwfdecGradientPattern SwfdecGradientPattern;
167 typedef struct _SwfdecGradientPatternClass SwfdecGradientPatternClass;
169 #define SWFDEC_TYPE_GRADIENT_PATTERN (swfdec_gradient_pattern_get_type())
170 #define SWFDEC_IS_GRADIENT_PATTERN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SWFDEC_TYPE_GRADIENT_PATTERN))
171 #define SWFDEC_IS_GRADIENT_PATTERN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SWFDEC_TYPE_GRADIENT_PATTERN))
172 #define SWFDEC_GRADIENT_PATTERN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SWFDEC_TYPE_GRADIENT_PATTERN, SwfdecGradientPattern))
173 #define SWFDEC_GRADIENT_PATTERN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SWFDEC_TYPE_GRADIENT_PATTERN, SwfdecGradientPatternClass))
174 #define SWFDEC_GRADIENT_PATTERN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SWFDEC_TYPE_GRADIENT_PATTERN, SwfdecGradientPatternClass))
176 struct _SwfdecGradientPattern
178 SwfdecPattern pattern;
180 SwfdecGradient * gradient; /* gradient to paint */
181 gboolean radial; /* TRUE for radial gradient, FALSE for linear gradient */
182 gboolean morph; /* TRUE for morph gradients */
183 double focus; /* focus point */
186 struct _SwfdecGradientPatternClass
188 SwfdecPatternClass pattern_class;
191 GType swfdec_gradient_pattern_get_type (void);
192 G_DEFINE_TYPE (SwfdecGradientPattern, swfdec_gradient_pattern, SWFDEC_TYPE_PATTERN);
194 static cairo_pattern_t *
195 swfdec_gradient_pattern_get_pattern (SwfdecPattern *pat,
196 const SwfdecColorTransform *trans, guint ratio)
198 guint i;
199 cairo_pattern_t *pattern;
200 SwfdecColor color;
201 double offset;
202 SwfdecGradientPattern *gradient = SWFDEC_GRADIENT_PATTERN (pat);
204 #if 0
205 /* use this when https://bugs.freedesktop.org/show_bug.cgi?id=8341 is fixed */
206 if (gradient->radial)
207 pattern = cairo_pattern_create_radial (0, 0, 0, 0, 0, 16384);
208 else
209 pattern = cairo_pattern_create_linear (-16384.0, 0, 16384.0, 0);
210 cairo_pattern_set_matrix (pattern, &pat->transform);
211 #else
213 cairo_matrix_t mat;
214 swfdec_matrix_morph (&mat, &pat->start_transform, &pat->end_transform, ratio);
215 if (gradient->radial) {
216 pattern = cairo_pattern_create_radial ((16384.0 / 256.0) * gradient->focus,
217 0, 0, 0, 0, 16384 / 256.0);
218 } else {
219 pattern = cairo_pattern_create_linear (-16384.0 / 256.0, 0, 16384.0 / 256.0, 0);
221 cairo_matrix_scale (&mat, 1 / 256.0, 1 / 256.0);
222 mat.x0 /= 256.0;
223 mat.y0 /= 256.0;
224 cairo_pattern_set_matrix (pattern, &mat);
226 #endif
227 if (gradient->morph) {
228 for (i = 0; i < gradient->gradient->n_gradients; i += 2){
229 color = swfdec_color_apply_morph (gradient->gradient->array[i].color,
230 gradient->gradient->array[i + 1].color, ratio);
231 color = swfdec_color_apply_transform (color, trans);
232 offset = gradient->gradient->array[i].ratio * (65535 - ratio) +
233 gradient->gradient->array[i + 1].ratio * ratio;
234 offset /= 65535 * 255;
235 cairo_pattern_add_color_stop_rgba (pattern, offset,
236 SWFDEC_COLOR_R(color) / 255.0, SWFDEC_COLOR_G(color) / 255.0,
237 SWFDEC_COLOR_B(color) / 255.0, SWFDEC_COLOR_A(color) / 255.0);
239 } else {
240 for (i = 0; i < gradient->gradient->n_gradients; i++){
241 color = swfdec_color_apply_transform (gradient->gradient->array[i].color,
242 trans);
243 offset = gradient->gradient->array[i].ratio / 255.0;
244 cairo_pattern_add_color_stop_rgba (pattern, offset,
245 SWFDEC_COLOR_R(color) / 255.0, SWFDEC_COLOR_G(color) / 255.0,
246 SWFDEC_COLOR_B(color) / 255.0, SWFDEC_COLOR_A(color) / 255.0);
249 return pattern;
252 static void
253 swfdec_gradient_pattern_dispose (GObject *object)
255 SwfdecGradientPattern *gradient = SWFDEC_GRADIENT_PATTERN (object);
257 g_free (gradient->gradient);
258 gradient->gradient = NULL;
260 G_OBJECT_CLASS (swfdec_gradient_pattern_parent_class)->dispose (object);
263 static void
264 swfdec_gradient_pattern_class_init (SwfdecGradientPatternClass *klass)
266 G_OBJECT_CLASS (klass)->dispose = swfdec_gradient_pattern_dispose;
268 SWFDEC_PATTERN_CLASS (klass)->get_pattern = swfdec_gradient_pattern_get_pattern;
271 static void
272 swfdec_gradient_pattern_init (SwfdecGradientPattern *pattern)
276 /*** EXPORTED API ***/
278 static SwfdecPattern *
279 swfdec_pattern_do_parse (SwfdecSwfDecoder *dec, gboolean rgba)
281 guint paint_style_type;
282 SwfdecBits *bits;
283 SwfdecPattern *pattern;
285 bits = &dec->b;
286 paint_style_type = swfdec_bits_get_u8 (bits);
287 SWFDEC_LOG (" type 0x%02x", paint_style_type);
289 if (paint_style_type == 0x00) {
290 pattern = g_object_new (SWFDEC_TYPE_COLOR_PATTERN, NULL);
291 if (rgba) {
292 SWFDEC_COLOR_PATTERN (pattern)->start_color = swfdec_bits_get_rgba (bits);
293 } else {
294 SWFDEC_COLOR_PATTERN (pattern)->start_color = swfdec_bits_get_color (bits);
296 SWFDEC_COLOR_PATTERN (pattern)->end_color = SWFDEC_COLOR_PATTERN (pattern)->start_color;
297 SWFDEC_LOG (" color %08x", SWFDEC_COLOR_PATTERN (pattern)->start_color);
298 } else if (paint_style_type == 0x10 || paint_style_type == 0x12 || paint_style_type == 0x13) {
299 SwfdecGradientPattern *gradient;
300 pattern = g_object_new (SWFDEC_TYPE_GRADIENT_PATTERN, NULL);
301 gradient = SWFDEC_GRADIENT_PATTERN (pattern);
302 swfdec_bits_get_matrix (bits, &pattern->start_transform, NULL);
303 pattern->end_transform = pattern->start_transform;
304 if (rgba) {
305 gradient->gradient = swfdec_bits_get_gradient_rgba (bits);
306 } else {
307 gradient->gradient = swfdec_bits_get_gradient (bits);
309 gradient->radial = (paint_style_type != 0x10);
310 /* FIXME: need a way to ensure 0x13 only happens in Flash 8 */
311 if (paint_style_type == 0x13) {
312 gradient->focus = swfdec_bits_get_s16 (bits) / 256.0;
314 } else if (paint_style_type >= 0x40 && paint_style_type <= 0x43) {
315 guint paint_id = swfdec_bits_get_u16 (bits);
316 SWFDEC_LOG (" background paint id = %d (type 0x%02x)",
317 paint_id, paint_style_type);
318 if (paint_id == 65535) {
319 /* FIXME: someone explain this magic paint id here */
320 pattern = g_object_new (SWFDEC_TYPE_COLOR_PATTERN, NULL);
321 SWFDEC_COLOR_PATTERN (pattern)->start_color = SWFDEC_COLOR_COMBINE (0, 255, 255, 255);
322 SWFDEC_COLOR_PATTERN (pattern)->end_color = SWFDEC_COLOR_PATTERN (pattern)->start_color;
323 swfdec_bits_get_matrix (bits, &pattern->start_transform, NULL);
324 pattern->end_transform = pattern->start_transform;
325 } else {
326 pattern = g_object_new (SWFDEC_TYPE_IMAGE_PATTERN, NULL);
327 swfdec_bits_get_matrix (bits, &pattern->start_transform, NULL);
328 pattern->end_transform = pattern->start_transform;
329 SWFDEC_IMAGE_PATTERN (pattern)->image = swfdec_swf_decoder_get_character (dec, paint_id);
330 if (!SWFDEC_IS_IMAGE (SWFDEC_IMAGE_PATTERN (pattern)->image)) {
331 g_object_unref (pattern);
332 SWFDEC_ERROR ("could not find image with id %u for pattern", paint_id);
333 return NULL;
335 if (paint_style_type == 0x40 || paint_style_type == 0x42) {
336 SWFDEC_IMAGE_PATTERN (pattern)->extend = CAIRO_EXTEND_REPEAT;
337 } else {
338 #if 0
339 /* not implemented yet in cairo */
340 SWFDEC_IMAGE_PATTERN (pattern)->extend = CAIRO_EXTEND_PAD;
341 #else
342 SWFDEC_IMAGE_PATTERN (pattern)->extend = CAIRO_EXTEND_NONE;
343 #endif
345 if (paint_style_type == 0x40 || paint_style_type == 0x41) {
346 SWFDEC_IMAGE_PATTERN (pattern)->filter = CAIRO_FILTER_BILINEAR;
347 } else {
348 SWFDEC_IMAGE_PATTERN (pattern)->filter = CAIRO_FILTER_NEAREST;
351 } else {
352 SWFDEC_ERROR ("unknown paint style type 0x%02x", paint_style_type);
353 return NULL;
355 if (cairo_matrix_invert (&pattern->start_transform)) {
356 SWFDEC_ERROR ("paint transform matrix not invertible, resetting");
357 cairo_matrix_init_identity (&pattern->start_transform);
358 cairo_matrix_init_identity (&pattern->end_transform);
360 swfdec_bits_syncbits (bits);
361 return pattern;
365 * swfdec_pattern_parse:
366 * @dec: a #SwfdecDecoder to parse from
367 * @rgba: TRUE if colors are RGBA, FALSE if they're just RGB
369 * Continues parsing @dec into a new #SwfdecPattern
371 * Returns: a new #SwfdecPattern or NULL on error
373 SwfdecPattern *
374 swfdec_pattern_parse (SwfdecSwfDecoder *dec)
376 g_return_val_if_fail (dec != NULL, NULL);
378 return swfdec_pattern_do_parse (dec, FALSE);
381 SwfdecPattern *
382 swfdec_pattern_parse_rgba (SwfdecSwfDecoder *dec)
384 g_return_val_if_fail (dec != NULL, NULL);
386 return swfdec_pattern_do_parse (dec, TRUE);
390 * swfdec_pattern_parse_morph:
391 * @dec: a #SwfdecDecoder to parse from
393 * Continues parsing @dec into a new #SwfdecPattern. This function is used by
394 * morph shapes.
396 * Returns: a new #SwfdecPattern or NULL on error
398 SwfdecPattern *
399 swfdec_pattern_parse_morph (SwfdecSwfDecoder *dec)
401 guint paint_style_type;
402 SwfdecBits *bits;
403 SwfdecPattern *pattern;
405 g_return_val_if_fail (dec != NULL, NULL);
407 bits = &dec->b;
408 paint_style_type = swfdec_bits_get_u8 (bits);
409 SWFDEC_LOG (" type 0x%02x", paint_style_type);
411 if (paint_style_type == 0x00) {
412 pattern = g_object_new (SWFDEC_TYPE_COLOR_PATTERN, NULL);
413 SWFDEC_COLOR_PATTERN (pattern)->start_color = swfdec_bits_get_rgba (bits);
414 SWFDEC_COLOR_PATTERN (pattern)->end_color = swfdec_bits_get_rgba (bits);
415 SWFDEC_LOG (" color %08x => %08x", SWFDEC_COLOR_PATTERN (pattern)->start_color,
416 SWFDEC_COLOR_PATTERN (pattern)->end_color);
417 } else if (paint_style_type == 0x10 || paint_style_type == 0x12) {
418 pattern = g_object_new (SWFDEC_TYPE_GRADIENT_PATTERN, NULL);
419 swfdec_bits_get_matrix (bits, &pattern->start_transform, NULL);
420 swfdec_bits_get_matrix (bits, &pattern->end_transform, NULL);
421 SWFDEC_GRADIENT_PATTERN (pattern)->gradient = swfdec_bits_get_morph_gradient (bits);
422 SWFDEC_GRADIENT_PATTERN (pattern)->radial = (paint_style_type == 0x12);
423 SWFDEC_GRADIENT_PATTERN (pattern)->morph = TRUE;
424 } else if (paint_style_type >= 0x40 && paint_style_type <= 0x43) {
425 guint paint_id = swfdec_bits_get_u16 (bits);
426 SWFDEC_LOG (" background paint id = %d (type 0x%02x)",
427 paint_id, paint_style_type);
428 if (paint_id == 65535) {
429 /* FIXME: someone explain this magic paint id here */
430 pattern = g_object_new (SWFDEC_TYPE_COLOR_PATTERN, NULL);
431 SWFDEC_COLOR_PATTERN (pattern)->start_color = SWFDEC_COLOR_COMBINE (0, 255, 255, 255);
432 SWFDEC_COLOR_PATTERN (pattern)->end_color = SWFDEC_COLOR_PATTERN (pattern)->start_color;
433 swfdec_bits_get_matrix (bits, &pattern->start_transform, NULL);
434 swfdec_bits_get_matrix (bits, &pattern->end_transform, NULL);
435 } else {
436 pattern = g_object_new (SWFDEC_TYPE_IMAGE_PATTERN, NULL);
437 swfdec_bits_get_matrix (bits, &pattern->start_transform, NULL);
438 swfdec_bits_get_matrix (bits, &pattern->end_transform, NULL);
439 SWFDEC_IMAGE_PATTERN (pattern)->image = swfdec_swf_decoder_get_character (dec, paint_id);
440 if (!SWFDEC_IS_IMAGE (SWFDEC_IMAGE_PATTERN (pattern)->image)) {
441 g_object_unref (pattern);
442 SWFDEC_ERROR ("could not find image with id %u for pattern", paint_id);
443 return NULL;
445 if (paint_style_type == 0x40 || paint_style_type == 0x42) {
446 SWFDEC_IMAGE_PATTERN (pattern)->extend = CAIRO_EXTEND_REPEAT;
447 } else {
448 SWFDEC_IMAGE_PATTERN (pattern)->extend = CAIRO_EXTEND_NONE;
450 if (paint_style_type == 0x40 || paint_style_type == 0x41) {
451 SWFDEC_IMAGE_PATTERN (pattern)->filter = CAIRO_FILTER_BILINEAR;
452 } else {
453 SWFDEC_IMAGE_PATTERN (pattern)->filter = CAIRO_FILTER_NEAREST;
456 } else {
457 SWFDEC_ERROR ("unknown paint style type 0x%02x", paint_style_type);
458 return NULL;
460 if (cairo_matrix_invert (&pattern->start_transform)) {
461 SWFDEC_ERROR ("paint start transform matrix not invertible, resetting");
462 cairo_matrix_init_identity (&pattern->start_transform);
464 if (cairo_matrix_invert (&pattern->end_transform)) {
465 SWFDEC_ERROR ("paint end transform matrix not invertible, resetting");
466 cairo_matrix_init_identity (&pattern->end_transform);
468 swfdec_bits_syncbits (bits);
469 return pattern;
473 * swfdec_pattern_paint:
474 * @pattern: a #SwfdecPattern
475 * @cr: the context to paint
476 * @path: the path to paint
477 * @trans: color transformation to apply before painting
478 * @ratio: For morphshapes, the ratio to apply. Other objects should set this to 0.
480 * Fills the current path of @cr with the given @pattern.
482 void
483 swfdec_pattern_paint (SwfdecPattern *pattern, cairo_t *cr, const cairo_path_t *path,
484 const SwfdecColorTransform *trans, guint ratio)
486 cairo_pattern_t *cpattern;
488 g_return_if_fail (SWFDEC_IS_PATTERN (pattern));
489 g_return_if_fail (cr != NULL);
490 g_return_if_fail (path != NULL);
491 g_return_if_fail (trans != NULL);
492 g_return_if_fail (ratio < 65536);
494 cpattern = swfdec_pattern_get_pattern (pattern, trans, ratio);
495 if (cpattern == NULL)
496 return;
497 #if CAIRO_VERSION_MAJOR < 2 && CAIRO_VERSION_MINOR < 4
498 cairo_append_path (cr, (cairo_path_t *) path);
499 #else
500 cairo_append_path (cr, path);
501 #endif
502 cairo_set_source (cr, cpattern);
503 cairo_pattern_destroy (cpattern);
504 cairo_fill (cr);
508 * swfdec_pattern_new_color:
509 * @color: color to paint in
511 * Creates a new pattern to paint with the given color
513 * Returns: a new @SwfdecPattern to paint with
515 SwfdecPattern *
516 swfdec_pattern_new_color (SwfdecColor color)
518 SwfdecPattern *pattern = g_object_new (SWFDEC_TYPE_COLOR_PATTERN, NULL);
520 SWFDEC_COLOR_PATTERN (pattern)->start_color = color;
521 SWFDEC_COLOR_PATTERN (pattern)->end_color = color;
523 return pattern;
526 char *
527 swfdec_pattern_to_string (SwfdecPattern *pattern)
529 g_return_val_if_fail (SWFDEC_IS_PATTERN (pattern), NULL);
531 if (SWFDEC_IS_IMAGE_PATTERN (pattern)) {
532 SwfdecImagePattern *image = SWFDEC_IMAGE_PATTERN (pattern);
533 if (image->image->width == 0)
534 cairo_surface_destroy (swfdec_image_create_surface (image->image));
535 return g_strdup_printf ("%ux%u image %u (%s, %s)", image->image->width,
536 image->image->height, SWFDEC_CHARACTER (image->image)->id,
537 image->extend == CAIRO_EXTEND_REPEAT ? "repeat" : "no repeat",
538 image->filter == CAIRO_FILTER_BILINEAR ? "bilinear" : "nearest");
539 } else if (SWFDEC_IS_COLOR_PATTERN (pattern)) {
540 if (SWFDEC_COLOR_PATTERN (pattern)->start_color == SWFDEC_COLOR_PATTERN (pattern)->end_color)
541 return g_strdup_printf ("color #%08X", SWFDEC_COLOR_PATTERN (pattern)->start_color);
542 else
543 return g_strdup_printf ("color #%08X => #%08X", SWFDEC_COLOR_PATTERN (pattern)->start_color,
544 SWFDEC_COLOR_PATTERN (pattern)->end_color);
545 } else if (SWFDEC_IS_GRADIENT_PATTERN (pattern)) {
546 SwfdecGradientPattern *gradient = SWFDEC_GRADIENT_PATTERN (pattern);
547 return g_strdup_printf ("%s gradient (%u colors)", gradient->radial ? "radial" : "linear",
548 gradient->gradient->n_gradients);
549 } else {
550 return g_strdup_printf ("%s", G_OBJECT_TYPE_NAME (pattern));
554 static void
555 swfdec_path_get_extents (const cairo_path_t *path, SwfdecRect *extents, double line_width)
557 cairo_path_data_t *data = path->data;
558 int i;
559 double x = 0, y = 0;
560 gboolean need_current = TRUE;
561 gboolean start = TRUE;
562 #define ADD_POINT(rect, x, y) G_STMT_START{ \
563 if (rect->x0 > x + line_width) \
564 rect->x0 = x + line_width; \
565 if (rect->x1 < x - line_width) \
566 rect->x1 = x - line_width; \
567 if (rect->y0 > y + line_width) \
568 rect->y0 = y + line_width; \
569 if (rect->y1 < y - line_width) \
570 rect->y1 = y - line_width; \
571 }G_STMT_END
572 g_assert (line_width >= 0.0);
573 for (i = 0; i < path->num_data; i++) {
574 switch (data[i].header.type) {
575 case CAIRO_PATH_CURVE_TO:
576 if (need_current) {
577 if (start) {
578 start = FALSE;
579 extents->x0 = x - line_width;
580 extents->x1 = x + line_width;
581 extents->y0 = y - line_width;
582 extents->y1 = y + line_width;
583 } else {
584 ADD_POINT (extents, x, y);
586 need_current = FALSE;
588 ADD_POINT (extents, data[i+1].point.x, data[i+1].point.y);
589 ADD_POINT (extents, data[i+2].point.x, data[i+2].point.y);
590 ADD_POINT (extents, data[i+3].point.x, data[i+3].point.y);
591 i += 3;
592 break;
593 case CAIRO_PATH_LINE_TO:
594 if (need_current) {
595 if (start) {
596 start = FALSE;
597 extents->x0 = x - line_width;
598 extents->x1 = x + line_width;
599 extents->y0 = y - line_width;
600 extents->y1 = y + line_width;
601 } else {
602 ADD_POINT (extents, x, y);
604 need_current = FALSE;
606 ADD_POINT (extents, data[i+1].point.x, data[i+1].point.y);
607 i++;
608 break;
609 case CAIRO_PATH_CLOSE_PATH:
610 x = 0;
611 y = 0;
612 break;
613 case CAIRO_PATH_MOVE_TO:
614 x = data[i+1].point.x;
615 y = data[i+1].point.y;
616 i++;
617 break;
618 default:
619 g_assert_not_reached ();
622 #undef ADD_POINT
625 #define MAX_ALIGN 10
627 void
628 swfdec_pattern_get_path_extents (SwfdecPattern *pattern, const cairo_path_t *path, SwfdecRect *extents)
630 if (SWFDEC_IS_STROKE (pattern)) {
631 SwfdecStroke *stroke = SWFDEC_STROKE (pattern);
632 double line_width = MAX (stroke->start_width, stroke->end_width);
633 line_width = MAX (line_width, SWFDEC_TWIPS_SCALE_FACTOR);
634 swfdec_path_get_extents (path, extents, line_width / 2);
635 /* add offsets for pixel-alignment here */
636 extents->x0 -= MAX_ALIGN;
637 extents->y0 -= MAX_ALIGN;
638 extents->x1 += MAX_ALIGN;
639 extents->y1 += MAX_ALIGN;
640 } else {
641 swfdec_path_get_extents (path, extents, 0.0);
645 cairo_pattern_t *
646 swfdec_pattern_get_pattern (SwfdecPattern *pattern,
647 const SwfdecColorTransform *trans, guint ratio)
649 SwfdecPatternClass *klass;
651 g_return_val_if_fail (SWFDEC_IS_PATTERN (pattern), NULL);
652 g_return_val_if_fail (trans != NULL, NULL);
653 g_return_val_if_fail (ratio < 65536, NULL);
655 klass = SWFDEC_PATTERN_GET_CLASS (pattern);
656 g_assert (klass->get_pattern);
657 return klass->get_pattern (pattern, trans, ratio);