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_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_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; }
gboolean gxps_matrix_parse (const gchar *data, cairo_matrix_t *matrix) { gchar **items; gdouble mm[6]; guint i; items = g_strsplit (data, ",", 6); if (g_strv_length (items) != 6) { g_strfreev (items); return FALSE; } for (i = 0; i < 6; i++) { if (!gxps_value_get_double (items[i], &mm[i])) { g_strfreev (items); return FALSE; } } g_strfreev (items); cairo_matrix_init (matrix, mm[0], mm[1], mm[2], mm[3], mm[4], mm[5]); 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 = { 0, }, viewbox = { 0, }; 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 = { 0, }, viewbox = { 0, }; cairo_matrix_t matrix; cairo_extend_t extend = CAIRO_EXTEND_NONE; double width, height; 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 */ width = gxps_transform_hypot (&matrix, viewport.width, 0); height = gxps_transform_hypot (&matrix, 0, viewport.height); cairo_save (brush->ctx->cr); cairo_rectangle (brush->ctx->cr, 0, 0, width, height); cairo_clip (brush->ctx->cr); cairo_push_group (brush->ctx->cr); cairo_translate (brush->ctx->cr, -viewbox.x, -viewbox.y); cairo_scale (brush->ctx->cr, width / viewbox.width, height / viewbox.height); visual = gxps_brush_visual_new (brush, &viewport, &viewbox); visual->extend = extend; cairo_matrix_init (&visual->matrix, viewport.width / width, 0, 0, viewport.height / height, viewport.x, viewport.y); cairo_matrix_multiply (&visual->matrix, &visual->matrix, &matrix); cairo_matrix_invert (&visual->matrix); 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_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); } }