[librsvg] bgo#340047 - Add support for the "baseline-shift" text attribute



commit e804fb1adcf564ce4bae661cc595a8d4df55efd3
Author: Menner <mik gmx org>
Date:   Sat Jan 2 09:42:53 2016 +0100

    bgo#340047 - Add support for the "baseline-shift" text attribute
    
    This commit adds support for the baseline-shift attribute for tags
    "sub/super/baseline".  We don't support percentages of the font size
    or explicit lengths yet.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=340047

 rsvg-css.c                                  |   24 ++++++++++++++-
 rsvg-private.h                              |    2 +
 rsvg-styles.c                               |   21 +++++++++++++
 rsvg-styles.h                               |    2 +
 rsvg-text.c                                 |   16 ++++++----
 tests/fixtures/reftests/bugs/340047-ref.png |  Bin 0 -> 4855 bytes
 tests/fixtures/reftests/bugs/340047.svg     |   43 +++++++++++++++++++++++++++
 7 files changed, 101 insertions(+), 7 deletions(-)
---
diff --git a/rsvg-css.c b/rsvg-css.c
index a7cd199..5b359a2 100644
--- a/rsvg-css.c
+++ b/rsvg-css.c
@@ -204,6 +204,7 @@ _rsvg_css_parse_length (const char *str)
     return out;
 }
 
+/* Recursive evaluation of all parent elements regarding absolute font size */
 double
 _rsvg_css_normalize_font_size (RsvgState * state, RsvgDrawingCtx * ctx)
 {
@@ -213,7 +214,7 @@ _rsvg_css_normalize_font_size (RsvgState * state, RsvgDrawingCtx * ctx)
     case 'p':
     case 'm':
     case 'x':
-        parent= rsvg_state_parent (state);
+        parent = rsvg_state_parent (state);
         if (parent) {
             double parent_size;
             parent_size = _rsvg_css_normalize_font_size (parent, ctx);
@@ -263,6 +264,27 @@ _rsvg_css_normalize_length (const RsvgLength * in, RsvgDrawingCtx * ctx, char di
     return 0;
 }
 
+/* Recursive evaluation of all parent elements regarding basline-shift */
+double
+_rsvg_css_accumulate_baseline_shift (RsvgState * state, RsvgDrawingCtx * ctx)
+{
+    RsvgState *parent;
+    double shift = 0.;
+
+    parent = rsvg_state_parent (state);
+    if (parent) {
+        if (state->has_baseline_shift) {
+            double parent_font_size;
+            parent_font_size = _rsvg_css_normalize_font_size (parent, ctx); /* font size from here */
+            shift = parent_font_size * state->baseline_shift;
+        }
+        shift += _rsvg_css_accumulate_baseline_shift (parent, ctx); /* baseline-shift for parent element */
+    }
+
+    return shift;
+}
+
+
 double
 _rsvg_css_hand_normalize_length (const RsvgLength * in, gdouble pixels_per_inch,
                                  gdouble width_or_height, gdouble font_size)
diff --git a/rsvg-private.h b/rsvg-private.h
index 17457f9..6921bc3 100644
--- a/rsvg-private.h
+++ b/rsvg-private.h
@@ -394,6 +394,8 @@ double _rsvg_css_hand_normalize_length  (const RsvgLength * in, gdouble pixels_p
                                          gdouble width_or_height, gdouble font_size);
 double _rsvg_css_normalize_font_size    (RsvgState * state, RsvgDrawingCtx * ctx);
 G_GNUC_INTERNAL
+double _rsvg_css_accumulate_baseline_shift (RsvgState * state, RsvgDrawingCtx * ctx);
+G_GNUC_INTERNAL
 RsvgLength _rsvg_css_parse_length (const char *str);
 G_GNUC_INTERNAL
 void _rsvg_push_view_box    (RsvgDrawingCtx * ctx, double w, double h);
diff --git a/rsvg-styles.c b/rsvg-styles.c
index 9a918ee..6aea884 100644
--- a/rsvg-styles.c
+++ b/rsvg-styles.c
@@ -118,6 +118,7 @@ rsvg_state_init (RsvgState * state)
     cairo_matrix_init_identity (&state->personal_affine);
     state->mask = NULL;
     state->opacity = 0xff;
+    state->baseline_shift = 0.;
     state->fill = rsvg_paint_server_parse (NULL, "#000");
     state->fill_opacity = 0xff;
     state->stroke_opacity = 0xff;
@@ -153,6 +154,7 @@ rsvg_state_init (RsvgState * state)
     state->middleMarker = NULL;
     state->endMarker = NULL;
 
+    state->has_baseline_shift = FALSE;
     state->has_current_color = FALSE;
     state->has_flood_color = FALSE;
     state->has_flood_opacity = FALSE;
@@ -253,6 +255,8 @@ rsvg_state_inherit_run (RsvgState * dst, const RsvgState * src,
 {
     gint i;
 
+    if (function (dst->has_baseline_shift, src->has_baseline_shift))
+        dst->baseline_shift = src->baseline_shift;
     if (function (dst->has_current_color, src->has_current_color))
         dst->current_color = src->current_color;
     if (function (dst->has_flood_color, src->has_flood_color))
@@ -513,6 +517,22 @@ rsvg_parse_style_pair (RsvgHandle * ctx,
     } else if (g_str_equal (name, "mask")) {
         g_free (state->mask);
         state->mask = rsvg_get_url_string (value);
+    } else if (g_str_equal (name, "baseline-shift")) {
+        /* These values come from Inkscape's SP_CSS_BASELINE_SHIFT_(SUB/SUPER/BASELINE);
+         * see sp_style_merge_baseline_shift_from_parent()
+         */
+        if (g_str_equal (value, "sub")) {
+           state->has_baseline_shift = TRUE;
+           state->baseline_shift = -0.2;
+        } else if (g_str_equal (value, "super")) {
+           state->has_baseline_shift = TRUE;
+           state->baseline_shift = 0.4;
+        } else if (g_str_equal (value, "baseline")) {
+           state->has_baseline_shift = TRUE;
+           state->baseline_shift = 0.;
+        } else {
+          g_warning ("value \'%s\' for attribute \'baseline-shift\' is not supported; only 'sub', 'super', 
and 'baseline' are supported\n", value);
+        }
     } else if (g_str_equal (name, "clip-path")) {
         g_free (state->clip_path);
         state->clip_path = rsvg_get_url_string (value);
@@ -862,6 +882,7 @@ void
 rsvg_parse_style_pairs (RsvgHandle * ctx, RsvgState * state, RsvgPropertyBag * atts)
 {
     rsvg_lookup_parse_style_pair (ctx, state, "a:adobe-blending-mode", atts);
+    rsvg_lookup_parse_style_pair (ctx, state, "baseline-shift", atts);
     rsvg_lookup_parse_style_pair (ctx, state, "clip-path", atts);
     rsvg_lookup_parse_style_pair (ctx, state, "clip-rule", atts);
     rsvg_lookup_parse_style_pair (ctx, state, "color", atts);
diff --git a/rsvg-styles.h b/rsvg-styles.h
index bd2b5cf..a044d3f 100644
--- a/rsvg-styles.h
+++ b/rsvg-styles.h
@@ -83,6 +83,8 @@ struct _RsvgState {
     char *mask;
     char *clip_path;
     guint8 opacity;             /* 0..255 */
+    double baseline_shift;
+    gboolean has_baseline_shift;
 
     RsvgPaintServer *fill;
     gboolean has_fill_server;
diff --git a/rsvg-text.c b/rsvg-text.c
index 6fb2007..52e52c3 100644
--- a/rsvg-text.c
+++ b/rsvg-text.c
@@ -163,6 +163,7 @@ static void
                             gdouble * x, gdouble * y, gboolean * lastwasspace,
                             gboolean usetextonly);
 
+/* This function is responsible of selecting render for a text element including its children and giving it 
the drawing context */
 static void
 _rsvg_node_text_type_children (RsvgNode * self, RsvgDrawingCtx * ctx,
                                gdouble * x, gdouble * y, gboolean * lastwasspace,
@@ -598,7 +599,8 @@ rsvg_text_render_text (RsvgDrawingCtx * ctx, const char *text, gdouble * x, gdou
     PangoLayout *layout;
     PangoLayoutIter *iter;
     RsvgState *state;
-    gint w, h, offsetX, offsetY;
+    gint w, h;
+    double offset_x, offset_y, offset;
 
     state = rsvg_current_state (ctx);
 
@@ -610,15 +612,17 @@ rsvg_text_render_text (RsvgDrawingCtx * ctx, const char *text, gdouble * x, gdou
     layout = rsvg_text_create_layout (ctx, state, text, context);
     pango_layout_get_size (layout, &w, &h);
     iter = pango_layout_get_iter (layout);
+    offset = pango_layout_iter_get_baseline (iter) / (double) PANGO_SCALE;
+    offset += _rsvg_css_accumulate_baseline_shift (state, ctx);
     if (PANGO_GRAVITY_IS_VERTICAL (state->text_gravity)) {
-        offsetX = -pango_layout_iter_get_baseline (iter) / (double)PANGO_SCALE;
-        offsetY = 0;
+        offset_x = -offset;
+        offset_y = 0;
     } else {
-        offsetX = 0;
-        offsetY = pango_layout_iter_get_baseline (iter) / (double)PANGO_SCALE;
+        offset_x = 0;
+        offset_y = offset;
     }
     pango_layout_iter_free (iter);
-    ctx->render->render_pango_layout (ctx, layout, *x - offsetX, *y - offsetY);
+    ctx->render->render_pango_layout (ctx, layout, *x - offset_x, *y - offset_y);
     if (PANGO_GRAVITY_IS_VERTICAL (state->text_gravity))
         *y += w / (double)PANGO_SCALE;
     else
diff --git a/tests/fixtures/reftests/bugs/340047-ref.png b/tests/fixtures/reftests/bugs/340047-ref.png
new file mode 100644
index 0000000..5895772
Binary files /dev/null and b/tests/fixtures/reftests/bugs/340047-ref.png differ
diff --git a/tests/fixtures/reftests/bugs/340047.svg b/tests/fixtures/reftests/bugs/340047.svg
new file mode 100644
index 0000000..4e0ee31
--- /dev/null
+++ b/tests/fixtures/reftests/bugs/340047.svg
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd";>
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/";
+   xmlns:cc="http://creativecommons.org/ns#";
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#";
+   xmlns:svg="http://www.w3.org/2000/svg";
+   xmlns="http://www.w3.org/2000/svg";
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd";
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape";
+   width="744.09448819"
+   height="1052.3622047"
+   id="svg2"
+   version="1.1"
+   inkscape:version="0.47 r22583"
+   sodipodi:docname="New document 1">
+
+    <g fill = "navy">
+        <text x = "10" y = "25" font-size = "20">
+            <tspan>
+                e = mc
+                <tspan baseline-shift = "super">
+                    2
+                </tspan>
+            </tspan>
+            <tspan x = "10" y = "60">
+                T
+                <tspan baseline-shift = "sub">
+                    i+2
+                </tspan>
+                =T
+                <tspan baseline-shift = "sub">
+                    i
+                </tspan>
+                + T
+                <tspan baseline-shift = "sub">
+                    i+1
+                </tspan>
+            </tspan>
+        </text>
+    </g>
+</svg>


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