📄 swfdec_shape.c
字号:
inttag_define_shape (SwfdecSwfDecoder * s, guint tag){ SwfdecBits *bits = &s->b; SwfdecShape *shape; int id; id = swfdec_bits_get_u16 (bits); shape = swfdec_swf_decoder_create_character (s, id, SWFDEC_TYPE_SHAPE); if (!shape) return SWFDEC_STATUS_OK; SWFDEC_INFO ("id=%d", id); swfdec_bits_get_rect (bits, &SWFDEC_GRAPHIC (shape)->extents); swfdec_shape_add_styles (s, shape, swfdec_pattern_parse, swfdec_stroke_parse); swfdec_shape_get_recs (s, shape, swfdec_pattern_parse, swfdec_stroke_parse); return SWFDEC_STATUS_OK;}inttag_define_shape_3 (SwfdecSwfDecoder * s, guint tag){ SwfdecBits *bits = &s->b; SwfdecShape *shape; int id; id = swfdec_bits_get_u16 (bits); shape = swfdec_swf_decoder_create_character (s, id, SWFDEC_TYPE_SHAPE); if (!shape) return SWFDEC_STATUS_OK; swfdec_bits_get_rect (bits, &SWFDEC_GRAPHIC (shape)->extents); swfdec_shape_add_styles (s, shape, swfdec_pattern_parse_rgba, swfdec_stroke_parse_rgba); swfdec_shape_get_recs (s, shape, swfdec_pattern_parse_rgba, swfdec_stroke_parse_rgba); return SWFDEC_STATUS_OK;}inttag_define_shape_4 (SwfdecSwfDecoder *s, guint tag){ SwfdecBits *bits = &s->b; SwfdecShape *shape; int id; SwfdecRect tmp; gboolean has_scale_strokes, has_noscale_strokes; id = swfdec_bits_get_u16 (bits); shape = swfdec_swf_decoder_create_character (s, id, SWFDEC_TYPE_SHAPE); if (!shape) return SWFDEC_STATUS_OK; swfdec_bits_get_rect (bits, &SWFDEC_GRAPHIC (shape)->extents); SWFDEC_LOG (" extents: %g %g x %g %g", SWFDEC_GRAPHIC (shape)->extents.x0, SWFDEC_GRAPHIC (shape)->extents.y0, SWFDEC_GRAPHIC (shape)->extents.x1, SWFDEC_GRAPHIC (shape)->extents.y1); swfdec_bits_get_rect (bits, &tmp); SWFDEC_LOG (" extents: %g %g x %g %g", tmp.x0, tmp.y0, tmp.x1, tmp.y1); swfdec_bits_getbits (bits, 6); has_scale_strokes = swfdec_bits_getbit (bits); has_noscale_strokes = swfdec_bits_getbit (bits); SWFDEC_LOG (" has scaling strokes: %d", has_scale_strokes); SWFDEC_LOG (" has non-scaling strokes: %d", has_noscale_strokes); swfdec_shape_add_styles (s, shape, swfdec_pattern_parse_rgba, swfdec_stroke_parse_extended); swfdec_shape_get_recs (s, shape, swfdec_pattern_parse_rgba, swfdec_stroke_parse_extended); return SWFDEC_STATUS_OK;}/* The shape creation process is a bit complicated since it requires matching * the Flash model to the cairo model. Note that this code is just random * guessing and nothing substantial. Otherwise I'd have a testsuite. :) * It does the following steps: * - Accumulate all sub path into an array of SubPath structs. a sub path is * the path between 2 style change records. * - For every fill style used, accumulate all paths in order of appearance. * The code assumes that every fill path is closed. * - Collect the lines. * - Sort the array so that lines get drawn after their left and right fill, * but as early as possible. SubPath.max_index and ShapeVec.last_index are * used for this. *//* FIXME: It might be that the Flash code uses a different order, namely * drawing all fills followed by all lines per style record. So everything after * new styles appeared is drawn later. * The current code works though, so I'm not interested in testing that idea ;) */static GSList *swfdec_shape_accumulate_one_polygon (SwfdecShape *shape, SwfdecShapeVec *target, guint style, SubPath *paths, guint start, guint paths_len, guint *max){ guint i; GSList *found = NULL; int x, y; g_assert (style != 0); /* paths[start] is our starting point */ if (paths[start].fill0style == style) { paths[start].fill0style = 0; } else { g_assert (style == paths[start].fill1style); paths[start].fill1style = 0; } x = paths[start].x_end; y = paths[start].y_end; found = g_slist_prepend (found, &paths[start]); *max = start; swfdec_path_move_to (&target->path, paths[start].x_start, paths[start].y_start); swfdec_path_append (&target->path, &paths[start].path); while (x != paths[start].x_start || y != paths[start].y_start) { SWFDEC_LOG ("now looking for point %u %u", x, y); for (i = start; i < paths_len; i++) { if (paths[i].fill0style != style && paths[i].fill1style != style) continue; if (paths[i].x_start == x && paths[i].y_start == y) { SWFDEC_LOG (" found it %u", i); x = paths[i].x_end; y = paths[i].y_end; swfdec_path_append (&target->path, &paths[i].path); } else if (paths[i].x_end == x && paths[i].y_end == y) { SWFDEC_LOG (" found it reverse %u", i); x = paths[i].x_start; y = paths[i].y_start; swfdec_path_append_reverse (&target->path, &paths[i].path, x, y); } else { continue; } if (paths[i].fill0style == style) paths[i].fill0style = 0; else paths[i].fill1style = 0; found = g_slist_prepend (found, &paths[i]); *max = i; break; } if (i == paths_len) { SWFDEC_ERROR ("could not find a closed path for style %u, starting at %d %d", style, paths[start].x_start, paths[start].y_start); goto fail; } } return found;fail: g_slist_free (found); return NULL;}static voidswfdec_shape_accumulate_one_fill (SwfdecShape *shape, SubPath *paths, guint start, guint paths_len){ SwfdecShapeVec *target; guint i, style, max = 0, cur; GSList *walk, *found = NULL; g_array_set_size (shape->vecs, shape->vecs->len + 1); target = &g_array_index (shape->vecs, SwfdecShapeVec, shape->vecs->len - 1); swfdec_shape_vec_init (target); if (paths[start].fill0style != 0) style = paths[start].fill0style; else style = paths[start].fill1style; for (i = start; i < paths_len; i++) { if (paths[i].fill0style == style) { walk = swfdec_shape_accumulate_one_polygon (shape, target, style, paths, i, paths_len, &cur); if (walk) { found = g_slist_concat (found, walk); max = MAX (max, cur); } else { goto fail; } } if (paths[i].fill1style == style) { walk = swfdec_shape_accumulate_one_polygon (shape, target, style, paths, i, paths_len, &cur); if (walk) { found = g_slist_concat (found, walk); max = MAX (max, cur); } else { goto fail; } } } target->last_index = 2 * max; for (walk = found; walk; walk = walk->next) { SubPath *sub = walk->data; sub->max_index = MAX (sub->max_index, max); } if (style > shape->fills->len) { SWFDEC_ERROR ("style index %u is too big, only %u styles available", style, shape->fills->len); goto fail; } else { target->pattern = g_ptr_array_index (shape->fills, style - 1); if (target->pattern == NULL) goto fail; g_object_ref (target->pattern); } g_slist_free (found); return;fail: g_slist_free (found); swfdec_shape_vec_finish (target); g_array_set_size (shape->vecs, shape->vecs->len - 1);}static voidswfdec_shape_accumulate_fills (SwfdecShape *shape, SubPath *paths, guint paths_len){ guint i; for (i = 0; i < paths_len; i++) { if (paths[i].fill0style != 0) swfdec_shape_accumulate_one_fill (shape, paths, i, paths_len); if (paths[i].fill1style != 0) swfdec_shape_accumulate_one_fill (shape, paths, i, paths_len); }}static voidswfdec_shape_accumulate_lines (SwfdecShape *shape, SubPath *paths, guint paths_len){ SwfdecShapeVec target = { 0, }; guint i; for (i = 0; i < paths_len; i++) { if (paths[i].linestyle == 0) continue; if (paths[i].linestyle > shape->lines->len) { SWFDEC_ERROR ("linestyle index %u is too big, only %u styles available", paths[i].linestyle, shape->lines->len); continue; } swfdec_shape_vec_init (&target); swfdec_path_move_to (&target.path, paths[i].x_start, paths[i].y_start); swfdec_path_append (&target.path, &paths[i].path); target.pattern = g_ptr_array_index (shape->lines, paths[i].linestyle - 1); g_object_ref (target.pattern); target.last_index = 2 * paths[i].max_index + 1; g_array_append_val (shape->vecs, target); }}static intswfdec_shape_vec_compare (gconstpointer a, gconstpointer b){ return ((const SwfdecShapeVec *) a)->last_index - ((const SwfdecShapeVec *) b)->last_index;}typedef enum { SWFDEC_SHAPE_TYPE_END, SWFDEC_SHAPE_TYPE_CHANGE, SWFDEC_SHAPE_TYPE_LINE, SWFDEC_SHAPE_TYPE_CURVE} SwfdecShapeType;static SwfdecShapeTypeswfdec_shape_peek_type (SwfdecBits *bits){ guint ret = swfdec_bits_peekbits (bits, 6); if (ret == 0) return SWFDEC_SHAPE_TYPE_END; if ((ret & 0x20) == 0) return SWFDEC_SHAPE_TYPE_CHANGE; if ((ret & 0x10) == 0) return SWFDEC_SHAPE_TYPE_CURVE; return SWFDEC_SHAPE_TYPE_LINE;}static voidswfdec_shape_parse_curve (SwfdecBits *bits, SubPath *path, int *x, int *y){ int n_bits; int cur_x, cur_y; int control_x, control_y; if (swfdec_bits_getbits (bits, 2) != 2) { g_assert_not_reached (); } n_bits = swfdec_bits_getbits (bits, 4) + 2; cur_x = *x; cur_y = *y; control_x = cur_x + swfdec_bits_getsbits (bits, n_bits); control_y = cur_y + swfdec_bits_getsbits (bits, n_bits); SWFDEC_LOG (" control %d,%d", control_x, control_y); *x = control_x + swfdec_bits_getsbits (bits, n_bits); *y = control_y + swfdec_bits_getsbits (bits, n_bits); SWFDEC_LOG (" anchor %d,%d", *x, *y); if (path) { swfdec_path_curve_to (&path->path, cur_x, cur_y, control_x, control_y, *x, *y); } else { SWFDEC_ERROR ("no path to curve in"); }}static voidswfdec_shape_parse_line (SwfdecBits *bits, SubPath *path, int *x, int *y, gboolean add_as_curve){ int n_bits; int general_line_flag; int cur_x, cur_y; if (swfdec_bits_getbits (bits, 2) != 3) { g_assert_not_reached (); } cur_x = *x; cur_y = *y; n_bits = swfdec_bits_getbits (bits, 4) + 2; general_line_flag = swfdec_bits_getbit (bits); if (general_line_flag == 1) { *x += swfdec_bits_getsbits (bits, n_bits); *y += swfdec_bits_getsbits (bits, n_bits); } else { int vert_line_flag = swfdec_bits_getbit (bits); if (vert_line_flag == 0) { *x += swfdec_bits_getsbits (bits, n_bits); } else { *y += swfdec_bits_getsbits (bits, n_bits); } } SWFDEC_LOG (" line to %d,%d", *x, *y); if (path) { if (add_as_curve) swfdec_path_curve_to (&path->path, cur_x, cur_y, (cur_x + *x) / 2, (cur_y + *y) / 2, *x, *y);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -