summaryrefslogtreecommitdiff
path: root/src/mbgl
diff options
context:
space:
mode:
authorJohn Firebaugh <john.firebaugh@gmail.com>2015-12-22 15:10:24 -0800
committerJohn Firebaugh <john.firebaugh@gmail.com>2015-12-23 12:50:42 -0800
commit16de579d7cfc2960793cbcb5e95741f22ab73768 (patch)
treeb4c3b7651f605e3d3dd61b469f61036bd2c4dcc3 /src/mbgl
parent7bd4745cf10c504a4899a37016e87bce45e51472 (diff)
downloadqtlocation-mapboxgl-16de579d7cfc2960793cbcb5e95741f22ab73768.tar.gz
[core] Rationalize error handling for resource loading
* Standardize on std::exception_ptr as the error representation (fixes #2854). * Don't format textual strings at the error source; pass on the constituent data via observer method parameters instead. * Use the null object pattern to simplify observer notification code. * Further refactoring for ResourceLoading tests.
Diffstat (limited to 'src/mbgl')
-rw-r--r--src/mbgl/map/map_context.cpp9
-rw-r--r--src/mbgl/map/map_context.hpp8
-rw-r--r--src/mbgl/map/raster_tile_data.cpp10
-rw-r--r--src/mbgl/map/source.cpp60
-rw-r--r--src/mbgl/map/source.hpp19
-rw-r--r--src/mbgl/map/tile_data.cpp6
-rw-r--r--src/mbgl/map/tile_data.hpp4
-rw-r--r--src/mbgl/map/tile_worker.hpp5
-rw-r--r--src/mbgl/map/vector_tile.cpp5
-rw-r--r--src/mbgl/map/vector_tile_data.cpp22
-rw-r--r--src/mbgl/sprite/sprite_parser.cpp6
-rw-r--r--src/mbgl/sprite/sprite_parser.hpp4
-rw-r--r--src/mbgl/sprite/sprite_store.cpp30
-rw-r--r--src/mbgl/sprite/sprite_store.hpp9
-rw-r--r--src/mbgl/style/style.cpp78
-rw-r--r--src/mbgl/style/style.hpp36
-rw-r--r--src/mbgl/text/glyph_pbf.cpp46
-rw-r--r--src/mbgl/text/glyph_pbf.hpp26
-rw-r--r--src/mbgl/text/glyph_store.cpp21
-rw-r--r--src/mbgl/text/glyph_store.hpp22
-rw-r--r--src/mbgl/util/worker.cpp20
-rw-r--r--src/mbgl/util/worker.hpp2
22 files changed, 157 insertions, 291 deletions
diff --git a/src/mbgl/map/map_context.cpp b/src/mbgl/map/map_context.cpp
index 75ca188fbb..f2c17824c3 100644
--- a/src/mbgl/map/map_context.cpp
+++ b/src/mbgl/map/map_context.cpp
@@ -311,16 +311,13 @@ void MapContext::onLowMemory() {
style->onLowMemory();
asyncInvalidate.send();
}
-
-void MapContext::onTileDataChanged() {
- assert(util::ThreadContext::currentlyOn(util::ThreadType::Map));
+
+void MapContext::onResourceLoaded() {
updateFlags |= Update::Repaint;
asyncUpdate.send();
}
-void MapContext::onResourceLoadingFailed(std::exception_ptr error) {
- assert(util::ThreadContext::currentlyOn(util::ThreadType::Map));
-
+void MapContext::onResourceError(std::exception_ptr error) {
if (data.mode == MapMode::Still && callback) {
callback(error, {});
callback = nullptr;
diff --git a/src/mbgl/map/map_context.hpp b/src/mbgl/map/map_context.hpp
index 24459f270a..012da785c9 100644
--- a/src/mbgl/map/map_context.hpp
+++ b/src/mbgl/map/map_context.hpp
@@ -65,14 +65,12 @@ public:
void onLowMemory();
void cleanup();
-
- // Style::Observer implementation.
- void onTileDataChanged() override;
- void onResourceLoadingFailed(std::exception_ptr error) override;
-
void dumpDebugLogs() const;
private:
+ void onResourceLoaded() override;
+ void onResourceError(std::exception_ptr) override;
+
// Update the state indicated by the accumulated Update flags, then render.
void update();
diff --git a/src/mbgl/map/raster_tile_data.cpp b/src/mbgl/map/raster_tile_data.cpp
index 7ef13301e8..5c85cbd034 100644
--- a/src/mbgl/map/raster_tile_data.cpp
+++ b/src/mbgl/map/raster_tile_data.cpp
@@ -6,8 +6,6 @@
#include <mbgl/util/worker.hpp>
#include <mbgl/util/work_request.hpp>
-#include <sstream>
-
using namespace mbgl;
RasterTileData::RasterTileData(const TileID& id_,
@@ -41,9 +39,7 @@ void RasterTileData::request(float pixelRatio,
if (res.error->reason == Response::Error::Reason::NotFound) {
state = State::parsed;
} else {
- std::stringstream message;
- message << "Failed to load [" << url << "]: " << res.error->message;
- error = message.str();
+ error = std::make_exception_ptr(std::runtime_error(res.error->message));
state = State::obsolete;
}
callback();
@@ -68,9 +64,7 @@ void RasterTileData::request(float pixelRatio,
state = State::parsed;
bucket = std::move(result.get<std::unique_ptr<Bucket>>());
} else {
- std::stringstream message;
- message << "Failed to parse [" << std::string(id) << "]: " << result.get<std::string>();
- error = message.str();
+ error = result.get<std::exception_ptr>();
state = State::obsolete;
}
diff --git a/src/mbgl/map/source.cpp b/src/mbgl/map/source.cpp
index f09d6db85a..a814e484ff 100644
--- a/src/mbgl/map/source.cpp
+++ b/src/mbgl/map/source.cpp
@@ -31,6 +31,7 @@
#include <rapidjson/error/en.h>
#include <algorithm>
+#include <sstream>
namespace mbgl {
@@ -75,9 +76,7 @@ void Source::load() {
req = nullptr;
if (res.error) {
- std::stringstream message;
- message << "Failed to load [" << info.url << "]: " << res.error->message;
- emitSourceLoadingFailed(message.str());
+ observer->onSourceError(*this, std::make_exception_ptr(std::runtime_error(res.error->message)));
return;
}
@@ -86,8 +85,8 @@ void Source::load() {
if (d.HasParseError()) {
std::stringstream message;
- message << "Failed to parse [" << info.url << "]: " << d.GetErrorOffset() << " - " << rapidjson::GetParseError_En(d.GetParseError());
- emitSourceLoadingFailed(message.str());
+ message << d.GetErrorOffset() << " - " << rapidjson::GetParseError_En(d.GetParseError());
+ observer->onSourceError(*this, std::make_exception_ptr(std::runtime_error(message.str())));
return;
}
@@ -98,8 +97,7 @@ void Source::load() {
}
loaded = true;
-
- emitSourceLoaded();
+ observer->onSourceLoaded(*this);
});
}
@@ -166,8 +164,8 @@ bool Source::handlePartialTile(const TileID& id, Worker&) {
return true;
}
- return tileData->parsePending([this]() {
- emitTileLoaded(false);
+ return tileData->parsePending([this, id]() {
+ observer->onTileLoaded(*this, id, false);
});
}
@@ -464,12 +462,12 @@ void Source::onLowMemory() {
cache.clear();
}
-void Source::setObserver(Observer* observer) {
- observer_ = observer;
+void Source::setObserver(Observer* observer_) {
+ observer = observer_;
}
-void Source::tileLoadingCompleteCallback(const TileID& normalized_id, const TransformState& transformState, bool collisionDebug) {
- auto it = tileDataMap.find(normalized_id);
+void Source::tileLoadingCompleteCallback(const TileID& id, const TransformState& transformState, bool collisionDebug) {
+ auto it = tileDataMap.find(id);
if (it == tileDataMap.end()) {
return;
}
@@ -479,43 +477,13 @@ void Source::tileLoadingCompleteCallback(const TileID& normalized_id, const Tran
return;
}
- if (tileData->getState() == TileData::State::obsolete && !tileData->getError().empty()) {
- emitTileLoadingFailed(tileData->getError());
+ if (tileData->getState() == TileData::State::obsolete && tileData->getError()) {
+ observer->onTileError(*this, id, tileData->getError());
return;
}
tileData->redoPlacement({ transformState.getAngle(), transformState.getPitch(), collisionDebug });
- emitTileLoaded(true);
-}
-
-void Source::emitSourceLoaded() {
- if (observer_) {
- observer_->onSourceLoaded();
- }
-}
-
-void Source::emitSourceLoadingFailed(const std::string& message) {
- if (!observer_) {
- return;
- }
-
- auto error = std::make_exception_ptr(util::SourceLoadingException(message));
- observer_->onSourceLoadingFailed(error);
-}
-
-void Source::emitTileLoaded(bool isNewTile) {
- if (observer_) {
- observer_->onTileLoaded(isNewTile);
- }
-}
-
-void Source::emitTileLoadingFailed(const std::string& message) {
- if (!observer_) {
- return;
- }
-
- auto error = std::make_exception_ptr(util::TileLoadingException(message));
- observer_->onTileLoadingFailed(error);
+ observer->onTileLoaded(*this, id, true);
}
void Source::dumpDebugLogs() const {
diff --git a/src/mbgl/map/source.hpp b/src/mbgl/map/source.hpp
index dc939113b2..36613c2052 100644
--- a/src/mbgl/map/source.hpp
+++ b/src/mbgl/map/source.hpp
@@ -25,11 +25,11 @@ public:
public:
virtual ~Observer() = default;
- virtual void onSourceLoaded() = 0;
- virtual void onSourceLoadingFailed(std::exception_ptr error) = 0;
+ virtual void onSourceLoaded(Source&) {};
+ virtual void onSourceError(Source&, std::exception_ptr) {};
- virtual void onTileLoaded(bool isNewTile) = 0;
- virtual void onTileLoadingFailed(std::exception_ptr error) = 0;
+ virtual void onTileLoaded(Source&, const TileID&, bool /* isNewTile */) {};
+ virtual void onTileError(Source&, const TileID&, std::exception_ptr) {};
};
Source();
@@ -64,12 +64,6 @@ public:
private:
void tileLoadingCompleteCallback(const TileID&, const TransformState&, bool collisionDebug);
-
- void emitSourceLoaded();
- void emitSourceLoadingFailed(const std::string& message);
- void emitTileLoaded(bool isNewTile);
- void emitTileLoadingFailed(const std::string& message);
-
bool handlePartialTile(const TileID &id, Worker &worker);
bool findLoadedChildren(const TileID& id, int32_t maxCoveringZoom, std::forward_list<TileID>& retain);
void findLoadedParent(const TileID& id, int32_t minCoveringZoom, std::forward_list<TileID>& retain);
@@ -82,7 +76,6 @@ private:
double getZoom(const TransformState &state) const;
-
// Stores the time when this source was most recently updated.
TimePoint updated = TimePoint::min();
@@ -92,7 +85,9 @@ private:
TileCache cache;
std::unique_ptr<FileRequest> req;
- Observer* observer_ = nullptr;
+
+ Observer nullObserver;
+ Observer* observer = &nullObserver;
};
} // namespace mbgl
diff --git a/src/mbgl/map/tile_data.cpp b/src/mbgl/map/tile_data.cpp
index bba7d7fe22..d9fd3f0047 100644
--- a/src/mbgl/map/tile_data.cpp
+++ b/src/mbgl/map/tile_data.cpp
@@ -1,5 +1,6 @@
#include <mbgl/map/tile_data.hpp>
#include <mbgl/renderer/debug_bucket.hpp>
+#include <mbgl/util/string.hpp>
namespace mbgl {
@@ -26,7 +27,10 @@ const char* TileData::StateToString(const State state) {
void TileData::dumpDebugLogs() const {
Log::Info(Event::General, "TileData::id: %s", std::string(id).c_str());
Log::Info(Event::General, "TileData::state: %s", TileData::StateToString(state));
- Log::Info(Event::General, "TileData::error: %s", error.c_str());
+
+ if (error) {
+ Log::Info(Event::General, "TileData::error: %s", util::toString(error).c_str());
+ }
}
} // namespace mbgl
diff --git a/src/mbgl/map/tile_data.hpp b/src/mbgl/map/tile_data.hpp
index ed3426cf80..2bb11054a6 100644
--- a/src/mbgl/map/tile_data.hpp
+++ b/src/mbgl/map/tile_data.hpp
@@ -88,7 +88,7 @@ public:
return state;
}
- std::string getError() const {
+ std::exception_ptr getError() const {
return error;
}
@@ -103,7 +103,7 @@ public:
protected:
std::atomic<State> state;
- std::string error;
+ std::exception_ptr error;
};
} // namespace mbgl
diff --git a/src/mbgl/map/tile_worker.hpp b/src/mbgl/map/tile_worker.hpp
index 14f996c1b0..d25b6e50f2 100644
--- a/src/mbgl/map/tile_worker.hpp
+++ b/src/mbgl/map/tile_worker.hpp
@@ -33,8 +33,9 @@ public:
std::unordered_map<std::string, std::unique_ptr<Bucket>> buckets;
};
-using TileParseResult = mapbox::util::variant<TileParseResultBuckets, // success
- std::string>; // error
+using TileParseResult = mapbox::util::variant<
+ TileParseResultBuckets, // success
+ std::exception_ptr>; // error
class TileWorker : public util::noncopyable {
public:
diff --git a/src/mbgl/map/vector_tile.cpp b/src/mbgl/map/vector_tile.cpp
index 00307f04a9..39e31da0d4 100644
--- a/src/mbgl/map/vector_tile.cpp
+++ b/src/mbgl/map/vector_tile.cpp
@@ -5,7 +5,6 @@
#include <mbgl/storage/file_source.hpp>
#include <mbgl/util/thread_context.hpp>
-#include <sstream>
#include <utility>
namespace mbgl {
@@ -194,9 +193,7 @@ std::unique_ptr<FileRequest> VectorTileMonitor::monitorTile(const GeometryTileMo
callback(nullptr, nullptr, res.modified, res.expires);
return;
} else {
- std::stringstream message;
- message << "Failed to load [" << url << "]: " << res.error->message;
- callback(std::make_exception_ptr(std::runtime_error(message.str())), nullptr, res.modified, res.expires);
+ callback(std::make_exception_ptr(std::runtime_error(res.error->message)), nullptr, res.modified, res.expires);
return;
}
}
diff --git a/src/mbgl/map/vector_tile_data.cpp b/src/mbgl/map/vector_tile_data.cpp
index 708ded02cc..3fe423b502 100644
--- a/src/mbgl/map/vector_tile_data.cpp
+++ b/src/mbgl/map/vector_tile_data.cpp
@@ -6,8 +6,6 @@
#include <mbgl/style/style.hpp>
#include <mbgl/storage/file_source.hpp>
-#include <sstream>
-
namespace mbgl {
VectorTileData::VectorTileData(const TileID& id_,
@@ -32,14 +30,10 @@ VectorTileData::VectorTileData(const TileID& id_,
Seconds modified_,
Seconds expires_) {
if (err) {
- try {
- std::rethrow_exception(err);
- } catch (const std::exception& e) {
- error = e.what();
- state = State::obsolete;
- callback();
- return;
- }
+ error = err;
+ state = State::obsolete;
+ callback();
+ return;
}
if (!tile) {
@@ -86,9 +80,7 @@ VectorTileData::VectorTileData(const TileID& id_,
redoPlacement();
}
} else {
- std::stringstream message;
- message << "Failed to parse [" << std::string(id) << "]: " << result.get<std::string>();
- error = message.str();
+ error = result.get<std::exception_ptr>();
state = State::obsolete;
}
@@ -130,9 +122,7 @@ bool VectorTileData::parsePending(std::function<void()> callback) {
redoPlacement();
}
} else {
- std::stringstream message;
- message << "Failed to parse [" << std::string(id) << "]: " << result.get<std::string>();
- error = message.str();
+ error = result.get<std::exception_ptr>();
state = State::obsolete;
}
diff --git a/src/mbgl/sprite/sprite_parser.cpp b/src/mbgl/sprite/sprite_parser.cpp
index 59dce93241..1aa95310c5 100644
--- a/src/mbgl/sprite/sprite_parser.cpp
+++ b/src/mbgl/sprite/sprite_parser.cpp
@@ -106,7 +106,7 @@ SpriteParseResult parseSprite(const std::string& image, const std::string& json)
try {
raster = decodeImage(image);
} catch (...) {
- return std::string("Could not parse sprite image");
+ return std::current_exception();
}
JSDocument doc;
@@ -115,9 +115,9 @@ SpriteParseResult parseSprite(const std::string& image, const std::string& json)
if (doc.HasParseError()) {
std::stringstream message;
message << "Failed to parse JSON: " << rapidjson::GetParseError_En(doc.GetParseError()) << " at offset " << doc.GetErrorOffset();
- return message.str();
+ return std::make_exception_ptr(std::runtime_error(message.str()));
} else if (!doc.IsObject()) {
- return std::string("Sprite JSON root must be an object");
+ return std::make_exception_ptr(std::runtime_error("Sprite JSON root must be an object"));
} else {
for (JSValue::ConstMemberIterator itr = doc.MemberBegin(); itr != doc.MemberEnd(); ++itr) {
const std::string name = { itr->name.GetString(), itr->name.GetStringLength() };
diff --git a/src/mbgl/sprite/sprite_parser.hpp b/src/mbgl/sprite/sprite_parser.hpp
index 468ba13c53..36e8947992 100644
--- a/src/mbgl/sprite/sprite_parser.hpp
+++ b/src/mbgl/sprite/sprite_parser.hpp
@@ -30,8 +30,8 @@ using Sprites = std::map<std::string, SpriteImagePtr>;
using SpriteParseResult = mapbox::util::variant<
- Sprites, // success
- std::string>; // error
+ Sprites, // success
+ std::exception_ptr>; // error
// Parses an image and an associated JSON file and returns the sprite objects.
SpriteParseResult parseSprite(const std::string& image, const std::string& json);
diff --git a/src/mbgl/sprite/sprite_store.cpp b/src/mbgl/sprite/sprite_store.cpp
index f54f3f18fd..0c3a7d3ba0 100644
--- a/src/mbgl/sprite/sprite_store.cpp
+++ b/src/mbgl/sprite/sprite_store.cpp
@@ -9,7 +9,6 @@
#include <cassert>
#include <string>
-#include <sstream>
namespace mbgl {
@@ -48,14 +47,11 @@ void SpriteStore::setURL(const std::string& url) {
loader->jsonRequest = nullptr;
if (res.error) {
- std::stringstream message;
- message << "Failed to load [" << jsonURL << "]: " << res.error->message;
- emitSpriteLoadingFailed(message.str());
- return;
+ observer->onSpriteError(std::make_exception_ptr(std::runtime_error(res.error->message)));
} else {
loader->json = res.data;
+ emitSpriteLoadedIfComplete();
}
- emitSpriteLoadedIfComplete();
});
loader->spriteRequest =
@@ -68,14 +64,11 @@ void SpriteStore::setURL(const std::string& url) {
loader->spriteRequest = nullptr;
if (res.error) {
- std::stringstream message;
- message << "Failed to load [" << spriteURL << "]: " << res.error->message;
- emitSpriteLoadingFailed(message.str());
- return;
+ observer->onSpriteError(std::make_exception_ptr(std::runtime_error(res.error->message)));
} else {
loader->image = res.data;
+ emitSpriteLoadedIfComplete();
}
- emitSpriteLoadedIfComplete();
});
}
@@ -91,23 +84,12 @@ void SpriteStore::emitSpriteLoadedIfComplete() {
if (result.is<Sprites>()) {
loaded = true;
setSprites(result.get<Sprites>());
- if (observer) {
- observer->onSpriteLoaded();
- }
+ observer->onSpriteLoaded();
} else {
- emitSpriteLoadingFailed(result.get<std::string>());
+ observer->onSpriteError(result.get<std::exception_ptr>());
}
}
-void SpriteStore::emitSpriteLoadingFailed(const std::string& message) {
- if (!observer) {
- return;
- }
-
- auto error = std::make_exception_ptr(util::SpriteLoadingException(message));
- observer->onSpriteLoadingFailed(error);
-}
-
void SpriteStore::setObserver(Observer* observer_) {
observer = observer_;
}
diff --git a/src/mbgl/sprite/sprite_store.hpp b/src/mbgl/sprite/sprite_store.hpp
index 98b43ac8e4..7c5fe71802 100644
--- a/src/mbgl/sprite/sprite_store.hpp
+++ b/src/mbgl/sprite/sprite_store.hpp
@@ -18,8 +18,8 @@ public:
public:
virtual ~Observer() = default;
- virtual void onSpriteLoaded() = 0;
- virtual void onSpriteLoadingFailed(std::exception_ptr) = 0;
+ virtual void onSpriteLoaded() {};
+ virtual void onSpriteError(std::exception_ptr) {};
};
SpriteStore(float pixelRatio);
@@ -54,16 +54,15 @@ public:
private:
void _setSprite(const std::string&, const std::shared_ptr<const SpriteImage>& = nullptr);
-
void emitSpriteLoadedIfComplete();
- void emitSpriteLoadingFailed(const std::string& message);
struct Loader;
std::unique_ptr<Loader> loader;
bool loaded = false;
- Observer* observer = nullptr;
+ Observer nullObserver;
+ Observer* observer = &nullObserver;
// Lock for sprites and dirty maps.
std::mutex mutex;
diff --git a/src/mbgl/style/style.cpp b/src/mbgl/style/style.cpp
index 77a544714e..b1c867a692 100644
--- a/src/mbgl/style/style.cpp
+++ b/src/mbgl/style/style.cpp
@@ -17,6 +17,7 @@
#include <mbgl/geometry/glyph_atlas.hpp>
#include <mbgl/geometry/line_atlas.hpp>
#include <mbgl/util/constants.hpp>
+#include <mbgl/util/string.hpp>
#include <mbgl/platform/log.hpp>
#include <mbgl/layer/background_layer.hpp>
@@ -304,73 +305,64 @@ void Style::onLowMemory() {
void Style::setObserver(Observer* observer_) {
assert(util::ThreadContext::currentlyOn(util::ThreadType::Map));
- assert(!observer);
-
observer = observer_;
}
-void Style::onGlyphRangeLoaded() {
+void Style::onGlyphsLoaded(const std::string& fontStack, const GlyphRange& glyphRange) {
shouldReparsePartialTiles = true;
-
- emitTileDataChanged();
+ observer->onGlyphsLoaded(fontStack, glyphRange);
+ observer->onResourceLoaded();
}
-void Style::onGlyphRangeLoadingFailed(std::exception_ptr error) {
- emitResourceLoadingFailed(error);
+void Style::onGlyphsError(const std::string& fontStack, const GlyphRange& glyphRange, std::exception_ptr error) {
+ lastError = error;
+ Log::Error(Event::Style, "Failed to load glyph range %d-%d for font stack %s: %s",
+ glyphRange.first, glyphRange.second, fontStack.c_str(), util::toString(error).c_str());
+ observer->onGlyphsError(fontStack, glyphRange, error);
+ observer->onResourceError(error);
}
-void Style::onSourceLoaded() {
- emitTileDataChanged();
+void Style::onSourceLoaded(Source& source) {
+ observer->onSourceLoaded(source);
+ observer->onResourceLoaded();
}
-void Style::onSourceLoadingFailed(std::exception_ptr error) {
- emitResourceLoadingFailed(error);
+void Style::onSourceError(Source& source, std::exception_ptr error) {
+ lastError = error;
+ Log::Error(Event::Style, "Failed to load source %s: %s",
+ source.info.source_id.c_str(), util::toString(error).c_str());
+ observer->onSourceError(source, error);
+ observer->onResourceError(error);
}
-void Style::onTileLoaded(bool isNewTile) {
+void Style::onTileLoaded(Source& source, const TileID& tileID, bool isNewTile) {
if (isNewTile) {
shouldReparsePartialTiles = true;
}
- emitTileDataChanged();
+ observer->onTileLoaded(source, tileID, isNewTile);
+ observer->onResourceLoaded();
}
-void Style::onTileLoadingFailed(std::exception_ptr error) {
- emitResourceLoadingFailed(error);
+void Style::onTileError(Source& source, const TileID& tileID, std::exception_ptr error) {
+ lastError = error;
+ Log::Error(Event::Style, "Failed to load tile %s for source %s: %s",
+ std::string(tileID).c_str(), source.info.source_id.c_str(), util::toString(error).c_str());
+ observer->onTileError(source, tileID, error);
+ observer->onResourceError(error);
}
void Style::onSpriteLoaded() {
shouldReparsePartialTiles = true;
- emitTileDataChanged();
-}
-
-void Style::onSpriteLoadingFailed(std::exception_ptr error) {
- emitResourceLoadingFailed(error);
+ observer->onSpriteLoaded();
+ observer->onResourceLoaded();
}
-void Style::emitTileDataChanged() {
- assert(util::ThreadContext::currentlyOn(util::ThreadType::Map));
-
- if (observer) {
- observer->onTileDataChanged();
- }
-}
-
-void Style::emitResourceLoadingFailed(std::exception_ptr error) {
- assert(util::ThreadContext::currentlyOn(util::ThreadType::Map));
-
- try {
- if (error) {
- lastError = error;
- std::rethrow_exception(error);
- }
- } catch(const std::exception& e) {
- Log::Error(Event::Style, "%s", e.what());
- }
-
- if (observer) {
- observer->onResourceLoadingFailed(error);
- }
+void Style::onSpriteError(std::exception_ptr error) {
+ lastError = error;
+ Log::Error(Event::Style, "Failed to load sprite: %s", util::toString(error).c_str());
+ observer->onSpriteError(error);
+ observer->onResourceError(error);
}
void Style::dumpDebugLogs() const {
diff --git a/src/mbgl/style/style.hpp b/src/mbgl/style/style.hpp
index ed5df04256..ba5da7435a 100644
--- a/src/mbgl/style/style.hpp
+++ b/src/mbgl/style/style.hpp
@@ -58,12 +58,18 @@ public:
Style(MapData&);
~Style();
- class Observer {
+ class Observer : public GlyphStore::Observer,
+ public SpriteStore::Observer,
+ public Source::Observer {
public:
- virtual ~Observer() = default;
-
- virtual void onTileDataChanged() = 0;
- virtual void onResourceLoadingFailed(std::exception_ptr error) = 0;
+ /**
+ * In addition to the individual glyph, sprite, and source events, the
+ * following "rollup" events are provided for convenience. They are
+ * strictly additive; e.g. when a source is loaded, both `onSourceLoaded`
+ * and `onResourceLoaded` will be called.
+ */
+ virtual void onResourceLoaded() {};
+ virtual void onResourceError(std::exception_ptr) {};
};
void setJSON(const std::string& data, const std::string& base);
@@ -115,25 +121,23 @@ private:
std::vector<std::unique_ptr<StyleLayer>>::const_iterator findLayer(const std::string& layerID) const;
// GlyphStore::Observer implementation.
- void onGlyphRangeLoaded() override;
- void onGlyphRangeLoadingFailed(std::exception_ptr error) override;
+ void onGlyphsLoaded(const std::string& fontStack, const GlyphRange&) override;
+ void onGlyphsError(const std::string& fontStack, const GlyphRange&, std::exception_ptr) override;
// SpriteStore::Observer implementation.
void onSpriteLoaded() override;
- void onSpriteLoadingFailed(std::exception_ptr error) override;
+ void onSpriteError(std::exception_ptr) override;
// Source::Observer implementation.
- void onSourceLoaded() override;
- void onSourceLoadingFailed(std::exception_ptr error) override;
- void onTileLoaded(bool isNewTile) override;
- void onTileLoadingFailed(std::exception_ptr error) override;
-
- void emitTileDataChanged();
- void emitResourceLoadingFailed(std::exception_ptr error);
+ void onSourceLoaded(Source&) override;
+ void onSourceError(Source&, std::exception_ptr) override;
+ void onTileLoaded(Source&, const TileID&, bool isNewTile) override;
+ void onTileError(Source&, const TileID&, std::exception_ptr) override;
bool shouldReparsePartialTiles = false;
- Observer* observer = nullptr;
+ Observer nullObserver;
+ Observer* observer = &nullObserver;
std::exception_ptr lastError;
diff --git a/src/mbgl/text/glyph_pbf.cpp b/src/mbgl/text/glyph_pbf.cpp
index c14f52de7a..0c0626c0de 100644
--- a/src/mbgl/text/glyph_pbf.cpp
+++ b/src/mbgl/text/glyph_pbf.cpp
@@ -12,8 +12,6 @@
#include <mbgl/util/token.hpp>
#include <mbgl/util/url.hpp>
-#include <sstream>
-
namespace {
void parseGlyphPBF(mbgl::FontStack& stack, const std::string& data) {
@@ -65,8 +63,10 @@ namespace mbgl {
GlyphPBF::GlyphPBF(GlyphStore* store,
const std::string& fontStack,
- const GlyphRange& glyphRange)
- : parsed(false) {
+ const GlyphRange& glyphRange,
+ GlyphStore::Observer* observer_)
+ : parsed(false),
+ observer(observer_) {
// Load the glyph set URL
std::string url = util::replaceTokens(store->getURL(), [&](const std::string &name) -> std::string {
if (name == "fontstack") return util::percentEncode(fontStack);
@@ -74,7 +74,7 @@ GlyphPBF::GlyphPBF(GlyphStore* store,
return "";
});
- auto requestCallback = [this, store, fontStack, url](Response res) {
+ auto requestCallback = [this, store, fontStack, glyphRange](Response res) {
if (res.stale) {
// Only handle fresh responses.
return;
@@ -82,12 +82,10 @@ GlyphPBF::GlyphPBF(GlyphStore* store,
req = nullptr;
if (res.error) {
- std::stringstream message;
- message << "Failed to load [" << url << "]: " << res.error->message;
- emitGlyphPBFLoadingFailed(message.str());
+ observer->onGlyphsError(fontStack, glyphRange, std::make_exception_ptr(std::runtime_error(res.error->message)));
} else {
data = res.data;
- parse(store, fontStack, url);
+ parse(store, fontStack, glyphRange);
}
};
@@ -97,7 +95,7 @@ GlyphPBF::GlyphPBF(GlyphStore* store,
GlyphPBF::~GlyphPBF() = default;
-void GlyphPBF::parse(GlyphStore* store, const std::string& fontStack, const std::string& url) {
+void GlyphPBF::parse(GlyphStore* store, const std::string& fontStack, const GlyphRange& glyphRange) {
assert(data);
if (data->empty()) {
// If there is no data, this means we either haven't
@@ -107,35 +105,13 @@ void GlyphPBF::parse(GlyphStore* store, const std::string& fontStack, const std:
try {
parseGlyphPBF(**store->getFontStack(fontStack), *data);
- } catch (const std::exception& ex) {
- std::stringstream message;
- message << "Failed to parse [" << url << "]: " << ex.what();
- emitGlyphPBFLoadingFailed(message.str());
+ } catch (...) {
+ observer->onGlyphsError(fontStack, glyphRange, std::current_exception());
return;
}
parsed = true;
-
- emitGlyphPBFLoaded();
-}
-
-void GlyphPBF::setObserver(Observer* observer_) {
- observer = observer_;
-}
-
-void GlyphPBF::emitGlyphPBFLoaded() {
- if (observer) {
- observer->onGlyphPBFLoaded();
- }
-}
-
-void GlyphPBF::emitGlyphPBFLoadingFailed(const std::string& message) {
- if (!observer) {
- return;
- }
-
- auto error = std::make_exception_ptr(util::GlyphRangeLoadingException(message));
- observer->onGlyphPBFLoadingFailed(error);
+ observer->onGlyphsLoaded(fontStack, glyphRange);
}
} // namespace mbgl
diff --git a/src/mbgl/text/glyph_pbf.hpp b/src/mbgl/text/glyph_pbf.hpp
index d595298516..e0f65e7789 100644
--- a/src/mbgl/text/glyph_pbf.hpp
+++ b/src/mbgl/text/glyph_pbf.hpp
@@ -2,6 +2,7 @@
#define MBGL_TEXT_GLYPH_PBF
#include <mbgl/text/glyph.hpp>
+#include <mbgl/text/glyph_store.hpp>
#include <mbgl/util/noncopyable.hpp>
#include <atomic>
@@ -11,43 +12,30 @@
namespace mbgl {
-class GlyphStore;
class FontStack;
class FileRequest;
class GlyphPBF : private util::noncopyable {
public:
- class Observer {
- public:
- virtual ~Observer() = default;
-
- virtual void onGlyphPBFLoaded() = 0;
- virtual void onGlyphPBFLoadingFailed(std::exception_ptr error) = 0;
- };
-
GlyphPBF(GlyphStore* store,
const std::string& fontStack,
- const GlyphRange& glyphRange);
- virtual ~GlyphPBF();
+ const GlyphRange&,
+ GlyphStore::Observer*);
+ ~GlyphPBF();
bool isParsed() const {
return parsed;
- };
-
- void setObserver(Observer* observer);
+ }
private:
- void emitGlyphPBFLoaded();
- void emitGlyphPBFLoadingFailed(const std::string& message);
-
- void parse(GlyphStore* store, const std::string& fontStack, const std::string& url);
+ void parse(GlyphStore*, const std::string& fontStack, const GlyphRange&);
std::shared_ptr<const std::string> data;
std::atomic<bool> parsed;
std::unique_ptr<FileRequest> req;
- Observer* observer = nullptr;
+ GlyphStore::Observer* observer = nullptr;
};
} // namespace mbgl
diff --git a/src/mbgl/text/glyph_store.cpp b/src/mbgl/text/glyph_store.cpp
index 047db17b7d..a3d1530e3d 100644
--- a/src/mbgl/text/glyph_store.cpp
+++ b/src/mbgl/text/glyph_store.cpp
@@ -7,6 +7,9 @@
namespace mbgl {
+GlyphStore::GlyphStore() = default;
+GlyphStore::~GlyphStore() = default;
+
void GlyphStore::requestGlyphRange(const std::string& fontStackName, const GlyphRange& range) {
assert(util::ThreadContext::currentlyOn(util::ThreadType::Map));
@@ -18,10 +21,8 @@ void GlyphStore::requestGlyphRange(const std::string& fontStackName, const Glyph
return;
}
- auto glyphPBF = std::make_unique<GlyphPBF>(this, fontStackName, range);
- glyphPBF->setObserver(this);
-
- rangeSets.emplace(range, std::move(glyphPBF));
+ rangeSets.emplace(range,
+ std::make_unique<GlyphPBF>(this, fontStackName, range, observer));
}
@@ -66,18 +67,6 @@ util::exclusive<FontStack> GlyphStore::getFontStack(const std::string& fontStack
return { it->second.get(), std::move(lock) };
}
-void GlyphStore::onGlyphPBFLoaded() {
- if (observer) {
- observer->onGlyphRangeLoaded();
- }
-}
-
-void GlyphStore::onGlyphPBFLoadingFailed(std::exception_ptr error) {
- if (observer) {
- observer->onGlyphRangeLoadingFailed(error);
- }
-}
-
void GlyphStore::setObserver(Observer* observer_) {
observer = observer_;
}
diff --git a/src/mbgl/text/glyph_store.hpp b/src/mbgl/text/glyph_store.hpp
index 4e665087ea..2236bce38c 100644
--- a/src/mbgl/text/glyph_store.hpp
+++ b/src/mbgl/text/glyph_store.hpp
@@ -3,7 +3,6 @@
#include <mbgl/text/font_stack.hpp>
#include <mbgl/text/glyph.hpp>
-#include <mbgl/text/glyph_pbf.hpp>
#include <mbgl/util/exclusive.hpp>
#include <mbgl/util/noncopyable.hpp>
#include <mbgl/util/work_queue.hpp>
@@ -15,21 +14,23 @@
namespace mbgl {
+class GlyphPBF;
+
// The GlyphStore manages the loading and storage of Glyphs
// and creation of FontStack objects. The GlyphStore lives
// on the MapThread but can be queried from any thread.
-class GlyphStore : public GlyphPBF::Observer, private util::noncopyable {
+class GlyphStore : private util::noncopyable {
public:
class Observer {
public:
virtual ~Observer() = default;
- virtual void onGlyphRangeLoaded() = 0;
- virtual void onGlyphRangeLoadingFailed(std::exception_ptr error) = 0;
+ virtual void onGlyphsLoaded(const std::string& /* fontStack */, const GlyphRange&) {};
+ virtual void onGlyphsError(const std::string& /* fontStack */, const GlyphRange&, std::exception_ptr) {};
};
- GlyphStore() = default;
- virtual ~GlyphStore() = default;
+ GlyphStore();
+ ~GlyphStore();
util::exclusive<FontStack> getFontStack(const std::string& fontStack);
@@ -38,7 +39,7 @@ public:
// made and when the glyph if finally parsed, it gets added to the respective
// FontStack and a signal is emitted to notify the observers. This method
// can be called from any thread.
- bool hasGlyphRanges(const std::string& fontStackName, const std::set<GlyphRange>& glyphRanges);
+ bool hasGlyphRanges(const std::string& fontStack, const std::set<GlyphRange>& glyphRanges);
void setURL(const std::string &url) {
glyphURL = url;
@@ -48,10 +49,6 @@ public:
return glyphURL;
}
- // GlyphPBF::Observer implementation.
- void onGlyphPBFLoaded() override;
- void onGlyphPBFLoadingFailed(std::exception_ptr error) override;
-
void setObserver(Observer* observer);
private:
@@ -67,7 +64,8 @@ private:
util::WorkQueue workQueue;
- Observer* observer = nullptr;
+ Observer nullObserver;
+ Observer* observer = &nullObserver;
};
} // namespace mbgl
diff --git a/src/mbgl/util/worker.cpp b/src/mbgl/util/worker.cpp
index d23831b440..49d1c2bc5b 100644
--- a/src/mbgl/util/worker.cpp
+++ b/src/mbgl/util/worker.cpp
@@ -18,18 +18,12 @@ public:
void parseRasterTile(std::unique_ptr<RasterBucket> bucket,
const std::shared_ptr<const std::string> data,
std::function<void(RasterTileParseResult)> callback) {
- PremultipliedImage image;
-
try {
- image = decodeImage(*data);
+ bucket->setImage(decodeImage(*data));
+ callback(RasterTileParseResult(std::move(bucket)));
} catch (...) {
- callback(RasterTileParseResult("error parsing raster image"));
- return;
+ callback(std::current_exception());
}
-
- bucket->setImage(std::move(image));
-
- callback(RasterTileParseResult(std::move(bucket)));
}
void parseGeometryTile(TileWorker* worker,
@@ -39,8 +33,8 @@ public:
std::function<void(TileParseResult)> callback) {
try {
callback(worker->parseAllLayers(std::move(layers), *tile, config));
- } catch (const std::exception& ex) {
- callback(TileParseResult(ex.what()));
+ } catch (...) {
+ callback(std::current_exception());
}
}
@@ -48,8 +42,8 @@ public:
std::function<void(TileParseResult)> callback) {
try {
callback(worker->parsePendingLayers());
- } catch (const std::exception& ex) {
- callback(TileParseResult(ex.what()));
+ } catch (...) {
+ callback(std::current_exception());
}
}
diff --git a/src/mbgl/util/worker.hpp b/src/mbgl/util/worker.hpp
index 5ba477491d..d4660d9e7c 100644
--- a/src/mbgl/util/worker.hpp
+++ b/src/mbgl/util/worker.hpp
@@ -16,7 +16,7 @@ class GeometryTileLoader;
using RasterTileParseResult = mapbox::util::variant<
std::unique_ptr<Bucket>, // success
- std::string>; // error
+ std::exception_ptr>; // error
class Worker : public mbgl::util::noncopyable {
public: