[libgxps] Move GXPSBrush code to a new file



commit 7e3635a6cac36cb8f29251d15046b477914bcab6
Author: Carlos Garcia Campos <carlosgc gnome org>
Date:   Mon Nov 14 19:51:19 2011 +0100

    Move GXPSBrush code to a new file

 libgxps/Makefile.am  |    2 +
 libgxps/gxps-brush.c | 1047 ++++++++++++++++++++++++++++++++++++++++++++++++++
 libgxps/gxps-brush.h |   47 +++
 libgxps/gxps-page.c  |  966 +---------------------------------------------
 4 files changed, 1105 insertions(+), 957 deletions(-)
---
diff --git a/libgxps/Makefile.am b/libgxps/Makefile.am
index 872c678..f8ae726 100644
--- a/libgxps/Makefile.am
+++ b/libgxps/Makefile.am
@@ -2,6 +2,7 @@ lib_LTLIBRARIES = libgxps.la
 
 NOINST_H_FILES = \
 	gxps-archive.h		\
+	gxps-brush.h		\
 	gxps-color.h		\
 	gxps-debug.h		\
 	gxps-fonts.h		\
@@ -26,6 +27,7 @@ libgxpsinclude_HEADERS = $(INST_H_FILES)
 
 libgxps_la_SOURCES = \
 	gxps-archive.c			\
+	gxps-brush.c			\
 	gxps-color.c			\
 	gxps-debug.c			\
 	gxps-document.c			\
diff --git a/libgxps/gxps-brush.c b/libgxps/gxps-brush.c
new file mode 100644
index 0000000..1b4e00a
--- /dev/null
+++ b/libgxps/gxps-brush.c
@@ -0,0 +1,1047 @@
+/* GXPSBrush
+ *
+ * Copyright (C) 2011  Carlos Garcia Campos <carlosgc 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 St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <config.h>
+
+#include <string.h>
+
+#include "gxps-brush.h"
+#include "gxps-matrix.h"
+#include "gxps-color.h"
+#include "gxps-parse-utils.h"
+#include "gxps-debug.h"
+
+typedef struct {
+        GXPSBrush        *brush;
+
+        gchar            *image_uri;
+        cairo_matrix_t    matrix;
+        cairo_rectangle_t viewport;
+        cairo_rectangle_t viewbox;
+        cairo_extend_t    extend;
+} GXPSBrushImage;
+
+struct _GXPSBrushVisual {
+        GXPSBrush        *brush;
+
+        cairo_matrix_t    matrix;
+        cairo_rectangle_t viewport;
+        cairo_rectangle_t viewbox;
+        cairo_extend_t    extend;
+};
+
+GXPSBrush *
+gxps_brush_new (GXPSRenderContext *ctx)
+{
+        GXPSBrush *brush;
+
+        brush = g_slice_new0 (GXPSBrush);
+        brush->ctx = ctx;
+        brush->opacity = 1.0;
+
+        return brush;
+}
+
+void
+gxps_brush_free (GXPSBrush *brush)
+{
+        if (G_UNLIKELY (!brush))
+                return;
+
+        cairo_pattern_destroy (brush->pattern);
+        g_slice_free (GXPSBrush, brush);
+}
+
+static gboolean
+hex (const gchar *spec,
+     gint         len,
+     guint       *c)
+{
+        const gchar *end;
+
+        *c = 0;
+        for (end = spec + len; spec != end; spec++) {
+                if (!g_ascii_isxdigit (*spec))
+                        return FALSE;
+
+                *c = (*c << 4) | g_ascii_xdigit_value (*spec);
+        }
+
+        return TRUE;
+}
+
+static gboolean
+gxps_color_s_rgb_parse (const gchar *color_str,
+                        GXPSColor   *color)
+{
+        gsize len = strlen (color_str);
+        guint a = 255;
+        guint r, g, b;
+
+        switch (len) {
+        case 6:
+                if (!hex (color_str, 2, &r) ||
+                    !hex (color_str + 2, 2, &g) ||
+                    !hex (color_str + 4, 2, &b))
+                        return FALSE;
+                break;
+        case 8:
+                if (!hex (color_str, 2, &a) ||
+                    !hex (color_str + 2, 2, &r) ||
+                    !hex (color_str + 4, 2, &g) ||
+                    !hex (color_str + 6, 2, &b))
+                        return FALSE;
+                break;
+        default:
+                return FALSE;
+        }
+
+        color->alpha = a / 255.;
+        color->red = r / 255.;
+        color->green = g / 255.;
+        color->blue = b / 255.;
+
+        return TRUE;
+}
+
+static gboolean
+gxps_color_sc_rgb_parse (const gchar *color_str,
+                         GXPSColor   *color)
+{
+        gchar **tokens;
+        gsize   len;
+        gdouble c[4];
+        guint   i, start;
+
+        tokens = g_strsplit (color_str, ",", 4);
+        len = g_strv_length (tokens);
+
+        switch (len) {
+        case 4:
+                if (!gxps_value_get_double (tokens[0], &c[0])) {
+                        g_strfreev (tokens);
+
+                        return FALSE;
+                }
+                start = 1;
+
+                break;
+        case 3:
+                c[0] = 1.0;
+                start = 0;
+                break;
+        default:
+                g_strfreev (tokens);
+                return FALSE;
+        }
+
+        for (i = start; i < len; i++) {
+                if (!gxps_value_get_double (tokens[i], &c[i])) {
+                        g_strfreev (tokens);
+
+                        return FALSE;
+                }
+        }
+
+        g_strfreev (tokens);
+
+        color->alpha = CLAMP (c[0], 0., 1.);
+        color->red = CLAMP (c[1], 0., 1.);
+        color->green = CLAMP (c[2], 0., 1.);
+        color->blue = CLAMP (c[3], 0., 1.);
+
+        return TRUE;
+}
+
+static gboolean
+gxps_color_icc_parse (const gchar *color_str,
+                      GXPSArchive *zip,
+                      GXPSColor   *color)
+{
+        const gchar *p;
+        gchar       *icc_profile_uri;
+        gchar      **tokens;
+        gsize        len;
+        gdouble      alpha;
+        gdouble      values[GXPS_COLOR_MAX_CHANNELS];
+        guint        i, j;
+        gboolean     retval;
+
+        p = strstr (color_str, " ");
+        if (!p)
+                return FALSE;
+
+        icc_profile_uri = g_strndup (color_str, strlen (color_str) - strlen (p));
+
+        tokens = g_strsplit (++p, ",", -1);
+        len = g_strv_length (tokens);
+        if (len < 2) {
+                g_strfreev (tokens);
+                g_free (icc_profile_uri);
+
+                return FALSE;
+        }
+
+        if (!gxps_value_get_double (tokens[0], &alpha)) {
+                g_strfreev (tokens);
+                g_free (icc_profile_uri);
+
+                return FALSE;
+        }
+
+        for (i = 0, j = 1; i < GXPS_COLOR_MAX_CHANNELS && j < len; i++, j++) {
+                if (!gxps_value_get_double (tokens[j], &values[i])) {
+                        g_strfreev (tokens);
+                        g_free (icc_profile_uri);
+
+                        return FALSE;
+                }
+        }
+
+        g_strfreev (tokens);
+
+        color->alpha = CLAMP (alpha, 0., 1.);
+        retval = gxps_color_new_for_icc (zip, icc_profile_uri, values, i, color);
+        g_free (icc_profile_uri);
+
+        return retval;
+}
+
+static gboolean
+gxps_color_parse (const gchar *data,
+                  GXPSArchive *zip,
+                  GXPSColor   *color)
+{
+        const gchar *p;
+
+        p = strstr (data, "#");
+        if (!p) {
+                p = strstr (data, "ContextColor");
+                if (p == data) {
+                        p += strlen ("ContextColor");
+                        return gxps_color_icc_parse (++p, zip, color);
+                }
+                GXPS_DEBUG (g_debug ("Unsupported color %s", data));
+
+                return FALSE;
+        }
+
+        if (p == data)
+                return gxps_color_s_rgb_parse (++p, color);
+
+        if (strncmp (data, "sc", 2) == 0 && p == data + 2)
+                return gxps_color_sc_rgb_parse (++p, color);
+
+        GXPS_DEBUG (g_debug ("Unsupported color %s", data));
+
+        return FALSE;
+}
+
+gboolean
+gxps_brush_solid_color_parse (const gchar      *data,
+                              GXPSArchive      *zip,
+                              gdouble           alpha,
+                              cairo_pattern_t **pattern)
+{
+        GXPSColor        color;
+        cairo_pattern_t *retval;
+
+        if (!gxps_color_parse (data, zip, &color))
+                return FALSE;
+
+        retval = cairo_pattern_create_rgba (color.red,
+                                            color.green,
+                                            color.blue,
+                                            color.alpha * alpha);
+        if (cairo_pattern_status (retval)) {
+                cairo_pattern_destroy (retval);
+
+                return FALSE;
+        }
+
+        if (pattern)
+                *pattern = retval;
+
+        return TRUE;
+}
+
+static cairo_extend_t
+gxps_spread_method_parse (const gchar *spread)
+{
+        if (strcmp (spread, "Pad") == 0)
+                return CAIRO_EXTEND_PAD;
+        else if (strcmp (spread, "Reflect") == 0)
+                return CAIRO_EXTEND_REFLECT;
+        else if (strcmp (spread, "Repeat") == 0)
+                return CAIRO_EXTEND_REPEAT;
+        return CAIRO_EXTEND_NONE;
+}
+
+static cairo_extend_t
+gxps_tile_mode_parse (const gchar *tile)
+{
+        if (strcmp (tile, "Tile") == 0)
+                return CAIRO_EXTEND_REPEAT;
+        else if (strcmp (tile, "FlipX") == 0)
+                GXPS_DEBUG (g_debug ("Unsupported tile mode FlipX"));
+        else if (strcmp (tile, "FlipY") == 0)
+                GXPS_DEBUG (g_debug ("Unsupported tile mode FlipY"));
+        else if (strcmp (tile, "FlipXY") == 0)
+                GXPS_DEBUG (g_debug ("Unsupported tile mode FlipXY"));
+
+        return CAIRO_EXTEND_NONE;
+}
+
+
+static GXPSBrushImage *
+gxps_brush_image_new (GXPSBrush         *brush,
+                      gchar             *image_uri,
+                      cairo_rectangle_t *viewport,
+                      cairo_rectangle_t *viewbox)
+{
+        GXPSBrushImage *image;
+
+        image = g_slice_new0 (GXPSBrushImage);
+        image->brush = brush;
+
+        cairo_matrix_init_identity (&image->matrix);
+
+        /* Required values */
+        image->image_uri = image_uri;
+        image->viewport = *viewport;
+        image->viewbox = *viewbox;
+
+        return image;
+}
+
+static void
+gxps_brush_image_free (GXPSBrushImage *image)
+{
+        if (G_UNLIKELY (!image))
+                return;
+
+        g_free (image->image_uri);
+
+        g_slice_free (GXPSBrushImage, image);
+}
+
+static void
+brush_image_start_element (GMarkupParseContext  *context,
+                           const gchar          *element_name,
+                           const gchar         **names,
+                           const gchar         **values,
+                           gpointer              user_data,
+                           GError              **error)
+{
+        GXPSBrushImage *image = (GXPSBrushImage *)user_data;
+
+        if (strcmp (element_name, "ImageBrush.Transform") == 0) {
+                GXPSMatrix *matrix;
+
+                matrix = gxps_matrix_new (image->brush->ctx);
+                gxps_matrix_parser_push (context, matrix);
+        } else {
+                gxps_parse_error (context,
+                                  image->brush->ctx->page->priv->source,
+                                  G_MARKUP_ERROR_UNKNOWN_ELEMENT,
+                                  element_name, NULL, NULL, error);
+        }
+}
+
+static void
+brush_image_end_element (GMarkupParseContext  *context,
+                         const gchar          *element_name,
+                         gpointer              user_data,
+                         GError              **error)
+{
+        GXPSBrushImage *image = (GXPSBrushImage *)user_data;
+
+        if (strcmp (element_name, "ImageBrush.Transform") == 0) {
+                GXPSMatrix *matrix;
+
+                matrix = g_markup_parse_context_pop (context);
+                image->matrix = matrix->matrix;
+                gxps_matrix_free (matrix);
+        } else {
+                gxps_parse_error (context,
+                                  image->brush->ctx->page->priv->source,
+                                  G_MARKUP_ERROR_UNKNOWN_ELEMENT,
+                                  element_name, NULL, NULL, error);
+        }
+}
+
+static GMarkupParser brush_image_parser = {
+        brush_image_start_element,
+        brush_image_end_element,
+        NULL,
+        NULL
+};
+
+static GXPSBrushVisual *
+gxps_brush_visual_new (GXPSBrush         *brush,
+                      cairo_rectangle_t *viewport,
+                      cairo_rectangle_t *viewbox)
+{
+        GXPSBrushVisual *visual;
+
+        visual = g_slice_new0 (GXPSBrushVisual);
+        visual->brush = brush;
+
+        /* Default */
+        visual->extend = CAIRO_EXTEND_NONE;
+        cairo_matrix_init_identity (&visual->matrix);
+
+        /* Required values */
+        visual->viewport = *viewport;
+        visual->viewbox = *viewbox;
+
+        return visual;
+}
+
+static void
+gxps_brush_visual_free (GXPSBrushVisual *visual)
+{
+        if (G_UNLIKELY (!visual))
+                return;
+
+        g_slice_free (GXPSBrushVisual, visual);
+}
+
+static void
+brush_gradient_start_element (GMarkupParseContext  *context,
+                              const gchar          *element_name,
+                              const gchar         **names,
+                              const gchar         **values,
+                              gpointer              user_data,
+                              GError              **error)
+{
+        GXPSBrush *brush = (GXPSBrush *)user_data;
+
+        if (strcmp (element_name, "LinearGradientBrush.GradientStops") == 0) {
+        } else if (strcmp (element_name, "RadialGradientBrush.GradientStops") == 0) {
+        } else if (strcmp (element_name, "GradientStop") == 0) {
+                gint      i;
+                GXPSColor color;
+                gboolean  has_color = FALSE;
+                gdouble   offset = -1;
+
+                for (i = 0; names[i] != NULL; i++) {
+                        if (strcmp (names[i], "Color") == 0) {
+                                has_color = TRUE;
+                                if (!gxps_color_parse (values[i], brush->ctx->page->priv->zip, &color)) {
+                                        gxps_parse_error (context,
+                                                          brush->ctx->page->priv->source,
+                                                          G_MARKUP_ERROR_INVALID_CONTENT,
+                                                          "GradientStop", "Color",
+                                                          values[i], error);
+                                        return;
+                                }
+                        } else if (strcmp (names[i], "Offset") == 0) {
+                                if (!gxps_value_get_double (values[i], &offset)) {
+                                        gxps_parse_error (context,
+                                                          brush->ctx->page->priv->source,
+                                                          G_MARKUP_ERROR_INVALID_CONTENT,
+                                                          "GradientStop", "Offset",
+                                                          values[i], error);
+                                        return;
+                                }
+                        } else {
+                                gxps_parse_error (context,
+                                                  brush->ctx->page->priv->source,
+                                                  G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE,
+                                                  "GradientStop", names[i],
+                                                  NULL, error);
+                                return;
+                        }
+                }
+
+                if (!has_color || offset == -1) {
+                        gxps_parse_error (context,
+                                          brush->ctx->page->priv->source,
+                                          G_MARKUP_ERROR_MISSING_ATTRIBUTE,
+                                          element_name,
+                                          !has_color ? "Color" : "Offset",
+                                          NULL, error);
+                        return;
+                }
+
+                cairo_pattern_add_color_stop_rgba (brush->pattern, offset,
+                                                   color.red,
+                                                   color.green,
+                                                   color.blue,
+                                                   color.alpha * brush->opacity);
+        }
+}
+
+static GMarkupParser brush_gradient_parser = {
+        brush_gradient_start_element,
+        NULL,
+        NULL,
+        NULL
+};
+
+static gboolean
+gxps_box_parse (const gchar       *box,
+                cairo_rectangle_t *rect)
+{
+        gchar **tokens;
+        gdouble b[4];
+        guint   i;
+
+        tokens = g_strsplit (box, ",", 4);
+        if (g_strv_length (tokens) != 4) {
+                g_strfreev (tokens);
+
+                return FALSE;
+        }
+
+        for (i = 0; i < 4; i++) {
+                if (!gxps_value_get_double (tokens[i], &b[i])) {
+                        g_strfreev (tokens);
+
+                        return FALSE;
+                }
+        }
+
+        rect->x = b[0];
+        rect->y = b[1];
+        rect->width = b[2];
+        rect->height = b[3];
+
+        g_strfreev (tokens);
+
+        return TRUE;
+}
+
+static void
+brush_start_element (GMarkupParseContext  *context,
+                     const gchar          *element_name,
+                     const gchar         **names,
+                     const gchar         **values,
+                     gpointer              user_data,
+                     GError              **error)
+{
+        GXPSBrush *brush = (GXPSBrush *)user_data;
+
+        if (strcmp (element_name, "SolidColorBrush") == 0) {
+                const gchar *color_str = NULL;
+                gint i;
+
+                for (i = 0; names[i] != NULL; i++) {
+                        if (strcmp (names[i], "Color") == 0) {
+                                color_str = values[i];
+                        } else if (strcmp (names[i], "Opacity") == 0) {
+                                if (!gxps_value_get_double (values[i], &brush->opacity)) {
+                                        gxps_parse_error (context,
+                                                          brush->ctx->page->priv->source,
+                                                          G_MARKUP_ERROR_INVALID_CONTENT,
+                                                          "SolidColorBrush", "Opacity",
+                                                          values[i], error);
+                                        return;
+                                }
+                        } else {
+                                gxps_parse_error (context,
+                                                  brush->ctx->page->priv->source,
+                                                  G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE,
+                                                  "SolidColorBrush", names[i],
+                                                  NULL, error);
+                                return;
+                        }
+                }
+
+                if (!color_str) {
+                        gxps_parse_error (context,
+                                          brush->ctx->page->priv->source,
+                                          G_MARKUP_ERROR_MISSING_ATTRIBUTE,
+                                          "SolidColorBrush", "Color",
+                                          NULL, error);
+                        return;
+                }
+
+                GXPS_DEBUG (g_message ("set_fill_pattern (solid)"));
+                if (!gxps_brush_solid_color_parse (color_str, brush->ctx->page->priv->zip,
+                                                   brush->opacity, &brush->pattern)) {
+                        gxps_parse_error (context,
+                                          brush->ctx->page->priv->source,
+                                          G_MARKUP_ERROR_INVALID_CONTENT,
+                                          "SolidColorBrush", "Color",
+                                          color_str, error);
+                        return;
+                }
+        } else if (strcmp (element_name, "ImageBrush") == 0) {
+                GXPSBrushImage *image;
+                gchar *image_source = NULL;
+                cairo_rectangle_t viewport, viewbox;
+                cairo_matrix_t matrix;
+                cairo_extend_t extend = CAIRO_EXTEND_NONE;
+                gint i;
+
+                cairo_matrix_init_identity (&matrix);
+
+                for (i = 0; names[i] != NULL; i++) {
+                        if (strcmp (names[i], "ImageSource") == 0) {
+                                image_source = gxps_resolve_relative_path (brush->ctx->page->priv->source,
+                                                                           values[i]);
+                        } else if (strcmp (names[i], "Transform") == 0) {
+                                if (!gxps_matrix_parse (values[i], &matrix)) {
+                                        gxps_parse_error (context,
+                                                          brush->ctx->page->priv->source,
+                                                          G_MARKUP_ERROR_INVALID_CONTENT,
+                                                          "ImageBrush", "Transform",
+                                                          values[i], error);
+                                        return;
+                                }
+                        } else if (strcmp (names[i], "Viewport") == 0) {
+                                if (!gxps_box_parse (values[i], &viewport)) {
+                                        gxps_parse_error (context,
+                                                          brush->ctx->page->priv->source,
+                                                          G_MARKUP_ERROR_INVALID_CONTENT,
+                                                          "ImageBrush", "Viewport",
+                                                          values[i], error);
+                                        return;
+                                }
+                        } else if (strcmp (names[i], "ViewportUnits") == 0) {
+                        } else if (strcmp (names[i], "Viewbox") == 0) {
+                                if (!gxps_box_parse (values[i], &viewbox)) {
+                                        gxps_parse_error (context,
+                                                          brush->ctx->page->priv->source,
+                                                          G_MARKUP_ERROR_INVALID_CONTENT,
+                                                          "ImageBrush", "Viewbox",
+                                                          values[i], error);
+                                        return;
+                                }
+                        } else if (strcmp (names[i], "ViewboxUnits") == 0) {
+                        } else if (strcmp (names[i], "TileMode") == 0) {
+                                extend = gxps_tile_mode_parse (values[i]);
+                        } else if (strcmp (names[i], "Opacity") == 0) {
+                                if (!gxps_value_get_double (values[i], &brush->opacity)) {
+                                        gxps_parse_error (context,
+                                                          brush->ctx->page->priv->source,
+                                                          G_MARKUP_ERROR_INVALID_CONTENT,
+                                                          "ImageBrush", "Opacity",
+                                                          values[i], error);
+                                        return;
+                                }
+                        } else  {
+                                gxps_parse_error (context,
+                                                  brush->ctx->page->priv->source,
+                                                  G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE,
+                                                  "ImageBrush", names[i],
+                                                  NULL, error);
+                                return;
+                        }
+
+                }
+
+                if (!image_source) {
+                        gxps_parse_error (context,
+                                          brush->ctx->page->priv->source,
+                                          G_MARKUP_ERROR_MISSING_ATTRIBUTE,
+                                          element_name, "ImageSource",
+                                          NULL, error);
+                        return;
+                }
+
+                /* GXPSBrushImage takes ownership of image_source */
+                image = gxps_brush_image_new (brush, image_source, &viewport, &viewbox);
+                image->extend = extend;
+                image->matrix = matrix;
+                g_markup_parse_context_push (context, &brush_image_parser, image);
+        } else if (strcmp (element_name, "LinearGradientBrush") == 0) {
+                gint           i;
+                gdouble        x0, y0, x1, y1;
+                cairo_extend_t extend = CAIRO_EXTEND_PAD;
+                cairo_matrix_t matrix;
+
+                x0 = y0 = x1 = y1 = -1;
+                cairo_matrix_init_identity (&matrix);
+
+                for (i = 0; names[i] != NULL; i++) {
+                        if (strcmp (names[i], "MappingMode") == 0) {
+                        } else if (strcmp (names[i], "StartPoint") == 0) {
+                                if (!gxps_point_parse (values[i], &x0, &y0)) {
+                                        gxps_parse_error (context,
+                                                          brush->ctx->page->priv->source,
+                                                          G_MARKUP_ERROR_INVALID_CONTENT,
+                                                          "LinearGradientBrush", "StartPoint",
+                                                          values[i], error);
+                                        return;
+                                }
+                        } else if (strcmp (names[i], "EndPoint") == 0) {
+                                if (!gxps_point_parse (values[i], &x1, &y1)) {
+                                        gxps_parse_error (context,
+                                                          brush->ctx->page->priv->source,
+                                                          G_MARKUP_ERROR_INVALID_CONTENT,
+                                                          "LinearGradientBrush", "EndPoint",
+                                                          values[i], error);
+                                        return;
+                                }
+                        } else if (strcmp (names[i], "SpreadMethod") == 0) {
+                                extend = gxps_spread_method_parse (values[i]);
+                        } else if (strcmp (names[i], "Opacity") == 0) {
+                                if (!gxps_value_get_double (values[i], &brush->opacity)) {
+                                        gxps_parse_error (context,
+                                                          brush->ctx->page->priv->source,
+                                                          G_MARKUP_ERROR_INVALID_CONTENT,
+                                                          "LinearGradientBrush", "Opacity",
+                                                          values[i], error);
+                                        return;
+                                }
+                        } else if (strcmp (names[i], "Transform") == 0) {
+                                if (!gxps_matrix_parse (values[i], &matrix)) {
+                                        gxps_parse_error (context,
+                                                          brush->ctx->page->priv->source,
+                                                          G_MARKUP_ERROR_INVALID_CONTENT,
+                                                          "LinearGradientBrush", "Transform",
+                                                          values[i], error);
+                                        return;
+                                }
+                        } else if (strcmp (names[i], "ColorInterpolationMode") == 0) {
+                                GXPS_DEBUG (g_debug ("Unsupported %s attribute: ColorInterpolationMode", element_name));
+                        } else {
+                                gxps_parse_error (context,
+                                                  brush->ctx->page->priv->source,
+                                                  G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE,
+                                                  element_name, names[i],
+                                                  NULL, error);
+                                return;
+                        }
+                }
+
+                if (x0 == -1 || y0 == -1 || x1 == -1 || y1 == -1) {
+                        gxps_parse_error (context,
+                                          brush->ctx->page->priv->source,
+                                          G_MARKUP_ERROR_MISSING_ATTRIBUTE,
+                                          element_name,
+                                          (x0 == -1 || y0 == -1) ? "StartPoint" : "EndPoint",
+                                          NULL, error);
+                        return;
+                }
+
+                GXPS_DEBUG (g_message ("set_fill_pattern (linear)"));
+                brush->pattern = cairo_pattern_create_linear (x0, y0, x1, y1);
+                cairo_pattern_set_matrix (brush->pattern, &matrix);
+                cairo_pattern_set_extend (brush->pattern, extend);
+                g_markup_parse_context_push (context, &brush_gradient_parser, brush);
+        } else if (strcmp (element_name, "RadialGradientBrush") == 0) {
+                gint           i;
+                gdouble        cx0, cy0, r0, cx1, cy1, r1;
+                cairo_extend_t extend = CAIRO_EXTEND_PAD;
+                cairo_matrix_t matrix;
+
+                cx0 = cy0 = r0 = cx1 = cy1 = r1 = -1;
+
+                cairo_matrix_init_identity (&matrix);
+
+                for (i = 0; names[i] != NULL; i++) {
+                        if (strcmp (names[i], "MappingMode") == 0) {
+                        } else if (strcmp (names[i], "GradientOrigin") == 0) {
+                                if (!gxps_point_parse (values[i], &cx0, &cy0)) {
+                                        gxps_parse_error (context,
+                                                          brush->ctx->page->priv->source,
+                                                          G_MARKUP_ERROR_INVALID_CONTENT,
+                                                          "RadialGradientBrush", "GradientOrigin",
+                                                          values[i], error);
+                                        return;
+                                }
+                        } else if (strcmp (names[i], "Center") == 0) {
+                                if (!gxps_point_parse (values[i], &cx1, &cy1)) {
+                                        gxps_parse_error (context,
+                                                          brush->ctx->page->priv->source,
+                                                          G_MARKUP_ERROR_INVALID_CONTENT,
+                                                          "RadialGradientBrush", "Center",
+                                                          values[i], error);
+                                        return;
+                                }
+                        } else if (strcmp (names[i], "RadiusX") == 0) {
+                                if (!gxps_value_get_double (values[i], &r0)) {
+                                        gxps_parse_error (context,
+                                                          brush->ctx->page->priv->source,
+                                                          G_MARKUP_ERROR_INVALID_CONTENT,
+                                                          "RadialGradientBrush", "RadiusX",
+                                                          values[i], error);
+                                        return;
+                                }
+                        } else if (strcmp (names[i], "RadiusY") == 0) {
+                                if (!gxps_value_get_double (values[i], &r1)) {
+                                        gxps_parse_error (context,
+                                                          brush->ctx->page->priv->source,
+                                                          G_MARKUP_ERROR_INVALID_CONTENT,
+                                                          "RadialGradientBrush", "RadiusY",
+                                                          values[i], error);
+                                        return;
+                                }
+                        } else if (strcmp (names[i], "SpreadMethod") == 0) {
+                                extend = gxps_spread_method_parse (values[i]);
+                        } else if (strcmp (names[i], "Opacity") == 0) {
+                                if (!gxps_value_get_double (values[i], &brush->opacity)) {
+                                        gxps_parse_error (context,
+                                                          brush->ctx->page->priv->source,
+                                                          G_MARKUP_ERROR_INVALID_CONTENT,
+                                                          "RadialGradientBrush", "Opacity",
+                                                          values[i], error);
+                                        return;
+                                }
+                        } else if (strcmp (names[i], "Transform") == 0) {
+                                if (!gxps_matrix_parse (values[i], &matrix)) {
+                                        gxps_parse_error (context,
+                                                          brush->ctx->page->priv->source,
+                                                          G_MARKUP_ERROR_INVALID_CONTENT,
+                                                          "RadialGradientBrush", "Transform",
+                                                          values[i], error);
+                                        return;
+                                }
+                        } else if (strcmp (names[i], "ColorInterpolationMode") == 0) {
+                                GXPS_DEBUG (g_debug ("Unsupported %s attribute: ColorInterpolationMode", element_name));
+                        } else {
+                                gxps_parse_error (context,
+                                                  brush->ctx->page->priv->source,
+                                                  G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE,
+                                                  element_name, names[i],
+                                                  NULL, error);
+                                return;
+                        }
+                }
+
+                if (cx0 == -1 || cy0 == -1 || cx1 == -1 || cy1 == -1) {
+                        gxps_parse_error (context,
+                                          brush->ctx->page->priv->source,
+                                          G_MARKUP_ERROR_MISSING_ATTRIBUTE,
+                                          element_name,
+                                          (cx0 == -1 || cy0 == -1) ? "GradientOrigin" : "Center",
+                                          NULL, error);
+                        return;
+                }
+                if (r0 == -1 || r1 == -1) {
+                        gxps_parse_error (context,
+                                          brush->ctx->page->priv->source,
+                                          G_MARKUP_ERROR_MISSING_ATTRIBUTE,
+                                          element_name,
+                                          (r0 == -1) ? "RadiusX" : "RadiusY",
+                                          NULL, error);
+                        return;
+                }
+
+                GXPS_DEBUG (g_message ("set_fill_pattern (radial)"));
+                brush->pattern = cairo_pattern_create_radial (cx0, cy0, 0, cx1, cy1, r1);
+                cairo_pattern_set_matrix (brush->pattern, &matrix);
+                cairo_pattern_set_extend (brush->pattern, extend);
+                g_markup_parse_context_push (context, &brush_gradient_parser, brush);
+        } else if (strcmp (element_name, "VisualBrush") == 0) {
+                GXPSBrushVisual *visual;
+                GXPSRenderContext *sub_ctx;
+                cairo_rectangle_t viewport, viewbox;
+                cairo_matrix_t matrix;
+                cairo_extend_t extend = CAIRO_EXTEND_NONE;
+                gint i;
+
+                cairo_matrix_init_identity (&matrix);
+
+                for (i = 0; names[i] != NULL; i++) {
+                        if (strcmp (names[i], "TileMode") == 0) {
+                                extend = gxps_tile_mode_parse (values[i]);
+                        } else if (strcmp (names[i], "Transform") == 0) {
+                                if (!gxps_matrix_parse (values[i], &matrix)) {
+                                        gxps_parse_error (context,
+                                                          brush->ctx->page->priv->source,
+                                                          G_MARKUP_ERROR_INVALID_CONTENT,
+                                                          "VisualBrush", "Transform",
+                                                          values[i], error);
+                                        return;
+                                }
+                        } else if (strcmp (names[i], "Viewport") == 0) {
+                                if (!gxps_box_parse (values[i], &viewport)) {
+                                        gxps_parse_error (context,
+                                                          brush->ctx->page->priv->source,
+                                                          G_MARKUP_ERROR_INVALID_CONTENT,
+                                                          "VisualBrush", "Viewport",
+                                                          values[i], error);
+                                        return;
+                                }
+                        } else if (strcmp (names[i], "ViewportUnits") == 0) {
+                        } else if (strcmp (names[i], "Viewbox") == 0) {
+                                if (!gxps_box_parse (values[i], &viewbox)) {
+                                        gxps_parse_error (context,
+                                                          brush->ctx->page->priv->source,
+                                                          G_MARKUP_ERROR_INVALID_CONTENT,
+                                                          "VisualBrush", "Viewbox",
+                                                          values[i], error);
+                                        return;
+                                }
+                        } else if (strcmp (names[i], "ViewboxUnits") == 0) {
+                        } else if (strcmp (names[i], "Opacity") == 0) {
+                                GXPS_DEBUG (g_debug ("Unsupported %s attribute: Opacity", element_name));
+                        } else if (strcmp (names[i], "Visual") == 0) {
+                                GXPS_DEBUG (g_debug ("Unsupported %s attribute: Visual", element_name));
+                        } else {
+                                gxps_parse_error (context,
+                                                  brush->ctx->page->priv->source,
+                                                  G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE,
+                                                  element_name, names[i],
+                                                  NULL, error);
+                                return;
+                        }
+                }
+
+                /* TODO: check required values */
+
+                /* Clip to viewport so that push group
+                 * will create a surface with the viport size
+                 */
+                cairo_save (brush->ctx->cr);
+                cairo_rectangle (brush->ctx->cr, viewbox.x, viewbox.y, viewbox.width, viewbox.height);
+                cairo_clip (brush->ctx->cr);
+                cairo_push_group (brush->ctx->cr);
+                visual = gxps_brush_visual_new (brush, &viewport, &viewbox);
+                visual->extend = extend;
+                sub_ctx = g_slice_new0 (GXPSRenderContext);
+                sub_ctx->page = brush->ctx->page;
+                sub_ctx->cr = brush->ctx->cr;
+                sub_ctx->visual = visual;
+                gxps_page_render_parser_push (context, sub_ctx);
+        } else {
+                gxps_parse_error (context,
+                                  brush->ctx->page->priv->source,
+                                  G_MARKUP_ERROR_UNKNOWN_ELEMENT,
+                                  element_name, NULL, NULL, error);
+        }
+}
+
+static void
+brush_end_element (GMarkupParseContext  *context,
+                   const gchar          *element_name,
+                   gpointer              user_data,
+                   GError              **error)
+{
+        GXPSBrush *brush = (GXPSBrush *)user_data;
+
+        if (strcmp (element_name, "SolidColorBrush") == 0) {
+        } else if (strcmp (element_name, "LinearGradientBrush") == 0) {
+                g_markup_parse_context_pop (context);
+        } else if (strcmp (element_name, "RadialGradientBrush") == 0) {
+                g_markup_parse_context_pop (context);
+        } else if (strcmp (element_name, "ImageBrush") == 0) {
+                GXPSBrushImage  *image;
+                cairo_surface_t *surface;
+                GError          *err = NULL;
+
+                image = g_markup_parse_context_pop (context);
+
+                GXPS_DEBUG (g_message ("set_fill_pattern (image)"));
+                surface = gxps_page_get_image (brush->ctx->page, image->image_uri, &err);
+                if (surface) {
+                        cairo_matrix_t matrix, port_matrix;
+                        gdouble        x_scale, y_scale;
+
+                        image->brush->pattern = cairo_pattern_create_for_surface (surface);
+                        cairo_pattern_set_extend (image->brush->pattern, image->extend);
+                        cairo_surface_destroy (surface);
+
+                        cairo_matrix_init (&port_matrix,
+                                           image->viewport.width,
+                                           0, 0,
+                                           image->viewport.height,
+                                           image->viewport.x,
+                                           image->viewport.y);
+                        cairo_matrix_multiply (&port_matrix, &port_matrix, &image->matrix);
+
+                        x_scale = image->viewbox.width / port_matrix.xx;
+                        y_scale = image->viewbox.height / port_matrix.yy;
+                        cairo_matrix_init (&matrix, x_scale, 0, 0, y_scale,
+                                           -port_matrix.x0 * x_scale,
+                                           -port_matrix.y0 * y_scale);
+                        cairo_pattern_set_matrix (image->brush->pattern, &matrix);
+
+                        if (brush->opacity != 1.0) {
+                                cairo_push_group (brush->ctx->cr);
+                                cairo_set_source (brush->ctx->cr, image->brush->pattern);
+                                cairo_pattern_destroy (image->brush->pattern);
+                                cairo_paint_with_alpha (brush->ctx->cr, brush->opacity);
+                                image->brush->pattern = cairo_pop_group (brush->ctx->cr);
+                        }
+
+                        if (cairo_pattern_status (image->brush->pattern)) {
+                                GXPS_DEBUG (g_debug ("%s", cairo_status_to_string (cairo_pattern_status (image->brush->pattern))));
+                                cairo_pattern_destroy (image->brush->pattern);
+                                image->brush->pattern = NULL;
+                        }
+                } else if (err) {
+                        GXPS_DEBUG (g_debug ("%s", err->message));
+                        g_error_free (err);
+                }
+                gxps_brush_image_free (image);
+        } else if (strcmp (element_name, "VisualBrush") == 0) {
+                GXPSRenderContext *sub_ctx;
+                GXPSBrushVisual   *visual;
+                cairo_matrix_t     matrix, port_matrix;
+                gdouble            x_scale, y_scale;
+
+                sub_ctx = g_markup_parse_context_pop (context);
+                visual = sub_ctx->visual;
+                g_slice_free (GXPSRenderContext, sub_ctx);
+
+                GXPS_DEBUG (g_message ("set_fill_pattern (visual)"));
+                visual->brush->pattern = cairo_pop_group (brush->ctx->cr);
+                /* Undo the clip */
+                cairo_restore (brush->ctx->cr);
+                cairo_pattern_set_extend (visual->brush->pattern, visual->extend);
+                cairo_matrix_init (&port_matrix,
+                                   visual->viewport.width,
+                                   0, 0,
+                                   visual->viewport.height,
+                                   visual->viewport.x,
+                                   visual->viewport.y);
+                cairo_matrix_multiply (&port_matrix, &port_matrix, &visual->matrix);
+
+                x_scale = visual->viewbox.width / port_matrix.xx;
+                y_scale = visual->viewbox.height / port_matrix.yy;
+                cairo_matrix_init (&matrix, x_scale, 0, 0, y_scale,
+                                   -port_matrix.x0 * x_scale,
+                                   -port_matrix.y0 * y_scale);
+
+                cairo_pattern_set_matrix (visual->brush->pattern, &matrix);
+                if (cairo_pattern_status (visual->brush->pattern)) {
+                        GXPS_DEBUG (g_debug ("%s", cairo_status_to_string (cairo_pattern_status (visual->brush->pattern))));
+                        cairo_pattern_destroy (visual->brush->pattern);
+                        visual->brush->pattern = NULL;
+                }
+
+                gxps_brush_visual_free (visual);
+        } else {
+                gxps_parse_error (context,
+                                  brush->ctx->page->priv->source,
+                                  G_MARKUP_ERROR_UNKNOWN_ELEMENT,
+                                  element_name, NULL, NULL, error);
+
+        }
+}
+
+static GMarkupParser brush_parser = {
+        brush_start_element,
+        brush_end_element,
+        NULL,
+        NULL
+};
+
+void
+gxps_brush_parser_push (GMarkupParseContext *context,
+                        GXPSBrush           *brush)
+{
+        g_markup_parse_context_push (context, &brush_parser, brush);
+}
diff --git a/libgxps/gxps-brush.h b/libgxps/gxps-brush.h
new file mode 100644
index 0000000..be3d3ff
--- /dev/null
+++ b/libgxps/gxps-brush.h
@@ -0,0 +1,47 @@
+/* GXPSBrush
+ *
+ * Copyright (C) 2011  Carlos Garcia Campos <carlosgc 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 St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef __GXPS_BRUSH_H__
+#define __GXPS_BRUSH_H__
+
+#include <cairo.h>
+#include "gxps-page-private.h"
+
+G_BEGIN_DECLS
+
+typedef struct _GXPSBrush GXPSBrush;
+
+struct _GXPSBrush {
+        GXPSRenderContext *ctx;
+        cairo_pattern_t   *pattern;
+        gdouble            opacity;
+};
+
+GXPSBrush *gxps_brush_new               (GXPSRenderContext   *ctx);
+void       gxps_brush_free              (GXPSBrush           *brush);
+gboolean   gxps_brush_solid_color_parse (const gchar         *data,
+                                         GXPSArchive         *zip,
+                                         gdouble              alpha,
+                                         cairo_pattern_t    **pattern);
+void       gxps_brush_parser_push       (GMarkupParseContext *context,
+                                         GXPSBrush           *brush);
+
+G_END_DECLS
+
+#endif /* __GXPS_BRUSH_H__ */
diff --git a/libgxps/gxps-page.c b/libgxps/gxps-page.c
index 9de1af6..b870f2a 100644
--- a/libgxps/gxps-page.c
+++ b/libgxps/gxps-page.c
@@ -24,6 +24,7 @@
 
 #include "gxps-page-private.h"
 #include "gxps-matrix.h"
+#include "gxps-brush.h"
 #include "gxps-fonts.h"
 #include "gxps-links.h"
 #include "gxps-images.h"
@@ -745,222 +746,6 @@ path_data_parse (const gchar *data,
 }
 
 static gboolean
-hex (const gchar *spec,
-     gint         len,
-     guint       *c)
-{
-	const gchar *end;
-
-	*c = 0;
-	for (end = spec + len; spec != end; spec++) {
-		if (!g_ascii_isxdigit (*spec))
-			return FALSE;
-
-		*c = (*c << 4) | g_ascii_xdigit_value (*spec);
-	}
-
-	return TRUE;
-}
-
-static gboolean
-gxps_color_s_rgb_parse (const gchar *color_str,
-                        GXPSColor   *color)
-{
-        gsize len = strlen (color_str);
-        guint a = 255;
-        guint r, g, b;
-
-        switch (len) {
-	case 6:
-		if (!hex (color_str, 2, &r) ||
-		    !hex (color_str + 2, 2, &g) ||
-		    !hex (color_str + 4, 2, &b))
-			return FALSE;
-		break;
-	case 8:
-		if (!hex (color_str, 2, &a) ||
-		    !hex (color_str + 2, 2, &r) ||
-		    !hex (color_str + 4, 2, &g) ||
-		    !hex (color_str + 6, 2, &b))
-			return FALSE;
-		break;
-	default:
-		return FALSE;
-	}
-
-        color->alpha = a / 255.;
-        color->red = r / 255.;
-        color->green = g / 255.;
-        color->blue = b / 255.;
-
-        return TRUE;
-}
-
-static gboolean
-gxps_color_sc_rgb_parse (const gchar *color_str,
-                         GXPSColor   *color)
-{
-        gchar **tokens;
-        gsize   len;
-        gdouble c[4];
-        guint   i, start;
-
-        tokens = g_strsplit (color_str, ",", 4);
-        len = g_strv_length (tokens);
-
-        switch (len) {
-        case 4:
-                if (!gxps_value_get_double (tokens[0], &c[0])) {
-                        g_strfreev (tokens);
-
-                        return FALSE;
-                }
-                start = 1;
-
-                break;
-        case 3:
-                c[0] = 1.0;
-                start = 0;
-                break;
-        default:
-                g_strfreev (tokens);
-                return FALSE;
-        }
-
-        for (i = start; i < len; i++) {
-                if (!gxps_value_get_double (tokens[i], &c[i])) {
-                        g_strfreev (tokens);
-
-                        return FALSE;
-                }
-        }
-
-        g_strfreev (tokens);
-
-        color->alpha = CLAMP (c[0], 0., 1.);
-        color->red = CLAMP (c[1], 0., 1.);
-        color->green = CLAMP (c[2], 0., 1.);
-        color->blue = CLAMP (c[3], 0., 1.);
-
-        return TRUE;
-}
-
-static gboolean
-gxps_color_icc_parse (const gchar *color_str,
-                      GXPSArchive *zip,
-                      GXPSColor   *color)
-{
-        const gchar *p;
-        gchar       *icc_profile_uri;
-        gchar      **tokens;
-        gsize        len;
-        gdouble      alpha;
-        gdouble      values[GXPS_COLOR_MAX_CHANNELS];
-        guint        i, j;
-        gboolean     retval;
-
-        p = strstr (color_str, " ");
-        if (!p)
-                return FALSE;
-
-        icc_profile_uri = g_strndup (color_str, strlen (color_str) - strlen (p));
-
-        tokens = g_strsplit (++p, ",", -1);
-        len = g_strv_length (tokens);
-        if (len < 2) {
-                g_strfreev (tokens);
-                g_free (icc_profile_uri);
-
-                return FALSE;
-        }
-
-        if (!gxps_value_get_double (tokens[0], &alpha)) {
-                g_strfreev (tokens);
-                g_free (icc_profile_uri);
-
-                return FALSE;
-        }
-
-        for (i = 0, j = 1; i < GXPS_COLOR_MAX_CHANNELS && j < len; i++, j++) {
-                if (!gxps_value_get_double (tokens[j], &values[i])) {
-                        g_strfreev (tokens);
-                        g_free (icc_profile_uri);
-
-                        return FALSE;
-                }
-        }
-
-        g_strfreev (tokens);
-
-        color->alpha = CLAMP (alpha, 0., 1.);
-        retval = gxps_color_new_for_icc (zip, icc_profile_uri, values, i, color);
-        g_free (icc_profile_uri);
-
-        return retval;
-}
-
-static gboolean
-gxps_color_parse (const gchar *color_str,
-                  GXPSArchive *zip,
-                  GXPSColor   *color)
-{
-        const gchar *p;
-
-        p = strstr (color_str, "#");
-        if (!p) {
-                p = strstr (color_str, "ContextColor");
-                if (p == color_str) {
-                        p += strlen ("ContextColor");
-                        return gxps_color_icc_parse (++p, zip, color);
-                }
-                GXPS_DEBUG (g_debug ("Unsupported color %s", color_str));
-
-                return FALSE;
-        }
-
-        if (p == color_str)
-                return gxps_color_s_rgb_parse (++p, color);
-
-        if (strncmp (color_str, "sc", 2) == 0 && p == color_str + 2)
-                return gxps_color_sc_rgb_parse (++p, color);
-
-        GXPS_DEBUG (g_debug ("Unsupported color %s", color_str));
-
-        return FALSE;
-}
-
-static cairo_pattern_t *
-gxps_create_solid_color_pattern_with_alpha (GXPSArchive *zip,
-                                            const gchar *color_str,
-                                            gdouble      alpha)
-{
-	cairo_pattern_t *pattern;
-        GXPSColor        color;
-
-	if (!gxps_color_parse (color_str, zip, &color))
-		return NULL;
-
-	pattern = cairo_pattern_create_rgba (color.red,
-                                             color.green,
-                                             color.blue,
-                                             color.alpha * alpha);
-	if (cairo_pattern_status (pattern)) {
-		cairo_pattern_destroy (pattern);
-
-		return NULL;
-	}
-
-	return pattern;
-}
-
-static cairo_pattern_t *
-gxps_create_solid_color_pattern (GXPSArchive *zip,
-                                 const gchar *color_str)
-{
-	return gxps_create_solid_color_pattern_with_alpha (zip, color_str, 1.0);
-}
-
-static gboolean
 gxps_boolean_parse (const gchar *value)
 {
 	return (strcmp (value, "true") == 0);
@@ -1038,39 +823,6 @@ gxps_fill_rule_parse (const gchar *rule)
 }
 
 static gboolean
-gxps_box_parse (const gchar       *box,
-		cairo_rectangle_t *rect)
-{
-	gchar **tokens;
-        gdouble b[4];
-        guint   i;
-
-	tokens = g_strsplit (box, ",", 4);
-	if (g_strv_length (tokens) != 4) {
-		g_strfreev (tokens);
-
-		return FALSE;
-	}
-
-        for (i = 0; i < 4; i++) {
-                if (!gxps_value_get_double (tokens[i], &b[i])) {
-                        g_strfreev (tokens);
-
-                        return FALSE;
-                }
-        }
-
-	rect->x = b[0];
-	rect->y = b[1];
-	rect->width = b[2];
-	rect->height = b[3];
-
-	g_strfreev (tokens);
-
-	return TRUE;
-}
-
-static gboolean
 gxps_points_parse (const gchar *points,
 		   gdouble    **coords,
 		   guint       *n_points)
@@ -1115,701 +867,6 @@ gxps_points_parse (const gchar *points,
 	return retval;
 }
 
-static cairo_extend_t
-gxps_spread_method_parse (const gchar *spread)
-{
-	if (strcmp (spread, "Pad") == 0)
-		return CAIRO_EXTEND_PAD;
-	else if (strcmp (spread, "Reflect") == 0)
-		return CAIRO_EXTEND_REFLECT;
-	else if (strcmp (spread, "Repeat") == 0)
-		return CAIRO_EXTEND_REPEAT;
-	return CAIRO_EXTEND_NONE;
-}
-
-static cairo_extend_t
-gxps_tile_mode_parse (const gchar *tile)
-{
-	if (strcmp (tile, "Tile") == 0)
-		return CAIRO_EXTEND_REPEAT;
-	else if (strcmp (tile, "FlipX") == 0)
-		GXPS_DEBUG (g_debug ("Unsupported tile mode FlipX"));
-	else if (strcmp (tile, "FlipY") == 0)
-		GXPS_DEBUG (g_debug ("Unsupported tile mode FlipY"));
-	else if (strcmp (tile, "FlipXY") == 0)
-		GXPS_DEBUG (g_debug ("Unsupported tile mode FlipXY"));
-
-	return CAIRO_EXTEND_NONE;
-}
-
-typedef struct {
-	GXPSRenderContext *ctx;
-	cairo_pattern_t   *pattern;
-	gdouble            opacity;
-} GXPSBrush;
-
-static GXPSBrush *
-gxps_brush_new (GXPSRenderContext *ctx)
-{
-	GXPSBrush *brush;
-
-	brush = g_slice_new0 (GXPSBrush);
-	brush->ctx = ctx;
-	brush->opacity = 1.0;
-
-	return brush;
-}
-
-static void
-gxps_brush_free (GXPSBrush *brush)
-{
-	if (G_UNLIKELY (!brush))
-		return;
-
-	cairo_pattern_destroy (brush->pattern);
-	g_slice_free (GXPSBrush, brush);
-}
-
-typedef struct {
-	GXPSBrush        *brush;
-
-	gchar            *image_uri;
-	cairo_matrix_t    matrix;
-	cairo_rectangle_t viewport;
-	cairo_rectangle_t viewbox;
-	cairo_extend_t    extend;
-} GXPSBrushImage;
-
-static GXPSBrushImage *
-gxps_brush_image_new (GXPSBrush         *brush,
-		      gchar             *image_uri,
-		      cairo_rectangle_t *viewport,
-		      cairo_rectangle_t *viewbox)
-{
-	GXPSBrushImage *image;
-
-	image = g_slice_new0 (GXPSBrushImage);
-	image->brush = brush;
-
-	cairo_matrix_init_identity (&image->matrix);
-
-	/* Required values */
-	image->image_uri = image_uri;
-	image->viewport = *viewport;
-	image->viewbox = *viewbox;
-
-	return image;
-}
-
-static void
-gxps_brush_image_free (GXPSBrushImage *image)
-{
-	if (G_UNLIKELY (!image))
-		return;
-
-	g_free (image->image_uri);
-
-	g_slice_free (GXPSBrushImage, image);
-}
-
-static void
-brush_image_start_element (GMarkupParseContext  *context,
-			   const gchar          *element_name,
-			   const gchar         **names,
-			   const gchar         **values,
-			   gpointer              user_data,
-			   GError              **error)
-{
-	GXPSBrushImage *image = (GXPSBrushImage *)user_data;
-
-	if (strcmp (element_name, "ImageBrush.Transform") == 0) {
-		GXPSMatrix *matrix;
-
-		matrix = gxps_matrix_new (image->brush->ctx);
-                gxps_matrix_parser_push (context, matrix);
-	} else {
-		gxps_parse_error (context,
-				  image->brush->ctx->page->priv->source,
-				  G_MARKUP_ERROR_UNKNOWN_ELEMENT,
-				  element_name, NULL, NULL, error);
-	}
-}
-
-static void
-brush_image_end_element (GMarkupParseContext  *context,
-			 const gchar          *element_name,
-			 gpointer              user_data,
-			 GError              **error)
-{
-	GXPSBrushImage *image = (GXPSBrushImage *)user_data;
-
-	if (strcmp (element_name, "ImageBrush.Transform") == 0) {
-		GXPSMatrix *matrix;
-
-		matrix = g_markup_parse_context_pop (context);
-		image->matrix = matrix->matrix;
-		gxps_matrix_free (matrix);
-	} else {
-		gxps_parse_error (context,
-				  image->brush->ctx->page->priv->source,
-				  G_MARKUP_ERROR_UNKNOWN_ELEMENT,
-				  element_name, NULL, NULL, error);
-	}
-}
-
-static GMarkupParser brush_image_parser = {
-	brush_image_start_element,
-	brush_image_end_element,
-	NULL,
-	NULL
-};
-
-struct _GXPSBrushVisual {
-	GXPSBrush        *brush;
-
-	cairo_matrix_t    matrix;
-	cairo_rectangle_t viewport;
-	cairo_rectangle_t viewbox;
-	cairo_extend_t    extend;
-};
-
-static GXPSBrushVisual *
-gxps_brush_visual_new (GXPSBrush         *brush,
-		      cairo_rectangle_t *viewport,
-		      cairo_rectangle_t *viewbox)
-{
-	GXPSBrushVisual *visual;
-
-	visual = g_slice_new0 (GXPSBrushVisual);
-	visual->brush = brush;
-
-	/* Default */
-	visual->extend = CAIRO_EXTEND_NONE;
-	cairo_matrix_init_identity (&visual->matrix);
-
-	/* Required values */
-	visual->viewport = *viewport;
-	visual->viewbox = *viewbox;
-
-	return visual;
-}
-
-static void
-gxps_brush_visual_free (GXPSBrushVisual *visual)
-{
-	if (G_UNLIKELY (!visual))
-		return;
-
-	g_slice_free (GXPSBrushVisual, visual);
-}
-
-static void
-brush_gradient_start_element (GMarkupParseContext  *context,
-			      const gchar          *element_name,
-			      const gchar         **names,
-			      const gchar         **values,
-			      gpointer              user_data,
-			      GError              **error)
-{
-	GXPSBrush *brush = (GXPSBrush *)user_data;
-
-	if (strcmp (element_name, "LinearGradientBrush.GradientStops") == 0) {
-	} else if (strcmp (element_name, "RadialGradientBrush.GradientStops") == 0) {
-	} else if (strcmp (element_name, "GradientStop") == 0) {
-		gint      i;
-                GXPSColor color;
-                gboolean  has_color = FALSE;
-		gdouble   offset = -1;
-
-		for (i = 0; names[i] != NULL; i++) {
-			if (strcmp (names[i], "Color") == 0) {
-                                has_color = TRUE;
-				if (!gxps_color_parse (values[i], brush->ctx->page->priv->zip, &color)) {
-					gxps_parse_error (context,
-							  brush->ctx->page->priv->source,
-							  G_MARKUP_ERROR_INVALID_CONTENT,
-							  "GradientStop", "Color",
-							  values[i], error);
-					return;
-				}
-			} else if (strcmp (names[i], "Offset") == 0) {
-                                if (!gxps_value_get_double (values[i], &offset)) {
-                                        gxps_parse_error (context,
-                                                          brush->ctx->page->priv->source,
-                                                          G_MARKUP_ERROR_INVALID_CONTENT,
-                                                          "GradientStop", "Offset",
-                                                          values[i], error);
-                                        return;
-                                }
-			}
-		}
-
-		if (!has_color || offset == -1) {
-			gxps_parse_error (context,
-					  brush->ctx->page->priv->source,
-					  G_MARKUP_ERROR_MISSING_ATTRIBUTE,
-					  element_name,
-					  !has_color ? "Color" : "Offset",
-					  NULL, error);
-			return;
-		}
-
-                cairo_pattern_add_color_stop_rgba (brush->pattern, offset,
-                                                   color.red,
-                                                   color.green,
-                                                   color.blue,
-                                                   color.alpha * brush->opacity);
-	}
-}
-
-static GMarkupParser brush_gradient_parser = {
-	brush_gradient_start_element,
-	NULL,
-	NULL,
-	NULL
-};
-
-static void
-brush_start_element (GMarkupParseContext  *context,
-		     const gchar          *element_name,
-		     const gchar         **names,
-		     const gchar         **values,
-		     gpointer              user_data,
-		     GError              **error)
-{
-	GXPSBrush *brush = (GXPSBrush *)user_data;
-
-	if (strcmp (element_name, "SolidColorBrush") == 0) {
-		const gchar *color_str = NULL;
-		gint i;
-
-		for (i = 0; names[i] != NULL; i++) {
-			if (strcmp (names[i], "Color") == 0) {
-				color_str = values[i];
-			} else if (strcmp (names[i], "Opacity") == 0) {
-				if (!gxps_value_get_double (values[i], &brush->opacity)) {
-					gxps_parse_error (context,
-							  brush->ctx->page->priv->source,
-							  G_MARKUP_ERROR_INVALID_CONTENT,
-                                                          "SolidColorBrush", "Opacity",
-							  values[i], error);
-					return;
-				}
-			} else if (strcmp (names[i], "X:Key") == 0) {
-				/* TODO */
-			}
-		}
-
-                if (!color_str) {
-                        gxps_parse_error (context,
-                                          brush->ctx->page->priv->source,
-                                          G_MARKUP_ERROR_MISSING_ATTRIBUTE,
-                                          "SolidColorBrush", "Color",
-                                          NULL, error);
-                        return;
-                }
-
-                brush->pattern = gxps_create_solid_color_pattern_with_alpha (brush->ctx->page->priv->zip,
-                                                                             color_str, brush->opacity);
-                GXPS_DEBUG (g_message ("set_fill_pattern (solid)"));
-		if (!brush->pattern) {
-			gxps_parse_error (context,
-					  brush->ctx->page->priv->source,
-					  G_MARKUP_ERROR_INVALID_CONTENT,
-                                          "SolidColorBrush", "Color",
-					  color_str, error);
-			return;
-		}
-	} else if (strcmp (element_name, "ImageBrush") == 0) {
-		GXPSBrushImage *image;
-		gchar *image_source = NULL;
-		cairo_rectangle_t viewport, viewbox;
-		cairo_matrix_t matrix;
-		cairo_extend_t extend = CAIRO_EXTEND_NONE;
-		gint i;
-
-		cairo_matrix_init_identity (&matrix);
-
-		for (i = 0; names[i] != NULL; i++) {
-			if (strcmp (names[i], "ImageSource") == 0) {
-				image_source = gxps_resolve_relative_path (brush->ctx->page->priv->source,
-									   values[i]);
-			} else if (strcmp (names[i], "Transform") == 0) {
-				if (!gxps_matrix_parse (values[i], &matrix)) {
-					gxps_parse_error (context,
-							  brush->ctx->page->priv->source,
-							  G_MARKUP_ERROR_INVALID_CONTENT,
-							  "ImageBrush", "Transform",
-							  values[i], error);
-					return;
-				}
-			} else if (strcmp (names[i], "Viewport") == 0) {
-				if (!gxps_box_parse (values[i], &viewport)) {
-					gxps_parse_error (context,
-							  brush->ctx->page->priv->source,
-							  G_MARKUP_ERROR_INVALID_CONTENT,
-							  "ImageBrush", "Viewport",
-							  values[i], error);
-					return;
-				}
-			} else if (strcmp (names[i], "ViewportUnits") == 0) {
-			} else if (strcmp (names[i], "Viewbox") == 0) {
-				if (!gxps_box_parse (values[i], &viewbox)) {
-					gxps_parse_error (context,
-							  brush->ctx->page->priv->source,
-							  G_MARKUP_ERROR_INVALID_CONTENT,
-							  "ImageBrush", "Viewbox",
-							  values[i], error);
-					return;
-				}
-			} else if (strcmp (names[i], "ViewboxUnits") == 0) {
-			} else if (strcmp (names[i], "TileMode") == 0) {
-				extend = gxps_tile_mode_parse (values[i]);
-			} else if (strcmp (names[i], "Opacity") == 0) {
-                                if (!gxps_value_get_double (values[i], &brush->opacity)) {
-                                        gxps_parse_error (context,
-                                                          brush->ctx->page->priv->source,
-                                                          G_MARKUP_ERROR_INVALID_CONTENT,
-                                                          "ImageBrush", "Opacity",
-                                                          values[i], error);
-                                        return;
-                                }
-			} else if (strcmp (names[i], "X:Key") == 0) {
-				/* TODO */
-			}
-
-		}
-
-		if (!image_source) {
-			gxps_parse_error (context,
-					  brush->ctx->page->priv->source,
-					  G_MARKUP_ERROR_MISSING_ATTRIBUTE,
-					  element_name, "ImageSource",
-					  NULL, error);
-			return;
-		}
-
-		/* GXPSBrushImage takes ownership of image_source */
-		image = gxps_brush_image_new (brush, image_source, &viewport, &viewbox);
-		image->extend = extend;
-		image->matrix = matrix;
-		g_markup_parse_context_push (context, &brush_image_parser, image);
-	} else if (strcmp (element_name, "LinearGradientBrush") == 0) {
-		gint           i;
-		gdouble        x0, y0, x1, y1;
-		cairo_extend_t extend = CAIRO_EXTEND_PAD;
-		cairo_matrix_t matrix;
-
-		cairo_matrix_init_identity (&matrix);
-
-		for (i = 0; names[i] != NULL; i++) {
-			if (strcmp (names[i], "MappingMode") == 0) {
-			} else if (strcmp (names[i], "StartPoint") == 0) {
-				if (!gxps_point_parse (values[i], &x0, &y0)) {
-					gxps_parse_error (context,
-							  brush->ctx->page->priv->source,
-							  G_MARKUP_ERROR_INVALID_CONTENT,
-							  "LinearGradientBrush", "StartPoint",
-							  values[i], error);
-					return;
-				}
-			} else if (strcmp (names[i], "EndPoint") == 0) {
-				if (!gxps_point_parse (values[i], &x1, &y1)) {
-					gxps_parse_error (context,
-							  brush->ctx->page->priv->source,
-							  G_MARKUP_ERROR_INVALID_CONTENT,
-							  "LinearGradientBrush", "EndPoint",
-							  values[i], error);
-					return;
-				}
-			} else if (strcmp (names[i], "SpreadMethod") == 0) {
-				extend = gxps_spread_method_parse (values[i]);
-			} else if (strcmp (names[i], "Opacity") == 0) {
-                                if (!gxps_value_get_double (values[i], &brush->opacity)) {
-                                        gxps_parse_error (context,
-                                                          brush->ctx->page->priv->source,
-                                                          G_MARKUP_ERROR_INVALID_CONTENT,
-                                                          "LinearGradientBrush", "Opacity",
-                                                          values[i], error);
-                                        return;
-                                }
-			} else if (strcmp (names[i], "Transform") == 0) {
-				if (!gxps_matrix_parse (values[i], &matrix)) {
-					gxps_parse_error (context,
-							  brush->ctx->page->priv->source,
-							  G_MARKUP_ERROR_INVALID_CONTENT,
-							  "LinearGradientBrush", "Transform",
-							  values[i], error);
-					return;
-				}
-			}
-		}
-
-		/* TODO: check required values */
-
-		GXPS_DEBUG (g_message ("set_fill_pattern (linear)"));
-		brush->pattern = cairo_pattern_create_linear (x0, y0, x1, y1);
-		cairo_pattern_set_matrix (brush->pattern, &matrix);
-		cairo_pattern_set_extend (brush->pattern, extend);
-		g_markup_parse_context_push (context, &brush_gradient_parser, brush);
-	} else if (strcmp (element_name, "RadialGradientBrush") == 0) {
-		gint           i;
-		gdouble        cx0, cy0, r0, cx1, cy1, r1 = 0;
-		cairo_extend_t extend = CAIRO_EXTEND_PAD;
-		cairo_matrix_t matrix;
-
-		cairo_matrix_init_identity (&matrix);
-
-		for (i = 0; names[i] != NULL; i++) {
-			if (strcmp (names[i], "MappingMode") == 0) {
-			} else if (strcmp (names[i], "GradientOrigin") == 0) {
-				if (!gxps_point_parse (values[i], &cx0, &cy0)) {
-					gxps_parse_error (context,
-							  brush->ctx->page->priv->source,
-							  G_MARKUP_ERROR_INVALID_CONTENT,
-							  "RadialGradientBrush", "GradientOrigin",
-							  values[i], error);
-					return;
-				}
-			} else if (strcmp (names[i], "Center") == 0) {
-				if (!gxps_point_parse (values[i], &cx1, &cy1)) {
-					gxps_parse_error (context,
-							  brush->ctx->page->priv->source,
-							  G_MARKUP_ERROR_INVALID_CONTENT,
-							  "RadialGradientBrush", "Center",
-							  values[i], error);
-					return;
-				}
-			} else if (strcmp (names[i], "RadiusX") == 0) {
-                                if (!gxps_value_get_double (values[i], &r0)) {
-                                        gxps_parse_error (context,
-                                                          brush->ctx->page->priv->source,
-                                                          G_MARKUP_ERROR_INVALID_CONTENT,
-                                                          "RadialGradientBrush", "RadiusX",
-                                                          values[i], error);
-                                        return;
-                                }
-			} else if (strcmp (names[i], "RadiusY") == 0) {
-                                if (!gxps_value_get_double (values[i], &r1)) {
-                                        gxps_parse_error (context,
-                                                          brush->ctx->page->priv->source,
-                                                          G_MARKUP_ERROR_INVALID_CONTENT,
-                                                          "RadialGradientBrush", "RadiusY",
-                                                          values[i], error);
-                                        return;
-                                }
-			} else if (strcmp (names[i], "SpreadMethod") == 0) {
-				extend = gxps_spread_method_parse (values[i]);
-			} else if (strcmp (names[i], "Opacity") == 0) {
-                                if (!gxps_value_get_double (values[i], &brush->opacity)) {
-                                        gxps_parse_error (context,
-                                                          brush->ctx->page->priv->source,
-                                                          G_MARKUP_ERROR_INVALID_CONTENT,
-                                                          "RadialGradientBrush", "Opacity",
-                                                          values[i], error);
-                                        return;
-                                }
-			} else if (strcmp (names[i], "Transform") == 0) {
-				if (!gxps_matrix_parse (values[i], &matrix)) {
-					gxps_parse_error (context,
-							  brush->ctx->page->priv->source,
-							  G_MARKUP_ERROR_INVALID_CONTENT,
-							  "RadialGradientBrush", "Transform",
-							  values[i], error);
-					return;
-				}
-			}
-		}
-
-		/* TODO: Check required values */
-
-		GXPS_DEBUG (g_message ("set_fill_pattern (radial)"));
-		brush->pattern = cairo_pattern_create_radial (cx0, cy0, 0, cx1, cy1, r1);
-		cairo_pattern_set_matrix (brush->pattern, &matrix);
-		cairo_pattern_set_extend (brush->pattern, extend);
-		g_markup_parse_context_push (context, &brush_gradient_parser, brush);
-	} else if (strcmp (element_name, "VisualBrush") == 0) {
-		GXPSBrushVisual *visual;
-		GXPSRenderContext *sub_ctx;
-		cairo_rectangle_t viewport, viewbox;
-		cairo_matrix_t matrix;
-		cairo_extend_t extend = CAIRO_EXTEND_NONE;
-		gint i;
-
-		cairo_matrix_init_identity (&matrix);
-
-		for (i = 0; names[i] != NULL; i++) {
-			if (strcmp (names[i], "TileMode") == 0) {
-				extend = gxps_tile_mode_parse (values[i]);
-			} else if (strcmp (names[i], "Transform") == 0) {
-				if (!gxps_matrix_parse (values[i], &matrix)) {
-					gxps_parse_error (context,
-							  brush->ctx->page->priv->source,
-							  G_MARKUP_ERROR_INVALID_CONTENT,
-							  "VisualBrush", "Transform",
-							  values[i], error);
-					return;
-				}
-			} else if (strcmp (names[i], "Viewport") == 0) {
-				if (!gxps_box_parse (values[i], &viewport)) {
-					gxps_parse_error (context,
-							  brush->ctx->page->priv->source,
-							  G_MARKUP_ERROR_INVALID_CONTENT,
-							  "VisualBrush", "Viewport",
-							  values[i], error);
-					return;
-				}
-			} else if (strcmp (names[i], "ViewportUnits") == 0) {
-			} else if (strcmp (names[i], "Viewbox") == 0) {
-				if (!gxps_box_parse (values[i], &viewbox)) {
-					gxps_parse_error (context,
-							  brush->ctx->page->priv->source,
-							  G_MARKUP_ERROR_INVALID_CONTENT,
-							  "VisualBrush", "Viewbox",
-							  values[i], error);
-					return;
-				}
-			} else if (strcmp (names[i], "ViewboxUnits") == 0) {
-			} else if (strcmp (names[i], "Opacity") == 0) {
-			} else {
-			}
-		}
-
-		/* TODO: check required values */
-
-		/* Clip to viewport so that push group
-		 * will create a surface with the viport size
-		 */
-		cairo_save (brush->ctx->cr);
-		cairo_rectangle (brush->ctx->cr, viewbox.x, viewbox.y, viewbox.width, viewbox.height);
-		cairo_clip (brush->ctx->cr);
-		cairo_push_group (brush->ctx->cr);
-		visual = gxps_brush_visual_new (brush, &viewport, &viewbox);
-		visual->extend = extend;
-		sub_ctx = g_slice_new0 (GXPSRenderContext);
-		sub_ctx->page = brush->ctx->page;
-		sub_ctx->cr = brush->ctx->cr;
-		sub_ctx->visual = visual;
-		g_markup_parse_context_push (context, &render_parser, sub_ctx);
-	} else {
-		GXPS_DEBUG (g_debug ("Unsupported Brush: %s", element_name));
-
-	}
-}
-
-static void
-brush_end_element (GMarkupParseContext  *context,
-		   const gchar          *element_name,
-		   gpointer              user_data,
-		   GError              **error)
-{
-	GXPSBrush *brush = (GXPSBrush *)user_data;
-
-	if (strcmp (element_name, "SolidColorBrush") == 0) {
-	} else if (strcmp (element_name, "LinearGradientBrush") == 0) {
-		g_markup_parse_context_pop (context);
-	} else if (strcmp (element_name, "RadialGradientBrush") == 0) {
-		g_markup_parse_context_pop (context);
-	} else if (strcmp (element_name, "ImageBrush") == 0) {
-		GXPSBrushImage  *image;
-		cairo_surface_t *surface;
-		GError          *err = NULL;
-
-		image = g_markup_parse_context_pop (context);
-
-		GXPS_DEBUG (g_message ("set_fill_pattern (image)"));
-		surface = gxps_page_get_image (brush->ctx->page, image->image_uri, &err);
-		if (surface) {
-			cairo_matrix_t matrix, port_matrix;
-			gdouble        x_scale, y_scale;
-
-			image->brush->pattern = cairo_pattern_create_for_surface (surface);
-			cairo_pattern_set_extend (image->brush->pattern, image->extend);
-			cairo_surface_destroy (surface);
-
-			cairo_matrix_init (&port_matrix,
-					   image->viewport.width,
-					   0, 0,
-					   image->viewport.height,
-					   image->viewport.x,
-					   image->viewport.y);
-			cairo_matrix_multiply (&port_matrix, &port_matrix, &image->matrix);
-
-			x_scale = image->viewbox.width / port_matrix.xx;
-			y_scale = image->viewbox.height / port_matrix.yy;
-			cairo_matrix_init (&matrix, x_scale, 0, 0, y_scale,
-					   -port_matrix.x0 * x_scale,
-					   -port_matrix.y0 * y_scale);
-			cairo_pattern_set_matrix (image->brush->pattern, &matrix);
-
-			if (brush->opacity != 1.0) {
-				cairo_push_group (brush->ctx->cr);
-				cairo_set_source (brush->ctx->cr, image->brush->pattern);
-				cairo_pattern_destroy (image->brush->pattern);
-				cairo_paint_with_alpha (brush->ctx->cr, brush->opacity);
-				image->brush->pattern = cairo_pop_group (brush->ctx->cr);
-			}
-
-			if (cairo_pattern_status (image->brush->pattern)) {
-				GXPS_DEBUG (g_debug ("%s", cairo_status_to_string (cairo_pattern_status (image->brush->pattern))));
-				cairo_pattern_destroy (image->brush->pattern);
-				image->brush->pattern = NULL;
-			}
-		} else if (err) {
-			GXPS_DEBUG (g_debug ("%s", err->message));
-			g_error_free (err);
-		}
-		gxps_brush_image_free (image);
-	} else if (strcmp (element_name, "VisualBrush") == 0) {
-		GXPSRenderContext *sub_ctx;
-		GXPSBrushVisual   *visual;
-		cairo_matrix_t     matrix, port_matrix;
-		gdouble            x_scale, y_scale;
-
-		sub_ctx = g_markup_parse_context_pop (context);
-		visual = sub_ctx->visual;
-		g_slice_free (GXPSRenderContext, sub_ctx);
-
-		GXPS_DEBUG (g_message ("set_fill_pattern (visual)"));
-		visual->brush->pattern = cairo_pop_group (brush->ctx->cr);
-		/* Undo the clip */
-		cairo_restore (brush->ctx->cr);
-		cairo_pattern_set_extend (visual->brush->pattern, visual->extend);
-		cairo_matrix_init (&port_matrix,
-				   visual->viewport.width,
-				   0, 0,
-				   visual->viewport.height,
-				   visual->viewport.x,
-				   visual->viewport.y);
-		cairo_matrix_multiply (&port_matrix, &port_matrix, &visual->matrix);
-
-		x_scale = visual->viewbox.width / port_matrix.xx;
-		y_scale = visual->viewbox.height / port_matrix.yy;
-		cairo_matrix_init (&matrix, x_scale, 0, 0, y_scale,
-				   -port_matrix.x0 * x_scale,
-				   -port_matrix.y0 * y_scale);
-
-		cairo_pattern_set_matrix (visual->brush->pattern, &matrix);
-		if (cairo_pattern_status (visual->brush->pattern)) {
-			GXPS_DEBUG (g_debug ("%s", cairo_status_to_string (cairo_pattern_status (visual->brush->pattern))));
-			cairo_pattern_destroy (visual->brush->pattern);
-			visual->brush->pattern = NULL;
-		}
-
-		gxps_brush_visual_free (visual);
-	} else {
-		GXPS_DEBUG (g_debug ("Unsupported Brush: %s", element_name));
-
-	}
-}
-
-static GMarkupParser brush_parser = {
-	brush_start_element,
-	brush_end_element,
-	NULL,
-	NULL
-};
-
 typedef struct {
 	GXPSRenderContext *ctx;
 
@@ -1860,7 +917,7 @@ canvas_start_element (GMarkupParseContext  *context,
 		GXPSBrush *brush;
 
 		brush = gxps_brush_new (canvas->ctx);
-		g_markup_parse_context_push (context, &brush_parser, brush);
+		gxps_brush_parser_push (context, brush);
 	} else {
 		render_start_element (context,
 				      element_name,
@@ -2185,12 +1242,12 @@ path_start_element (GMarkupParseContext  *context,
 		GXPSBrush *brush;
 
 		brush = gxps_brush_new (path->ctx);
-		g_markup_parse_context_push (context, &brush_parser, brush);
+		gxps_brush_parser_push (context, brush);
 	} else if (strcmp (element_name, "Path.Stroke") == 0) {
 		GXPSBrush *brush;
 
 		brush = gxps_brush_new (path->ctx);
-		g_markup_parse_context_push (context, &brush_parser, brush);
+		gxps_brush_parser_push (context, brush);
 	} else if (strcmp (element_name, "Path.Data") == 0) {
 	} else if (strcmp (element_name, "PathGeometry") == 0) {
 		gint i;
@@ -2858,12 +1915,12 @@ glyphs_start_element (GMarkupParseContext  *context,
 		GXPSBrush *brush;
 
 		brush = gxps_brush_new (glyphs->ctx);
-		g_markup_parse_context_push (context, &brush_parser, brush);
+		gxps_brush_parser_push (context, brush);
 	} else if (strcmp (element_name, "Glyphs.OpacityMask") == 0) {
 		GXPSBrush *brush;
 
 		brush = gxps_brush_new (glyphs->ctx);
-		g_markup_parse_context_push (context, &brush_parser, brush);
+		gxps_brush_parser_push (context, brush);
 	} else {
 	}
 }
@@ -2955,9 +2012,7 @@ render_start_element (GMarkupParseContext  *context,
 				path->clip_data = g_strdup (values[i]);
 			} else if (strcmp (names[i], "Fill") == 0) {
 				GXPS_DEBUG (g_message ("set_fill_pattern (solid)"));
-				path->fill_pattern = gxps_create_solid_color_pattern (ctx->page->priv->zip,
-                                                                                      values[i]);
-				if (!path->fill_pattern) {
+                                if (!gxps_brush_solid_color_parse (values[i], ctx->page->priv->zip, 1., &path->fill_pattern)) {
 					gxps_parse_error (context,
 							  ctx->page->priv->source,
 							  G_MARKUP_ERROR_INVALID_CONTENT,
@@ -2966,9 +2021,7 @@ render_start_element (GMarkupParseContext  *context,
 				}
 			} else if (strcmp (names[i], "Stroke") == 0) {
 				GXPS_DEBUG (g_message ("set_stroke_pattern (solid)"));
-				path->stroke_pattern = gxps_create_solid_color_pattern (ctx->page->priv->zip,
-                                                                                        values[i]);
-				if (!path->stroke_pattern) {
+                                if (!gxps_brush_solid_color_parse (values[i], ctx->page->priv->zip, 1., &path->stroke_pattern)) {
 					gxps_parse_error (context,
 							  ctx->page->priv->source,
 							  G_MARKUP_ERROR_INVALID_CONTENT,
@@ -3173,8 +2226,7 @@ render_start_element (GMarkupParseContext  *context,
 		glyphs->opacity = opacity;
 		if (fill_color) {
 			GXPS_DEBUG (g_message ("set_fill_pattern (solid)"));
-			glyphs->fill_pattern = gxps_create_solid_color_pattern (ctx->page->priv->zip,
-                                                                                fill_color);
+                        gxps_brush_solid_color_parse (fill_color, ctx->page->priv->zip, 1., &glyphs->fill_pattern);
 		}
 
 		if (glyphs->opacity != 1.0)



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]