From a9c3b5a389a249a9ddb62250cdcb8f8edb2f7280 Mon Sep 17 00:00:00 2001 From: Alexander Shalamov Date: Wed, 13 Nov 2019 10:47:41 +0200 Subject: [PATCH] [core] Add evaluated images to styled text sections --- src/mbgl/layout/symbol_layout.cpp | 31 ++++++++++++++---------- src/mbgl/text/tagged_string.cpp | 40 ++++++++++++++++++++++++++++--- src/mbgl/text/tagged_string.hpp | 23 +++++++++++++----- test/text/tagged_string.test.cpp | 6 ++--- 4 files changed, 76 insertions(+), 24 deletions(-) diff --git a/src/mbgl/layout/symbol_layout.cpp b/src/mbgl/layout/symbol_layout.cpp index af0b1bd21..54708d554 100644 --- a/src/mbgl/layout/symbol_layout.cpp +++ b/src/mbgl/layout/symbol_layout.cpp @@ -146,27 +146,34 @@ SymbolLayout::SymbolLayout(const BucketParameters& parameters, ft.formattedText = TaggedString(); for (const auto & section : formatted.sections) { - std::string u8string = section.text; - if (textTransform == TextTransformType::Uppercase) { - u8string = platform::uppercase(u8string); - } else if (textTransform == TextTransformType::Lowercase) { - u8string = platform::lowercase(u8string); + if (!section.image) { + std::string u8string = section.text; + if (textTransform == TextTransformType::Uppercase) { + u8string = platform::uppercase(u8string); + } else if (textTransform == TextTransformType::Lowercase) { + u8string = platform::lowercase(u8string); + } + + ft.formattedText->addTextSection(applyArabicShaping(util::convertUTF8ToUTF16(u8string)), + section.fontScale ? *section.fontScale : 1.0, + section.fontStack ? *section.fontStack : baseFontStack, + section.textColor); + } else { + layoutParameters.imageDependencies.emplace(section.image->id(), ImageType::Icon); + ft.formattedText->addImageSection(section.image->id()); } - - ft.formattedText->addSection(applyArabicShaping(util::convertUTF8ToUTF16(u8string)), - section.fontScale ? *section.fontScale : 1.0, - section.fontStack ? *section.fontStack : baseFontStack, - section.textColor); } - const bool canVerticalizeText = layout->get() == AlignmentType::Map && layout->get() != SymbolPlacementType::Point && ft.formattedText->allowsVerticalWritingMode(); // Loop through all characters of this text and collect unique codepoints. for (std::size_t j = 0; j < ft.formattedText->length(); j++) { - const auto& sectionFontStack = formatted.sections[ft.formattedText->getSectionIndex(j)].fontStack; + const auto& section = formatted.sections[ft.formattedText->getSectionIndex(j)]; + if (section.image) continue; + + const auto& sectionFontStack = section.fontStack; GlyphIDs& dependencies = layoutParameters.glyphDependencies[sectionFontStack ? *sectionFontStack : baseFontStack]; char16_t codePoint = ft.formattedText->getCharCodeAt(j); diff --git a/src/mbgl/text/tagged_string.cpp b/src/mbgl/text/tagged_string.cpp index e8a1c6f51..83ccd610c 100644 --- a/src/mbgl/text/tagged_string.cpp +++ b/src/mbgl/text/tagged_string.cpp @@ -1,16 +1,50 @@ -#include #include +#include #include +#include + +namespace { +char16_t PUAbegin = u'\uE000'; +char16_t PUAend = u'\uF8FF'; +} // namespace namespace mbgl { - -void TaggedString::addSection(const std::u16string& sectionText, double scale, FontStack fontStack, optional textColor) { + +void TaggedString::addTextSection(const std::u16string& sectionText, + double scale, + FontStack fontStack, + optional textColor) { styledText.first += sectionText; sections.emplace_back(scale, fontStack, std::move(textColor)); styledText.second.resize(styledText.first.size(), sections.size() - 1); supportsVerticalWritingMode = nullopt; } +void TaggedString::addImageSection(const std::string& imageID) { + const auto& nextImageSectionCharCode = getNextImageSectionCharCode(); + if (!nextImageSectionCharCode) { + Log::Warning(Event::Style, "Exceeded maximum number of images in a label."); + return; + } + + styledText.first += *nextImageSectionCharCode; + sections.emplace_back(imageID); + styledText.second.resize(styledText.first.size(), sections.size() - 1); +} + +optional TaggedString::getNextImageSectionCharCode() { + if (imageSectionID == 0u) { + imageSectionID = PUAbegin; + return imageSectionID; + } + + if (++imageSectionID > PUAend) { + return nullopt; + } + + return imageSectionID; +} + void TaggedString::trim() { std::size_t beginningWhitespace = styledText.first.find_first_not_of(u" \t\n\v\f\r"); if (beginningWhitespace == std::u16string::npos) { diff --git a/src/mbgl/text/tagged_string.hpp b/src/mbgl/text/tagged_string.hpp index 698e539a4..fba3bbf41 100644 --- a/src/mbgl/text/tagged_string.hpp +++ b/src/mbgl/text/tagged_string.hpp @@ -13,11 +13,14 @@ struct SectionOptions { fontStack(std::move(fontStack_)), textColor(std::move(textColor_)) {} - + + explicit SectionOptions(std::string imageID_) : scale(1.0), imageID(std::move(imageID_)) {} + double scale; FontStackHash fontStackHash; FontStack fontStack; optional textColor; + optional imageID; }; /** @@ -76,11 +79,13 @@ struct TaggedString { const StyledText& getStyledText() const { return styledText; } - - void addSection(const std::u16string& text, - double scale, - FontStack fontStack, - optional textColor_ = nullopt); + + void addTextSection(const std::u16string& text, + double scale, + FontStack fontStack, + optional textColor_ = nullopt); + + void addImageSection(const std::string& imageID); const SectionOptions& sectionAt(std::size_t index) const { return sections.at(index); @@ -100,10 +105,16 @@ struct TaggedString { void verticalizePunctuation(); bool allowsVerticalWritingMode(); +private: + optional getNextImageSectionCharCode(); + private: StyledText styledText; std::vector sections; optional supportsVerticalWritingMode; + // Max number of images within a text is 6400 U+E000–U+F8FF + // that covers Basic Multilingual Plane Unicode Private Use Area (PUA). + char16_t imageSectionID = 0u; }; } // namespace mbgl diff --git a/test/text/tagged_string.test.cpp b/test/text/tagged_string.test.cpp index da1141f00..ebf10c47f 100644 --- a/test/text/tagged_string.test.cpp +++ b/test/text/tagged_string.test.cpp @@ -11,9 +11,9 @@ TEST(TaggedString, Trim) { EXPECT_EQ(basic.rawText(), u"trim that and not this"); TaggedString twoSections; - twoSections.addSection(u" \t\ntrim that", 1.5f, {}); - twoSections.addSection(u" and not this \n\t", 0.5f, {}); - + twoSections.addTextSection(u" \t\ntrim that", 1.5f, {}); + twoSections.addTextSection(u" and not this \n\t", 0.5f, {}); + twoSections.trim(); EXPECT_EQ(twoSections.rawText(), u"trim that and not this");