summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorTavmjong Bah <tavmjong@free.fr>2019-11-13 09:05:52 +0000
committerTavmjong Bah <tavmjong@free.fr>2019-11-13 09:05:52 +0000
commit6ae14ec71c2c005cb03ef6e0f5146bc30441acc7 (patch)
tree8145f98d4c41cd8a1af775575fb910d0adf82b02 /src
parentUpdate inkscape.pot (diff)
downloadinkscape-6ae14ec71c2c005cb03ef6e0f5146bc30441acc7.tar.gz
inkscape-6ae14ec71c2c005cb03ef6e0f5146bc30441acc7.zip
Fix alignment error for inline-size SVG 1.1 fallback text.
Puts white space at end of line into separate tspan when 'text-anchor' is not start.
Diffstat (limited to 'src')
-rw-r--r--src/extension/internal/svg.cpp47
-rw-r--r--src/object/sp-tspan.cpp7
2 files changed, 50 insertions, 4 deletions
diff --git a/src/extension/internal/svg.cpp b/src/extension/internal/svg.cpp
index 932ece46a..bc82c5692 100644
--- a/src/extension/internal/svg.cpp
+++ b/src/extension/internal/svg.cpp
@@ -384,6 +384,11 @@ static void insert_text_fallback( Inkscape::XML::Node *repr, SPDocument *origina
sp_repr_css_attr_unref(css);
}
+ // We need to put trailing white space into it's own tspan for inline size so
+ // it is excluded during calculation of line position in SVG 1.1 renderers.
+ bool trim = text->has_inline_size() &&
+ !(text->style->text_anchor.computed == SP_CSS_TEXT_ANCHOR_START);
+
// Make a list of children to delete at end:
std::vector<Inkscape::XML::Node *> old_children;
for (auto child = repr->firstChild(); child; child = child->next()) {
@@ -408,8 +413,9 @@ static void insert_text_fallback( Inkscape::XML::Node *repr, SPDocument *origina
// Create a <tspan> with 'x' and 'y' for each line.
Inkscape::XML::Node *line_tspan = repr->document()->createElement("svg:tspan");
- // This could be useful if one wants to edit in an old version of Inkscape but we need to check if it breaks anything:
- // line_tspan->setAttribute("sodipodi:role", "line");
+ // This could be useful if one wants to edit in an old version of Inkscape but we
+ // need to check if it breaks anything:
+ line_tspan->setAttribute("sodipodi:role", "line");
Geom::Point line_anchor_point = text->layout.characterAnchorPoint(it);
double line_x = line_anchor_point[Geom::X];
@@ -447,6 +453,13 @@ static void insert_text_fallback( Inkscape::XML::Node *repr, SPDocument *origina
Inkscape::Text::Layout::iterator it_line_end = it;
it_line_end.nextStartOfLine();
+ // Find last span in line so we can put trailing whitespace in its own tspan for SVG 1.1 fallback.
+ Inkscape::Text::Layout::iterator it_last_span = it;
+ it_last_span.nextStartOfLine();
+ it_last_span.prevStartOfSpan();
+
+ Glib::ustring trailing_whitespace;
+
// Loop over chunks in line
while (it != it_line_end) {
@@ -495,6 +508,14 @@ static void insert_text_fallback( Inkscape::XML::Node *repr, SPDocument *origina
Glib::ustring new_string;
while (span_text_start_iter != span_text_end_iter)
new_string += *span_text_start_iter++; // grr. no substr() with iterators
+
+ if (it == it_last_span && trim) {
+ // Found last span in line
+ const auto s = new_string.find_last_not_of(" \t"); // Any other white space characters needed?
+ trailing_whitespace = new_string.substr(s+1, new_string.length());
+ new_string.erase(s+1);
+ }
+
Inkscape::XML::Node *new_text = repr->document()->createTextNode(new_string.c_str());
span_tspan->appendChild(new_text);
Inkscape::GC::release(new_text);
@@ -505,13 +526,33 @@ static void insert_text_fallback( Inkscape::XML::Node *repr, SPDocument *origina
// Add tspan to document
line_tspan->appendChild(span_tspan);
- line_tspan->setAttribute("sodipodi:role", "line");
Inkscape::GC::release(span_tspan);
}
// Add line tspan to document
repr->appendChild(line_tspan);
Inkscape::GC::release(line_tspan);
+
+ // For center and end justified text, we need to remove any spaces and put them
+ // into a separate tspan (alignment is done by "text chunk" and spaces at ends of
+ // line will mess this up).
+ if (trim && trailing_whitespace.length() != 0) {
+
+ Inkscape::XML::Node *space_tspan = repr->document()->createElement("svg:tspan");
+ // Set either 'x' or 'y' to force a new text chunk. To do: this really should
+ // be positioned at the end of the line (overhanging).
+ if (text->is_horizontal()) {
+ sp_repr_set_svg_double(space_tspan, "y", line_y);
+ } else {
+ sp_repr_set_svg_double(space_tspan, "x", line_x);
+ }
+ Inkscape::XML::Node *space = repr->document()->createTextNode(trailing_whitespace.c_str());
+ space_tspan->appendChild(space);
+ Inkscape::GC::release(space);
+ line_tspan->appendChild(space_tspan);
+ Inkscape::GC::release(space_tspan);
+ }
+
}
for (auto i: old_children) {
diff --git a/src/object/sp-tspan.cpp b/src/object/sp-tspan.cpp
index cee3f7d37..bbd8818d6 100644
--- a/src/object/sp-tspan.cpp
+++ b/src/object/sp-tspan.cpp
@@ -60,7 +60,12 @@ void SPTSpan::build(SPDocument *doc, Inkscape::XML::Node *repr) {
this->readAttr( "dx" );
this->readAttr( "dy" );
this->readAttr( "rotate" );
- this->readAttr( "sodipodi:role" );
+
+ // Strip sodipodi:role from SVG 2 flowed text.
+ SPText* text = dynamic_cast<SPText*>(parent);
+ if (text && !(text->has_shape_inside() || text->has_inline_size())) {
+ this->readAttr( "sodipodi:role" );
+ }
SPItem::build(doc, repr);
}