summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKonstantin Käfer <mail@kkaefer.com>2014-08-05 16:18:23 +0200
committerKonstantin Käfer <mail@kkaefer.com>2014-08-05 16:18:23 +0200
commit898c5dc7c3ebf36c6a4df3ab62ad6aacfc82985a (patch)
treefc546a2747f9b244bdc2afc79df0ec65e2625fb0
parent05b95ab05714a05901c92fc52a23ba21ec14925a (diff)
downloadqtlocation-mapboxgl-898c5dc7c3ebf36c6a4df3ab62ad6aacfc82985a.tar.gz
port text alignment algorithm
-rw-r--r--include/mbgl/text/glyph_store.hpp17
-rw-r--r--src/renderer/symbol_bucket.cpp19
-rw-r--r--src/text/glyph_store.cpp116
3 files changed, 88 insertions, 64 deletions
diff --git a/include/mbgl/text/glyph_store.hpp b/include/mbgl/text/glyph_store.hpp
index 9c874b31b0..66cf8e75b3 100644
--- a/include/mbgl/text/glyph_store.hpp
+++ b/include/mbgl/text/glyph_store.hpp
@@ -3,6 +3,7 @@
#include <mbgl/text/glyph.hpp>
#include <mbgl/util/pbf.hpp>
+#include <mbgl/util/vec.hpp>
#include <cstdint>
#include <vector>
@@ -30,17 +31,11 @@ public:
void insert(uint32_t id, const SDFGlyph &glyph);
const std::map<uint32_t, GlyphMetrics> &getMetrics() const;
const std::map<uint32_t, SDFGlyph> &getSDFs() const;
- const Shaping getShaping(const std::u32string &string,
- const float &maxWidth,
- const float &lineHeight,
- const float &alignment,
- const float &verticalAlignment,
- const float &letterSpacing) const;
- void lineWrap(Shaping &shaping,
- const float &lineHeight,
- const float &maxWidth,
- const float &alignment,
- const float &verticalAlignment) const;
+ const Shaping getShaping(const std::u32string &string, float maxWidth, float lineHeight,
+ float horizontalAlign, float verticalAlign, float justify,
+ float spacing, const vec2<float> &translate) const;
+ void lineWrap(Shaping &shaping, float lineHeight, float maxWidth, float horizontalAlign,
+ float verticalAlign, float justify) const;
private:
std::map<uint32_t, std::string> bitmaps;
diff --git a/src/renderer/symbol_bucket.cpp b/src/renderer/symbol_bucket.cpp
index e5bd3a3e1a..4072cf0c61 100644
--- a/src/renderer/symbol_bucket.cpp
+++ b/src/renderer/symbol_bucket.cpp
@@ -126,6 +126,10 @@ void SymbolBucket::addFeatures(const VectorTileLayer &layer, const FilterExpress
else if (properties.text.vertical_align == TextVerticalAlignType::Top)
verticalAlign = 0;
+ float justify = 0.5;
+ if (properties.text.justify == TextJustifyType::Right) justify = 1;
+ else if (properties.text.justify == TextJustifyType::Left) justify = 0;
+
const FontStack &fontStack = glyphStore.getFontStack(properties.text.font);
for (const SymbolFeature &feature : features) {
@@ -135,9 +139,15 @@ void SymbolBucket::addFeatures(const VectorTileLayer &layer, const FilterExpress
// if feature has text, shape the text
if (feature.label.length()) {
- shaping = fontStack.getShaping(feature.label, properties.text.max_width,
- properties.text.line_height, horizontalAlign,
- verticalAlign, properties.text.letter_spacing);
+ shaping = fontStack.getShaping(
+ /* string */ feature.label,
+ /* maxWidth */ properties.text.max_width,
+ /* lineHeight */ properties.text.line_height,
+ /* horizontalAlign */ horizontalAlign,
+ /* verticalAlign */ verticalAlign,
+ /* justify */ justify,
+ /* spacing */ properties.text.letter_spacing,
+ /* translate */ properties.text.offset);
// Add the glyphs we need for this label to the glyph atlas.
if (shaping.size()) {
@@ -219,7 +229,8 @@ void SymbolBucket::addFeature(const std::vector<Coordinate> &line, const Shaping
anchors = {Anchor{float(line[0].x), float(line[0].y), 0, minScale}};
}
- const vec2<float> origin = {0, 0};
+ // TODO: figure out correct ascender height.
+ const vec2<float> origin = {0, -17};
for (Anchor &anchor : anchors) {
diff --git a/src/text/glyph_store.cpp b/src/text/glyph_store.cpp
index fa39902227..a28569d851 100644
--- a/src/text/glyph_store.cpp
+++ b/src/text/glyph_store.cpp
@@ -6,6 +6,7 @@
#include <mbgl/util/pbf.hpp>
#include <mbgl/util/constants.hpp>
#include <mbgl/util/token.hpp>
+#include <mbgl/util/math.hpp>
#include <mbgl/platform/platform.hpp>
#include <uv.h>
#include <algorithm>
@@ -30,91 +31,108 @@ const std::map<uint32_t, SDFGlyph> &FontStack::getSDFs() const {
return sdfs;
}
-const Shaping FontStack::getShaping(const std::u32string &string, const float &maxWidth,
- const float &lineHeight, const float &alignment, const float &verticalAlignment,
- const float &letterSpacing) const {
-
+const Shaping FontStack::getShaping(const std::u32string &string, const float maxWidth,
+ const float lineHeight, const float horizontalAlign,
+ const float verticalAlign, const float justify,
+ const float spacing, const vec2<float> &translate) const {
std::lock_guard<std::mutex> lock(mtx);
- uint32_t i = 0;
- uint32_t x = 0;
+
Shaping shaping;
+
+ uint32_t x = translate.x;
+ const uint32_t y = translate.y;
+
// Loop through all characters of this label and shape.
for (uint32_t chr : string) {
- shaping.emplace_back(chr, x, 0);
- i++;
+ shaping.emplace_back(chr, x, y);
auto metric = metrics.find(chr);
if (metric != metrics.end()) {
- x += metric->second.advance + letterSpacing;
+ x += metric->second.advance + spacing;
}
}
- lineWrap(shaping, lineHeight, maxWidth, alignment, verticalAlignment);
+ if (!shaping.size())
+ return shaping;
+
+ lineWrap(shaping, lineHeight, maxWidth, horizontalAlign, verticalAlign, justify);
return shaping;
}
-void alignVertically(Shaping &shaping, const uint32_t &lines, const float &lineHeight, const float &verticalAlign) {
- // TODO: figure out correct ascender height.
- const float dy = -(lineHeight * (lines - 1) + 24) * verticalAlign - 5;
- for (PositionedGlyph &shape : shaping) {
- shape.y += dy;
+void align(Shaping &shaping, const float justify, const float horizontalAlign,
+ const float verticalAlign, const uint32_t maxLineLength, const float lineHeight,
+ const uint32_t line) {
+ const float shiftX = (justify - horizontalAlign) * maxLineLength;
+ const float shiftY = (-verticalAlign * (line + 1) + 0.5) * lineHeight;
+
+ for (PositionedGlyph &glyph : shaping) {
+ glyph.x += shiftX;
+ glyph.y += shiftY;
}
}
-void alignHorizontally(Shaping &shaping, const std::map<uint32_t, GlyphMetrics> &metrics,
- const uint32_t &start, const uint32_t &end, const float &alignment) {
- auto & shape = shaping.at(end);
- auto metric = metrics.find(shape.glyph);
+void justifyLine(Shaping &shaping, const std::map<uint32_t, GlyphMetrics> &metrics, uint32_t start,
+ uint32_t end, float justify) {
+ PositionedGlyph &glyph = shaping[end];
+ auto metric = metrics.find(glyph.glyph);
if (metric != metrics.end()) {
- uint32_t lastAdvance = metric->second.advance;
- int32_t lineIndent = (shape.x + lastAdvance) * alignment;
+ const uint32_t lastAdvance = metric->second.advance;
+ const float lineIndent = float(glyph.x + lastAdvance) * justify;
+
for (uint32_t j = start; j <= end; j++) {
shaping[j].x -= lineIndent;
}
}
}
-void FontStack::lineWrap(Shaping &shaping, const float &lineHeight, const float &maxWidth,
- const float &alignment, const float &verticalAlignment) const {
-
- std::size_t num_shapes = shaping.size();
- if (!num_shapes) {
- return;
- }
+void FontStack::lineWrap(Shaping &shaping, const float lineHeight, const float maxWidth,
+ const float horizontalAlign, const float verticalAlign,
+ const float justify) const {
uint32_t lastSafeBreak = 0;
+
uint32_t lengthBeforeCurrentLine = 0;
uint32_t lineStartIndex = 0;
uint32_t line = 0;
- for (uint32_t i = 0; i < shaping.size(); i++) {
- PositionedGlyph &shape = shaping[i];
- shape.x -= lengthBeforeCurrentLine;
- shape.y += lineHeight * line;
+ uint32_t maxLineLength = 0;
- if (shape.x > maxWidth && lastSafeBreak > 0) {
+ if (maxWidth) {
+ for (uint32_t i = 0; i < shaping.size(); i++) {
+ PositionedGlyph &shape = shaping[i];
- uint32_t lineLength = shaping[lastSafeBreak + 1].x;
+ shape.x -= lengthBeforeCurrentLine;
+ shape.y += lineHeight * line;
- for (uint32_t k = lastSafeBreak + 1; k <= i; k++) {
- shaping[k].y += lineHeight;
- shaping[k].x -= lineLength;
- }
+ if (shape.x > maxWidth && lastSafeBreak > 0) {
+
+ uint32_t lineLength = shaping[lastSafeBreak + 1].x;
+ maxLineLength = util::max(lineLength, maxLineLength);
+
+ for (uint32_t k = lastSafeBreak + 1; k <= i; k++) {
+ shaping[k].y += lineHeight;
+ shaping[k].x -= lineLength;
+ }
+
+ if (justify) {
+ justifyLine(shaping, metrics, lineStartIndex, lastSafeBreak - 1, justify);
+ }
- if (alignment) {
- alignHorizontally(shaping, metrics, lineStartIndex, lastSafeBreak - 1, alignment);
+ lineStartIndex = lastSafeBreak + 1;
+ lastSafeBreak = 0;
+ lengthBeforeCurrentLine += lineLength;
+ line++;
}
- lineStartIndex = lastSafeBreak + 1;
- lastSafeBreak = 0;
- lengthBeforeCurrentLine += lineLength;
- line++;
- }
- if (shape.glyph == 32) {
- lastSafeBreak = i;
+ if (shape.glyph == 32) {
+ lastSafeBreak = i;
+ }
}
}
- alignHorizontally(shaping, metrics, lineStartIndex, shaping.size() - 1, alignment);
- alignVertically(shaping, line + 1, lineHeight, verticalAlignment);
+
+ maxLineLength = maxLineLength || shaping.back().x;
+
+ justifyLine(shaping, metrics, lineStartIndex, shaping.size() - 1, justify);
+ align(shaping, justify, horizontalAlign, verticalAlign, maxLineLength, lineHeight, line);
}
GlyphPBF::GlyphPBF(const std::string &glyphURL, const std::string &fontStack, GlyphRange glyphRange)