Commit e804fb1a authored by Menner's avatar Menner Committed by Federico Mena Quintero

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
parent 1fc06fe6
......@@ -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)
......
......@@ -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);
......
......@@ -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);
......
......@@ -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;
......
......@@ -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
......
<?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>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment