[librsvg/rustification] rsvg-cairo-draw.c: Use the Rust implementation of the gradient resolver
- From: Federico Mena Quintero <federico src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [librsvg/rustification] rsvg-cairo-draw.c: Use the Rust implementation of the gradient resolver
- Date: Thu, 1 Dec 2016 03:20:18 +0000 (UTC)
commit 30d12a9aa7ac0c0289f143484f5e7a585289f89d
Author: Federico Mena Quintero <federico gnome org>
Date: Wed Nov 30 21:17:59 2016 -0600
rsvg-cairo-draw.c: Use the Rust implementation of the gradient resolver
rsvg-cairo-draw.c | 240 +++++++++++++----------------------------------------
1 files changed, 58 insertions(+), 182 deletions(-)
---
diff --git a/rsvg-cairo-draw.c b/rsvg-cairo-draw.c
index 8def513..142a7a7 100644
--- a/rsvg-cairo-draw.c
+++ b/rsvg-cairo-draw.c
@@ -41,19 +41,11 @@
#include <pango/pangocairo.h>
-typedef struct {
- cairo_pattern_t *pattern;
- guint8 opacity;
- double last_offset;
- gboolean stops_are_valid;
-} AddStopsClosure;
-
static gboolean
-add_color_stop (RsvgNode *node, gpointer data)
+add_color_stop_to_gradient (RsvgNode *node, gpointer data)
{
- AddStopsClosure *closure = data;
+ Gradient *gradient = data;
RsvgGradientStop *stop;
- guint32 rgba;
if (rsvg_node_type (node) != RSVG_NODE_TYPE_STOP)
return TRUE; /* just ignore this node */
@@ -61,171 +53,84 @@ add_color_stop (RsvgNode *node, gpointer data)
stop = (RsvgGradientStop *) node;
if (!stop->is_valid) {
- closure->stops_are_valid = FALSE;
+ /* Don't add any more stops. */
return FALSE;
}
- /* deal with unsorted stop offsets as per the spec */
- closure->last_offset = MAX (closure->last_offset, stop->offset);
-
- rgba = stop->rgba;
- cairo_pattern_add_color_stop_rgba (closure->pattern,
- closure->last_offset,
- ((rgba >> 24) & 0xff) / 255.0,
- ((rgba >> 16) & 0xff) / 255.0,
- ((rgba >> 8) & 0xff) / 255.0,
- (((rgba >> 0) & 0xff) * closure->opacity) / 255.0 / 255.0);
+ gradient_add_color_stop (gradient, stop->offset, stop->rgba);
return TRUE;
}
-/* Adds the color stops from the array of child nodes (of type RSVG_NODE_TYPE_STOP)
- * to a cairo_pattern_t.
- *
- * Returns true if the stops are all valid and conform to the SVG spec; false
- * otherwise. It is up to the caller to decide whether to render the gradient
- * in this last case: it will have color stops added only up to the first invalid
- * stop.
- */
-static gboolean
-add_color_stops_for_gradient (RsvgNode *node, cairo_pattern_t *pattern, guint8 opacity)
+static void
+add_color_stops_to_gradient (Gradient *gradient, RsvgNode *node)
{
- AddStopsClosure closure;
-
- closure.pattern = pattern;
- closure.opacity = opacity;
- closure.last_offset = 0.0;
- closure.stops_are_valid = TRUE;
-
- rsvg_node_foreach_child (node, add_color_stop, &closure);
-
- return closure.stops_are_valid;
+ rsvg_node_foreach_child (node, add_color_stop_to_gradient, gradient);
}
-static void
-set_source_gradient_common (RsvgDrawingCtx *ctx,
- RsvgNode *node,
- cairo_pattern_t *pattern,
- cairo_extend_t extend,
- guint8 opacity,
- cairo_matrix_t affine,
- gboolean obj_bbox,
- RsvgBbox bbox)
+static Gradient *
+linear_gradient_to_rust (RsvgLinearGradient *linear)
{
- RsvgCairoRender *render = RSVG_CAIRO_RENDER (ctx->render);
- cairo_t *cr = render->cr;
-
- if (obj_bbox) {
- cairo_matrix_t bboxmatrix;
- cairo_matrix_init (&bboxmatrix, bbox.rect.width, 0, 0, bbox.rect.height,
- bbox.rect.x, bbox.rect.y);
- cairo_matrix_multiply (&affine, &affine, &bboxmatrix);
- }
+ Gradient *gradient;
- cairo_matrix_invert (&affine);
- cairo_pattern_set_matrix (pattern, &affine);
- cairo_pattern_set_extend (pattern, extend);
+ gradient = gradient_linear_new (linear->hasx1 ? &linear->x1 : NULL,
+ linear->hasy1 ? &linear->y1 : NULL,
+ linear->hasx2 ? &linear->x2 : NULL,
+ linear->hasy2 ? &linear->y2 : NULL,
+ linear->hasbbox ? &linear->obj_bbox : NULL,
+ linear->hastransform ? &linear->affine : NULL,
+ linear->hasspread ? &linear->spread : NULL,
+ linear->fallback);
- /* We ignore the return value of add_color_stops_for_gradient(), which is
- * whether the stops are conformant to the spec. This is so that we can
- * render a partially-generated gradient if some of the stops are invalid.
- */
- add_color_stops_for_gradient (node, pattern, opacity);
+ add_color_stops_to_gradient (gradient, (RsvgNode *) linear);
- cairo_set_source (cr, pattern);
+ return gradient;
}
-static void
-_set_source_rsvg_linear_gradient (RsvgDrawingCtx * ctx,
- RsvgLinearGradient * linear,
- guint8 opacity, RsvgBbox bbox)
+static Gradient *
+radial_gradient_to_rust (RsvgRadialGradient *radial)
{
- cairo_pattern_t *pattern;
- RsvgLinearGradient statlinear;
+ Gradient *gradient;
- statlinear = *linear;
- linear = &statlinear;
- rsvg_linear_gradient_fix_fallback (ctx, linear);
-
- if (linear->obj_bbox)
- rsvg_drawing_ctx_push_view_box (ctx, 1., 1.);
- pattern = cairo_pattern_create_linear (rsvg_length_normalize (&linear->x1, ctx),
- rsvg_length_normalize (&linear->y1, ctx),
- rsvg_length_normalize (&linear->x2, ctx),
- rsvg_length_normalize (&linear->y2, ctx));
-
- if (linear->obj_bbox)
- rsvg_drawing_ctx_pop_view_box (ctx);
+ gradient = gradient_radial_new (radial->hascx ? &radial->cx : NULL,
+ radial->hascy ? &radial->cy : NULL,
+ radial->hasr ? &radial->r : NULL,
+ radial->hasfx ? &radial->fx : NULL,
+ radial->hasfy ? &radial->fy : NULL,
+ radial->hasbbox ? &radial->obj_bbox : NULL,
+ radial->hastransform ? &radial->affine : NULL,
+ radial->hasspread ? &radial->spread : NULL,
+ radial->fallback);
- set_source_gradient_common (ctx,
- (RsvgNode *) linear,
- pattern,
- linear->spread,
- opacity,
- linear->affine,
- linear->obj_bbox,
- bbox);
+ add_color_stops_to_gradient (gradient, (RsvgNode *) radial);
- cairo_pattern_destroy (pattern);
+ return gradient;
}
-/* SVG defines radial gradients as being inside a circle (cx, cy, radius). The
- * gradient projects out from a focus point (fx, fy), which is assumed to be
- * inside the circle, to the edge of the circle.
- *
- * The description of https://www.w3.org/TR/SVG/pservers.html#RadialGradientElement
- * states:
- *
- * If the point defined by ‘fx’ and ‘fy’ lies outside the circle defined by
- * ‘cx’, ‘cy’ and ‘r’, then the user agent shall set the focal point to the
- * intersection of the line from (‘cx’, ‘cy’) to (‘fx’, ‘fy’) with the circle
- * defined by ‘cx’, ‘cy’ and ‘r’.
- *
- * So, let's do that!
- */
-static void
-fix_focus_point (double fx, double fy, double cx, double cy, double radius,
- double *out_fx, double *out_fy)
+Gradient *
+rsvg_gradient_node_to_rust_gradient (RsvgNode *node)
{
- double vx, vy;
- double mag, scale;
-
- /* Easy case first: the focus point is inside the circle */
-
- if ((fx - cx) * (fx - cx) + (fy - cy) * (fy - cy) <= radius * radius) {
- *out_fx = fx;
- *out_fy = fy;
- return;
+ if (rsvg_node_type (node) == RSVG_NODE_TYPE_LINEAR_GRADIENT) {
+ return linear_gradient_to_rust ((RsvgLinearGradient *) node);
+ } else if (rsvg_node_type (node) == RSVG_NODE_TYPE_RADIAL_GRADIENT) {
+ return radial_gradient_to_rust ((RsvgRadialGradient *) node);
+ } else {
+ return NULL;
}
+}
- /* Hard case: focus point is outside the circle.
- *
- * First, translate everything to the origin.
- */
-
- fx -= cx;
- fy -= cy;
-
- /* Find the vector from the origin to (fx, fy) */
-
- vx = fx;
- vy = fy;
-
- /* Find the vector's magnitude */
-
- mag = sqrt (vx * vx + vy * vy);
-
- /* Normalize the vector to have a magnitude equal to radius; (vx, vy) will now be on the edge of the
circle */
-
- scale = mag / radius;
+static void
+_set_source_rsvg_linear_gradient (RsvgDrawingCtx *ctx,
+ RsvgLinearGradient *linear,
+ guint8 opacity, RsvgBbox bbox)
+{
+ Gradient *gradient;
- vx /= scale;
- vy /= scale;
+ gradient = linear_gradient_to_rust (linear);
- /* Translate back to (cx, cy) and we are done! */
+ gradient_resolve_fallbacks_and_set_pattern (gradient, ctx, opacity, bbox);
- *out_fx = vx + cx;
- *out_fy = vy + cy;
+ gradient_destroy (gradient);
}
static void
@@ -233,44 +138,13 @@ _set_source_rsvg_radial_gradient (RsvgDrawingCtx * ctx,
RsvgRadialGradient * radial,
guint8 opacity, RsvgBbox bbox)
{
- cairo_pattern_t *pattern;
- RsvgRadialGradient statradial;
- double fx, fy;
- double cx, cy, radius;
- double new_fx, new_fy;
-
- statradial = *radial;
- radial = &statradial;
- rsvg_radial_gradient_fix_fallback (ctx, radial);
-
- if (radial->obj_bbox)
- rsvg_drawing_ctx_push_view_box (ctx, 1., 1.);
-
- fx = rsvg_length_normalize (&radial->fx, ctx);
- fy = rsvg_length_normalize (&radial->fy, ctx);
+ Gradient *gradient;
- cx = rsvg_length_normalize (&radial->cx, ctx);
- cy = rsvg_length_normalize (&radial->cy, ctx);
- radius = rsvg_length_normalize (&radial->r, ctx);
+ gradient = radial_gradient_to_rust (radial);
- fix_focus_point (fx, fy, cx, cy, radius, &new_fx, &new_fy);
+ gradient_resolve_fallbacks_and_set_pattern (gradient, ctx, opacity, bbox);
- pattern = cairo_pattern_create_radial (new_fx, new_fy, 0.0,
- cx, cy, radius);
-
- if (radial->obj_bbox)
- rsvg_drawing_ctx_pop_view_box (ctx);
-
- set_source_gradient_common (ctx,
- (RsvgNode *) radial,
- pattern,
- radial->spread,
- opacity,
- radial->affine,
- radial->obj_bbox,
- bbox);
-
- cairo_pattern_destroy (pattern);
+ gradient_destroy (gradient);
}
static void
@@ -581,6 +455,8 @@ rsvg_cairo_render_pango_layout (RsvgDrawingCtx * ctx, PangoLayout * layout, doub
}
}
+
+
void
rsvg_cairo_render_path_builder (RsvgDrawingCtx * ctx, RsvgPathBuilder *builder)
{
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]