summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Firebaugh <john.firebaugh@gmail.com>2017-06-01 10:30:49 -0700
committerJohn Firebaugh <john.firebaugh@gmail.com>2017-06-13 10:18:43 -0700
commit92252849c1a2ddf7887d1908841fa3c90dd59766 (patch)
tree9d192d0e60b46479122ea2e4a606b598287d49d7
parentb201a7900f989af432aaea500a0e6c5ea5bbba53 (diff)
downloadqtlocation-mapboxgl-92252849c1a2ddf7887d1908841fa3c90dd59766.tar.gz
[core] Per-bucket glyph atlases
-rw-r--r--cmake/core-files.cmake4
-rw-r--r--cmake/test-files.cmake2
-rw-r--r--src/mbgl/gl/context.cpp1
-rw-r--r--src/mbgl/layout/symbol_instance.hpp2
-rw-r--r--src/mbgl/layout/symbol_layout.cpp19
-rw-r--r--src/mbgl/layout/symbol_layout.hpp7
-rw-r--r--src/mbgl/renderer/buckets/symbol_bucket.cpp2
-rw-r--r--src/mbgl/renderer/buckets/symbol_bucket.hpp2
-rw-r--r--src/mbgl/renderer/painter.cpp3
-rw-r--r--src/mbgl/renderer/painter.hpp2
-rw-r--r--src/mbgl/renderer/painters/painter_symbol.cpp4
-rw-r--r--src/mbgl/renderer/render_style.cpp10
-rw-r--r--src/mbgl/renderer/render_style.hpp10
-rw-r--r--src/mbgl/renderer/tile_parameters.hpp4
-rw-r--r--src/mbgl/text/glyph.hpp20
-rw-r--r--src/mbgl/text/glyph_atlas.cpp280
-rw-r--r--src/mbgl/text/glyph_atlas.hpp105
-rw-r--r--src/mbgl/text/glyph_manager.cpp145
-rw-r--r--src/mbgl/text/glyph_manager.hpp68
-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.cpp10
-rw-r--r--src/mbgl/text/glyph_pbf.hpp18
-rw-r--r--src/mbgl/text/quads.cpp4
-rw-r--r--src/mbgl/text/quads.hpp2
-rw-r--r--src/mbgl/text/shaping.cpp18
-rw-r--r--src/mbgl/text/shaping.hpp3
-rw-r--r--src/mbgl/tile/geometry_tile.cpp10
-rw-r--r--src/mbgl/tile/geometry_tile.hpp6
-rw-r--r--src/mbgl/tile/geometry_tile_worker.cpp26
-rw-r--r--src/mbgl/tile/geometry_tile_worker.hpp8
-rw-r--r--test/style/source.test.cpp6
-rw-r--r--test/text/glyph_loader.test.cpp (renamed from test/text/glyph_atlas.test.cpp)54
-rw-r--r--test/tile/annotation_tile.test.cpp6
-rw-r--r--test/tile/geojson_tile.test.cpp6
-rw-r--r--test/tile/raster_tile.test.cpp6
-rw-r--r--test/tile/vector_tile.test.cpp6
36 files changed, 409 insertions, 474 deletions
diff --git a/cmake/core-files.cmake b/cmake/core-files.cmake
index 44e4f40f19..d228f9b429 100644
--- a/cmake/core-files.cmake
+++ b/cmake/core-files.cmake
@@ -473,7 +473,9 @@ set(MBGL_CORE_FILES
src/mbgl/text/glyph.hpp
src/mbgl/text/glyph_atlas.cpp
src/mbgl/text/glyph_atlas.hpp
- src/mbgl/text/glyph_atlas_observer.hpp
+ src/mbgl/text/glyph_manager.cpp
+ src/mbgl/text/glyph_manager.hpp
+ src/mbgl/text/glyph_manager_observer.hpp
src/mbgl/text/glyph_pbf.cpp
src/mbgl/text/glyph_pbf.hpp
src/mbgl/text/glyph_range.hpp
diff --git a/cmake/test-files.cmake b/cmake/test-files.cmake
index 093fc56dbd..421c6045c8 100644
--- a/cmake/test-files.cmake
+++ b/cmake/test-files.cmake
@@ -107,7 +107,7 @@ set(MBGL_TEST_FILES
test/style/style_parser.test.cpp
# text
- test/text/glyph_atlas.test.cpp
+ test/text/glyph_loader.test.cpp
test/text/glyph_pbf.test.cpp
test/text/quads.test.cpp
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
diff --git a/test/style/source.test.cpp b/test/style/source.test.cpp
index 0ab98a63b1..630d701299 100644
--- a/test/style/source.test.cpp
+++ b/test/style/source.test.cpp
@@ -32,7 +32,7 @@
#include <mbgl/annotation/annotation_manager.hpp>
#include <mbgl/annotation/annotation_source.hpp>
#include <mbgl/sprite/sprite_atlas.hpp>
-#include <mbgl/text/glyph_atlas.hpp>
+#include <mbgl/text/glyph_manager.hpp>
#include <cstdint>
@@ -49,7 +49,7 @@ public:
ThreadPool threadPool { 1 };
AnnotationManager annotationManager;
SpriteAtlas spriteAtlas;
- GlyphAtlas glyphAtlas { { 512, 512, }, fileSource };
+ GlyphManager glyphManager { fileSource };
TileParameters tileParameters {
1.0,
@@ -60,7 +60,7 @@ public:
MapMode::Continuous,
annotationManager,
spriteAtlas,
- glyphAtlas
+ glyphManager
};
SourceTest() {
diff --git a/test/text/glyph_atlas.test.cpp b/test/text/glyph_loader.test.cpp
index 01e0f115c0..be197ebb46 100644
--- a/test/text/glyph_atlas.test.cpp
+++ b/test/text/glyph_loader.test.cpp
@@ -1,7 +1,7 @@
#include <mbgl/test/util.hpp>
#include <mbgl/test/stub_file_source.hpp>
-#include <mbgl/text/glyph_atlas.hpp>
+#include <mbgl/text/glyph_manager.hpp>
#include <mbgl/util/run_loop.hpp>
#include <mbgl/util/string.hpp>
#include <mbgl/util/io.hpp>
@@ -9,7 +9,7 @@
using namespace mbgl;
-class StubGlyphAtlasObserver : public GlyphAtlasObserver {
+class StubGlyphManagerObserver : public GlyphManagerObserver {
public:
void onGlyphsLoaded(const FontStack& fontStack, const GlyphRange& glyphRange) override {
if (glyphsLoaded) glyphsLoaded(fontStack, glyphRange);
@@ -25,28 +25,28 @@ public:
class StubGlyphRequestor : public GlyphRequestor {
public:
- void onGlyphsAvailable(GlyphPositionMap positions) override {
- if (glyphsAvailable) glyphsAvailable(std::move(positions));
+ void onGlyphsAvailable(GlyphMap glyphs) override {
+ if (glyphsAvailable) glyphsAvailable(std::move(glyphs));
}
- std::function<void (GlyphPositionMap)> glyphsAvailable;
+ std::function<void (GlyphMap)> glyphsAvailable;
};
-class GlyphAtlasTest {
+class GlyphManagerTest {
public:
util::RunLoop loop;
StubFileSource fileSource;
- StubGlyphAtlasObserver observer;
+ StubGlyphManagerObserver observer;
StubGlyphRequestor requestor;
- GlyphAtlas glyphAtlas{ { 32, 32 }, fileSource };
+ GlyphManager glyphManager { fileSource };
void run(const std::string& url, GlyphDependencies dependencies) {
// Squelch logging.
Log::setObserver(std::make_unique<Log::NullObserver>());
- glyphAtlas.setURL(url);
- glyphAtlas.setObserver(&observer);
- glyphAtlas.getGlyphs(requestor, std::move(dependencies));
+ glyphManager.setURL(url);
+ glyphManager.setObserver(&observer);
+ glyphManager.getGlyphs(requestor, std::move(dependencies));
loop.run();
}
@@ -56,8 +56,8 @@ public:
}
};
-TEST(GlyphAtlas, LoadingSuccess) {
- GlyphAtlasTest test;
+TEST(GlyphManager, LoadingSuccess) {
+ GlyphManagerTest test;
test.fileSource.glyphsResponse = [&] (const Resource& resource) {
EXPECT_EQ(Resource::Kind::Glyphs, resource.kind);
@@ -76,8 +76,8 @@ TEST(GlyphAtlas, LoadingSuccess) {
ASSERT_EQ(range, GlyphRange(0, 255));
};
- test.requestor.glyphsAvailable = [&] (GlyphPositionMap positions) {
- const auto& testPositions = positions.at({{"Test Stack"}});
+ test.requestor.glyphsAvailable = [&] (GlyphMap glyphs) {
+ const auto& testPositions = glyphs.at({{"Test Stack"}});
ASSERT_EQ(testPositions.size(), 3u);
ASSERT_EQ(testPositions.count(u'a'), 1u);
@@ -95,8 +95,8 @@ TEST(GlyphAtlas, LoadingSuccess) {
});
}
-TEST(GlyphAtlas, LoadingFail) {
- GlyphAtlasTest test;
+TEST(GlyphManager, LoadingFail) {
+ GlyphManagerTest test;
test.fileSource.glyphsResponse = [&] (const Resource&) {
Response response;
@@ -116,7 +116,7 @@ TEST(GlyphAtlas, LoadingFail) {
test.end();
};
- test.requestor.glyphsAvailable = [&] (GlyphPositionMap) {
+ test.requestor.glyphsAvailable = [&] (GlyphMap) {
FAIL();
test.end();
};
@@ -128,8 +128,8 @@ TEST(GlyphAtlas, LoadingFail) {
});
}
-TEST(GlyphAtlas, LoadingCorrupted) {
- GlyphAtlasTest test;
+TEST(GlyphManager, LoadingCorrupted) {
+ GlyphManagerTest test;
test.fileSource.glyphsResponse = [&] (const Resource&) {
Response response;
@@ -147,7 +147,7 @@ TEST(GlyphAtlas, LoadingCorrupted) {
test.end();
};
- test.requestor.glyphsAvailable = [&] (GlyphPositionMap) {
+ test.requestor.glyphsAvailable = [&] (GlyphMap) {
FAIL();
test.end();
};
@@ -159,8 +159,8 @@ TEST(GlyphAtlas, LoadingCorrupted) {
});
}
-TEST(GlyphAtlas, LoadingCancel) {
- GlyphAtlasTest test;
+TEST(GlyphManager, LoadingCancel) {
+ GlyphManagerTest test;
test.fileSource.glyphsResponse = [&] (const Resource&) {
test.end();
@@ -178,8 +178,8 @@ TEST(GlyphAtlas, LoadingCancel) {
});
}
-TEST(GlyphAtlas, LoadingInvalid) {
- GlyphAtlasTest test;
+TEST(GlyphManager, LoadingInvalid) {
+ GlyphManagerTest test;
test.fileSource.glyphsResponse = [&] (const Resource& resource) {
EXPECT_EQ(Resource::Kind::Glyphs, resource.kind);
@@ -198,8 +198,8 @@ TEST(GlyphAtlas, LoadingInvalid) {
ASSERT_EQ(range, GlyphRange(0, 255));
};
- test.requestor.glyphsAvailable = [&] (GlyphPositionMap positions) {
- const auto& testPositions = positions.at({{"Test Stack"}});
+ test.requestor.glyphsAvailable = [&] (GlyphMap glyphs) {
+ const auto& testPositions = glyphs.at({{"Test Stack"}});
ASSERT_EQ(testPositions.size(), 2u);
ASSERT_FALSE(bool(testPositions.at(u'A')));
diff --git a/test/tile/annotation_tile.test.cpp b/test/tile/annotation_tile.test.cpp
index 927799b26d..168dbf5292 100644
--- a/test/tile/annotation_tile.test.cpp
+++ b/test/tile/annotation_tile.test.cpp
@@ -13,7 +13,7 @@
#include <mbgl/annotation/annotation_manager.hpp>
#include <mbgl/annotation/annotation_tile.hpp>
#include <mbgl/sprite/sprite_atlas.hpp>
-#include <mbgl/text/glyph_atlas.hpp>
+#include <mbgl/text/glyph_manager.hpp>
#include <memory>
@@ -28,7 +28,7 @@ public:
AnnotationManager annotationManager;
RenderStyle style { threadPool, fileSource };
SpriteAtlas spriteAtlas;
- GlyphAtlas glyphAtlas { { 512, 512, }, fileSource };
+ GlyphManager glyphManager { fileSource };
TileParameters tileParameters {
1.0,
@@ -39,7 +39,7 @@ public:
MapMode::Continuous,
annotationManager,
spriteAtlas,
- glyphAtlas
+ glyphManager
};
};
diff --git a/test/tile/geojson_tile.test.cpp b/test/tile/geojson_tile.test.cpp
index 92068d5e43..9a9fe9a78f 100644
--- a/test/tile/geojson_tile.test.cpp
+++ b/test/tile/geojson_tile.test.cpp
@@ -11,7 +11,7 @@
#include <mbgl/style/layers/circle_layer.hpp>
#include <mbgl/annotation/annotation_manager.hpp>
#include <mbgl/sprite/sprite_atlas.hpp>
-#include <mbgl/text/glyph_atlas.hpp>
+#include <mbgl/text/glyph_manager.hpp>
#include <memory>
@@ -26,7 +26,7 @@ public:
ThreadPool threadPool { 1 };
AnnotationManager annotationManager;
SpriteAtlas spriteAtlas;
- GlyphAtlas glyphAtlas { { 512, 512, }, fileSource };
+ GlyphManager glyphManager { fileSource };
Tileset tileset { { "https://example.com" }, { 0, 22 }, "none" };
TileParameters tileParameters {
@@ -38,7 +38,7 @@ public:
MapMode::Continuous,
annotationManager,
spriteAtlas,
- glyphAtlas
+ glyphManager
};
};
diff --git a/test/tile/raster_tile.test.cpp b/test/tile/raster_tile.test.cpp
index 1bd35700b3..ba296c0360 100644
--- a/test/tile/raster_tile.test.cpp
+++ b/test/tile/raster_tile.test.cpp
@@ -10,7 +10,7 @@
#include <mbgl/renderer/tile_parameters.hpp>
#include <mbgl/renderer/buckets/raster_bucket.hpp>
#include <mbgl/sprite/sprite_atlas.hpp>
-#include <mbgl/text/glyph_atlas.hpp>
+#include <mbgl/text/glyph_manager.hpp>
using namespace mbgl;
@@ -22,7 +22,7 @@ public:
ThreadPool threadPool { 1 };
AnnotationManager annotationManager;
SpriteAtlas spriteAtlas;
- GlyphAtlas glyphAtlas { { 512, 512, }, fileSource };
+ GlyphManager glyphManager { fileSource };
Tileset tileset { { "https://example.com" }, { 0, 22 }, "none" };
TileParameters tileParameters {
@@ -34,7 +34,7 @@ public:
MapMode::Continuous,
annotationManager,
spriteAtlas,
- glyphAtlas
+ glyphManager
};
};
diff --git a/test/tile/vector_tile.test.cpp b/test/tile/vector_tile.test.cpp
index a44eeb9001..e1a1635bd3 100644
--- a/test/tile/vector_tile.test.cpp
+++ b/test/tile/vector_tile.test.cpp
@@ -14,7 +14,7 @@
#include <mbgl/geometry/feature_index.hpp>
#include <mbgl/annotation/annotation_manager.hpp>
#include <mbgl/sprite/sprite_atlas.hpp>
-#include <mbgl/text/glyph_atlas.hpp>
+#include <mbgl/text/glyph_manager.hpp>
#include <memory>
@@ -28,7 +28,7 @@ public:
ThreadPool threadPool { 1 };
AnnotationManager annotationManager;
SpriteAtlas spriteAtlas;
- GlyphAtlas glyphAtlas { { 512, 512, }, fileSource };
+ GlyphManager glyphManager { fileSource };
Tileset tileset { { "https://example.com" }, { 0, 22 }, "none" };
TileParameters tileParameters {
@@ -40,7 +40,7 @@ public:
MapMode::Continuous,
annotationManager,
spriteAtlas,
- glyphAtlas
+ glyphManager
};
};