[Swfdec-commits] 5 commits - README swfdec/Makefile.am swfdec/swfdec_blur_filter.c swfdec/swfdec_blur_filter.h swfdec/swfdec_button.c swfdec/swfdec_button_movie.c swfdec/swfdec_convolution_matrix.c swfdec/swfdec_convolution_matrix.h swfdec/swfdec_filter_as.c swfdec/swfdec_filter.c swfdec/swfdec_filter.h swfdec/swfdec_movie.c swfdec/swfdec_movie.h swfdec/swfdec_renderer.c swfdec/swfdec_sprite_movie_as.c swfdec/swfdec_sprite_movie.c
Benjamin Otte
company at kemper.freedesktop.org
Sun Sep 14 14:39:04 PDT 2008
README | 2
swfdec/Makefile.am | 2
swfdec/swfdec_blur_filter.c | 160 ++++++++++++++++++++++++++++++++++++-
swfdec/swfdec_blur_filter.h | 4
swfdec/swfdec_button.c | 6 -
swfdec/swfdec_button_movie.c | 6 -
swfdec/swfdec_convolution_matrix.c | 152 +++++++++++++++++++++++++++++++++++
swfdec/swfdec_convolution_matrix.h | 54 ++++++++++++
swfdec/swfdec_filter.c | 114 ++++++++++++++++++++++++--
swfdec/swfdec_filter.h | 24 ++++-
swfdec/swfdec_filter_as.c | 21 +---
swfdec/swfdec_movie.c | 104 ++++++++++++++++++------
swfdec/swfdec_movie.h | 3
swfdec/swfdec_renderer.c | 23 +++--
swfdec/swfdec_sprite_movie.c | 17 +++
swfdec/swfdec_sprite_movie_as.c | 27 ++++++
16 files changed, 646 insertions(+), 73 deletions(-)
New commits:
commit 89a900a9aaf4e0e2e15f9742fb6846575e1568c7
Author: Benjamin Otte <otte at gnome.org>
Date: Sun Sep 14 23:22:48 2008 +0200
make blur actually work
It's probably still very slow, because cacheAsBitmap isn't implemented
diff --git a/swfdec/Makefile.am b/swfdec/Makefile.am
index 30c974b..f9d8dfe 100644
--- a/swfdec/Makefile.am
+++ b/swfdec/Makefile.am
@@ -68,6 +68,7 @@ libswfdec_source_files = \
swfdec_color_transform_as.c \
swfdec_constant_pool.c \
swfdec_convolution_filter.c \
+ swfdec_convolution_matrix.c \
swfdec_debug.c \
swfdec_decoder.c \
swfdec_displacement_map_filter.c \
@@ -269,6 +270,7 @@ noinst_HEADERS = \
swfdec_color.h \
swfdec_color_transform_as.h \
swfdec_constant_pool.h \
+ swfdec_convolution_matrix.h \
swfdec_debug.h \
swfdec_decoder.h \
swfdec_draw.h \
diff --git a/swfdec/swfdec_blur_filter.c b/swfdec/swfdec_blur_filter.c
index 68f817b..aab6386 100644
--- a/swfdec/swfdec_blur_filter.c
+++ b/swfdec/swfdec_blur_filter.c
@@ -22,13 +22,164 @@
#endif
#include "swfdec_blur_filter.h"
+
+#include <math.h>
+
#include "swfdec_debug.h"
G_DEFINE_TYPE (SwfdecBlurFilter, swfdec_blur_filter, SWFDEC_TYPE_FILTER)
static void
+swfdec_blur_filter_clone (SwfdecFilter *dfilter, SwfdecFilter *sfilter)
+{
+ SwfdecBlurFilter *dest = SWFDEC_BLUR_FILTER (dfilter);
+ SwfdecBlurFilter *source = SWFDEC_BLUR_FILTER (sfilter);
+
+ dest->x = source->x;
+ dest->y = source->y;
+ dest->quality = source->quality;
+}
+
+static void
+swfdec_blur_filter_create_convolution_matrix (SwfdecBlurFilter *blur)
+{
+ guint x, y, w, h;
+ double div, blurx, blury;
+
+ if (blur->matrix)
+ return;
+
+ blurx = MAX (blur->x, 1);
+ blury = MAX (blur->y, 1);
+ w = ceil ((blurx - 1) / 2);
+ w = w * 2 + 1;
+ h = ceil ((blury - 1) / 2);
+ h = h * 2 + 1;
+
+ blur->matrix = swfdec_convolution_matrix_new (w, h);
+ div = 1.0 / (blurx * blury);
+ for (y = 0; y < h; y++) {
+ double val = div;
+ if (y == 0 || y == w - 1) {
+ val *= (1 - (h - MAX (blur->y, 1)) / 2);
+ }
+ for (x = 0; x < w; x++) {
+ if (x == 0 || x == w - 1) {
+ swfdec_convolution_matrix_set (blur->matrix, x, y,
+ val * (1 - (w - MAX (blur->x, 1)) / 2));
+ } else {
+ swfdec_convolution_matrix_set (blur->matrix, x, y, val);
+ }
+ }
+ }
+}
+
+static void
+swfdec_blur_filter_get_rectangle (SwfdecFilter *filter, SwfdecRectangle *dest,
+ const SwfdecRectangle *source)
+{
+ SwfdecBlurFilter *blur = SWFDEC_BLUR_FILTER (filter);
+ guint x, y;
+
+ swfdec_blur_filter_create_convolution_matrix (blur);
+ x = swfdec_convolution_matrix_get_width (blur->matrix) / 2 * blur->quality;
+ y = swfdec_convolution_matrix_get_height (blur->matrix) / 2 * blur->quality;
+
+ dest->x = source->x - x;
+ dest->y = source->y - y;
+ dest->width = source->width + 2 * x;
+ dest->height = source->height + 2 * y;
+}
+
+static cairo_pattern_t *
+swfdec_blur_filter_apply (SwfdecFilter *filter, cairo_pattern_t *pattern,
+ const SwfdecRectangle *rect)
+{
+ SwfdecBlurFilter *blur = SWFDEC_BLUR_FILTER (filter);
+ cairo_surface_t *a, *b;
+ guint i, j, x, y;
+ guint8 *adata, *bdata;
+ guint astride, bstride;
+ cairo_t *cr;
+
+ if (blur->x <= 1.0 && blur->y <= 1.0)
+ return cairo_pattern_reference (pattern);
+
+ swfdec_blur_filter_create_convolution_matrix (blur);
+ x = swfdec_convolution_matrix_get_width (blur->matrix) / 2;
+ y = swfdec_convolution_matrix_get_height (blur->matrix) / 2;
+
+ /* FIXME: make this work in a single pass (requires smarter matrix construction) */
+ a = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
+ rect->width + 2 * x * blur->quality,
+ rect->height + 2 * y * blur->quality);
+ cairo_surface_set_device_offset (a,
+ - rect->x + x * blur->quality, - rect->y + y * blur->quality);
+ b = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
+ rect->width + 2 * x * blur->quality,
+ rect->height + 2 * y * blur->quality);
+ cairo_surface_set_device_offset (b,
+ - rect->x + x * blur->quality, - rect->y + y * blur->quality);
+
+ cr = cairo_create (b);
+ cairo_set_source (cr, pattern);
+ cairo_rectangle (cr, rect->x, rect->y, rect->width, rect->height);
+ cairo_fill (cr);
+ cairo_destroy (cr);
+ adata = cairo_image_surface_get_data (a);
+ astride = cairo_image_surface_get_stride (a);
+ bdata = cairo_image_surface_get_data (b);
+ bstride = cairo_image_surface_get_stride (b);
+ for (i = 1, j = blur->quality - 1; i <= blur->quality; i++, j--) {
+ swfdec_convolution_matrix_apply (blur->matrix,
+ rect->width + 2 * x * i, rect->height + 2 * y * i,
+ adata + 4 * x * j + astride * y * j, astride,
+ bdata + 4 * x * j + bstride * y * j, bstride);
+ i++;
+ j--;
+ if (i > blur->quality) {
+ cairo_surface_destroy (b);
+ goto out;
+ }
+ swfdec_convolution_matrix_apply (blur->matrix,
+ rect->width + 2 * x * i, rect->height + 2 * y * i,
+ bdata + 4 * x * j + bstride * y * j, bstride,
+ adata + 4 * x * j + astride * y * j, astride);
+ }
+
+ cairo_surface_destroy (a);
+ a = b;
+out:
+ pattern = cairo_pattern_create_for_surface (a);
+ cairo_surface_destroy (a);
+
+ return pattern;
+}
+
+static void
+swfdec_blur_filter_dispose (GObject *object)
+{
+ SwfdecBlurFilter *blur = SWFDEC_BLUR_FILTER (object);
+
+ if (blur->matrix) {
+ swfdec_convolution_matrix_free (blur->matrix);
+ blur->matrix = NULL;
+ }
+
+ G_OBJECT_CLASS (swfdec_blur_filter_parent_class)->dispose (object);
+}
+
+static void
swfdec_blur_filter_class_init (SwfdecBlurFilterClass *klass)
{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ SwfdecFilterClass *filter_class = SWFDEC_FILTER_CLASS (klass);
+
+ object_class->dispose = swfdec_blur_filter_dispose;
+
+ filter_class->clone = swfdec_blur_filter_clone;
+ filter_class->get_rectangle = swfdec_blur_filter_get_rectangle;
+ filter_class->apply = swfdec_blur_filter_apply;
}
static void
@@ -40,8 +191,13 @@ swfdec_blur_filter_init (SwfdecBlurFilter *filter)
}
void
-swfdec_blur_filter_invalidate (SwfdecBlurFilter *filter)
+swfdec_blur_filter_invalidate (SwfdecBlurFilter *blur)
{
- g_return_if_fail (SWFDEC_IS_BLUR_FILTER (filter));
+ g_return_if_fail (SWFDEC_IS_BLUR_FILTER (blur));
+
+ if (blur->matrix) {
+ swfdec_convolution_matrix_free (blur->matrix);
+ blur->matrix = NULL;
+ }
}
diff --git a/swfdec/swfdec_blur_filter.h b/swfdec/swfdec_blur_filter.h
index 6a78276..776d59f 100644
--- a/swfdec/swfdec_blur_filter.h
+++ b/swfdec/swfdec_blur_filter.h
@@ -21,6 +21,7 @@
#define _SWFDEC_BLUR_FILTER_H_
#include <swfdec/swfdec_filter.h>
+#include <swfdec/swfdec_convolution_matrix.h>
G_BEGIN_DECLS
@@ -41,6 +42,7 @@ struct _SwfdecBlurFilter {
double x; /* blur in horizontal direction */
double y; /* blur in vertical direction */
guint quality; /* number of passes */
+ SwfdecConvolutionMatrix *matrix; /* matrix if computed or NULL */
};
struct _SwfdecBlurFilterClass {
@@ -49,7 +51,7 @@ struct _SwfdecBlurFilterClass {
GType swfdec_blur_filter_get_type (void);
-void swfdec_blur_filter_invalidate (SwfdecBlurFilter * filter);
+void swfdec_blur_filter_invalidate (SwfdecBlurFilter * blur);
G_END_DECLS
diff --git a/swfdec/swfdec_button.c b/swfdec/swfdec_button.c
index aa3a8c1..8957f81 100644
--- a/swfdec/swfdec_button.c
+++ b/swfdec/swfdec_button.c
@@ -165,10 +165,8 @@ tag_func_define_button_2 (SwfdecSwfDecoder * s, guint tag)
trans.x0, trans.y0);
swfdec_bits_get_color_transform (&bits, &ctrans);
- if (has_filters) {
- GSList *list = swfdec_filter_parse (&bits);
- g_slist_free (list);
- }
+ if (has_filters)
+ swfdec_filter_skip (&bits);
if (has_blend_mode) {
guint blend_mode = swfdec_bits_get_u8 (&bits);
SWFDEC_LOG (" blend mode = %u", blend_mode);
diff --git a/swfdec/swfdec_button_movie.c b/swfdec/swfdec_button_movie.c
index d4d23f9..aa154ae 100644
--- a/swfdec/swfdec_button_movie.c
+++ b/swfdec/swfdec_button_movie.c
@@ -83,10 +83,8 @@ swfdec_button_movie_perform_place (SwfdecButtonMovie *button, SwfdecBits *bits)
} else {
blend_mode = 0;
}
- if (has_filters) {
- GSList *filters = swfdec_filter_parse (bits);
- g_slist_free (filters);
- }
+ if (has_filters)
+ new->filters = swfdec_filter_parse (player, bits);
} else {
/* DefineButton1 record */
v2 = FALSE;
diff --git a/swfdec/swfdec_convolution_matrix.c b/swfdec/swfdec_convolution_matrix.c
new file mode 100644
index 0000000..994d355
--- /dev/null
+++ b/swfdec/swfdec_convolution_matrix.c
@@ -0,0 +1,152 @@
+/* Swfdec
+ * Copyright (C) 2008 Benjamin Otte <otte at 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 "swfdec_convolution_matrix.h"
+
+#include "swfdec_color.h"
+#include "swfdec_debug.h"
+
+struct _SwfdecConvolutionMatrix {
+ guint width;
+ guint height;
+ double matrix[1];
+};
+
+SwfdecConvolutionMatrix *
+swfdec_convolution_matrix_new (guint width, guint height)
+{
+ SwfdecConvolutionMatrix *matrix;
+
+ g_return_val_if_fail (width % 2 != 0, NULL);
+ g_return_val_if_fail (height % 2 != 0, NULL);
+
+ matrix = g_slice_alloc0 (sizeof (SwfdecConvolutionMatrix) +
+ sizeof (guint8) * (width * height * 256 - 1));
+ matrix->width = width;
+ matrix->height = height;
+ return matrix;
+}
+
+void
+swfdec_convolution_matrix_free (SwfdecConvolutionMatrix *matrix)
+{
+ g_return_if_fail (matrix != NULL);
+
+ g_slice_free1 (sizeof (SwfdecConvolutionMatrix) +
+ sizeof (guint8) * (matrix->width * matrix->height * 256 - 1), matrix);
+}
+
+void
+swfdec_convolution_matrix_set (SwfdecConvolutionMatrix *matrix,
+ guint x, guint y, double value)
+{
+ g_return_if_fail (matrix != NULL);
+ g_return_if_fail (x < matrix->width);
+ g_return_if_fail (y < matrix->height);
+
+ matrix->matrix[matrix->width * y + x] = value;
+}
+
+double
+swfdec_convolution_matrix_get (SwfdecConvolutionMatrix *matrix, guint x, guint y)
+{
+ g_return_val_if_fail (matrix != NULL, 0);
+ g_return_val_if_fail (x < matrix->width, 0);
+ g_return_val_if_fail (y < matrix->height, 0);
+
+ return matrix->matrix[matrix->width * y + x];
+}
+
+guint
+swfdec_convolution_matrix_get_width (SwfdecConvolutionMatrix *matrix)
+{
+ g_return_val_if_fail (matrix != NULL, 1);
+
+ return matrix->width;
+}
+
+guint
+swfdec_convolution_matrix_get_height (SwfdecConvolutionMatrix *matrix)
+{
+ g_return_val_if_fail (matrix != NULL, 1);
+
+ return matrix->height;
+}
+
+void
+swfdec_convolution_matrix_apply (SwfdecConvolutionMatrix *matrix, guint width, guint height,
+ guint8 *tdata, guint tstride, const guint8 *sdata, guint sstride)
+{
+ double r, g, b, a;
+ guint x, y;
+ int offx, offy, offyend, offxend;
+
+ g_return_if_fail (matrix != NULL);
+ g_return_if_fail (width > 0);
+ g_return_if_fail (height > 0);
+ g_return_if_fail (tdata != NULL);
+ g_return_if_fail (tstride >= width * 4);
+ g_return_if_fail (sdata != NULL);
+ g_return_if_fail (sstride >= width * 4);
+
+ for (y = 0; y < height; y++) {
+ for (x = 0; x < width; x++) {
+ double *next = matrix->matrix;
+ a = r = g = b = 0;
+ offy = y - matrix->height / 2;
+ offyend = offy + matrix->height;
+ for (; offy < offyend; offy++) {
+ if (offy < 0 || (guint) offy >= height) {
+ next += matrix->width;
+ continue;
+ }
+ offx = x - matrix->width / 2;
+ offxend = offx + matrix->width;
+ for (; offx < offxend; offx++) {
+ const guint8 *cur;
+ if (offx < 0 || (guint) offx >= width) {
+ next++;
+ continue;
+ }
+ cur = &sdata[4 * offx + sstride * offy];
+ g_assert (cur < sdata + sstride * height);
+ a += *next * cur[SWFDEC_COLOR_INDEX_ALPHA];
+ r += *next * cur[SWFDEC_COLOR_INDEX_RED];
+ g += *next * cur[SWFDEC_COLOR_INDEX_GREEN];
+ b += *next * cur[SWFDEC_COLOR_INDEX_BLUE];
+ next++;
+ }
+ }
+ a = CLAMP (a, 0, 255);
+ r = CLAMP (r, 0, a);
+ g = CLAMP (g, 0, a);
+ b = CLAMP (b, 0, a);
+ tdata[4 * x + SWFDEC_COLOR_INDEX_ALPHA] = a;
+ tdata[4 * x + SWFDEC_COLOR_INDEX_RED] = r;
+ tdata[4 * x + SWFDEC_COLOR_INDEX_GREEN] = g;
+ tdata[4 * x + SWFDEC_COLOR_INDEX_BLUE] = b;
+ }
+ tdata += tstride;
+ }
+}
+
diff --git a/swfdec/swfdec_convolution_matrix.h b/swfdec/swfdec_convolution_matrix.h
new file mode 100644
index 0000000..12d578a
--- /dev/null
+++ b/swfdec/swfdec_convolution_matrix.h
@@ -0,0 +1,54 @@
+/* Swfdec
+ * Copyright (C) 2008 Benjamin Otte <otte at 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
+ */
+
+#ifndef _SWFDEC_CONVOLUTION_MATRIX_H_
+#define _SWFDEC_CONVOLUTION_MATRIX_H_
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+
+typedef struct _SwfdecConvolutionMatrix SwfdecConvolutionMatrix;
+
+SwfdecConvolutionMatrix *
+ swfdec_convolution_matrix_new (guint width,
+ guint height);
+void swfdec_convolution_matrix_free (SwfdecConvolutionMatrix * matrix);
+
+void swfdec_convolution_matrix_set (SwfdecConvolutionMatrix * matrix,
+ guint x,
+ guint y,
+ double value);
+double swfdec_convolution_matrix_get (SwfdecConvolutionMatrix * matrix,
+ guint x,
+ guint y);
+guint swfdec_convolution_matrix_get_width (SwfdecConvolutionMatrix * matrix);
+guint swfdec_convolution_matrix_get_height (SwfdecConvolutionMatrix * matrix);
+void swfdec_convolution_matrix_apply (SwfdecConvolutionMatrix * matrix,
+ guint width,
+ guint height,
+ guint8 * tdata,
+ guint tstride,
+ const guint8 * sdata,
+ guint sstride);
+
+
+G_END_DECLS
+#endif
diff --git a/swfdec/swfdec_filter.c b/swfdec/swfdec_filter.c
index 8bff38c..d78154e 100644
--- a/swfdec/swfdec_filter.c
+++ b/swfdec/swfdec_filter.c
@@ -1,5 +1,5 @@
/* Swfdec
- * Copyright (C) 2007 Benjamin Otte <otte at gnome.org>
+ * Copyright (C) 2007-2008 Benjamin Otte <otte at gnome.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -22,6 +22,8 @@
#endif
#include "swfdec_filter.h"
+
+#include "swfdec_blur_filter.h"
#include "swfdec_debug.h"
G_DEFINE_ABSTRACT_TYPE (SwfdecFilter, swfdec_filter, SWFDEC_TYPE_AS_OBJECT)
@@ -36,29 +38,48 @@ swfdec_filter_init (SwfdecFilter *array)
{
}
+SwfdecFilter *
+swfdec_filter_clone (SwfdecFilter *filter)
+{
+ SwfdecFilter *clone;
+ SwfdecFilterClass *klass;
+
+ g_return_val_if_fail (SWFDEC_IS_FILTER (filter), NULL);
+
+ klass = SWFDEC_FILTER_GET_CLASS (filter);
+ clone = g_object_new (G_OBJECT_CLASS_TYPE (klass), "context",
+ swfdec_gc_object_get_context (filter), NULL);
+ klass->clone (clone, filter);
+
+ return clone;
+}
+
cairo_pattern_t *
-swfdec_filter_apply (SwfdecFilter *filter, cairo_pattern_t *pattern)
+swfdec_filter_apply (SwfdecFilter *filter, cairo_pattern_t *pattern,
+ const SwfdecRectangle *rect)
{
SwfdecFilterClass *klass;
cairo_pattern_t *ret;
g_return_val_if_fail (SWFDEC_IS_FILTER (filter), NULL);
g_return_val_if_fail (pattern != NULL, NULL);
+ g_return_val_if_fail (rect != NULL, NULL);
klass = SWFDEC_FILTER_GET_CLASS (filter);
g_assert (klass->apply);
- ret = klass->apply (filter, pattern);
+ ret = klass->apply (filter, pattern, rect);
cairo_pattern_destroy (pattern);
return ret;
}
GSList *
-swfdec_filter_parse (SwfdecBits *bits)
+swfdec_filter_parse (SwfdecPlayer *player, SwfdecBits *bits)
{
GSList *filters = NULL;
guint i, n_filters, filter_id;
+ g_return_val_if_fail (SWFDEC_IS_PLAYER (player), NULL);
g_return_val_if_fail (bits != NULL, NULL);
n_filters = swfdec_bits_get_u8 (bits);
@@ -71,8 +92,21 @@ swfdec_filter_parse (SwfdecBits *bits)
swfdec_bits_skip_bytes (bits, 16);
break;
case 1:
- SWFDEC_WARNING (" blur");
- swfdec_bits_skip_bytes (bits, 9);
+ {
+ SwfdecBlurFilter *filter;
+
+ filter = g_object_new (SWFDEC_TYPE_BLUR_FILTER,
+ "context", player, NULL);
+ SWFDEC_LOG (" blur");
+ filter->x = swfdec_bits_get_u32 (bits) / 65536.0;
+ filter->y = swfdec_bits_get_u32 (bits) / 65536.0;
+ filter->quality = swfdec_bits_getbits (bits, 5);
+ SWFDEC_LOG (" x = %g", filter->x);
+ SWFDEC_LOG (" y = %g", filter->x);
+ SWFDEC_LOG (" quality = %u", filter->quality);
+ swfdec_bits_getbits (bits, 3);
+ filters = g_slist_prepend (filters, filter);
+ }
break;
case 2:
SWFDEC_WARNING (" glow");
@@ -121,3 +155,71 @@ swfdec_filter_parse (SwfdecBits *bits)
return filters;
}
+void
+swfdec_filter_skip (SwfdecBits *bits)
+{
+ guint i, n_filters, filter_id;
+
+ g_return_if_fail (bits != NULL);
+
+ n_filters = swfdec_bits_get_u8 (bits);
+ for (i = 0; i < n_filters && swfdec_bits_left (bits); i++) {
+ filter_id = swfdec_bits_get_u8 (bits);
+ switch (filter_id) {
+ case 0:
+ swfdec_bits_skip_bytes (bits, 16);
+ break;
+ case 1:
+ swfdec_bits_skip_bytes (bits, 9);
+ break;
+ case 2:
+ swfdec_bits_skip_bytes (bits, 15);
+ break;
+ case 3:
+ swfdec_bits_skip_bytes (bits, 27);
+ break;
+ case 4:
+ {
+ guint n;
+ n = swfdec_bits_get_u8 (bits);
+ swfdec_bits_skip_bytes (bits, n * 5 + 19);
+ }
+ break;
+ case 5:
+ {
+ guint x, y;
+ x = swfdec_bits_get_u8 (bits);
+ y = swfdec_bits_get_u8 (bits);
+ swfdec_bits_skip_bytes (bits, (x + y) * 4 + 13);
+ }
+ break;
+ case 6:
+ swfdec_bits_skip_bytes (bits, 20 * 4);
+ break;
+ case 7:
+ {
+ guint n;
+ n = swfdec_bits_get_u8 (bits);
+ swfdec_bits_skip_bytes (bits, n * 5 + 19);
+ }
+ break;
+ default:
+ SWFDEC_ERROR ("unknown filter id %u", filter_id);
+ break;
+ }
+ }
+}
+
+void
+swfdec_filter_get_rectangle (SwfdecFilter *filter, SwfdecRectangle *dest,
+ const SwfdecRectangle *source)
+{
+ SwfdecFilterClass *klass;
+
+ g_return_if_fail (SWFDEC_IS_FILTER (filter));
+ g_return_if_fail (dest != NULL);
+ g_return_if_fail (source != NULL);
+
+ klass = SWFDEC_FILTER_GET_CLASS (filter);
+ klass->get_rectangle (filter, dest, source);
+}
diff --git a/swfdec/swfdec_filter.h b/swfdec/swfdec_filter.h
index b15b9f7..6431dac 100644
--- a/swfdec/swfdec_filter.h
+++ b/swfdec/swfdec_filter.h
@@ -1,5 +1,5 @@
/* Swfdec
- * Copyright (C) 2007 Benjamin Otte <otte at gnome.org>
+ * Copyright (C) 2007-2008 Benjamin Otte <otte at gnome.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -43,17 +43,31 @@ struct _SwfdecFilter {
struct _SwfdecFilterClass {
SwfdecAsObjectClass object_class;
- SwfdecFilter * (* clone) (SwfdecFilter * filter);
+ void (* clone) (SwfdecFilter * dest,
+ SwfdecFilter * source);
+ void (* get_rectangle) (SwfdecFilter * filter,
+ SwfdecRectangle * dest,
+ const SwfdecRectangle *source);
cairo_pattern_t * (* apply) (SwfdecFilter * filter,
- cairo_pattern_t * pattern);
+ cairo_pattern_t * pattern,
+ const SwfdecRectangle *rect);
};
GType swfdec_filter_get_type (void);
+SwfdecFilter * swfdec_filter_clone (SwfdecFilter * filter);
cairo_pattern_t * swfdec_filter_apply (SwfdecFilter * filter,
- cairo_pattern_t * pattern);
-GSList * swfdec_filter_parse (SwfdecBits * bits);
+ cairo_pattern_t * pattern,
+ const SwfdecRectangle *source);
+void swfdec_filter_get_rectangle
+ (SwfdecFilter * filter,
+ SwfdecRectangle * dest,
+ const SwfdecRectangle *source);
+GSList * swfdec_filter_parse (SwfdecPlayer * player,
+ SwfdecBits * bits);
+void swfdec_filter_skip (SwfdecBits * bits);
+
G_END_DECLS
#endif
diff --git a/swfdec/swfdec_filter_as.c b/swfdec/swfdec_filter_as.c
index 0f00211..f02108d 100644
--- a/swfdec/swfdec_filter_as.c
+++ b/swfdec/swfdec_filter_as.c
@@ -1,5 +1,5 @@
/* Swfdec
- * Copyright (C) 2006-2007 Benjamin Otte <otte at gnome.org>
+ * Copyright (C) 2006-2008 Benjamin Otte <otte at gnome.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -22,26 +22,21 @@
#endif
#include "swfdec_filter.h"
+
#include "swfdec_as_internal.h"
+#include "swfdec_as_native_function.h"
#include "swfdec_debug.h"
-SWFDEC_AS_NATIVE (1112, 1, swfdec_filter_clone)
+SWFDEC_AS_NATIVE (1112, 1, swfdec_filter_do_clone)
void
-swfdec_filter_clone (SwfdecAsContext *cx, SwfdecAsObject *object,
+swfdec_filter_do_clone (SwfdecAsContext *cx, SwfdecAsObject *object,
guint argc, SwfdecAsValue *argv, SwfdecAsValue *retval)
{
SwfdecFilter *filter;
- SwfdecFilterClass *klass;
-
- if (!SWFDEC_IS_FILTER (object))
- return;
- filter = SWFDEC_FILTER (object);
- klass = SWFDEC_FILTER_GET_CLASS (filter);
- g_assert (klass->clone);
+ SWFDEC_AS_CHECK (SWFDEC_TYPE_FILTER, &filter, "");
- filter = klass->clone (filter);
- if (filter)
- SWFDEC_AS_VALUE_SET_OBJECT (retval, SWFDEC_AS_OBJECT (filter));
+ filter = swfdec_filter_clone (filter);
+ SWFDEC_AS_VALUE_SET_OBJECT (retval, SWFDEC_AS_OBJECT (filter));
}
diff --git a/swfdec/swfdec_movie.c b/swfdec/swfdec_movie.c
index 90f8cf0..a9c7feb 100644
--- a/swfdec/swfdec_movie.c
+++ b/swfdec/swfdec_movie.c
@@ -34,6 +34,7 @@
#include "swfdec_debug.h"
#include "swfdec_draw.h"
#include "swfdec_event.h"
+#include "swfdec_filter.h"
#include "swfdec_graphic.h"
#include "swfdec_image.h"
#include "swfdec_loader_internal.h"
@@ -695,14 +696,14 @@ typedef enum {
SWFDEC_GROUP_NONE = 0,
SWFDEC_GROUP_NORMAL,
SWFDEC_GROUP_CACHED,
- SWFDEC_GROUP_BITMAP
+ SWFDEC_GROUP_FILTERS
} SwfdecGroup;
static SwfdecGroup
swfdec_movie_needs_group (SwfdecMovie *movie)
{
if (movie->filters)
- return SWFDEC_GROUP_BITMAP;
+ return SWFDEC_GROUP_FILTERS;
if (movie->cache_as_bitmap)
return SWFDEC_GROUP_CACHED;
if (movie->blend_mode > 1)
@@ -714,8 +715,8 @@ static cairo_operator_t
swfdec_movie_get_operator_for_blend_mode (guint blend_mode)
{
switch (blend_mode) {
+ case SWFDEC_BLEND_MODE_NONE:
case SWFDEC_BLEND_MODE_NORMAL:
- SWFDEC_ERROR ("shouldn't need to get operator without blend mode?!");
case SWFDEC_BLEND_MODE_LAYER:
return CAIRO_OPERATOR_OVER;
case SWFDEC_BLEND_MODE_ADD:
@@ -741,6 +742,31 @@ swfdec_movie_get_operator_for_blend_mode (guint blend_mode)
}
}
+static cairo_pattern_t *
+swfdec_movie_apply_filters (SwfdecMovie *movie, cairo_pattern_t *pattern)
+{
+ SwfdecRect rect;
+ SwfdecRectangle area;
+ GSList *walk;
+
+ if (movie->filters == NULL)
+ return pattern;
+
+ rect = movie->original_extents;
+ swfdec_movie_rect_local_to_global (movie, &rect);
+ swfdec_rect_transform (&rect, &rect,
+ &SWFDEC_PLAYER (swfdec_gc_object_get_context (movie))->priv->global_to_stage);
+ swfdec_rectangle_init_rect (&area, &rect);
+ /* FIXME: hack to make textfield borders work - looks like Adobe does this, too */
+ area.width++;
+ area.height++;
+ for (walk = movie->filters; walk; walk = walk->next) {
+ pattern = swfdec_filter_apply (walk->data, pattern, &area);
+ swfdec_filter_get_rectangle (walk->data, &area, &area);
+ }
+ return pattern;
+}
+
/**
* swfdec_movie_mask:
* @movie: The movie to act as the mask
@@ -857,14 +883,28 @@ swfdec_movie_render (SwfdecMovie *movie, cairo_t *cr,
} else {
cairo_restore (cr);
}
- if (group != SWFDEC_GROUP_NONE) {
+ if (group == SWFDEC_GROUP_FILTERS) {
cairo_pattern_t *pattern;
pattern = cairo_pop_group (cr);
+ cairo_save (cr);
+ swfdec_renderer_reset_matrix (cr);
+ {
+ cairo_matrix_t mat;
+ cairo_get_matrix (cr, &mat);
+ cairo_matrix_invert (&mat);
+ cairo_pattern_set_matrix (pattern, &mat);
+ }
+ pattern = swfdec_movie_apply_filters (movie, pattern);
cairo_set_source (cr, pattern);
cairo_set_operator (cr, swfdec_movie_get_operator_for_blend_mode (movie->blend_mode));
cairo_paint (cr);
cairo_pattern_destroy (pattern);
+ cairo_restore (cr);
+ } else if (group != SWFDEC_GROUP_NONE) {
+ cairo_pop_group_to_source (cr);
+ cairo_set_operator (cr, swfdec_movie_get_operator_for_blend_mode (movie->blend_mode));
+ cairo_paint (cr);
}
}
@@ -992,16 +1032,15 @@ static void
swfdec_movie_mark (SwfdecGcObject *object)
{
SwfdecMovie *movie = SWFDEC_MOVIE (object);
- GList *walk;
GSList *iter;
if (movie->parent)
swfdec_gc_object_mark (movie->parent);
swfdec_as_string_mark (movie->original_name);
swfdec_as_string_mark (movie->name);
- for (walk = movie->list; walk; walk = walk->next) {
- swfdec_gc_object_mark (walk->data);
- }
+ g_list_foreach (movie->list, (GFunc) swfdec_gc_object_mark, NULL);
+ g_slist_foreach (movie->filters, (GFunc) swfdec_gc_object_mark, NULL);
+
for (iter = movie->variable_listeners; iter != NULL; iter = iter->next) {
SwfdecMovieVariableListener *listener = iter->data;
swfdec_gc_object_mark (listener->object);
diff --git a/swfdec/swfdec_movie.h b/swfdec/swfdec_movie.h
index 1e93a50..f00098a 100644
--- a/swfdec/swfdec_movie.h
+++ b/swfdec/swfdec_movie.h
@@ -78,6 +78,7 @@ typedef enum {
SWFDEC_MOVIE_PROPERTY_YMOUSE = 21
} SwfdecMovieProperty;
+#define SWFDEC_BLEND_MODE_NONE 0
#define SWFDEC_BLEND_MODE_NORMAL 1
#define SWFDEC_BLEND_MODE_LAYER 2
#define SWFDEC_BLEND_MODE_MULTIPLY 3
diff --git a/swfdec/swfdec_sprite_movie.c b/swfdec/swfdec_sprite_movie.c
index 451cdfa..e78efc2 100644
--- a/swfdec/swfdec_sprite_movie.c
+++ b/swfdec/swfdec_sprite_movie.c
@@ -159,6 +159,7 @@ swfdec_sprite_movie_perform_place (SwfdecSpriteMovie *movie, SwfdecBits *bits, g
const char *name;
guint blend_mode;
SwfdecGraphic *graphic;
+ GSList *filters;
dec = SWFDEC_SWF_DECODER (mov->resource->decoder);
version = dec->version;
@@ -250,8 +251,9 @@ swfdec_sprite_movie_perform_place (SwfdecSpriteMovie *movie, SwfdecBits *bits, g
}
if (has_filter) {
- GSList *filters = swfdec_filter_parse (bits);
- g_slist_free (filters);
+ filters = swfdec_filter_parse (player, bits);
+ } else {
+ filters = NULL;
}
if (has_blend_mode) {
@@ -327,6 +329,8 @@ swfdec_sprite_movie_perform_place (SwfdecSpriteMovie *movie, SwfdecBits *bits, g
SWFDEC_FIXME ("character %u is not a graphic (does it even exist?), aborting", id);
if (events)
swfdec_event_list_free (events);
+ g_slist_foreach (filters, (GFunc) g_object_unref, NULL);
+ g_slist_free (filters);
return FALSE;
}
cur = swfdec_movie_new (player, depth, mov, mov->resource, graphic, name);
@@ -340,8 +344,15 @@ swfdec_sprite_movie_perform_place (SwfdecSpriteMovie *movie, SwfdecBits *bits, g
}
swfdec_movie_initialize (cur);
}
-
out:
+ if (has_filter) {
+ if (cur->filters) {
+ g_slist_foreach (cur->filters, (GFunc) g_object_unref, NULL);
+ g_slist_free (cur->filters);
+ }
+ cur->filters = filters;
+ }
+
if (events)
swfdec_event_list_free (events);
return TRUE;
diff --git a/swfdec/swfdec_sprite_movie_as.c b/swfdec/swfdec_sprite_movie_as.c
index b1bb452..181f2c1 100644
--- a/swfdec/swfdec_sprite_movie_as.c
+++ b/swfdec/swfdec_sprite_movie_as.c
@@ -31,6 +31,7 @@
#include "swfdec_bits.h"
#include "swfdec_debug.h"
#include "swfdec_decoder.h"
+#include "swfdec_filter.h"
#include "swfdec_internal.h"
#include "swfdec_player_internal.h"
#include "swfdec_sprite.h"
@@ -143,7 +144,31 @@ void
swfdec_sprite_movie_set_filters (SwfdecAsContext *cx, SwfdecAsObject *object,
guint argc, SwfdecAsValue *argv, SwfdecAsValue *rval)
{
- SWFDEC_STUB ("MovieClip.filters (set)");
+ SwfdecAsObject *array;
+ SwfdecAsValue val;
+ SwfdecFilter *filter;
+ SwfdecMovie *movie;
+ int i, length;
+ GSList *list;
+
+ SWFDEC_AS_CHECK (SWFDEC_TYPE_MOVIE, &movie, "o", &array);
+
+ swfdec_as_object_get_variable (array, SWFDEC_AS_STR_length, &val);
+ length = swfdec_as_value_to_integer (cx, &val);
+
+ list = NULL;
+ for (i = 0; i < length; i++) {
+ if (!swfdec_as_object_get_variable (array,
+ swfdec_as_integer_to_string (cx, i), &val) ||
+ !SWFDEC_AS_VALUE_IS_OBJECT (&val) ||
+ !SWFDEC_IS_FILTER (SWFDEC_AS_VALUE_GET_OBJECT (&val)))
+ continue;
+ filter = SWFDEC_FILTER (SWFDEC_AS_VALUE_GET_OBJECT (&val));
+ filter = swfdec_filter_clone (filter);
+ list = g_slist_prepend (list, filter);
+ }
+ g_slist_free (movie->filters);
+ movie->filters = list;
}
SWFDEC_AS_NATIVE (900, 419, swfdec_sprite_movie_get_transform)
commit a6c8fc9e8be525245a0afd93c476b76c269c87b4
Author: Benjamin Otte <otte at gnome.org>
Date: Sun Sep 14 20:20:58 2008 +0200
improve documentation for SwfdecRenderer
It seems to be unclear that SwfdecRenderer objects should be kept around.
diff --git a/swfdec/swfdec_renderer.c b/swfdec/swfdec_renderer.c
index 7e4495c..259f28a 100644
--- a/swfdec/swfdec_renderer.c
+++ b/swfdec/swfdec_renderer.c
@@ -42,18 +42,21 @@ struct _SwfdecRendererPrivate {
* The #SwfdecRenderer object is used internally to improve rendering done by
* Swfdec.
*
- * The first thing #SwfdecRenderer does is provide a way to cache data relevant
- * to rendering.
+ * The first thing a #SwfdecRenderer does is provide a way to cache data relevant
+ * to rendering. This means it will cache surfaces that are expensive to create
+ * (like decoded JPEG images) in a format most suitable to quick rendering.
+ * Therefore, it's a good idea to keep renderers around as long as any drawing
+ * to the attached surface happens.
*
- * The second thing it does is provide access to the surface that is used for
- * rendering, even when not in the process of rendering. This is relevant for
- * font backends, as different surfaces provide different native fonts. See
- * swfdec_player_set_default_backend() for details about this.
+ * The second thing a #SwfdecRenderer does is provide access to the surface
+ * that is used for rendering, even when not in the process of rendering. This
+ * is relevant for font backends, as different surfaces provide different
+ * native fonts. See swfdec_player_set_default_backend() for details about this.
*
- * The third thing it does is provide a list of virtual functions for critical
- * operations that you can optimize using subclasses to provide faster
- * implementations. Note that a working default implementation is provided, so
- * you only need to override the functions you care about.
+ * The third thing #SwfdecRenderer does is provide a list of virtual functions
+ * for critical operations that you can optimize using subclasses to provide
+ * faster implementations. Note that a working default implementation is
+ * provided, so you only need to override the functions you care about.
* See #SwfdecRendererClass for details about these functions.
*/
commit a0c5effa5511259fa85f370d8c70a9d1d1820266
Author: Benjamin Otte <otte at gnome.org>
Date: Sun Sep 14 19:52:55 2008 +0200
We require glib 2.16
diff --git a/README b/README
index f9e0632..09955b8 100644
--- a/README
+++ b/README
@@ -64,7 +64,7 @@ Limitations:
Dependencies:
cairo (>= 1.2.0 - >= 1.8.0 recommended) with png support enabled
- glib (>= 2.14.0)
+ glib (>= 2.16.0)
liboil (>= 0.3.6)
Pangocairo (>= 1.16.0) - this is provided by Pango
zlib (>= 1.1.4)
commit a21547aeb5666886f3d0a0201e2a6d5b406d606e
Author: Benjamin Otte <otte at gnome.org>
Date: Wed Sep 10 18:56:29 2008 +0200
only do save/restore when needed
diff --git a/swfdec/swfdec_movie.c b/swfdec/swfdec_movie.c
index a37537e..90f8cf0 100644
--- a/swfdec/swfdec_movie.c
+++ b/swfdec/swfdec_movie.c
@@ -806,8 +806,9 @@ swfdec_movie_render (SwfdecMovie *movie, cairo_t *cr,
}
if (movie->masked_by != NULL) {
cairo_push_group (cr);
+ } else {
+ cairo_save (cr);
}
- cairo_save (cr);
SWFDEC_LOG ("transforming movie, transform: %g %g %g %g %g %g",
movie->matrix.xx, movie->matrix.yy,
@@ -836,7 +837,6 @@ swfdec_movie_render (SwfdecMovie *movie, cairo_t *cr,
if (cairo_status (cr) != CAIRO_STATUS_SUCCESS) {
g_warning ("error rendering with cairo: %s", cairo_status_to_string (cairo_status (cr)));
}
- cairo_restore (cr);
if (movie->masked_by) {
cairo_pattern_t *mask;
cairo_matrix_t mat;
@@ -854,6 +854,8 @@ swfdec_movie_render (SwfdecMovie *movie, cairo_t *cr,
cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
cairo_mask (cr, mask);
cairo_pattern_destroy (mask);
+ } else {
+ cairo_restore (cr);
}
if (group != SWFDEC_GROUP_NONE) {
cairo_pattern_t *pattern;
commit b520fea5127b93a614a214eab0662ff915a31bbf
Author: Benjamin Otte <otte at gnome.org>
Date: Wed Sep 10 10:55:33 2008 +0200
render mask before blend mode
also add some features required for filters/cacheAsBitmap
diff --git a/swfdec/swfdec_movie.c b/swfdec/swfdec_movie.c
index adbe5a7..a37537e 100644
--- a/swfdec/swfdec_movie.c
+++ b/swfdec/swfdec_movie.c
@@ -690,10 +690,24 @@ swfdec_movie_do_contains (SwfdecMovie *movie, double x, double y, gboolean event
return NULL;
}
-static gboolean
+/* NB: order is important */
+typedef enum {
+ SWFDEC_GROUP_NONE = 0,
+ SWFDEC_GROUP_NORMAL,
+ SWFDEC_GROUP_CACHED,
+ SWFDEC_GROUP_BITMAP
+} SwfdecGroup;
+
+static SwfdecGroup
swfdec_movie_needs_group (SwfdecMovie *movie)
{
- return (movie->blend_mode > 1);
+ if (movie->filters)
+ return SWFDEC_GROUP_BITMAP;
+ if (movie->cache_as_bitmap)
+ return SWFDEC_GROUP_CACHED;
+ if (movie->blend_mode > 1)
+ return SWFDEC_GROUP_NORMAL;
+ return SWFDEC_GROUP_NONE;
}
static cairo_operator_t
@@ -767,7 +781,7 @@ swfdec_movie_render (SwfdecMovie *movie, cairo_t *cr,
{
SwfdecMovieClass *klass;
SwfdecColorTransform trans;
- gboolean group;
+ SwfdecGroup group;
g_return_if_fail (SWFDEC_IS_MOVIE (movie));
g_return_if_fail (cr != NULL);
@@ -782,13 +796,16 @@ swfdec_movie_render (SwfdecMovie *movie, cairo_t *cr,
return;
}
- if (movie->masked_by != NULL) {
- cairo_push_group (cr);
- }
group = swfdec_movie_needs_group (movie);
- if (group) {
+ if (group == SWFDEC_GROUP_NORMAL) {
SWFDEC_DEBUG ("pushing group for blend mode %u", movie->blend_mode);
cairo_push_group (cr);
+ } else if (group != SWFDEC_GROUP_NONE) {
+ SWFDEC_FIXME ("implement cache-as-bitmap and filters here");
+ cairo_push_group (cr);
+ }
+ if (movie->masked_by != NULL) {
+ cairo_push_group (cr);
}
cairo_save (cr);
@@ -820,15 +837,6 @@ swfdec_movie_render (SwfdecMovie *movie, cairo_t *cr,
g_warning ("error rendering with cairo: %s", cairo_status_to_string (cairo_status (cr)));
}
cairo_restore (cr);
- if (group) {
- cairo_pattern_t *pattern;
-
- pattern = cairo_pop_group (cr);
- cairo_set_source (cr, pattern);
- cairo_set_operator (cr, swfdec_movie_get_operator_for_blend_mode (movie->blend_mode));
- cairo_paint (cr);
- cairo_pattern_destroy (pattern);
- }
if (movie->masked_by) {
cairo_pattern_t *mask;
cairo_matrix_t mat;
@@ -847,6 +855,15 @@ swfdec_movie_render (SwfdecMovie *movie, cairo_t *cr,
cairo_mask (cr, mask);
cairo_pattern_destroy (mask);
}
+ if (group != SWFDEC_GROUP_NONE) {
+ cairo_pattern_t *pattern;
+
+ pattern = cairo_pop_group (cr);
+ cairo_set_source (cr, pattern);
+ cairo_set_operator (cr, swfdec_movie_get_operator_for_blend_mode (movie->blend_mode));
+ cairo_paint (cr);
+ cairo_pattern_destroy (pattern);
+ }
}
static void
diff --git a/swfdec/swfdec_movie.h b/swfdec/swfdec_movie.h
index 512abf0..1e93a50 100644
--- a/swfdec/swfdec_movie.h
+++ b/swfdec/swfdec_movie.h
@@ -156,6 +156,8 @@ struct _SwfdecMovie {
/* drawing state */
SwfdecMovie * mask_of; /* movie this movie is a mask of or NULL if none */
SwfdecMovie * masked_by; /* movie we are masked by or NULL if none */
+ GSList * filters; /* filters to apply to movie */
+ gboolean cache_as_bitmap; /* the movie should be cached */
/* FIXME: could it be that shape drawing (SwfdecGraphicMovie etc) uses these same objects? */
SwfdecImage * image; /* image loaded via loadMovie */
SwfdecRect draw_extents; /* extents of the items in the following list */
More information about the Swfdec-commits
mailing list