[lasem] svg_text: add support for multiple x, y, dx, and dy.
- From: Emmanuel Pacaud <emmanuel src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [lasem] svg_text: add support for multiple x, y, dx, and dy.
- Date: Mon, 5 Nov 2012 21:58:00 +0000 (UTC)
commit 409c1594c5dfcfb0a489bfa17397c16711a78637
Author: Emmanuel Pacaud <emmanuel gnome org>
Date: Mon Nov 5 22:57:36 2012 +0100
svg_text: add support for multiple x, y, dx, and dy.
src/lsmsvgattributes.h | 5 +
src/lsmsvglength.c | 59 ++++++++++++
src/lsmsvglength.h | 6 ++
src/lsmsvgtextelement.c | 83 ++++++++++++-----
src/lsmsvgtextelement.h | 6 +-
src/lsmsvgtraits.c | 74 +++++++++++++++
src/lsmsvgtraits.h | 1 +
src/lsmsvgtspanelement.c | 65 ++++++++++----
src/lsmsvgtspanelement.h | 6 +-
src/lsmsvgview.c | 221 ++++++++++++++++++++++++++++++++++++++++++----
src/lsmsvgview.h | 15 +++-
tests/.gitignore | 1 +
12 files changed, 476 insertions(+), 66 deletions(-)
---
diff --git a/src/lsmsvgattributes.h b/src/lsmsvgattributes.h
index 3e5c8e4..9ddd92d 100644
--- a/src/lsmsvgattributes.h
+++ b/src/lsmsvgattributes.h
@@ -60,6 +60,11 @@ typedef struct {
typedef struct {
LsmAttribute base;
+ LsmSvgLengthList list;
+} LsmSvgLengthListAttribute;
+
+typedef struct {
+ LsmAttribute base;
LsmSvgPaint paint;
} LsmSvgPaintAttribute;
diff --git a/src/lsmsvglength.c b/src/lsmsvglength.c
index 4e04f40..83b88db 100644
--- a/src/lsmsvglength.c
+++ b/src/lsmsvglength.c
@@ -24,6 +24,7 @@
#include <math.h>
#include <lsmsvglength.h>
+#include <lsmsvgenums.h>
LsmSvgViewbox *
lsm_svg_viewbox_new (double resolution_ppi,
@@ -91,3 +92,61 @@ lsm_svg_length_normalize (const LsmSvgLength *length,
return 0.0;
}
+
+gboolean
+lsm_svg_parse_length (char **str, LsmSvgLength *length)
+{
+ char *c;
+
+ if (str == NULL || *str == NULL || length == NULL)
+ return FALSE;
+
+ if (!lsm_str_parse_double (str, &length->value_unit))
+ return FALSE;
+
+ c = *str;
+
+ if (c[0] != '\0') {
+ if (c[0] == '%') {
+ length->type = LSM_SVG_LENGTH_TYPE_PERCENTAGE;
+ c++;
+ } else if (c[0] == 'e') {
+ if (c[1] == 'm') {
+ length->type = LSM_SVG_LENGTH_TYPE_EMS;
+ c += 2;
+ } else if (c[1] == 'x') {
+ length->type = LSM_SVG_LENGTH_TYPE_EXS;
+ c += 2;
+ } else
+ length->type = LSM_SVG_LENGTH_TYPE_ERROR;
+ } else if (c[0] == 'p') {
+ if (c[1] == 'x') {
+ length->type = LSM_SVG_LENGTH_TYPE_PX;
+ c += 2;
+ } else if (c[1] == 'c') {
+ length->type = LSM_SVG_LENGTH_TYPE_PC;
+ c += 2;
+ } else if (c[1] == 't') {
+ length->type = LSM_SVG_LENGTH_TYPE_PT;
+ c += 2;
+ } else
+ length->type = LSM_SVG_LENGTH_TYPE_ERROR;
+ } else if (c[0] == 'c' && c[0] == 'm') {
+ length->type = LSM_SVG_LENGTH_TYPE_CM;
+ c += 2;
+ } else if (c[0] == 'm' && c[0] == 'm') {
+ length->type = LSM_SVG_LENGTH_TYPE_MM;
+ c += 2;
+ } else if (c[0] == 'i' && c[0] == 'n') {
+ length->type = LSM_SVG_LENGTH_TYPE_IN;
+ c += 2;
+ } else
+ length->type = LSM_SVG_LENGTH_TYPE_NUMBER;
+ } else {
+ length->type = LSM_SVG_LENGTH_TYPE_NUMBER;
+ }
+
+ *str = c;
+
+ return TRUE;
+}
diff --git a/src/lsmsvglength.h b/src/lsmsvglength.h
index 95c21f6..10d5e52 100644
--- a/src/lsmsvglength.h
+++ b/src/lsmsvglength.h
@@ -53,6 +53,12 @@ double lsm_svg_length_normalize (const LsmSvgLength *length,
const LsmSvgViewbox *viewbox,
double font_size,
LsmSvgLengthDirection direction);
+gboolean lsm_svg_parse_length (char **str, LsmSvgLength *length);
+
+typedef struct {
+ unsigned int n_lengths;
+ LsmSvgLength *lengths;
+} LsmSvgLengthList;
G_END_DECLS
diff --git a/src/lsmsvgtextelement.c b/src/lsmsvgtextelement.c
index bb647ce..fd21f22 100644
--- a/src/lsmsvgtextelement.c
+++ b/src/lsmsvgtextelement.c
@@ -52,37 +52,56 @@ lsm_svg_text_element_render (LsmSvgElement *self, LsmSvgView *view)
LsmSvgTextElement *text = LSM_SVG_TEXT_ELEMENT (self);
LsmDomNode *node = LSM_DOM_NODE (self);
LsmDomNode *iter;
- GString *string = g_string_new ("");
- double x, y;
+ double *x, *y, *dx, *dy;
+ unsigned int n_x, n_y, n_dx, n_dy;
+ gboolean first_text = TRUE;
if (node->first_child == NULL)
return;
- for (iter = LSM_DOM_NODE (self)->first_child; iter != NULL; iter = iter->next_sibling) {
+ lsm_svg_view_start_text (view);
+
+ x = lsm_svg_view_normalize_length_list (view, &text->x.list, LSM_SVG_LENGTH_DIRECTION_HORIZONTAL, &n_x);
+ y = lsm_svg_view_normalize_length_list (view, &text->y.list, LSM_SVG_LENGTH_DIRECTION_HORIZONTAL, &n_y);
+ dx = lsm_svg_view_normalize_length_list (view, &text->dx.list, LSM_SVG_LENGTH_DIRECTION_HORIZONTAL, &n_dx);
+ dy = lsm_svg_view_normalize_length_list (view, &text->dy.list, LSM_SVG_LENGTH_DIRECTION_HORIZONTAL, &n_dy);
+
+ iter = LSM_DOM_NODE (self)->first_child;
+ while (iter != NULL) {
if (LSM_IS_DOM_TEXT (iter)) {
- g_string_append (string, lsm_dom_node_get_node_value (iter));
+ GString *string;
+ string = g_string_new ("");
+ for (; LSM_IS_DOM_TEXT (iter); iter = iter->next_sibling)
+ g_string_append (string, lsm_dom_node_get_node_value (iter));
+ lsm_str_consolidate (string->str);
+ if (first_text) {
+ lsm_svg_view_show_text (view, string->str, n_x, x, n_y, y, n_dx, dx, n_dy, dy);
+ first_text = FALSE;
+ } else
+ lsm_svg_view_show_text (view, string->str, 0, NULL, 0, NULL, 0, NULL, 0, NULL);
+ g_string_free (string, TRUE);
+ } else {
+ if (LSM_IS_SVG_ELEMENT (iter))
+ lsm_svg_element_render (LSM_SVG_ELEMENT (iter), view);
+ iter = iter->next_sibling;
}
}
- x = lsm_svg_view_normalize_length (view, &text->x.length, LSM_SVG_LENGTH_DIRECTION_HORIZONTAL);
- y = lsm_svg_view_normalize_length (view, &text->y.length, LSM_SVG_LENGTH_DIRECTION_VERTICAL);
-
- lsm_svg_view_show_text (view, g_strstrip (string->str), x, y);
+ g_free (x);
+ g_free (y);
+ g_free (dx);
+ g_free (dy);
- g_string_free (string, TRUE);
-
- for (iter = LSM_DOM_NODE (self)->first_child; iter != NULL; iter = iter->next_sibling)
- if (LSM_IS_SVG_ELEMENT (iter))
- lsm_svg_element_render (LSM_SVG_ELEMENT (iter), view);
+ lsm_svg_view_end_text (view);
}
static void
lsm_svg_text_element_get_extents (LsmSvgElement *self, LsmSvgView *view, LsmExtents *extents)
{
- LsmSvgTextElement *text = LSM_SVG_TEXT_ELEMENT (self);
+/* LsmSvgTextElement *text = LSM_SVG_TEXT_ELEMENT (self);*/
LsmDomNode *iter;
GString *string = g_string_new ("");
- double x, y;
+/* double x, y;*/
for (iter = LSM_DOM_NODE (self)->first_child; iter != NULL; iter = iter->next_sibling) {
if (LSM_IS_DOM_TEXT (iter)) {
@@ -90,10 +109,10 @@ lsm_svg_text_element_get_extents (LsmSvgElement *self, LsmSvgView *view, LsmExte
}
}
- x = lsm_svg_view_normalize_length (view, &text->x.length, LSM_SVG_LENGTH_DIRECTION_HORIZONTAL);
- y = lsm_svg_view_normalize_length (view, &text->y.length, LSM_SVG_LENGTH_DIRECTION_VERTICAL);
+/* x = lsm_svg_view_normalize_length (view, &text->x.length, LSM_SVG_LENGTH_DIRECTION_HORIZONTAL);*/
+/* y = lsm_svg_view_normalize_length (view, &text->y.length, LSM_SVG_LENGTH_DIRECTION_VERTICAL);*/
- lsm_svg_view_text_extents (view, g_strstrip (string->str), x, y, extents);
+ lsm_svg_view_text_extents (view, g_strstrip (string->str), 0, 0, 0, NULL, 0, NULL, extents);
g_string_free (string, TRUE);
}
@@ -106,13 +125,15 @@ lsm_svg_text_element_new (void)
return g_object_new (LSM_TYPE_SVG_TEXT_ELEMENT, NULL);
}
-static const LsmSvgLength length_default = { .value_unit = 0.0, .type = LSM_SVG_LENGTH_TYPE_PX};
+static const LsmSvgLengthList length_list_default = {.n_lengths = 0, .lengths = NULL};
static void
lsm_svg_text_element_init (LsmSvgTextElement *self)
{
- self->x.length = length_default;
- self->y.length = length_default;
+ self->x.list = length_list_default;
+ self->y.list = length_list_default;
+ self->dx.list = length_list_default;
+ self->dy.list = length_list_default;
}
static void
@@ -127,14 +148,26 @@ static const LsmAttributeInfos lsm_svg_text_element_attribute_infos[] = {
{
.name = "x",
.attribute_offset = offsetof (LsmSvgTextElement, x),
- .trait_class = &lsm_svg_length_trait_class,
- .trait_default = &length_default
+ .trait_class = &lsm_svg_length_list_trait_class,
+ .trait_default = &length_list_default
},
{
.name = "y",
.attribute_offset = offsetof (LsmSvgTextElement, y),
- .trait_class = &lsm_svg_length_trait_class,
- .trait_default = &length_default
+ .trait_class = &lsm_svg_length_list_trait_class,
+ .trait_default = &length_list_default
+ },
+ {
+ .name = "dx",
+ .attribute_offset = offsetof (LsmSvgTextElement, dx),
+ .trait_class = &lsm_svg_length_list_trait_class,
+ .trait_default = &length_list_default
+ },
+ {
+ .name = "dy",
+ .attribute_offset = offsetof (LsmSvgTextElement, dy),
+ .trait_class = &lsm_svg_length_list_trait_class,
+ .trait_default = &length_list_default
}
};
diff --git a/src/lsmsvgtextelement.h b/src/lsmsvgtextelement.h
index 4cd8421..b34b13f 100644
--- a/src/lsmsvgtextelement.h
+++ b/src/lsmsvgtextelement.h
@@ -41,8 +41,10 @@ typedef struct _LsmSvgTextElementClass LsmSvgTextElementClass;
struct _LsmSvgTextElement {
LsmSvgTransformable base;
- LsmSvgLengthAttribute x;
- LsmSvgLengthAttribute y;
+ LsmSvgLengthListAttribute x;
+ LsmSvgLengthListAttribute y;
+ LsmSvgLengthListAttribute dx;
+ LsmSvgLengthListAttribute dy;
};
struct _LsmSvgTextElementClass {
diff --git a/src/lsmsvgtraits.c b/src/lsmsvgtraits.c
index 053467e..fb5ef5b 100644
--- a/src/lsmsvgtraits.c
+++ b/src/lsmsvgtraits.c
@@ -131,6 +131,78 @@ const LsmTraitClass lsm_svg_length_trait_class = {
.to_string = lsm_svg_length_trait_to_string
};
+static gboolean
+lsm_svg_length_list_trait_from_string (LsmTrait *abstract_trait, char *string)
+{
+ LsmSvgLengthList *length_list = (LsmSvgLengthList *) abstract_trait;
+ unsigned int n_lengths = 1;
+ unsigned int i;
+ gboolean success = FALSE;
+ char *iter = (char *) string;
+
+ g_free (length_list->lengths);
+ length_list->n_lengths = 0;
+ length_list->lengths = NULL;
+
+ while (*iter != '\0') {
+ if (*iter == ',' ||
+ *iter == ' ') {
+ n_lengths++;
+ do {
+ iter++;
+ } while (*iter == ',' ||
+ *iter == ' ');
+ } else
+ iter++;
+ }
+
+ length_list->lengths = g_new (LsmSvgLength, n_lengths);
+ length_list->n_lengths = n_lengths;
+ iter = (char *)string;
+ lsm_str_skip_spaces (&iter);
+
+ for (i = 0; i < n_lengths; i++) {
+ success = lsm_svg_parse_length (&iter, &length_list->lengths[i]);
+
+ if (!success)
+ break;
+ lsm_str_skip_comma_and_spaces (&iter);
+ }
+
+ if (!success) {
+ g_free (length_list->lengths);
+ length_list->lengths = NULL;
+ length_list->n_lengths = 0;
+ }
+
+ return TRUE;
+}
+
+static char *
+lsm_svg_length_list_trait_to_string (LsmTrait *abstract_trait)
+{
+ g_assert_not_reached ();
+
+ return NULL;
+}
+
+static void
+lsm_svg_length_list_trait_finalize (LsmTrait *abstract_trait)
+{
+ LsmSvgLengthList *svg_length_list = (LsmSvgLengthList *) abstract_trait;
+
+ g_free (svg_length_list->lengths);
+ svg_length_list->n_lengths = 0;
+ svg_length_list->lengths = NULL;
+}
+
+const LsmTraitClass lsm_svg_length_list_trait_class = {
+ .size = sizeof (LsmSvgLengthList),
+ .from_string = lsm_svg_length_list_trait_from_string,
+ .to_string = lsm_svg_length_list_trait_to_string,
+ .finalize = lsm_svg_length_list_trait_finalize
+};
+
static void
_init_matrix (LsmSvgMatrix *matrix, LsmSvgTransformType transform, unsigned int n_values, double values[])
{
@@ -785,6 +857,8 @@ static char *
lsm_svg_dash_array_trait_to_string (LsmTrait *abstract_trait)
{
g_assert_not_reached ();
+
+ return NULL;
}
static void
diff --git a/src/lsmsvgtraits.h b/src/lsmsvgtraits.h
index 7fb2644..62be70d 100644
--- a/src/lsmsvgtraits.h
+++ b/src/lsmsvgtraits.h
@@ -84,6 +84,7 @@ extern const LsmTraitClass lsm_svg_font_stretch_trait_class;
extern const LsmTraitClass lsm_svg_font_style_trait_class;
extern const LsmTraitClass lsm_svg_font_weight_trait_class;
extern const LsmTraitClass lsm_svg_length_trait_class;
+extern const LsmTraitClass lsm_svg_length_list_trait_class;
extern const LsmTraitClass lsm_svg_line_join_trait_class;
extern const LsmTraitClass lsm_svg_line_cap_trait_class;
extern const LsmTraitClass lsm_svg_marker_units_trait_class;
diff --git a/src/lsmsvgtspanelement.c b/src/lsmsvgtspanelement.c
index 9e16950..2e87fea 100644
--- a/src/lsmsvgtspanelement.c
+++ b/src/lsmsvgtspanelement.c
@@ -52,26 +52,45 @@ lsm_svg_tspan_element_render (LsmSvgElement *self, LsmSvgView *view)
LsmSvgTspanElement *tspan = LSM_SVG_TSPAN_ELEMENT (self);
LsmDomNode *node = LSM_DOM_NODE (self);
LsmDomNode *iter;
- GString *string = g_string_new ("");
- double x, y;
+ double *x, *y, *dx, *dy;
+ unsigned int n_x, n_y, n_dx, n_dy;
+ gboolean first_text = TRUE;
lsm_debug_render ("[LsmSvgTspanElement::render] Render");
if (node->first_child == NULL)
return;
- for (iter = LSM_DOM_NODE (self)->first_child; iter != NULL; iter = iter->next_sibling) {
+ x = lsm_svg_view_normalize_length_list (view, &tspan->x.list, LSM_SVG_LENGTH_DIRECTION_HORIZONTAL, &n_x);
+ y = lsm_svg_view_normalize_length_list (view, &tspan->y.list, LSM_SVG_LENGTH_DIRECTION_HORIZONTAL, &n_y);
+ dx = lsm_svg_view_normalize_length_list (view, &tspan->dx.list, LSM_SVG_LENGTH_DIRECTION_HORIZONTAL, &n_dx);
+ dy = lsm_svg_view_normalize_length_list (view, &tspan->dy.list, LSM_SVG_LENGTH_DIRECTION_HORIZONTAL, &n_dy);
+
+ iter = LSM_DOM_NODE (self)->first_child;
+ while (iter != NULL) {
if (LSM_IS_DOM_TEXT (iter)) {
- g_string_append (string, lsm_dom_node_get_node_value (iter));
+ GString *string;
+ string = g_string_new ("");
+ for (; LSM_IS_DOM_TEXT (iter); iter = iter->next_sibling)
+ g_string_append (string, lsm_dom_node_get_node_value (iter));
+ lsm_str_consolidate (string->str);
+ if (first_text) {
+ lsm_svg_view_show_text (view, string->str, n_x, x, n_y, y, n_dx, dx, n_dy, dy);
+ first_text = FALSE;
+ } else
+ lsm_svg_view_show_text (view, string->str, 0, NULL, 0, NULL, 0, NULL, 0, NULL);
+ g_string_free (string, TRUE);
+ } else {
+ if (LSM_IS_SVG_ELEMENT (iter))
+ lsm_svg_element_render (LSM_SVG_ELEMENT (iter), view);
+ iter = iter->next_sibling;
}
}
- x = lsm_svg_view_normalize_length (view, &tspan->x.length, LSM_SVG_LENGTH_DIRECTION_HORIZONTAL);
- y = lsm_svg_view_normalize_length (view, &tspan->y.length, LSM_SVG_LENGTH_DIRECTION_VERTICAL);
-
- lsm_svg_view_show_text (view, g_strstrip (string->str), x, y);
-
- g_string_free (string, TRUE);
+ g_free (x);
+ g_free (y);
+ g_free (dx);
+ g_free (dy);
}
/* LsmSvgTspanElement implementation */
@@ -82,13 +101,13 @@ lsm_svg_tspan_element_new (void)
return g_object_new (LSM_TYPE_SVG_TSPAN_ELEMENT, NULL);
}
-static const LsmSvgLength length_default = { .value_unit = 0.0, .type = LSM_SVG_LENGTH_TYPE_PX};
+static const LsmSvgLengthList length_list_default = {.n_lengths = 0, .lengths = NULL};
static void
lsm_svg_tspan_element_init (LsmSvgTspanElement *self)
{
- self->x.length = length_default;
- self->y.length = length_default;
+ self->x.list = length_list_default;
+ self->y.list = length_list_default;
}
static void
@@ -103,14 +122,26 @@ static const LsmAttributeInfos lsm_svg_tspan_element_attribute_infos[] = {
{
.name = "x",
.attribute_offset = offsetof (LsmSvgTspanElement, x),
- .trait_class = &lsm_svg_length_trait_class,
- .trait_default = &length_default
+ .trait_class = &lsm_svg_length_list_trait_class,
+ .trait_default = &length_list_default
},
{
.name = "y",
.attribute_offset = offsetof (LsmSvgTspanElement, y),
- .trait_class = &lsm_svg_length_trait_class,
- .trait_default = &length_default
+ .trait_class = &lsm_svg_length_list_trait_class,
+ .trait_default = &length_list_default
+ },
+ {
+ .name = "dx",
+ .attribute_offset = offsetof (LsmSvgTspanElement, dx),
+ .trait_class = &lsm_svg_length_list_trait_class,
+ .trait_default = &length_list_default
+ },
+ {
+ .name = "dy",
+ .attribute_offset = offsetof (LsmSvgTspanElement, dy),
+ .trait_class = &lsm_svg_length_list_trait_class,
+ .trait_default = &length_list_default
}
};
diff --git a/src/lsmsvgtspanelement.h b/src/lsmsvgtspanelement.h
index b2019b7..afb3ed1 100644
--- a/src/lsmsvgtspanelement.h
+++ b/src/lsmsvgtspanelement.h
@@ -41,8 +41,10 @@ typedef struct _LsmSvgTspanElementClass LsmSvgTspanElementClass;
struct _LsmSvgTspanElement {
LsmSvgElement element;
- LsmSvgLengthAttribute x;
- LsmSvgLengthAttribute y;
+ LsmSvgLengthListAttribute x;
+ LsmSvgLengthListAttribute y;
+ LsmSvgLengthListAttribute dx;
+ LsmSvgLengthListAttribute dy;
};
struct _LsmSvgTspanElementClass {
diff --git a/src/lsmsvgview.c b/src/lsmsvgview.c
index 5ea92f4..ebc487b 100644
--- a/src/lsmsvgview.c
+++ b/src/lsmsvgview.c
@@ -121,6 +121,27 @@ lsm_svg_view_normalize_length (LsmSvgView *view, const LsmSvgLength *length, Lsm
return lsm_svg_length_normalize (length, view->viewbox_stack->data, view->style->font_size_px, direction);
}
+double *
+lsm_svg_view_normalize_length_list (LsmSvgView *view, const LsmSvgLengthList *list, LsmSvgLengthDirection direction, unsigned int *n_data)
+{
+ double *data;
+ unsigned int i;
+
+ g_return_val_if_fail (n_data != NULL, NULL);
+ *n_data = 0;
+ g_return_val_if_fail (LSM_IS_SVG_VIEW (view), NULL);
+
+ if (list->n_lengths == 0)
+ return NULL;
+
+ *n_data = list->n_lengths;
+ data = g_new (double, list->n_lengths);
+ for (i = 0; i < list->n_lengths; i++)
+ data[i] = lsm_svg_view_normalize_length (view, &list->lengths[i], direction);
+
+ return data;
+}
+
static void
_start_pattern (LsmSvgView *view, const LsmBox *extents, const LsmBox *object_extents, double opacity)
{
@@ -1037,7 +1058,10 @@ lsm_svg_view_show_polygon (LsmSvgView *view, const char *points)
}
static void
-_update_pango_layout (LsmSvgView *view, char const *string, double x, double y, LsmSvgViewPathInfos *path_infos)
+_update_pango_layout (LsmSvgView *view, unsigned int n, char const *string, double x, double y,
+ unsigned int n_dx, const double *dx,
+ unsigned int n_dy, const double *dy,
+ LsmSvgViewPathInfos *path_infos)
{
const LsmSvgStyle *style;
PangoLayout *pango_layout;
@@ -1046,7 +1070,10 @@ _update_pango_layout (LsmSvgView *view, char const *string, double x, double y,
PangoStyle font_style;
PangoLayoutIter *iter;
PangoRectangle rectangle;
+ PangoAttrList *attrs;
+ PangoAttribute *attr;
int baseline;
+ int i;
double x1, y1;
style = view->style;
@@ -1104,7 +1131,38 @@ _update_pango_layout (LsmSvgView *view, char const *string, double x, double y,
}
pango_font_description_set_style (font_description, font_style);
- pango_layout_set_text (pango_layout, string, -1);
+ pango_layout_set_text (pango_layout, string, n);
+
+ attrs = pango_attr_list_new ();
+ for (i = 0; i < n_dx; i++) {
+
+ attr = pango_attr_letter_spacing_new (pango_units_from_double (dx[i]));
+ attr->start_index = i;
+ if (i < n_dx - 1)
+ attr->end_index = i + 1;
+ else
+ attr->end_index = PANGO_ATTR_INDEX_TO_TEXT_END;
+
+ pango_attr_list_insert (attrs, attr);
+
+ printf ("spacing = %g\n", dx[i]);
+ }
+ for (i = 0; i < n_dy; i++) {
+
+ attr = pango_attr_rise_new (-pango_units_from_double (dy[i]));
+ attr->start_index = i;
+ if (i < n_dy - 1)
+ attr->end_index = i + 1;
+ else
+ attr->end_index = PANGO_ATTR_INDEX_TO_TEXT_END;
+
+ pango_attr_list_insert (attrs, attr);
+
+ printf ("rise = %g\n", dy[i]);
+ }
+ pango_layout_set_attributes (pango_layout, attrs);
+ pango_attr_list_unref (attrs);
+
pango_layout_set_font_description (pango_layout, font_description);
pango_layout_get_extents (pango_layout, &rectangle, NULL);
@@ -1148,7 +1206,7 @@ _lock_pango_layout (LsmSvgView *view)
view->pango_layout_stack = g_slist_prepend (view->pango_layout_stack, view->pango_layout);
view->pango_layout = pango_layout_new (pango_context);
- lsm_debug_render ("[LsmSvgView::show_text] Create a new pango layout");
+ lsm_debug_render ("[LsmSvgView::_lock_pango_layout] Create a new pango layout");
return TRUE;
}
@@ -1163,7 +1221,7 @@ _unlock_pango_layout (LsmSvgView *view, gboolean need_pop)
{
if (need_pop) {
- lsm_debug_render ("[LsmSvgView::show_text] Free the child pango layout");
+ lsm_debug_render ("[LsmSvgView::_unlock_pango_layout] Free the child pango layout");
if (view->pango_layout != NULL) {
g_object_unref (view->pango_layout);
@@ -1172,23 +1230,31 @@ _unlock_pango_layout (LsmSvgView *view, gboolean need_pop)
view->pango_layout_stack = g_slist_delete_link (view->pango_layout_stack,
view->pango_layout_stack);
} else
- g_warning ("[LsmSvgView::show_text] Pango layout stack empty");
+ g_warning ("[LsmSvgView::_unlock_pango_layout] Pango layout stack empty");
}
view->is_pango_layout_in_use = FALSE;
}
-void
-lsm_svg_view_show_text (LsmSvgView *view, char const *string, double x, double y)
+static void
+_show_text (LsmSvgView *view,
+ unsigned int n, char const *string,
+ unsigned int n_x, double *x, unsigned int n_y, double *y,
+ unsigned int n_dx, double *dx, unsigned int n_dy, double *dy)
{
LsmSvgViewPathInfos path_infos = default_path_infos;
+ PangoRectangle extents;
+ PangoLayoutIter *layout_iter;
const LsmSvgStyle *style;
gboolean need_pop;
+ double x_text;
+ double y_text;
+ double x_end, y_end;
+ double baseline;
+ cairo_t *cairo;
- if (string == NULL || string[0] == '\0')
- return;
- g_return_if_fail (LSM_IS_SVG_VIEW (view));
+ cairo = view->dom_view.cairo;
style = view->style;
@@ -1196,28 +1262,143 @@ lsm_svg_view_show_text (LsmSvgView *view, char const *string, double x, double y
need_pop = _lock_pango_layout (view);
- _update_pango_layout (view, string, x, y, &path_infos);
+ cairo_get_current_point (cairo, &x_text, &y_text);
+ if (x != NULL)
+ x_text = x[0];
+ if (y != NULL)
+ y_text = y[0];
+
+
+ _update_pango_layout (view, n, string, x_text, y_text, n_dx, dx, n_dy, dy, &path_infos);
if (style->writing_mode->value == LSM_SVG_WRITING_MODE_TB ||
style->writing_mode->value == LSM_SVG_WRITING_MODE_TB_RL) {
- cairo_save (view->dom_view.cairo);
- cairo_rotate (view->dom_view.cairo, M_PI / 2.0);
- cairo_move_to (view->dom_view.cairo, path_infos.extents.x1, path_infos.extents.y1);
+ cairo_save (cairo);
+ cairo_rotate (cairo, M_PI / 2.0);
+ cairo_move_to (cairo, path_infos.extents.x1, path_infos.extents.y1);
process_path (view, &path_infos);
- cairo_restore (view->dom_view.cairo);
+ cairo_restore (cairo);
} else {
- cairo_move_to (view->dom_view.cairo, path_infos.extents.x1, path_infos.extents.y1);
+ cairo_move_to (cairo, path_infos.extents.x1, path_infos.extents.y1);
process_path (view, &path_infos);
}
+ layout_iter = pango_layout_get_iter (view->pango_layout);
+ pango_layout_iter_get_line_extents (layout_iter, NULL, &extents);
+ baseline = pango_units_to_double (pango_layout_iter_get_baseline (layout_iter));
+ pango_layout_iter_free (layout_iter);
+
+ x_end = pango_units_to_double (extents.x + extents.width) + path_infos.extents.x1;
+ y_end = pango_units_to_double (extents.y) + baseline + path_infos.extents.y1;
+
+ if (view->debug_text) {
+ double x1, y1;
+
+ lsm_debug_render ("[LsmSvgView::_show_text] Logical extents %gx%g at %g,%g\n",
+ pango_units_to_double (extents.width),
+ pango_units_to_double (extents.height),
+ pango_units_to_double (extents.x),
+ pango_units_to_double (extents.y));
+
+ lsm_debug_render ("[LsmSvgView::_show_text] End point is %g, %g\n", x_end, y_end);
+ lsm_debug_render ("[LsmSvgView::_show_text] Baseline = %g\n", baseline);
+
+ x1 = 1;
+ y1 = 1;
+ cairo_device_to_user_distance (cairo, &x1, &y1);
+
+ cairo_set_source_rgba (cairo, 1.0, 0.0, 0.0, 0.2);
+ cairo_set_line_width (cairo, x1);
+ cairo_rectangle (cairo, path_infos.extents.x1, path_infos.extents.y1,
+ pango_units_to_double (extents.x + extents.width),
+ pango_units_to_double (extents.y + extents.height));
+ cairo_stroke (cairo);
+ cairo_set_source_rgba (cairo, 1.0, 0.0, 0.0, 0.2);
+ cairo_arc (cairo, x_end, y_end, 4.0 * x1, 0.0, 2.0 * M_PI);
+ cairo_arc (cairo, path_infos.extents.x1, path_infos.extents.y1, 4.0 * x1, 0.0, 2.0 * M_PI);
+ cairo_fill (cairo);
+ }
+
+ cairo_move_to (cairo, x_end, y_end);
+
_unlock_pango_layout (view, need_pop);
}
void
-lsm_svg_view_text_extents (LsmSvgView *view, char const *string, double x, double y, LsmExtents *extents)
+lsm_svg_view_start_text (LsmSvgView *view)
+{
+ g_return_if_fail (LSM_IS_SVG_VIEW (view));
+
+ cairo_move_to (view->dom_view.cairo, 0, 0);
+}
+
+void
+lsm_svg_view_end_text (LsmSvgView *view)
+{
+ g_return_if_fail (LSM_IS_SVG_VIEW (view));
+
+ cairo_new_path (view->dom_view.cairo);
+}
+
+void
+lsm_svg_view_show_text (LsmSvgView *view, char const *string,
+ unsigned int n_x, double *x, unsigned int n_y, double *y,
+ unsigned int n_dx, double *dx, unsigned int n_dy, double *dy)
+{
+ unsigned int n, i;
+ char *iter = (char *) string;
+
+ if (string == NULL || string[0] == '\0')
+ return;
+
+ g_return_if_fail (LSM_IS_SVG_VIEW (view));
+ g_return_if_fail (n_x > 0 || x == NULL);
+ g_return_if_fail (n_y > 0 || y == NULL);
+ g_return_if_fail (n_dx > 0 || dx == NULL);
+ g_return_if_fail (n_dy > 0 || dy == NULL);
+
+ n = MAX (n_x, n_y);
+ if (n <= 1) {
+ _show_text (view, strlen (string), string, n_x, x, n_y, y, n_dx, dx, n_dy, dy);
+ return;
+ }
+
+ for (i = 0; (i < n - 1) && iter[0] != '\0'; i++) {
+ char *next_char;
+
+ next_char = g_utf8_next_char (iter);
+ _show_text (view, next_char - iter, iter,
+ i < n_x ? n_x - i : 0,
+ i < n_x ? &x[i] : NULL,
+ i < n_y ? n_y - i : 0,
+ i < n_y ? &y[i] : NULL,
+ i < n_dx ? n_dx - i : 0,
+ i < n_dx ? &dx[i] : NULL,
+ i < n_dy ? n_dy - i : 0,
+ i < n_dy ? &dy[i] : NULL);
+ iter = next_char;
+ }
+
+ if (iter[0] != '\0')
+ _show_text (view, strlen (iter), iter,
+ i < n_x ? n_x - i : 0,
+ i < n_x ? &x[i] : NULL,
+ i < n_y ? n_y - i : 0,
+ i < n_y ? &y[i] : NULL,
+ i < n_dx ? n_dx - i : 0,
+ i < n_dx ? &dx[i] : NULL,
+ i < n_dy ? n_dy - i : 0,
+ i < n_dy ? &dy[i] : NULL);
+}
+
+void
+lsm_svg_view_text_extents (LsmSvgView *view, char const *string,
+ double x, double y,
+ unsigned int n_dx, double *dx, unsigned int n_dy, double *dy,
+ LsmExtents *extents)
{
LsmSvgViewPathInfos path_infos = default_path_infos;
gboolean need_pop;
@@ -1235,7 +1416,7 @@ lsm_svg_view_text_extents (LsmSvgView *view, char const *string, double x, doubl
need_pop = _lock_pango_layout (view);
- _update_pango_layout (view, string, x, y, &path_infos);
+ _update_pango_layout (view, strlen (string), string, x, y, n_dx, dx, n_dy, dy, &path_infos);
_unlock_pango_layout (view, need_pop);
@@ -2354,6 +2535,10 @@ lsm_svg_view_set_debug (LsmDomView *view, const char *feature, gboolean enable)
svg_view->debug_mask = enable;
else if (g_strcmp0 (feature, "pattern") == 0)
svg_view->debug_pattern = enable;
+ else if (g_strcmp0 (feature, "group") == 0)
+ svg_view->debug_group = enable;
+ else if (g_strcmp0 (feature, "text") == 0)
+ svg_view->debug_text = enable;
}
LsmSvgView *
diff --git a/src/lsmsvgview.h b/src/lsmsvgview.h
index 23de59b..c60203c 100644
--- a/src/lsmsvgview.h
+++ b/src/lsmsvgview.h
@@ -79,6 +79,8 @@ struct _LsmSvgView {
gboolean debug_filter;
gboolean debug_mask;
gboolean debug_pattern;
+ gboolean debug_group;
+ gboolean debug_text;
};
struct _LsmSvgViewClass {
@@ -91,6 +93,8 @@ LsmSvgView * lsm_svg_view_new (LsmSvgDocument *document);
double lsm_svg_view_normalize_length (LsmSvgView *view, const LsmSvgLength *length,
LsmSvgLengthDirection direction);
+double * lsm_svg_view_normalize_length_list (LsmSvgView *view, const LsmSvgLengthList *list, LsmSvgLengthDirection direction,
+ unsigned int *n_data);
const LsmBox * lsm_svg_view_get_pattern_extents (LsmSvgView *view);
const LsmBox * lsm_svg_view_get_object_extents (LsmSvgView *view);
@@ -124,8 +128,15 @@ void lsm_svg_view_show_path (LsmSvgView *view, const char *d);
void lsm_svg_view_show_line (LsmSvgView *view, double x1, double y1, double x2, double y2);
void lsm_svg_view_show_polyline (LsmSvgView *view, const char *points);
void lsm_svg_view_show_polygon (LsmSvgView *view, const char *points);
-void lsm_svg_view_show_text (LsmSvgView *view, char const *text, double x, double y);
-void lsm_svg_view_text_extents (LsmSvgView *view, char const *string, double x, double y, LsmExtents *extents);
+void lsm_svg_view_start_text (LsmSvgView *view);
+void lsm_svg_view_end_text (LsmSvgView *view);
+void lsm_svg_view_show_text (LsmSvgView *view, char const *string,
+ unsigned int n_x, double *x, unsigned int n_y, double *y,
+ unsigned int n_dx, double *dx, unsigned int n_dy, double *dy);
+void lsm_svg_view_text_extents (LsmSvgView *view, char const *string,
+ double x, double y,
+ unsigned int n_dx, double *dx, unsigned int n_dy, double *dy,
+ LsmExtents *extents);
void lsm_svg_view_show_pixbuf (LsmSvgView *view, GdkPixbuf *pixbuf);
void lsm_svg_view_push_viewbox (LsmSvgView *view, const LsmBox *viewbox);
diff --git a/tests/.gitignore b/tests/.gitignore
index 450d4ba..21a68cd 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -1,4 +1,5 @@
dom
+str
lsm-test
fuzz.*
*-diff.png
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]