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.
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
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"
36 G_DEFINE_ABSTRACT_TYPE (SwfdecPattern
, swfdec_pattern
, G_TYPE_OBJECT
);
39 swfdec_pattern_class_init (SwfdecPatternClass
*klass
)
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
);
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);
93 swfdec_color_pattern_class_init (SwfdecColorPatternClass
*klass
)
95 SWFDEC_PATTERN_CLASS (klass
)->get_pattern
= swfdec_color_pattern_get_pattern
;
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
;
139 cairo_surface_t
*surface
;
141 surface
= swfdec_image_create_surface_transformed (image
->image
, trans
);
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
);
154 swfdec_image_pattern_class_init (SwfdecImagePatternClass
*klass
)
156 SWFDEC_PATTERN_CLASS (klass
)->get_pattern
= swfdec_image_pattern_get_pattern
;
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
)
199 cairo_pattern_t
*pattern
;
202 SwfdecGradientPattern
*gradient
= SWFDEC_GRADIENT_PATTERN (pat
);
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);
209 pattern
= cairo_pattern_create_linear (-16384.0, 0, 16384.0, 0);
210 cairo_pattern_set_matrix (pattern
, &pat
->transform
);
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);
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);
224 cairo_pattern_set_matrix (pattern
, &mat
);
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);
240 for (i
= 0; i
< gradient
->gradient
->n_gradients
; i
++){
241 color
= swfdec_color_apply_transform (gradient
->gradient
->array
[i
].color
,
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);
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
);
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
;
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
;
283 SwfdecPattern
*pattern
;
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
);
292 SWFDEC_COLOR_PATTERN (pattern
)->start_color
= swfdec_bits_get_rgba (bits
);
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
;
305 gradient
->gradient
= swfdec_bits_get_gradient_rgba (bits
);
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
;
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
);
335 if (paint_style_type
== 0x40 || paint_style_type
== 0x42) {
336 SWFDEC_IMAGE_PATTERN (pattern
)->extend
= CAIRO_EXTEND_REPEAT
;
339 /* not implemented yet in cairo */
340 SWFDEC_IMAGE_PATTERN (pattern
)->extend
= CAIRO_EXTEND_PAD
;
342 SWFDEC_IMAGE_PATTERN (pattern
)->extend
= CAIRO_EXTEND_NONE
;
345 if (paint_style_type
== 0x40 || paint_style_type
== 0x41) {
346 SWFDEC_IMAGE_PATTERN (pattern
)->filter
= CAIRO_FILTER_BILINEAR
;
348 SWFDEC_IMAGE_PATTERN (pattern
)->filter
= CAIRO_FILTER_NEAREST
;
352 SWFDEC_ERROR ("unknown paint style type 0x%02x", paint_style_type
);
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
);
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
374 swfdec_pattern_parse (SwfdecSwfDecoder
*dec
)
376 g_return_val_if_fail (dec
!= NULL
, NULL
);
378 return swfdec_pattern_do_parse (dec
, FALSE
);
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
396 * Returns: a new #SwfdecPattern or NULL on error
399 swfdec_pattern_parse_morph (SwfdecSwfDecoder
*dec
)
401 guint paint_style_type
;
403 SwfdecPattern
*pattern
;
405 g_return_val_if_fail (dec
!= NULL
, NULL
);
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
);
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
);
445 if (paint_style_type
== 0x40 || paint_style_type
== 0x42) {
446 SWFDEC_IMAGE_PATTERN (pattern
)->extend
= CAIRO_EXTEND_REPEAT
;
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
;
453 SWFDEC_IMAGE_PATTERN (pattern
)->filter
= CAIRO_FILTER_NEAREST
;
457 SWFDEC_ERROR ("unknown paint style type 0x%02x", paint_style_type
);
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
);
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.
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
)
497 #if CAIRO_VERSION_MAJOR < 2 && CAIRO_VERSION_MINOR < 4
498 cairo_append_path (cr
, (cairo_path_t
*) path
);
500 cairo_append_path (cr
, path
);
502 cairo_set_source (cr
, cpattern
);
503 cairo_pattern_destroy (cpattern
);
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
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
;
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
);
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
);
550 return g_strdup_printf ("%s", G_OBJECT_TYPE_NAME (pattern
));
555 swfdec_path_get_extents (const cairo_path_t
*path
, SwfdecRect
*extents
, double line_width
)
557 cairo_path_data_t
*data
= path
->data
;
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; \
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
:
579 extents
->x0
= x
- line_width
;
580 extents
->x1
= x
+ line_width
;
581 extents
->y0
= y
- line_width
;
582 extents
->y1
= y
+ line_width
;
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
);
593 case CAIRO_PATH_LINE_TO
:
597 extents
->x0
= x
- line_width
;
598 extents
->x1
= x
+ line_width
;
599 extents
->y0
= y
- line_width
;
600 extents
->y1
= y
+ line_width
;
602 ADD_POINT (extents
, x
, y
);
604 need_current
= FALSE
;
606 ADD_POINT (extents
, data
[i
+1].point
.x
, data
[i
+1].point
.y
);
609 case CAIRO_PATH_CLOSE_PATH
:
613 case CAIRO_PATH_MOVE_TO
:
614 x
= data
[i
+1].point
.x
;
615 y
= data
[i
+1].point
.y
;
619 g_assert_not_reached ();
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
;
641 swfdec_path_get_extents (path
, extents
, 0.0);
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
);