diff options
| author | Jabier Arraiza Cenoz <jabier.arraiza@marker.es> | 2015-03-18 18:07:14 +0000 |
|---|---|---|
| committer | Jabiertxof <jtx@jtx.marker.es> | 2015-03-18 18:07:14 +0000 |
| commit | e77956b4dbd029c9f6949f81fe083606f995c624 (patch) | |
| tree | 74adda4df8986d65f70efb341c6235277361fd35 /src/libnrtype | |
| parent | updated code to work on 0.92 code (diff) | |
| parent | Latvian translation update (diff) | |
| download | inkscape-e77956b4dbd029c9f6949f81fe083606f995c624.tar.gz inkscape-e77956b4dbd029c9f6949f81fe083606f995c624.zip | |
update to trunk
(bzr r12588.1.39)
Diffstat (limited to 'src/libnrtype')
| -rw-r--r-- | src/libnrtype/Layout-TNG-Compute.cpp | 74 | ||||
| -rw-r--r-- | src/libnrtype/Layout-TNG-Input.cpp | 7 | ||||
| -rw-r--r-- | src/libnrtype/Layout-TNG-OutIter.cpp | 27 | ||||
| -rw-r--r-- | src/libnrtype/Layout-TNG-Output.cpp | 32 | ||||
| -rw-r--r-- | src/libnrtype/Layout-TNG.cpp | 9 | ||||
| -rw-r--r-- | src/libnrtype/Layout-TNG.h | 47 | ||||
| -rw-r--r-- | src/libnrtype/font-lister.cpp | 19 |
7 files changed, 166 insertions, 49 deletions
diff --git a/src/libnrtype/Layout-TNG-Compute.cpp b/src/libnrtype/Layout-TNG-Compute.cpp index bd1acbe46..beff3734b 100644 --- a/src/libnrtype/Layout-TNG-Compute.cpp +++ b/src/libnrtype/Layout-TNG-Compute.cpp @@ -344,7 +344,7 @@ static void dumpUnbrokenSpans(ParagraphInfo *para){ if (char_attributes.is_mandatory_break && span->end != span->start) { *last_emergency_break_span = *last_break_span = *span; - TRACE(("span %d end of para; width = %f chars = %d\n", span->start.iter_span - para.unbroken_spans.begin(), span->width, char_count)); + TRACE(("span %ld end of para; width = %f chars = %d\n", span->start.iter_span - para.unbroken_spans.begin(), span->width, char_count)); return false; } @@ -362,7 +362,7 @@ static void dumpUnbrokenSpans(ParagraphInfo *para){ } // todo: break between chars if necessary (ie no word breaks present) when doing rectangular flowing - // sum the glyph widths, letter spacing and word spacing to get the character width + // sum the glyph widths, letter spacing, word spacing, and textLength adjustment to get the character width double char_width = 0.0; while (span->end_glyph_index < (unsigned)span->end.iter_span->glyph_string->num_glyphs && span->end.iter_span->glyph_string->log_clusters[span->end_glyph_index] <= (int)span->end.char_byte) { @@ -373,9 +373,10 @@ static void dumpUnbrokenSpans(ParagraphInfo *para){ span->end_glyph_index++; } if (char_attributes.is_cursor_position) - char_width += text_source->style->letter_spacing.computed; + char_width += text_source->style->letter_spacing.computed * _flow.getTextLengthMultiplierDue(); if (char_attributes.is_white) - char_width += text_source->style->word_spacing.computed; + char_width += text_source->style->word_spacing.computed * _flow.getTextLengthMultiplierDue(); + char_width += _flow.getTextLengthIncrementDue(); span->width += char_width; IFTRACE(char_count++); @@ -400,13 +401,13 @@ static void dumpUnbrokenSpans(ParagraphInfo *para){ span->word_spacing = text_source->style->word_spacing.computed; if (test_width > maximum_width && !char_attributes.is_white) { // whitespaces don't matter, we can put as many as we want at eol - TRACE(("span %d exceeded scanrun; width = %f chars = %d\n", span->start.iter_span - para.unbroken_spans.begin(), span->width, char_count)); + TRACE(("span %ld exceeded scanrun; width = %f chars = %d\n", span->start.iter_span - para.unbroken_spans.begin(), span->width, char_count)); return false; } } while (span->end.char_byte != 0); // while we haven't wrapped to the next span - TRACE(("fitted span %d width = %f chars = %d\n", span->start.iter_span - para.unbroken_spans.begin(), span->width, char_count)); + TRACE(("fitted span %ld width = %f chars = %d\n", span->start.iter_span - para.unbroken_spans.begin(), span->width, char_count)); return true; } @@ -661,6 +662,14 @@ static void dumpUnbrokenSpans(ParagraphInfo *para){ new_glyph.in_character = _flow._characters.size(); new_glyph.rotation = glyph_rotate; + // We may have scaled font size to fit textLength; now, if + // @lengthAdjust=spacingAndGlyphs, this scaling must be only horizontal, + // not vertical, so we unscale it back vertically during output + if (_flow.lengthAdjust == Inkscape::Text::Layout::LENGTHADJUST_SPACINGANDGLYPHS) + new_glyph.vertical_scale = 1.0 / _flow.getTextLengthMultiplierDue(); + else + new_glyph.vertical_scale = 1.0; + /* put something like this back in when we do glyph-rotation-horizontal/vertical if (new_span.block_progression == LEFT_TO_RIGHT || new_span.block_progression == RIGHT_TO_LEFT) { new_glyph.x += new_span.line_height.ascent; @@ -743,9 +752,10 @@ static void dumpUnbrokenSpans(ParagraphInfo *para){ new_character.in_glyph = _flow._glyphs.size() - 1; _flow._characters.push_back(new_character); if (new_character.char_attributes.is_white) - advance_width += text_source->style->word_spacing.computed + add_to_each_whitespace; // justification + advance_width += text_source->style->word_spacing.computed * _flow.getTextLengthMultiplierDue() + add_to_each_whitespace; // justification if (new_character.char_attributes.is_cursor_position) - advance_width += text_source->style->letter_spacing.computed; + advance_width += text_source->style->letter_spacing.computed * _flow.getTextLengthMultiplierDue(); + advance_width += _flow.getTextLengthIncrementDue(); iter_source_text++; char_index_in_unbroken_span++; char_byte = iter_source_text.base() - unbroken_span.input_stream_first_character.base(); @@ -1111,13 +1121,13 @@ unsigned Layout::Calculator::_buildSpansForPara(ParagraphInfo *para) const UnbrokenSpan new_span; new_span.pango_item_index = -1; new_span.input_index = input_index; - new_span.line_height.ascent = control_code->ascent; - new_span.line_height.descent = control_code->descent; + new_span.line_height.ascent = control_code->ascent * _flow.getTextLengthMultiplierDue(); + new_span.line_height.descent = control_code->descent * _flow.getTextLengthMultiplierDue(); new_span.line_height.leading = 0.0; new_span.text_bytes = 0; new_span.char_index_in_para = char_index_in_para; para->unbroken_spans.push_back(new_span); - TRACE(("add gap span %d\n", para->unbroken_spans.size() - 1)); + TRACE(("add gap span %lu\n", para->unbroken_spans.size() - 1)); } } else if (_flow._input_stream[input_index]->Type() == TEXT_SOURCE && pango_item_index < para->pango_items.size()) { Layout::InputStreamTextSource const *text_source = static_cast<Layout::InputStreamTextSource const *>(_flow._input_stream[input_index]); @@ -1154,13 +1164,13 @@ unsigned Layout::Calculator::_buildSpansForPara(ParagraphInfo *para) const if (_block_progression == TOP_TO_BOTTOM || _block_progression == BOTTOM_TO_TOP) { if (text_source->x.size() > char_index_in_source) new_span.x = text_source->x[char_index_in_source]; if (text_source->y.size() > char_index_in_source) new_span.y = text_source->y[char_index_in_source]; - if (text_source->dx.size() > char_index_in_source) new_span.dx = text_source->dx[char_index_in_source]; - if (text_source->dy.size() > char_index_in_source) new_span.dy = text_source->dy[char_index_in_source]; + if (text_source->dx.size() > char_index_in_source) new_span.dx = text_source->dx[char_index_in_source].computed * _flow.getTextLengthMultiplierDue(); + if (text_source->dy.size() > char_index_in_source) new_span.dy = text_source->dy[char_index_in_source].computed * _flow.getTextLengthMultiplierDue(); } else { if (text_source->x.size() > char_index_in_source) new_span.y = text_source->x[char_index_in_source]; if (text_source->y.size() > char_index_in_source) new_span.x = text_source->y[char_index_in_source]; - if (text_source->dx.size() > char_index_in_source) new_span.dy = text_source->dx[char_index_in_source]; - if (text_source->dy.size() > char_index_in_source) new_span.dx = text_source->dy[char_index_in_source]; + if (text_source->dx.size() > char_index_in_source) new_span.dy = text_source->dx[char_index_in_source].computed * _flow.getTextLengthMultiplierDue(); + if (text_source->dy.size() > char_index_in_source) new_span.dx = text_source->dy[char_index_in_source].computed * _flow.getTextLengthMultiplierDue(); } if (text_source->rotate.size() > char_index_in_source) new_span.rotate = text_source->rotate[char_index_in_source]; else if (char_index_in_source == 0) new_span.rotate = 0.f; @@ -1189,7 +1199,7 @@ unsigned Layout::Calculator::_buildSpansForPara(ParagraphInfo *para) const } // now we know the length, do some final calculations and add the UnbrokenSpan to the list - new_span.font_size = text_source->styleComputeFontSize(); + new_span.font_size = text_source->styleComputeFontSize() * _flow.getTextLengthMultiplierDue(); if (new_span.text_bytes) { new_span.glyph_string = pango_glyph_string_new(); /* Some assertions intended to help diagnose bug #1277746. */ @@ -1289,7 +1299,7 @@ unsigned Layout::Calculator::_buildSpansForPara(ParagraphInfo *para) const new_span.baseline_shift = text_source->style->baseline_shift.computed; // TODO: metrics for vertical text - TRACE(("add text span %d \"%s\"\n", para->unbroken_spans.size(), text_source->text->raw().substr(span_start_byte_in_source, new_span.text_bytes).c_str())); + TRACE(("add text span %lu \"%s\"\n", para->unbroken_spans.size(), text_source->text->raw().substr(span_start_byte_in_source, new_span.text_bytes).c_str())); TRACE((" %d glyphs\n", new_span.glyph_string->num_glyphs)); } else { // if there's no text we still need to initialise the styles @@ -1302,7 +1312,7 @@ unsigned Layout::Calculator::_buildSpansForPara(ParagraphInfo *para) const new_span.line_height.setZero(); new_span.line_height_multiplier = 1.0; } - TRACE(("add style init span %d\n", para->unbroken_spans.size())); + TRACE(("add style init span %lu\n", para->unbroken_spans.size())); } para->unbroken_spans.push_back(new_span); @@ -1338,7 +1348,7 @@ bool Layout::Calculator::_goToNextWrapShape() _current_shape_index++; if (_current_shape_index == _flow._input_wrap_shapes.size()) return false; _scanline_maker = new ShapeScanlineMaker(_flow._input_wrap_shapes[_current_shape_index].shape, _block_progression); - TRACE(("begin wrap shape %d\n", _current_shape_index)); + TRACE(("begin wrap shape %u\n", _current_shape_index)); return true; } @@ -1396,7 +1406,7 @@ bool Layout::Calculator::_findChunksForLine(ParagraphInfo const ¶, scan_runs = _scanline_maker->makeScanline(*line_height); } - TRACE(("finding line fit y=%f, %d scan runs\n", scan_runs.front().y, scan_runs.size())); + TRACE(("finding line fit y=%f, %lu scan runs\n", scan_runs.front().y, scan_runs.size())); chunk_info->clear(); chunk_info->reserve(scan_runs.size()); if (para.direction == RIGHT_TO_LEFT) std::reverse(scan_runs.begin(), scan_runs.end()); @@ -1495,7 +1505,7 @@ bool Layout::Calculator::_buildChunksInScanRun(ParagraphInfo const ¶, } } - TRACE(("chunk complete, used %f width (%d whitespaces, %d brokenspans)\n", new_chunk.text_width, new_chunk.whitespace_count, new_chunk.broken_spans.size())); + TRACE(("chunk complete, used %f width (%d whitespaces, %lu brokenspans)\n", new_chunk.text_width, new_chunk.whitespace_count, new_chunk.broken_spans.size())); chunk_info->push_back(new_chunk); if (scan_run.width() >= 4.0 * line_height->total() && last_span_at_break.end == start_span_pos) { @@ -1533,7 +1543,7 @@ bool Layout::Calculator::_buildChunksInScanRun(ParagraphInfo const ¶, chunk_info->back().text_width += last_span_at_break.width; chunk_info->back().whitespace_count += last_span_at_break.whitespace_count; } - TRACE(("correction: fitted span %d width = %f\n", last_span_at_break.start.iter_span - para.unbroken_spans.begin(), last_span_at_break.width)); + TRACE(("correction: fitted span %lu width = %f\n", last_span_at_break.start.iter_span - para.unbroken_spans.begin(), last_span_at_break.width)); } } @@ -1556,6 +1566,7 @@ bool Layout::Calculator::_buildChunksInScanRun(ParagraphInfo const ¶, return true; } + /** The management function to start the whole thing off. */ bool Layout::Calculator::calculate() { @@ -1605,7 +1616,7 @@ bool Layout::Calculator::calculate() else para.alignment = para.direction == LEFT_TO_RIGHT ? LEFT : RIGHT; - TRACE(("para prepared, adding as #%d\n", _flow._paragraphs.size())); + TRACE(("para prepared, adding as #%lu\n", _flow._paragraphs.size())); Layout::Paragraph new_paragraph; new_paragraph.base_direction = para.direction; new_paragraph.alignment = para.alignment; @@ -1627,7 +1638,7 @@ bool Layout::Calculator::calculate() _scanline_maker->completeLine(); // Increments y by line height } while (span_pos.iter_span != para.unbroken_spans.end()); - TRACE(("para %d end\n\n", _flow._paragraphs.size() - 1)); + TRACE(("para %lu end\n\n", _flow._paragraphs.size() - 1)); if (_scanline_maker != NULL) { bool is_empty_para = _flow._characters.empty() || _flow._characters.back().line(&_flow).in_paragraph != _flow._paragraphs.size() - 1; if ((is_empty_para && para_end_input_index + 1 >= _flow._input_stream.size()) @@ -1690,6 +1701,14 @@ bool Layout::Calculator::calculate() _flow._input_truncated = true; } + if (_flow.textLength._set) { + // Calculate the adjustment needed to meet the textLength + double actual_length = _flow.getActualLength(); + double difference = _flow.textLength.computed - actual_length; + _flow.textLengthMultiplier = (actual_length + difference) / actual_length; + _flow.textLengthIncrement = difference / (_flow._characters.size() == 1? 1 : _flow._characters.size() - 1); + } + return true; } @@ -1739,7 +1758,12 @@ void Layout::_calculateCursorShapeForEmpty() bool Layout::calculateFlow() { - bool result = Calculator(this).calculate(); + Layout::Calculator calc = Calculator(this); + bool result = calc.calculate(); + if (textLengthIncrement != 0) { + TRACE(("Recalculating layout the second time to fit textLength!\n")); + result = calc.calculate(); + } if (_characters.empty()) _calculateCursorShapeForEmpty(); return result; diff --git a/src/libnrtype/Layout-TNG-Input.cpp b/src/libnrtype/Layout-TNG-Input.cpp index fa1e8c11b..84f3f260e 100644 --- a/src/libnrtype/Layout-TNG-Input.cpp +++ b/src/libnrtype/Layout-TNG-Input.cpp @@ -72,6 +72,11 @@ void Layout::appendText(Glib::ustring const &text, SPStyle *style, void *source_ last_rotate = *it; new_source->rotate.resize(1, last_rotate); } + new_source->textLength._set = optional_attributes->textLength._set; + new_source->textLength.value = optional_attributes->textLength.value; + new_source->textLength.computed = optional_attributes->textLength.computed; + new_source->textLength.unit = optional_attributes->textLength.unit; + new_source->lengthAdjust = optional_attributes->lengthAdjust; } _input_stream.push_back(new_source); @@ -325,7 +330,7 @@ PangoFontDescription *Layout::InputStreamTextSource::styleGetFontDescription() c Layout::InputStreamTextSource::~InputStreamTextSource() { - sp_style_unref(style); + sp_style_unref(style); } }//namespace Text diff --git a/src/libnrtype/Layout-TNG-OutIter.cpp b/src/libnrtype/Layout-TNG-OutIter.cpp index 6dc42d998..c9c318960 100644 --- a/src/libnrtype/Layout-TNG-OutIter.cpp +++ b/src/libnrtype/Layout-TNG-OutIter.cpp @@ -401,15 +401,17 @@ std::vector<Geom::Point> Layout::createSelectionShape(iterator const &it_start, bottom_right[Geom::X] = span_x + _characters[char_index].x; double baseline_y = _spans[span_index].line(this).baseline_y + _spans[span_index].baseline_shift; + double vertical_scale = _glyphs.back().vertical_scale; + if (_directions_are_orthogonal(_blockProgression(), TOP_TO_BOTTOM)) { - double span_height = _spans[span_index].line_height.ascent + _spans[span_index].line_height.descent; + double span_height = vertical_scale * (_spans[span_index].line_height.ascent + _spans[span_index].line_height.descent); top_left[Geom::Y] = top_left[Geom::X]; top_left[Geom::X] = baseline_y - span_height * 0.5; bottom_right[Geom::Y] = bottom_right[Geom::X]; bottom_right[Geom::X] = baseline_y + span_height * 0.5; } else { - top_left[Geom::Y] = baseline_y - _spans[span_index].line_height.ascent; - bottom_right[Geom::Y] = baseline_y + _spans[span_index].line_height.descent; + top_left[Geom::Y] = baseline_y - vertical_scale * _spans[span_index].line_height.ascent; + bottom_right[Geom::Y] = baseline_y + vertical_scale * _spans[span_index].line_height.descent; } } @@ -505,21 +507,23 @@ void Layout::queryCursorShape(iterator const &it, Geom::Point &position, double position[Geom::Y] = span->line(this).baseline_y + span->baseline_shift; } // up to now *position is the baseline point, not the final point which will be the bottom of the descent + double vertical_scale = _glyphs.back().vertical_scale; + if (_directions_are_orthogonal(_blockProgression(), TOP_TO_BOTTOM)) { - height = span->line_height.ascent + span->line_height.descent; + height = vertical_scale * span->line_height.ascent + span->line_height.descent; rotation += M_PI / 2; std::swap(position[Geom::X], position[Geom::Y]); - position[Geom::X] -= sin(rotation) * height * 0.5; - position[Geom::Y] += cos(rotation) * height * 0.5; + position[Geom::X] -= vertical_scale * sin(rotation) * height * 0.5; + position[Geom::Y] += vertical_scale * cos(rotation) * height * 0.5; } else { double caret_slope_run = 0.0, caret_slope_rise = 1.0; if (span->font) const_cast<font_instance*>(span->font)->FontSlope(caret_slope_run, caret_slope_rise); double caret_slope = atan2(caret_slope_run, caret_slope_rise); - height = (span->line_height.ascent + span->line_height.descent) / cos(caret_slope); + height = vertical_scale * (span->line_height.ascent + span->line_height.descent) / cos(caret_slope); rotation += caret_slope; - position[Geom::X] -= sin(rotation) * span->line_height.descent; - position[Geom::Y] += cos(rotation) * span->line_height.descent; + position[Geom::X] -= sin(rotation) * vertical_scale * span->line_height.descent; + position[Geom::Y] += cos(rotation) * vertical_scale * span->line_height.descent; } } } @@ -601,9 +605,10 @@ void Layout::simulateLayoutUsingKerning(iterator const &from, iterator const &to if (input_item->Type() == TEXT_SOURCE) { SPStyle const *style = static_cast<InputStreamTextSource*>(input_item)->style; if (_characters[char_index].char_attributes.is_white) - dx -= style->word_spacing.computed; + dx -= style->word_spacing.computed * getTextLengthMultiplierDue(); if (_characters[char_index].char_attributes.is_cursor_position) - dx -= style->letter_spacing.computed; + dx -= style->letter_spacing.computed * getTextLengthMultiplierDue(); + dx -= getTextLengthIncrementDue(); } if (fabs(dx) > 0.0001) { diff --git a/src/libnrtype/Layout-TNG-Output.cpp b/src/libnrtype/Layout-TNG-Output.cpp index 61a141cc3..6e3faf33b 100644 --- a/src/libnrtype/Layout-TNG-Output.cpp +++ b/src/libnrtype/Layout-TNG-Output.cpp @@ -108,7 +108,7 @@ void Layout::_getGlyphTransformMatrix(int glyph_index, Geom::Affine *matrix) con (*matrix)[0] = span.font_size * cos_rotation; (*matrix)[1] = span.font_size * sin_rotation; (*matrix)[2] = span.font_size * sin_rotation; - (*matrix)[3] = -span.font_size * cos_rotation; + (*matrix)[3] = -span.font_size * cos_rotation * (_glyphs[glyph_index].vertical_scale); // unscale vertically so the specified text height is preserved if lengthAdjust=spacingAndGlyphs if (span.block_progression == LEFT_TO_RIGHT || span.block_progression == RIGHT_TO_LEFT) { (*matrix)[4] = _lines[_chunks[span.in_chunk].in_line].baseline_y + _glyphs[glyph_index].y; (*matrix)[5] = _chunks[span.in_chunk].left_x + _glyphs[glyph_index].x; @@ -804,6 +804,36 @@ void Layout::transform(Geom::Affine const &transform) } } +double Layout::getTextLengthIncrementDue() const +{ + if (textLength._set && textLengthIncrement != 0 && lengthAdjust == Inkscape::Text::Layout::LENGTHADJUST_SPACING) { + return textLengthIncrement; + } + return 0; +} + + +double Layout::getTextLengthMultiplierDue() const +{ + if (textLength._set && textLengthMultiplier != 1 && (lengthAdjust == Inkscape::Text::Layout::LENGTHADJUST_SPACINGANDGLYPHS)) { + return textLengthMultiplier; + } + return 1; +} + +double Layout::getActualLength() const +{ + double length = 0; + for (std::vector<Span>::const_iterator it_span = _spans.begin() ; it_span != _spans.end() ; it_span++) { + // take x_end of the last span of each chunk + if (it_span == _spans.end() - 1 || (it_span + 1)->in_chunk != it_span->in_chunk) + length += it_span->x_end; + } + return length; + + +} + }//namespace Text }//namespace Inkscape diff --git a/src/libnrtype/Layout-TNG.cpp b/src/libnrtype/Layout-TNG.cpp index dd9c90949..8b0889188 100644 --- a/src/libnrtype/Layout-TNG.cpp +++ b/src/libnrtype/Layout-TNG.cpp @@ -20,6 +20,10 @@ Layout::Layout() : _input_truncated(0), _path_fitted(NULL) { + textLength._set = false; + textLengthMultiplier = 1; + textLengthIncrement = 0; + lengthAdjust = LENGTHADJUST_SPACING; } Layout::~Layout() @@ -31,6 +35,11 @@ void Layout::clear() { _clearInputObjects(); _clearOutputObjects(); + + textLength._set = false; + textLengthMultiplier = 1; + textLengthIncrement = 0; + lengthAdjust = LENGTHADJUST_SPACING; } bool Layout::_directions_are_orthogonal(Direction d1, Direction d2) diff --git a/src/libnrtype/Layout-TNG.h b/src/libnrtype/Layout-TNG.h index fd5bbfaef..e91c32ebe 100644 --- a/src/libnrtype/Layout-TNG.h +++ b/src/libnrtype/Layout-TNG.h @@ -21,6 +21,7 @@ #include <algorithm> #include <vector> #include <boost/optional.hpp> +#include <svg/svg-length.h> #ifdef HAVE_CAIRO_PDF namespace Inkscape { @@ -37,7 +38,6 @@ using Inkscape::Extension::Internal::CairoRenderContext; class SPStyle; class Shape; struct SPPrintContext; -class SVGLength; class Path; class SPCurve; class font_instance; @@ -160,6 +160,9 @@ public: /** Display alignment for shapes. See appendWrapShape(). */ enum DisplayAlign {DISPLAY_ALIGN_BEFORE, DISPLAY_ALIGN_CENTER, DISPLAY_ALIGN_AFTER}; + /** lengthAdjust values */ + enum LengthAdjust {LENGTHADJUST_SPACING, LENGTHADJUST_SPACINGANDGLYPHS}; + /** The optional attributes which can be applied to a SVG text or related tag. See appendText(). See SVG1.1 section 10.4 for the definitions of all these members. See sp_svg_length_list_read() for @@ -172,6 +175,8 @@ public: std::vector<SVGLength> dx; std::vector<SVGLength> dy; std::vector<SVGLength> rotate; + SVGLength textLength; + LengthAdjust lengthAdjust; }; /** Control codes which can be embedded in the text to be flowed. See @@ -290,6 +295,43 @@ public: //@} + // ************************** textLength and friends ************************* + + /** Gives the length target of this layout, as given by textLength attribute. + + FIXME: by putting it here we only support @textLength on text and flowRoot, not on any + spans inside. For spans, we will need to add markers of start and end of a textLength span + into the _input_stream. These spans can nest (SVG 1.1, section 10.5). After a first layout + calculation, we would go through the input stream and, for each end of a textLength span, + go through its items, choose those where it wasn't yet set by a nested span, calculate + their number of characters, divide the length deficit by it, and set set the + textLengthMultiplier for those characters only. For now we do this for the entire layout, + without dealing with spans. + */ + SVGLength textLength; + + /** How do we meet textLength if specified: by letterspacing or by scaling horizontally */ + LengthAdjust lengthAdjust; + + /** By how much each character needs to be wider or narrower, using the specified lengthAdjust + strategy, for the layout to meet its textLength target. Is set to non-zero after the layout + is calculated for the first time, then it is recalculated with each glyph getting its adjustment. */ + /** This one is used by scaling strategies: each glyph width is multiplied by this */ + double textLengthMultiplier; + /** This one is used by letterspacing strategy: to each glyph width, this is added */ + double textLengthIncrement; + + /** Get the actual spacing increment if it's due with the current values of above stuff, otherwise 0 */ + double getTextLengthIncrementDue() const; + /** Get the actual scale multiplier if it's due with the current values of above stuff, otherwise 1 */ + double getTextLengthMultiplierDue() const; + + /** Get actual length of layout, by summing span lengths. For one-line non-flowed text, just + the width; for multiline non-flowed, sum of lengths of all lines; for flowed text, sum of + scanline widths for all non-last lines plus text width of last line. */ + double getActualLength() const; + + // ************************** doing the actual flowing ************************* /** \name Processing @@ -618,6 +660,8 @@ private: std::vector<SVGLength> dx; std::vector<SVGLength> dy; std::vector<SVGLength> rotate; + SVGLength textLength; + LengthAdjust lengthAdjust; // a few functions for some of the more complicated style accesses float styleComputeFontSize() const; @@ -701,6 +745,7 @@ private: float y; /// relative to the current line's baseline float rotation; /// absolute, modulo any object transforms, which we don't know about float width; + float vertical_scale; /// to implement lengthAdjust="spacingAndGlyphs" that must scale glyphs only horizontally; instead we change font size and then undo that change vertically only inline Span const & span(Layout const *l) const {return l->_spans[l->_characters[in_character].in_span];} inline Chunk const & chunk(Layout const *l) const {return l->_chunks[l->_spans[l->_characters[in_character].in_span].in_chunk];} inline Line const & line(Layout const *l) const {return l->_lines[l->_chunks[l->_spans[l->_characters[in_character].in_span].in_chunk].in_line];} diff --git a/src/libnrtype/font-lister.cpp b/src/libnrtype/font-lister.cpp index fad06cd00..a6ab3b239 100644 --- a/src/libnrtype/font-lister.cpp +++ b/src/libnrtype/font-lister.cpp @@ -385,27 +385,27 @@ std::pair<Glib::ustring, Glib::ustring> FontLister::selection_update() #endif // Get fontspec from a selection, preferences, or thin air. Glib::ustring fontspec; - SPStyle *query = sp_style_new(SP_ACTIVE_DOCUMENT); + SPStyle query(SP_ACTIVE_DOCUMENT); // Directly from stored font specification. int result = - sp_desktop_query_style(SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONT_SPECIFICATION); + sp_desktop_query_style(SP_ACTIVE_DESKTOP, &query, QUERY_STYLE_PROPERTY_FONT_SPECIFICATION); //std::cout << " Attempting selected style" << std::endl; - if (result != QUERY_STYLE_NOTHING && query->font_specification.set) { - fontspec = query->font_specification.value; + if (result != QUERY_STYLE_NOTHING && query.font_specification.set) { + fontspec = query.font_specification.value; //std::cout << " fontspec from query :" << fontspec << ":" << std::endl; } // From style if (fontspec.empty()) { //std::cout << " Attempting desktop style" << std::endl; - int rfamily = sp_desktop_query_style(SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTFAMILY); - int rstyle = sp_desktop_query_style(SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTSTYLE); + int rfamily = sp_desktop_query_style(SP_ACTIVE_DESKTOP, &query, QUERY_STYLE_PROPERTY_FONTFAMILY); + int rstyle = sp_desktop_query_style(SP_ACTIVE_DESKTOP, &query, QUERY_STYLE_PROPERTY_FONTSTYLE); // Must have text in selection if (rfamily != QUERY_STYLE_NOTHING && rstyle != QUERY_STYLE_NOTHING) { - fontspec = fontspec_from_style(query); + fontspec = fontspec_from_style(&query); } //std::cout << " fontspec from style :" << fontspec << ":" << std::endl; } @@ -413,11 +413,10 @@ std::pair<Glib::ustring, Glib::ustring> FontLister::selection_update() // From preferences if (fontspec.empty()) { //std::cout << " Attempting preferences" << std::endl; - sp_style_read_from_prefs(query, "/tools/text"); - fontspec = fontspec_from_style(query); + query.readFromPrefs("/tools/text"); + fontspec = fontspec_from_style(&query); //std::cout << " fontspec from prefs :" << fontspec << ":" << std::endl; } - sp_style_unref(query); // From thin air if (fontspec.empty()) { |
