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 | |
parent | b201a7900f989af432aaea500a0e6c5ea5bbba53 (diff) | |
download | qtlocation-mapboxgl-92252849c1a2ddf7887d1908841fa3c90dd59766.tar.gz |
[core] Per-bucket glyph atlases
Diffstat (limited to 'src')
28 files changed, 363 insertions, 430 deletions
diff --git a/src/mbgl/gl/context.cpp b/src/mbgl/gl/context.cpp index 348e0a0e77..1b4d6fbcb7 100644 --- a/src/mbgl/gl/context.cpp +++ b/src/mbgl/gl/context.cpp @@ -397,6 +397,7 @@ Context::createFramebuffer(const Texture& color, UniqueTexture Context::createTexture(const Size size, const void* data, TextureFormat format, TextureUnit unit) { auto obj = createTexture(); + pixelStoreUnpack = { 1 }; updateTexture(obj, size, data, format, unit); // We are using clamp to edge here since OpenGL ES doesn't allow GL_REPEAT on NPOT textures. // We use those when the pixelRatio isn't a power of two, e.g. on iPhone 6 Plus. diff --git a/src/mbgl/layout/symbol_instance.hpp b/src/mbgl/layout/symbol_instance.hpp index eadbf67475..6a5d0c7cf3 100644 --- a/src/mbgl/layout/symbol_instance.hpp +++ b/src/mbgl/layout/symbol_instance.hpp @@ -1,7 +1,7 @@ #pragma once #include <mbgl/text/quads.hpp> -#include <mbgl/text/glyph.hpp> +#include <mbgl/text/glyph_atlas.hpp> #include <mbgl/text/collision_feature.hpp> #include <mbgl/style/layers/symbol_layer_properties.hpp> diff --git a/src/mbgl/layout/symbol_layout.cpp b/src/mbgl/layout/symbol_layout.cpp index b1cfc113fb..6d769e43c4 100644 --- a/src/mbgl/layout/symbol_layout.cpp +++ b/src/mbgl/layout/symbol_layout.cpp @@ -175,7 +175,7 @@ bool SymbolLayout::hasSymbolInstances() const { return !symbolInstances.empty(); } -void SymbolLayout::prepare(const GlyphPositionMap& glyphs, const IconMap& icons) { +void SymbolLayout::prepare(const GlyphMap& glyphs, const IconMap& icons) { float horizontalAlign = 0.5; float verticalAlign = 0.5; @@ -217,17 +217,20 @@ void SymbolLayout::prepare(const GlyphPositionMap& glyphs, const IconMap& icons) layout.get<TextJustify>() == TextJustifyType::Left ? 0 : 0.5; - const bool textAlongLine = layout.get<TextRotationAlignment>() == AlignmentType::Map && layout.get<SymbolPlacement>() == SymbolPlacementType::Line; + auto glyphPositionsIt = glyphs.find(layout.get<TextFont>()); + if (glyphPositionsIt != glyphs.end()) { + glyphAtlas = makeGlyphAtlas(glyphPositionsIt->second); + } + for (auto it = features.begin(); it != features.end(); ++it) { auto& feature = *it; if (feature.geometry.empty()) continue; std::pair<Shaping, Shaping> shapedTextOrientations; optional<PositionedIcon> shapedIcon; - GlyphPositions face; // if feature has text, shape the text if (feature.text) { @@ -281,8 +284,7 @@ void SymbolLayout::prepare(const GlyphPositionMap& glyphs, const IconMap& icons) // if either shapedText or icon position is present, add the feature if (shapedTextOrientations.first || shapedIcon) { - auto glyphPositionsIt = glyphs.find(layout.get<TextFont>()); - addFeature(std::distance(features.begin(), it), feature, shapedTextOrientations, shapedIcon, glyphPositionsIt == glyphs.end() ? GlyphPositions() : glyphPositionsIt->second); + addFeature(std::distance(features.begin(), it), feature, shapedTextOrientations, shapedIcon); } feature.geometry.clear(); @@ -294,8 +296,7 @@ void SymbolLayout::prepare(const GlyphPositionMap& glyphs, const IconMap& icons) void SymbolLayout::addFeature(const std::size_t index, const SymbolFeature& feature, const std::pair<Shaping, Shaping>& shapedTextOrientations, - optional<PositionedIcon> shapedIcon, - const GlyphPositions& glyphs) { + optional<PositionedIcon> shapedIcon) { const float minScale = 0.5f; const float glyphSize = 24.0f; @@ -352,7 +353,7 @@ void SymbolLayout::addFeature(const std::size_t index, addToBuffers, symbolInstances.size(), textBoxScale, textPadding, textPlacement, iconBoxScale, iconPadding, iconPlacement, - glyphs, indexedFeature, index); + glyphAtlas.positions, indexedFeature, index); }; const auto& type = feature.getType(); @@ -426,6 +427,8 @@ bool SymbolLayout::anchorIsTooClose(const std::u16string& text, const float repe std::unique_ptr<SymbolBucket> SymbolLayout::place(CollisionTile& collisionTile) { auto bucket = std::make_unique<SymbolBucket>(layout, layerPaintProperties, textSize, iconSize, zoom, sdfIcons, iconsNeedLinear); + bucket->text.atlasImage = glyphAtlas.image.clone(); + // Calculate which labels can be shown and when they can be shown and // create the bufers used for rendering. diff --git a/src/mbgl/layout/symbol_layout.hpp b/src/mbgl/layout/symbol_layout.hpp index 770820542d..e947ee354b 100644 --- a/src/mbgl/layout/symbol_layout.hpp +++ b/src/mbgl/layout/symbol_layout.hpp @@ -33,7 +33,7 @@ public: IconDependencies&, GlyphDependencies&); - void prepare(const GlyphPositionMap& glyphs, const IconMap& icons); + void prepare(const GlyphMap& glyphs, const IconMap& icons); std::unique_ptr<SymbolBucket> place(CollisionTile&); @@ -53,8 +53,7 @@ private: void addFeature(const size_t, const SymbolFeature&, const std::pair<Shaping, Shaping>& shapedTextOrientations, - optional<PositionedIcon> shapedIcon, - const GlyphPositions& face); + optional<PositionedIcon> shapedIcon); bool anchorIsTooClose(const std::u16string& text, const float repeatDistance, const Anchor&); std::map<std::u16string, std::vector<Anchor>> compareText; @@ -94,6 +93,8 @@ private: std::vector<SymbolInstance> symbolInstances; std::vector<SymbolFeature> features; + GlyphAtlas glyphAtlas; + BiDi bidi; // Consider moving this up to geometry tile worker to reduce reinstantiation costs; use of BiDi/ubiditransform object must be constrained to one thread }; diff --git a/src/mbgl/renderer/buckets/symbol_bucket.cpp b/src/mbgl/renderer/buckets/symbol_bucket.cpp index bc4e5f57cb..fceffaa5f4 100644 --- a/src/mbgl/renderer/buckets/symbol_bucket.cpp +++ b/src/mbgl/renderer/buckets/symbol_bucket.cpp @@ -3,6 +3,7 @@ #include <mbgl/renderer/layers/render_symbol_layer.hpp> #include <mbgl/renderer/bucket_parameters.hpp> #include <mbgl/style/layers/symbol_layer_impl.hpp> +#include <mbgl/text/glyph_atlas.hpp> namespace mbgl { @@ -38,6 +39,7 @@ void SymbolBucket::upload(gl::Context& context) { if (hasTextData()) { text.vertexBuffer = context.createVertexBuffer(std::move(text.vertices)); text.indexBuffer = context.createIndexBuffer(std::move(text.triangles)); + text.atlasTexture = context.createTexture(std::move(text.atlasImage), 0); textSizeBinder->upload(context); } diff --git a/src/mbgl/renderer/buckets/symbol_bucket.hpp b/src/mbgl/renderer/buckets/symbol_bucket.hpp index 652f2ea8e3..76b3467a9a 100644 --- a/src/mbgl/renderer/buckets/symbol_bucket.hpp +++ b/src/mbgl/renderer/buckets/symbol_bucket.hpp @@ -46,9 +46,11 @@ public: gl::VertexVector<SymbolLayoutVertex> vertices; gl::IndexVector<gl::Triangles> triangles; gl::SegmentVector<SymbolTextAttributes> segments; + AlphaImage atlasImage; optional<gl::VertexBuffer<SymbolLayoutVertex>> vertexBuffer; optional<gl::IndexBuffer<gl::Triangles>> indexBuffer; + optional<gl::Texture> atlasTexture; } text; std::unique_ptr<SymbolSizeBinder> iconSizeBinder; diff --git a/src/mbgl/renderer/painter.cpp b/src/mbgl/renderer/painter.cpp index e04d25d06a..6f0ddf8467 100644 --- a/src/mbgl/renderer/painter.cpp +++ b/src/mbgl/renderer/painter.cpp @@ -23,7 +23,6 @@ #include <mbgl/sprite/sprite_atlas.hpp> #include <mbgl/geometry/line_atlas.hpp> -#include <mbgl/text/glyph_atlas.hpp> #include <mbgl/programs/program_parameters.hpp> #include <mbgl/programs/programs.hpp> @@ -138,7 +137,6 @@ void Painter::render(RenderStyle& style, const FrameData& frame_, View& view) { view }; - glyphAtlas = style.glyphAtlas.get(); spriteAtlas = style.spriteAtlas.get(); lineAtlas = style.lineAtlas.get(); @@ -172,7 +170,6 @@ void Painter::render(RenderStyle& style, const FrameData& frame_, View& view) { spriteAtlas->upload(context, 0); lineAtlas->upload(context, 0); - glyphAtlas->upload(context, 0); frameHistory.upload(context, 0); } diff --git a/src/mbgl/renderer/painter.hpp b/src/mbgl/renderer/painter.hpp index 75a3ad5f89..c8b61c6bf8 100644 --- a/src/mbgl/renderer/painter.hpp +++ b/src/mbgl/renderer/painter.hpp @@ -34,7 +34,6 @@ class RenderStyle; class RenderTile; class SpriteAtlas; class View; -class GlyphAtlas; class LineAtlas; struct FrameData; class Tile; @@ -153,7 +152,6 @@ public: const float depthEpsilon = 1.0f / (1 << 16); SpriteAtlas* spriteAtlas = nullptr; - GlyphAtlas* glyphAtlas = nullptr; LineAtlas* lineAtlas = nullptr; optional<OffscreenTexture> extrusionTexture; diff --git a/src/mbgl/renderer/painters/painter_symbol.cpp b/src/mbgl/renderer/painters/painter_symbol.cpp index 563489987c..5a5264d178 100644 --- a/src/mbgl/renderer/painters/painter_symbol.cpp +++ b/src/mbgl/renderer/painters/painter_symbol.cpp @@ -105,12 +105,12 @@ void Painter::renderSymbol(PaintParameters& parameters, } if (bucket.hasTextData()) { - glyphAtlas->bind(context, 0); + context.bindTexture(*bucket.text.atlasTexture, 0, gl::TextureFilter::Linear); auto values = layer.textPropertyValues(layout); auto paintPropertyValues = layer.textPaintProperties(); - const Size texsize = glyphAtlas->getSize(); + const Size texsize = bucket.text.atlasTexture->size; if (values.hasHalo) { draw(parameters.programs.symbolGlyph, diff --git a/src/mbgl/renderer/render_style.cpp b/src/mbgl/renderer/render_style.cpp index 0998722f75..845bdbe63b 100644 --- a/src/mbgl/renderer/render_style.cpp +++ b/src/mbgl/renderer/render_style.cpp @@ -21,7 +21,7 @@ #include <mbgl/style/transition_options.hpp> #include <mbgl/sprite/sprite_atlas.hpp> #include <mbgl/sprite/sprite_loader.hpp> -#include <mbgl/text/glyph_atlas.hpp> +#include <mbgl/text/glyph_manager.hpp> #include <mbgl/geometry/line_atlas.hpp> #include <mbgl/sprite/sprite_atlas.hpp> #include <mbgl/map/query.hpp> @@ -38,7 +38,7 @@ RenderStyleObserver nullObserver; RenderStyle::RenderStyle(Scheduler& scheduler_, FileSource& fileSource_) : scheduler(scheduler_), fileSource(fileSource_), - glyphAtlas(std::make_unique<GlyphAtlas>(Size{ 2048, 2048 }, fileSource)), + glyphManager(std::make_unique<GlyphManager>(fileSource)), spriteAtlas(std::make_unique<SpriteAtlas>()), lineAtlas(std::make_unique<LineAtlas>(Size{ 256, 512 })), imageImpls(makeMutable<std::vector<Immutable<style::Image::Impl>>>()), @@ -46,7 +46,7 @@ RenderStyle::RenderStyle(Scheduler& scheduler_, FileSource& fileSource_) layerImpls(makeMutable<std::vector<Immutable<style::Layer::Impl>>>()), renderLight(makeMutable<Light::Impl>()), observer(&nullObserver) { - glyphAtlas->setObserver(this); + glyphManager->setObserver(this); } RenderStyle::~RenderStyle() = default; @@ -101,10 +101,10 @@ void RenderStyle::update(const UpdateParameters& parameters) { parameters.mode, parameters.annotationManager, *spriteAtlas, - *glyphAtlas + *glyphManager }; - glyphAtlas->setURL(parameters.glyphURL); + glyphManager->setURL(parameters.glyphURL); // Update light. const bool lightChanged = renderLight.impl != parameters.light; diff --git a/src/mbgl/renderer/render_style.hpp b/src/mbgl/renderer/render_style.hpp index ff222f2569..26aebda3ab 100644 --- a/src/mbgl/renderer/render_style.hpp +++ b/src/mbgl/renderer/render_style.hpp @@ -5,7 +5,7 @@ #include <mbgl/renderer/render_source_observer.hpp> #include <mbgl/renderer/render_layer.hpp> #include <mbgl/renderer/render_light.hpp> -#include <mbgl/text/glyph_atlas_observer.hpp> +#include <mbgl/text/glyph_manager_observer.hpp> #include <mbgl/map/zoom_history.hpp> #include <mbgl/map/mode.hpp> @@ -16,7 +16,7 @@ namespace mbgl { class FileSource; -class GlyphAtlas; +class GlyphManager; class SpriteAtlas; class LineAtlas; class RenderData; @@ -32,7 +32,7 @@ class Source; class Layer; } // namespace style -class RenderStyle : public GlyphAtlasObserver, +class RenderStyle : public GlyphManagerObserver, public RenderSourceObserver { public: RenderStyle(Scheduler&, FileSource&); @@ -66,7 +66,7 @@ public: Scheduler& scheduler; FileSource& fileSource; - std::unique_ptr<GlyphAtlas> glyphAtlas; + std::unique_ptr<GlyphManager> glyphManager; std::unique_ptr<SpriteAtlas> spriteAtlas; std::unique_ptr<LineAtlas> lineAtlas; @@ -79,7 +79,7 @@ private: std::unordered_map<std::string, std::unique_ptr<RenderLayer>> renderLayers; RenderLight renderLight; - // GlyphAtlasObserver implementation. + // GlyphManagerObserver implementation. void onGlyphsError(const FontStack&, const GlyphRange&, std::exception_ptr) override; // RenderSourceObserver implementation. diff --git a/src/mbgl/renderer/tile_parameters.hpp b/src/mbgl/renderer/tile_parameters.hpp index b4a84ec6c8..88def11585 100644 --- a/src/mbgl/renderer/tile_parameters.hpp +++ b/src/mbgl/renderer/tile_parameters.hpp @@ -9,7 +9,7 @@ class Scheduler; class FileSource; class AnnotationManager; class SpriteAtlas; -class GlyphAtlas; +class GlyphManager; class TileParameters { public: @@ -21,7 +21,7 @@ public: const MapMode mode; AnnotationManager& annotationManager; SpriteAtlas& spriteAtlas; - GlyphAtlas& glyphAtlas; + GlyphManager& glyphManager; }; } // namespace mbgl 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 diff --git a/src/mbgl/tile/geometry_tile.cpp b/src/mbgl/tile/geometry_tile.cpp index c35fe42f6a..13034910a4 100644 --- a/src/mbgl/tile/geometry_tile.cpp +++ b/src/mbgl/tile/geometry_tile.cpp @@ -38,13 +38,13 @@ GeometryTile::GeometryTile(const OverscaledTileID& id_, obsolete, parameters.mode, parameters.pixelRatio), - glyphAtlas(parameters.glyphAtlas), + glyphManager(parameters.glyphManager), spriteAtlas(parameters.spriteAtlas), placementThrottler(Milliseconds(300), [this] { invokePlacement(); }) { } GeometryTile::~GeometryTile() { - glyphAtlas.removeGlyphs(*this); + glyphManager.removeRequestor(*this); spriteAtlas.removeRequestor(*this); markObsolete(); } @@ -145,12 +145,12 @@ void GeometryTile::onError(std::exception_ptr err) { observer->onTileError(*this, err); } -void GeometryTile::onGlyphsAvailable(GlyphPositionMap glyphPositions) { - worker.invoke(&GeometryTileWorker::onGlyphsAvailable, std::move(glyphPositions)); +void GeometryTile::onGlyphsAvailable(GlyphMap glyphs) { + worker.invoke(&GeometryTileWorker::onGlyphsAvailable, std::move(glyphs)); } void GeometryTile::getGlyphs(GlyphDependencies glyphDependencies) { - glyphAtlas.getGlyphs(*this, std::move(glyphDependencies)); + glyphManager.getGlyphs(*this, std::move(glyphDependencies)); } void GeometryTile::onIconsAvailable(IconMap icons) { diff --git a/src/mbgl/tile/geometry_tile.hpp b/src/mbgl/tile/geometry_tile.hpp index e92d2f4975..659f4f7e9f 100644 --- a/src/mbgl/tile/geometry_tile.hpp +++ b/src/mbgl/tile/geometry_tile.hpp @@ -3,7 +3,7 @@ #include <mbgl/sprite/sprite_atlas.hpp> #include <mbgl/tile/tile.hpp> #include <mbgl/tile/geometry_tile_worker.hpp> -#include <mbgl/text/glyph_atlas.hpp> +#include <mbgl/text/glyph_manager.hpp> #include <mbgl/text/placement_config.hpp> #include <mbgl/util/feature.hpp> #include <mbgl/util/throttler.hpp> @@ -38,7 +38,7 @@ public: void setPlacementConfig(const PlacementConfig&) override; void setLayers(const std::vector<Immutable<style::Layer::Impl>>&) override; - void onGlyphsAvailable(GlyphPositionMap) override; + void onGlyphsAvailable(GlyphMap) override; void onIconsAvailable(IconMap) override; void getGlyphs(GlyphDependencies); @@ -96,7 +96,7 @@ private: std::shared_ptr<Mailbox> mailbox; Actor<GeometryTileWorker> worker; - GlyphAtlas& glyphAtlas; + GlyphManager& glyphManager; SpriteAtlas& spriteAtlas; uint64_t correlationID = 0; diff --git a/src/mbgl/tile/geometry_tile_worker.cpp b/src/mbgl/tile/geometry_tile_worker.cpp index 3fd6bb47f0..8eaea161d2 100644 --- a/src/mbgl/tile/geometry_tile_worker.cpp +++ b/src/mbgl/tile/geometry_tile_worker.cpp @@ -197,37 +197,37 @@ void GeometryTileWorker::coalesce() { self.invoke(&GeometryTileWorker::coalesced); } -void GeometryTileWorker::onGlyphsAvailable(GlyphPositionMap newGlyphPositions) { - for (auto& newFontGlyphs : newGlyphPositions) { +void GeometryTileWorker::onGlyphsAvailable(GlyphMap newGlyphMap) { + for (auto& newFontGlyphs : newGlyphMap) { const FontStack& fontStack = newFontGlyphs.first; - GlyphPositions& newPositions = newFontGlyphs.second; + Glyphs& newGlyphs = newFontGlyphs.second; - GlyphPositions& positions = glyphPositions[fontStack]; + Glyphs& glyphs = glyphMap[fontStack]; GlyphIDs& pendingGlyphIDs = pendingGlyphDependencies[fontStack]; - for (auto& newPosition : newPositions) { - const GlyphID& glyphID = newPosition.first; - optional<Glyph>& glyph = newPosition.second; + for (auto& newGlyph : newGlyphs) { + const GlyphID& glyphID = newGlyph.first; + optional<Immutable<Glyph>>& glyph = newGlyph.second; if (pendingGlyphIDs.erase(glyphID)) { - positions.emplace(glyphID, std::move(glyph)); + glyphs.emplace(glyphID, std::move(glyph)); } } } symbolDependenciesChanged(); } -void GeometryTileWorker::onIconsAvailable(IconMap newIcons) { - icons = std::move(newIcons); +void GeometryTileWorker::onIconsAvailable(IconMap newIconMap) { + iconMap = std::move(newIconMap); pendingIconDependencies.clear(); symbolDependenciesChanged(); } void GeometryTileWorker::requestNewGlyphs(const GlyphDependencies& glyphDependencies) { for (auto& fontDependencies : glyphDependencies) { - auto fontGlyphs = glyphPositions.find(fontDependencies.first); + auto fontGlyphs = glyphMap.find(fontDependencies.first); for (auto glyphID : fontDependencies.second) { - if (fontGlyphs == glyphPositions.end() || fontGlyphs->second.find(glyphID) == fontGlyphs->second.end()) { + if (fontGlyphs == glyphMap.end() || fontGlyphs->second.find(glyphID) == fontGlyphs->second.end()) { pendingGlyphDependencies[fontDependencies.first].insert(glyphID); } } @@ -393,7 +393,7 @@ void GeometryTileWorker::attemptPlacement() { } if (symbolLayout->state == SymbolLayout::Pending) { - symbolLayout->prepare(glyphPositions, icons); + symbolLayout->prepare(glyphMap, iconMap); symbolLayout->state = SymbolLayout::Placed; } diff --git a/src/mbgl/tile/geometry_tile_worker.hpp b/src/mbgl/tile/geometry_tile_worker.hpp index 3a15763a82..c07c16dd9b 100644 --- a/src/mbgl/tile/geometry_tile_worker.hpp +++ b/src/mbgl/tile/geometry_tile_worker.hpp @@ -17,9 +17,7 @@ namespace mbgl { class GeometryTile; class GeometryTileData; -class GlyphAtlas; class SymbolLayout; -class RenderLayer; namespace style { class Layer; @@ -39,7 +37,7 @@ public: void setData(std::unique_ptr<const GeometryTileData>, uint64_t correlationID); void setPlacementConfig(PlacementConfig, uint64_t correlationID); - void onGlyphsAvailable(GlyphPositionMap glyphs); + void onGlyphsAvailable(GlyphMap glyphs); void onIconsAvailable(IconMap icons); private: @@ -82,8 +80,8 @@ private: std::vector<std::unique_ptr<SymbolLayout>> symbolLayouts; GlyphDependencies pendingGlyphDependencies; IconDependencies pendingIconDependencies; - GlyphPositionMap glyphPositions; - IconMap icons; + GlyphMap glyphMap; + IconMap iconMap; }; } // namespace mbgl |