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
29 #include "swfdec_shape.h"
31 #include "swfdec_debug.h"
32 #include "swfdec_path.h"
33 #include "swfdec_shape_parser.h"
34 #include "swfdec_stroke.h"
36 G_DEFINE_TYPE (SwfdecShape
, swfdec_shape
, SWFDEC_TYPE_GRAPHIC
)
39 swfdec_shape_dispose (GObject
*object
)
41 SwfdecShape
* shape
= SWFDEC_SHAPE (object
);
43 g_slist_foreach (shape
->draws
, (GFunc
) g_object_unref
, NULL
);
44 g_slist_free (shape
->draws
);
47 G_OBJECT_CLASS (swfdec_shape_parent_class
)->dispose (G_OBJECT (shape
));
51 swfdec_shape_render (SwfdecGraphic
*graphic
, cairo_t
*cr
,
52 const SwfdecColorTransform
*trans
)
54 SwfdecShape
*shape
= SWFDEC_SHAPE (graphic
);
58 cairo_clip_extents (cr
, &inval
.x0
, &inval
.y0
, &inval
.x1
, &inval
.y1
);
60 for (walk
= shape
->draws
; walk
; walk
= walk
->next
) {
61 SwfdecDraw
*draw
= walk
->data
;
63 if (!swfdec_rect_intersect (NULL
, &draw
->extents
, &inval
))
66 swfdec_draw_paint (draw
, cr
, trans
);
71 swfdec_shape_mouse_in (SwfdecGraphic
*graphic
, double x
, double y
)
73 SwfdecShape
*shape
= SWFDEC_SHAPE (graphic
);
76 for (walk
= shape
->draws
; walk
; walk
= walk
->next
) {
77 SwfdecDraw
*draw
= walk
->data
;
79 if (swfdec_draw_contains (draw
, x
, y
))
86 swfdec_shape_class_init (SwfdecShapeClass
* g_class
)
88 GObjectClass
*object_class
= G_OBJECT_CLASS (g_class
);
89 SwfdecGraphicClass
*graphic_class
= SWFDEC_GRAPHIC_CLASS (g_class
);
91 object_class
->dispose
= swfdec_shape_dispose
;
93 graphic_class
->render
= swfdec_shape_render
;
94 graphic_class
->mouse_in
= swfdec_shape_mouse_in
;
98 swfdec_shape_init (SwfdecShape
* shape
)
103 tag_define_shape (SwfdecSwfDecoder
* s
, guint tag
)
105 SwfdecBits
*bits
= &s
->b
;
107 SwfdecShapeParser
*parser
;
110 id
= swfdec_bits_get_u16 (bits
);
112 shape
= swfdec_swf_decoder_create_character (s
, id
, SWFDEC_TYPE_SHAPE
);
114 return SWFDEC_STATUS_OK
;
116 SWFDEC_INFO ("id=%d", id
);
118 swfdec_bits_get_rect (bits
, &SWFDEC_GRAPHIC (shape
)->extents
);
120 parser
= swfdec_shape_parser_new ((SwfdecParseDrawFunc
) swfdec_pattern_parse
,
121 (SwfdecParseDrawFunc
) swfdec_stroke_parse
, s
);
122 swfdec_shape_parser_parse (parser
, bits
);
123 shape
->draws
= swfdec_shape_parser_free (parser
);
125 return SWFDEC_STATUS_OK
;
129 tag_define_shape_3 (SwfdecSwfDecoder
* s
, guint tag
)
131 SwfdecBits
*bits
= &s
->b
;
133 SwfdecShapeParser
*parser
;
136 id
= swfdec_bits_get_u16 (bits
);
137 shape
= swfdec_swf_decoder_create_character (s
, id
, SWFDEC_TYPE_SHAPE
);
139 return SWFDEC_STATUS_OK
;
141 swfdec_bits_get_rect (bits
, &SWFDEC_GRAPHIC (shape
)->extents
);
143 parser
= swfdec_shape_parser_new ((SwfdecParseDrawFunc
) swfdec_pattern_parse_rgba
,
144 (SwfdecParseDrawFunc
) swfdec_stroke_parse_rgba
, s
);
145 swfdec_shape_parser_parse (parser
, bits
);
146 shape
->draws
= swfdec_shape_parser_free (parser
);
148 return SWFDEC_STATUS_OK
;
152 tag_define_shape_4 (SwfdecSwfDecoder
*s
, guint tag
)
154 SwfdecBits
*bits
= &s
->b
;
156 SwfdecShapeParser
*parser
;
159 gboolean has_scale_strokes
, has_noscale_strokes
;
161 id
= swfdec_bits_get_u16 (bits
);
162 shape
= swfdec_swf_decoder_create_character (s
, id
, SWFDEC_TYPE_SHAPE
);
164 return SWFDEC_STATUS_OK
;
166 swfdec_bits_get_rect (bits
, &SWFDEC_GRAPHIC (shape
)->extents
);
167 SWFDEC_LOG (" extents: %g %g x %g %g",
168 SWFDEC_GRAPHIC (shape
)->extents
.x0
, SWFDEC_GRAPHIC (shape
)->extents
.y0
,
169 SWFDEC_GRAPHIC (shape
)->extents
.x1
, SWFDEC_GRAPHIC (shape
)->extents
.y1
);
170 swfdec_bits_get_rect (bits
, &tmp
);
171 SWFDEC_LOG (" extents: %g %g x %g %g",
172 tmp
.x0
, tmp
.y0
, tmp
.x1
, tmp
.y1
);
173 swfdec_bits_getbits (bits
, 6);
174 has_scale_strokes
= swfdec_bits_getbit (bits
);
175 has_noscale_strokes
= swfdec_bits_getbit (bits
);
176 SWFDEC_LOG (" has scaling strokes: %d", has_scale_strokes
);
177 SWFDEC_LOG (" has non-scaling strokes: %d", has_noscale_strokes
);
179 parser
= swfdec_shape_parser_new ((SwfdecParseDrawFunc
) swfdec_pattern_parse_rgba
,
180 (SwfdecParseDrawFunc
) swfdec_stroke_parse_extended
, s
);
181 swfdec_shape_parser_parse (parser
, bits
);
182 shape
->draws
= swfdec_shape_parser_free (parser
);
184 return SWFDEC_STATUS_OK
;
188 /*** MORPH SHAPE ***/
190 #include "swfdec_morphshape.h"
193 swfdec_morph_shape_do_change (SwfdecBits
*end_bits
, SubPath
*other
, SwfdecMorphShape
*morph
,
194 GArray
*path_array
, SubPath
*path
, int *x
, int *y
)
200 g_array_set_size (path_array
, path_array
->len
+ 1);
201 path
= &g_array_index (path_array
, SubPath
, path_array
->len
- 1);
203 swfdec_path_init (&path
->path
);
204 if (swfdec_shape_peek_type (end_bits
) == SWFDEC_SHAPE_TYPE_CHANGE
) {
205 int state_line_styles
, state_fill_styles1
, state_fill_styles0
, state_moveto
;
207 if (swfdec_bits_getbit (end_bits
) != 0) {
208 g_assert_not_reached ();
210 if (swfdec_bits_getbit (end_bits
)) {
211 SWFDEC_ERROR ("new styles aren't allowed in end edges, ignoring");
213 state_line_styles
= swfdec_bits_getbit (end_bits
);
214 state_fill_styles1
= swfdec_bits_getbit (end_bits
);
215 state_fill_styles0
= swfdec_bits_getbit (end_bits
);
216 state_moveto
= swfdec_bits_getbit (end_bits
);
218 int n_bits
= swfdec_bits_getbits (end_bits
, 5);
219 *x
= swfdec_bits_getsbits (end_bits
, n_bits
);
220 *y
= swfdec_bits_getsbits (end_bits
, n_bits
);
222 SWFDEC_LOG (" moveto %d,%d", *x
, *y
);
224 if (state_fill_styles0
) {
225 guint check
= swfdec_bits_getbits (end_bits
, morph
->n_fill_bits
) +
226 SWFDEC_SHAPE (morph
)->fills_offset
;
227 if (check
!= path
->fill0style
)
228 SWFDEC_ERROR ("end fill0style %u differs from start fill0style %u", check
, path
->fill0style
);
230 if (state_fill_styles1
) {
231 guint check
= swfdec_bits_getbits (end_bits
, morph
->n_fill_bits
) +
232 SWFDEC_SHAPE (morph
)->fills_offset
;
233 if (check
!= path
->fill1style
)
234 SWFDEC_ERROR ("end fill1style %u differs from start fill1style %u", check
, path
->fill1style
);
236 if (state_line_styles
) {
237 guint check
= swfdec_bits_getbits (end_bits
, morph
->n_line_bits
) +
238 SWFDEC_SHAPE (morph
)->lines_offset
;
239 if (check
!= path
->linestyle
)
240 SWFDEC_ERROR ("end linestyle %u differs from start linestyle %u", check
, path
->linestyle
);
249 swfdec_morph_shape_get_recs (SwfdecSwfDecoder
* s
, SwfdecMorphShape
*morph
, SwfdecBits
*end_bits
)
251 int start_x
= 0, start_y
= 0, end_x
= 0, end_y
= 0;
252 SubPath
*start_path
= NULL
, *end_path
= NULL
;
253 GArray
*start_path_array
, *end_path_array
, *tmp
;
254 SwfdecShapeType start_type
, end_type
;
255 SwfdecBits
*start_bits
= &s
->b
;
256 SwfdecShape
*shape
= SWFDEC_SHAPE (morph
);
258 /* First, accumulate all sub-paths into an array */
259 start_path_array
= g_array_new (FALSE
, TRUE
, sizeof (SubPath
));
260 end_path_array
= g_array_new (FALSE
, TRUE
, sizeof (SubPath
));
262 while ((start_type
= swfdec_shape_peek_type (start_bits
))) {
263 end_type
= swfdec_shape_peek_type (end_bits
);
264 if (end_type
== SWFDEC_SHAPE_TYPE_CHANGE
&& start_type
!= SWFDEC_SHAPE_TYPE_CHANGE
) {
267 start_path
->x_end
= start_x
;
268 start_path
->y_end
= start_y
;
270 g_array_set_size (start_path_array
, start_path_array
->len
+ 1);
271 path
= &g_array_index (start_path_array
, SubPath
, start_path_array
->len
- 1);
275 swfdec_path_init (&start_path
->path
);
276 start_path
->x_start
= start_x
;
277 start_path
->y_start
= start_y
;
278 end_path
= swfdec_morph_shape_do_change (end_bits
, start_path
, morph
, end_path_array
, end_path
, &end_x
, &end_y
);
281 switch (start_type
) {
282 case SWFDEC_SHAPE_TYPE_CHANGE
:
283 start_path
= swfdec_shape_parse_change (s
, shape
, start_path_array
, start_path
, &start_x
, &start_y
,
284 swfdec_pattern_parse_morph
, swfdec_stroke_parse_morph
);
285 end_path
= swfdec_morph_shape_do_change (end_bits
, start_path
, morph
, end_path_array
, end_path
, &end_x
, &end_y
);
287 case SWFDEC_SHAPE_TYPE_LINE
:
288 if (end_type
== SWFDEC_SHAPE_TYPE_LINE
) {
289 swfdec_shape_parse_line (start_bits
, start_path
, &start_x
, &start_y
, FALSE
);
290 swfdec_shape_parse_line (end_bits
, end_path
, &end_x
, &end_y
, FALSE
);
291 } else if (end_type
== SWFDEC_SHAPE_TYPE_CURVE
) {
292 swfdec_shape_parse_line (start_bits
, start_path
, &start_x
, &start_y
, TRUE
);
293 swfdec_shape_parse_curve (end_bits
, end_path
, &end_x
, &end_y
);
295 SWFDEC_ERROR ("edge type didn't match, wanted line or curve, but got %s",
296 end_type
? "change" : "end");
300 case SWFDEC_SHAPE_TYPE_CURVE
:
301 swfdec_shape_parse_curve (start_bits
, start_path
, &start_x
, &start_y
);
302 if (end_type
== SWFDEC_SHAPE_TYPE_LINE
) {
303 swfdec_shape_parse_line (end_bits
, end_path
, &end_x
, &end_y
, TRUE
);
304 } else if (end_type
== SWFDEC_SHAPE_TYPE_CURVE
) {
305 swfdec_shape_parse_curve (end_bits
, end_path
, &end_x
, &end_y
);
307 SWFDEC_ERROR ("edge type didn't match, wanted line or curve, but got %s",
308 end_type
? "change" : "end");
312 case SWFDEC_SHAPE_TYPE_END
:
314 g_assert_not_reached ();
319 start_path
->x_end
= start_x
;
320 start_path
->y_end
= start_y
;
323 end_path
->x_end
= end_x
;
324 end_path
->y_end
= end_y
;
326 swfdec_bits_getbits (start_bits
, 6);
327 swfdec_bits_syncbits (start_bits
);
328 if (swfdec_bits_getbits (end_bits
, 6) != 0) {
329 SWFDEC_ERROR ("end shapes are not finished when start shapes are");
331 swfdec_bits_syncbits (end_bits
);
334 /* FIXME: there's probably a problem if start and end paths get accumulated in
335 * different ways, this could lead to the morphs not looking like they should.
336 * Need a good testcase for this first though.
337 * FIXME: Also, due to error handling, there needs to be syncing of code paths
340 shape
->vecs
= morph
->end_vecs
;
341 swfdec_shape_initialize_from_sub_paths (shape
, end_path_array
);
342 morph
->end_vecs
= shape
->vecs
;
344 swfdec_shape_initialize_from_sub_paths (shape
, start_path_array
);
345 g_assert (morph
->end_vecs
->len
== shape
->vecs
->len
);
351 SwfdecBits
*bits
= &s
->b
;
352 SwfdecMorphShape
*morph
;
355 id
= swfdec_bits_get_u16 (bits
);
357 morph
= swfdec_swf_decoder_create_character (s
, id
, SWFDEC_TYPE_MORPH_SHAPE
);
359 return SWFDEC_STATUS_OK
;
361 SWFDEC_INFO ("id=%d", id
);
363 swfdec_bits_get_rect (bits
, &SWFDEC_GRAPHIC (morph
)->extents
);
364 swfdec_bits_get_rect (bits
, &morph
->end_extents
);
365 offset
= swfdec_bits_get_u32 (bits
);
367 if (swfdec_bits_skip_bytes (&end_bits
, offset
) != offset
) {
368 SWFDEC_ERROR ("wrong offset in DefineMorphShape");
369 return SWFDEC_STATUS_OK
;
371 bits
->end
= end_bits
.ptr
;
373 swfdec_shape_add_styles (s
, SWFDEC_SHAPE (morph
),
374 swfdec_pattern_parse_morph
, swfdec_stroke_parse_morph
);
376 morph
->n_fill_bits
= swfdec_bits_getbits (&end_bits
, 4);
377 morph
->n_line_bits
= swfdec_bits_getbits (&end_bits
, 4);
378 SWFDEC_LOG ("%u fill bits, %u line bits in end shape", morph
->n_fill_bits
, morph
->n_line_bits
);
380 swfdec_morph_shape_get_recs (s
, morph
, &end_bits
);
381 if (swfdec_bits_left (&s
->b
)) {
382 SWFDEC_WARNING ("early finish when parsing start shapes: %u bytes",
383 swfdec_bits_left (&s
->b
));
388 return SWFDEC_STATUS_OK
;