Notify failures when loading glyphs
This commit is contained in:
@@ -11,6 +11,11 @@ struct Exception : std::runtime_error {
|
||||
inline Exception(const std::string &msg) : std::runtime_error(msg) {}
|
||||
};
|
||||
|
||||
struct GlyphRangeLoadingException : Exception {
|
||||
inline GlyphRangeLoadingException(const char *msg) : Exception(msg) {}
|
||||
inline GlyphRangeLoadingException(const std::string &msg) : Exception(msg) {}
|
||||
};
|
||||
|
||||
struct MisuseException : Exception {
|
||||
inline MisuseException(const char *msg) : Exception(msg) {}
|
||||
inline MisuseException(const std::string &msg) : Exception(msg) {}
|
||||
|
||||
@@ -104,6 +104,10 @@ void ResourceLoader::onGlyphRangeLoaded() {
|
||||
emitTileDataChanged();
|
||||
}
|
||||
|
||||
void ResourceLoader::onGlyphRangeLoadingFailed(std::exception_ptr error) {
|
||||
emitResourceLoadingFailed(error);
|
||||
}
|
||||
|
||||
void ResourceLoader::onSourceLoaded() {
|
||||
emitTileDataChanged();
|
||||
}
|
||||
|
||||
@@ -63,6 +63,7 @@ public:
|
||||
|
||||
// GlyphStore::Observer implementation.
|
||||
void onGlyphRangeLoaded() override;
|
||||
void onGlyphRangeLoadingFailed(std::exception_ptr error) override;
|
||||
|
||||
// Source::Observer implementation.
|
||||
void onSourceLoaded() override;
|
||||
|
||||
@@ -1,20 +1,23 @@
|
||||
#include <mbgl/text/glyph_store.hpp>
|
||||
|
||||
#include <mbgl/map/environment.hpp>
|
||||
#include <mbgl/util/std.hpp>
|
||||
#include <mbgl/util/string.hpp>
|
||||
#include <mbgl/util/utf.hpp>
|
||||
#include <mbgl/util/pbf.hpp>
|
||||
#include <mbgl/util/url.hpp>
|
||||
#include <mbgl/util/constants.hpp>
|
||||
#include <mbgl/util/token.hpp>
|
||||
#include <mbgl/util/math.hpp>
|
||||
#include <mbgl/util/uv_detail.hpp>
|
||||
#include <mbgl/storage/file_source.hpp>
|
||||
#include <mbgl/platform/log.hpp>
|
||||
#include <mbgl/platform/platform.hpp>
|
||||
#include <mbgl/storage/file_source.hpp>
|
||||
#include <mbgl/util/constants.hpp>
|
||||
#include <mbgl/util/exception.hpp>
|
||||
#include <mbgl/util/math.hpp>
|
||||
#include <mbgl/util/pbf.hpp>
|
||||
#include <mbgl/util/std.hpp>
|
||||
#include <mbgl/util/string.hpp>
|
||||
#include <mbgl/util/token.hpp>
|
||||
#include <mbgl/util/url.hpp>
|
||||
#include <mbgl/util/utf.hpp>
|
||||
#include <mbgl/util/uv_detail.hpp>
|
||||
#include <mbgl/util/uv_detail.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
@@ -139,7 +142,8 @@ GlyphPBF::GlyphPBF(const std::string& glyphURL,
|
||||
const std::string& fontStack,
|
||||
GlyphRange glyphRange,
|
||||
Environment& env_,
|
||||
const GlyphLoadedCallback& callback)
|
||||
const GlyphLoadedCallback& successCallback,
|
||||
const GlyphLoadingFailedCallback& failureCallback)
|
||||
: parsed(false), env(env_) {
|
||||
// Load the glyph set URL
|
||||
std::string url = util::replaceTokens(glyphURL, [&](const std::string &name) -> std::string {
|
||||
@@ -149,20 +153,20 @@ GlyphPBF::GlyphPBF(const std::string& glyphURL,
|
||||
});
|
||||
|
||||
// The prepare call jumps back to the main thread.
|
||||
req = env.request({ Resource::Kind::Glyphs, url }, [&, url, callback](const Response &res) {
|
||||
req = env.request({ Resource::Kind::Glyphs, url }, [&, url, successCallback, failureCallback](const Response &res) {
|
||||
req = nullptr;
|
||||
|
||||
if (res.status != Response::Successful) {
|
||||
// Something went wrong with loading the glyph pbf.
|
||||
const std::string msg = std::string { "[ERROR] failed to load glyphs: " } + url + " message: " + res.message;
|
||||
Log::Error(Event::HttpRequest, msg);
|
||||
std::stringstream message;
|
||||
message << "Failed to load [" << url << "]: " << res.message;
|
||||
failureCallback(message.str());
|
||||
} else {
|
||||
// Transfer the data to the GlyphSet and signal its availability.
|
||||
// Once it is available, the caller will need to call parse() to actually
|
||||
// parse the data we received. We are not doing this here since this callback is being
|
||||
// called from another (unknown) thread.
|
||||
data = res.data;
|
||||
callback(this);
|
||||
successCallback(this);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -234,8 +238,10 @@ bool GlyphPBF::isParsed() const {
|
||||
GlyphStore::GlyphStore(uv_loop_t* loop, Environment& env_)
|
||||
: env(env_),
|
||||
asyncEmitGlyphRangeLoaded(util::make_unique<uv::async>(loop, [this] { emitGlyphRangeLoaded(); })),
|
||||
asyncEmitGlyphRangeLoadedingFailed(util::make_unique<uv::async>(loop, [this] { emitGlyphRangeLoadingFailed(); })),
|
||||
observer(nullptr) {
|
||||
asyncEmitGlyphRangeLoaded->unref();
|
||||
asyncEmitGlyphRangeLoadedingFailed->unref();
|
||||
}
|
||||
|
||||
GlyphStore::~GlyphStore() {
|
||||
@@ -254,19 +260,26 @@ bool GlyphStore::requestGlyphRangesIfNeeded(const std::string& fontStackName,
|
||||
return requestIsNeeded;
|
||||
}
|
||||
|
||||
auto callback = [this, fontStackName](GlyphPBF* glyph) {
|
||||
auto successCallback = [this, fontStackName](GlyphPBF* glyph) {
|
||||
auto fontStack = createFontStack(fontStackName);
|
||||
glyph->parse(**fontStack);
|
||||
asyncEmitGlyphRangeLoaded->send();
|
||||
};
|
||||
|
||||
auto failureCallback = [this](const std::string& message) {
|
||||
std::lock_guard<std::mutex> lock(errorMessageMutex);
|
||||
errorMessage = message;
|
||||
asyncEmitGlyphRangeLoadedingFailed->send();
|
||||
};
|
||||
|
||||
std::lock_guard<std::mutex> lock(rangesMutex);
|
||||
auto& rangeSets = ranges[fontStackName];
|
||||
|
||||
for (const auto& range : glyphRanges) {
|
||||
const auto& rangeSets_it = rangeSets.find(range);
|
||||
if (rangeSets_it == rangeSets.end()) {
|
||||
auto glyph = util::make_unique<GlyphPBF>(glyphURL, fontStackName, range, env, callback);
|
||||
auto glyph = util::make_unique<GlyphPBF>(glyphURL, fontStackName, range, env,
|
||||
successCallback, failureCallback);
|
||||
rangeSets.emplace(range, std::move(glyph));
|
||||
requestIsNeeded = true;
|
||||
continue;
|
||||
@@ -312,4 +325,14 @@ void GlyphStore::emitGlyphRangeLoaded() {
|
||||
}
|
||||
}
|
||||
|
||||
void GlyphStore::emitGlyphRangeLoadingFailed() {
|
||||
if (!observer) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(errorMessageMutex);
|
||||
auto error = std::make_exception_ptr(util::GlyphRangeLoadingException(errorMessage));
|
||||
observer->onGlyphRangeLoadingFailed(error);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -59,12 +59,14 @@ private:
|
||||
class GlyphPBF {
|
||||
public:
|
||||
using GlyphLoadedCallback = std::function<void(GlyphPBF*)>;
|
||||
using GlyphLoadingFailedCallback = std::function<void(const std::string&)>;
|
||||
|
||||
GlyphPBF(const std::string &glyphURL,
|
||||
const std::string &fontStack,
|
||||
GlyphRange glyphRange,
|
||||
Environment &env,
|
||||
const GlyphLoadedCallback& callback);
|
||||
const GlyphLoadedCallback& successCallback,
|
||||
const GlyphLoadingFailedCallback& failureCallback);
|
||||
~GlyphPBF();
|
||||
|
||||
void parse(FontStack &stack);
|
||||
@@ -91,6 +93,7 @@ public:
|
||||
virtual ~Observer() = default;
|
||||
|
||||
virtual void onGlyphRangeLoaded() = 0;
|
||||
virtual void onGlyphRangeLoadingFailed(std::exception_ptr error) = 0;
|
||||
};
|
||||
|
||||
GlyphStore(uv_loop_t* loop, Environment &);
|
||||
@@ -110,6 +113,7 @@ public:
|
||||
|
||||
private:
|
||||
void emitGlyphRangeLoaded();
|
||||
void emitGlyphRangeLoadingFailed();
|
||||
|
||||
util::exclusive<FontStack> createFontStack(const std::string &fontStack);
|
||||
|
||||
@@ -122,7 +126,11 @@ private:
|
||||
std::unordered_map<std::string, std::unique_ptr<FontStack>> stacks;
|
||||
std::mutex stacksMutex;
|
||||
|
||||
std::string errorMessage;
|
||||
std::mutex errorMessageMutex;
|
||||
|
||||
std::unique_ptr<uv::async> asyncEmitGlyphRangeLoaded;
|
||||
std::unique_ptr<uv::async> asyncEmitGlyphRangeLoadedingFailed;
|
||||
|
||||
Observer* observer;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user