diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 18:24:48 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 18:24:48 +0000 |
commit | cca66b9ec4e494c1d919bff0f71a820d8afab1fa (patch) | |
tree | 146f39ded1c938019e1ed42d30923c2ac9e86789 /src/libnrtype/Layout-TNG-Input.cpp | |
parent | Initial commit. (diff) | |
download | inkscape-upstream.tar.xz inkscape-upstream.zip |
Adding upstream version 1.2.2.upstream/1.2.2upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | src/libnrtype/Layout-TNG-Input.cpp | 241 |
1 files changed, 241 insertions, 0 deletions
diff --git a/src/libnrtype/Layout-TNG-Input.cpp b/src/libnrtype/Layout-TNG-Input.cpp new file mode 100644 index 0000000..cc7d02a --- /dev/null +++ b/src/libnrtype/Layout-TNG-Input.cpp @@ -0,0 +1,241 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Inkscape::Text::Layout - text layout engine input functions + * + * Authors: + * Richard Hughes <cyreve@users.sf.net> + * + * Copyright (C) 2005 Richard Hughes + * + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" // only include where actually required! +#endif + +#ifndef PANGO_ENABLE_ENGINE +#define PANGO_ENABLE_ENGINE +#endif + +#include "Layout-TNG.h" +#include "style.h" +#include "svg/svg-length.h" +#include "FontFactory.h" + + +namespace Inkscape { +namespace Text { + +void Layout::_clearInputObjects() +{ + for(auto & it : _input_stream) { + delete it; + } + + _input_stream.clear(); + _input_wrap_shapes.clear(); +} + +// this function does nothing more than store all its parameters for future reference +void Layout::appendText(Glib::ustring const &text, + SPStyle *style, + SPObject *source, + OptionalTextTagAttrs const *optional_attributes, + unsigned optional_attributes_offset, + Glib::ustring::const_iterator text_begin, + Glib::ustring::const_iterator text_end) +{ + if (style == nullptr) return; + + InputStreamTextSource *new_source = new InputStreamTextSource; + + new_source->source = source; + new_source->text = &text; + new_source->text_begin = text_begin; + new_source->text_end = text_end; + new_source->style = style; + sp_style_ref(style); + + new_source->text_length = 0; + for ( ; text_begin != text_end && text_begin != text.end() ; ++text_begin) + new_source->text_length++; // save this because calculating the length of a UTF-8 string is expensive + + if (optional_attributes) { + // we need to fill in x and y even if the text is empty so that empty paragraphs can be positioned correctly + _copyInputVector(optional_attributes->x, optional_attributes_offset, &new_source->x, std::max(1, new_source->text_length)); + _copyInputVector(optional_attributes->y, optional_attributes_offset, &new_source->y, std::max(1, new_source->text_length)); + _copyInputVector(optional_attributes->dx, optional_attributes_offset, &new_source->dx, new_source->text_length); + _copyInputVector(optional_attributes->dy, optional_attributes_offset, &new_source->dy, new_source->text_length); + _copyInputVector(optional_attributes->rotate, optional_attributes_offset, &new_source->rotate, new_source->text_length); + if (!optional_attributes->rotate.empty() && optional_attributes_offset >= optional_attributes->rotate.size()) { + SVGLength last_rotate; + last_rotate = 0.f; + for (auto it : optional_attributes->rotate) + if (it._set) + 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); +} + +void Layout::_copyInputVector(std::vector<SVGLength> const &input_vector, unsigned input_offset, std::vector<SVGLength> *output_vector, size_t max_length) +{ + output_vector->clear(); + if (input_offset >= input_vector.size()) return; + output_vector->reserve(std::min(max_length, input_vector.size() - input_offset)); + while (input_offset < input_vector.size() && max_length != 0) { + if (!input_vector[input_offset]._set) + break; + output_vector->push_back(input_vector[input_offset]); + input_offset++; + max_length--; + } +} + +// just save what we've been given, really +void Layout::appendControlCode(TextControlCode code, SPObject *source, double width, double ascent, double descent) +{ + InputStreamControlCode *new_code = new InputStreamControlCode; + + new_code->source = source; + new_code->code = code; + new_code->width = width; + new_code->ascent = ascent; + new_code->descent = descent; + + _input_stream.push_back(new_code); +} + +// more saving of the parameters +void Layout::appendWrapShape(Shape const *shape, DisplayAlign display_align) +{ + _input_wrap_shapes.emplace_back(); + _input_wrap_shapes.back().shape = shape; + _input_wrap_shapes.back().display_align = display_align; +} + +Layout::Direction Layout::InputStreamTextSource::styleGetBlockProgression() const +{ + switch( style->writing_mode.computed ) { + case SP_CSS_WRITING_MODE_LR_TB: + case SP_CSS_WRITING_MODE_RL_TB: + return TOP_TO_BOTTOM; + + case SP_CSS_WRITING_MODE_TB_RL: + return RIGHT_TO_LEFT; + + case SP_CSS_WRITING_MODE_TB_LR: + return LEFT_TO_RIGHT; + + default: + std::cerr << "Layout::InputTextStream::styleGetBlockProgression: invalid writing mode." << std::endl; + } + return TOP_TO_BOTTOM; +} + +SPCSSTextOrientation Layout::InputStreamTextSource::styleGetTextOrientation() const +{ + return ((SPCSSTextOrientation)style->text_orientation.computed); +} + +SPCSSBaseline Layout::InputStreamTextSource::styleGetDominantBaseline() const +{ + return ((SPCSSBaseline)style->dominant_baseline.computed); +} + +static Layout::Alignment text_anchor_to_alignment(unsigned anchor, Layout::Direction para_direction) +{ + switch (anchor) { + default: + case SP_CSS_TEXT_ANCHOR_START: return para_direction == Layout::LEFT_TO_RIGHT ? Layout::LEFT : Layout::RIGHT; + case SP_CSS_TEXT_ANCHOR_MIDDLE: return Layout::CENTER; + case SP_CSS_TEXT_ANCHOR_END: return para_direction == Layout::LEFT_TO_RIGHT ? Layout::RIGHT : Layout::LEFT; + } +} + +Layout::Alignment Layout::InputStreamTextSource::styleGetAlignment(Layout::Direction para_direction, bool try_text_align) const +{ + if (!try_text_align) + return text_anchor_to_alignment(style->text_anchor.computed, para_direction); + + // there's no way to tell the difference between text-anchor set higher up the cascade to the default and + // text-anchor never set anywhere in the cascade, so in order to detect which of text-anchor or text-align + // to use we'll have to run up the style tree ourselves. + SPStyle const *this_style = style; + + for ( ; ; ) { + // If both text-align and text-anchor are set at the same level, text-align takes + // precedence because it is the most expressive. + if (this_style->text_align.set) { + switch (style->text_align.computed) { + default: + case SP_CSS_TEXT_ALIGN_START: return para_direction == LEFT_TO_RIGHT ? LEFT : RIGHT; + case SP_CSS_TEXT_ALIGN_END: return para_direction == LEFT_TO_RIGHT ? RIGHT : LEFT; + case SP_CSS_TEXT_ALIGN_LEFT: return LEFT; + case SP_CSS_TEXT_ALIGN_RIGHT: return RIGHT; + case SP_CSS_TEXT_ALIGN_CENTER: return CENTER; + case SP_CSS_TEXT_ALIGN_JUSTIFY: return FULL; + } + } + if (this_style->text_anchor.set) + return text_anchor_to_alignment(this_style->text_anchor.computed, para_direction); + if (this_style->object == nullptr || this_style->object->parent == nullptr) break; + this_style = this_style->object->parent->style; + if (this_style == nullptr) break; + } + return para_direction == LEFT_TO_RIGHT ? LEFT : RIGHT; +} + +font_instance *Layout::InputStreamTextSource::styleGetFontInstance() const +{ + PangoFontDescription *descr = styleGetFontDescription(); + if (descr == nullptr) return nullptr; + font_instance *res = (font_factory::Default())->Face(descr); + pango_font_description_free(descr); + return res; +} + +PangoFontDescription *Layout::InputStreamTextSource::styleGetFontDescription() const +{ + // This use to be done by code here but it duplicated more complete code in FontFactory.cpp. + PangoFontDescription *descr = ink_font_description_from_style( style ); + + // Font size not yet set +#ifdef USE_PANGO_WIN32 + + // Damn Pango fudges the size, so we need to unfudge. See source of pango_win32_font_map_init() + pango_font_description_set_size(descr, + (int) ((font_factory::Default())->fontSize*PANGO_SCALE*72 / GetDeviceCaps(pango_win32_get_dc(),LOGPIXELSY)) + ); + + // We unset stretch on Win32, because pango-win32 has no concept of it + // (Windows doesn't really provide any useful field it could use). + // If we did set stretch, then any text with a font-stretch attribute would + // end up falling back to a default. + pango_font_description_unset_fields(descr, PANGO_FONT_MASK_STRETCH); + +#else + + // mandatory huge size (hinting workaround) + pango_font_description_set_size(descr, (int) ((font_factory::Default())->fontSize*PANGO_SCALE)); + +#endif + + return descr; +} + +Layout::InputStreamTextSource::~InputStreamTextSource() +{ + sp_style_unref(style); +} + +}//namespace Text +}//namespace Inkscape |