From 1b9d4d792cbd877f627987cbd0d5ed41709375c8 Mon Sep 17 00:00:00 2001 From: Alexander Shalamov Date: Sun, 4 Aug 2019 14:44:22 +0300 Subject: [core] Render half-width glyphs in upright orientation This change forces glyphs whose natural orientation in vertical writing mode is 'sideways' to be rendered in upright orientation (only for non complex text layouts). This is different compared to W3C / browser behavior that is by default, renders glyphs in their respective natural orientation. In the future, there might need to add a new layout property that would control glyph orientation separately (e.g., text-glyph-orientation: natural | upright). --- src/mbgl/layout/symbol_layout.cpp | 3 ++- src/mbgl/text/quads.cpp | 6 +++++- src/mbgl/text/shaping.cpp | 17 ++++++++++++----- src/mbgl/text/shaping.hpp | 3 ++- src/mbgl/util/i18n.cpp | 8 ++++++++ src/mbgl/util/i18n.hpp | 2 ++ 6 files changed, 31 insertions(+), 8 deletions(-) diff --git a/src/mbgl/layout/symbol_layout.cpp b/src/mbgl/layout/symbol_layout.cpp index be6444bb16..dbf209b414 100644 --- a/src/mbgl/layout/symbol_layout.cpp +++ b/src/mbgl/layout/symbol_layout.cpp @@ -314,7 +314,8 @@ void SymbolLayout::prepareSymbols(const GlyphMap& glyphMap, const GlyphPositions /* translate */ textOffset, /* writingMode */ writingMode, /* bidirectional algorithm object */ bidi, - /* glyphs */ glyphMap); + /* glyphs */ glyphMap, + allowVerticalPlacement); return result; }; diff --git a/src/mbgl/text/quads.cpp b/src/mbgl/text/quads.cpp index 9ff26ddd8d..b08c2bc0ba 100644 --- a/src/mbgl/text/quads.cpp +++ b/src/mbgl/text/quads.cpp @@ -160,7 +160,11 @@ SymbolQuads getGlyphQuads(const Shaping& shapedText, const Point center{ -halfAdvance, halfAdvance - Shaping::yOffset }; const float verticalRotation = -M_PI_2; - const Point xOffsetCorrection{ 5.0f - Shaping::yOffset, 0.0f }; + + // xHalfWidhtOffsetcorrection is a difference between full-width and half-width + // advance, should be 0 for full-width glyphs and will pull up half-width glyphs. + const float xHalfWidhtOffsetcorrection = util::ONE_EM / 2 - halfAdvance; + const Point xOffsetCorrection{ 5.0f - Shaping::yOffset - xHalfWidhtOffsetcorrection, 0.0f }; tl = util::rotate(tl - center, verticalRotation) + center + xOffsetCorrection + verticalizedLabelOffset; tr = util::rotate(tr - center, verticalRotation) + center + xOffsetCorrection + verticalizedLabelOffset; diff --git a/src/mbgl/text/shaping.cpp b/src/mbgl/text/shaping.cpp index 3ed35fc725..7bf0e14f80 100644 --- a/src/mbgl/text/shaping.cpp +++ b/src/mbgl/text/shaping.cpp @@ -290,7 +290,8 @@ void shapeLines(Shaping& shaping, const style::SymbolAnchorType textAnchor, const style::TextJustifyType textJustify, const WritingModeType writingMode, - const GlyphMap& glyphMap) { + const GlyphMap& glyphMap, + bool allowVerticalPlacement) { float x = 0; float y = Shaping::yOffset; @@ -332,8 +333,13 @@ void shapeLines(Shaping& shaping, const double baselineOffset = (lineMaxScale - section.scale) * util::ONE_EM; const Glyph& glyph = **it->second; - - if (writingMode == WritingModeType::Horizontal || !util::i18n::hasUprightVerticalOrientation(codePoint)) { + + if (writingMode == WritingModeType::Horizontal || + // Don't verticalize glyphs that have no upright orientation if vertical placement is disabled. + (!allowVerticalPlacement && !util::i18n::hasUprightVerticalOrientation(codePoint)) || + // If vertical placement is ebabled, don't verticalize glyphs that + // are from complex text layout script, or whitespaces. + (allowVerticalPlacement && (util::i18n::isWhitespace(codePoint) || util::i18n::isCharInComplexShapingScript(codePoint)))) { shaping.positionedGlyphs.emplace_back(codePoint, x, y + baselineOffset, false, section.fontStackHash, section.scale, sectionIndex); x += glyph.metrics.advance * section.scale + spacing; } else { @@ -377,7 +383,8 @@ const Shaping getShaping(const TaggedString& formattedString, const Point& translate, const WritingModeType writingMode, BiDi& bidi, - const GlyphMap& glyphs) { + const GlyphMap& glyphs, + bool allowVerticalPlacement) { std::vector reorderedLines; if (formattedString.sectionCount() == 1) { auto untaggedLines = bidi.processText(formattedString.rawText(), @@ -394,7 +401,7 @@ const Shaping getShaping(const TaggedString& formattedString, } Shaping shaping(translate.x, translate.y, writingMode, reorderedLines.size()); shapeLines(shaping, reorderedLines, spacing, lineHeight, textAnchor, - textJustify, writingMode, glyphs); + textJustify, writingMode, glyphs, allowVerticalPlacement); return shaping; } diff --git a/src/mbgl/text/shaping.hpp b/src/mbgl/text/shaping.hpp index 766b1ce233..f3a01e3caf 100644 --- a/src/mbgl/text/shaping.hpp +++ b/src/mbgl/text/shaping.hpp @@ -69,6 +69,7 @@ const Shaping getShaping(const TaggedString& string, const Point& translate, const WritingModeType, BiDi& bidi, - const GlyphMap& glyphs); + const GlyphMap& glyphs, + bool allowVerticalPlacement); } // namespace mbgl diff --git a/src/mbgl/util/i18n.cpp b/src/mbgl/util/i18n.cpp index 716481734e..885c8ec3d1 100644 --- a/src/mbgl/util/i18n.cpp +++ b/src/mbgl/util/i18n.cpp @@ -643,6 +643,14 @@ bool isStringInSupportedScript(const std::string& input) { return true; } +bool isCharInComplexShapingScript(char16_t chr) { + return isInArabic(chr) || + isInArabicSupplement(chr) || + isInArabicExtendedA(chr) || + isInArabicPresentationFormsA(chr) || + isInArabicPresentationFormsB(chr); +} + bool isWhitespace(char16_t chr) { return chr == u' ' || chr == u'\t' || chr == u'\n' || chr == u'\v' || chr == u'\f' || chr == u'\r'; } diff --git a/src/mbgl/util/i18n.hpp b/src/mbgl/util/i18n.hpp index c7544f443b..7e75aa06f7 100644 --- a/src/mbgl/util/i18n.hpp +++ b/src/mbgl/util/i18n.hpp @@ -75,6 +75,8 @@ char16_t verticalizePunctuation(char16_t chr); bool isStringInSupportedScript(const std::string& input); +bool isCharInComplexShapingScript(char16_t chr); + bool isWhitespace(char16_t chr); } // namespace i18n -- cgit v1.2.1