summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTavmjong Bah <tavmjong@free.fr>2019-03-23 11:32:10 +0000
committerTavmjong Bah <tavmjong@free.fr>2019-03-23 11:32:10 +0000
commit605ef4a43ea0cf89d19d46679e9e0b5bb9e464b2 (patch)
tree283dd62c5459007d9400dcf5195e6f68d386c82a
parentAllow guide duplication in guides dialog (diff)
downloadinkscape-605ef4a43ea0cf89d19d46679e9e0b5bb9e464b2.tar.gz
inkscape-605ef4a43ea0cf89d19d46679e9e0b5bb9e464b2.zip
Fix text rendering when Inkscape multi-line text has an empty first line.
Possible fix for GitLab issue #45.
-rw-r--r--src/libnrtype/Layout-TNG-Compute.cpp42
-rw-r--r--src/object/sp-text.cpp46
-rw-r--r--src/object/sp-text.h4
3 files changed, 85 insertions, 7 deletions
diff --git a/src/libnrtype/Layout-TNG-Compute.cpp b/src/libnrtype/Layout-TNG-Compute.cpp
index a248847f7..f31fffa86 100644
--- a/src/libnrtype/Layout-TNG-Compute.cpp
+++ b/src/libnrtype/Layout-TNG-Compute.cpp
@@ -560,6 +560,8 @@ void Layout::Calculator::_outputLine(ParagraphInfo const &para,
new_line.baseline_y += line_height.getTypoAscent();
}
+ TRACE((" initial new_line.baseline_y: %f\n", new_line.baseline_y ));
+
new_line.in_shape = _current_shape_index;
_flow._lines.push_back(new_line);
@@ -603,12 +605,15 @@ void Layout::Calculator::_outputLine(ParagraphInfo const &para,
// NOTE: for vertical text, "y" is the user-space "x" value.
if( it_chunk->broken_spans.front().start.iter_span->y._set ) {
- // Use set "y" attribute
+ // Use set "y" attribute for baseline
new_line.baseline_y = it_chunk->broken_spans.front().start.iter_span->y.computed;
+ TRACE((" chunk new_line.baseline_y: %f\n", new_line.baseline_y ));
+
// Save baseline
_flow._lines.back().baseline_y = new_line.baseline_y;
+ // Calculate new top of box... given specified baseline.
double top_of_line_box = new_line.baseline_y;
if( _block_progression == RIGHT_TO_LEFT ) {
// Vertical text, use em box center as baseline
@@ -620,7 +625,7 @@ void Layout::Calculator::_outputLine(ParagraphInfo const &para,
top_of_line_box -= line_height.getTypoAscent();
}
TRACE((" y attribute set, next line top_of_line_box: %f\n", top_of_line_box ));
- // Set the initial y coordinate of the next line (see above).
+ // Set the initial y coordinate of the for this line (see above).
_scanline_maker->setNewYCoordinate(top_of_line_box);
}
@@ -952,10 +957,12 @@ void Layout::Calculator::_createFirstScanlineMaker()
if (_flow._input_wrap_shapes.empty()) {
// create the special no-wrapping infinite scanline maker
double initial_x = 0, initial_y = 0;
- if (!text_source->x.empty())
+ if (!text_source->x.empty()) {
initial_x = text_source->x.front().computed;
- if (!text_source->y.empty())
+ }
+ if (!text_source->y.empty()) {
initial_y = text_source->y.front().computed;
+ }
_scanline_maker = new InfiniteScanlineMaker(initial_x, initial_y, _block_progression);
TRACE((" wrapping disabled\n"));
}
@@ -1878,6 +1885,33 @@ bool Layout::Calculator::calculate()
keep_going = false;
break; // No room for text and not useful to try again at same place.
}
+
+ // For Inkscape multi-line text (using role="line") we run into a problem if the first
+ // line is empty - namely, there is no character to attach a 'y' attribute value. The
+ // result is that the code that takes a baseline position (e.g. 'y') and finds the top
+ // of the layout box is bypassed resulting in wrongly placed text (we layout the text
+ // relative to the top of the box as this is required for text-in-a-shape). We don't
+ // know how to find the top of the box from the 'y' position until we have found the
+ // line height parameters for the given line (after calling _findChunksForLine() just
+ // above).
+ if (para.first_input_index == 0) {
+
+ // Calculate new top of box... given specified baseline.
+ double top_of_line_box = _scanline_maker->yCoordinate(); // Set in constructor.
+ if( _block_progression == RIGHT_TO_LEFT ) {
+ // Vertical text, use em box center as baseline
+ top_of_line_box += 0.5 * line_box_height.emSize();
+ } else if (_block_progression == LEFT_TO_RIGHT ) {
+ // Vertical text, use em box center as baseline
+ top_of_line_box -= 0.5 * line_box_height.emSize();
+ } else {
+ top_of_line_box -= line_box_height.getTypoAscent();
+ }
+ TRACE((" y attribute set, next line top_of_line_box: %f\n", top_of_line_box ));
+ // Set the initial y coordinate of the for this line (see above).
+ _scanline_maker->setNewYCoordinate(top_of_line_box);
+ }
+
_outputLine(para, line_box_height, line_chunk_info);
_scanline_maker->setLineHeight( line_box_height );
_scanline_maker->completeLine(); // Increments y by line height
diff --git a/src/object/sp-text.cpp b/src/object/sp-text.cpp
index ff8bd9af7..b65170642 100644
--- a/src/object/sp-text.cpp
+++ b/src/object/sp-text.cpp
@@ -617,7 +617,7 @@ unsigned SPText::_buildLayoutInput(SPObject *object, Inkscape::Text::Layout::Opt
// we've found 'x' and 'y' and then creating the Shape at the end.)
if (is_horizontal()) {
// Horizontal text
- SVGLength* y = attributes.getFirstYLength();
+ SVGLength* y = _getFirstYLength();
if (y) {
optional_attrs.y.push_back(*y);
} else {
@@ -625,14 +625,13 @@ unsigned SPText::_buildLayoutInput(SPObject *object, Inkscape::Text::Layout::Opt
}
} else {
// Vertical text
- SVGLength* x = attributes.getFirstXLength();
+ SVGLength* x = _getFirstXLength();
if (x) {
optional_attrs.x.push_back(*x);
} else {
std::cerr << "SPText::_buildLayoutInput: No 'x' attribute value with vertical 'inline-size'!" << std::endl;
}
}
-
}
// set textLength on the entire layout, see note in TNG-Layout.h
@@ -773,6 +772,47 @@ Shape* SPText::_buildExclusionShape() const
return result;
}
+
+// SVG requires one to use the first x/y value found on a child element if x/y not given on text
+// element. TODO: Recurse.
+SVGLength*
+SPText::_getFirstXLength()
+{
+ SVGLength* x = attributes.getFirstXLength();
+
+ if (!x) {
+ for (auto& child: children) {
+ if (SP_IS_TSPAN(&child)) {
+ SPTSpan *tspan = SP_TSPAN(&child);
+ x = tspan->attributes.getFirstXLength();
+ break;
+ }
+ }
+ }
+
+ return x;
+}
+
+
+SVGLength*
+SPText::_getFirstYLength()
+{
+ SVGLength* y = attributes.getFirstYLength();
+
+ if (!y) {
+ for (auto& child: children) {
+ if (SP_IS_TSPAN(&child)) {
+ SPTSpan *tspan = SP_TSPAN(&child);
+ y = tspan->attributes.getFirstYLength();
+ break;
+ }
+ }
+ }
+
+ return y;
+}
+
+
void SPText::rebuildLayout()
{
layout.clear();
diff --git a/src/object/sp-text.h b/src/object/sp-text.h
index a4c8b9d84..f2483bd03 100644
--- a/src/object/sp-text.h
+++ b/src/object/sp-text.h
@@ -78,6 +78,10 @@ private:
/** Union all exlusion shapes. */
Shape* _buildExclusionShape() const;
+ /** Find first x/y valuse which may be in a descendent element. */
+ SVGLength* _getFirstXLength();
+ SVGLength* _getFirstYLength();
+
public:
/** Optimize textpath text on next set_transform. */
void optimizeTextpathText() {_optimizeTextpathText = true;}