[librsvg: 1/12] state: move direction and writing mode to rust
- From: Federico Mena Quintero <federico src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [librsvg: 1/12] state: move direction and writing mode to rust
- Date: Tue, 24 Apr 2018 23:15:09 +0000 (UTC)
commit dbb23aae044f72d541db73fb9fb1aef2084df46b
Author: Paolo Borelli <pborelli gnome org>
Date: Sat Apr 21 10:24:21 2018 +0200
state: move direction and writing mode to rust
Note that the logic used to set the direction on the pango context
is changed: in the C code, whichever of the two properties was set
last defined text_dir. Instead now we keep both in the state, then
when creating the pango layout we set the default dir in this way:
- if bidi is set to override, from the direction prop (including
its default)
- otherwise if direction is specified, it wins
- otherwise we default to the direction associated with the
writing mode
I am not sure this is correct, but at least the logic is now in
one place, and it seems less aleatory than what was there before.
The test suite passes.
librsvg/rsvg-styles.c | 57 ---------------------------
librsvg/rsvg-styles.h | 13 -------
rsvg_internals/src/draw.rs | 11 +++++-
rsvg_internals/src/state.rs | 58 +++++++++++++++++++++------
rsvg_internals/src/text.rs | 95 +++++++++++++++++++++++++++++++--------------
5 files changed, 120 insertions(+), 114 deletions(-)
---
diff --git a/librsvg/rsvg-styles.c b/librsvg/rsvg-styles.c
index de32a311..0477e8c7 100644
--- a/librsvg/rsvg-styles.c
+++ b/librsvg/rsvg-styles.c
@@ -113,8 +113,6 @@ rsvg_state_init (RsvgState * state)
state->flood_color = 0;
state->flood_opacity = 255;
- state->text_dir = PANGO_DIRECTION_LTR;
- state->text_gravity = PANGO_GRAVITY_SOUTH;
state->cond_true = TRUE;
state->has_current_color = FALSE;
@@ -127,8 +125,6 @@ rsvg_state_init (RsvgState * state)
state->has_cond = FALSE;
state->has_stop_color = FALSE;
state->has_stop_opacity = FALSE;
- state->has_text_dir = FALSE;
- state->has_text_gravity = FALSE;
state->state_rust = rsvg_state_rust_new();
}
@@ -252,10 +248,6 @@ rsvg_state_inherit_run (RsvgState * dst, const RsvgState * src,
}
if (function (dst->has_cond, src->has_cond))
dst->cond_true = src->cond_true;
- 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;
rsvg_state_rust_inherit_run (dst->state_rust, src->state_rust, function, inherituninheritables);
@@ -516,43 +508,6 @@ rsvg_parse_style_pair (RsvgState *state,
}
break;
- case RSVG_ATTRIBUTE_DIRECTION:
- {
- state->has_text_dir = TRUE;
- if (g_str_equal (value, "inherit")) {
- state->text_dir = PANGO_DIRECTION_LTR;
- state->has_text_dir = FALSE;
- } else if (g_str_equal (value, "rtl"))
- state->text_dir = PANGO_DIRECTION_RTL;
- else /* ltr */
- state->text_dir = PANGO_DIRECTION_LTR;
- }
- break;
-
- case RSVG_ATTRIBUTE_WRITING_MODE:
- {
- /* 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;
- 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;
- 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;
- }
- }
- break;
-
case RSVG_ATTRIBUTE_STOP_COLOR:
{
state->has_stop_color = TRUE;
@@ -1249,18 +1204,6 @@ rsvg_state_get_current_color (RsvgState *state)
return state->current_color;
}
-PangoDirection
-rsvg_state_get_text_dir (RsvgState *state)
-{
- return state->text_dir;
-}
-
-PangoGravity
-rsvg_state_get_text_gravity (RsvgState *state)
-{
- return state->text_gravity;
-}
-
RsvgPaintServer *
rsvg_state_get_fill (RsvgState *state)
{
diff --git a/librsvg/rsvg-styles.h b/librsvg/rsvg-styles.h
index 4e4bc23c..4f48d341 100644
--- a/librsvg/rsvg-styles.h
+++ b/librsvg/rsvg-styles.h
@@ -60,13 +60,6 @@ struct _RsvgState {
guint8 stroke_opacity; /* 0..255 */
gboolean has_stroke_opacity;
- PangoDirection text_dir;
- gboolean has_text_dir;
- PangoGravity text_gravity;
- gboolean has_text_gravity;
-
- guint text_offset;
-
RsvgCssColorSpec stop_color;
gboolean has_stop_color;
@@ -170,12 +163,6 @@ RsvgOpacitySpec *rsvg_state_get_stop_opacity (RsvgState *state);
G_GNUC_INTERNAL
guint32 rsvg_state_get_current_color (RsvgState *state);
-G_GNUC_INTERNAL
-PangoDirection rsvg_state_get_text_dir (RsvgState *state);
-
-G_GNUC_INTERNAL
-PangoGravity rsvg_state_get_text_gravity (RsvgState *state);
-
G_GNUC_INTERNAL
RsvgPaintServer *rsvg_state_get_fill (RsvgState *state);
diff --git a/rsvg_internals/src/draw.rs b/rsvg_internals/src/draw.rs
index 4b71da60..371afd80 100644
--- a/rsvg_internals/src/draw.rs
+++ b/rsvg_internals/src/draw.rs
@@ -25,7 +25,6 @@ use state::{
StrokeWidth,
TextRendering,
};
-use text;
pub fn draw_path_builder(draw_ctx: *mut RsvgDrawingCtx, builder: &PathBuilder, clipping: bool) {
if !clipping {
@@ -399,6 +398,14 @@ pub fn draw_pango_layout(
cr.restore();
}
+// FIXME: should the pango crate provide this like PANGO_GRAVITY_IS_VERTICAL() ?
+fn gravity_is_vertical(gravity: pango::Gravity) -> bool {
+ match gravity {
+ pango::Gravity::East | pango::Gravity::West => true,
+ _ => false,
+ }
+}
+
fn compute_text_bbox(
ink: &pango::Rectangle,
x: f64,
@@ -415,7 +422,7 @@ fn compute_text_bbox(
let ink_width = f64::from(ink.width);
let ink_height = f64::from(ink.height);
- if text::gravity_is_vertical(gravity) {
+ if gravity_is_vertical(gravity) {
bbox.set_rect(&cairo::Rectangle {
x: x + (ink_x - ink_height) / pango_scale,
y: y + ink_y / pango_scale,
diff --git a/rsvg_internals/src/state.rs b/rsvg_internals/src/state.rs
index 8098b1ed..e6c4ca0c 100644
--- a/rsvg_internals/src/state.rs
+++ b/rsvg_internals/src/state.rs
@@ -2,8 +2,6 @@ use cairo::{self, MatrixTrait};
use glib::translate::*;
use glib_sys;
use libc;
-use pango;
-use pango_sys;
use std::cell::RefCell;
use std::collections::HashSet;
use std::ptr;
@@ -43,6 +41,7 @@ pub struct State {
pub clip_path: Option<ClipPath>,
pub clip_rule: Option<ClipRule>,
pub comp_op: Option<CompOp>,
+ pub direction: Option<Direction>,
pub display: Option<Display>,
pub enable_background: Option<EnableBackground>,
pub fill_rule: Option<FillRule>,
@@ -71,6 +70,7 @@ pub struct State {
pub text_rendering: Option<TextRendering>,
pub unicode_bidi: Option<UnicodeBidi>,
pub visibility: Option<Visibility>,
+ pub writing_mode: Option<WritingMode>,
pub xml_lang: Option<XmlLang>,
pub xml_space: Option<XmlSpace>,
@@ -87,6 +87,7 @@ impl State {
clip_path: Default::default(),
clip_rule: Default::default(),
comp_op: Default::default(),
+ direction: Default::default(),
display: Default::default(),
enable_background: Default::default(),
fill_rule: Default::default(),
@@ -115,6 +116,7 @@ impl State {
text_rendering: Default::default(),
unicode_bidi: Default::default(),
visibility: Default::default(),
+ writing_mode: Default::default(),
xml_lang: Default::default(),
xml_space: Default::default(),
@@ -146,6 +148,10 @@ impl State {
self.comp_op = parse_property(value, ())?;
}
+ Attribute::Direction => {
+ self.direction = parse_property(value, ())?;
+ }
+
Attribute::Display => {
self.display = parse_property(value, ())?;
}
@@ -272,6 +278,10 @@ impl State {
self.visibility = parse_property(value, ())?;
}
+ Attribute::WritingMode => {
+ self.writing_mode = parse_property(value, ())?;
+ }
+
Attribute::XmlLang => {
// xml:lang is not a property; it is a non-presentation attribute and as such
// cannot have the "inherit" value. So, we don't call parse_property() for it,
@@ -326,8 +336,6 @@ extern "C" {
fn rsvg_state_get_current_color(state: *const RsvgState) -> u32;
fn rsvg_state_get_stroke(state: *const RsvgState) -> *const PaintServer;
fn rsvg_state_get_stroke_opacity(state: *const RsvgState) -> u8;
- fn rsvg_state_get_text_dir(state: *const RsvgState) -> pango_sys::PangoDirection;
- fn rsvg_state_get_text_gravity(state: *const RsvgState) -> pango_sys::PangoGravity;
fn rsvg_state_get_fill(state: *const RsvgState) -> *const PaintServer;
fn rsvg_state_get_fill_opacity(state: *const RsvgState) -> u8;
@@ -403,6 +411,15 @@ pub fn is_visible(state: *const RsvgState) -> bool {
}
}
+pub fn text_gravity_is_vertical(state: *const RsvgState) -> bool {
+ let rstate = get_state_rust(state);
+
+ match rstate.writing_mode {
+ Some(WritingMode::Tb) | Some(WritingMode::TbRl) => true,
+ _ => false,
+ }
+}
+
pub fn get_cond_true(state: *const RsvgState) -> bool {
unsafe { from_glib(rsvg_state_get_cond_true(state)) }
}
@@ -459,14 +476,6 @@ pub fn get_stroke_opacity(state: *const RsvgState) -> u8 {
unsafe { rsvg_state_get_stroke_opacity(state) }
}
-pub fn get_text_dir(state: *const RsvgState) -> pango::Direction {
- unsafe { from_glib(rsvg_state_get_text_dir(state)) }
-}
-
-pub fn get_text_gravity(state: *const RsvgState) -> pango::Gravity {
- unsafe { from_glib(rsvg_state_get_text_gravity(state)) }
-}
-
pub fn get_fill<'a>(state: *const RsvgState) -> Option<&'a PaintServer> {
unsafe {
let ps = rsvg_state_get_fill(state);
@@ -581,6 +590,16 @@ make_property!(
"exclusion" => Exclusion,
);
+make_property!(
+ Direction,
+ default: Ltr,
+ inherits_automatically: true,
+
+ identifiers:
+ "ltr" => Ltr,
+ "rtl" => Rtl,
+);
+
make_property!(
Display,
default: Inline,
@@ -895,6 +914,20 @@ make_property!(
"collapse" => Collapse,
);
+make_property!(
+ WritingMode,
+ default: LrTb,
+ inherits_automatically: true,
+
+ identifiers:
+ "lr" => Lr,
+ "lr-tb" => LrTb,
+ "rl" => Rl,
+ "rl-tb" => RlTb,
+ "tb" => Tb,
+ "tb-rl" => TbRl,
+);
+
make_property!(
XmlLang,
default: "C".to_string(),
@@ -1030,6 +1063,7 @@ pub extern "C" fn rsvg_state_rust_inherit_run(
// please keep these sorted
inherit(inherit_fn, &mut dst.baseline_shift, &src.baseline_shift);
inherit(inherit_fn, &mut dst.clip_rule, &src.clip_rule);
+ inherit(inherit_fn, &mut dst.direction, &src.direction);
inherit(inherit_fn, &mut dst.display, &src.display);
inherit(inherit_fn, &mut dst.fill_rule, &src.fill_rule);
inherit(inherit_fn, &mut dst.font_family, &src.font_family);
diff --git a/rsvg_internals/src/text.rs b/rsvg_internals/src/text.rs
index 4d5423b6..e0c30d0e 100644
--- a/rsvg_internals/src/text.rs
+++ b/rsvg_internals/src/text.rs
@@ -23,6 +23,7 @@ use property_bag::PropertyBag;
use space::xml_space_normalize;
use state::{
self,
+ Direction,
FontFamily,
FontStretch,
FontStyle,
@@ -32,6 +33,7 @@ use state::{
RsvgState,
TextAnchor,
UnicodeBidi,
+ WritingMode,
XmlLang,
};
@@ -98,8 +100,7 @@ impl NodeChars {
let baseline = f64::from(layout.get_baseline()) / f64::from(pango::SCALE);
let offset = baseline + drawing_ctx::get_accumulated_baseline_shift(draw_ctx);
- let gravity = state::get_text_gravity(state);
- if gravity_is_vertical(gravity) {
+ if state::text_gravity_is_vertical(state) {
draw_pango_layout(draw_ctx, &layout, *x + offset, *y, clipping);
*y += f64::from(width) / f64::from(pango::SCALE);
} else {
@@ -167,11 +168,10 @@ impl NodeTrait for NodeText {
let state = drawing_ctx::get_current_state(draw_ctx);
let anchor = state::get_state_rust(state).text_anchor.unwrap_or_default();
- let gravity = state::get_text_gravity(state);
let offset = anchor_offset(node, draw_ctx, anchor, false);
- if gravity_is_vertical(gravity) {
+ if state::text_gravity_is_vertical(state) {
y -= offset;
dy = match anchor {
TextAnchor::Start => dy,
@@ -291,8 +291,7 @@ impl NodeTSpan {
}
let state = drawing_ctx::get_current_state(draw_ctx);
- let gravity = state::get_text_gravity(state);
- if gravity_is_vertical(gravity) {
+ if state::text_gravity_is_vertical(state) {
*length += self.dy.get().normalize(draw_ctx);
} else {
*length += self.dx.get().normalize(draw_ctx);
@@ -317,14 +316,14 @@ impl NodeTSpan {
let mut dy = self.dy.get().normalize(draw_ctx);
let state = drawing_ctx::get_current_state(draw_ctx);
+ let vertical = state::text_gravity_is_vertical(state);
let anchor = state::get_state_rust(state).text_anchor.unwrap_or_default();
- let gravity = state::get_text_gravity(state);
let offset = anchor_offset(node, draw_ctx, anchor, usetextonly);
if let Some(self_x) = self.x.get() {
*x = self_x.normalize(draw_ctx);
- if !gravity_is_vertical(gravity) {
+ if !vertical {
*x -= offset;
dx = match anchor {
TextAnchor::Start => dx,
@@ -337,7 +336,7 @@ impl NodeTSpan {
if let Some(self_y) = self.y.get() {
*y = self_y.normalize(draw_ctx);
- if gravity_is_vertical(gravity) {
+ if vertical {
*y -= offset;
dy = match anchor {
TextAnchor::Start => dy,
@@ -381,15 +380,6 @@ impl NodeTrait for NodeTSpan {
}
}
-// FIXME: should the pango crate provide this like PANGO_GRAVITY_IS_VERTICAL() /
-// PANGO_GRAVITY_IS_IMPROPER()?
-pub fn gravity_is_vertical(gravity: pango::Gravity) -> bool {
- match gravity {
- pango::Gravity::East | pango::Gravity::West => true,
- _ => false,
- }
-}
-
fn to_pango_units(v: f64) -> i32 {
(v * f64::from(pango::SCALE)) as i32
}
@@ -451,6 +441,46 @@ impl From<FontWeight> for pango::Weight {
}
}
+impl From<Direction> for pango::Direction {
+ fn from(d: Direction) -> pango::Direction {
+ match d {
+ Direction::Ltr => pango::Direction::Ltr,
+ Direction::Rtl => pango::Direction::Rtl,
+ }
+ }
+}
+
+impl From<Direction> for pango::Alignment {
+ fn from(d: Direction) -> pango::Alignment {
+ match d {
+ Direction::Ltr => pango::Alignment::Left,
+ Direction::Rtl => pango::Alignment::Right,
+ }
+ }
+}
+
+impl From<WritingMode> for pango::Direction {
+ fn from(m: WritingMode) -> pango::Direction {
+ match m {
+ WritingMode::LrTb | WritingMode::Lr | WritingMode::Tb | WritingMode::TbRl => {
+ pango::Direction::Ltr
+ }
+ WritingMode::RlTb | WritingMode::Rl => pango::Direction::Rtl,
+ }
+ }
+}
+
+impl From<WritingMode> for pango::Gravity {
+ fn from(m: WritingMode) -> pango::Gravity {
+ match m {
+ WritingMode::Tb | WritingMode::TbRl => pango::Gravity::East,
+ WritingMode::LrTb | WritingMode::Lr | WritingMode::RlTb | WritingMode::Rl => {
+ pango::Gravity::South
+ }
+ }
+ }
+}
+
fn create_pango_layout(draw_ctx: *const RsvgDrawingCtx, text: &str) -> pango::Layout {
let state = drawing_ctx::get_current_state(draw_ctx);
let rstate = state::get_state_rust(state);
@@ -461,17 +491,25 @@ fn create_pango_layout(draw_ctx: *const RsvgDrawingCtx, text: &str) -> pango::La
pango_context.set_language(&pango_lang);
}
- match rstate.unicode_bidi {
- Some(UnicodeBidi::Override) | Some(UnicodeBidi::Embed) => {
- pango_context.set_base_dir(state::get_text_dir(state));
+ pango_context.set_base_gravity(pango::Gravity::from(
+ rstate.writing_mode.unwrap_or_default(),
+ ));
+
+ match (rstate.unicode_bidi, rstate.direction) {
+ (Some(UnicodeBidi::Override), _) | (Some(UnicodeBidi::Embed), _) => {
+ pango_context
+ .set_base_dir(pango::Direction::from(rstate.direction.unwrap_or_default()));
}
- _ => (),
- }
+ (_, Some(direction)) => {
+ pango_context.set_base_dir(pango::Direction::from(direction));
+ }
- let gravity = state::get_text_gravity(state);
- if gravity_is_vertical(gravity) {
- pango_context.set_base_gravity(gravity);
+ (_, _) => {
+ pango_context.set_base_dir(pango::Direction::from(
+ rstate.writing_mode.unwrap_or_default(),
+ ));
+ }
}
let mut font_desc = pango_context.get_font_description().unwrap();
@@ -520,10 +558,7 @@ fn create_pango_layout(draw_ctx: *const RsvgDrawingCtx, text: &str) -> pango::La
layout.set_attributes(&attr_list);
- layout.set_alignment(match state::get_text_dir(state) {
- pango::Direction::Ltr => pango::Alignment::Left,
- _ => pango::Alignment::Right,
- });
+ layout.set_alignment(pango::Alignment::from(rstate.direction.unwrap_or_default()));
let t = xml_space_normalize(rstate.xml_space.unwrap_or_default(), text);
layout.set_text(&t);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]