diff options
author | John Firebaugh <john.firebaugh@gmail.com> | 2017-06-01 10:30:49 -0700 |
---|---|---|
committer | John Firebaugh <john.firebaugh@gmail.com> | 2017-06-13 10:18:43 -0700 |
commit | 92252849c1a2ddf7887d1908841fa3c90dd59766 (patch) | |
tree | 9d192d0e60b46479122ea2e4a606b598287d49d7 /src/mbgl/text | |
parent | b201a7900f989af432aaea500a0e6c5ea5bbba53 (diff) | |
download | qtlocation-mapboxgl-92252849c1a2ddf7887d1908841fa3c90dd59766.tar.gz |
[core] Per-bucket glyph atlases
Diffstat (limited to 'src/mbgl/text')
-rw-r--r-- | src/mbgl/text/glyph.hpp | 20 | ||||
-rw-r--r-- | src/mbgl/text/glyph_atlas.cpp | 280 | ||||
-rw-r--r-- | src/mbgl/text/glyph_atlas.hpp | 105 | ||||
-rw-r--r-- | src/mbgl/text/glyph_manager.cpp | 145 | ||||
-rw-r--r-- | src/mbgl/text/glyph_manager.hpp | 68 | ||||
-rw-r--r-- | src/mbgl/text/glyph_manager_observer.hpp (renamed from src/mbgl/text/glyph_atlas_observer.hpp) | 4 | ||||
-rw-r--r-- | src/mbgl/text/glyph_pbf.cpp | 10 | ||||
-rw-r--r-- | src/mbgl/text/glyph_pbf.hpp | 18 | ||||
-rw-r--r-- | src/mbgl/text/quads.cpp | 4 | ||||
-rw-r--r-- | src/mbgl/text/quads.hpp | 2 | ||||
-rw-r--r-- | src/mbgl/text/shaping.cpp | 18 | ||||
-rw-r--r-- | src/mbgl/text/shaping.hpp | 3 |
12 files changed, 304 insertions, 373 deletions
diff --git a/src/mbgl/text/glyph.hpp b/src/mbgl/text/glyph.hpp index 7cfb9aa0d9..b9eaedd302 100644 --- a/src/mbgl/text/glyph.hpp +++ b/src/mbgl/text/glyph.hpp @@ -5,6 +5,8 @@ #include <mbgl/util/rect.hpp> #include <mbgl/util/traits.hpp> #include <mbgl/util/optional.hpp> +#include <mbgl/util/immutable.hpp> +#include <mbgl/util/image.hpp> #include <cstdint> #include <vector> @@ -35,13 +37,23 @@ inline bool operator==(const GlyphMetrics& lhs, const GlyphMetrics& rhs) { lhs.advance == rhs.advance; } -struct Glyph { - Rect<uint16_t> rect; +class Glyph { +public: + // We're using this value throughout the Mapbox GL ecosystem. If this is different, the glyphs + // also need to be reencoded. + static constexpr const uint8_t borderSize = 3; + + GlyphID id = 0; + + // A signed distance field of the glyph with a border (see above). + AlphaImage bitmap; + + // Glyph metrics GlyphMetrics metrics; }; -using GlyphPositions = std::map<GlyphID, optional<Glyph>>; -using GlyphPositionMap = std::map<FontStack, GlyphPositions>; +using Glyphs = std::map<GlyphID, optional<Immutable<Glyph>>>; +using GlyphMap = std::map<FontStack, Glyphs>; class PositionedGlyph { public: diff --git a/src/mbgl/text/glyph_atlas.cpp b/src/mbgl/text/glyph_atlas.cpp index c6083fe0cc..a08455ec63 100644 --- a/src/mbgl/text/glyph_atlas.cpp +++ b/src/mbgl/text/glyph_atlas.cpp @@ -1,256 +1,64 @@ #include <mbgl/text/glyph_atlas.hpp> -#include <mbgl/text/glyph_atlas_observer.hpp> -#include <mbgl/text/glyph_pbf.hpp> -#include <mbgl/gl/context.hpp> -#include <mbgl/util/logging.hpp> -#include <mbgl/util/platform.hpp> -#include <mbgl/storage/file_source.hpp> -#include <mbgl/storage/resource.hpp> -#include <mbgl/storage/response.hpp> -#include <cassert> -#include <algorithm> +#include <mapbox/shelf-pack.hpp> namespace mbgl { -static GlyphAtlasObserver nullObserver; +static constexpr uint32_t padding = 1; -GlyphAtlas::GlyphAtlas(const Size size, FileSource& fileSource_) - : fileSource(fileSource_), - observer(&nullObserver), - bin(size.width, size.height), - image(size), - dirty(true) { -} - -GlyphAtlas::~GlyphAtlas() = default; +GlyphAtlas makeGlyphAtlas(const Glyphs& glyphs) { + GlyphAtlas result; -void GlyphAtlas::getGlyphs(GlyphRequestor& requestor, GlyphDependencies glyphDependencies) { - auto dependencies = std::make_shared<GlyphDependencies>(std::move(glyphDependencies)); + mapbox::ShelfPack::ShelfPackOptions options; + options.autoResize = true; + mapbox::ShelfPack pack(0, 0, options); - // Figure out which glyph ranges need to be fetched. For each range that does need to - // be fetched, record an entry mapping the requestor to a shared pointer containing the - // dependencies. When the shared pointer becomes unique, we know that all the dependencies - // for that requestor have been fetched, and can notify it of completion. - for (const auto& dependency : *dependencies) { - const FontStack& fontStack = dependency.first; - Entry& entry = entries[fontStack]; + std::vector<mapbox::Bin> bins; + bins.reserve(glyphs.size()); - const GlyphIDs& glyphIDs = dependency.second; - GlyphRangeSet ranges; - for (const auto& glyphID : glyphIDs) { - ranges.insert(getGlyphRange(glyphID)); - } - - for (const auto& range : ranges) { - auto it = entry.ranges.find(range); - if (it == entry.ranges.end() || !it->second.parsed) { - GlyphRequest& request = requestRange(entry, fontStack, range); - request.requestors[&requestor] = dependencies; - } + for (const auto& entry : glyphs) { + if (entry.second && (*entry.second)->bitmap.valid()) { + const Glyph& glyph = **entry.second; + bins.emplace_back(glyph.id, + glyph.bitmap.size.width + 2 * padding, + glyph.bitmap.size.height + 2 * padding); } } - // If the shared dependencies pointer is already unique, then all dependent glyph ranges - // have already been loaded. Send a notification immediately. - if (dependencies.unique()) { - addGlyphs(requestor, *dependencies); - } -} - -GlyphAtlas::GlyphRequest& GlyphAtlas::requestRange(Entry& entry, const FontStack& fontStack, const GlyphRange& range) { - GlyphRequest& request = entry.ranges[range]; - - if (request.req) { - return request; - } + mapbox::ShelfPack::PackOptions packOptions; + packOptions.inPlace = true; + pack.pack(bins, packOptions); - request.req = fileSource.request(Resource::glyphs(glyphURL, fontStack, range), [this, fontStack, range](Response res) { - processResponse(res, fontStack, range); + result.image = AlphaImage({ + static_cast<uint32_t>(pack.width()), + static_cast<uint32_t>(pack.height()) }); - return request; -} - -void GlyphAtlas::processResponse(const Response& res, const FontStack& fontStack, const GlyphRange& range) { - if (res.error) { - observer->onGlyphsError(fontStack, range, std::make_exception_ptr(std::runtime_error(res.error->message))); - return; - } - - if (res.notModified) { - return; - } - - Entry& entry = entries[fontStack]; - GlyphRequest& request = entry.ranges[range]; - - if (!res.noContent) { - std::vector<SDFGlyph> glyphs; - - try { - glyphs = parseGlyphPBF(range, *res.data); - } catch (...) { - observer->onGlyphsError(fontStack, range, std::current_exception()); - return; - } - - for (auto& glyph : glyphs) { - auto it = entry.glyphs.find(glyph.id); - if (it == entry.glyphs.end()) { - // Glyph doesn't exist yet. - entry.glyphs.emplace(glyph.id, GlyphValue { - std::move(glyph.bitmap), - std::move(glyph.metrics), - {}, {} - }); - } else if (it->second.metrics == glyph.metrics) { - if (it->second.bitmap != glyph.bitmap) { - // The actual bitmap was updated; this is unsupported. - Log::Warning(Event::Glyph, "Modified glyph changed bitmap represenation"); - } - // At least try to update it in case it's currently unused. - // If it is already used, we won't attempt to update the glyph atlas texture. - it->second.bitmap = std::move(glyph.bitmap); - } else { - // The metrics were updated; this is unsupported. - Log::Warning(Event::Glyph, "Modified glyph has different metrics"); - return; - } - } + for (const auto& bin : bins) { + const Glyph& glyph = **glyphs.at(bin.id); + + AlphaImage::copy(glyph.bitmap, + result.image, + { 0, 0 }, + { + bin.x + padding, + bin.y + padding + }, + glyph.bitmap.size); + + result.positions.emplace(glyph.id, + GlyphPosition { + Rect<uint16_t> { + static_cast<uint16_t>(bin.x), + static_cast<uint16_t>(bin.y), + static_cast<uint16_t>(bin.w), + static_cast<uint16_t>(bin.h) + }, + glyph.metrics + }); } - request.parsed = true; - - for (auto& pair : request.requestors) { - GlyphRequestor& requestor = *pair.first; - const std::shared_ptr<GlyphDependencies>& dependencies = pair.second; - if (dependencies.unique()) { - addGlyphs(requestor, *dependencies); - } - } - - request.requestors.clear(); - - observer->onGlyphsLoaded(fontStack, range); -} - -void GlyphAtlas::setObserver(GlyphAtlasObserver* observer_) { - observer = observer_ ? observer_ : &nullObserver; -} - -void GlyphAtlas::addGlyphs(GlyphRequestor& requestor, const GlyphDependencies& glyphDependencies) { - GlyphPositionMap glyphPositions; - - for (const auto& dependency : glyphDependencies) { - const FontStack& fontStack = dependency.first; - const GlyphIDs& glyphIDs = dependency.second; - - GlyphPositions& positions = glyphPositions[fontStack]; - Entry& entry = entries[fontStack]; - - for (const auto& glyphID : glyphIDs) { - // Make a glyph position entry even if we didn't get an SDF for the glyph. During layout, - // an empty optional is treated as "loaded but nothing to show", wheras no entry in the - // positions map means "not loaded yet". - optional<Glyph>& glyph = positions[glyphID]; - - auto it = entry.glyphs.find(glyphID); - if (it == entry.glyphs.end()) - continue; - - it->second.ids.insert(&requestor); - - glyph = Glyph { - addGlyph(it->second), - it->second.metrics - }; - } - } - - requestor.onGlyphsAvailable(glyphPositions); -} - -Rect<uint16_t> GlyphAtlas::addGlyph(GlyphValue& value) { - // The glyph is already in this texture. - if (value.rect) { - return *value.rect; - } - - // We don't need to add glyphs without a bitmap (e.g. whitespace). - if (!value.bitmap.valid()) { - return {}; - } - - // Add a 1px border around every image. - const uint32_t padding = 1; - const uint16_t width = value.bitmap.size.width + 2 * padding; - const uint16_t height = value.bitmap.size.height + 2 * padding; - - Rect<uint16_t> rect = bin.allocate(width, height); - if (rect.w == 0) { - Log::Error(Event::OpenGL, "glyph bitmap overflow"); - return {}; - } - - AlphaImage::copy(value.bitmap, image, { 0, 0 }, { rect.x + padding, rect.y + padding }, value.bitmap.size); - value.rect = rect; - dirty = true; - - return rect; -} - -void GlyphAtlas::removeGlyphValues(GlyphRequestor& requestor, std::map<GlyphID, GlyphValue>& values) { - for (auto& it : values) { - GlyphValue& value = it.second; - if (value.ids.erase(&requestor) && value.ids.empty() && value.rect) { - const Rect<uint16_t>& rect = *value.rect; - - // Clear out the bitmap. - uint8_t *target = image.data.get(); - for (uint32_t y = 0; y < rect.h; y++) { - uint32_t y1 = image.size.width * (rect.y + y) + rect.x; - for (uint32_t x = 0; x < rect.w; x++) { - target[y1 + x] = 0; - } - } - - bin.release(rect); - value.rect = {}; - } - } -} - -void GlyphAtlas::removePendingRanges(mbgl::GlyphRequestor& requestor, std::map<GlyphRange, GlyphRequest>& ranges) { - for (auto& range : ranges) { - range.second.requestors.erase(&requestor); - } -} - -void GlyphAtlas::removeGlyphs(GlyphRequestor& requestor) { - for (auto& entry : entries) { - removeGlyphValues(requestor, entry.second.glyphs); - removePendingRanges(requestor, entry.second.ranges); - } -} - -Size GlyphAtlas::getSize() const { - return image.size; -} - -void GlyphAtlas::upload(gl::Context& context, gl::TextureUnit unit) { - if (!texture) { - texture = context.createTexture(image, unit); - } else if (dirty) { - context.updateTexture(*texture, image, unit); - } - - dirty = false; -} - -void GlyphAtlas::bind(gl::Context& context, gl::TextureUnit unit) { - upload(context, unit); - context.bindTexture(*texture, unit, gl::TextureFilter::Linear); + return result; } } // namespace mbgl diff --git a/src/mbgl/text/glyph_atlas.hpp b/src/mbgl/text/glyph_atlas.hpp index cd6f57d57f..7a90085642 100644 --- a/src/mbgl/text/glyph_atlas.hpp +++ b/src/mbgl/text/glyph_atlas.hpp @@ -1,109 +1,24 @@ #pragma once #include <mbgl/text/glyph.hpp> -#include <mbgl/text/glyph_atlas_observer.hpp> -#include <mbgl/text/glyph_range.hpp> -#include <mbgl/geometry/binpack.hpp> -#include <mbgl/util/noncopyable.hpp> -#include <mbgl/util/optional.hpp> -#include <mbgl/util/font_stack.hpp> -#include <mbgl/util/image.hpp> -#include <mbgl/gl/texture.hpp> -#include <mbgl/gl/object.hpp> -#include <string> -#include <unordered_set> -#include <unordered_map> - -class GlyphAtlasTest; +#include <mapbox/shelf-pack.hpp> namespace mbgl { -class FileSource; -class AsyncRequest; -class Response; - -namespace gl { -class Context; -} // namespace gl - -class GlyphRequestor { -public: - virtual ~GlyphRequestor() = default; - virtual void onGlyphsAvailable(GlyphPositionMap) = 0; +struct GlyphPosition { + Rect<uint16_t> rect; + GlyphMetrics metrics; }; - -class GlyphAtlas : public util::noncopyable { -public: - GlyphAtlas(Size, FileSource&); - ~GlyphAtlas(); - - // Workers send a `getGlyphs` message to the main thread once they have determined - // which glyphs they will need. Invoking this method will increment reference - // counts for all the glyphs in `GlyphDependencies`. If all glyphs are already - // locally available, the observer will be notified that the glyphs are available - // immediately. Otherwise, a request on the FileSource is made, and when all glyphs - // are parsed and added to the atlas, the observer will be notified. - // Workers are given a copied 'GlyphPositions' map to use for placing their glyphs. - // The positions specified in this object are guaranteed to be - // valid for the lifetime of the tile. - void getGlyphs(GlyphRequestor&, GlyphDependencies); - void removeGlyphs(GlyphRequestor&); - - void setURL(const std::string& url) { - glyphURL = url; - } - - void setObserver(GlyphAtlasObserver*); - - // Binds the atlas texture to the GPU, and uploads data if it is out of date. - void bind(gl::Context&, gl::TextureUnit unit); - - // Uploads the texture to the GPU to be available when we need it. This is a lazy operation; - // the texture is only bound when the data is out of date (=dirty). - void upload(gl::Context&, gl::TextureUnit unit); - - Size getSize() const; -private: - FileSource& fileSource; - std::string glyphURL; +using GlyphPositions = std::map<GlyphID, GlyphPosition>; - struct GlyphValue { - AlphaImage bitmap; - GlyphMetrics metrics; - optional<Rect<uint16_t>> rect; - std::unordered_set<GlyphRequestor*> ids; - }; - - struct GlyphRequest { - bool parsed = false; - std::unique_ptr<AsyncRequest> req; - std::unordered_map<GlyphRequestor*, std::shared_ptr<GlyphDependencies>> requestors; - }; - - struct Entry { - std::map<GlyphRange, GlyphRequest> ranges; - std::map<GlyphID, GlyphValue> glyphs; - }; - - std::unordered_map<FontStack, Entry, FontStackHash> entries; - - GlyphRequest& requestRange(Entry&, const FontStack&, const GlyphRange&); - void processResponse(const Response&, const FontStack&, const GlyphRange&); - - void addGlyphs(GlyphRequestor&, const GlyphDependencies&); - Rect<uint16_t> addGlyph(GlyphValue&); - - void removeGlyphValues(GlyphRequestor&, std::map<GlyphID, GlyphValue>&); - void removePendingRanges(GlyphRequestor&, std::map<GlyphRange, GlyphRequest>&); - - GlyphAtlasObserver* observer = nullptr; - - BinPack<uint16_t> bin; +class GlyphAtlas { +public: AlphaImage image; - bool dirty; - mbgl::optional<gl::Texture> texture; + GlyphPositions positions; }; +GlyphAtlas makeGlyphAtlas(const Glyphs&); + } // namespace mbgl diff --git a/src/mbgl/text/glyph_manager.cpp b/src/mbgl/text/glyph_manager.cpp new file mode 100644 index 0000000000..916d39ae62 --- /dev/null +++ b/src/mbgl/text/glyph_manager.cpp @@ -0,0 +1,145 @@ +#include <mbgl/text/glyph_manager.hpp> +#include <mbgl/text/glyph_manager_observer.hpp> +#include <mbgl/text/glyph_pbf.hpp> +#include <mbgl/storage/file_source.hpp> +#include <mbgl/storage/resource.hpp> +#include <mbgl/storage/response.hpp> + +namespace mbgl { + +static GlyphManagerObserver nullObserver; + +GlyphManager::GlyphManager(FileSource& fileSource_) + : fileSource(fileSource_), + observer(&nullObserver) { +} + +GlyphManager::~GlyphManager() = default; + +void GlyphManager::getGlyphs(GlyphRequestor& requestor, GlyphDependencies glyphDependencies) { + auto dependencies = std::make_shared<GlyphDependencies>(std::move(glyphDependencies)); + + // Figure out which glyph ranges need to be fetched. For each range that does need to + // be fetched, record an entry mapping the requestor to a shared pointer containing the + // dependencies. When the shared pointer becomes unique, we know that all the dependencies + // for that requestor have been fetched, and can notify it of completion. + for (const auto& dependency : *dependencies) { + const FontStack& fontStack = dependency.first; + Entry& entry = entries[fontStack]; + + const GlyphIDs& glyphIDs = dependency.second; + GlyphRangeSet ranges; + for (const auto& glyphID : glyphIDs) { + ranges.insert(getGlyphRange(glyphID)); + } + + for (const auto& range : ranges) { + auto it = entry.ranges.find(range); + if (it == entry.ranges.end() || !it->second.parsed) { + GlyphRequest& request = requestRange(entry, fontStack, range); + request.requestors[&requestor] = dependencies; + } + } + } + + // If the shared dependencies pointer is already unique, then all dependent glyph ranges + // have already been loaded. Send a notification immediately. + if (dependencies.unique()) { + notify(requestor, *dependencies); + } +} + +GlyphManager::GlyphRequest& GlyphManager::requestRange(Entry& entry, const FontStack& fontStack, const GlyphRange& range) { + GlyphRequest& request = entry.ranges[range]; + + if (request.req) { + return request; + } + + request.req = fileSource.request(Resource::glyphs(glyphURL, fontStack, range), [this, fontStack, range](Response res) { + processResponse(res, fontStack, range); + }); + + return request; +} + +void GlyphManager::processResponse(const Response& res, const FontStack& fontStack, const GlyphRange& range) { + if (res.error) { + observer->onGlyphsError(fontStack, range, std::make_exception_ptr(std::runtime_error(res.error->message))); + return; + } + + if (res.notModified) { + return; + } + + Entry& entry = entries[fontStack]; + GlyphRequest& request = entry.ranges[range]; + + if (!res.noContent) { + std::vector<Glyph> glyphs; + + try { + glyphs = parseGlyphPBF(range, *res.data); + } catch (...) { + observer->onGlyphsError(fontStack, range, std::current_exception()); + return; + } + + for (auto& glyph : glyphs) { + entry.glyphs.erase(glyph.id); + entry.glyphs.emplace(glyph.id, makeMutable<Glyph>(std::move(glyph))); + } + } + + request.parsed = true; + + for (auto& pair : request.requestors) { + GlyphRequestor& requestor = *pair.first; + const std::shared_ptr<GlyphDependencies>& dependencies = pair.second; + if (dependencies.unique()) { + notify(requestor, *dependencies); + } + } + + request.requestors.clear(); + + observer->onGlyphsLoaded(fontStack, range); +} + +void GlyphManager::setObserver(GlyphManagerObserver* observer_) { + observer = observer_ ? observer_ : &nullObserver; +} + +void GlyphManager::notify(GlyphRequestor& requestor, const GlyphDependencies& glyphDependencies) { + GlyphMap response; + + for (const auto& dependency : glyphDependencies) { + const FontStack& fontStack = dependency.first; + const GlyphIDs& glyphIDs = dependency.second; + + Glyphs& glyphs = response[fontStack]; + Entry& entry = entries[fontStack]; + + for (const auto& glyphID : glyphIDs) { + auto it = entry.glyphs.find(glyphID); + if (it != entry.glyphs.end()) { + glyphs.emplace(*it); + } else { + glyphs.emplace(glyphID, std::experimental::nullopt); + } + } + } + + requestor.onGlyphsAvailable(response); +} + +void GlyphManager::removeRequestor(GlyphRequestor& requestor) { + for (auto& entry : entries) { + for (auto& range : entry.second.ranges) { + range.second.requestors.erase(&requestor); + } + } +} + +} // namespace mbgl diff --git a/src/mbgl/text/glyph_manager.hpp b/src/mbgl/text/glyph_manager.hpp new file mode 100644 index 0000000000..00df079462 --- /dev/null +++ b/src/mbgl/text/glyph_manager.hpp @@ -0,0 +1,68 @@ +#pragma once + +#include <mbgl/text/glyph.hpp> +#include <mbgl/text/glyph_manager_observer.hpp> +#include <mbgl/text/glyph_range.hpp> +#include <mbgl/util/noncopyable.hpp> +#include <mbgl/util/font_stack.hpp> +#include <mbgl/util/immutable.hpp> + +#include <string> +#include <unordered_map> + +namespace mbgl { + +class FileSource; +class AsyncRequest; +class Response; + +class GlyphRequestor { +public: + virtual ~GlyphRequestor() = default; + virtual void onGlyphsAvailable(GlyphMap) = 0; +}; + +class GlyphManager : public util::noncopyable { +public: + GlyphManager(FileSource&); + ~GlyphManager(); + + // Workers send a `getGlyphs` message to the main thread once they have determined + // their `GlyphDependencies`. If all glyphs are already locally available, GlyphManager + // will provide them to the requestor immediately. Otherwise, it makes a request on the + // FileSource is made for each range neeed, and notifies the observer when all are + // complete. + void getGlyphs(GlyphRequestor&, GlyphDependencies); + void removeRequestor(GlyphRequestor&); + + void setURL(const std::string& url) { + glyphURL = url; + } + + void setObserver(GlyphManagerObserver*); + +private: + FileSource& fileSource; + std::string glyphURL; + + struct GlyphRequest { + bool parsed = false; + std::unique_ptr<AsyncRequest> req; + std::unordered_map<GlyphRequestor*, std::shared_ptr<GlyphDependencies>> requestors; + }; + + struct Entry { + std::map<GlyphRange, GlyphRequest> ranges; + std::map<GlyphID, Immutable<Glyph>> glyphs; + }; + + std::unordered_map<FontStack, Entry, FontStackHash> entries; + + GlyphRequest& requestRange(Entry&, const FontStack&, const GlyphRange&); + void processResponse(const Response&, const FontStack&, const GlyphRange&); + void notify(GlyphRequestor&, const GlyphDependencies&); + + GlyphManagerObserver* observer = nullptr; +}; + +} // namespace mbgl diff --git a/src/mbgl/text/glyph_atlas_observer.hpp b/src/mbgl/text/glyph_manager_observer.hpp index 9841017117..b8678e060a 100644 --- a/src/mbgl/text/glyph_atlas_observer.hpp +++ b/src/mbgl/text/glyph_manager_observer.hpp @@ -8,9 +8,9 @@ namespace mbgl { -class GlyphAtlasObserver { +class GlyphManagerObserver { public: - virtual ~GlyphAtlasObserver() = default; + virtual ~GlyphManagerObserver() = default; virtual void onGlyphsLoaded(const FontStack&, const GlyphRange&) {} virtual void onGlyphsError(const FontStack&, const GlyphRange&, std::exception_ptr) {} diff --git a/src/mbgl/text/glyph_pbf.cpp b/src/mbgl/text/glyph_pbf.cpp index 033f50fe9c..cfaf803f75 100644 --- a/src/mbgl/text/glyph_pbf.cpp +++ b/src/mbgl/text/glyph_pbf.cpp @@ -4,8 +4,8 @@ namespace mbgl { -std::vector<SDFGlyph> parseGlyphPBF(const GlyphRange& glyphRange, const std::string& data) { - std::vector<SDFGlyph> result; +std::vector<Glyph> parseGlyphPBF(const GlyphRange& glyphRange, const std::string& data) { + std::vector<Glyph> result; result.reserve(256); protozero::pbf_reader glyphs_pbf(data); @@ -15,7 +15,7 @@ std::vector<SDFGlyph> parseGlyphPBF(const GlyphRange& glyphRange, const std::str while (fontstack_pbf.next(3)) { auto glyph_pbf = fontstack_pbf.get_message(); - SDFGlyph glyph; + Glyph glyph; protozero::data_view glyphData; bool hasID = false, hasWidth = false, hasHeight = false, hasLeft = false, @@ -73,8 +73,8 @@ std::vector<SDFGlyph> parseGlyphPBF(const GlyphRange& glyphRange, const std::str // with the implicit border size, otherwise we expect there to be no bitmap at all. if (glyph.metrics.width && glyph.metrics.height) { const Size size { - glyph.metrics.width + 2 * SDFGlyph::borderSize, - glyph.metrics.height + 2 * SDFGlyph::borderSize + glyph.metrics.width + 2 * Glyph::borderSize, + glyph.metrics.height + 2 * Glyph::borderSize }; if (size.area() != glyphData.size()) { diff --git a/src/mbgl/text/glyph_pbf.hpp b/src/mbgl/text/glyph_pbf.hpp index 162aeed93a..28a28b4114 100644 --- a/src/mbgl/text/glyph_pbf.hpp +++ b/src/mbgl/text/glyph_pbf.hpp @@ -2,28 +2,12 @@ #include <mbgl/text/glyph.hpp> #include <mbgl/text/glyph_range.hpp> -#include <mbgl/util/image.hpp> #include <string> #include <vector> namespace mbgl { -class SDFGlyph { -public: - // We're using this value throughout the Mapbox GL ecosystem. If this is different, the glyphs - // also need to be reencoded. - static constexpr const uint8_t borderSize = 3; - - GlyphID id = 0; - - // A signed distance field of the glyph with a border (see above). - AlphaImage bitmap; - - // Glyph metrics - GlyphMetrics metrics; -}; - -std::vector<SDFGlyph> parseGlyphPBF(const GlyphRange&, const std::string& data); +std::vector<Glyph> parseGlyphPBF(const GlyphRange&, const std::string& data); } // namespace mbgl diff --git a/src/mbgl/text/quads.cpp b/src/mbgl/text/quads.cpp index 33b94d7114..ad57342b82 100644 --- a/src/mbgl/text/quads.cpp +++ b/src/mbgl/text/quads.cpp @@ -315,10 +315,10 @@ SymbolQuads getGlyphQuads(Anchor& anchor, for (const PositionedGlyph &positionedGlyph: shapedText.positionedGlyphs) { auto face_it = face.find(positionedGlyph.glyph); - if (face_it == face.end() || !face_it->second || !(*face_it->second).rect.hasArea()) + if (face_it == face.end()) continue; - const Glyph& glyph = *face_it->second; + const GlyphPosition& glyph = face_it->second; const Rect<uint16_t>& rect = glyph.rect; const float centerX = (positionedGlyph.x + glyph.metrics.advance / 2.0f) * boxScale; diff --git a/src/mbgl/text/quads.hpp b/src/mbgl/text/quads.hpp index 38dad95243..89df423529 100644 --- a/src/mbgl/text/quads.hpp +++ b/src/mbgl/text/quads.hpp @@ -1,6 +1,6 @@ #pragma once -#include <mbgl/text/glyph.hpp> +#include <mbgl/text/glyph_atlas.hpp> #include <mbgl/style/types.hpp> #include <mbgl/style/layers/symbol_layer_properties.hpp> #include <mbgl/tile/geometry_tile_data.hpp> diff --git a/src/mbgl/text/shaping.cpp b/src/mbgl/text/shaping.cpp index f9f90627d4..0ef347ba0b 100644 --- a/src/mbgl/text/shaping.cpp +++ b/src/mbgl/text/shaping.cpp @@ -42,7 +42,7 @@ void align(Shaping& shaping, // justify left = 0, right = 1, center = .5 void justifyLine(std::vector<PositionedGlyph>& positionedGlyphs, - const GlyphPositions& glyphs, + const Glyphs& glyphs, std::size_t start, std::size_t end, float justify) { @@ -53,7 +53,7 @@ void justifyLine(std::vector<PositionedGlyph>& positionedGlyphs, PositionedGlyph& glyph = positionedGlyphs[end]; auto it = glyphs.find(glyph.glyph); if (it != glyphs.end() && it->second) { - const uint32_t lastAdvance = it->second->metrics.advance; + const uint32_t lastAdvance = (*it->second)->metrics.advance; const float lineIndent = float(glyph.x + lastAdvance) * justify; for (std::size_t j = start; j <= end; j++) { @@ -65,13 +65,13 @@ void justifyLine(std::vector<PositionedGlyph>& positionedGlyphs, float determineAverageLineWidth(const std::u16string& logicalInput, const float spacing, float maxWidth, - const GlyphPositions& glyphs) { + const Glyphs& glyphs) { float totalWidth = 0; for (char16_t chr : logicalInput) { auto it = glyphs.find(chr); if (it != glyphs.end() && it->second) { - totalWidth += it->second->metrics.advance + spacing; + totalWidth += (*it->second)->metrics.advance + spacing; } } @@ -164,7 +164,7 @@ std::set<std::size_t> determineLineBreaks(const std::u16string& logicalInput, const float spacing, float maxWidth, const WritingModeType writingMode, - const GlyphPositions& glyphs) { + const Glyphs& glyphs) { if (!maxWidth || writingMode != WritingModeType::Horizontal) { return {}; } @@ -182,7 +182,7 @@ std::set<std::size_t> determineLineBreaks(const std::u16string& logicalInput, const char16_t codePoint = logicalInput[i]; auto it = glyphs.find(codePoint); if (it != glyphs.end() && it->second && !boost::algorithm::is_any_of(u" \t\n\v\f\r")(codePoint)) { - currentX += it->second->metrics.advance + spacing; + currentX += (*it->second)->metrics.advance + spacing; } // Ideographic characters, spaces, and word-breaking punctuation that often appear without @@ -208,7 +208,7 @@ void shapeLines(Shaping& shaping, const Point<float>& translate, const float verticalHeight, const WritingModeType writingMode, - const GlyphPositions& glyphs) { + const Glyphs& glyphs) { // the y offset *should* be part of the font metadata const int32_t yOffset = -17; @@ -234,7 +234,7 @@ void shapeLines(Shaping& shaping, continue; } - const Glyph& glyph = *it->second; + const Glyph& glyph = **it->second; if (writingMode == WritingModeType::Horizontal || !util::i18n::hasUprightVerticalOrientation(chr)) { shaping.positionedGlyphs.emplace_back(chr, x, y, 0); @@ -280,7 +280,7 @@ const Shaping getShaping(const std::u16string& logicalInput, const float verticalHeight, const WritingModeType writingMode, BiDi& bidi, - const GlyphPositions& glyphs) { + const Glyphs& glyphs) { Shaping shaping(translate.x, translate.y, writingMode); std::vector<std::u16string> reorderedLines = diff --git a/src/mbgl/text/shaping.hpp b/src/mbgl/text/shaping.hpp index bf81b9213c..1984b14e1d 100644 --- a/src/mbgl/text/shaping.hpp +++ b/src/mbgl/text/shaping.hpp @@ -2,7 +2,6 @@ #include <mbgl/text/glyph.hpp> #include <mbgl/sprite/sprite_atlas.hpp> -#include <mbgl/style/image.hpp> namespace mbgl { @@ -54,6 +53,6 @@ const Shaping getShaping(const std::u16string& string, float verticalHeight, const WritingModeType, BiDi& bidi, - const GlyphPositions& glyphs); + const Glyphs& glyphs); } // namespace mbgl |