summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Loer <chris.loer@gmail.com>2016-11-16 12:50:57 -0800
committerJohn Firebaugh <john.firebaugh@gmail.com>2016-11-17 14:33:03 -0800
commitd4fc66af3924805d40576989c1e139ddafcc4670 (patch)
tree87e8dac7bc21051086f2765b4d04e884aad4cec7
parentbceeba29a3fa85105c21718ed0be8704508ab585 (diff)
downloadqtlocation-mapboxgl-d4fc66af3924805d40576989c1e139ddafcc4670.tar.gz
[core] Add minimal line breaking support for RTL text.
-rw-r--r--src/mbgl/layout/symbol_feature.hpp2
-rw-r--r--src/mbgl/layout/symbol_layout.cpp5
-rw-r--r--src/mbgl/text/bidi.cpp7
-rw-r--r--src/mbgl/text/bidi.hpp9
-rw-r--r--src/mbgl/text/glyph_set.cpp13
-rw-r--r--src/mbgl/text/glyph_set.hpp5
-rw-r--r--test/util/merge_lines.test.cpp48
7 files changed, 52 insertions, 37 deletions
diff --git a/src/mbgl/layout/symbol_feature.hpp b/src/mbgl/layout/symbol_feature.hpp
index 9e0eacaac5..b1ac3ffe78 100644
--- a/src/mbgl/layout/symbol_feature.hpp
+++ b/src/mbgl/layout/symbol_feature.hpp
@@ -1,5 +1,6 @@
#pragma once
+#include <mbgl/text/bidi.hpp>
#include <mbgl/tile/geometry_tile_data.hpp>
#include <mbgl/util/optional.hpp>
@@ -11,6 +12,7 @@ class SymbolFeature {
public:
GeometryCollection geometry;
optional<std::u16string> text;
+ optional<WritingDirection> writingDirection;
optional<std::string> icon;
std::size_t index;
};
diff --git a/src/mbgl/layout/symbol_layout.cpp b/src/mbgl/layout/symbol_layout.cpp
index 00395fafc2..6556d65d3d 100644
--- a/src/mbgl/layout/symbol_layout.cpp
+++ b/src/mbgl/layout/symbol_layout.cpp
@@ -92,7 +92,9 @@ SymbolLayout::SymbolLayout(std::string bucketName_,
u8string = platform::lowercase(u8string);
}
- ft.text = bidi.bidiTransform(util::utf8_to_utf16::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 (char16_t chr : *ft.text) {
@@ -196,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,
diff --git a/src/mbgl/text/bidi.cpp b/src/mbgl/text/bidi.cpp
index 2b6967110c..4c127e9cab 100644
--- a/src/mbgl/text/bidi.cpp
+++ b/src/mbgl/text/bidi.cpp
@@ -2,6 +2,7 @@
#include <mbgl/text/bidi.hpp>
#include <unicode/ubidi.h>
+#include <unicode/ubiditransform.h>
#include <unicode/ushape.h>
namespace mbgl {
@@ -44,10 +45,12 @@ std::u16string BiDi::bidiTransform(const std::u16string& input) {
return std::u16string(outputText.get(), outputLength);
}
-bool BiDi::baseDirectionRightToLeft(const std::u16string& input) {
+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<int32_t>(input.size())) == UBIDI_RTL;
+ return ubidi_getBaseDirection(input.c_str(), static_cast<int32_t>(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
index 030ac88ce2..e29bf041e2 100644
--- a/src/mbgl/text/bidi.hpp
+++ b/src/mbgl/text/bidi.hpp
@@ -3,17 +3,20 @@
#include <string>
#include <mbgl/util/noncopyable.hpp>
-#include <unicode/ubiditransform.h>
-namespace mbgl {
+struct UBiDiTransform;
+namespace mbgl {
+
+enum class WritingDirection : bool { LeftToRight, RightToLeft };
+
class BiDi : private util::noncopyable {
public:
BiDi();
~BiDi();
std::u16string bidiTransform(const std::u16string&);
- bool baseDirectionRightToLeft(const std::u16string&);
+ WritingDirection baseWritingDirection(const std::u16string&);
private:
UBiDiTransform* transform;
diff --git a/src/mbgl/text/glyph_set.cpp b/src/mbgl/text/glyph_set.cpp
index f0e3991540..67c2ab93e4 100644
--- a/src/mbgl/text/glyph_set.cpp
+++ b/src/mbgl/text/glyph_set.cpp
@@ -2,6 +2,7 @@
#include <mbgl/platform/log.hpp>
#include <mbgl/math/minmax.hpp>
#include <mbgl/util/i18n.hpp>
+#include <mbgl/text/bidi.hpp>
#include <cassert>
@@ -31,7 +32,7 @@ const std::map<uint32_t, SDFGlyph> &GlyphSet::getSDFs() const {
return sdfs;
}
-const Shaping GlyphSet::getShaping(const std::u16string &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<float> &translate) const {
@@ -56,7 +57,7 @@ const Shaping GlyphSet::getShaping(const std::u16string &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<PositionedGlyph> &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<float> &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 004cae343d..b4fcf4c3a4 100644
--- a/src/mbgl/text/glyph_set.hpp
+++ b/src/mbgl/text/glyph_set.hpp
@@ -1,5 +1,6 @@
#pragma once
+#include <mbgl/text/bidi.hpp>
#include <mbgl/text/glyph.hpp>
#include <mbgl/util/geometry.hpp>
@@ -9,12 +10,12 @@ class GlyphSet {
public:
void insert(uint32_t id, SDFGlyph&&);
const std::map<uint32_t, SDFGlyph> &getSDFs() const;
- const Shaping getShaping(const std::u16string &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<float> &translate) const;
void lineWrap(Shaping &shaping, float lineHeight, float maxWidth, float horizontalAlign,
float verticalAlign, float justify, const Point<float> &translate,
- bool useBalancedIdeographicBreaking) const;
+ bool useBalancedIdeographicBreaking, const WritingDirection writingDirection) const;
private:
std::map<uint32_t, SDFGlyph> sdfs;
diff --git a/test/util/merge_lines.test.cpp b/test/util/merge_lines.test.cpp
index 30cd1af068..8383183e0a 100644
--- a/test/util/merge_lines.test.cpp
+++ b/test/util/merge_lines.test.cpp
@@ -9,21 +9,21 @@ const std::u16string bbb = u"b";
TEST(MergeLines, SameText) {
// merges lines with the same text
std::vector<mbgl::SymbolFeature> 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<mbgl::SymbolFeature> 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<mbgl::SymbolFeature> 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<mbgl::SymbolFeature> 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<mbgl::SymbolFeature> 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<mbgl::SymbolFeature> 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);