diff options
author | Konstantin Käfer <mail@kkaefer.com> | 2015-05-22 12:30:18 +0200 |
---|---|---|
committer | Konstantin Käfer <mail@kkaefer.com> | 2015-05-22 12:30:18 +0200 |
commit | 3cf76ce9078a2cb181748fbf79741fb75a1f6b65 (patch) | |
tree | 2331685339615fbbd38ec054e5121b49e364d7a4 | |
parent | 8678d5034a0e20a60d4de3964fc672c487cbf020 (diff) | |
download | qtlocation-mapboxgl-3cf76ce9078a2cb181748fbf79741fb75a1f6b65.tar.gz |
split up glyph_store.cpp into multiple files
-rw-r--r-- | src/mbgl/geometry/glyph_atlas.cpp | 2 | ||||
-rw-r--r-- | src/mbgl/renderer/symbol_bucket.cpp | 1 | ||||
-rw-r--r-- | src/mbgl/text/font_stack.cpp | 123 | ||||
-rw-r--r-- | src/mbgl/text/font_stack.hpp | 28 | ||||
-rw-r--r-- | src/mbgl/text/glyph.hpp | 15 | ||||
-rw-r--r-- | src/mbgl/text/glyph_pbf.cpp | 115 | ||||
-rw-r--r-- | src/mbgl/text/glyph_pbf.hpp | 47 | ||||
-rw-r--r-- | src/mbgl/text/glyph_store.cpp | 231 | ||||
-rw-r--r-- | src/mbgl/text/glyph_store.hpp | 73 |
9 files changed, 337 insertions, 298 deletions
diff --git a/src/mbgl/geometry/glyph_atlas.cpp b/src/mbgl/geometry/glyph_atlas.cpp index 02271b9c74..0c6af54785 100644 --- a/src/mbgl/geometry/glyph_atlas.cpp +++ b/src/mbgl/geometry/glyph_atlas.cpp @@ -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> diff --git a/src/mbgl/renderer/symbol_bucket.cpp b/src/mbgl/renderer/symbol_bucket.cpp index d984752f1a..28113b6184 100644 --- a/src/mbgl/renderer/symbol_bucket.cpp +++ b/src/mbgl/renderer/symbol_bucket.cpp @@ -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> diff --git a/src/mbgl/text/font_stack.cpp b/src/mbgl/text/font_stack.cpp new file mode 100644 index 0000000000..4bec6b1b48 --- /dev/null +++ b/src/mbgl/text/font_stack.cpp @@ -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 diff --git a/src/mbgl/text/font_stack.hpp b/src/mbgl/text/font_stack.hpp new file mode 100644 index 0000000000..7340cb17a9 --- /dev/null +++ b/src/mbgl/text/font_stack.hpp @@ -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 diff --git a/src/mbgl/text/glyph.hpp b/src/mbgl/text/glyph.hpp index b0af261cc6..0677bcff30 100644 --- a/src/mbgl/text/glyph.hpp +++ b/src/mbgl/text/glyph.hpp @@ -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 diff --git a/src/mbgl/text/glyph_pbf.cpp b/src/mbgl/text/glyph_pbf.cpp new file mode 100644 index 0000000000..c0642af290 --- /dev/null +++ b/src/mbgl/text/glyph_pbf.cpp @@ -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; +} + +} diff --git a/src/mbgl/text/glyph_pbf.hpp b/src/mbgl/text/glyph_pbf.hpp new file mode 100644 index 0000000000..cb36dde03e --- /dev/null +++ b/src/mbgl/text/glyph_pbf.hpp @@ -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 diff --git a/src/mbgl/text/glyph_store.cpp b/src/mbgl/text/glyph_store.cpp index 72c7b16a84..c6e00f0591 100644 --- a/src/mbgl/text/glyph_store.cpp +++ b/src/mbgl/text/glyph_store.cpp @@ -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(); })), diff --git a/src/mbgl/text/glyph_store.hpp b/src/mbgl/text/glyph_store.hpp index 77452a3057..746bcd1338 100644 --- a/src/mbgl/text/glyph_store.hpp +++ b/src/mbgl/text/glyph_store.hpp @@ -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 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; -}; +class FontStack; +class GlyphPBF; -// Manages Glyphrange PBF loading. +// Manages GlyphRange PBF loading. class GlyphStore { public: class Observer { |