diff options
| -rw-r--r-- | src/libnrtype/Layout-TNG-Compute.cpp | 42 | ||||
| -rw-r--r-- | src/object/sp-text.cpp | 46 | ||||
| -rw-r--r-- | src/object/sp-text.h | 4 |
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 ¶, 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 ¶, // 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 ¶, 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;} |
