[lasem] svg: enable filter code.
- From: Emmanuel Pacaud <emmanuel src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [lasem] svg: enable filter code.
- Date: Sat, 13 Oct 2012 19:49:51 +0000 (UTC)
commit 3ee63e245d9ed256005666a5cd53b87e20296ba6
Author: Emmanuel Pacaud <emmanuel gnome org>
Date: Sat Oct 13 21:49:13 2012 +0200
svg: enable filter code.
src/lsmsvgfilterelement.c | 58 ++++++++++---
src/lsmsvgfilterelement.h | 4 +-
src/lsmsvgfiltergaussianblur.c | 16 +++-
src/lsmsvgfilterprimitive.c | 14 +++-
src/lsmsvgfilterprimitive.h | 3 +
src/lsmsvgview.c | 181 ++++++++++++++++++++++++++++++----------
src/lsmsvgview.h | 1 +
7 files changed, 216 insertions(+), 61 deletions(-)
---
diff --git a/src/lsmsvgfilterelement.c b/src/lsmsvgfilterelement.c
index 07255c1..0a337f5 100644
--- a/src/lsmsvgfilterelement.c
+++ b/src/lsmsvgfilterelement.c
@@ -45,12 +45,53 @@ lsm_svg_filter_element_can_append_child (LsmDomNode *self, LsmDomNode *child)
/* LsmSvgElement implementation */
+LsmBox
+lsm_svg_filter_element_get_effect_viewport (LsmSvgFilterElement *filter, const LsmBox *source_extents, LsmSvgView *view)
+{
+ static LsmBox null_extents = {.x = 0.0, .y = 0.0, .width = 0.0, .height = 0.0};
+ gboolean is_object_bounding_box;
+ LsmBox viewport;
+
+ g_return_val_if_fail (LSM_IS_SVG_FILTER_ELEMENT (filter), null_extents);
+ g_return_val_if_fail (source_extents != NULL, null_extents);
+ g_return_val_if_fail (LSM_IS_SVG_VIEW (view), null_extents);
+
+ is_object_bounding_box = (filter->units.value == LSM_SVG_PATTERN_UNITS_OBJECT_BOUNDING_BOX);
+
+ if (is_object_bounding_box) {
+ LsmBox viewbox = {.x = 0.0, .y = .0, .width = 1.0, .height = 1.0};
+
+ lsm_svg_view_push_viewbox (view, &viewbox);
+ }
+
+ viewport.x = lsm_svg_view_normalize_length (view, &filter->x.length,
+ LSM_SVG_LENGTH_DIRECTION_HORIZONTAL);
+ viewport.y = lsm_svg_view_normalize_length (view, &filter->y.length,
+ LSM_SVG_LENGTH_DIRECTION_VERTICAL);
+ viewport.width = lsm_svg_view_normalize_length (view, &filter->width.length,
+ LSM_SVG_LENGTH_DIRECTION_HORIZONTAL);
+ viewport.height = lsm_svg_view_normalize_length (view, &filter->height.length,
+ LSM_SVG_LENGTH_DIRECTION_VERTICAL);
+
+ if (is_object_bounding_box) {
+ lsm_svg_view_pop_viewbox (view);
+
+ viewport.x = viewport.x * source_extents->width + source_extents->x;
+ viewport.y = viewport.y * source_extents->height + source_extents->y;
+ viewport.width *= source_extents->width;
+ viewport.height *= source_extents->height;
+ }
+
+ return viewport;
+}
+
static void
lsm_svg_filter_element_render (LsmSvgElement *self, LsmSvgView *view)
{
LsmSvgFilterElement *filter = LSM_SVG_FILTER_ELEMENT (self);
LsmDomNode *node;
LsmBox viewport;
+ LsmBox viewbox = {.x = 0.0, .y = .0, .width = 1.0, .height = 1.0};
const LsmBox *filter_extents;
gboolean is_object_bounding_box;
@@ -61,15 +102,12 @@ lsm_svg_filter_element_render (LsmSvgElement *self, LsmSvgView *view)
filter->enable_rendering = FALSE;
}
- filter_extents = lsm_svg_view_get_pattern_extents (view);
+ filter_extents = lsm_svg_view_get_object_extents (view);
is_object_bounding_box = (filter->units.value == LSM_SVG_PATTERN_UNITS_OBJECT_BOUNDING_BOX);
- if (is_object_bounding_box) {
- LsmBox viewbox = {.x = 0.0, .y = .0, .width = 1.0, .height = 1.0};
-
+ if (is_object_bounding_box)
lsm_svg_view_push_viewbox (view, &viewbox);
- }
viewport.x = lsm_svg_view_normalize_length (view, &filter->x.length,
LSM_SVG_LENGTH_DIRECTION_HORIZONTAL);
@@ -100,18 +138,14 @@ lsm_svg_filter_element_render (LsmSvgElement *self, LsmSvgView *view)
is_object_bounding_box = (filter->primitive_units.value == LSM_SVG_PATTERN_UNITS_OBJECT_BOUNDING_BOX);
- if (is_object_bounding_box) {
- LsmBox viewbox = {.x = 0.0, .y = .0, .width = 1.0, .height = 1.0};
-
- lsm_svg_view_push_viewbox (view, &viewbox);
- }
+ lsm_svg_view_push_viewport (view, &viewport,
+ is_object_bounding_box ? &viewbox : NULL, NULL, LSM_SVG_OVERFLOW_VISIBLE);
for (node = LSM_DOM_NODE (filter)->first_child; node != NULL; node = node->next_sibling)
if (LSM_IS_SVG_FILTER_PRIMITIVE (node))
lsm_svg_filter_primitive_apply (LSM_SVG_FILTER_PRIMITIVE (node), view);
- if (is_object_bounding_box)
- lsm_svg_view_pop_viewbox (view);
+ lsm_svg_view_pop_viewport (view);
}
static void
diff --git a/src/lsmsvgfilterelement.h b/src/lsmsvgfilterelement.h
index 41c198d..7b1e3d1 100644
--- a/src/lsmsvgfilterelement.h
+++ b/src/lsmsvgfilterelement.h
@@ -57,7 +57,9 @@ struct _LsmSvgFilterElementClass {
GType lsm_svg_filter_element_get_type (void);
-LsmDomNode * lsm_svg_filter_element_new (void);
+LsmDomNode * lsm_svg_filter_element_new (void);
+LsmBox lsm_svg_filter_element_get_effect_viewport (LsmSvgFilterElement *filter,
+ const LsmBox *source_extents, LsmSvgView *view);
G_END_DECLS
diff --git a/src/lsmsvgfiltergaussianblur.c b/src/lsmsvgfiltergaussianblur.c
index 86f4694..b96a4b3 100644
--- a/src/lsmsvgfiltergaussianblur.c
+++ b/src/lsmsvgfiltergaussianblur.c
@@ -42,10 +42,20 @@ lsm_svg_filter_gaussian_blur_apply (LsmSvgFilterPrimitive *self, LsmSvgView *vi
double x, double y, double w, double h)
{
LsmSvgFilterGaussianBlur *blur = LSM_SVG_FILTER_GAUSSIAN_BLUR (self);
+ LsmSvgLength length;
+ double std_a, std_b;
- lsm_svg_view_apply_gaussian_blur (view, input, output, x, y, w, h,
- blur->std_deviation.value.a,
- blur->std_deviation.value.b);
+ length.type = LSM_SVG_LENGTH_TYPE_ERROR;
+
+ length.value_unit = blur->std_deviation.value.a;
+ std_a = lsm_svg_view_normalize_length (view, &length, LSM_SVG_LENGTH_DIRECTION_HORIZONTAL);
+
+ length.value_unit = blur->std_deviation.value.b;
+ std_b = lsm_svg_view_normalize_length (view, &length, LSM_SVG_LENGTH_DIRECTION_HORIZONTAL);
+
+ lsm_svg_view_apply_gaussian_blur (view, input, output,
+ x, y, w, h,
+ std_a, std_b);
}
/* LsmSvgFilterGaussianBlur implementation */
diff --git a/src/lsmsvgfilterprimitive.c b/src/lsmsvgfilterprimitive.c
index dce8de4..2d9cf44 100644
--- a/src/lsmsvgfilterprimitive.c
+++ b/src/lsmsvgfilterprimitive.c
@@ -53,8 +53,10 @@ lsm_svg_filter_primitive_apply (LsmSvgFilterPrimitive *self, LsmSvgView *view)
w = lsm_svg_view_normalize_length (view, &self->width.length, LSM_SVG_LENGTH_DIRECTION_HORIZONTAL);
h = lsm_svg_view_normalize_length (view, &self->height.length, LSM_SVG_LENGTH_DIRECTION_VERTICAL);
+ lsm_log_render ("[Svg::FilterPrimitive::apply] Apply %s", lsm_dom_node_get_node_name (LSM_DOM_NODE (self)));
+
if (primitive_class->apply != NULL)
- primitive_class->apply (self, view, NULL, NULL, x, y, w, h);
+ primitive_class->apply (self, view, self->in.value, self->result.value, x, y, w, h);
}
static const LsmSvgLength x_y_default = { .value_unit = 0.0, .type = LSM_SVG_LENGTH_TYPE_PERCENTAGE};
@@ -101,6 +103,16 @@ static const LsmAttributeInfos lsm_svg_filter_primitive_attribute_infos[] = {
.attribute_offset = offsetof (LsmSvgFilterPrimitive, height),
.trait_class = &lsm_svg_length_trait_class,
.trait_default = &width_height_default
+ },
+ {
+ .name = "in",
+ .attribute_offset = offsetof (LsmSvgFilterPrimitive, in),
+ .trait_class = &lsm_null_trait_class
+ },
+ {
+ .name = "result",
+ .attribute_offset = offsetof (LsmSvgFilterPrimitive, result),
+ .trait_class = &lsm_null_trait_class
}
};
diff --git a/src/lsmsvgfilterprimitive.h b/src/lsmsvgfilterprimitive.h
index c593732..e3fc05f 100644
--- a/src/lsmsvgfilterprimitive.h
+++ b/src/lsmsvgfilterprimitive.h
@@ -45,6 +45,9 @@ struct _LsmSvgFilterPrimitive {
LsmSvgLengthAttribute y;
LsmSvgLengthAttribute width;
LsmSvgLengthAttribute height;
+
+ LsmAttribute in;
+ LsmAttribute result;
};
struct _LsmSvgFilterPrimitiveClass {
diff --git a/src/lsmsvgview.c b/src/lsmsvgview.c
index 87e7ad2..a467f1b 100644
--- a/src/lsmsvgview.c
+++ b/src/lsmsvgview.c
@@ -27,6 +27,7 @@
#include <lsmsvgelement.h>
#include <lsmsvgsvgelement.h>
#include <lsmsvgradialgradientelement.h>
+#include <lsmsvgfilterelement.h>
#include <lsmsvglineargradientelement.h>
#include <lsmsvgpatternelement.h>
#include <lsmsvgmarkerelement.h>
@@ -64,6 +65,7 @@ struct _LsmSvgViewPatternData {
cairo_pattern_t *pattern;
LsmBox extents;
+ LsmBox object_extents;
double opacity;
};
@@ -77,7 +79,7 @@ lsm_svg_view_normalize_length (LsmSvgView *view, const LsmSvgLength *length, Lsm
}
static void
-_start_pattern (LsmSvgView *view, const LsmBox *extents, double opacity)
+_start_pattern (LsmSvgView *view, const LsmBox *extents, const LsmBox *object_extents, double opacity)
{
lsm_debug_render ("[LsmSvgView::start_pattern]");
@@ -88,6 +90,7 @@ _start_pattern (LsmSvgView *view, const LsmBox *extents, double opacity)
view->pattern_data->pattern = NULL;
view->pattern_data->extents = *extents;
view->pattern_data->opacity = opacity;
+ view->pattern_data->object_extents = *object_extents;
view->dom_view.cairo = NULL;
}
@@ -289,7 +292,7 @@ lsm_svg_view_create_surface_pattern (LsmSvgView *view,
x_scale = device_width / viewport->width;
y_scale = device_height / viewport->height;
- lsm_debug_render ("[LsmSvgView::create_pattern] pattern size = %g ,%g at %g, %g (scale %g x %g)",
+ lsm_debug_render ("[LsmSvgView::create_surface_pattern] pattern size = %g ,%g at %g, %g (scale %g x %g)",
device_width, device_height, viewport->x, viewport->y, x_scale, y_scale);
switch (surface_type) {
@@ -336,6 +339,10 @@ lsm_svg_view_create_surface_pattern (LsmSvgView *view,
cairo_pattern_set_matrix (view->pattern_data->pattern, &matrix);
cairo_pattern_set_extend (view->pattern_data->pattern, CAIRO_EXTEND_REPEAT);
+ lsm_debug_render ("[LsmSvgView::create_surface_pattern] Pattern matrix %g, %g, %g, %g, %g, %g",
+ matrix.xx, matrix.xy, matrix.yx, matrix.yy,
+ matrix.x0, matrix.y0);
+
return TRUE;
}
@@ -801,7 +808,7 @@ _paint_url (LsmSvgView *view,
lsm_debug_render ("[LsmSvgView::_paint_url] Pattern extents x = %g, y = %g, w = %g, h = %g",
extents.x, extents.y, extents.width, extents.height);
- _start_pattern (view, &extents, opacity);
+ _start_pattern (view, &extents, &extents, opacity);
lsm_svg_element_force_render (LSM_SVG_ELEMENT (element), view);
@@ -1861,7 +1868,7 @@ lsm_svg_view_pop_mask (LsmSvgView *view)
cairo = view->dom_view.cairo;
- _start_pattern (view, &mask_extents, 1.0);
+ _start_pattern (view, &mask_extents, &mask_extents, 1.0);
lsm_svg_element_force_render (LSM_SVG_ELEMENT (mask_element), view);
@@ -1913,38 +1920,55 @@ lsm_svg_view_pop_mask (LsmSvgView *view)
void
lsm_svg_view_push_filter (LsmSvgView *view)
{
-#if 0
LsmExtents extents;
- LsmBox source_extents;
- gboolean result;
+ LsmBox object_extents;
+ LsmBox effect_viewport;
+ LsmSvgElement *filter_element;
+ gboolean success;
g_return_if_fail (LSM_IS_SVG_VIEW (view));
g_return_if_fail (view->element_stack != NULL);
lsm_svg_element_get_extents (view->element_stack->data, view, &extents);
- source_extents.x = extents.x1;
- source_extents.y = extents.y1;
- source_extents.width = extents.x2 - extents.x1;
- source_extents.height = extents.y2 - extents.y1;
+ object_extents.x = extents.x1;
+ object_extents.y = extents.y1;
+ object_extents.width = extents.x2 - extents.x1;
+ object_extents.height = extents.y2 - extents.y1;
+
+ filter_element = lsm_svg_document_get_element_by_url (LSM_SVG_DOCUMENT (view->dom_view.document),
+ view->style->filter->value);
+
+ if (LSM_IS_SVG_FILTER_ELEMENT (filter_element)) {
+ effect_viewport = lsm_svg_filter_element_get_effect_viewport (LSM_SVG_FILTER_ELEMENT (filter_element),
+ &object_extents, view);
+
+ _start_pattern (view, &effect_viewport, &object_extents,
+ view->style->opacity != NULL ? view->style->opacity->value : 1.0);
- _start_pattern (view, &source_extents, 1.0);
+ success = lsm_svg_view_create_surface_pattern (view,
+ &effect_viewport,
+ NULL,
+ LSM_SVG_VIEW_SURFACE_TYPE_IMAGE);
+ } else {
+ _start_pattern (view, &object_extents, &object_extents, 0.0);
+
+ success = lsm_svg_view_create_surface_pattern (view,
+ &object_extents,
+ NULL,
+ LSM_SVG_VIEW_SURFACE_TYPE_IMAGE);
+ }
- result = lsm_svg_view_create_surface_pattern (view,
- &source_extents,
- NULL,
- LSM_SVG_VIEW_SURFACE_TYPE_IMAGE);
-#endif
+ if (!success)
+ lsm_warning_render ("LsmSvgView::push_filter] Failed to create subsurface");
}
void
lsm_svg_view_pop_filter (LsmSvgView *view)
{
-#if 0
LsmSvgElement *filter_element;
LsmFilterSurface *filter_surface;
cairo_surface_t *surface;
- cairo_t *cairo;
GSList *iter;
g_return_if_fail (LSM_IS_SVG_VIEW (view));
@@ -1952,41 +1976,74 @@ lsm_svg_view_pop_filter (LsmSvgView *view)
filter_element = lsm_svg_document_get_element_by_url (LSM_SVG_DOCUMENT (view->dom_view.document),
view->style->filter->value);
-TODO: lsm_svg_view_circular_reference_check
+ if (LSM_IS_SVG_FILTER_ELEMENT (filter_element) &&
+ view->pattern_data->pattern != NULL) {
+ view->filter_surfaces = NULL;
- cairo = view->pattern_data->old_cairo;
+ cairo_pattern_get_surface (view->pattern_data->pattern, &surface);
+ filter_surface = lsm_filter_surface_new_with_content ("SourceGraphic", 0, 0, surface);
- view->filter_surfaces = NULL;
+ view->filter_surfaces = g_slist_prepend (view->filter_surfaces, filter_surface);
- cairo_pattern_get_surface (view->pattern_data->pattern, &surface);
- filter_surface = lsm_filter_surface_new_with_content ("SourceGraphic", 0, 0, surface);
+ lsm_svg_element_force_render (filter_element, view);
- view->filter_surfaces = g_slist_prepend (view->filter_surfaces, filter_surface);
+ cairo_pattern_set_extend (view->pattern_data->pattern, CAIRO_EXTEND_NONE);
+ cairo_set_source (view->pattern_data->old_cairo, view->pattern_data->pattern);
+ cairo_paint_with_alpha (view->pattern_data->old_cairo, view->pattern_data->opacity);
-#if 1
- {
- char *filename;
- static int count = 0;
+ if (view->debug_filter) {
+ GSList *iter;
+ char *filename;
+ static int count = 0;
- filename = g_strdup_printf ("filter-%04d-%s.png", count++, view->style->filter->value);
- cairo_surface_write_to_png (cairo_get_target (view->dom_view.cairo), filename);
- g_free (filename);
- }
-#endif
+ for (iter = view->filter_surfaces; iter != NULL; iter = iter->next) {
+ LsmFilterSurface *surface = iter->data;
-#if 1
- cairo_pattern_set_extend (view->pattern_data->pattern, CAIRO_EXTEND_NONE);
- cairo_set_source (cairo, view->pattern_data->pattern);
- cairo_paint (cairo);
-#endif
+ filename = g_strdup_printf ("filter-%04d-%s-%s.png", count++,
+ view->style->filter->value,
+ lsm_filter_surface_get_name (surface));
+ cairo_surface_write_to_png (lsm_filter_surface_get_cairo_surface (surface), filename);
+ g_free (filename);
+ }
+ }
- for (iter = view->filter_surfaces; iter != NULL; iter = iter->next)
- lsm_filter_surface_free (iter->data);
- g_slist_free (view->filter_surfaces);
- view->filter_surfaces = NULL;
+ for (iter = view->filter_surfaces; iter != NULL; iter = iter->next)
+ lsm_filter_surface_unref (iter->data);
+ g_slist_free (view->filter_surfaces);
+ view->filter_surfaces = NULL;
+ }
_end_pattern (view);
-#endif
+}
+
+static LsmFilterSurface *
+_get_filter_surface (LsmSvgView *view, const char *input)
+{
+ GSList *iter;
+
+ if (input == NULL)
+ return view->filter_surfaces->data;
+
+ for (iter = view->filter_surfaces; iter != NULL; iter = iter->next) {
+ LsmFilterSurface *surface = iter->data;
+
+ if (g_strcmp0 (input, lsm_filter_surface_get_name (surface)) == 0)
+ return surface;
+ }
+
+ return NULL;
+}
+
+static LsmFilterSurface *
+_create_filter_surface (LsmSvgView *view, const char *output, LsmFilterSurface *input_surface)
+{
+ LsmFilterSurface *surface;
+
+ surface = lsm_filter_surface_new_similar (output, input_surface);
+
+ view->filter_surfaces = g_slist_prepend (view->filter_surfaces, surface);
+
+ return surface;
}
void
@@ -1994,6 +2051,31 @@ lsm_svg_view_apply_gaussian_blur (LsmSvgView *view, const char *input, const cha
double x, double y, double w, double h,
double std_x, double std_y)
{
+ LsmFilterSurface *input_surface;
+ LsmFilterSurface *output_surface;
+
+ g_return_if_fail (LSM_IS_SVG_VIEW (view));
+
+ input_surface = _get_filter_surface (view, input);
+
+ if (input_surface == NULL) {
+ lsm_debug_render ("[SvgView::apply_gaussian_blur] Input '%s' not found", input);
+ return;
+ }
+
+ output_surface = _create_filter_surface (view, output, input_surface);
+
+ lsm_log_render ("[SvgView::apply_gaussian_blur] %s -> %s (x:%g,y:%g,w:%g,h:%g) (%g,%g)",
+ input != NULL ? input : "previous",
+ output != NULL ? output : "next",
+ x, y, w, h, std_x, std_y);
+
+ cairo_user_to_device_distance (view->dom_view.cairo, &std_x, &std_y);
+
+ lsm_log_render ("[SvgView::apply_gaussian_blur] %g px,%g px",
+ std_x, std_y);
+
+ lsm_filter_surface_fast_blur (input_surface, output_surface, std_x, std_y);
}
void
@@ -2125,6 +2207,17 @@ lsm_svg_view_get_pattern_extents (LsmSvgView *view)
}
const LsmBox *
+lsm_svg_view_get_object_extents (LsmSvgView *view)
+{
+ static LsmBox null_extents = {.x = 0.0, .y = 0.0, .width = 0.0, .height = 0.0};
+
+ g_return_val_if_fail (LSM_IS_SVG_VIEW (view), &null_extents);
+ g_return_val_if_fail (view->pattern_data != NULL, &null_extents);
+
+ return &view->pattern_data->object_extents;
+}
+
+const LsmBox *
lsm_svg_view_get_clip_extents (LsmSvgView *view)
{
static LsmBox null_extents = {.x = 0.0, .y = 0.0, .width = 0.0, .height = 0.0};
diff --git a/src/lsmsvgview.h b/src/lsmsvgview.h
index 20e20d5..b247050 100644
--- a/src/lsmsvgview.h
+++ b/src/lsmsvgview.h
@@ -92,6 +92,7 @@ double lsm_svg_view_normalize_length (LsmSvgView *view, const LsmSvgLength *
LsmSvgLengthDirection direction);
const LsmBox * lsm_svg_view_get_pattern_extents (LsmSvgView *view);
+const LsmBox * lsm_svg_view_get_object_extents (LsmSvgView *view);
const LsmBox * lsm_svg_view_get_clip_extents (LsmSvgView *view);
void lsm_svg_view_calculate_path_extents (LsmSvgView *view, const char *path,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]