[librsvg] Support basic vertical writing (Gnome Bug #664533)
- From: Christian Persch <chpe src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [librsvg] Support basic vertical writing (Gnome Bug #664533)
- Date: Mon, 28 Nov 2011 12:48:00 +0000 (UTC)
commit 1af28cd186ace50c87ce8d90203c52f50ed45f83
Author: KUROSAWA Takeshi <taken spc gmail com>
Date: Sat Nov 26 00:11:38 2011 +0900
Support basic vertical writing (Gnome Bug #664533)
Support vertical writing text (writing-mode: tb-rl | tb)
http://www.w3.org/TR/SVG11/text.html#SettingInlineProgressionDirection
Bump pango dependency to 1.16.0 to use its vertical text APIs.
Currently, we ignore both glyph-orientation-vertical and
glyph-orientation-horizontal.
configure.in | 2 +-
rsvg-cairo-draw.c | 30 +++++++++++---
rsvg-styles.c | 21 +++++++---
rsvg-styles.h | 2 +
rsvg-text.c | 111 ++++++++++++++++++++++++++++++++++++++---------------
5 files changed, 122 insertions(+), 44 deletions(-)
---
diff --git a/configure.in b/configure.in
index 4595c99..85bf155 100644
--- a/configure.in
+++ b/configure.in
@@ -34,7 +34,7 @@ GLIB_REQUIRED=2.12.0
GIO_REQUIRED=2.24.0
LIBXML_REQUIRED=2.7.0
CAIRO_REQUIRED=1.2.0
-PANGOCAIRO_REQUIRED=1.10.0
+PANGOCAIRO_REQUIRED=1.16.0
GDK_PIXBUF_REQUIRED=1.3.7
GTK2_REQUIRED=2.16.0
GTK3_REQUIRED=3.0.0
diff --git a/rsvg-cairo-draw.c b/rsvg-cairo-draw.c
index c8dc6d3..0029a03 100644
--- a/rsvg-cairo-draw.c
+++ b/rsvg-cairo-draw.c
@@ -390,6 +390,8 @@ rsvg_cairo_render_pango_layout (RsvgDrawingCtx * ctx, PangoLayout * layout, doub
RsvgState *state = rsvg_current_state (ctx);
PangoRectangle ink;
RsvgBbox bbox;
+ PangoGravity gravity = pango_context_get_gravity (pango_layout_get_context (layout));
+ double rotation;
cairo_set_antialias (render->cr, state->text_rendering_type);
@@ -398,13 +400,22 @@ rsvg_cairo_render_pango_layout (RsvgDrawingCtx * ctx, PangoLayout * layout, doub
pango_layout_get_extents (layout, &ink, NULL);
rsvg_bbox_init (&bbox, &state->affine);
- bbox.rect.x = x + ink.x / (double)PANGO_SCALE;
- bbox.rect.y = y + ink.y / (double)PANGO_SCALE;
- bbox.rect.width = ink.width / (double)PANGO_SCALE;
- bbox.rect.height = ink.height / (double)PANGO_SCALE;
+ if (PANGO_GRAVITY_IS_VERTICAL (gravity)) {
+ bbox.rect.x = x + (ink.x - ink.height) / (double)PANGO_SCALE;
+ bbox.rect.y = y + ink.y / (double)PANGO_SCALE;
+ bbox.rect.width = ink.height / (double)PANGO_SCALE;
+ bbox.rect.height = ink.width / (double)PANGO_SCALE;
+ } else {
+ bbox.rect.x = x + ink.x / (double)PANGO_SCALE;
+ bbox.rect.y = y + ink.y / (double)PANGO_SCALE;
+ bbox.rect.width = ink.width / (double)PANGO_SCALE;
+ bbox.rect.height = ink.height / (double)PANGO_SCALE;
+ }
bbox.virgin = 0;
+ rotation = pango_gravity_to_rotation (gravity);
if (state->fill) {
+ cairo_save (render->cr);
cairo_move_to (render->cr, x, y);
rsvg_bbox_insert (&render->bbox, &bbox);
_set_source_rsvg_paint_server (ctx,
@@ -412,14 +423,16 @@ rsvg_cairo_render_pango_layout (RsvgDrawingCtx * ctx, PangoLayout * layout, doub
state->fill,
state->fill_opacity,
bbox, rsvg_current_state (ctx)->current_color);
-
+ if (rotation != 0.)
+ cairo_rotate (render->cr, -rotation);
pango_cairo_show_layout (render->cr, layout);
+ cairo_restore (render->cr);
}
if (state->stroke) {
+ cairo_save (render->cr);
cairo_move_to (render->cr, x, y);
rsvg_bbox_insert (&render->bbox, &bbox);
- pango_cairo_layout_path (render->cr, layout);
_set_source_rsvg_paint_server (ctx,
state->current_color,
@@ -427,6 +440,10 @@ rsvg_cairo_render_pango_layout (RsvgDrawingCtx * ctx, PangoLayout * layout, doub
state->stroke_opacity,
bbox, rsvg_current_state (ctx)->current_color);
+ if (rotation != 0.)
+ cairo_rotate (render->cr, -rotation);
+ pango_cairo_layout_path (render->cr, layout);
+
cairo_set_line_width (render->cr, _rsvg_css_normalize_length (&state->stroke_width, ctx, 'h'));
cairo_set_miter_limit (render->cr, state->miter_limit);
cairo_set_line_cap (render->cr, (cairo_line_cap_t) state->cap);
@@ -434,6 +451,7 @@ rsvg_cairo_render_pango_layout (RsvgDrawingCtx * ctx, PangoLayout * layout, doub
cairo_set_dash (render->cr, state->dash.dash, state->dash.n_dash,
_rsvg_css_normalize_length (&state->dash.offset, ctx, 'o'));
cairo_stroke (render->cr);
+ cairo_restore (render->cr);
}
}
diff --git a/rsvg-styles.c b/rsvg-styles.c
index d137cd6..dead491 100644
--- a/rsvg-styles.c
+++ b/rsvg-styles.c
@@ -142,6 +142,7 @@ rsvg_state_init (RsvgState * state)
state->font_weight = PANGO_WEIGHT_NORMAL;
state->font_stretch = PANGO_STRETCH_NORMAL;
state->text_dir = PANGO_DIRECTION_LTR;
+ state->text_gravity = PANGO_GRAVITY_SOUTH;
state->unicode_bidi = UNICODE_BIDI_NORMAL;
state->text_anchor = TEXT_ANCHOR_START;
state->letter_spacing = _rsvg_css_parse_length ("0.0");
@@ -181,6 +182,7 @@ rsvg_state_init (RsvgState * state)
state->has_font_stretch = FALSE;
state->has_font_decor = FALSE;
state->has_text_dir = FALSE;
+ state->has_text_gravity = FALSE;
state->has_unicode_bidi = FALSE;
state->has_text_anchor = FALSE;
state->has_letter_spacing = FALSE;
@@ -302,6 +304,8 @@ rsvg_state_inherit_run (RsvgState * dst, const RsvgState * src,
dst->font_decor = src->font_decor;
if (function (dst->has_text_dir, src->has_text_dir))
dst->text_dir = src->text_dir;
+ if (function (dst->has_text_gravity, src->has_text_gravity))
+ dst->text_gravity = src->text_gravity;
if (function (dst->has_unicode_bidi, src->has_unicode_bidi))
dst->unicode_bidi = src->unicode_bidi;
if (function (dst->has_text_anchor, src->has_text_anchor))
@@ -715,17 +719,22 @@ rsvg_parse_style_pair (RsvgHandle * ctx,
/* TODO: these aren't quite right... */
state->has_text_dir = TRUE;
+ state->has_text_gravity = TRUE;
if (g_str_equal (value, "inherit")) {
state->text_dir = PANGO_DIRECTION_LTR;
state->has_text_dir = FALSE;
- } else if (g_str_equal (value, "lr-tb") || g_str_equal (value, "tb"))
- state->text_dir = PANGO_DIRECTION_TTB_LTR;
- else if (g_str_equal (value, "rl"))
+ state->text_gravity = PANGO_GRAVITY_SOUTH;
+ state->has_text_gravity = FALSE;
+ } else if (g_str_equal (value, "lr-tb") || g_str_equal (value, "lr")) {
+ state->text_dir = PANGO_DIRECTION_LTR;
+ state->text_gravity = PANGO_GRAVITY_SOUTH;
+ } else if (g_str_equal (value, "rl-tb") || g_str_equal (value, "rl")) {
state->text_dir = PANGO_DIRECTION_RTL;
- else if (g_str_equal (value, "tb-rl") || g_str_equal (value, "rl-tb"))
- state->text_dir = PANGO_DIRECTION_TTB_RTL;
- else
+ state->text_gravity = PANGO_GRAVITY_SOUTH;
+ } else if (g_str_equal (value, "tb-rl") || g_str_equal (value, "tb")) {
state->text_dir = PANGO_DIRECTION_LTR;
+ state->text_gravity = PANGO_GRAVITY_EAST;
+ }
} else if (g_str_equal (name, "text-anchor")) {
state->has_text_anchor = TRUE;
if (g_str_equal (value, "inherit")) {
diff --git a/rsvg-styles.h b/rsvg-styles.h
index 248d8d7..87c36eb 100644
--- a/rsvg-styles.h
+++ b/rsvg-styles.h
@@ -129,6 +129,8 @@ struct _RsvgState {
gboolean has_font_decor;
PangoDirection text_dir;
gboolean has_text_dir;
+ PangoGravity text_gravity;
+ gboolean has_text_gravity;
UnicodeBidi unicode_bidi;
gboolean has_unicode_bidi;
TextAnchor text_anchor;
diff --git a/rsvg-text.c b/rsvg-text.c
index 7417054..03d9201 100644
--- a/rsvg-text.c
+++ b/rsvg-text.c
@@ -216,7 +216,7 @@ static gdouble rsvg_text_length_text_as_string (RsvgDrawingCtx * ctx, const char
static int
_rsvg_node_text_length_children (RsvgNode * self, RsvgDrawingCtx * ctx,
- gdouble * x, gboolean * lastwasspace,
+ gdouble * length, gboolean * lastwasspace,
gboolean usetextonly)
{
guint i;
@@ -230,22 +230,22 @@ _rsvg_node_text_length_children (RsvgNode * self, RsvgDrawingCtx * ctx,
if (type == RSVG_NODE_TYPE_CHARS) {
RsvgNodeChars *chars = (RsvgNodeChars *) node;
GString *str = _rsvg_text_chomp (rsvg_current_state (ctx), chars->contents, lastwasspace);
- *x += rsvg_text_length_text_as_string (ctx, str->str);
+ *length += rsvg_text_length_text_as_string (ctx, str->str);
g_string_free (str, TRUE);
} else {
if (usetextonly) {
- out = _rsvg_node_text_length_children(node, ctx, x,
+ out = _rsvg_node_text_length_children(node, ctx, length,
lastwasspace,
usetextonly);
} else {
if (type == RSVG_NODE_TYPE_TSPAN) {
RsvgNodeText *tspan = (RsvgNodeText *) node;
- out = _rsvg_node_text_length_tspan (tspan, ctx, x,
+ out = _rsvg_node_text_length_tspan (tspan, ctx, length,
lastwasspace,
usetextonly);
} else if (type == RSVG_NODE_TYPE_TREF) {
RsvgNodeTref *tref = (RsvgNodeTref *) node;
- out = _rsvg_node_text_length_tref (tref, ctx, x,
+ out = _rsvg_node_text_length_tref (tref, ctx, length,
lastwasspace,
usetextonly);
}
@@ -262,24 +262,36 @@ _rsvg_node_text_length_children (RsvgNode * self, RsvgDrawingCtx * ctx,
static void
_rsvg_node_text_draw (RsvgNode * self, RsvgDrawingCtx * ctx, int dominate)
{
- double x, y;
+ double x, y, dx, dy, length = 0;
gboolean lastwasspace = TRUE;
RsvgNodeText *text = (RsvgNodeText *) self;
rsvg_state_reinherit_top (ctx, self->state, dominate);
x = _rsvg_css_normalize_length (&text->x, ctx, 'h');
y = _rsvg_css_normalize_length (&text->y, ctx, 'v');
- x += _rsvg_css_normalize_length (&text->dx, ctx, 'h');
- y += _rsvg_css_normalize_length (&text->dy, ctx, 'v');
+ dx = _rsvg_css_normalize_length (&text->dx, ctx, 'h');
+ dy = _rsvg_css_normalize_length (&text->dy, ctx, 'v');
if (rsvg_current_state (ctx)->text_anchor != TEXT_ANCHOR_START) {
- double length = 0;
_rsvg_node_text_length_children (self, ctx, &length, &lastwasspace, FALSE);
+ if (rsvg_current_state (ctx)->text_anchor == TEXT_ANCHOR_MIDDLE)
+ length /= 2;
+ }
+ if (PANGO_GRAVITY_IS_VERTICAL (rsvg_current_state (ctx)->text_gravity)) {
+ y -= length;
+ if (rsvg_current_state (ctx)->text_anchor == TEXT_ANCHOR_MIDDLE)
+ dy /= 2;
if (rsvg_current_state (ctx)->text_anchor == TEXT_ANCHOR_END)
- x -= length;
+ dy = 0;
+ } else {
+ x -= length;
if (rsvg_current_state (ctx)->text_anchor == TEXT_ANCHOR_MIDDLE)
- x -= length / 2;
+ dx /= 2;
+ if (rsvg_current_state (ctx)->text_anchor == TEXT_ANCHOR_END)
+ dx = 0;
}
+ x += dx;
+ y += dy;
lastwasspace = TRUE;
_rsvg_node_text_type_children (self, ctx, &x, &y, &lastwasspace, FALSE);
@@ -302,37 +314,62 @@ _rsvg_node_text_type_tspan (RsvgNodeText * self, RsvgDrawingCtx * ctx,
gdouble * x, gdouble * y, gboolean * lastwasspace,
gboolean usetextonly)
{
+ double dx, dy, length = 0;
rsvg_state_reinherit_top (ctx, self->super.state, 0);
+ dx = _rsvg_css_normalize_length (&self->dx, ctx, 'h');
+ dy = _rsvg_css_normalize_length (&self->dy, ctx, 'v');
+
+ if (rsvg_current_state (ctx)->text_anchor != TEXT_ANCHOR_START) {
+ gboolean lws = *lastwasspace;
+ _rsvg_node_text_length_children (&self->super, ctx, &length, &lws,
+ usetextonly);
+ if (rsvg_current_state (ctx)->text_anchor == TEXT_ANCHOR_MIDDLE)
+ length /= 2;
+ }
+
if (self->x.factor != 'n') {
*x = _rsvg_css_normalize_length (&self->x, ctx, 'h');
- if (rsvg_current_state (ctx)->text_anchor != TEXT_ANCHOR_START) {
- double length = 0;
- gboolean lws = *lastwasspace;
- _rsvg_node_text_length_children (&self->super, ctx, &length, &lws,
- usetextonly);
- if (rsvg_current_state (ctx)->text_anchor == TEXT_ANCHOR_END)
- *x -= length;
+ if (!PANGO_GRAVITY_IS_VERTICAL (rsvg_current_state (ctx)->text_gravity)) {
+ *x -= length;
if (rsvg_current_state (ctx)->text_anchor == TEXT_ANCHOR_MIDDLE)
- *x -= length / 2;
+ dx /= 2;
+ if (rsvg_current_state (ctx)->text_anchor == TEXT_ANCHOR_END)
+ dx = 0;
}
}
- if (self->y.factor != 'n')
+ *x += dx;
+
+ if (self->y.factor != 'n') {
*y = _rsvg_css_normalize_length (&self->y, ctx, 'v');
- *x += _rsvg_css_normalize_length (&self->dx, ctx, 'h');
- *y += _rsvg_css_normalize_length (&self->dy, ctx, 'v');
+ if (PANGO_GRAVITY_IS_VERTICAL (rsvg_current_state (ctx)->text_gravity)) {
+ *y -= length;
+ if (rsvg_current_state (ctx)->text_anchor == TEXT_ANCHOR_MIDDLE)
+ dy /= 2;
+ if (rsvg_current_state (ctx)->text_anchor == TEXT_ANCHOR_END)
+ dy = 0;
+ }
+ }
+ *y += dy;
_rsvg_node_text_type_children (&self->super, ctx, x, y, lastwasspace,
usetextonly);
}
static int
-_rsvg_node_text_length_tspan (RsvgNodeText * self, RsvgDrawingCtx * ctx, gdouble * x,
+_rsvg_node_text_length_tspan (RsvgNodeText * self,
+ RsvgDrawingCtx * ctx, gdouble * length,
gboolean * lastwasspace, gboolean usetextonly)
{
if (self->x.factor != 'n' || self->y.factor != 'n')
return TRUE;
- return _rsvg_node_text_length_children (&self->super, ctx, x, lastwasspace,
- usetextonly);
+
+ if (PANGO_GRAVITY_IS_VERTICAL (rsvg_current_state (ctx)->text_gravity))
+ *length += _rsvg_css_normalize_length (&self->dy, ctx, 'v');
+ else
+ *length += _rsvg_css_normalize_length (&self->dx, ctx, 'h');
+
+ return _rsvg_node_text_length_children (&self->super, ctx, length,
+ lastwasspace, usetextonly);
}
static void
@@ -448,6 +485,9 @@ rsvg_text_create_layout (RsvgDrawingCtx * ctx,
if (state->unicode_bidi == UNICODE_BIDI_OVERRIDE || state->unicode_bidi == UNICODE_BIDI_EMBED)
pango_context_set_base_dir (context, state->text_dir);
+ if (PANGO_GRAVITY_IS_VERTICAL (state->text_gravity))
+ pango_context_set_base_gravity (context, state->text_gravity);
+
font_desc = pango_font_description_copy (pango_context_get_font_description (context));
if (state->font_family)
@@ -495,8 +535,7 @@ rsvg_text_create_layout (RsvgDrawingCtx * ctx,
else
pango_layout_set_text (layout, NULL, 0);
- pango_layout_set_alignment (layout, (state->text_dir == PANGO_DIRECTION_LTR ||
- state->text_dir == PANGO_DIRECTION_TTB_LTR) ?
+ pango_layout_set_alignment (layout, (state->text_dir == PANGO_DIRECTION_LTR) ?
PANGO_ALIGN_LEFT : PANGO_ALIGN_RIGHT);
return layout;
@@ -528,7 +567,7 @@ rsvg_text_render_text (RsvgDrawingCtx * ctx, const char *text, gdouble * x, gdou
PangoLayout *layout;
PangoLayoutIter *iter;
RsvgState *state;
- gint w, h, baseline;
+ gint w, h, offsetX, offsetY;
state = rsvg_current_state (ctx);
@@ -540,10 +579,20 @@ 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);
- baseline = pango_layout_iter_get_baseline (iter) / (double)PANGO_SCALE;
+ if (PANGO_GRAVITY_IS_VERTICAL (state->text_gravity)) {
+ offsetX = -pango_layout_iter_get_baseline (iter) / (double)PANGO_SCALE;
+ offsetY = 0;
+ } else {
+ offsetX = 0;
+ offsetY = pango_layout_iter_get_baseline (iter) / (double)PANGO_SCALE;
+ }
pango_layout_iter_free (iter);
- ctx->render->render_pango_layout (ctx, layout, *x, *y - baseline);
- *x += w / (double)PANGO_SCALE;
+ ctx->render->render_pango_layout (ctx, layout, *x - offsetX, *y - offsetY);
+ if (PANGO_GRAVITY_IS_VERTICAL (state->text_gravity))
+ *y += w / (double)PANGO_SCALE;
+ else
+ *x += w / (double)PANGO_SCALE;
+
g_object_unref (layout);
g_object_unref (context);
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]