[librsvg/rustification] Implement rsvg_length_normalize() fully in Rust



commit 4d19ded9d0e880e0bb0fd9cd9580c4175276dde8
Author: Federico Mena Quintero <federico gnome org>
Date:   Wed Nov 16 18:27:05 2016 -0600

    Implement rsvg_length_normalize() fully in Rust
    
    We add an RsvgLength::normalize() method, and the corresponding
    rsvg_length_normalize() function to make this accessible to the C code.
    
    This removes the old _rsvg_css_normalize_length() function.

 rsvg-base.c             |    2 +-
 rsvg-cairo-draw.c       |   36 +++++++++++++-------------
 rsvg-css.c              |   64 +----------------------------------------------
 rsvg-filter.c           |   38 ++++++++++++++--------------
 rsvg-image.c            |    8 +++---
 rsvg-marker.c           |   12 ++++----
 rsvg-private.h          |    4 ++-
 rsvg-shapes.c           |   34 ++++++++++++------------
 rsvg-structure.c        |   16 ++++++------
 rsvg-text.c             |   22 ++++++++--------
 rust/src/drawing_ctx.rs |   20 ++++++++++++++
 rust/src/length.rs      |   64 ++++++++++++++++++++++++++++++++++++++++++++---
 12 files changed, 168 insertions(+), 152 deletions(-)
---
diff --git a/rsvg-base.c b/rsvg-base.c
index eda5934..22b52f3 100644
--- a/rsvg-base.c
+++ b/rsvg-base.c
@@ -2195,7 +2195,7 @@ rsvg_get_normalized_stroke_width (RsvgDrawingCtx *ctx)
 {
     RsvgState *state = rsvg_current_state (ctx);
 
-    return _rsvg_css_normalize_length (&state->stroke_width, ctx);
+    return rsvg_length_normalize (&state->stroke_width, ctx);
 }
 
 
diff --git a/rsvg-cairo-draw.c b/rsvg-cairo-draw.c
index 070b76a..e4995a1 100644
--- a/rsvg-cairo-draw.c
+++ b/rsvg-cairo-draw.c
@@ -101,10 +101,10 @@ _set_source_rsvg_linear_gradient (RsvgDrawingCtx * ctx,
 
     if (linear->obj_bbox)
         rsvg_drawing_ctx_push_view_box (ctx, 1., 1.);
-    pattern = cairo_pattern_create_linear (_rsvg_css_normalize_length (&linear->x1, ctx),
-                                           _rsvg_css_normalize_length (&linear->y1, ctx),
-                                           _rsvg_css_normalize_length (&linear->x2, ctx),
-                                           _rsvg_css_normalize_length (&linear->y2, ctx));
+    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);
@@ -210,12 +210,12 @@ _set_source_rsvg_radial_gradient (RsvgDrawingCtx * ctx,
     if (radial->obj_bbox)
         rsvg_drawing_ctx_push_view_box (ctx, 1., 1.);
 
-    fx = _rsvg_css_normalize_length (&radial->fx, ctx);
-    fy = _rsvg_css_normalize_length (&radial->fy, ctx);
+    fx = rsvg_length_normalize (&radial->fx, ctx);
+    fy = rsvg_length_normalize (&radial->fy, ctx);
 
-    cx = _rsvg_css_normalize_length (&radial->cx, ctx);
-    cy = _rsvg_css_normalize_length (&radial->cy, ctx);
-    radius = _rsvg_css_normalize_length (&radial->r, ctx);
+    cx = rsvg_length_normalize (&radial->cx, ctx);
+    cy = rsvg_length_normalize (&radial->cy, ctx);
+    radius = rsvg_length_normalize (&radial->r, ctx);
 
     fix_focus_point (fx, fy, cx, cy, radius, &new_fx, &new_fy);
 
@@ -289,10 +289,10 @@ _set_source_rsvg_pattern (RsvgDrawingCtx * ctx,
     if (rsvg_pattern->obj_bbox)
         rsvg_drawing_ctx_push_view_box (ctx, 1., 1.);
 
-    patternx = _rsvg_css_normalize_length (&rsvg_pattern->x, ctx);
-    patterny = _rsvg_css_normalize_length (&rsvg_pattern->y, ctx);
-    patternw = _rsvg_css_normalize_length (&rsvg_pattern->width, ctx);
-    patternh = _rsvg_css_normalize_length (&rsvg_pattern->height, ctx);
+    patternx = rsvg_length_normalize (&rsvg_pattern->x, ctx);
+    patterny = rsvg_length_normalize (&rsvg_pattern->y, ctx);
+    patternw = rsvg_length_normalize (&rsvg_pattern->width, ctx);
+    patternh = rsvg_length_normalize (&rsvg_pattern->height, ctx);
 
     if (rsvg_pattern->obj_bbox)
         rsvg_drawing_ctx_pop_view_box (ctx);
@@ -484,7 +484,7 @@ setup_cr_for_stroke (cairo_t *cr, RsvgDrawingCtx *ctx, RsvgState *state)
     cairo_set_line_cap (cr, (cairo_line_cap_t) state->cap);
     cairo_set_line_join (cr, (cairo_line_join_t) state->join);
     cairo_set_dash (cr, state->dash.dash, state->dash.n_dash,
-                    _rsvg_css_normalize_length (&state->dash.offset, ctx));
+                    rsvg_length_normalize (&state->dash.offset, ctx));
 }
 
 void
@@ -740,10 +740,10 @@ rsvg_cairo_generate_mask (cairo_t * cr, RsvgMask * self, RsvgDrawingCtx * ctx, R
     if (self->maskunits == objectBoundingBox)
         rsvg_drawing_ctx_push_view_box (ctx, 1, 1);
 
-    sx = _rsvg_css_normalize_length (&self->x, ctx);
-    sy = _rsvg_css_normalize_length (&self->y, ctx);
-    sw = _rsvg_css_normalize_length (&self->width, ctx);
-    sh = _rsvg_css_normalize_length (&self->height, ctx);
+    sx = rsvg_length_normalize (&self->x, ctx);
+    sy = rsvg_length_normalize (&self->y, ctx);
+    sw = rsvg_length_normalize (&self->width, ctx);
+    sh = rsvg_length_normalize (&self->height, ctx);
 
     if (self->maskunits == objectBoundingBox)
         rsvg_drawing_ctx_pop_view_box (ctx);
diff --git a/rsvg-css.c b/rsvg-css.c
index 21d5027..6df3bbf 100644
--- a/rsvg-css.c
+++ b/rsvg-css.c
@@ -109,7 +109,7 @@ normalize_font_size (RsvgState * state, RsvgDrawingCtx * ctx)
         }
         break;
     default:
-        return _rsvg_css_normalize_length (&state->font_size, ctx);
+        return rsvg_length_normalize (&state->font_size, ctx);
         break;
     }
 
@@ -122,68 +122,6 @@ rsvg_drawing_ctx_get_normalized_font_size (RsvgDrawingCtx *ctx)
     return normalize_font_size (rsvg_current_state (ctx), ctx);
 }
 
-static double
-viewport_percentage (double width, double height)
-{
-    /* https://www.w3.org/TR/SVG/coords.html#Units
-     *
-     * "For any other length value expressed as a percentage of the viewport, the
-     * percentage is calculated as the specified percentage of
-     * sqrt((actual-width)**2 + (actual-height)**2))/sqrt(2)."
-     */
-    return sqrt (width * width + height * height) / M_SQRT2;
-}
-
-double
-_rsvg_css_normalize_length (const RsvgLength * in, RsvgDrawingCtx * ctx)
-{
-    if (in->unit == LENGTH_UNIT_DEFAULT)
-        return in->length;
-    else if (in->unit == LENGTH_UNIT_PERCENT) {
-        double w, h;
-
-        rsvg_drawing_ctx_get_view_box_size (ctx, &w, &h);
-
-        switch (in->dir) {
-        case LENGTH_DIR_HORIZONTAL:
-            return in->length * w;
-
-        case LENGTH_DIR_VERTICAL:
-            return in->length * h;
-
-        case LENGTH_DIR_BOTH:
-            return in->length * viewport_percentage (w, h);
-        }
-    } else if (in->unit == LENGTH_UNIT_FONT_EM || in->unit == LENGTH_UNIT_FONT_EX) {
-        double font = rsvg_drawing_ctx_get_normalized_font_size (ctx);
-        if (in->unit == LENGTH_UNIT_FONT_EM)
-            return in->length * font;
-        else
-            return in->length * font / 2.;
-    } else if (in->unit == LENGTH_UNIT_INCH) {
-        double dpi_x, dpi_y;
-
-        rsvg_drawing_ctx_get_dpi (ctx, &dpi_x, &dpi_y);
-
-        switch (in->dir) {
-        case LENGTH_DIR_HORIZONTAL:
-            return in->length * dpi_x;
-
-        case LENGTH_DIR_VERTICAL:
-            return in->length * dpi_y;
-
-        case LENGTH_DIR_BOTH:
-            return in->length * viewport_percentage (dpi_x, dpi_y);
-        }
-    } else if (in->unit == LENGTH_UNIT_RELATIVE_LARGER) {
-        /* todo: "larger" */
-    } else if (in->unit == LENGTH_UNIT_RELATIVE_SMALLER) {
-        /* todo: "smaller" */
-    }
-
-    return 0;
-}
-
 /* Recursive evaluation of all parent elements regarding basline-shift */
 double
 _rsvg_css_accumulate_baseline_shift (RsvgState * state, RsvgDrawingCtx * ctx)
diff --git a/rsvg-filter.c b/rsvg-filter.c
index ff588c0..1a6a806 100644
--- a/rsvg-filter.c
+++ b/rsvg-filter.c
@@ -161,10 +161,10 @@ rsvg_filter_primitive_get_bounds (RsvgFilterPrimitive * self, RsvgFilterContext
     otherbox.virgin = 0;
     if (ctx->filter->filterunits == objectBoundingBox)
         rsvg_drawing_ctx_push_view_box (ctx->ctx, 1., 1.);
-    otherbox.rect.x = _rsvg_css_normalize_length (&ctx->filter->x, ctx->ctx);
-    otherbox.rect.y = _rsvg_css_normalize_length (&ctx->filter->y, ctx->ctx);
-    otherbox.rect.width = _rsvg_css_normalize_length (&ctx->filter->width, ctx->ctx);
-    otherbox.rect.height = _rsvg_css_normalize_length (&ctx->filter->height, ctx->ctx);
+    otherbox.rect.x = rsvg_length_normalize (&ctx->filter->x, ctx->ctx);
+    otherbox.rect.y = rsvg_length_normalize (&ctx->filter->y, ctx->ctx);
+    otherbox.rect.width = rsvg_length_normalize (&ctx->filter->width, ctx->ctx);
+    otherbox.rect.height = rsvg_length_normalize (&ctx->filter->height, ctx->ctx);
     if (ctx->filter->filterunits == objectBoundingBox)
         rsvg_drawing_ctx_pop_view_box (ctx->ctx);
 
@@ -177,11 +177,11 @@ rsvg_filter_primitive_get_bounds (RsvgFilterPrimitive * self, RsvgFilterContext
             if (ctx->filter->primitiveunits == objectBoundingBox)
                 rsvg_drawing_ctx_push_view_box (ctx->ctx, 1., 1.);
             if (self->x_specified)
-                otherbox.rect.x = _rsvg_css_normalize_length (&self->x, ctx->ctx);
+                otherbox.rect.x = rsvg_length_normalize (&self->x, ctx->ctx);
             else
                 otherbox.rect.x = 0;
             if (self->y_specified)
-                otherbox.rect.y = _rsvg_css_normalize_length (&self->y, ctx->ctx);
+                otherbox.rect.y = rsvg_length_normalize (&self->y, ctx->ctx);
             else
                 otherbox.rect.y = 0;
 
@@ -191,12 +191,12 @@ rsvg_filter_primitive_get_bounds (RsvgFilterPrimitive * self, RsvgFilterContext
                 rsvg_drawing_ctx_get_view_box_size (ctx->ctx, &curr_vbox_w, &curr_vbox_h);
 
                 if (self->width_specified)
-                    otherbox.rect.width = _rsvg_css_normalize_length (&self->width, ctx->ctx);
+                    otherbox.rect.width = rsvg_length_normalize (&self->width, ctx->ctx);
                 else
                     otherbox.rect.width = curr_vbox_w;
 
                 if (self->height_specified)
-                    otherbox.rect.height = _rsvg_css_normalize_length (&self->height, ctx->ctx);
+                    otherbox.rect.height = rsvg_length_normalize (&self->height, ctx->ctx);
                 else
                     otherbox.rect.height = curr_vbox_h;
             }
@@ -2018,8 +2018,8 @@ rsvg_filter_primitive_offset_render (RsvgFilterPrimitive * self, RsvgFilterConte
 
     output_pixels = cairo_image_surface_get_data (output);
 
-    dx = _rsvg_css_normalize_length (&upself->dx, ctx->ctx);
-    dy = _rsvg_css_normalize_length (&upself->dy, ctx->ctx);
+    dx = rsvg_length_normalize (&upself->dx, ctx->ctx);
+    dy = rsvg_length_normalize (&upself->dy, ctx->ctx);
 
     ox = ctx->paffine.xx * dx + ctx->paffine.xy * dy;
     oy = ctx->paffine.yx * dx + ctx->paffine.yy * dy;
@@ -4263,9 +4263,9 @@ get_light_direction (RsvgNodeLightSource * source, gdouble x1, gdouble y1, gdoub
             double x, y;
             x = affine->xx * x1 + affine->xy * y1 + affine->x0;
             y = affine->yx * x1 + affine->yy * y1 + affine->y0;
-            output.x = _rsvg_css_normalize_length (&source->x, ctx) - x;
-            output.y = _rsvg_css_normalize_length (&source->y, ctx) - y;
-            output.z = _rsvg_css_normalize_length (&source->z, ctx) - z;
+            output.x = rsvg_length_normalize (&source->x, ctx) - x;
+            output.y = rsvg_length_normalize (&source->y, ctx) - y;
+            output.z = rsvg_length_normalize (&source->z, ctx) - z;
             output = normalise (output);
         }
         break;
@@ -4286,12 +4286,12 @@ get_light_color (RsvgNodeLightSource * source, vector3 color,
     if (source->type != SPOTLIGHT)
         return color;
 
-    sx = _rsvg_css_normalize_length (&source->x, ctx);
-    sy = _rsvg_css_normalize_length (&source->y, ctx);
-    sz = _rsvg_css_normalize_length (&source->z, ctx);
-    spx = _rsvg_css_normalize_length (&source->pointsAtX, ctx);
-    spy = _rsvg_css_normalize_length (&source->pointsAtY, ctx);
-    spz = _rsvg_css_normalize_length (&source->pointsAtZ, ctx);
+    sx = rsvg_length_normalize (&source->x, ctx);
+    sy = rsvg_length_normalize (&source->y, ctx);
+    sz = rsvg_length_normalize (&source->z, ctx);
+    spx = rsvg_length_normalize (&source->pointsAtX, ctx);
+    spy = rsvg_length_normalize (&source->pointsAtY, ctx);
+    spz = rsvg_length_normalize (&source->pointsAtZ, ctx);
 
     x = affine->xx * x1 + affine->xy * y1 + affine->x0;
     y = affine->yx * x1 + affine->yy * y1 + affine->y0;
diff --git a/rsvg-image.c b/rsvg-image.c
index 1c2b438..92fc004 100644
--- a/rsvg-image.c
+++ b/rsvg-image.c
@@ -172,10 +172,10 @@ rsvg_node_image_draw (RsvgNode * self, RsvgDrawingCtx * ctx, int dominate)
     if (surface == NULL)
         return;
 
-    x = _rsvg_css_normalize_length (&z->x, ctx);
-    y = _rsvg_css_normalize_length (&z->y, ctx);
-    w = _rsvg_css_normalize_length (&z->w, ctx);
-    h = _rsvg_css_normalize_length (&z->h, ctx);
+    x = rsvg_length_normalize (&z->x, ctx);
+    y = rsvg_length_normalize (&z->y, ctx);
+    w = rsvg_length_normalize (&z->w, ctx);
+    h = rsvg_length_normalize (&z->h, ctx);
 
     rsvg_state_reinherit_top (ctx, z->super.state, dominate);
 
diff --git a/rsvg-marker.c b/rsvg-marker.c
index cb9916a..2ae5532 100644
--- a/rsvg-marker.c
+++ b/rsvg-marker.c
@@ -141,8 +141,8 @@ rsvg_marker_render (const char * marker_name, gdouble xpos, gdouble ypos, gdoubl
 
     if (self->vbox.active) {
         double w, h, x, y;
-        w = _rsvg_css_normalize_length (&self->width, ctx);
-        h = _rsvg_css_normalize_length (&self->height, ctx);
+        w = rsvg_length_normalize (&self->width, ctx);
+        h = rsvg_length_normalize (&self->height, ctx);
         x = 0;
         y = 0;
 
@@ -158,8 +158,8 @@ rsvg_marker_render (const char * marker_name, gdouble xpos, gdouble ypos, gdoubl
     }
 
     cairo_matrix_init_translate (&taffine,
-                                 -_rsvg_css_normalize_length (&self->refX, ctx),
-                                 -_rsvg_css_normalize_length (&self->refY, ctx));
+                                 -rsvg_length_normalize (&self->refX, ctx),
+                                 -rsvg_length_normalize (&self->refY, ctx));
     cairo_matrix_multiply (&affine, &taffine, &affine);
 
     rsvg_state_push (ctx);
@@ -181,8 +181,8 @@ rsvg_marker_render (const char * marker_name, gdouble xpos, gdouble ypos, gdoubl
                                     self->vbox.rect.width, self->vbox.rect.height);
         else
             rsvg_add_clipping_rect (ctx, 0, 0,
-                                    _rsvg_css_normalize_length (&self->width, ctx),
-                                    _rsvg_css_normalize_length (&self->height, ctx));
+                                    rsvg_length_normalize (&self->width, ctx),
+                                    rsvg_length_normalize (&self->height, ctx));
     }
 
     for (i = 0; i < self->super.children->len; i++) {
diff --git a/rsvg-private.h b/rsvg-private.h
index bc58bb2..c7dc94f 100644
--- a/rsvg-private.h
+++ b/rsvg-private.h
@@ -420,8 +420,10 @@ G_GNUC_INTERNAL
 void rsvg_bbox_insert   (RsvgBbox * dst, RsvgBbox * src);
 G_GNUC_INTERNAL
 void rsvg_bbox_clip     (RsvgBbox * dst, RsvgBbox * src);
+
+/* This is implemented in rust/src/length.rs */
 G_GNUC_INTERNAL
-double _rsvg_css_normalize_length       (const RsvgLength * in, RsvgDrawingCtx * ctx);
+double rsvg_length_normalize (const RsvgLength *length, RsvgDrawingCtx * ctx);
 
 /* This is implemented in rust/src/length.rs */
 G_GNUC_INTERNAL
diff --git a/rsvg-shapes.c b/rsvg-shapes.c
index 134d0fb..484a9f6 100644
--- a/rsvg-shapes.c
+++ b/rsvg-shapes.c
@@ -278,10 +278,10 @@ _rsvg_node_line_draw (RsvgNode * overself, RsvgDrawingCtx * ctx, int dominate)
 
     builder = rsvg_path_builder_new ();
 
-    x1 = _rsvg_css_normalize_length (&self->x1, ctx);
-    y1 = _rsvg_css_normalize_length (&self->y1, ctx);
-    x2 = _rsvg_css_normalize_length (&self->x2, ctx);
-    y2 = _rsvg_css_normalize_length (&self->y2, ctx);
+    x1 = rsvg_length_normalize (&self->x1, ctx);
+    y1 = rsvg_length_normalize (&self->y1, ctx);
+    x2 = rsvg_length_normalize (&self->x2, ctx);
+    y2 = rsvg_length_normalize (&self->y2, ctx);
 
     rsvg_path_builder_move_to (builder, x1, y1);
     rsvg_path_builder_line_to (builder, x2, y2);
@@ -354,16 +354,16 @@ _rsvg_node_rect_draw (RsvgNode * self, RsvgDrawingCtx * ctx, int dominate)
     RsvgPathBuilder *builder;
     RsvgNodeRect *rect = (RsvgNodeRect *) self;
 
-    x = _rsvg_css_normalize_length (&rect->x, ctx);
-    y = _rsvg_css_normalize_length (&rect->y, ctx);
+    x = rsvg_length_normalize (&rect->x, ctx);
+    y = rsvg_length_normalize (&rect->y, ctx);
 
     /* FIXME: negative w/h/rx/ry is an error, per http://www.w3.org/TR/SVG11/shapes.html#RectElement
      * For now we'll just take the absolute value.
      */
-    w = fabs (_rsvg_css_normalize_length (&rect->w, ctx));
-    h = fabs (_rsvg_css_normalize_length (&rect->h, ctx));
-    rx = fabs (_rsvg_css_normalize_length (&rect->rx, ctx));
-    ry = fabs (_rsvg_css_normalize_length (&rect->ry, ctx));
+    w = fabs (rsvg_length_normalize (&rect->w, ctx));
+    h = fabs (rsvg_length_normalize (&rect->h, ctx));
+    rx = fabs (rsvg_length_normalize (&rect->rx, ctx));
+    ry = fabs (rsvg_length_normalize (&rect->ry, ctx));
 
     if (w == 0. || h == 0.)
         return;
@@ -534,9 +534,9 @@ _rsvg_node_circle_draw (RsvgNode * self, RsvgDrawingCtx * ctx, int dominate)
     double cx, cy, r;
     RsvgPathBuilder *builder;
 
-    cx = _rsvg_css_normalize_length (&circle->cx, ctx);
-    cy = _rsvg_css_normalize_length (&circle->cy, ctx);
-    r = _rsvg_css_normalize_length (&circle->r, ctx);
+    cx = rsvg_length_normalize (&circle->cx, ctx);
+    cy = rsvg_length_normalize (&circle->cy, ctx);
+    r = rsvg_length_normalize (&circle->r, ctx);
 
     if (r <= 0)
         return;
@@ -626,10 +626,10 @@ _rsvg_node_ellipse_draw (RsvgNode * self, RsvgDrawingCtx * ctx, int dominate)
     double cx, cy, rx, ry;
     RsvgPathBuilder *builder;
 
-    cx = _rsvg_css_normalize_length (&ellipse->cx, ctx);
-    cy = _rsvg_css_normalize_length (&ellipse->cy, ctx);
-    rx = _rsvg_css_normalize_length (&ellipse->rx, ctx);
-    ry = _rsvg_css_normalize_length (&ellipse->ry, ctx);
+    cx = rsvg_length_normalize (&ellipse->cx, ctx);
+    cy = rsvg_length_normalize (&ellipse->cy, ctx);
+    rx = rsvg_length_normalize (&ellipse->rx, ctx);
+    ry = rsvg_length_normalize (&ellipse->ry, ctx);
 
     if (rx <= 0 || ry <= 0)
         return;
diff --git a/rsvg-structure.c b/rsvg-structure.c
index 666f475..54dfd0a 100644
--- a/rsvg-structure.c
+++ b/rsvg-structure.c
@@ -176,10 +176,10 @@ rsvg_node_use_draw (RsvgNode * self, RsvgDrawingCtx * ctx, int dominate)
     RsvgState *state;
     cairo_matrix_t affine;
     double x, y, w, h;
-    x = _rsvg_css_normalize_length (&use->x, ctx);
-    y = _rsvg_css_normalize_length (&use->y, ctx);
-    w = _rsvg_css_normalize_length (&use->w, ctx);
-    h = _rsvg_css_normalize_length (&use->h, ctx);
+    x = rsvg_length_normalize (&use->x, ctx);
+    y = rsvg_length_normalize (&use->y, ctx);
+    w = rsvg_length_normalize (&use->w, ctx);
+    h = rsvg_length_normalize (&use->h, ctx);
 
     rsvg_state_reinherit_top (ctx, self->state, dominate);
 
@@ -253,10 +253,10 @@ rsvg_node_svg_draw (RsvgNode * self, RsvgDrawingCtx * ctx, int dominate)
     double nx, ny, nw, nh;
     sself = (RsvgNodeSvg *) self;
 
-    nx = _rsvg_css_normalize_length (&sself->x, ctx);
-    ny = _rsvg_css_normalize_length (&sself->y, ctx);
-    nw = _rsvg_css_normalize_length (&sself->w, ctx);
-    nh = _rsvg_css_normalize_length (&sself->h, ctx);
+    nx = rsvg_length_normalize (&sself->x, ctx);
+    ny = rsvg_length_normalize (&sself->y, ctx);
+    nw = rsvg_length_normalize (&sself->w, ctx);
+    nh = rsvg_length_normalize (&sself->h, ctx);
 
     rsvg_state_reinherit_top (ctx, self->state, dominate);
 
diff --git a/rsvg-text.c b/rsvg-text.c
index 1bb7eed..ad0c31a 100644
--- a/rsvg-text.c
+++ b/rsvg-text.c
@@ -282,10 +282,10 @@ _rsvg_node_text_draw (RsvgNode * self, RsvgDrawingCtx * ctx, int dominate)
     RsvgNodeText *text = (RsvgNodeText *) self;
     rsvg_state_reinherit_top (ctx, self->state, dominate);
 
-    x = _rsvg_css_normalize_length (&text->x, ctx);
-    y = _rsvg_css_normalize_length (&text->y, ctx);
-    dx = _rsvg_css_normalize_length (&text->dx, ctx);
-    dy = _rsvg_css_normalize_length (&text->dy, ctx);
+    x = rsvg_length_normalize (&text->x, ctx);
+    y = rsvg_length_normalize (&text->y, ctx);
+    dx = rsvg_length_normalize (&text->dx, ctx);
+    dy = rsvg_length_normalize (&text->dy, ctx);
 
     if (rsvg_current_state (ctx)->text_anchor != TEXT_ANCHOR_START) {
         _rsvg_node_text_length_children (self, ctx, &length, &lastwasspace, FALSE);
@@ -332,8 +332,8 @@ _rsvg_node_text_type_tspan (RsvgNodeText * self, RsvgDrawingCtx * ctx,
     double dx, dy, length = 0;
     rsvg_state_reinherit_top (ctx, self->super.state, 0);
 
-    dx = _rsvg_css_normalize_length (&self->dx, ctx);
-    dy = _rsvg_css_normalize_length (&self->dy, ctx);
+    dx = rsvg_length_normalize (&self->dx, ctx);
+    dy = rsvg_length_normalize (&self->dy, ctx);
 
     if (rsvg_current_state (ctx)->text_anchor != TEXT_ANCHOR_START) {
         gboolean lws = *lastwasspace;
@@ -344,7 +344,7 @@ _rsvg_node_text_type_tspan (RsvgNodeText * self, RsvgDrawingCtx * ctx,
     }
 
     if (self->x_specified) {
-        *x = _rsvg_css_normalize_length (&self->x, ctx);
+        *x = rsvg_length_normalize (&self->x, ctx);
         if (!PANGO_GRAVITY_IS_VERTICAL (rsvg_current_state (ctx)->text_gravity)) {
             *x -= length;
             if (rsvg_current_state (ctx)->text_anchor == TEXT_ANCHOR_MIDDLE)
@@ -356,7 +356,7 @@ _rsvg_node_text_type_tspan (RsvgNodeText * self, RsvgDrawingCtx * ctx,
     *x += dx;
 
     if (self->y_specified) {
-        *y = _rsvg_css_normalize_length (&self->y, ctx);
+        *y = rsvg_length_normalize (&self->y, ctx);
         if (PANGO_GRAVITY_IS_VERTICAL (rsvg_current_state (ctx)->text_gravity)) {
             *y -= length;
             if (rsvg_current_state (ctx)->text_anchor == TEXT_ANCHOR_MIDDLE)
@@ -379,9 +379,9 @@ _rsvg_node_text_length_tspan (RsvgNodeText * self,
         return TRUE;
 
     if (PANGO_GRAVITY_IS_VERTICAL (rsvg_current_state (ctx)->text_gravity))
-        *length += _rsvg_css_normalize_length (&self->dy, ctx);
+        *length += rsvg_length_normalize (&self->dy, ctx);
     else
-        *length += _rsvg_css_normalize_length (&self->dx, ctx);
+        *length += rsvg_length_normalize (&self->dx, ctx);
 
     return _rsvg_node_text_length_children (&self->super, ctx, length,
                                              lastwasspace, usetextonly);
@@ -545,7 +545,7 @@ rsvg_text_create_layout (RsvgDrawingCtx * ctx, const char *text, PangoContext *
     pango_font_description_free (font_desc);
 
     attr_list = pango_attr_list_new ();
-    attribute = pango_attr_letter_spacing_new (_rsvg_css_normalize_length (&state->letter_spacing, ctx) * 
PANGO_SCALE);
+    attribute = pango_attr_letter_spacing_new (rsvg_length_normalize (&state->letter_spacing, ctx) * 
PANGO_SCALE);
     attribute->start_index = 0;
     attribute->end_index = G_MAXINT;
     pango_attr_list_insert (attr_list, attribute); 
diff --git a/rust/src/drawing_ctx.rs b/rust/src/drawing_ctx.rs
index 2a16d82..915e717 100644
--- a/rust/src/drawing_ctx.rs
+++ b/rust/src/drawing_ctx.rs
@@ -1,11 +1,31 @@
 pub enum RsvgDrawingCtx {}
 
 extern "C" {
+    fn rsvg_drawing_ctx_get_dpi (draw_ctx: *const RsvgDrawingCtx,
+                                 out_dpi_x: *mut f64,
+                                 out_dpi_y: *mut f64);
+
+    fn rsvg_drawing_ctx_get_normalized_font_size (draw_ctx: *const RsvgDrawingCtx) -> f64;
+
     fn rsvg_drawing_ctx_get_view_box_size (draw_ctx: *const RsvgDrawingCtx,
                                            out_x: *mut f64,
                                            out_y: *mut f64);
 }
 
+pub fn get_dpi (draw_ctx: *const RsvgDrawingCtx) -> (f64, f64) {
+    let mut dpi_x: f64 = 0.0;
+    let mut dpi_y: f64 = 0.0;
+
+    unsafe { rsvg_drawing_ctx_get_dpi (draw_ctx, &mut dpi_x, &mut dpi_y); }
+
+    (dpi_x, dpi_y)
+}
+
+
+pub fn get_normalized_font_size (draw_ctx: *const RsvgDrawingCtx) -> f64 {
+    unsafe { rsvg_drawing_ctx_get_normalized_font_size (draw_ctx) }
+}
+
 pub fn get_view_box_size (draw_ctx: *const RsvgDrawingCtx) -> (f64, f64) {
     let mut w: f64 = 0.0;
     let mut h: f64 = 0.0;
diff --git a/rust/src/length.rs b/rust/src/length.rs
index 6946b9a..16d0f05 100644
--- a/rust/src/length.rs
+++ b/rust/src/length.rs
@@ -1,9 +1,13 @@
 extern crate libc;
 extern crate glib;
 
+use std::f64;
+
 use self::glib::translate::*;
 
 use strtod::*;
+use drawing_ctx;
+use drawing_ctx::RsvgDrawingCtx;
 
 /* Keep this in sync with ../../rsvg-private.h:LengthUnit */
 #[repr(C)]
@@ -40,8 +44,6 @@ pub struct RsvgLength {
     dir: LengthDir
 }
 
-pub enum RsvgDrawingCtx {}
-
 const POINTS_PER_INCH: f64 = 72.0;
 const CM_PER_INCH:     f64 = 2.54;
 const MM_PER_INCH:     f64 = 25.4;
@@ -79,7 +81,7 @@ pub extern fn rsvg_length_parse (string: *const libc::c_char, dir: LengthDir) ->
  * need to know if they are horizontal/vertical/both.  For example,
  * a some_object.width="50%" is 50% with respect to the current
  * viewport's width.  In this case, the @dir argument is used
- * when _rsvg_css_normalize_length() needs to know to what the
+ * inside RsvgLength::normalize(), when it needs to know to what the
  * length refers.
  */
 impl RsvgLength {
@@ -157,6 +159,46 @@ impl RsvgLength {
         }
     }
 
+    pub fn normalize (&self, draw_ctx: *const RsvgDrawingCtx) -> f64 {
+        match self.unit {
+            LengthUnit::Default => {
+                self.length
+            },
+
+            LengthUnit::Percent => {
+                let (width, height) = drawing_ctx::get_view_box_size (draw_ctx);
+
+                match self.dir {
+                    LengthDir::Horizontal => { self.length * width },
+                    LengthDir::Vertical   => { self.length * height },
+                    LengthDir::Both       => { self.length * viewport_percentage (width, height) }
+                }
+            },
+
+            LengthUnit::FontEm => {
+                self.length * drawing_ctx::get_normalized_font_size (draw_ctx)
+            },
+
+            LengthUnit::FontEx => {
+                self.length * drawing_ctx::get_normalized_font_size (draw_ctx) / 2.0
+            },
+
+            LengthUnit::Inch => {
+                let (dpi_x, dpi_y) = drawing_ctx::get_dpi (draw_ctx);
+
+                match self.dir {
+                    LengthDir::Horizontal => { self.length * dpi_x },
+                    LengthDir::Vertical   => { self.length * dpi_y },
+                    LengthDir::Both       => { self.length * viewport_percentage (dpi_x, dpi_y) }
+                }
+            },
+
+            // FIXME: these are pending: 
https://www.w3.org/TR/2008/REC-CSS2-20080411/fonts.html#propdef-font-size
+            LengthUnit::RelativeLarger |
+            LengthUnit::RelativeSmaller => { 0.0 }
+        }
+    }
+
     pub fn hand_normalize (&self,
                            pixels_per_inch: f64,
                            width_or_height: f64,
@@ -177,9 +219,23 @@ impl RsvgLength {
     }
 }
 
+fn viewport_percentage (x: f64, y: f64) -> f64 {
+    /* https://www.w3.org/TR/SVG/coords.html#Units
+     *
+     * "For any other length value expressed as a percentage of the viewport, the
+     * percentage is calculated as the specified percentage of
+     * sqrt((actual-width)**2 + (actual-height)**2))/sqrt(2)."
+     */
+    return (x * x + y * y).sqrt () / f64::consts::SQRT_2;
+}
+
 #[no_mangle]
 pub extern fn rsvg_length_normalize (raw_length: *const RsvgLength, draw_ctx: *const RsvgDrawingCtx) -> f64 {
-    unimplemented! ();
+    assert! (!raw_length.is_null ());
+
+    let length: &RsvgLength = unsafe { &*raw_length };
+
+    length.normalize (draw_ctx)
 }
 
 #[no_mangle]


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