split up glyph_store.cpp into multiple files
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
#include <mbgl/geometry/glyph_atlas.hpp>
|
||||
|
||||
#include <mbgl/text/font_stack.hpp>
|
||||
|
||||
#include <mbgl/platform/gl.hpp>
|
||||
#include <mbgl/platform/log.hpp>
|
||||
#include <mbgl/platform/platform.hpp>
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <mbgl/geometry/resample.hpp>
|
||||
#include <mbgl/renderer/painter.hpp>
|
||||
#include <mbgl/text/glyph_store.hpp>
|
||||
#include <mbgl/text/font_stack.hpp>
|
||||
#include <mbgl/text/placement.hpp>
|
||||
#include <mbgl/platform/log.hpp>
|
||||
#include <mbgl/text/collision.hpp>
|
||||
|
||||
123
src/mbgl/text/font_stack.cpp
Normal file
123
src/mbgl/text/font_stack.cpp
Normal file
@@ -0,0 +1,123 @@
|
||||
#include <mbgl/text/font_stack.hpp>
|
||||
|
||||
#include <mbgl/util/math.hpp>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
void FontStack::insert(uint32_t id, const SDFGlyph &glyph) {
|
||||
metrics.emplace(id, glyph.metrics);
|
||||
bitmaps.emplace(id, glyph.bitmap);
|
||||
sdfs.emplace(id, glyph);
|
||||
}
|
||||
|
||||
const std::map<uint32_t, GlyphMetrics> &FontStack::getMetrics() const {
|
||||
return metrics;
|
||||
}
|
||||
|
||||
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 horizontalAlign,
|
||||
const float verticalAlign, const float justify,
|
||||
const float spacing, const vec2<float> &translate) const {
|
||||
Shaping shaping;
|
||||
|
||||
int32_t x = std::round(translate.x * 24); // one em
|
||||
const int32_t y = std::round(translate.y * 24); // one em
|
||||
|
||||
// Loop through all characters of this label and shape.
|
||||
for (uint32_t chr : string) {
|
||||
shaping.emplace_back(chr, x, y);
|
||||
auto metric = metrics.find(chr);
|
||||
if (metric != metrics.end()) {
|
||||
x += metric->second.advance + spacing;
|
||||
}
|
||||
}
|
||||
|
||||
if (!shaping.size())
|
||||
return shaping;
|
||||
|
||||
lineWrap(shaping, lineHeight, maxWidth, horizontalAlign, verticalAlign, justify);
|
||||
|
||||
return shaping;
|
||||
}
|
||||
|
||||
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 (auto& glyph : shaping) {
|
||||
glyph.x += shiftX;
|
||||
glyph.y += shiftY;
|
||||
}
|
||||
}
|
||||
|
||||
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()) {
|
||||
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 horizontalAlign, const float verticalAlign,
|
||||
const float justify) const {
|
||||
uint32_t lastSafeBreak = 0;
|
||||
|
||||
uint32_t lengthBeforeCurrentLine = 0;
|
||||
uint32_t lineStartIndex = 0;
|
||||
uint32_t line = 0;
|
||||
|
||||
uint32_t maxLineLength = 0;
|
||||
|
||||
if (maxWidth) {
|
||||
for (uint32_t i = 0; i < shaping.size(); i++) {
|
||||
PositionedGlyph &shape = shaping[i];
|
||||
|
||||
shape.x -= lengthBeforeCurrentLine;
|
||||
shape.y += lineHeight * line;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
lineStartIndex = lastSafeBreak + 1;
|
||||
lastSafeBreak = 0;
|
||||
lengthBeforeCurrentLine += lineLength;
|
||||
line++;
|
||||
}
|
||||
|
||||
if (shape.glyph == 32) {
|
||||
lastSafeBreak = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!maxLineLength) maxLineLength = shaping.back().x;
|
||||
|
||||
justifyLine(shaping, metrics, lineStartIndex, uint32_t(shaping.size()) - 1, justify);
|
||||
align(shaping, justify, horizontalAlign, verticalAlign, maxLineLength, lineHeight, line);
|
||||
}
|
||||
|
||||
} // end namespace mbgl
|
||||
28
src/mbgl/text/font_stack.hpp
Normal file
28
src/mbgl/text/font_stack.hpp
Normal file
@@ -0,0 +1,28 @@
|
||||
#ifndef MBGL_TEXT_FONT_STACK
|
||||
#define MBGL_TEXT_FONT_STACK
|
||||
|
||||
#include <mbgl/text/glyph.hpp>
|
||||
#include <mbgl/util/vec.hpp>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
class FontStack {
|
||||
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, 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;
|
||||
std::map<uint32_t, GlyphMetrics> metrics;
|
||||
std::map<uint32_t, SDFGlyph> sdfs;
|
||||
};
|
||||
|
||||
} // end namespace mbgl
|
||||
|
||||
#endif
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
namespace mbgl {
|
||||
@@ -55,6 +56,18 @@ public:
|
||||
};
|
||||
|
||||
typedef std::vector<PositionedGlyph> Shaping;
|
||||
}
|
||||
|
||||
class SDFGlyph {
|
||||
public:
|
||||
uint32_t id = 0;
|
||||
|
||||
// A signed distance field of the glyph with a border of 3 pixels.
|
||||
std::string bitmap;
|
||||
|
||||
// Glyph metrics
|
||||
GlyphMetrics metrics;
|
||||
};
|
||||
|
||||
} // end namespace mbgl
|
||||
|
||||
#endif
|
||||
|
||||
115
src/mbgl/text/glyph_pbf.cpp
Normal file
115
src/mbgl/text/glyph_pbf.cpp
Normal file
@@ -0,0 +1,115 @@
|
||||
#include <mbgl/text/glyph_pbf.hpp>
|
||||
#include <mbgl/text/font_stack.hpp>
|
||||
|
||||
#include <mbgl/map/environment.hpp>
|
||||
|
||||
#include <mbgl/storage/resource.hpp>
|
||||
#include <mbgl/storage/response.hpp>
|
||||
|
||||
#include <mbgl/util/pbf.hpp>
|
||||
#include <mbgl/util/string.hpp>
|
||||
#include <mbgl/util/token.hpp>
|
||||
#include <mbgl/util/url.hpp>
|
||||
|
||||
#include <sstream>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
GlyphPBF::GlyphPBF(const std::string& glyphURL,
|
||||
const std::string& fontStack,
|
||||
GlyphRange glyphRange,
|
||||
Environment& env_,
|
||||
const GlyphLoadedCallback& successCallback,
|
||||
const GlyphLoadingFailedCallback& failureCallback)
|
||||
: parsed(false), env(env_) {
|
||||
// Load the glyph set URL
|
||||
std::string url = util::replaceTokens(glyphURL, [&](const std::string &name) -> std::string {
|
||||
if (name == "fontstack") return util::percentEncode(fontStack);
|
||||
if (name == "range") return util::toString(glyphRange.first) + "-" + util::toString(glyphRange.second);
|
||||
return "";
|
||||
});
|
||||
|
||||
// The prepare call jumps back to the main thread.
|
||||
req = env.request({ Resource::Kind::Glyphs, url }, [&, url, successCallback, failureCallback](const Response &res) {
|
||||
req = nullptr;
|
||||
|
||||
if (res.status != Response::Successful) {
|
||||
std::stringstream message;
|
||||
message << "Failed to load [" << url << "]: " << res.message;
|
||||
failureCallback(message.str());
|
||||
} else {
|
||||
// Transfer the data to the GlyphSet and signal its availability.
|
||||
// Once it is available, the caller will need to call parse() to actually
|
||||
// parse the data we received. We are not doing this here since this callback is being
|
||||
// called from another (unknown) thread.
|
||||
data = res.data;
|
||||
successCallback(this);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
GlyphPBF::~GlyphPBF() {
|
||||
if (req) {
|
||||
env.cancelRequest(req);
|
||||
}
|
||||
}
|
||||
|
||||
void GlyphPBF::parse(FontStack &stack) {
|
||||
if (!data.size()) {
|
||||
// If there is no data, this means we either haven't received any data, or
|
||||
// we have already parsed the data.
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse the glyph PBF
|
||||
pbf glyphs_pbf(reinterpret_cast<const uint8_t *>(data.data()), data.size());
|
||||
|
||||
while (glyphs_pbf.next()) {
|
||||
if (glyphs_pbf.tag == 1) { // stacks
|
||||
pbf fontstack_pbf = glyphs_pbf.message();
|
||||
while (fontstack_pbf.next()) {
|
||||
if (fontstack_pbf.tag == 3) { // glyphs
|
||||
pbf glyph_pbf = fontstack_pbf.message();
|
||||
|
||||
SDFGlyph glyph;
|
||||
|
||||
while (glyph_pbf.next()) {
|
||||
if (glyph_pbf.tag == 1) { // id
|
||||
glyph.id = glyph_pbf.varint();
|
||||
} else if (glyph_pbf.tag == 2) { // bitmap
|
||||
glyph.bitmap = glyph_pbf.string();
|
||||
} else if (glyph_pbf.tag == 3) { // width
|
||||
glyph.metrics.width = glyph_pbf.varint();
|
||||
} else if (glyph_pbf.tag == 4) { // height
|
||||
glyph.metrics.height = glyph_pbf.varint();
|
||||
} else if (glyph_pbf.tag == 5) { // left
|
||||
glyph.metrics.left = glyph_pbf.svarint();
|
||||
} else if (glyph_pbf.tag == 6) { // top
|
||||
glyph.metrics.top = glyph_pbf.svarint();
|
||||
} else if (glyph_pbf.tag == 7) { // advance
|
||||
glyph.metrics.advance = glyph_pbf.varint();
|
||||
} else {
|
||||
glyph_pbf.skip();
|
||||
}
|
||||
}
|
||||
|
||||
stack.insert(glyph.id, glyph);
|
||||
} else {
|
||||
fontstack_pbf.skip();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
glyphs_pbf.skip();
|
||||
}
|
||||
}
|
||||
|
||||
data.clear();
|
||||
|
||||
parsed = true;
|
||||
}
|
||||
|
||||
bool GlyphPBF::isParsed() const {
|
||||
return parsed;
|
||||
}
|
||||
|
||||
}
|
||||
47
src/mbgl/text/glyph_pbf.hpp
Normal file
47
src/mbgl/text/glyph_pbf.hpp
Normal file
@@ -0,0 +1,47 @@
|
||||
#ifndef MBGL_TEXT_GLYPH_PBF
|
||||
#define MBGL_TEXT_GLYPH_PBF
|
||||
|
||||
#include <mbgl/text/glyph.hpp>
|
||||
|
||||
#include <functional>
|
||||
#include <atomic>
|
||||
#include <string>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
class Environment;
|
||||
class FontStack;
|
||||
class Request;
|
||||
|
||||
class GlyphPBF {
|
||||
public:
|
||||
using GlyphLoadedCallback = std::function<void(GlyphPBF*)>;
|
||||
using GlyphLoadingFailedCallback = std::function<void(const std::string&)>;
|
||||
|
||||
GlyphPBF(const std::string &glyphURL,
|
||||
const std::string &fontStack,
|
||||
GlyphRange glyphRange,
|
||||
Environment &env,
|
||||
const GlyphLoadedCallback& successCallback,
|
||||
const GlyphLoadingFailedCallback& failureCallback);
|
||||
~GlyphPBF();
|
||||
|
||||
void parse(FontStack &stack);
|
||||
bool isParsed() const;
|
||||
|
||||
private:
|
||||
GlyphPBF(const GlyphPBF &) = delete;
|
||||
GlyphPBF(GlyphPBF &&) = delete;
|
||||
GlyphPBF &operator=(const GlyphPBF &) = delete;
|
||||
GlyphPBF &operator=(GlyphPBF &&) = delete;
|
||||
|
||||
std::string data;
|
||||
std::atomic<bool> parsed;
|
||||
|
||||
Environment& env;
|
||||
Request* req = nullptr;
|
||||
};
|
||||
|
||||
} // end namespace mbgl
|
||||
|
||||
#endif
|
||||
@@ -1,240 +1,13 @@
|
||||
#include <mbgl/text/glyph_store.hpp>
|
||||
#include <mbgl/text/glyph_pbf.hpp>
|
||||
#include <mbgl/text/font_stack.hpp>
|
||||
|
||||
#include <mbgl/map/environment.hpp>
|
||||
#include <mbgl/platform/log.hpp>
|
||||
#include <mbgl/platform/platform.hpp>
|
||||
#include <mbgl/storage/file_source.hpp>
|
||||
#include <mbgl/util/constants.hpp>
|
||||
#include <mbgl/util/exception.hpp>
|
||||
#include <mbgl/util/math.hpp>
|
||||
#include <mbgl/util/pbf.hpp>
|
||||
#include <mbgl/util/std.hpp>
|
||||
#include <mbgl/util/string.hpp>
|
||||
#include <mbgl/util/token.hpp>
|
||||
#include <mbgl/util/url.hpp>
|
||||
#include <mbgl/util/utf.hpp>
|
||||
#include <mbgl/util/uv_detail.hpp>
|
||||
#include <mbgl/util/uv_detail.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
|
||||
void FontStack::insert(uint32_t id, const SDFGlyph &glyph) {
|
||||
metrics.emplace(id, glyph.metrics);
|
||||
bitmaps.emplace(id, glyph.bitmap);
|
||||
sdfs.emplace(id, glyph);
|
||||
}
|
||||
|
||||
const std::map<uint32_t, GlyphMetrics> &FontStack::getMetrics() const {
|
||||
return metrics;
|
||||
}
|
||||
|
||||
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 horizontalAlign,
|
||||
const float verticalAlign, const float justify,
|
||||
const float spacing, const vec2<float> &translate) const {
|
||||
Shaping shaping;
|
||||
|
||||
int32_t x = std::round(translate.x * 24); // one em
|
||||
const int32_t y = std::round(translate.y * 24); // one em
|
||||
|
||||
// Loop through all characters of this label and shape.
|
||||
for (uint32_t chr : string) {
|
||||
shaping.emplace_back(chr, x, y);
|
||||
auto metric = metrics.find(chr);
|
||||
if (metric != metrics.end()) {
|
||||
x += metric->second.advance + spacing;
|
||||
}
|
||||
}
|
||||
|
||||
if (!shaping.size())
|
||||
return shaping;
|
||||
|
||||
lineWrap(shaping, lineHeight, maxWidth, horizontalAlign, verticalAlign, justify);
|
||||
|
||||
return shaping;
|
||||
}
|
||||
|
||||
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 (auto& glyph : shaping) {
|
||||
glyph.x += shiftX;
|
||||
glyph.y += shiftY;
|
||||
}
|
||||
}
|
||||
|
||||
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()) {
|
||||
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 horizontalAlign, const float verticalAlign,
|
||||
const float justify) const {
|
||||
uint32_t lastSafeBreak = 0;
|
||||
|
||||
uint32_t lengthBeforeCurrentLine = 0;
|
||||
uint32_t lineStartIndex = 0;
|
||||
uint32_t line = 0;
|
||||
|
||||
uint32_t maxLineLength = 0;
|
||||
|
||||
if (maxWidth) {
|
||||
for (uint32_t i = 0; i < shaping.size(); i++) {
|
||||
PositionedGlyph &shape = shaping[i];
|
||||
|
||||
shape.x -= lengthBeforeCurrentLine;
|
||||
shape.y += lineHeight * line;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
lineStartIndex = lastSafeBreak + 1;
|
||||
lastSafeBreak = 0;
|
||||
lengthBeforeCurrentLine += lineLength;
|
||||
line++;
|
||||
}
|
||||
|
||||
if (shape.glyph == 32) {
|
||||
lastSafeBreak = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!maxLineLength) maxLineLength = shaping.back().x;
|
||||
|
||||
justifyLine(shaping, metrics, lineStartIndex, uint32_t(shaping.size()) - 1, justify);
|
||||
align(shaping, justify, horizontalAlign, verticalAlign, maxLineLength, lineHeight, line);
|
||||
}
|
||||
|
||||
GlyphPBF::GlyphPBF(const std::string& glyphURL,
|
||||
const std::string& fontStack,
|
||||
GlyphRange glyphRange,
|
||||
Environment& env_,
|
||||
const GlyphLoadedCallback& successCallback,
|
||||
const GlyphLoadingFailedCallback& failureCallback)
|
||||
: parsed(false), env(env_) {
|
||||
// Load the glyph set URL
|
||||
std::string url = util::replaceTokens(glyphURL, [&](const std::string &name) -> std::string {
|
||||
if (name == "fontstack") return util::percentEncode(fontStack);
|
||||
if (name == "range") return util::toString(glyphRange.first) + "-" + util::toString(glyphRange.second);
|
||||
return "";
|
||||
});
|
||||
|
||||
// The prepare call jumps back to the main thread.
|
||||
req = env.request({ Resource::Kind::Glyphs, url }, [&, url, successCallback, failureCallback](const Response &res) {
|
||||
req = nullptr;
|
||||
|
||||
if (res.status != Response::Successful) {
|
||||
std::stringstream message;
|
||||
message << "Failed to load [" << url << "]: " << res.message;
|
||||
failureCallback(message.str());
|
||||
} else {
|
||||
// Transfer the data to the GlyphSet and signal its availability.
|
||||
// Once it is available, the caller will need to call parse() to actually
|
||||
// parse the data we received. We are not doing this here since this callback is being
|
||||
// called from another (unknown) thread.
|
||||
data = res.data;
|
||||
successCallback(this);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
GlyphPBF::~GlyphPBF() {
|
||||
if (req) {
|
||||
env.cancelRequest(req);
|
||||
}
|
||||
}
|
||||
|
||||
void GlyphPBF::parse(FontStack &stack) {
|
||||
if (!data.size()) {
|
||||
// If there is no data, this means we either haven't received any data, or
|
||||
// we have already parsed the data.
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse the glyph PBF
|
||||
pbf glyphs_pbf(reinterpret_cast<const uint8_t *>(data.data()), data.size());
|
||||
|
||||
while (glyphs_pbf.next()) {
|
||||
if (glyphs_pbf.tag == 1) { // stacks
|
||||
pbf fontstack_pbf = glyphs_pbf.message();
|
||||
while (fontstack_pbf.next()) {
|
||||
if (fontstack_pbf.tag == 3) { // glyphs
|
||||
pbf glyph_pbf = fontstack_pbf.message();
|
||||
|
||||
SDFGlyph glyph;
|
||||
|
||||
while (glyph_pbf.next()) {
|
||||
if (glyph_pbf.tag == 1) { // id
|
||||
glyph.id = glyph_pbf.varint();
|
||||
} else if (glyph_pbf.tag == 2) { // bitmap
|
||||
glyph.bitmap = glyph_pbf.string();
|
||||
} else if (glyph_pbf.tag == 3) { // width
|
||||
glyph.metrics.width = glyph_pbf.varint();
|
||||
} else if (glyph_pbf.tag == 4) { // height
|
||||
glyph.metrics.height = glyph_pbf.varint();
|
||||
} else if (glyph_pbf.tag == 5) { // left
|
||||
glyph.metrics.left = glyph_pbf.svarint();
|
||||
} else if (glyph_pbf.tag == 6) { // top
|
||||
glyph.metrics.top = glyph_pbf.svarint();
|
||||
} else if (glyph_pbf.tag == 7) { // advance
|
||||
glyph.metrics.advance = glyph_pbf.varint();
|
||||
} else {
|
||||
glyph_pbf.skip();
|
||||
}
|
||||
}
|
||||
|
||||
stack.insert(glyph.id, glyph);
|
||||
} else {
|
||||
fontstack_pbf.skip();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
glyphs_pbf.skip();
|
||||
}
|
||||
}
|
||||
|
||||
data.clear();
|
||||
|
||||
parsed = true;
|
||||
}
|
||||
|
||||
bool GlyphPBF::isParsed() const {
|
||||
return parsed;
|
||||
}
|
||||
|
||||
GlyphStore::GlyphStore(uv_loop_t* loop, Environment& env_)
|
||||
: env(env_),
|
||||
asyncEmitGlyphRangeLoaded(util::make_unique<uv::async>(loop, [this] { emitGlyphRangeLoaded(); })),
|
||||
|
||||
@@ -2,90 +2,27 @@
|
||||
#define MBGL_TEXT_GLYPH_STORE
|
||||
|
||||
#include <mbgl/text/glyph.hpp>
|
||||
#include <mbgl/util/vec.hpp>
|
||||
#include <mbgl/util/ptr.hpp>
|
||||
|
||||
#include <mbgl/util/exclusive.hpp>
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
#include <future>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <exception>
|
||||
|
||||
typedef struct uv_loop_s uv_loop_t;
|
||||
|
||||
namespace uv {
|
||||
|
||||
class async;
|
||||
|
||||
}
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
class FileSource;
|
||||
class Environment;
|
||||
class Request;
|
||||
class FontStack;
|
||||
class GlyphPBF;
|
||||
|
||||
class SDFGlyph {
|
||||
public:
|
||||
uint32_t id = 0;
|
||||
|
||||
// A signed distance field of the glyph with a border of 3 pixels.
|
||||
std::string bitmap;
|
||||
|
||||
// Glyph metrics
|
||||
GlyphMetrics metrics;
|
||||
};
|
||||
|
||||
class FontStack {
|
||||
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, 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;
|
||||
std::map<uint32_t, GlyphMetrics> metrics;
|
||||
std::map<uint32_t, SDFGlyph> sdfs;
|
||||
};
|
||||
|
||||
class GlyphPBF {
|
||||
public:
|
||||
using GlyphLoadedCallback = std::function<void(GlyphPBF*)>;
|
||||
using GlyphLoadingFailedCallback = std::function<void(const std::string&)>;
|
||||
|
||||
GlyphPBF(const std::string &glyphURL,
|
||||
const std::string &fontStack,
|
||||
GlyphRange glyphRange,
|
||||
Environment &env,
|
||||
const GlyphLoadedCallback& successCallback,
|
||||
const GlyphLoadingFailedCallback& failureCallback);
|
||||
~GlyphPBF();
|
||||
|
||||
void parse(FontStack &stack);
|
||||
bool isParsed() const;
|
||||
|
||||
private:
|
||||
GlyphPBF(const GlyphPBF &) = delete;
|
||||
GlyphPBF(GlyphPBF &&) = delete;
|
||||
GlyphPBF &operator=(const GlyphPBF &) = delete;
|
||||
GlyphPBF &operator=(GlyphPBF &&) = delete;
|
||||
|
||||
std::string data;
|
||||
std::atomic_bool parsed;
|
||||
|
||||
Environment& env;
|
||||
Request* req = nullptr;
|
||||
};
|
||||
|
||||
// Manages Glyphrange PBF loading.
|
||||
// Manages GlyphRange PBF loading.
|
||||
class GlyphStore {
|
||||
public:
|
||||
class Observer {
|
||||
|
||||
Reference in New Issue
Block a user