copy/paste caused some issues here
[swfdec.git] / libswfdec / swfdec_shape.c
blobca86d8f9557acefc088c114739629d9c1490e291
1 /* Swfdec
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
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
26 #include <math.h>
27 #include <string.h>
29 #include "swfdec_shape.h"
30 #include "swfdec.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)
38 static void
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);
45 shape->draws = NULL;
47 G_OBJECT_CLASS (swfdec_shape_parent_class)->dispose (G_OBJECT (shape));
50 static void
51 swfdec_shape_render (SwfdecGraphic *graphic, cairo_t *cr,
52 const SwfdecColorTransform *trans, const SwfdecRect *inval)
54 SwfdecShape *shape = SWFDEC_SHAPE (graphic);
55 GSList *walk;
57 for (walk = shape->draws; walk; walk = walk->next) {
58 SwfdecDraw *draw = walk->data;
60 if (!swfdec_rect_intersect (NULL, &draw->extents, inval))
61 continue;
63 swfdec_draw_paint (draw, cr, trans);
67 static gboolean
68 swfdec_shape_mouse_in (SwfdecGraphic *graphic, double x, double y)
70 SwfdecShape *shape = SWFDEC_SHAPE (graphic);
71 GSList *walk;
73 for (walk = shape->draws; walk; walk = walk->next) {
74 SwfdecDraw *draw = walk->data;
76 if (swfdec_draw_contains (draw, x, y))
77 return TRUE;
79 return FALSE;
82 static void
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;
94 static void
95 swfdec_shape_init (SwfdecShape * shape)
99 int
100 tag_define_shape (SwfdecSwfDecoder * s, guint tag)
102 SwfdecBits *bits = &s->b;
103 SwfdecShape *shape;
104 SwfdecShapeParser *parser;
105 int id;
107 id = swfdec_bits_get_u16 (bits);
109 shape = swfdec_swf_decoder_create_character (s, id, SWFDEC_TYPE_SHAPE);
110 if (!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;
129 SwfdecShape *shape;
130 SwfdecShapeParser *parser;
131 int id;
133 id = swfdec_bits_get_u16 (bits);
134 shape = swfdec_swf_decoder_create_character (s, id, SWFDEC_TYPE_SHAPE);
135 if (!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;
152 SwfdecShape *shape;
153 SwfdecShapeParser *parser;
154 int id;
155 SwfdecRect tmp;
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);
160 if (!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;
184 #if 0
185 /*** MORPH SHAPE ***/
187 #include "swfdec_morphshape.h"
189 static SubPath *
190 swfdec_morph_shape_do_change (SwfdecBits *end_bits, SubPath *other, SwfdecMorphShape *morph,
191 GArray *path_array, SubPath *path, int *x, int *y)
193 if (path) {
194 path->x_end = *x;
195 path->y_end = *y;
197 g_array_set_size (path_array, path_array->len + 1);
198 path = &g_array_index (path_array, SubPath, path_array->len - 1);
199 *path = *other;
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);
214 if (state_moveto) {
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);
240 path->x_start = *x;
241 path->y_start = *y;
242 return path;
245 static void
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) {
262 SubPath *path;
263 if (start_path) {
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);
269 if (start_path)
270 *path = *start_path;
271 start_path = path;
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);
276 continue;
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);
283 break;
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);
291 } else {
292 SWFDEC_ERROR ("edge type didn't match, wanted line or curve, but got %s",
293 end_type ? "change" : "end");
294 goto error;
296 break;
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);
303 } else {
304 SWFDEC_ERROR ("edge type didn't match, wanted line or curve, but got %s",
305 end_type ? "change" : "end");
306 goto error;
308 break;
309 case SWFDEC_SHAPE_TYPE_END:
310 default:
311 g_assert_not_reached ();
312 break;
315 if (start_path) {
316 start_path->x_end = start_x;
317 start_path->y_end = start_y;
319 if (end_path) {
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);
330 error:
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
336 tmp = shape->vecs;
337 shape->vecs = morph->end_vecs;
338 swfdec_shape_initialize_from_sub_paths (shape, end_path_array);
339 morph->end_vecs = shape->vecs;
340 shape->vecs = tmp;
341 swfdec_shape_initialize_from_sub_paths (shape, start_path_array);
342 g_assert (morph->end_vecs->len == shape->vecs->len);
344 #endif
346 #if 0
347 SwfdecBits end_bits;
348 SwfdecBits *bits = &s->b;
349 SwfdecMorphShape *morph;
350 guint offset;
351 int id;
352 id = swfdec_bits_get_u16 (bits);
354 morph = swfdec_swf_decoder_create_character (s, id, SWFDEC_TYPE_MORPH_SHAPE);
355 if (!morph)
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);
363 end_bits = *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));
383 s->b = end_bits;
385 return SWFDEC_STATUS_OK;
387 #endif