Bug 22803 - Make header conform to implementation
[swfdec.git] / swfdec / swfdec_shape.c
blobd873b03d5e6ecaa970b18cd411f672681dc459bb
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)
54 SwfdecShape *shape = SWFDEC_SHAPE (graphic);
55 SwfdecRect inval;
56 GSList *walk;
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))
64 continue;
66 swfdec_draw_paint (draw, cr, trans);
70 static gboolean
71 swfdec_shape_mouse_in (SwfdecGraphic *graphic, double x, double y)
73 SwfdecShape *shape = SWFDEC_SHAPE (graphic);
74 GSList *walk;
76 for (walk = shape->draws; walk; walk = walk->next) {
77 SwfdecDraw *draw = walk->data;
79 if (swfdec_draw_contains (draw, x, y))
80 return TRUE;
82 return FALSE;
85 static void
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;
97 static void
98 swfdec_shape_init (SwfdecShape * shape)
103 tag_define_shape (SwfdecSwfDecoder * s, guint tag)
105 SwfdecBits *bits = &s->b;
106 SwfdecShape *shape;
107 SwfdecShapeParser *parser;
108 int id;
110 id = swfdec_bits_get_u16 (bits);
112 shape = swfdec_swf_decoder_create_character (s, id, SWFDEC_TYPE_SHAPE);
113 if (!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;
132 SwfdecShape *shape;
133 SwfdecShapeParser *parser;
134 int id;
136 id = swfdec_bits_get_u16 (bits);
137 shape = swfdec_swf_decoder_create_character (s, id, SWFDEC_TYPE_SHAPE);
138 if (!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;
155 SwfdecShape *shape;
156 SwfdecShapeParser *parser;
157 int id;
158 SwfdecRect tmp;
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);
163 if (!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;
187 #if 0
188 /*** MORPH SHAPE ***/
190 #include "swfdec_morphshape.h"
192 static SubPath *
193 swfdec_morph_shape_do_change (SwfdecBits *end_bits, SubPath *other, SwfdecMorphShape *morph,
194 GArray *path_array, SubPath *path, int *x, int *y)
196 if (path) {
197 path->x_end = *x;
198 path->y_end = *y;
200 g_array_set_size (path_array, path_array->len + 1);
201 path = &g_array_index (path_array, SubPath, path_array->len - 1);
202 *path = *other;
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);
217 if (state_moveto) {
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);
243 path->x_start = *x;
244 path->y_start = *y;
245 return path;
248 static void
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) {
265 SubPath *path;
266 if (start_path) {
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);
272 if (start_path)
273 *path = *start_path;
274 start_path = path;
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);
279 continue;
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);
286 break;
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);
294 } else {
295 SWFDEC_ERROR ("edge type didn't match, wanted line or curve, but got %s",
296 end_type ? "change" : "end");
297 goto error;
299 break;
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);
306 } else {
307 SWFDEC_ERROR ("edge type didn't match, wanted line or curve, but got %s",
308 end_type ? "change" : "end");
309 goto error;
311 break;
312 case SWFDEC_SHAPE_TYPE_END:
313 default:
314 g_assert_not_reached ();
315 break;
318 if (start_path) {
319 start_path->x_end = start_x;
320 start_path->y_end = start_y;
322 if (end_path) {
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);
333 error:
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
339 tmp = shape->vecs;
340 shape->vecs = morph->end_vecs;
341 swfdec_shape_initialize_from_sub_paths (shape, end_path_array);
342 morph->end_vecs = shape->vecs;
343 shape->vecs = tmp;
344 swfdec_shape_initialize_from_sub_paths (shape, start_path_array);
345 g_assert (morph->end_vecs->len == shape->vecs->len);
347 #endif
349 #if 0
350 SwfdecBits end_bits;
351 SwfdecBits *bits = &s->b;
352 SwfdecMorphShape *morph;
353 guint offset;
354 int id;
355 id = swfdec_bits_get_u16 (bits);
357 morph = swfdec_swf_decoder_create_character (s, id, SWFDEC_TYPE_MORPH_SHAPE);
358 if (!morph)
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);
366 end_bits = *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));
386 s->b = end_bits;
388 return SWFDEC_STATUS_OK;
390 #endif