Bug 22803 - Make header conform to implementation
[swfdec.git] / swfdec / swfdec_pattern.c
blobe2f6e873e489e98a91c6d4cc2aceb8e4af0d08b8
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_gradient_pattern.h"
32 #include "swfdec_image.h"
33 #include "swfdec_path.h"
34 #include "swfdec_renderer_internal.h"
35 #include "swfdec_stroke.h"
37 /*** PATTERN ***/
39 G_DEFINE_ABSTRACT_TYPE (SwfdecPattern, swfdec_pattern, SWFDEC_TYPE_DRAW);
41 static void
42 swfdec_pattern_compute_extents (SwfdecDraw *draw)
44 swfdec_path_get_extents (&draw->path, &draw->extents);
47 static void
48 swfdec_pattern_paint (SwfdecDraw *draw, cairo_t *cr, const SwfdecColorTransform *trans)
50 cairo_pattern_t *pattern;
52 pattern = swfdec_pattern_get_pattern (SWFDEC_PATTERN (draw), swfdec_renderer_get (cr),
53 trans);
54 if (pattern == NULL)
55 return;
56 cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
57 cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD);
58 cairo_append_path (cr, &draw->path);
59 cairo_set_source (cr, pattern);
60 cairo_pattern_destroy (pattern);
61 cairo_fill (cr);
64 static void
65 swfdec_pattern_morph (SwfdecDraw *dest, SwfdecDraw *source, guint ratio)
67 SwfdecPattern *dpattern = SWFDEC_PATTERN (dest);
68 SwfdecPattern *spattern = SWFDEC_PATTERN (source);
70 swfdec_matrix_morph (&dpattern->start_transform,
71 &spattern->start_transform, &spattern->end_transform, ratio);
72 dpattern->end_transform = dpattern->start_transform;
73 dpattern->transform = dpattern->start_transform;
74 if (cairo_matrix_invert (&dpattern->transform)) {
75 SWFDEC_ERROR ("morphed paint transform matrix not invertible, using default");
76 dpattern->transform = spattern->transform;
79 SWFDEC_DRAW_CLASS (swfdec_pattern_parent_class)->morph (dest, source, ratio);
82 static gboolean
83 swfdec_pattern_contains (SwfdecDraw *draw, cairo_t *cr, double x, double y)
85 cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD);
86 cairo_append_path (cr, &draw->path);
87 return cairo_in_fill (cr, x, y);
90 static void
91 swfdec_pattern_class_init (SwfdecPatternClass *klass)
93 SwfdecDrawClass *draw_class = SWFDEC_DRAW_CLASS (klass);
95 draw_class->morph = swfdec_pattern_morph;
96 draw_class->paint = swfdec_pattern_paint;
97 draw_class->compute_extents = swfdec_pattern_compute_extents;
98 draw_class->contains = swfdec_pattern_contains;
101 static void
102 swfdec_pattern_init (SwfdecPattern *pattern)
104 cairo_matrix_init_identity (&pattern->transform);
105 cairo_matrix_init_identity (&pattern->start_transform);
106 cairo_matrix_init_identity (&pattern->end_transform);
109 /*** COLOR PATTERN ***/
111 typedef struct _SwfdecColorPattern SwfdecColorPattern;
112 typedef struct _SwfdecColorPatternClass SwfdecColorPatternClass;
114 #define SWFDEC_TYPE_COLOR_PATTERN (swfdec_color_pattern_get_type())
115 #define SWFDEC_IS_COLOR_PATTERN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SWFDEC_TYPE_COLOR_PATTERN))
116 #define SWFDEC_IS_COLOR_PATTERN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SWFDEC_TYPE_COLOR_PATTERN))
117 #define SWFDEC_COLOR_PATTERN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SWFDEC_TYPE_COLOR_PATTERN, SwfdecColorPattern))
118 #define SWFDEC_COLOR_PATTERN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SWFDEC_TYPE_COLOR_PATTERN, SwfdecColorPatternClass))
119 #define SWFDEC_COLOR_PATTERN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SWFDEC_TYPE_COLOR_PATTERN, SwfdecColorPatternClass))
121 struct _SwfdecColorPattern
123 SwfdecPattern pattern;
125 SwfdecColor start_color; /* color to paint with at the beginning */
126 SwfdecColor end_color; /* color to paint with in the end */
129 struct _SwfdecColorPatternClass
131 SwfdecPatternClass pattern_class;
134 GType swfdec_color_pattern_get_type (void);
135 G_DEFINE_TYPE (SwfdecColorPattern, swfdec_color_pattern, SWFDEC_TYPE_PATTERN);
137 static void
138 swfdec_color_pattern_morph (SwfdecDraw *dest, SwfdecDraw *source, guint ratio)
140 SwfdecColorPattern *dpattern = SWFDEC_COLOR_PATTERN (dest);
141 SwfdecColorPattern *spattern = SWFDEC_COLOR_PATTERN (source);
143 dpattern->start_color = swfdec_color_apply_morph (spattern->start_color, spattern->end_color, ratio);
144 dpattern->end_color = dpattern->start_color;
146 SWFDEC_DRAW_CLASS (swfdec_color_pattern_parent_class)->morph (dest, source, ratio);
149 static cairo_pattern_t *
150 swfdec_color_pattern_get_pattern (SwfdecPattern *pat, SwfdecRenderer *renderer,
151 const SwfdecColorTransform *trans)
153 SwfdecColor color = SWFDEC_COLOR_PATTERN (pat)->start_color;
155 color = swfdec_color_apply_transform (color, trans);
156 return cairo_pattern_create_rgba (
157 SWFDEC_COLOR_RED (color) / 255.0, SWFDEC_COLOR_GREEN (color) / 255.0,
158 SWFDEC_COLOR_BLUE (color) / 255.0, SWFDEC_COLOR_ALPHA (color) / 255.0);
161 static void
162 swfdec_color_pattern_class_init (SwfdecColorPatternClass *klass)
164 SWFDEC_DRAW_CLASS (klass)->morph = swfdec_color_pattern_morph;
166 SWFDEC_PATTERN_CLASS (klass)->get_pattern = swfdec_color_pattern_get_pattern;
169 static void
170 swfdec_color_pattern_init (SwfdecColorPattern *pattern)
174 /*** IMAGE PATTERN ***/
176 typedef struct _SwfdecImagePattern SwfdecImagePattern;
177 typedef struct _SwfdecImagePatternClass SwfdecImagePatternClass;
179 #define SWFDEC_TYPE_IMAGE_PATTERN (swfdec_image_pattern_get_type())
180 #define SWFDEC_IS_IMAGE_PATTERN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SWFDEC_TYPE_IMAGE_PATTERN))
181 #define SWFDEC_IS_IMAGE_PATTERN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SWFDEC_TYPE_IMAGE_PATTERN))
182 #define SWFDEC_IMAGE_PATTERN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SWFDEC_TYPE_IMAGE_PATTERN, SwfdecImagePattern))
183 #define SWFDEC_IMAGE_PATTERN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SWFDEC_TYPE_IMAGE_PATTERN, SwfdecImagePatternClass))
184 #define SWFDEC_IMAGE_PATTERN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SWFDEC_TYPE_IMAGE_PATTERN, SwfdecImagePatternClass))
186 struct _SwfdecImagePattern
188 SwfdecPattern pattern;
190 SwfdecImage * image; /* image to paint */
191 cairo_extend_t extend;
192 cairo_filter_t filter;
195 struct _SwfdecImagePatternClass
197 SwfdecPatternClass pattern_class;
200 GType swfdec_image_pattern_get_type (void);
201 G_DEFINE_TYPE (SwfdecImagePattern, swfdec_image_pattern, SWFDEC_TYPE_PATTERN);
203 static void
204 swfdec_image_pattern_morph (SwfdecDraw *dest, SwfdecDraw *source, guint ratio)
206 SwfdecImagePattern *dpattern = SWFDEC_IMAGE_PATTERN (dest);
207 SwfdecImagePattern *spattern = SWFDEC_IMAGE_PATTERN (source);
209 dpattern->image = g_object_ref (spattern->image);
210 dpattern->extend = spattern->extend;
211 dpattern->filter = spattern->filter;
213 SWFDEC_DRAW_CLASS (swfdec_image_pattern_parent_class)->morph (dest, source, ratio);
216 static void
217 swfdec_image_pattern_paint (SwfdecDraw *draw, cairo_t *cr, const SwfdecColorTransform *trans)
219 cairo_pattern_t *pattern;
221 if (swfdec_color_transform_is_alpha (trans)) {
222 SwfdecColorTransform identity;
223 swfdec_color_transform_init_identity (&identity);
224 pattern = swfdec_pattern_get_pattern (SWFDEC_PATTERN (draw),
225 swfdec_renderer_get (cr), &identity);
226 if (pattern == NULL)
227 return;
228 cairo_save (cr);
229 cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
230 cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD);
231 cairo_append_path (cr, &draw->path);
232 cairo_clip (cr);
233 cairo_set_source (cr, pattern);
234 cairo_pattern_destroy (pattern);
235 cairo_paint_with_alpha (cr, trans->aa / 256.0);
236 cairo_restore (cr);
237 } else {
238 SWFDEC_DRAW_CLASS (swfdec_image_pattern_parent_class)->paint (draw, cr, trans);
242 static cairo_pattern_t *
243 swfdec_image_pattern_get_pattern (SwfdecPattern *pat, SwfdecRenderer *renderer,
244 const SwfdecColorTransform *trans)
246 SwfdecImagePattern *image = SWFDEC_IMAGE_PATTERN (pat);
247 cairo_pattern_t *pattern;
248 cairo_surface_t *surface;
250 if (swfdec_color_transform_is_mask (trans))
251 return cairo_pattern_create_rgb (0, 0, 0);
252 surface = swfdec_image_create_surface_transformed (image->image, renderer, trans);
253 if (surface == NULL)
254 return NULL;
255 pattern = cairo_pattern_create_for_surface (surface);
256 cairo_surface_destroy (surface);
257 cairo_pattern_set_matrix (pattern, &pat->transform);
258 cairo_pattern_set_extend (pattern, image->extend);
259 cairo_pattern_set_filter (pattern, image->filter);
260 return pattern;
263 static void
264 swfdec_image_pattern_class_init (SwfdecImagePatternClass *klass)
266 SWFDEC_DRAW_CLASS (klass)->morph = swfdec_image_pattern_morph;
267 SWFDEC_DRAW_CLASS (klass)->paint = swfdec_image_pattern_paint;
269 SWFDEC_PATTERN_CLASS (klass)->get_pattern = swfdec_image_pattern_get_pattern;
272 static void
273 swfdec_image_pattern_init (SwfdecImagePattern *pattern)
277 /*** EXPORTED API ***/
279 static SwfdecDraw *
280 swfdec_pattern_do_parse (SwfdecBits *bits, SwfdecSwfDecoder *dec, gboolean rgba)
282 guint paint_style_type;
283 SwfdecPattern *pattern;
285 paint_style_type = swfdec_bits_get_u8 (bits);
286 SWFDEC_LOG (" type 0x%02x", paint_style_type);
288 if (paint_style_type == 0x00) {
289 pattern = g_object_new (SWFDEC_TYPE_COLOR_PATTERN, NULL);
290 if (rgba) {
291 SWFDEC_COLOR_PATTERN (pattern)->start_color = swfdec_bits_get_rgba (bits);
292 } else {
293 SWFDEC_COLOR_PATTERN (pattern)->start_color = swfdec_bits_get_color (bits);
295 SWFDEC_COLOR_PATTERN (pattern)->end_color = SWFDEC_COLOR_PATTERN (pattern)->start_color;
296 SWFDEC_LOG (" color %08x", SWFDEC_COLOR_PATTERN (pattern)->start_color);
297 } else if (paint_style_type == 0x10 || paint_style_type == 0x12 || paint_style_type == 0x13) {
298 SwfdecGradientPattern *gradient;
299 guint i, interpolation;
300 pattern = SWFDEC_PATTERN (swfdec_gradient_pattern_new ());
301 gradient = SWFDEC_GRADIENT_PATTERN (pattern);
302 swfdec_bits_get_matrix (bits, &pattern->start_transform, NULL);
303 pattern->end_transform = pattern->start_transform;
304 switch (swfdec_bits_getbits (bits, 2)) {
305 case 0:
306 gradient->extend = CAIRO_EXTEND_PAD;
307 break;
308 case 1:
309 gradient->extend = CAIRO_EXTEND_REFLECT;
310 break;
311 case 2:
312 gradient->extend = CAIRO_EXTEND_REPEAT;
313 break;
314 case 3:
315 SWFDEC_ERROR ("spread mode 3 is undefined for gradients");
316 gradient->extend = CAIRO_EXTEND_PAD;
317 break;
318 default:
319 g_assert_not_reached ();
321 interpolation = swfdec_bits_getbits (bits, 2);
322 if (interpolation) {
323 SWFDEC_FIXME ("only normal interpolation is implemented, mode %u is not", interpolation);
325 gradient->n_gradients = swfdec_bits_getbits (bits, 4);
326 for (i = 0; i < gradient->n_gradients; i++) {
327 gradient->gradient[i].ratio = swfdec_bits_get_u8 (bits);
328 if (rgba)
329 gradient->gradient[i].color = swfdec_bits_get_rgba (bits);
330 else
331 gradient->gradient[i].color = swfdec_bits_get_color (bits);
333 gradient->radial = (paint_style_type != 0x10);
334 /* FIXME: need a way to ensure 0x13 only happens in Flash 8 */
335 if (paint_style_type == 0x13) {
336 gradient->focus = swfdec_bits_get_s16 (bits) / 256.0;
338 } else if (paint_style_type >= 0x40 && paint_style_type <= 0x43) {
339 guint paint_id = swfdec_bits_get_u16 (bits);
340 SWFDEC_LOG (" background paint id = %d (type 0x%02x)",
341 paint_id, paint_style_type);
342 if (paint_id == 65535) {
343 /* FIXME: someone explain this magic paint id here */
344 pattern = g_object_new (SWFDEC_TYPE_COLOR_PATTERN, NULL);
345 SWFDEC_COLOR_PATTERN (pattern)->start_color = SWFDEC_COLOR_COMBINE (0, 255, 255, 255);
346 SWFDEC_COLOR_PATTERN (pattern)->end_color = SWFDEC_COLOR_PATTERN (pattern)->start_color;
347 swfdec_bits_get_matrix (bits, &pattern->start_transform, NULL);
348 pattern->end_transform = pattern->start_transform;
349 } else {
350 pattern = g_object_new (SWFDEC_TYPE_IMAGE_PATTERN, NULL);
351 swfdec_bits_get_matrix (bits, &pattern->start_transform, NULL);
352 pattern->end_transform = pattern->start_transform;
353 SWFDEC_IMAGE_PATTERN (pattern)->image = swfdec_swf_decoder_get_character (dec, paint_id);
354 if (!SWFDEC_IS_IMAGE (SWFDEC_IMAGE_PATTERN (pattern)->image)) {
355 g_object_unref (pattern);
356 SWFDEC_ERROR ("could not find image with id %u for pattern", paint_id);
357 return NULL;
359 if (paint_style_type == 0x40 || paint_style_type == 0x42) {
360 SWFDEC_IMAGE_PATTERN (pattern)->extend = CAIRO_EXTEND_REPEAT;
361 } else {
362 SWFDEC_IMAGE_PATTERN (pattern)->extend = CAIRO_EXTEND_PAD;
364 if (paint_style_type == 0x40 || paint_style_type == 0x41) {
365 SWFDEC_IMAGE_PATTERN (pattern)->filter = CAIRO_FILTER_BILINEAR;
366 } else {
367 SWFDEC_IMAGE_PATTERN (pattern)->filter = CAIRO_FILTER_NEAREST;
370 } else {
371 SWFDEC_ERROR ("unknown paint style type 0x%02x", paint_style_type);
372 return NULL;
374 pattern->transform = pattern->start_transform;
375 if (cairo_matrix_invert (&pattern->transform)) {
376 SWFDEC_ERROR ("paint transform matrix not invertible, resetting");
377 cairo_matrix_init_identity (&pattern->transform);
379 swfdec_bits_syncbits (bits);
380 return SWFDEC_DRAW (pattern);
384 * swfdec_pattern_parse:
385 * @bits: the bits to parse from
386 * @dec: a #SwfdecDecoder to take context from
387 * @rgba: TRUE if colors are RGBA, FALSE if they're just RGB
389 * Continues parsing @dec into a new #SwfdecPattern
391 * Returns: a new #SwfdecPattern or NULL on error
393 SwfdecDraw *
394 swfdec_pattern_parse (SwfdecBits *bits, SwfdecSwfDecoder *dec)
396 g_return_val_if_fail (bits != NULL, NULL);
397 g_return_val_if_fail (SWFDEC_IS_SWF_DECODER (dec), NULL);
399 return swfdec_pattern_do_parse (bits, dec, FALSE);
402 SwfdecDraw *
403 swfdec_pattern_parse_rgba (SwfdecBits *bits, SwfdecSwfDecoder *dec)
405 g_return_val_if_fail (bits != NULL, NULL);
406 g_return_val_if_fail (SWFDEC_IS_SWF_DECODER (dec), NULL);
408 return swfdec_pattern_do_parse (bits, dec, TRUE);
412 * swfdec_pattern_parse_morph:
413 * @dec: a #SwfdecDecoder to parse from
415 * Continues parsing @dec into a new #SwfdecPattern. This function is used by
416 * morph shapes.
418 * Returns: a new #SwfdecPattern or NULL on error
420 SwfdecDraw *
421 swfdec_pattern_parse_morph (SwfdecBits *bits, SwfdecSwfDecoder *dec)
423 guint paint_style_type;
424 SwfdecPattern *pattern;
426 g_return_val_if_fail (bits != NULL, NULL);
427 g_return_val_if_fail (SWFDEC_IS_SWF_DECODER (dec), NULL);
429 paint_style_type = swfdec_bits_get_u8 (bits);
430 SWFDEC_LOG (" type 0x%02x", paint_style_type);
432 if (paint_style_type == 0x00) {
433 pattern = g_object_new (SWFDEC_TYPE_COLOR_PATTERN, NULL);
434 SWFDEC_COLOR_PATTERN (pattern)->start_color = swfdec_bits_get_rgba (bits);
435 SWFDEC_COLOR_PATTERN (pattern)->end_color = swfdec_bits_get_rgba (bits);
436 SWFDEC_LOG (" color %08x => %08x", SWFDEC_COLOR_PATTERN (pattern)->start_color,
437 SWFDEC_COLOR_PATTERN (pattern)->end_color);
438 } else if (paint_style_type == 0x10 || paint_style_type == 0x12 || paint_style_type == 0x13) {
439 SwfdecGradientPattern *gradient;
440 guint i, interpolation;
441 pattern = SWFDEC_PATTERN (swfdec_gradient_pattern_new ());
442 gradient = SWFDEC_GRADIENT_PATTERN (pattern);
443 swfdec_bits_get_matrix (bits, &pattern->start_transform, NULL);
444 swfdec_bits_get_matrix (bits, &pattern->end_transform, NULL);
445 switch (swfdec_bits_getbits (bits, 2)) {
446 case 0:
447 gradient->extend = CAIRO_EXTEND_PAD;
448 break;
449 case 1:
450 gradient->extend = CAIRO_EXTEND_REFLECT;
451 break;
452 case 2:
453 gradient->extend = CAIRO_EXTEND_REPEAT;
454 break;
455 case 3:
456 SWFDEC_ERROR ("spread mode 3 is undefined for gradients");
457 gradient->extend = CAIRO_EXTEND_PAD;
458 break;
459 default:
460 g_assert_not_reached ();
462 interpolation = swfdec_bits_getbits (bits, 2);
463 if (interpolation) {
464 SWFDEC_FIXME ("only normal interpolation is implemented, mode %u is not", interpolation);
466 gradient->n_gradients = swfdec_bits_getbits (bits, 4);
467 for (i = 0; i < gradient->n_gradients; i++) {
468 gradient->gradient[i].ratio = swfdec_bits_get_u8 (bits);
469 gradient->gradient[i].color = swfdec_bits_get_rgba (bits);
470 gradient->end_gradient[i].ratio = swfdec_bits_get_u8 (bits);
471 gradient->end_gradient[i].color = swfdec_bits_get_rgba (bits);
473 gradient->radial = (paint_style_type != 0x10);
474 /* FIXME: need a way to ensure 0x13 only happens in Flash 8 */
475 if (paint_style_type == 0x13) {
476 gradient->focus = swfdec_bits_get_s16 (bits) / 256.0;
478 } else if (paint_style_type >= 0x40 && paint_style_type <= 0x43) {
479 guint paint_id = swfdec_bits_get_u16 (bits);
480 SWFDEC_LOG (" background paint id = %d (type 0x%02x)",
481 paint_id, paint_style_type);
482 if (paint_id == 65535) {
483 /* FIXME: someone explain this magic paint id here */
484 pattern = g_object_new (SWFDEC_TYPE_COLOR_PATTERN, NULL);
485 SWFDEC_COLOR_PATTERN (pattern)->start_color = SWFDEC_COLOR_COMBINE (0, 255, 255, 255);
486 SWFDEC_COLOR_PATTERN (pattern)->end_color = SWFDEC_COLOR_PATTERN (pattern)->start_color;
487 swfdec_bits_get_matrix (bits, &pattern->start_transform, NULL);
488 swfdec_bits_get_matrix (bits, &pattern->end_transform, NULL);
489 } else {
490 pattern = g_object_new (SWFDEC_TYPE_IMAGE_PATTERN, NULL);
491 swfdec_bits_get_matrix (bits, &pattern->start_transform, NULL);
492 swfdec_bits_get_matrix (bits, &pattern->end_transform, NULL);
493 SWFDEC_IMAGE_PATTERN (pattern)->image = swfdec_swf_decoder_get_character (dec, paint_id);
494 if (!SWFDEC_IS_IMAGE (SWFDEC_IMAGE_PATTERN (pattern)->image)) {
495 g_object_unref (pattern);
496 SWFDEC_ERROR ("could not find image with id %u for pattern", paint_id);
497 return NULL;
499 if (paint_style_type == 0x40 || paint_style_type == 0x42) {
500 SWFDEC_IMAGE_PATTERN (pattern)->extend = CAIRO_EXTEND_REPEAT;
501 } else {
502 SWFDEC_IMAGE_PATTERN (pattern)->extend = CAIRO_EXTEND_PAD;
504 if (paint_style_type == 0x40 || paint_style_type == 0x41) {
505 SWFDEC_IMAGE_PATTERN (pattern)->filter = CAIRO_FILTER_BILINEAR;
506 } else {
507 SWFDEC_IMAGE_PATTERN (pattern)->filter = CAIRO_FILTER_NEAREST;
510 } else {
511 SWFDEC_ERROR ("unknown paint style type 0x%02x", paint_style_type);
512 return NULL;
514 pattern->transform = pattern->start_transform;
515 if (cairo_matrix_invert (&pattern->transform)) {
516 SWFDEC_ERROR ("paint transform matrix not invertible, resetting");
517 cairo_matrix_init_identity (&pattern->transform);
519 swfdec_bits_syncbits (bits);
520 return SWFDEC_DRAW (pattern);
524 * swfdec_pattern_new_color:
525 * @color: color to paint in
527 * Creates a new pattern to paint with the given color
529 * Returns: a new @SwfdecPattern to paint with
531 SwfdecPattern *
532 swfdec_pattern_new_color (SwfdecColor color)
534 SwfdecPattern *pattern = g_object_new (SWFDEC_TYPE_COLOR_PATTERN, NULL);
536 SWFDEC_COLOR_PATTERN (pattern)->start_color = color;
537 SWFDEC_COLOR_PATTERN (pattern)->end_color = color;
539 return pattern;
542 char *
543 swfdec_pattern_to_string (SwfdecPattern *pattern)
545 g_return_val_if_fail (SWFDEC_IS_PATTERN (pattern), NULL);
547 if (SWFDEC_IS_IMAGE_PATTERN (pattern)) {
548 SwfdecImagePattern *image = SWFDEC_IMAGE_PATTERN (pattern);
549 if (image->image->width == 0)
550 cairo_surface_destroy (swfdec_image_create_surface (image->image, NULL));
551 return g_strdup_printf ("%ux%u image %u (%s, %s)", image->image->width,
552 image->image->height, SWFDEC_CHARACTER (image->image)->id,
553 image->extend == CAIRO_EXTEND_REPEAT ? "repeat" : "no repeat",
554 image->filter == CAIRO_FILTER_BILINEAR ? "bilinear" : "nearest");
555 } else if (SWFDEC_IS_COLOR_PATTERN (pattern)) {
556 if (SWFDEC_COLOR_PATTERN (pattern)->start_color == SWFDEC_COLOR_PATTERN (pattern)->end_color)
557 return g_strdup_printf ("color #%08X", SWFDEC_COLOR_PATTERN (pattern)->start_color);
558 else
559 return g_strdup_printf ("color #%08X => #%08X", SWFDEC_COLOR_PATTERN (pattern)->start_color,
560 SWFDEC_COLOR_PATTERN (pattern)->end_color);
561 } else if (SWFDEC_IS_GRADIENT_PATTERN (pattern)) {
562 SwfdecGradientPattern *gradient = SWFDEC_GRADIENT_PATTERN (pattern);
563 return g_strdup_printf ("%s gradient (%u colors)", gradient->radial ? "radial" : "linear",
564 gradient->n_gradients);
565 } else {
566 return g_strdup_printf ("%s", G_OBJECT_TYPE_NAME (pattern));
570 cairo_pattern_t *
571 swfdec_pattern_get_pattern (SwfdecPattern *pattern, SwfdecRenderer *renderer,
572 const SwfdecColorTransform *trans)
574 SwfdecPatternClass *klass;
576 g_return_val_if_fail (SWFDEC_IS_PATTERN (pattern), NULL);
577 g_return_val_if_fail (SWFDEC_IS_RENDERER (renderer), NULL);
578 g_return_val_if_fail (trans != NULL, NULL);
580 klass = SWFDEC_PATTERN_GET_CLASS (pattern);
581 g_assert (klass->get_pattern);
582 return klass->get_pattern (pattern, renderer, trans);