diff options
author | Thiago Marcos P. Santos <thiago@mapbox.com> | 2015-05-27 18:34:06 +0300 |
---|---|---|
committer | Thiago Marcos P. Santos <thiago@mapbox.com> | 2015-05-28 09:33:08 +0300 |
commit | f8cc50683ad52cff702fb3b324502c5e792917a0 (patch) | |
tree | edd32efdce794fc7ece9dc9584452456daa5304e /src | |
parent | 48875d8d6ccabd344d95be15f8537b0c8c8f7f18 (diff) | |
download | qtlocation-mapboxgl-f8cc50683ad52cff702fb3b324502c5e792917a0.tar.gz |
Notify tile parsing errors
The tile parsing is done in a worker thread and if it fails,
we set the tile state to "obsolete" and set an error message.
When the completion callback is fired, we check for the error
message and if it is set, we emit the error signal.
The trick here is the signal cannot be emitted directly from
the worker thread because that would violate data ownership rules.
Diffstat (limited to 'src')
-rw-r--r-- | src/mbgl/map/source.cpp | 30 | ||||
-rw-r--r-- | src/mbgl/map/source.hpp | 2 | ||||
-rw-r--r-- | src/mbgl/map/tile_data.cpp | 15 | ||||
-rw-r--r-- | src/mbgl/map/tile_data.hpp | 16 | ||||
-rw-r--r-- | src/mbgl/map/vector_tile_data.cpp | 6 |
5 files changed, 50 insertions, 19 deletions
diff --git a/src/mbgl/map/source.cpp b/src/mbgl/map/source.cpp index eb273d785d..faae3285fe 100644 --- a/src/mbgl/map/source.cpp +++ b/src/mbgl/map/source.cpp @@ -287,26 +287,25 @@ TileData::State Source::addTile(MapData& data, new_tile.data = cache.get(normalized_id.to_uint64()); } - auto successCallback = std::bind(&Source::emitTileLoaded, this, true); - auto failureCallback = std::bind(&Source::emitTileLoadingFailed, this, std::placeholders::_1); - if (!new_tile.data) { + auto callback = std::bind(&Source::tileLoadingCompleteCallback, this, normalized_id); + // If we don't find working tile data, we're just going to load it. if (info.type == SourceType::Vector) { new_tile.data = std::make_shared<VectorTileData>(normalized_id, data.transform.getMaxZoom(), style, glyphAtlas, glyphStore, spriteAtlas, sprite, info); new_tile.data->request( - style.workers, transformState.getPixelRatio(), successCallback, failureCallback); + style.workers, transformState.getPixelRatio(), callback); } else if (info.type == SourceType::Raster) { new_tile.data = std::make_shared<RasterTileData>(normalized_id, texturePool, info); new_tile.data->request( - style.workers, transformState.getPixelRatio(), successCallback, failureCallback); + style.workers, transformState.getPixelRatio(), callback); } else if (info.type == SourceType::Annotations) { new_tile.data = std::make_shared<LiveTileData>(normalized_id, data.annotationManager, data.transform.getMaxZoom(), style, glyphAtlas, glyphStore, spriteAtlas, sprite, info); - new_tile.data->reparse(style.workers, successCallback); + new_tile.data->reparse(style.workers, callback); } else { throw std::runtime_error("source type not implemented"); } @@ -539,6 +538,25 @@ void Source::setObserver(Observer* observer) { observer_ = observer; } +void Source::tileLoadingCompleteCallback(const TileID& normalized_id) { + auto it = tile_data.find(normalized_id); + if (it == tile_data.end()) { + return; + } + + util::ptr<TileData> data = it->second.lock(); + if (!data) { + return; + } + + if (data->getState() == TileData::State::obsolete && !data->getError().empty()) { + emitTileLoadingFailed(data->getError()); + return; + } + + emitTileLoaded(true); +} + void Source::emitSourceLoaded() { if (observer_) { observer_->onSourceLoaded(); diff --git a/src/mbgl/map/source.hpp b/src/mbgl/map/source.hpp index d4c29b3e75..174dd996b5 100644 --- a/src/mbgl/map/source.hpp +++ b/src/mbgl/map/source.hpp @@ -104,6 +104,8 @@ public: bool enabled; private: + void tileLoadingCompleteCallback(const TileID& normalized_id); + void emitSourceLoaded(); void emitSourceLoadingFailed(const std::string& message); void emitTileLoaded(bool isNewTile); diff --git a/src/mbgl/map/tile_data.cpp b/src/mbgl/map/tile_data.cpp index be0d7d32fe..fc2d48bb5b 100644 --- a/src/mbgl/map/tile_data.cpp +++ b/src/mbgl/map/tile_data.cpp @@ -38,18 +38,18 @@ void TileData::setState(const State& state_) { void TileData::request(Worker& worker, float pixelRatio, - const std::function<void()>& successCallback, - const std::function<void(const std::string& message)>& failureCallback) { + const std::function<void()>& callback) { std::string url = source.tileURL(id, pixelRatio); state = State::loading; - req = env.request({ Resource::Kind::Tile, url }, [url, successCallback, failureCallback, &worker, this](const Response &res) { + req = env.request({ Resource::Kind::Tile, url }, [url, callback, &worker, this](const Response &res) { req = nullptr; if (res.status != Response::Successful) { std::stringstream message; message << "Failed to load [" << url << "]: " << res.message; - failureCallback(message.str()); + setError(message.str()); + callback(); return; } @@ -57,7 +57,7 @@ void TileData::request(Worker& worker, data = res.data; // Schedule tile parsing in another thread - reparse(worker, successCallback); + reparse(worker, callback); }); } @@ -88,3 +88,8 @@ bool TileData::reparse(Worker& worker, std::function<void()> callback) { workRequest = worker.send([this] { parse(); endParsing(); }, callback); return true; } + +void TileData::setError(const std::string& message) { + error = message; + setState(State::obsolete); +} diff --git a/src/mbgl/map/tile_data.hpp b/src/mbgl/map/tile_data.hpp index 0d34b2df74..d2a91b880f 100644 --- a/src/mbgl/map/tile_data.hpp +++ b/src/mbgl/map/tile_data.hpp @@ -44,10 +44,7 @@ public: TileData(const TileID&, const SourceInfo&); ~TileData(); - void request(Worker&, - float pixelRatio, - const std::function<void()>& successCallback, - const std::function<void(const std::string& message)>& failureCallback); + void request(Worker&, float pixelRatio, const std::function<void()>& callback); // Schedule a tile reparse on a worker thread and call the callback on // completion. It will return true if the work was schedule or false it was @@ -71,13 +68,20 @@ public: // We let subclasses override setState() so they // can intercept the state change and react accordingly. virtual void setState(const State& state); - inline State getState() const { return state; } void endParsing(); + // Error message to be set in case of request + // and parsing errors. + void setError(const std::string& message); + + std::string getError() const { + return error; + } + // Override this in the child class. virtual void parse() = 0; virtual Bucket* getBucket(StyleLayer const &layer_desc) = 0; @@ -106,6 +110,8 @@ protected: private: std::atomic<State> state; + std::string error; + protected: // Contains the tile ID string for painting debug information. DebugFontBuffer debugFontBuffer; diff --git a/src/mbgl/map/vector_tile_data.cpp b/src/mbgl/map/vector_tile_data.cpp index 4d77c8ef81..e464c55c90 100644 --- a/src/mbgl/map/vector_tile_data.cpp +++ b/src/mbgl/map/vector_tile_data.cpp @@ -59,9 +59,9 @@ void VectorTileData::parse() { setState(State::parsed); } } catch (const std::exception& ex) { - Log::Error(Event::ParseTile, "Parsing [%d/%d/%d] failed: %s", id.z, id.x, id.y, ex.what()); - setState(State::obsolete); - return; + std::stringstream message; + message << "Failed to parse [" << int(id.z) << "/" << id.x << "/" << id.y << "]: " << ex.what(); + setError(message.str()); } } |