📄 swfdec_shape.c
字号:
/* Swfdec * Copyright (C) 2003-2006 David Schleef <ds@schleef.org> * 2005-2006 Eric Anholt <eric@anholt.net> * 2006-2007 Benjamin Otte <otte@gnome.org> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA */#ifdef HAVE_CONFIG_H#include "config.h"#endif#include <math.h>#include <string.h>#include "swfdec_shape.h"#include "swfdec.h"#include "swfdec_debug.h"#include "swfdec_stroke.h"G_DEFINE_TYPE (SwfdecShape, swfdec_shape, SWFDEC_TYPE_GRAPHIC)/*** PATHS ***/static voidswfdec_path_init (cairo_path_t *path){ path->status = CAIRO_STATUS_SUCCESS; path->data = NULL; path->num_data = 0;}static voidswfdec_path_reset (cairo_path_t *path){ path->status = CAIRO_STATUS_SUCCESS; g_free (path->data); path->data = NULL; path->num_data = 0;}#define swfdec_path_require_size(path, steps) \ swfdec_path_ensure_size ((path), (path)->num_data + steps)static voidswfdec_path_ensure_size (cairo_path_t *path, int size){#define SWFDEC_PATH_STEPS 32 /* round up to next multiple of SWFDEC_PATH_STEPS */ int current_size = path->num_data - path->num_data % SWFDEC_PATH_STEPS; if (path->num_data % SWFDEC_PATH_STEPS) current_size += SWFDEC_PATH_STEPS; if (size % SWFDEC_PATH_STEPS) size += SWFDEC_PATH_STEPS - size % SWFDEC_PATH_STEPS; g_assert (current_size % SWFDEC_PATH_STEPS == 0); g_assert (size % SWFDEC_PATH_STEPS == 0); while (size <= current_size) return; SWFDEC_LOG ("extending size of %p from %u to %u", path, current_size, size); path->data = g_renew (cairo_path_data_t, path->data, size);}static voidswfdec_path_move_to (cairo_path_t *path, double x, double y){ cairo_path_data_t *cur; swfdec_path_require_size (path, 2); cur = &path->data[path->num_data++]; cur->header.type = CAIRO_PATH_MOVE_TO; cur->header.length = 2; cur = &path->data[path->num_data++]; cur->point.x = x; cur->point.y = y;}static voidswfdec_path_line_to (cairo_path_t *path, double x, double y){ cairo_path_data_t *cur; swfdec_path_require_size (path, 2); cur = &path->data[path->num_data++]; cur->header.type = CAIRO_PATH_LINE_TO; cur->header.length = 2; cur = &path->data[path->num_data++]; cur->point.x = x; cur->point.y = y;}static voidswfdec_path_curve_to (cairo_path_t *path, double start_x, double start_y, double control_x, double control_y, double end_x, double end_y){ cairo_path_data_t *cur; swfdec_path_require_size (path, 4); cur = &path->data[path->num_data++]; cur->header.type = CAIRO_PATH_CURVE_TO; cur->header.length = 4;#define WEIGHT (2.0/3.0) cur = &path->data[path->num_data++]; cur->point.x = control_x * WEIGHT + (1-WEIGHT) * start_x; cur->point.y = control_y * WEIGHT + (1-WEIGHT) * start_y; cur = &path->data[path->num_data++]; cur->point.x = control_x * WEIGHT + (1-WEIGHT) * end_x; cur->point.y = control_y * WEIGHT + (1-WEIGHT) * end_y; cur = &path->data[path->num_data++]; cur->point.x = end_x; cur->point.y = end_y;}static voidswfdec_path_append (cairo_path_t *path, const cairo_path_t *append){ swfdec_path_require_size (path, append->num_data); memcpy (&path->data[path->num_data], append->data, sizeof (cairo_path_data_t) * append->num_data); path->num_data += append->num_data;}static voidswfdec_path_append_reverse (cairo_path_t *path, const cairo_path_t *append, double x, double y){ cairo_path_data_t *out, *in; int i; swfdec_path_require_size (path, append->num_data); path->num_data += append->num_data; out = &path->data[path->num_data - 1]; in = append->data; for (i = 0; i < append->num_data; i++) { switch (in[i].header.type) { case CAIRO_PATH_LINE_TO: out[-i].point.x = x; out[-i].point.y = y; out[-i - 1].header = in[i].header; i++; break; case CAIRO_PATH_CURVE_TO: out[-i].point.x = x; out[-i].point.y = y; out[-i - 3].header = in[i].header; out[-i - 1].point = in[i + 1].point; out[-i - 2].point = in[i + 2].point; i += 3; break; case CAIRO_PATH_CLOSE_PATH: case CAIRO_PATH_MOVE_TO: /* these two don't exist in our code */ default: g_assert_not_reached (); } x = in[i].point.x; y = in[i].point.y; }}/*** SUBPATH ***/typedef struct { int x_start, y_start; int x_end, y_end; cairo_path_t path; guint fill0style; guint fill1style; guint linestyle; guint max_index;} SubPath;/*** SHAPE ***/static voidswfdec_shape_vec_finish (SwfdecShapeVec * shapevec){ if (shapevec->pattern) { g_object_unref (shapevec->pattern); shapevec->pattern = NULL; } if (shapevec->fill_cr) { cairo_destroy (shapevec->fill_cr); shapevec->fill_cr = NULL; } swfdec_path_reset (&shapevec->path);}static voidswfdec_shape_vec_init (SwfdecShapeVec *vec){ swfdec_path_init (&vec->path);}static voidswfdec_shape_dispose (GObject *object){ guint i; SwfdecShape * shape = SWFDEC_SHAPE (object); for (i = 0; i < shape->vecs->len; i++) { swfdec_shape_vec_finish (&g_array_index (shape->vecs, SwfdecShapeVec, i)); } g_array_free (shape->vecs, TRUE); for (i = 0; i < shape->fills->len; i++) { if (g_ptr_array_index (shape->fills, i)) g_object_unref (g_ptr_array_index (shape->fills, i)); } g_ptr_array_free (shape->fills, TRUE); for (i = 0; i < shape->lines->len; i++) { if (g_ptr_array_index (shape->lines, i)) g_object_unref (g_ptr_array_index (shape->lines, i)); } g_ptr_array_free (shape->lines, TRUE); G_OBJECT_CLASS (swfdec_shape_parent_class)->dispose (G_OBJECT (shape));}static voidswfdec_shape_render (SwfdecGraphic *graphic, cairo_t *cr, const SwfdecColorTransform *trans, const SwfdecRect *inval, gboolean fill){ SwfdecShape *shape = SWFDEC_SHAPE (graphic); guint i; cairo_set_operator (cr, CAIRO_OPERATOR_OVER); cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD); for (i = 0; i < shape->vecs->len; i++) { SwfdecShapeVec *vec = &g_array_index (shape->vecs, SwfdecShapeVec, i); g_assert (vec->path.num_data); g_assert (vec->pattern); if (!swfdec_rect_intersect (NULL, &vec->extents, inval)) continue; /* hack to not append paths for lines */ if (!fill && vec->last_index % 2 != 0) continue; if (fill) { if (SWFDEC_IS_PATTERN (vec->pattern)) { swfdec_pattern_paint (vec->pattern, cr, &vec->path, trans, 0); } else { swfdec_stroke_paint (vec->pattern, cr, &vec->path, trans, 0); } } else { cairo_append_path (cr, &vec->path); } }}static gbooleanswfdec_shape_mouse_in (SwfdecGraphic *graphic, double x, double y){ SwfdecShapeVec *shapevec; SwfdecShape *shape = SWFDEC_SHAPE (graphic); static cairo_surface_t *surface = NULL; guint i; for (i = 0; i < shape->vecs->len; i++) { shapevec = &g_array_index (shape->vecs, SwfdecShapeVec, i); g_assert (shapevec->path.num_data); g_assert (shapevec->pattern); /* FIXME: handle strokes */ if (SWFDEC_IS_STROKE (shapevec->pattern)) continue; if (shapevec->fill_cr == NULL) { /* FIXME: do less memory intensive fill checking plz */ if (surface == NULL) surface = cairo_image_surface_create (CAIRO_FORMAT_A8, 1, 1); shapevec->fill_cr = cairo_create (surface); cairo_set_fill_rule (shapevec->fill_cr, CAIRO_FILL_RULE_EVEN_ODD); cairo_append_path (shapevec->fill_cr, &shapevec->path); } if (cairo_in_fill (shapevec->fill_cr, x, y)) return TRUE; } return FALSE;}static voidswfdec_shape_class_init (SwfdecShapeClass * g_class){ GObjectClass *object_class = G_OBJECT_CLASS (g_class); SwfdecGraphicClass *graphic_class = SWFDEC_GRAPHIC_CLASS (g_class); object_class->dispose = swfdec_shape_dispose; graphic_class->render = swfdec_shape_render; graphic_class->mouse_in = swfdec_shape_mouse_in;}static voidswfdec_shape_init (SwfdecShape * shape){ shape->fills = g_ptr_array_new (); shape->lines = g_ptr_array_new (); shape->vecs = g_array_new (FALSE, TRUE, sizeof (SwfdecShapeVec));}static voidswfdec_shape_add_styles (SwfdecSwfDecoder * s, SwfdecShape * shape, SwfdecPatternFunc parse_fill, SwfdecStrokeFunc parse_stroke){ int n_fill_styles; int n_line_styles; int i; SwfdecBits *bits = &s->b; swfdec_bits_syncbits (bits); shape->fills_offset = shape->fills->len; n_fill_styles = swfdec_bits_get_u8 (bits); if (n_fill_styles == 0xff) { n_fill_styles = swfdec_bits_get_u16 (bits); } SWFDEC_LOG (" n_fill_styles %d", n_fill_styles); for (i = 0; i < n_fill_styles && swfdec_bits_left (bits); i++) { SwfdecPattern *pattern; SWFDEC_LOG (" fill style %d:", i); pattern = parse_fill (s); g_ptr_array_add (shape->fills, pattern); } shape->lines_offset = shape->lines->len; n_line_styles = swfdec_bits_get_u8 (bits); if (n_line_styles == 0xff) { n_line_styles = swfdec_bits_get_u16 (bits); } SWFDEC_LOG (" n_line_styles %d", n_line_styles); for (i = 0; i < n_line_styles && swfdec_bits_left (bits); i++) { g_ptr_array_add (shape->lines, parse_stroke (s)); } shape->n_fill_bits = swfdec_bits_getbits (bits, 4); shape->n_line_bits = swfdec_bits_getbits (bits, 4);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -