summaryrefslogtreecommitdiff
path: root/src/mbgl/text/glyph_set.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mbgl/text/glyph_set.cpp')
-rw-r--r--src/mbgl/text/glyph_set.cpp54
1 files changed, 31 insertions, 23 deletions
diff --git a/src/mbgl/text/glyph_set.cpp b/src/mbgl/text/glyph_set.cpp
index f9a90f9bb0..19a6e2cddd 100644
--- a/src/mbgl/text/glyph_set.cpp
+++ b/src/mbgl/text/glyph_set.cpp
@@ -42,18 +42,17 @@ const Shaping GlyphSet::getShaping(const std::u16string& logicalInput,
const float justify,
const float spacing,
const Point<float>& translate,
+ const float verticalHeight,
+ const WritingModeType writingMode,
BiDi& bidi) const {
-
- // The string stored in shaping.text is used for finding duplicates, but may end up quite
- // different from the glyphs that get shown
- Shaping shaping(translate.x * 24, translate.y * 24, logicalInput);
+ Shaping shaping(translate.x * 24, translate.y * 24, writingMode);
std::vector<std::u16string> reorderedLines =
bidi.processText(logicalInput,
- determineLineBreaks(logicalInput, spacing, maxWidth));
+ determineLineBreaks(logicalInput, spacing, maxWidth, writingMode));
shapeLines(shaping, reorderedLines, spacing, lineHeight, horizontalAlign, verticalAlign,
- justify, translate);
+ justify, translate, verticalHeight, writingMode);
return shaping;
}
@@ -114,7 +113,7 @@ float GlyphSet::determineAverageLineWidth(const std::u16string& logicalInput,
int32_t targetLineCount = std::fmax(1, std::ceil(totalWidth / maxWidth));
return totalWidth / targetLineCount;
}
-
+
float calculateBadness(const float lineWidth, const float targetWidth, const float penalty, const bool isLastBreak) {
const float raggedness = std::pow(lineWidth - targetWidth, 2);
if (isLastBreak) {
@@ -130,7 +129,7 @@ float calculateBadness(const float lineWidth, const float targetWidth, const flo
}
return raggedness + std::pow(penalty, 2);
}
-
+
float calculatePenalty(char16_t codePoint, char16_t nextCodePoint) {
float penalty = 0;
// Force break on newline
@@ -146,28 +145,28 @@ float calculatePenalty(char16_t codePoint, char16_t nextCodePoint) {
if (nextCodePoint == 0x29 || nextCodePoint == 0xff09) {
penalty += 50;
}
-
+
return penalty;
}
-
+
struct PotentialBreak {
PotentialBreak(const std::size_t p_index, const float p_x, const PotentialBreak* p_priorBreak, const float p_badness)
: index(p_index), x(p_x), priorBreak(p_priorBreak), badness(p_badness)
{}
-
+
const std::size_t index;
const float x;
const PotentialBreak* priorBreak;
const float badness;
};
-
+
PotentialBreak evaluateBreak(const std::size_t breakIndex, const float breakX, const float targetWidth, const std::list<PotentialBreak>& potentialBreaks, const float penalty, const bool isLastBreak) {
// We could skip evaluating breaks where the line length (breakX - priorBreak.x) > maxWidth
// ...but in fact we allow lines longer than maxWidth (if there's no break points)
// ...and when targetWidth and maxWidth are close, strictly enforcing maxWidth can give
// more lopsided results.
-
+
const PotentialBreak* bestPriorBreak = nullptr;
float bestBreakBadness = calculateBadness(breakX, targetWidth, penalty, isLastBreak);
for (const auto& potentialBreak : potentialBreaks) {
@@ -182,7 +181,7 @@ PotentialBreak evaluateBreak(const std::size_t breakIndex, const float breakX, c
return PotentialBreak(breakIndex, breakX, bestPriorBreak, bestBreakBadness);
}
-
+
std::set<std::size_t> leastBadBreaks(const PotentialBreak& lastLineBreak) {
std::set<std::size_t> leastBadBreaks = { lastLineBreak.index };
const PotentialBreak* priorBreak = lastLineBreak.priorBreak;
@@ -198,17 +197,18 @@ std::set<std::size_t> leastBadBreaks(const PotentialBreak& lastLineBreak) {
// more intuitive, but we can't do that because the visual order may be changed by line breaks!
std::set<std::size_t> GlyphSet::determineLineBreaks(const std::u16string& logicalInput,
const float spacing,
- float maxWidth) const {
- if (!maxWidth) {
+ float maxWidth,
+ const WritingModeType writingMode) const {
+ if (!maxWidth || writingMode != WritingModeType::Horizontal) {
return {};
}
if (logicalInput.empty()) {
return {};
}
-
+
const float targetWidth = determineAverageLineWidth(logicalInput, spacing, maxWidth);
-
+
std::list<PotentialBreak> potentialBreaks;
float currentX = 0;
@@ -218,7 +218,7 @@ std::set<std::size_t> GlyphSet::determineLineBreaks(const std::u16string& logica
if (it != sdfs.end() && !boost::algorithm::is_any_of(u" \t\n\v\f\r")(codePoint)) {
currentX += it->second.metrics.advance + spacing;
}
-
+
// Ideographic characters, spaces, and word-breaking punctuation that often appear without
// surrounding spaces.
if ((i < logicalInput.size() - 1) &&
@@ -239,7 +239,9 @@ void GlyphSet::shapeLines(Shaping& shaping,
const float horizontalAlign,
const float verticalAlign,
const float justify,
- const Point<float>& translate) const {
+ const Point<float>& translate,
+ const float verticalHeight,
+ const WritingModeType writingMode) const {
// the y offset *should* be part of the font metadata
const int32_t yOffset = -17;
@@ -266,15 +268,21 @@ void GlyphSet::shapeLines(Shaping& shaping,
}
const SDFGlyph& glyph = it->second;
- shaping.positionedGlyphs.emplace_back(chr, x, y);
- x += glyph.metrics.advance + spacing;
+
+ if (writingMode == WritingModeType::Horizontal || !util::i18n::hasUprightVerticalOrientation(chr)) {
+ shaping.positionedGlyphs.emplace_back(chr, x, y, 0);
+ x += glyph.metrics.advance + spacing;
+ } else {
+ shaping.positionedGlyphs.emplace_back(chr, x, 0, -M_PI_2);
+ x += verticalHeight + spacing;
+ }
}
// Only justify if we placed at least one glyph
if (shaping.positionedGlyphs.size() != lineStartIndex) {
float lineLength = x - spacing; // Don't count trailing spacing
maxLineLength = util::max(lineLength, maxLineLength);
-
+
justifyLine(shaping.positionedGlyphs, sdfs, lineStartIndex,
shaping.positionedGlyphs.size() - 1, justify);
}