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_stroke.h"
34 G_DEFINE_TYPE (SwfdecShape
, swfdec_shape
, SWFDEC_TYPE_GRAPHIC
)
39 swfdec_path_init (cairo_path_t
*path
)
41 path
->status
= CAIRO_STATUS_SUCCESS
;
47 swfdec_path_reset (cairo_path_t
*path
)
49 path
->status
= CAIRO_STATUS_SUCCESS
;
55 #define swfdec_path_require_size(path, steps) \
56 swfdec_path_ensure_size ((path), (path)->num_data + steps)
58 swfdec_path_ensure_size (cairo_path_t
*path
, int size
)
60 #define SWFDEC_PATH_STEPS 32
61 /* round up to next multiple of SWFDEC_PATH_STEPS */
62 int current_size
= path
->num_data
- path
->num_data
% SWFDEC_PATH_STEPS
;
63 if (path
->num_data
% SWFDEC_PATH_STEPS
)
64 current_size
+= SWFDEC_PATH_STEPS
;
66 if (size
% SWFDEC_PATH_STEPS
)
67 size
+= SWFDEC_PATH_STEPS
- size
% SWFDEC_PATH_STEPS
;
68 g_assert (current_size
% SWFDEC_PATH_STEPS
== 0);
69 g_assert (size
% SWFDEC_PATH_STEPS
== 0);
70 while (size
<= current_size
)
72 SWFDEC_LOG ("extending size of %p from %u to %u", path
, current_size
, size
);
73 path
->data
= g_renew (cairo_path_data_t
, path
->data
, size
);
77 swfdec_path_move_to (cairo_path_t
*path
, double x
, double y
)
79 cairo_path_data_t
*cur
;
81 swfdec_path_require_size (path
, 2);
82 cur
= &path
->data
[path
->num_data
++];
83 cur
->header
.type
= CAIRO_PATH_MOVE_TO
;
84 cur
->header
.length
= 2;
85 cur
= &path
->data
[path
->num_data
++];
91 swfdec_path_line_to (cairo_path_t
*path
, double x
, double y
)
93 cairo_path_data_t
*cur
;
95 swfdec_path_require_size (path
, 2);
96 cur
= &path
->data
[path
->num_data
++];
97 cur
->header
.type
= CAIRO_PATH_LINE_TO
;
98 cur
->header
.length
= 2;
99 cur
= &path
->data
[path
->num_data
++];
105 swfdec_path_curve_to (cairo_path_t
*path
, double start_x
, double start_y
,
106 double control_x
, double control_y
, double end_x
, double end_y
)
108 cairo_path_data_t
*cur
;
110 swfdec_path_require_size (path
, 4);
111 cur
= &path
->data
[path
->num_data
++];
112 cur
->header
.type
= CAIRO_PATH_CURVE_TO
;
113 cur
->header
.length
= 4;
114 #define WEIGHT (2.0/3.0)
115 cur
= &path
->data
[path
->num_data
++];
116 cur
->point
.x
= control_x
* WEIGHT
+ (1-WEIGHT
) * start_x
;
117 cur
->point
.y
= control_y
* WEIGHT
+ (1-WEIGHT
) * start_y
;
118 cur
= &path
->data
[path
->num_data
++];
119 cur
->point
.x
= control_x
* WEIGHT
+ (1-WEIGHT
) * end_x
;
120 cur
->point
.y
= control_y
* WEIGHT
+ (1-WEIGHT
) * end_y
;
121 cur
= &path
->data
[path
->num_data
++];
122 cur
->point
.x
= end_x
;
123 cur
->point
.y
= end_y
;
127 swfdec_path_append (cairo_path_t
*path
, const cairo_path_t
*append
)
129 swfdec_path_require_size (path
, append
->num_data
);
130 memcpy (&path
->data
[path
->num_data
], append
->data
, sizeof (cairo_path_data_t
) * append
->num_data
);
131 path
->num_data
+= append
->num_data
;
135 swfdec_path_append_reverse (cairo_path_t
*path
, const cairo_path_t
*append
,
138 cairo_path_data_t
*out
, *in
;
141 swfdec_path_require_size (path
, append
->num_data
);
142 path
->num_data
+= append
->num_data
;
143 out
= &path
->data
[path
->num_data
- 1];
145 for (i
= 0; i
< append
->num_data
; i
++) {
146 switch (in
[i
].header
.type
) {
147 case CAIRO_PATH_LINE_TO
:
150 out
[-i
- 1].header
= in
[i
].header
;
153 case CAIRO_PATH_CURVE_TO
:
156 out
[-i
- 3].header
= in
[i
].header
;
157 out
[-i
- 1].point
= in
[i
+ 1].point
;
158 out
[-i
- 2].point
= in
[i
+ 2].point
;
161 case CAIRO_PATH_CLOSE_PATH
:
162 case CAIRO_PATH_MOVE_TO
:
163 /* these two don't exist in our code */
165 g_assert_not_reached ();
175 int x_start
, y_start
;
187 swfdec_shape_vec_finish (SwfdecShapeVec
* shapevec
)
189 if (shapevec
->pattern
) {
190 g_object_unref (shapevec
->pattern
);
191 shapevec
->pattern
= NULL
;
193 if (shapevec
->fill_cr
) {
194 cairo_destroy (shapevec
->fill_cr
);
195 shapevec
->fill_cr
= NULL
;
198 swfdec_path_reset (&shapevec
->path
);
202 swfdec_shape_vec_init (SwfdecShapeVec
*vec
)
204 swfdec_path_init (&vec
->path
);
208 swfdec_shape_dispose (GObject
*object
)
211 SwfdecShape
* shape
= SWFDEC_SHAPE (object
);
213 for (i
= 0; i
< shape
->vecs
->len
; i
++) {
214 swfdec_shape_vec_finish (&g_array_index (shape
->vecs
, SwfdecShapeVec
, i
));
216 g_array_free (shape
->vecs
, TRUE
);
217 for (i
= 0; i
< shape
->fills
->len
; i
++) {
218 if (g_ptr_array_index (shape
->fills
, i
))
219 g_object_unref (g_ptr_array_index (shape
->fills
, i
));
221 g_ptr_array_free (shape
->fills
, TRUE
);
223 for (i
= 0; i
< shape
->lines
->len
; i
++) {
224 if (g_ptr_array_index (shape
->lines
, i
))
225 g_object_unref (g_ptr_array_index (shape
->lines
, i
));
227 g_ptr_array_free (shape
->lines
, TRUE
);
229 G_OBJECT_CLASS (swfdec_shape_parent_class
)->dispose (G_OBJECT (shape
));
233 swfdec_shape_render (SwfdecGraphic
*graphic
, cairo_t
*cr
,
234 const SwfdecColorTransform
*trans
, const SwfdecRect
*inval
, gboolean fill
)
236 SwfdecShape
*shape
= SWFDEC_SHAPE (graphic
);
239 cairo_set_operator (cr
, CAIRO_OPERATOR_OVER
);
240 cairo_set_fill_rule (cr
, CAIRO_FILL_RULE_EVEN_ODD
);
242 for (i
= 0; i
< shape
->vecs
->len
; i
++) {
243 SwfdecShapeVec
*vec
= &g_array_index (shape
->vecs
, SwfdecShapeVec
, i
);
245 g_assert (vec
->path
.num_data
);
246 g_assert (vec
->pattern
);
247 if (!swfdec_rect_intersect (NULL
, &vec
->extents
, inval
))
250 /* hack to not append paths for lines */
251 if (!fill
&& vec
->last_index
% 2 != 0)
255 if (SWFDEC_IS_PATTERN (vec
->pattern
)) {
256 swfdec_pattern_paint (vec
->pattern
, cr
, &vec
->path
, trans
, 0);
258 swfdec_stroke_paint (vec
->pattern
, cr
, &vec
->path
, trans
, 0);
261 cairo_append_path (cr
, &vec
->path
);
267 swfdec_shape_mouse_in (SwfdecGraphic
*graphic
, double x
, double y
)
269 SwfdecShapeVec
*shapevec
;
270 SwfdecShape
*shape
= SWFDEC_SHAPE (graphic
);
271 static cairo_surface_t
*surface
= NULL
;
274 for (i
= 0; i
< shape
->vecs
->len
; i
++) {
275 shapevec
= &g_array_index (shape
->vecs
, SwfdecShapeVec
, i
);
277 g_assert (shapevec
->path
.num_data
);
278 g_assert (shapevec
->pattern
);
279 /* FIXME: handle strokes */
280 if (SWFDEC_IS_STROKE (shapevec
->pattern
))
282 if (shapevec
->fill_cr
== NULL
) {
283 /* FIXME: do less memory intensive fill checking plz */
285 surface
= cairo_image_surface_create (CAIRO_FORMAT_A8
, 1, 1);
286 shapevec
->fill_cr
= cairo_create (surface
);
287 cairo_set_fill_rule (shapevec
->fill_cr
, CAIRO_FILL_RULE_EVEN_ODD
);
288 cairo_append_path (shapevec
->fill_cr
, &shapevec
->path
);
290 if (cairo_in_fill (shapevec
->fill_cr
, x
, y
))
297 swfdec_shape_class_init (SwfdecShapeClass
* g_class
)
299 GObjectClass
*object_class
= G_OBJECT_CLASS (g_class
);
300 SwfdecGraphicClass
*graphic_class
= SWFDEC_GRAPHIC_CLASS (g_class
);
302 object_class
->dispose
= swfdec_shape_dispose
;
304 graphic_class
->render
= swfdec_shape_render
;
305 graphic_class
->mouse_in
= swfdec_shape_mouse_in
;
309 swfdec_shape_init (SwfdecShape
* shape
)
311 shape
->fills
= g_ptr_array_new ();
312 shape
->lines
= g_ptr_array_new ();
313 shape
->vecs
= g_array_new (FALSE
, TRUE
, sizeof (SwfdecShapeVec
));
317 swfdec_shape_add_styles (SwfdecSwfDecoder
* s
, SwfdecShape
* shape
,
318 SwfdecPatternFunc parse_fill
, SwfdecStrokeFunc parse_stroke
)
323 SwfdecBits
*bits
= &s
->b
;
325 swfdec_bits_syncbits (bits
);
326 shape
->fills_offset
= shape
->fills
->len
;
327 n_fill_styles
= swfdec_bits_get_u8 (bits
);
328 if (n_fill_styles
== 0xff) {
329 n_fill_styles
= swfdec_bits_get_u16 (bits
);
331 SWFDEC_LOG (" n_fill_styles %d", n_fill_styles
);
332 for (i
= 0; i
< n_fill_styles
&& swfdec_bits_left (bits
); i
++) {
333 SwfdecPattern
*pattern
;
335 SWFDEC_LOG (" fill style %d:", i
);
337 pattern
= parse_fill (s
);
338 g_ptr_array_add (shape
->fills
, pattern
);
341 shape
->lines_offset
= shape
->lines
->len
;
342 n_line_styles
= swfdec_bits_get_u8 (bits
);
343 if (n_line_styles
== 0xff) {
344 n_line_styles
= swfdec_bits_get_u16 (bits
);
346 SWFDEC_LOG (" n_line_styles %d", n_line_styles
);
347 for (i
= 0; i
< n_line_styles
&& swfdec_bits_left (bits
); i
++) {
348 g_ptr_array_add (shape
->lines
, parse_stroke (s
));
351 shape
->n_fill_bits
= swfdec_bits_getbits (bits
, 4);
352 shape
->n_line_bits
= swfdec_bits_getbits (bits
, 4);
356 tag_define_shape (SwfdecSwfDecoder
* s
, guint tag
)
358 SwfdecBits
*bits
= &s
->b
;
362 id
= swfdec_bits_get_u16 (bits
);
364 shape
= swfdec_swf_decoder_create_character (s
, id
, SWFDEC_TYPE_SHAPE
);
366 return SWFDEC_STATUS_OK
;
368 SWFDEC_INFO ("id=%d", id
);
370 swfdec_bits_get_rect (bits
, &SWFDEC_GRAPHIC (shape
)->extents
);
372 swfdec_shape_add_styles (s
, shape
, swfdec_pattern_parse
, swfdec_stroke_parse
);
374 swfdec_shape_get_recs (s
, shape
, swfdec_pattern_parse
, swfdec_stroke_parse
);
376 return SWFDEC_STATUS_OK
;
380 tag_define_shape_3 (SwfdecSwfDecoder
* s
, guint tag
)
382 SwfdecBits
*bits
= &s
->b
;
386 id
= swfdec_bits_get_u16 (bits
);
387 shape
= swfdec_swf_decoder_create_character (s
, id
, SWFDEC_TYPE_SHAPE
);
389 return SWFDEC_STATUS_OK
;
391 swfdec_bits_get_rect (bits
, &SWFDEC_GRAPHIC (shape
)->extents
);
393 swfdec_shape_add_styles (s
, shape
, swfdec_pattern_parse_rgba
, swfdec_stroke_parse_rgba
);
395 swfdec_shape_get_recs (s
, shape
, swfdec_pattern_parse_rgba
, swfdec_stroke_parse_rgba
);
397 return SWFDEC_STATUS_OK
;
401 tag_define_shape_4 (SwfdecSwfDecoder
*s
, guint tag
)
403 SwfdecBits
*bits
= &s
->b
;
407 gboolean has_scale_strokes
, has_noscale_strokes
;
409 id
= swfdec_bits_get_u16 (bits
);
410 shape
= swfdec_swf_decoder_create_character (s
, id
, SWFDEC_TYPE_SHAPE
);
412 return SWFDEC_STATUS_OK
;
414 swfdec_bits_get_rect (bits
, &SWFDEC_GRAPHIC (shape
)->extents
);
415 SWFDEC_LOG (" extents: %g %g x %g %g",
416 SWFDEC_GRAPHIC (shape
)->extents
.x0
, SWFDEC_GRAPHIC (shape
)->extents
.y0
,
417 SWFDEC_GRAPHIC (shape
)->extents
.x1
, SWFDEC_GRAPHIC (shape
)->extents
.y1
);
418 swfdec_bits_get_rect (bits
, &tmp
);
419 SWFDEC_LOG (" extents: %g %g x %g %g",
420 tmp
.x0
, tmp
.y0
, tmp
.x1
, tmp
.y1
);
421 swfdec_bits_getbits (bits
, 6);
422 has_scale_strokes
= swfdec_bits_getbit (bits
);
423 has_noscale_strokes
= swfdec_bits_getbit (bits
);
424 SWFDEC_LOG (" has scaling strokes: %d", has_scale_strokes
);
425 SWFDEC_LOG (" has non-scaling strokes: %d", has_noscale_strokes
);
427 swfdec_shape_add_styles (s
, shape
, swfdec_pattern_parse_rgba
, swfdec_stroke_parse_extended
);
429 swfdec_shape_get_recs (s
, shape
, swfdec_pattern_parse_rgba
, swfdec_stroke_parse_extended
);
431 return SWFDEC_STATUS_OK
;
434 /* The shape creation process is a bit complicated since it requires matching
435 * the Flash model to the cairo model. Note that this code is just random
436 * guessing and nothing substantial. Otherwise I'd have a testsuite. :)
437 * It does the following steps:
438 * - Accumulate all sub path into an array of SubPath structs. a sub path is
439 * the path between 2 style change records.
440 * - For every fill style used, accumulate all paths in order of appearance.
441 * The code assumes that every fill path is closed.
442 * - Collect the lines.
443 * - Sort the array so that lines get drawn after their left and right fill,
444 * but as early as possible. SubPath.max_index and ShapeVec.last_index are
447 /* FIXME: It might be that the Flash code uses a different order, namely
448 * drawing all fills followed by all lines per style record. So everything after
449 * new styles appeared is drawn later.
450 * The current code works though, so I'm not interested in testing that idea ;)
454 swfdec_shape_accumulate_one_polygon (SwfdecShape
*shape
, SwfdecShapeVec
*target
,
455 guint style
, SubPath
*paths
, guint start
, guint paths_len
, guint
*max
)
458 GSList
*found
= NULL
;
461 g_assert (style
!= 0);
462 /* paths[start] is our starting point */
463 if (paths
[start
].fill0style
== style
) {
464 paths
[start
].fill0style
= 0;
466 g_assert (style
== paths
[start
].fill1style
);
467 paths
[start
].fill1style
= 0;
469 x
= paths
[start
].x_end
;
470 y
= paths
[start
].y_end
;
471 found
= g_slist_prepend (found
, &paths
[start
]);
473 swfdec_path_move_to (&target
->path
, paths
[start
].x_start
, paths
[start
].y_start
);
474 swfdec_path_append (&target
->path
, &paths
[start
].path
);
475 while (x
!= paths
[start
].x_start
|| y
!= paths
[start
].y_start
) {
476 SWFDEC_LOG ("now looking for point %u %u", x
, y
);
477 for (i
= start
; i
< paths_len
; i
++) {
478 if (paths
[i
].fill0style
!= style
&& paths
[i
].fill1style
!= style
)
480 if (paths
[i
].x_start
== x
&& paths
[i
].y_start
== y
) {
481 SWFDEC_LOG (" found it %u", i
);
484 swfdec_path_append (&target
->path
, &paths
[i
].path
);
485 } else if (paths
[i
].x_end
== x
&& paths
[i
].y_end
== y
) {
486 SWFDEC_LOG (" found it reverse %u", i
);
487 x
= paths
[i
].x_start
;
488 y
= paths
[i
].y_start
;
489 swfdec_path_append_reverse (&target
->path
, &paths
[i
].path
, x
, y
);
493 if (paths
[i
].fill0style
== style
)
494 paths
[i
].fill0style
= 0;
496 paths
[i
].fill1style
= 0;
497 found
= g_slist_prepend (found
, &paths
[i
]);
501 if (i
== paths_len
) {
502 SWFDEC_ERROR ("could not find a closed path for style %u, starting at %d %d", style
,
503 paths
[start
].x_start
, paths
[start
].y_start
);
510 g_slist_free (found
);
515 swfdec_shape_accumulate_one_fill (SwfdecShape
*shape
, SubPath
*paths
,
516 guint start
, guint paths_len
)
518 SwfdecShapeVec
*target
;
519 guint i
, style
, max
= 0, cur
;
520 GSList
*walk
, *found
= NULL
;
522 g_array_set_size (shape
->vecs
, shape
->vecs
->len
+ 1);
523 target
= &g_array_index (shape
->vecs
, SwfdecShapeVec
, shape
->vecs
->len
- 1);
524 swfdec_shape_vec_init (target
);
525 if (paths
[start
].fill0style
!= 0)
526 style
= paths
[start
].fill0style
;
528 style
= paths
[start
].fill1style
;
530 for (i
= start
; i
< paths_len
; i
++) {
531 if (paths
[i
].fill0style
== style
) {
532 walk
= swfdec_shape_accumulate_one_polygon (shape
, target
, style
,
533 paths
, i
, paths_len
, &cur
);
535 found
= g_slist_concat (found
, walk
);
536 max
= MAX (max
, cur
);
541 if (paths
[i
].fill1style
== style
) {
542 walk
= swfdec_shape_accumulate_one_polygon (shape
, target
, style
,
543 paths
, i
, paths_len
, &cur
);
545 found
= g_slist_concat (found
, walk
);
546 max
= MAX (max
, cur
);
552 target
->last_index
= 2 * max
;
553 for (walk
= found
; walk
; walk
= walk
->next
) {
554 SubPath
*sub
= walk
->data
;
555 sub
->max_index
= MAX (sub
->max_index
, max
);
557 if (style
> shape
->fills
->len
) {
558 SWFDEC_ERROR ("style index %u is too big, only %u styles available", style
,
562 target
->pattern
= g_ptr_array_index (shape
->fills
, style
- 1);
563 if (target
->pattern
== NULL
)
565 g_object_ref (target
->pattern
);
567 g_slist_free (found
);
571 g_slist_free (found
);
572 swfdec_shape_vec_finish (target
);
573 g_array_set_size (shape
->vecs
, shape
->vecs
->len
- 1);
577 swfdec_shape_accumulate_fills (SwfdecShape
*shape
, SubPath
*paths
, guint paths_len
)
581 for (i
= 0; i
< paths_len
; i
++) {
582 if (paths
[i
].fill0style
!= 0)
583 swfdec_shape_accumulate_one_fill (shape
, paths
, i
, paths_len
);
584 if (paths
[i
].fill1style
!= 0)
585 swfdec_shape_accumulate_one_fill (shape
, paths
, i
, paths_len
);
590 swfdec_shape_accumulate_lines (SwfdecShape
*shape
, SubPath
*paths
, guint paths_len
)
592 SwfdecShapeVec target
= { 0, };
595 for (i
= 0; i
< paths_len
; i
++) {
596 if (paths
[i
].linestyle
== 0)
598 if (paths
[i
].linestyle
> shape
->lines
->len
) {
599 SWFDEC_ERROR ("linestyle index %u is too big, only %u styles available",
600 paths
[i
].linestyle
, shape
->lines
->len
);
604 swfdec_shape_vec_init (&target
);
605 swfdec_path_move_to (&target
.path
, paths
[i
].x_start
, paths
[i
].y_start
);
606 swfdec_path_append (&target
.path
, &paths
[i
].path
);
607 target
.pattern
= g_ptr_array_index (shape
->lines
, paths
[i
].linestyle
- 1);
608 g_object_ref (target
.pattern
);
609 target
.last_index
= 2 * paths
[i
].max_index
+ 1;
610 g_array_append_val (shape
->vecs
, target
);
615 swfdec_shape_vec_compare (gconstpointer a
, gconstpointer b
)
617 return ((const SwfdecShapeVec
*) a
)->last_index
- ((const SwfdecShapeVec
*) b
)->last_index
;
621 SWFDEC_SHAPE_TYPE_END
,
622 SWFDEC_SHAPE_TYPE_CHANGE
,
623 SWFDEC_SHAPE_TYPE_LINE
,
624 SWFDEC_SHAPE_TYPE_CURVE
627 static SwfdecShapeType
628 swfdec_shape_peek_type (SwfdecBits
*bits
)
630 guint ret
= swfdec_bits_peekbits (bits
, 6);
633 return SWFDEC_SHAPE_TYPE_END
;
634 if ((ret
& 0x20) == 0)
635 return SWFDEC_SHAPE_TYPE_CHANGE
;
636 if ((ret
& 0x10) == 0)
637 return SWFDEC_SHAPE_TYPE_CURVE
;
638 return SWFDEC_SHAPE_TYPE_LINE
;
642 swfdec_shape_parse_curve (SwfdecBits
*bits
, SubPath
*path
,
647 int control_x
, control_y
;
649 if (swfdec_bits_getbits (bits
, 2) != 2) {
650 g_assert_not_reached ();
653 n_bits
= swfdec_bits_getbits (bits
, 4) + 2;
658 control_x
= cur_x
+ swfdec_bits_getsbits (bits
, n_bits
);
659 control_y
= cur_y
+ swfdec_bits_getsbits (bits
, n_bits
);
660 SWFDEC_LOG (" control %d,%d", control_x
, control_y
);
662 *x
= control_x
+ swfdec_bits_getsbits (bits
, n_bits
);
663 *y
= control_y
+ swfdec_bits_getsbits (bits
, n_bits
);
664 SWFDEC_LOG (" anchor %d,%d", *x
, *y
);
666 swfdec_path_curve_to (&path
->path
,
668 control_x
, control_y
,
671 SWFDEC_ERROR ("no path to curve in");
676 swfdec_shape_parse_line (SwfdecBits
*bits
, SubPath
*path
,
677 int *x
, int *y
, gboolean add_as_curve
)
680 int general_line_flag
;
683 if (swfdec_bits_getbits (bits
, 2) != 3) {
684 g_assert_not_reached ();
689 n_bits
= swfdec_bits_getbits (bits
, 4) + 2;
690 general_line_flag
= swfdec_bits_getbit (bits
);
691 if (general_line_flag
== 1) {
692 *x
+= swfdec_bits_getsbits (bits
, n_bits
);
693 *y
+= swfdec_bits_getsbits (bits
, n_bits
);
695 int vert_line_flag
= swfdec_bits_getbit (bits
);
696 if (vert_line_flag
== 0) {
697 *x
+= swfdec_bits_getsbits (bits
, n_bits
);
699 *y
+= swfdec_bits_getsbits (bits
, n_bits
);
702 SWFDEC_LOG (" line to %d,%d", *x
, *y
);
705 swfdec_path_curve_to (&path
->path
, cur_x
, cur_y
,
706 (cur_x
+ *x
) / 2, (cur_y
+ *y
) / 2, *x
, *y
);
708 swfdec_path_line_to (&path
->path
, *x
, *y
);
710 SWFDEC_ERROR ("no path to line in");
715 swfdec_shape_parse_change (SwfdecSwfDecoder
*s
, SwfdecShape
*shape
, GArray
*path_array
, SubPath
*path
,
716 int *x
, int *y
, SwfdecPatternFunc parse_fill
, SwfdecStrokeFunc parse_stroke
)
718 int state_new_styles
, state_line_styles
, state_fill_styles1
, state_fill_styles0
, state_moveto
;
719 SwfdecBits
*bits
= &s
->b
;
721 if (swfdec_bits_getbit (bits
) != 0) {
722 g_assert_not_reached ();
725 state_new_styles
= swfdec_bits_getbit (bits
);
726 state_line_styles
= swfdec_bits_getbit (bits
);
727 state_fill_styles1
= swfdec_bits_getbit (bits
);
728 state_fill_styles0
= swfdec_bits_getbit (bits
);
729 state_moveto
= swfdec_bits_getbit (bits
);
735 g_array_set_size (path_array
, path_array
->len
+ 1);
736 path
= &g_array_index (path_array
, SubPath
, path_array
->len
- 1);
737 if (path_array
->len
> 1)
738 *path
= g_array_index (path_array
, SubPath
, path_array
->len
- 2);
739 swfdec_path_init (&path
->path
);
741 int n_bits
= swfdec_bits_getbits (bits
, 5);
742 *x
= swfdec_bits_getsbits (bits
, n_bits
);
743 *y
= swfdec_bits_getsbits (bits
, n_bits
);
745 SWFDEC_LOG (" moveto %d,%d", *x
, *y
);
749 if (state_fill_styles0
) {
750 path
->fill0style
= swfdec_bits_getbits (bits
, shape
->n_fill_bits
);
751 if (path
->fill0style
)
752 path
->fill0style
+= shape
->fills_offset
;
753 SWFDEC_LOG (" * fill0style = %d", path
->fill0style
);
755 SWFDEC_LOG (" * not changing fill0style");
757 if (state_fill_styles1
) {
758 path
->fill1style
= swfdec_bits_getbits (bits
, shape
->n_fill_bits
);
759 if (path
->fill1style
)
760 path
->fill1style
+= shape
->fills_offset
;
761 SWFDEC_LOG (" * fill1style = %d", path
->fill1style
);
763 SWFDEC_LOG (" * not changing fill1style");
765 if (state_line_styles
) {
766 path
->linestyle
= swfdec_bits_getbits (bits
, shape
->n_line_bits
);
768 path
->linestyle
+= shape
->lines_offset
;
769 SWFDEC_LOG (" * linestyle = %d", path
->linestyle
);
771 SWFDEC_LOG (" * not changing linestyle");
773 if (state_new_styles
) {
774 guint old_fills_offset
= shape
->fills_offset
;
775 guint old_lines_offset
= shape
->lines_offset
;
776 SWFDEC_LOG (" * new styles");
777 swfdec_shape_add_styles (s
, shape
, parse_fill
, parse_stroke
);
778 if (path
->fill0style
)
779 path
->fill0style
+= shape
->fills_offset
- old_fills_offset
;
780 if (path
->fill1style
)
781 path
->fill1style
+= shape
->fills_offset
- old_fills_offset
;
783 path
->linestyle
+= shape
->lines_offset
- old_lines_offset
;
789 swfdec_shape_initialize_from_sub_paths (SwfdecShape
*shape
, GArray
*path_array
)
795 for (i
= 0; i
< path_array
->len
; i
++) {
796 SubPath
*path
= &g_array_index (path_array
, SubPath
, i
);
797 g_print ("%d %d => %d %d - %u %u %u\n", path
->x_start
, path
->y_start
, path
->x_end
, path
->y_end
,
798 path
->fill0style
, path
->fill1style
, path
->linestyle
);
801 swfdec_shape_accumulate_fills (shape
, (SubPath
*) path_array
->data
, path_array
->len
);
802 swfdec_shape_accumulate_lines (shape
, (SubPath
*) path_array
->data
, path_array
->len
);
803 for (i
= 0; i
< path_array
->len
; i
++) {
804 swfdec_path_reset (&g_array_index (path_array
, SubPath
, i
).path
);
806 g_array_free (path_array
, TRUE
);
808 g_array_sort (shape
->vecs
, swfdec_shape_vec_compare
);
809 for (i
= 0; i
< shape
->vecs
->len
; i
++) {
810 SwfdecShapeVec
*vec
= &g_array_index (shape
->vecs
, SwfdecShapeVec
, i
);
811 swfdec_pattern_get_path_extents (vec
->pattern
, &vec
->path
, &vec
->extents
);
812 swfdec_rect_union (&SWFDEC_GRAPHIC (shape
)->extents
, &SWFDEC_GRAPHIC (shape
)->extents
, &vec
->extents
);
817 swfdec_shape_get_recs (SwfdecSwfDecoder
* s
, SwfdecShape
* shape
,
818 SwfdecPatternFunc pattern_func
, SwfdecStrokeFunc stroke_func
)
821 SubPath
*path
= NULL
;
823 SwfdecShapeType type
;
824 SwfdecBits
*bits
= &s
->b
;
826 /* First, accumulate all sub-paths into an array */
827 path_array
= g_array_new (FALSE
, TRUE
, sizeof (SubPath
));
829 while ((type
= swfdec_shape_peek_type (bits
))) {
831 case SWFDEC_SHAPE_TYPE_CHANGE
:
832 path
= swfdec_shape_parse_change (s
, shape
, path_array
, path
, &x
, &y
, pattern_func
, stroke_func
);
834 case SWFDEC_SHAPE_TYPE_LINE
:
835 swfdec_shape_parse_line (bits
, path
, &x
, &y
, FALSE
);
837 case SWFDEC_SHAPE_TYPE_CURVE
:
838 swfdec_shape_parse_curve (bits
, path
, &x
, &y
);
840 case SWFDEC_SHAPE_TYPE_END
:
842 g_assert_not_reached ();
850 swfdec_bits_getbits (bits
, 6);
851 swfdec_bits_syncbits (bits
);
853 swfdec_shape_initialize_from_sub_paths (shape
, path_array
);
856 /*** MORPH SHAPE ***/
858 #include "swfdec_morphshape.h"
861 swfdec_morph_shape_do_change (SwfdecBits
*end_bits
, SubPath
*other
, SwfdecMorphShape
*morph
,
862 GArray
*path_array
, SubPath
*path
, int *x
, int *y
)
868 g_array_set_size (path_array
, path_array
->len
+ 1);
869 path
= &g_array_index (path_array
, SubPath
, path_array
->len
- 1);
871 swfdec_path_init (&path
->path
);
872 if (swfdec_shape_peek_type (end_bits
) == SWFDEC_SHAPE_TYPE_CHANGE
) {
873 int state_line_styles
, state_fill_styles1
, state_fill_styles0
, state_moveto
;
875 if (swfdec_bits_getbit (end_bits
) != 0) {
876 g_assert_not_reached ();
878 if (swfdec_bits_getbit (end_bits
)) {
879 SWFDEC_ERROR ("new styles aren't allowed in end edges, ignoring");
881 state_line_styles
= swfdec_bits_getbit (end_bits
);
882 state_fill_styles1
= swfdec_bits_getbit (end_bits
);
883 state_fill_styles0
= swfdec_bits_getbit (end_bits
);
884 state_moveto
= swfdec_bits_getbit (end_bits
);
886 int n_bits
= swfdec_bits_getbits (end_bits
, 5);
887 *x
= swfdec_bits_getsbits (end_bits
, n_bits
);
888 *y
= swfdec_bits_getsbits (end_bits
, n_bits
);
890 SWFDEC_LOG (" moveto %d,%d", *x
, *y
);
892 if (state_fill_styles0
) {
893 guint check
= swfdec_bits_getbits (end_bits
, morph
->n_fill_bits
) +
894 SWFDEC_SHAPE (morph
)->fills_offset
;
895 if (check
!= path
->fill0style
)
896 SWFDEC_ERROR ("end fill0style %u differs from start fill0style %u", check
, path
->fill0style
);
898 if (state_fill_styles1
) {
899 guint check
= swfdec_bits_getbits (end_bits
, morph
->n_fill_bits
) +
900 SWFDEC_SHAPE (morph
)->fills_offset
;
901 if (check
!= path
->fill1style
)
902 SWFDEC_ERROR ("end fill1style %u differs from start fill1style %u", check
, path
->fill1style
);
904 if (state_line_styles
) {
905 guint check
= swfdec_bits_getbits (end_bits
, morph
->n_line_bits
) +
906 SWFDEC_SHAPE (morph
)->lines_offset
;
907 if (check
!= path
->linestyle
)
908 SWFDEC_ERROR ("end linestyle %u differs from start linestyle %u", check
, path
->linestyle
);
917 swfdec_morph_shape_get_recs (SwfdecSwfDecoder
* s
, SwfdecMorphShape
*morph
, SwfdecBits
*end_bits
)
919 int start_x
= 0, start_y
= 0, end_x
= 0, end_y
= 0;
920 SubPath
*start_path
= NULL
, *end_path
= NULL
;
921 GArray
*start_path_array
, *end_path_array
, *tmp
;
922 SwfdecShapeType start_type
, end_type
;
923 SwfdecBits
*start_bits
= &s
->b
;
924 SwfdecShape
*shape
= SWFDEC_SHAPE (morph
);
926 /* First, accumulate all sub-paths into an array */
927 start_path_array
= g_array_new (FALSE
, TRUE
, sizeof (SubPath
));
928 end_path_array
= g_array_new (FALSE
, TRUE
, sizeof (SubPath
));
930 while ((start_type
= swfdec_shape_peek_type (start_bits
))) {
931 end_type
= swfdec_shape_peek_type (end_bits
);
932 if (end_type
== SWFDEC_SHAPE_TYPE_CHANGE
&& start_type
!= SWFDEC_SHAPE_TYPE_CHANGE
) {
935 start_path
->x_end
= start_x
;
936 start_path
->y_end
= start_y
;
938 g_array_set_size (start_path_array
, start_path_array
->len
+ 1);
939 path
= &g_array_index (start_path_array
, SubPath
, start_path_array
->len
- 1);
943 swfdec_path_init (&start_path
->path
);
944 start_path
->x_start
= start_x
;
945 start_path
->y_start
= start_y
;
946 end_path
= swfdec_morph_shape_do_change (end_bits
, start_path
, morph
, end_path_array
, end_path
, &end_x
, &end_y
);
949 switch (start_type
) {
950 case SWFDEC_SHAPE_TYPE_CHANGE
:
951 start_path
= swfdec_shape_parse_change (s
, shape
, start_path_array
, start_path
, &start_x
, &start_y
,
952 swfdec_pattern_parse_morph
, swfdec_stroke_parse_morph
);
953 end_path
= swfdec_morph_shape_do_change (end_bits
, start_path
, morph
, end_path_array
, end_path
, &end_x
, &end_y
);
955 case SWFDEC_SHAPE_TYPE_LINE
:
956 if (end_type
== SWFDEC_SHAPE_TYPE_LINE
) {
957 swfdec_shape_parse_line (start_bits
, start_path
, &start_x
, &start_y
, FALSE
);
958 swfdec_shape_parse_line (end_bits
, end_path
, &end_x
, &end_y
, FALSE
);
959 } else if (end_type
== SWFDEC_SHAPE_TYPE_CURVE
) {
960 swfdec_shape_parse_line (start_bits
, start_path
, &start_x
, &start_y
, TRUE
);
961 swfdec_shape_parse_curve (end_bits
, end_path
, &end_x
, &end_y
);
963 SWFDEC_ERROR ("edge type didn't match, wanted line or curve, but got %s",
964 end_type
? "change" : "end");
968 case SWFDEC_SHAPE_TYPE_CURVE
:
969 swfdec_shape_parse_curve (start_bits
, start_path
, &start_x
, &start_y
);
970 if (end_type
== SWFDEC_SHAPE_TYPE_LINE
) {
971 swfdec_shape_parse_line (end_bits
, end_path
, &end_x
, &end_y
, TRUE
);
972 } else if (end_type
== SWFDEC_SHAPE_TYPE_CURVE
) {
973 swfdec_shape_parse_curve (end_bits
, end_path
, &end_x
, &end_y
);
975 SWFDEC_ERROR ("edge type didn't match, wanted line or curve, but got %s",
976 end_type
? "change" : "end");
980 case SWFDEC_SHAPE_TYPE_END
:
982 g_assert_not_reached ();
987 start_path
->x_end
= start_x
;
988 start_path
->y_end
= start_y
;
991 end_path
->x_end
= end_x
;
992 end_path
->y_end
= end_y
;
994 swfdec_bits_getbits (start_bits
, 6);
995 swfdec_bits_syncbits (start_bits
);
996 if (swfdec_bits_getbits (end_bits
, 6) != 0) {
997 SWFDEC_ERROR ("end shapes are not finished when start shapes are");
999 swfdec_bits_syncbits (end_bits
);
1002 /* FIXME: there's probably a problem if start and end paths get accumulated in
1003 * different ways, this could lead to the morphs not looking like they should.
1004 * Need a good testcase for this first though.
1005 * FIXME: Also, due to error handling, there needs to be syncing of code paths
1008 shape
->vecs
= morph
->end_vecs
;
1009 swfdec_shape_initialize_from_sub_paths (shape
, end_path_array
);
1010 morph
->end_vecs
= shape
->vecs
;
1012 swfdec_shape_initialize_from_sub_paths (shape
, start_path_array
);
1013 g_assert (morph
->end_vecs
->len
== shape
->vecs
->len
);
1017 tag_define_morph_shape (SwfdecSwfDecoder
* s
, guint tag
)
1019 SwfdecBits end_bits
;
1020 SwfdecBits
*bits
= &s
->b
;
1021 SwfdecMorphShape
*morph
;
1024 id
= swfdec_bits_get_u16 (bits
);
1026 morph
= swfdec_swf_decoder_create_character (s
, id
, SWFDEC_TYPE_MORPH_SHAPE
);
1028 return SWFDEC_STATUS_OK
;
1030 SWFDEC_INFO ("id=%d", id
);
1032 swfdec_bits_get_rect (bits
, &SWFDEC_GRAPHIC (morph
)->extents
);
1033 swfdec_bits_get_rect (bits
, &morph
->end_extents
);
1034 offset
= swfdec_bits_get_u32 (bits
);
1036 if (swfdec_bits_skip_bytes (&end_bits
, offset
) != offset
) {
1037 SWFDEC_ERROR ("wrong offset in DefineMorphShape");
1038 return SWFDEC_STATUS_OK
;
1040 bits
->end
= end_bits
.ptr
;
1042 swfdec_shape_add_styles (s
, SWFDEC_SHAPE (morph
),
1043 swfdec_pattern_parse_morph
, swfdec_stroke_parse_morph
);
1045 morph
->n_fill_bits
= swfdec_bits_getbits (&end_bits
, 4);
1046 morph
->n_line_bits
= swfdec_bits_getbits (&end_bits
, 4);
1047 SWFDEC_LOG ("%u fill bits, %u line bits in end shape", morph
->n_fill_bits
, morph
->n_line_bits
);
1049 swfdec_morph_shape_get_recs (s
, morph
, &end_bits
);
1050 if (swfdec_bits_left (&s
->b
)) {
1051 SWFDEC_WARNING ("early finish when parsing start shapes: %u bytes",
1052 swfdec_bits_left (&s
->b
));
1057 return SWFDEC_STATUS_OK
;