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
, const SwfdecRect
*inval
)
54 SwfdecShape
*shape
= SWFDEC_SHAPE (graphic
);
57 for (walk
= shape
->draws
; walk
; walk
= walk
->next
) {
58 SwfdecDraw
*draw
= walk
->data
;
60 if (!swfdec_rect_intersect (NULL
, &draw
->extents
, inval
))
63 swfdec_draw_paint (draw
, cr
, trans
);
68 swfdec_shape_mouse_in (SwfdecGraphic
*graphic
, double x
, double y
)
70 SwfdecShape
*shape
= SWFDEC_SHAPE (graphic
);
73 for (walk
= shape
->draws
; walk
; walk
= walk
->next
) {
74 SwfdecDraw
*draw
= walk
->data
;
76 if (swfdec_draw_contains (draw
, x
, y
))
83 swfdec_shape_class_init (SwfdecShapeClass
* g_class
)
85 GObjectClass
*object_class
= G_OBJECT_CLASS (g_class
);
86 SwfdecGraphicClass
*graphic_class
= SWFDEC_GRAPHIC_CLASS (g_class
);
88 object_class
->dispose
= swfdec_shape_dispose
;
90 graphic_class
->render
= swfdec_shape_render
;
91 graphic_class
->mouse_in
= swfdec_shape_mouse_in
;
95 swfdec_shape_init (SwfdecShape
* shape
)
100 tag_define_shape (SwfdecSwfDecoder
* s
, guint tag
)
102 SwfdecBits
*bits
= &s
->b
;
104 SwfdecShapeParser
*parser
;
107 id
= swfdec_bits_get_u16 (bits
);
109 shape
= swfdec_swf_decoder_create_character (s
, id
, SWFDEC_TYPE_SHAPE
);
111 return SWFDEC_STATUS_OK
;
113 SWFDEC_INFO ("id=%d", id
);
115 swfdec_bits_get_rect (bits
, &SWFDEC_GRAPHIC (shape
)->extents
);
117 parser
= swfdec_shape_parser_new ((SwfdecParseDrawFunc
) swfdec_pattern_parse
,
118 (SwfdecParseDrawFunc
) swfdec_stroke_parse
, s
);
119 swfdec_shape_parser_parse (parser
, bits
);
120 shape
->draws
= swfdec_shape_parser_free (parser
);
122 return SWFDEC_STATUS_OK
;
126 tag_define_shape_3 (SwfdecSwfDecoder
* s
, guint tag
)
128 SwfdecBits
*bits
= &s
->b
;
130 SwfdecShapeParser
*parser
;
133 id
= swfdec_bits_get_u16 (bits
);
134 shape
= swfdec_swf_decoder_create_character (s
, id
, SWFDEC_TYPE_SHAPE
);
136 return SWFDEC_STATUS_OK
;
138 swfdec_bits_get_rect (bits
, &SWFDEC_GRAPHIC (shape
)->extents
);
140 parser
= swfdec_shape_parser_new ((SwfdecParseDrawFunc
) swfdec_pattern_parse_rgba
,
141 (SwfdecParseDrawFunc
) swfdec_stroke_parse_rgba
, s
);
142 swfdec_shape_parser_parse (parser
, bits
);
143 shape
->draws
= swfdec_shape_parser_free (parser
);
145 return SWFDEC_STATUS_OK
;
149 tag_define_shape_4 (SwfdecSwfDecoder
*s
, guint tag
)
151 SwfdecBits
*bits
= &s
->b
;
153 SwfdecShapeParser
*parser
;
156 gboolean has_scale_strokes
, has_noscale_strokes
;
158 id
= swfdec_bits_get_u16 (bits
);
159 shape
= swfdec_swf_decoder_create_character (s
, id
, SWFDEC_TYPE_SHAPE
);
161 return SWFDEC_STATUS_OK
;
163 swfdec_bits_get_rect (bits
, &SWFDEC_GRAPHIC (shape
)->extents
);
164 SWFDEC_LOG (" extents: %g %g x %g %g",
165 SWFDEC_GRAPHIC (shape
)->extents
.x0
, SWFDEC_GRAPHIC (shape
)->extents
.y0
,
166 SWFDEC_GRAPHIC (shape
)->extents
.x1
, SWFDEC_GRAPHIC (shape
)->extents
.y1
);
167 swfdec_bits_get_rect (bits
, &tmp
);
168 SWFDEC_LOG (" extents: %g %g x %g %g",
169 tmp
.x0
, tmp
.y0
, tmp
.x1
, tmp
.y1
);
170 swfdec_bits_getbits (bits
, 6);
171 has_scale_strokes
= swfdec_bits_getbit (bits
);
172 has_noscale_strokes
= swfdec_bits_getbit (bits
);
173 SWFDEC_LOG (" has scaling strokes: %d", has_scale_strokes
);
174 SWFDEC_LOG (" has non-scaling strokes: %d", has_noscale_strokes
);
176 parser
= swfdec_shape_parser_new ((SwfdecParseDrawFunc
) swfdec_pattern_parse_rgba
,
177 (SwfdecParseDrawFunc
) swfdec_stroke_parse_extended
, s
);
178 swfdec_shape_parser_parse (parser
, bits
);
179 shape
->draws
= swfdec_shape_parser_free (parser
);
181 return SWFDEC_STATUS_OK
;
185 /*** MORPH SHAPE ***/
187 #include "swfdec_morphshape.h"
190 swfdec_morph_shape_do_change (SwfdecBits
*end_bits
, SubPath
*other
, SwfdecMorphShape
*morph
,
191 GArray
*path_array
, SubPath
*path
, int *x
, int *y
)
197 g_array_set_size (path_array
, path_array
->len
+ 1);
198 path
= &g_array_index (path_array
, SubPath
, path_array
->len
- 1);
200 swfdec_path_init (&path
->path
);
201 if (swfdec_shape_peek_type (end_bits
) == SWFDEC_SHAPE_TYPE_CHANGE
) {
202 int state_line_styles
, state_fill_styles1
, state_fill_styles0
, state_moveto
;
204 if (swfdec_bits_getbit (end_bits
) != 0) {
205 g_assert_not_reached ();
207 if (swfdec_bits_getbit (end_bits
)) {
208 SWFDEC_ERROR ("new styles aren't allowed in end edges, ignoring");
210 state_line_styles
= swfdec_bits_getbit (end_bits
);
211 state_fill_styles1
= swfdec_bits_getbit (end_bits
);
212 state_fill_styles0
= swfdec_bits_getbit (end_bits
);
213 state_moveto
= swfdec_bits_getbit (end_bits
);
215 int n_bits
= swfdec_bits_getbits (end_bits
, 5);
216 *x
= swfdec_bits_getsbits (end_bits
, n_bits
);
217 *y
= swfdec_bits_getsbits (end_bits
, n_bits
);
219 SWFDEC_LOG (" moveto %d,%d", *x
, *y
);
221 if (state_fill_styles0
) {
222 guint check
= swfdec_bits_getbits (end_bits
, morph
->n_fill_bits
) +
223 SWFDEC_SHAPE (morph
)->fills_offset
;
224 if (check
!= path
->fill0style
)
225 SWFDEC_ERROR ("end fill0style %u differs from start fill0style %u", check
, path
->fill0style
);
227 if (state_fill_styles1
) {
228 guint check
= swfdec_bits_getbits (end_bits
, morph
->n_fill_bits
) +
229 SWFDEC_SHAPE (morph
)->fills_offset
;
230 if (check
!= path
->fill1style
)
231 SWFDEC_ERROR ("end fill1style %u differs from start fill1style %u", check
, path
->fill1style
);
233 if (state_line_styles
) {
234 guint check
= swfdec_bits_getbits (end_bits
, morph
->n_line_bits
) +
235 SWFDEC_SHAPE (morph
)->lines_offset
;
236 if (check
!= path
->linestyle
)
237 SWFDEC_ERROR ("end linestyle %u differs from start linestyle %u", check
, path
->linestyle
);
246 swfdec_morph_shape_get_recs (SwfdecSwfDecoder
* s
, SwfdecMorphShape
*morph
, SwfdecBits
*end_bits
)
248 int start_x
= 0, start_y
= 0, end_x
= 0, end_y
= 0;
249 SubPath
*start_path
= NULL
, *end_path
= NULL
;
250 GArray
*start_path_array
, *end_path_array
, *tmp
;
251 SwfdecShapeType start_type
, end_type
;
252 SwfdecBits
*start_bits
= &s
->b
;
253 SwfdecShape
*shape
= SWFDEC_SHAPE (morph
);
255 /* First, accumulate all sub-paths into an array */
256 start_path_array
= g_array_new (FALSE
, TRUE
, sizeof (SubPath
));
257 end_path_array
= g_array_new (FALSE
, TRUE
, sizeof (SubPath
));
259 while ((start_type
= swfdec_shape_peek_type (start_bits
))) {
260 end_type
= swfdec_shape_peek_type (end_bits
);
261 if (end_type
== SWFDEC_SHAPE_TYPE_CHANGE
&& start_type
!= SWFDEC_SHAPE_TYPE_CHANGE
) {
264 start_path
->x_end
= start_x
;
265 start_path
->y_end
= start_y
;
267 g_array_set_size (start_path_array
, start_path_array
->len
+ 1);
268 path
= &g_array_index (start_path_array
, SubPath
, start_path_array
->len
- 1);
272 swfdec_path_init (&start_path
->path
);
273 start_path
->x_start
= start_x
;
274 start_path
->y_start
= start_y
;
275 end_path
= swfdec_morph_shape_do_change (end_bits
, start_path
, morph
, end_path_array
, end_path
, &end_x
, &end_y
);
278 switch (start_type
) {
279 case SWFDEC_SHAPE_TYPE_CHANGE
:
280 start_path
= swfdec_shape_parse_change (s
, shape
, start_path_array
, start_path
, &start_x
, &start_y
,
281 swfdec_pattern_parse_morph
, swfdec_stroke_parse_morph
);
282 end_path
= swfdec_morph_shape_do_change (end_bits
, start_path
, morph
, end_path_array
, end_path
, &end_x
, &end_y
);
284 case SWFDEC_SHAPE_TYPE_LINE
:
285 if (end_type
== SWFDEC_SHAPE_TYPE_LINE
) {
286 swfdec_shape_parse_line (start_bits
, start_path
, &start_x
, &start_y
, FALSE
);
287 swfdec_shape_parse_line (end_bits
, end_path
, &end_x
, &end_y
, FALSE
);
288 } else if (end_type
== SWFDEC_SHAPE_TYPE_CURVE
) {
289 swfdec_shape_parse_line (start_bits
, start_path
, &start_x
, &start_y
, TRUE
);
290 swfdec_shape_parse_curve (end_bits
, end_path
, &end_x
, &end_y
);
292 SWFDEC_ERROR ("edge type didn't match, wanted line or curve, but got %s",
293 end_type
? "change" : "end");
297 case SWFDEC_SHAPE_TYPE_CURVE
:
298 swfdec_shape_parse_curve (start_bits
, start_path
, &start_x
, &start_y
);
299 if (end_type
== SWFDEC_SHAPE_TYPE_LINE
) {
300 swfdec_shape_parse_line (end_bits
, end_path
, &end_x
, &end_y
, TRUE
);
301 } else if (end_type
== SWFDEC_SHAPE_TYPE_CURVE
) {
302 swfdec_shape_parse_curve (end_bits
, end_path
, &end_x
, &end_y
);
304 SWFDEC_ERROR ("edge type didn't match, wanted line or curve, but got %s",
305 end_type
? "change" : "end");
309 case SWFDEC_SHAPE_TYPE_END
:
311 g_assert_not_reached ();
316 start_path
->x_end
= start_x
;
317 start_path
->y_end
= start_y
;
320 end_path
->x_end
= end_x
;
321 end_path
->y_end
= end_y
;
323 swfdec_bits_getbits (start_bits
, 6);
324 swfdec_bits_syncbits (start_bits
);
325 if (swfdec_bits_getbits (end_bits
, 6) != 0) {
326 SWFDEC_ERROR ("end shapes are not finished when start shapes are");
328 swfdec_bits_syncbits (end_bits
);
331 /* FIXME: there's probably a problem if start and end paths get accumulated in
332 * different ways, this could lead to the morphs not looking like they should.
333 * Need a good testcase for this first though.
334 * FIXME: Also, due to error handling, there needs to be syncing of code paths
337 shape
->vecs
= morph
->end_vecs
;
338 swfdec_shape_initialize_from_sub_paths (shape
, end_path_array
);
339 morph
->end_vecs
= shape
->vecs
;
341 swfdec_shape_initialize_from_sub_paths (shape
, start_path_array
);
342 g_assert (morph
->end_vecs
->len
== shape
->vecs
->len
);
348 SwfdecBits
*bits
= &s
->b
;
349 SwfdecMorphShape
*morph
;
352 id
= swfdec_bits_get_u16 (bits
);
354 morph
= swfdec_swf_decoder_create_character (s
, id
, SWFDEC_TYPE_MORPH_SHAPE
);
356 return SWFDEC_STATUS_OK
;
358 SWFDEC_INFO ("id=%d", id
);
360 swfdec_bits_get_rect (bits
, &SWFDEC_GRAPHIC (morph
)->extents
);
361 swfdec_bits_get_rect (bits
, &morph
->end_extents
);
362 offset
= swfdec_bits_get_u32 (bits
);
364 if (swfdec_bits_skip_bytes (&end_bits
, offset
) != offset
) {
365 SWFDEC_ERROR ("wrong offset in DefineMorphShape");
366 return SWFDEC_STATUS_OK
;
368 bits
->end
= end_bits
.ptr
;
370 swfdec_shape_add_styles (s
, SWFDEC_SHAPE (morph
),
371 swfdec_pattern_parse_morph
, swfdec_stroke_parse_morph
);
373 morph
->n_fill_bits
= swfdec_bits_getbits (&end_bits
, 4);
374 morph
->n_line_bits
= swfdec_bits_getbits (&end_bits
, 4);
375 SWFDEC_LOG ("%u fill bits, %u line bits in end shape", morph
->n_fill_bits
, morph
->n_line_bits
);
377 swfdec_morph_shape_get_recs (s
, morph
, &end_bits
);
378 if (swfdec_bits_left (&s
->b
)) {
379 SWFDEC_WARNING ("early finish when parsing start shapes: %u bytes",
380 swfdec_bits_left (&s
->b
));
385 return SWFDEC_STATUS_OK
;