diff --git a/CMakeLists.txt b/CMakeLists.txt index 064710780ff..6358976e6aa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -52,6 +52,7 @@ mason_use(earcut VERSION 0.12.1 HEADER_ONLY) mason_use(protozero VERSION 1.4.2 HEADER_ONLY) mason_use(pixelmatch VERSION 0.10.0 HEADER_ONLY) mason_use(geojson VERSION 0.3.2 HEADER_ONLY) +mason_use(icu VERSION 58.1) if(WITH_COVERAGE) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --coverage") diff --git a/cmake/core-files.cmake b/cmake/core-files.cmake index 0bde8505e86..bbfec6a4c20 100644 --- a/cmake/core-files.cmake +++ b/cmake/core-files.cmake @@ -360,6 +360,8 @@ set(MBGL_CORE_FILES src/mbgl/text/quads.hpp src/mbgl/text/shaping.cpp src/mbgl/text/shaping.hpp + src/mbgl/text/bidi.cpp + src/mbgl/text/bidi.hpp # tile src/mbgl/tile/geojson_tile.cpp diff --git a/cmake/core.cmake b/cmake/core.cmake index bc5e7eb7186..9c1bf4a6f20 100644 --- a/cmake/core.cmake +++ b/cmake/core.cmake @@ -45,6 +45,7 @@ target_add_mason_package(mbgl-core PRIVATE supercluster) target_add_mason_package(mbgl-core PRIVATE kdbush) target_add_mason_package(mbgl-core PRIVATE earcut) target_add_mason_package(mbgl-core PRIVATE protozero) +target_add_mason_package(mbgl-core PRIVATE icu) mbgl_platform_core() diff --git a/package.json b/package.json index 598e1fef44a..8b8e57460b1 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ "lodash": "^4.16.4", "mapbox-gl-shaders": "mapbox/mapbox-gl-shaders#597115a1e1bd982944b068f8accde34eada74fc2", "mapbox-gl-style-spec": "mapbox/mapbox-gl-style-spec#7f62a4fc9f21e619824d68abbc4b03cbc1685572", - "mapbox-gl-test-suite": "mapbox/mapbox-gl-test-suite#87192085b3c1ebe668524511bfba28381e5eb627", + "mapbox-gl-test-suite": "mapbox/mapbox-gl-test-suite#c32d0c5ac80e3b7393bc17b8944e64fa5cffd90a", "mkdirp": "^0.5.1", "node-cmake": "^1.2.1", "request": "^2.72.0", diff --git a/platform/default/mbgl/storage/offline_download.cpp b/platform/default/mbgl/storage/offline_download.cpp index 9e2e11c86f7..3edc75845c7 100644 --- a/platform/default/mbgl/storage/offline_download.cpp +++ b/platform/default/mbgl/storage/offline_download.cpp @@ -184,7 +184,7 @@ void OfflineDownload::activateDownload() { if (!parser.glyphURL.empty()) { for (const auto& fontStack : parser.fontStacks()) { - for (uint32_t i = 0; i < GLYPH_RANGES_PER_FONT_STACK; i++) { + for (char16_t i = 0; i < GLYPH_RANGES_PER_FONT_STACK; i++) { queueResource(Resource::glyphs(parser.glyphURL, fontStack, getGlyphRange(i * GLYPHS_PER_GLYPH_RANGE))); } } diff --git a/platform/default/string_stdlib.cpp b/platform/default/string_stdlib.cpp index 90a75c17389..0e97fc54d55 100644 --- a/platform/default/string_stdlib.cpp +++ b/platform/default/string_stdlib.cpp @@ -1,10 +1,10 @@ #include -#include #define NU_WITH_TOUPPER #define NU_WITH_TOLOWER #define NU_WITH_UTF8_WRITER #include #include +#include namespace mbgl { namespace platform { diff --git a/src/mbgl/layout/merge_lines.cpp b/src/mbgl/layout/merge_lines.cpp index f4fdb826179..676cbc092df 100644 --- a/src/mbgl/layout/merge_lines.cpp +++ b/src/mbgl/layout/merge_lines.cpp @@ -47,10 +47,10 @@ enum class Side { }; size_t -getKey(const std::u32string& text, const GeometryCollection& geom, Side side) { +getKey(const std::u16string& text, const GeometryCollection& geom, Side side) { const GeometryCoordinate& coord = side == Side::Right ? geom[0].back() : geom[0].front(); - auto hash = std::hash()(text); + auto hash = std::hash()(text); boost::hash_combine(hash, coord.x); boost::hash_combine(hash, coord.y); return hash; diff --git a/src/mbgl/layout/symbol_feature.hpp b/src/mbgl/layout/symbol_feature.hpp index 99db4f9ac56..b1ac3ffe78a 100644 --- a/src/mbgl/layout/symbol_feature.hpp +++ b/src/mbgl/layout/symbol_feature.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include @@ -10,7 +11,8 @@ namespace mbgl { class SymbolFeature { public: GeometryCollection geometry; - optional text; + optional text; + optional writingDirection; optional icon; std::size_t index; }; diff --git a/src/mbgl/layout/symbol_layout.cpp b/src/mbgl/layout/symbol_layout.cpp index d974e6a3570..6556d65d3d0 100644 --- a/src/mbgl/layout/symbol_layout.cpp +++ b/src/mbgl/layout/symbol_layout.cpp @@ -20,6 +20,8 @@ #include #include +#include + namespace mbgl { using namespace style; @@ -90,10 +92,12 @@ SymbolLayout::SymbolLayout(std::string bucketName_, u8string = platform::lowercase(u8string); } - ft.text = util::utf8_to_utf32::convert(u8string); + std::u16string u16string = util::utf8_to_utf16::convert(u8string); + ft.text = bidi.bidiTransform(u16string); + ft.writingDirection = bidi.baseWritingDirection(u16string); // Loop through all characters of this text and collect unique codepoints. - for (char32_t chr : *ft.text) { + for (char16_t chr : *ft.text) { ranges.insert(getGlyphRange(chr)); } } @@ -194,6 +198,7 @@ void SymbolLayout::prepare(uintptr_t tileUID, if (feature.text) { shapedText = glyphSet->getShaping( /* string */ *feature.text, + /* base direction of text */ *feature.writingDirection, /* maxWidth: ems */ layout.symbolPlacement != SymbolPlacementType::Line ? layout.textMaxWidth * 24 : 0, /* lineHeight: ems */ layout.textLineHeight * 24, @@ -309,7 +314,7 @@ void SymbolLayout::addFeature(const GeometryCollection &lines, } } -bool SymbolLayout::anchorIsTooClose(const std::u32string &text, const float repeatDistance, Anchor &anchor) { +bool SymbolLayout::anchorIsTooClose(const std::u16string &text, const float repeatDistance, Anchor &anchor) { if (compareText.find(text) == compareText.end()) { compareText.emplace(text, Anchors()); } else { diff --git a/src/mbgl/layout/symbol_layout.hpp b/src/mbgl/layout/symbol_layout.hpp index 54acf84aaf5..c21398fabf7 100644 --- a/src/mbgl/layout/symbol_layout.hpp +++ b/src/mbgl/layout/symbol_layout.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -64,8 +65,8 @@ class SymbolLayout { const GlyphPositions& face, const size_t index); - bool anchorIsTooClose(const std::u32string& text, const float repeatDistance, Anchor&); - std::map> compareText; + bool anchorIsTooClose(const std::u16string& text, const float repeatDistance, Anchor&); + std::map> compareText; void addToDebugBuffers(CollisionTile&, SymbolBucket&); @@ -91,6 +92,8 @@ class SymbolLayout { GlyphRangeSet ranges; std::vector symbolInstances; std::vector features; + + BiDi bidi; // Consider moving this up to geometry tile worker to reduce reinstantiation costs; use of BiDi/ubiditransform object must be constrained to one thread }; } // namespace mbgl diff --git a/src/mbgl/text/bidi.cpp b/src/mbgl/text/bidi.cpp new file mode 100644 index 00000000000..4c127e9cabc --- /dev/null +++ b/src/mbgl/text/bidi.cpp @@ -0,0 +1,56 @@ +#include + +#include +#include +#include +#include + +namespace mbgl { + +BiDi::BiDi() { + UErrorCode errorCode = U_ZERO_ERROR; + transform = ubiditransform_open(&errorCode); // Only error is failure to allocate memory, in + // that case ubidi_transform would fall back to + // creating transform object on the fly +} + +BiDi::~BiDi() { + if (transform) + ubiditransform_close(transform); +} + +std::u16string BiDi::bidiTransform(const std::u16string& input) { + UErrorCode errorCode = U_ZERO_ERROR; + + std::unique_ptr outputText = + std::make_unique(input.size() * 2); // Maximum output of ubidi_transform is twice + // the size of input according to + // ubidi_transform.h + uint32_t outputLength = ubiditransform_transform( + transform, input.c_str(), static_cast(input.size()), outputText.get(), + static_cast(input.size()) * 2, + UBIDI_DEFAULT_LTR, // Assume input is LTR unless strong RTL characters are found + UBIDI_LOGICAL, // Input is in logical order + UBIDI_LTR, // Output is in "visual LTR" order + UBIDI_VISUAL, // '' + UBIDI_MIRRORING_ON, // Use mirroring lookups for things like parentheses that need mirroring + // in RTL text + U_SHAPE_LETTERS_SHAPE, // Add options here for handling numbers in bidirectional text + &errorCode); + + // If the algorithm fails for any reason, fall back to non-transformed text + if (U_FAILURE(errorCode)) + return input; + + return std::u16string(outputText.get(), outputLength); +} + +WritingDirection BiDi::baseWritingDirection(const std::u16string& input) { + // This just looks for the first character with a strong direction property, it does not perform + // the BiDi algorithm + return ubidi_getBaseDirection(input.c_str(), static_cast(input.size())) == UBIDI_RTL + ? WritingDirection::RightToLeft + : WritingDirection::LeftToRight; +} + +} // end namespace mbgl diff --git a/src/mbgl/text/bidi.hpp b/src/mbgl/text/bidi.hpp new file mode 100644 index 00000000000..e29bf041e2a --- /dev/null +++ b/src/mbgl/text/bidi.hpp @@ -0,0 +1,25 @@ +#pragma once + +#include + +#include + +struct UBiDiTransform; + +namespace mbgl { + +enum class WritingDirection : bool { LeftToRight, RightToLeft }; + +class BiDi : private util::noncopyable { +public: + BiDi(); + ~BiDi(); + + std::u16string bidiTransform(const std::u16string&); + WritingDirection baseWritingDirection(const std::u16string&); + +private: + UBiDiTransform* transform; +}; + +} // end namespace mbgl diff --git a/src/mbgl/text/glyph.cpp b/src/mbgl/text/glyph.cpp index a877d7a7993..29929b73e6e 100644 --- a/src/mbgl/text/glyph.cpp +++ b/src/mbgl/text/glyph.cpp @@ -3,7 +3,7 @@ namespace mbgl { // Note: this only works for the BMP -GlyphRange getGlyphRange(char32_t glyph) { +GlyphRange getGlyphRange(char16_t glyph) { unsigned start = (glyph/256) * 256; unsigned end = (start + 255); if (start > 65280) start = 65280; diff --git a/src/mbgl/text/glyph.hpp b/src/mbgl/text/glyph.hpp index a333f68ff4c..d07fbdff219 100644 --- a/src/mbgl/text/glyph.hpp +++ b/src/mbgl/text/glyph.hpp @@ -11,7 +11,7 @@ namespace mbgl { // Note: this only works for the BMP -GlyphRange getGlyphRange(char32_t glyph); +GlyphRange getGlyphRange(char16_t glyph); struct GlyphMetrics { explicit operator bool() const { @@ -63,10 +63,10 @@ class PositionedGlyph { class Shaping { public: explicit Shaping() : top(0), bottom(0), left(0), right(0) {} - explicit Shaping(float x, float y, std::u32string text_) + explicit Shaping(float x, float y, std::u16string text_) : text(std::move(text_)), top(y), bottom(y), left(x), right(x) {} std::vector positionedGlyphs; - std::u32string text; + std::u16string text; int32_t top; int32_t bottom; int32_t left; diff --git a/src/mbgl/text/glyph_atlas.cpp b/src/mbgl/text/glyph_atlas.cpp index 031e89d13ab..57b8b140175 100644 --- a/src/mbgl/text/glyph_atlas.cpp +++ b/src/mbgl/text/glyph_atlas.cpp @@ -81,7 +81,7 @@ void GlyphAtlas::setObserver(GlyphAtlasObserver* observer_) { } void GlyphAtlas::addGlyphs(uintptr_t tileUID, - const std::u32string& text, + const std::u16string& text, const FontStack& fontStack, const GlyphSet& glyphSet, GlyphPositions& face) @@ -90,7 +90,7 @@ void GlyphAtlas::addGlyphs(uintptr_t tileUID, const std::map& sdfs = glyphSet.getSDFs(); - for (uint32_t chr : text) + for (char16_t chr : text) { auto sdf_it = sdfs.find(chr); if (sdf_it == sdfs.end()) { diff --git a/src/mbgl/text/glyph_atlas.hpp b/src/mbgl/text/glyph_atlas.hpp index 550ca4cc172..af14aace5b7 100644 --- a/src/mbgl/text/glyph_atlas.hpp +++ b/src/mbgl/text/glyph_atlas.hpp @@ -55,7 +55,7 @@ class GlyphAtlas : public util::noncopyable { void setObserver(GlyphAtlasObserver* observer); void addGlyphs(uintptr_t tileUID, - const std::u32string& text, + const std::u16string& text, const FontStack&, const GlyphSet&, GlyphPositions&); diff --git a/src/mbgl/text/glyph_set.cpp b/src/mbgl/text/glyph_set.cpp index c778de207b5..67c2ab93e44 100644 --- a/src/mbgl/text/glyph_set.cpp +++ b/src/mbgl/text/glyph_set.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include @@ -31,7 +32,7 @@ const std::map &GlyphSet::getSDFs() const { return sdfs; } -const Shaping GlyphSet::getShaping(const std::u32string &string, const float maxWidth, +const Shaping GlyphSet::getShaping(const std::u16string &string, const WritingDirection writingDirection, const float maxWidth, const float lineHeight, const float horizontalAlign, const float verticalAlign, const float justify, const float spacing, const Point &translate) const { @@ -44,7 +45,7 @@ const Shaping GlyphSet::getShaping(const std::u32string &string, const float max const float y = yOffset; // Loop through all characters of this label and shape. - for (uint32_t chr : string) { + for (char16_t chr : string) { auto it = sdfs.find(chr); if (it != sdfs.end()) { shaping.positionedGlyphs.emplace_back(chr, x, y); @@ -56,7 +57,7 @@ const Shaping GlyphSet::getShaping(const std::u32string &string, const float max return shaping; lineWrap(shaping, lineHeight, maxWidth, horizontalAlign, verticalAlign, justify, translate, - util::i18n::allowsIdeographicBreaking(string)); + util::i18n::allowsIdeographicBreaking(string), writingDirection); return shaping; } @@ -90,7 +91,9 @@ void justifyLine(std::vector &positionedGlyphs, const std::map< void GlyphSet::lineWrap(Shaping &shaping, const float lineHeight, float maxWidth, const float horizontalAlign, const float verticalAlign, const float justify, const Point &translate, - bool useBalancedIdeographicBreaking) const { + bool useBalancedIdeographicBreaking, const WritingDirection writingDirection) const { + float lineFeedOffset = writingDirection == WritingDirection::RightToLeft ? -lineHeight : lineHeight; + uint32_t lastSafeBreak = 0; uint32_t lengthBeforeCurrentLine = 0; @@ -112,7 +115,7 @@ void GlyphSet::lineWrap(Shaping &shaping, const float lineHeight, float maxWidth PositionedGlyph &shape = positionedGlyphs[i]; shape.x -= lengthBeforeCurrentLine; - shape.y += lineHeight * line; + shape.y += lineFeedOffset * line; if (shape.x > maxWidth && lastSafeBreak > 0) { @@ -120,7 +123,7 @@ void GlyphSet::lineWrap(Shaping &shaping, const float lineHeight, float maxWidth maxLineLength = util::max(lineLength, maxLineLength); for (uint32_t k = lastSafeBreak + 1; k <= i; k++) { - positionedGlyphs[k].y += lineHeight; + positionedGlyphs[k].y += lineFeedOffset; positionedGlyphs[k].x -= lineLength; } diff --git a/src/mbgl/text/glyph_set.hpp b/src/mbgl/text/glyph_set.hpp index fed7960a5f7..b4fcf4c3a4d 100644 --- a/src/mbgl/text/glyph_set.hpp +++ b/src/mbgl/text/glyph_set.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include @@ -9,12 +10,12 @@ class GlyphSet { public: void insert(uint32_t id, SDFGlyph&&); const std::map &getSDFs() const; - const Shaping getShaping(const std::u32string &string, float maxWidth, float lineHeight, + const Shaping getShaping(const std::u16string &string, const WritingDirection writingDirection, float maxWidth, float lineHeight, float horizontalAlign, float verticalAlign, float justify, float spacing, const Point &translate) const; void lineWrap(Shaping &shaping, float lineHeight, float maxWidth, float horizontalAlign, float verticalAlign, float justify, const Point &translate, - bool useBalancedIdeographicBreaking) const; + bool useBalancedIdeographicBreaking, const WritingDirection writingDirection) const; private: std::map sdfs; diff --git a/src/mbgl/util/i18n.cpp b/src/mbgl/util/i18n.cpp index dbfa24c5cf4..97dda763206 100644 --- a/src/mbgl/util/i18n.cpp +++ b/src/mbgl/util/i18n.cpp @@ -8,7 +8,7 @@ namespace { @param last The last codepoint in the block, inclusive. */ #define DEFINE_IS_IN_UNICODE_BLOCK(name, first, last) \ - inline bool isIn##name(uint32_t codepoint) { \ + inline bool isIn##name(uint16_t codepoint) { \ return codepoint >= first && codepoint <= last; \ } @@ -294,13 +294,13 @@ namespace mbgl { namespace util { namespace i18n { -bool isVisible(uint32_t chr) { +bool isVisible(uint16_t chr) { return (chr == 0x0a /* newline */ || chr == 0x20 /* space */ || chr == 0x200b /* zero-width space */); } -bool allowsWordBreaking(uint32_t chr) { +bool allowsWordBreaking(uint16_t chr) { return (chr == 0x0a /* newline */ || chr == 0x20 /* space */ || chr == 0x26 /* ampersand */ @@ -314,8 +314,8 @@ bool allowsWordBreaking(uint32_t chr) { || chr == 0x2013 /* en dash */); } -bool allowsIdeographicBreaking(const std::u32string& string) { - for (uint32_t chr : string) { +bool allowsIdeographicBreaking(const std::u16string& string) { + for (uint16_t chr : string) { if (!allowsIdeographicBreaking(chr)) { return false; } @@ -323,7 +323,7 @@ bool allowsIdeographicBreaking(const std::u32string& string) { return true; } -bool allowsIdeographicBreaking(uint32_t chr) { +bool allowsIdeographicBreaking(uint16_t chr) { // Return early for characters outside all ideographic ranges. if (chr < 0x2E80) return false; diff --git a/src/mbgl/util/i18n.hpp b/src/mbgl/util/i18n.hpp index fe324f53620..c07dc91ed65 100644 --- a/src/mbgl/util/i18n.hpp +++ b/src/mbgl/util/i18n.hpp @@ -7,20 +7,20 @@ namespace util { namespace i18n { /** Returns whether a character is a visible character. */ -bool isVisible(uint32_t chr); +bool isVisible(uint16_t chr); /** Returns whether a line break can be inserted after the character indicated by the given Unicode codepoint due to word breaking. */ -bool allowsWordBreaking(uint32_t chr); +bool allowsWordBreaking(uint16_t chr); /** Returns whether a line break can be inserted after any character in the given string. If false, line breaking should occur on word boundaries instead. */ -bool allowsIdeographicBreaking(const std::u32string& string); +bool allowsIdeographicBreaking(const std::u16string& string); /** Returns whether a line break can be inserted after the character indicated by the given Unicode codepoint due to ideographic breaking. */ -bool allowsIdeographicBreaking(uint32_t chr); +bool allowsIdeographicBreaking(uint16_t chr); } // namespace i18n } // namespace util diff --git a/src/mbgl/util/utf.hpp b/src/mbgl/util/utf.hpp index 560ca3ba7fb..81330cfc83f 100644 --- a/src/mbgl/util/utf.hpp +++ b/src/mbgl/util/utf.hpp @@ -2,18 +2,17 @@ #include -#include +#include +#include namespace mbgl { namespace util { -class utf8_to_utf32 { - public: - static std::u32string convert(std::string const& utf8) - { - boost::u8_to_u32_iterator begin(utf8.begin()); - boost::u8_to_u32_iterator end(utf8.end()); - return std::u32string(begin,end); +class utf8_to_utf16 { +public: + static std::u16string convert(std::string const& utf8) { + std::wstring_convert, char16_t> converter; + return converter.from_bytes(utf8); } }; diff --git a/test/util/merge_lines.test.cpp b/test/util/merge_lines.test.cpp index db81d8b2094..8383183e0aa 100644 --- a/test/util/merge_lines.test.cpp +++ b/test/util/merge_lines.test.cpp @@ -3,27 +3,27 @@ #include #include -const std::u32string aaa = U"a"; -const std::u32string bbb = U"b"; +const std::u16string aaa = u"a"; +const std::u16string bbb = u"b"; TEST(MergeLines, SameText) { // merges lines with the same text std::vector input1 = { - { {{{0, 0}, {1, 0}, {2, 0}}}, aaa, {}, 0 }, - { {{{4, 0}, {5, 0}, {6, 0}}}, bbb, {}, 0 }, - { {{{8, 0}, {9, 0}}}, aaa, {}, 0 }, - { {{{2, 0}, {3, 0}, {4, 0}}}, aaa, {}, 0 }, - { {{{6, 0}, {7, 0}, {8, 0}}}, aaa, {}, 0 }, - { {{{5, 0}, {6, 0}}}, aaa, {}, 0 } + { {{{0, 0}, {1, 0}, {2, 0}}}, aaa, mbgl::WritingDirection::LeftToRight, {}, 0 }, + { {{{4, 0}, {5, 0}, {6, 0}}}, bbb, mbgl::WritingDirection::LeftToRight, {}, 0 }, + { {{{8, 0}, {9, 0}}}, aaa, mbgl::WritingDirection::LeftToRight, {}, 0 }, + { {{{2, 0}, {3, 0}, {4, 0}}}, aaa, mbgl::WritingDirection::LeftToRight, {}, 0 }, + { {{{6, 0}, {7, 0}, {8, 0}}}, aaa, mbgl::WritingDirection::LeftToRight, {}, 0 }, + { {{{5, 0}, {6, 0}}}, aaa, mbgl::WritingDirection::LeftToRight, {}, 0 } }; const std::vector expected1 = { - { {{{0, 0}, {1, 0}, {2, 0}, {3, 0}, {4, 0}}}, aaa, {}, 0 }, - { {{{4, 0}, {5, 0}, {6, 0}}}, bbb, {}, 0 }, - { {{{5, 0}, {6, 0}, {7, 0}, {8, 0}, {9, 0}}}, aaa, {}, 0 }, - { {{}}, aaa, {}, 0 }, - { {{}}, aaa, {}, 0 }, - { {{}}, aaa, {}, 0 } + { {{{0, 0}, {1, 0}, {2, 0}, {3, 0}, {4, 0}}}, aaa, mbgl::WritingDirection::LeftToRight, {}, 0 }, + { {{{4, 0}, {5, 0}, {6, 0}}}, bbb, mbgl::WritingDirection::LeftToRight, {}, 0 }, + { {{{5, 0}, {6, 0}, {7, 0}, {8, 0}, {9, 0}}}, aaa, mbgl::WritingDirection::LeftToRight, {}, 0 }, + { {{}}, aaa, mbgl::WritingDirection::LeftToRight, {}, 0 }, + { {{}}, aaa, mbgl::WritingDirection::LeftToRight, {}, 0 }, + { {{}}, aaa, mbgl::WritingDirection::LeftToRight, {}, 0 } }; mbgl::util::mergeLines(input1); @@ -36,15 +36,15 @@ TEST(MergeLines, SameText) { TEST(MergeLines, BothEnds) { // mergeLines handles merge from both ends std::vector input2 = { - { {{{0, 0}, {1, 0}, {2, 0}}}, aaa, {}, 0 }, - { {{{4, 0}, {5, 0}, {6, 0}}}, aaa, {}, 0 }, - { {{{2, 0}, {3, 0}, {4, 0}}}, aaa, {}, 0 } + { {{{0, 0}, {1, 0}, {2, 0}}}, aaa, mbgl::WritingDirection::LeftToRight, {}, 0 }, + { {{{4, 0}, {5, 0}, {6, 0}}}, aaa, mbgl::WritingDirection::LeftToRight, {}, 0 }, + { {{{2, 0}, {3, 0}, {4, 0}}}, aaa, mbgl::WritingDirection::LeftToRight, {}, 0 } }; const std::vector expected2 = { - { {{{0, 0}, {1, 0}, {2, 0}, {3, 0}, {4, 0}, {5, 0}, {6, 0}}}, aaa, {}, 0 }, - { {{}}, aaa, {}, 0 }, - { {{}}, aaa, {}, 0 } + { {{{0, 0}, {1, 0}, {2, 0}, {3, 0}, {4, 0}, {5, 0}, {6, 0}}}, aaa, mbgl::WritingDirection::LeftToRight, {}, 0 }, + { {{}}, aaa, mbgl::WritingDirection::LeftToRight, {}, 0 }, + { {{}}, aaa, mbgl::WritingDirection::LeftToRight, {}, 0 } }; mbgl::util::mergeLines(input2); @@ -57,15 +57,15 @@ TEST(MergeLines, BothEnds) { TEST(MergeLines, CircularLines) { // mergeLines handles circular lines std::vector input3 = { - { {{{0, 0}, {1, 0}, {2, 0}}}, aaa, {}, 0 }, - { {{{2, 0}, {3, 0}, {4, 0}}}, aaa, {}, 0 }, - { {{{4, 0}, {0, 0}}}, aaa, {}, 0 } + { {{{0, 0}, {1, 0}, {2, 0}}}, aaa, mbgl::WritingDirection::LeftToRight, {}, 0 }, + { {{{2, 0}, {3, 0}, {4, 0}}}, aaa, mbgl::WritingDirection::LeftToRight, {}, 0 }, + { {{{4, 0}, {0, 0}}}, aaa, mbgl::WritingDirection::LeftToRight, {}, 0 } }; const std::vector expected3 = { - { {{{0, 0}, {1, 0}, {2, 0}, {3, 0}, {4, 0}, {0, 0}}}, aaa, {}, 0 }, - { {{}}, aaa, {}, 0 }, - { {{}}, aaa, {}, 0 } + { {{{0, 0}, {1, 0}, {2, 0}, {3, 0}, {4, 0}, {0, 0}}}, aaa, mbgl::WritingDirection::LeftToRight, {}, 0 }, + { {{}}, aaa, mbgl::WritingDirection::LeftToRight, {}, 0 }, + { {{}}, aaa, mbgl::WritingDirection::LeftToRight, {}, 0 } }; mbgl::util::mergeLines(input3);