[core] Virtualize Source::load
This commit is contained in:
@@ -8,6 +8,10 @@ AnnotationSource::AnnotationSource()
|
||||
: Source(SourceType::Annotations, AnnotationManager::SourceID, "", util::tileSize, std::make_unique<Tileset>()) {
|
||||
}
|
||||
|
||||
void AnnotationSource::load(FileSource&) {
|
||||
loaded = true;
|
||||
}
|
||||
|
||||
std::unique_ptr<Tile> AnnotationSource::createTile(const OverscaledTileID& tileID,
|
||||
const style::UpdateParameters& parameters) {
|
||||
return std::make_unique<AnnotationTile>(tileID, id, parameters);
|
||||
|
||||
@@ -8,6 +8,8 @@ class AnnotationSource : public style::Source {
|
||||
public:
|
||||
AnnotationSource();
|
||||
|
||||
void load(FileSource&) final;
|
||||
|
||||
private:
|
||||
std::unique_ptr<Tile> createTile(const OverscaledTileID&, const style::UpdateParameters&) final;
|
||||
};
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
#include <mbgl/util/constants.hpp>
|
||||
#include <mbgl/storage/resource.hpp>
|
||||
#include <mbgl/storage/response.hpp>
|
||||
#include <mbgl/storage/file_source.hpp>
|
||||
#include <mbgl/style/layer.hpp>
|
||||
#include <mbgl/style/update_parameters.hpp>
|
||||
#include <mbgl/style/query_parameters.hpp>
|
||||
@@ -20,7 +19,6 @@
|
||||
#include <mbgl/util/tile_cover.hpp>
|
||||
#include <mbgl/util/enum.hpp>
|
||||
|
||||
#include <mbgl/style/parser.hpp>
|
||||
#include <mbgl/gl/debugging.hpp>
|
||||
|
||||
#include <mbgl/algorithm/update_renderables.hpp>
|
||||
@@ -29,10 +27,7 @@
|
||||
#include <mapbox/geojsonvt/convert.hpp>
|
||||
#include <mapbox/geometry/envelope.hpp>
|
||||
|
||||
#include <rapidjson/error/en.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
|
||||
namespace mbgl {
|
||||
namespace style {
|
||||
@@ -70,95 +65,10 @@ bool Source::isLoading() const {
|
||||
return !loaded && req.operator bool();
|
||||
}
|
||||
|
||||
void Source::load(FileSource& fileSource) {
|
||||
if (url.empty()) {
|
||||
// In case there is no URL set, we assume that we already have all of the data because the
|
||||
// TileJSON was specified inline in the stylesheet.
|
||||
loaded = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (req) {
|
||||
// We don't have a Tileset object yet, but there's already a request underway to load
|
||||
// the data.
|
||||
return;
|
||||
}
|
||||
|
||||
// URL may either be a TileJSON file, or a GeoJSON file.
|
||||
req = fileSource.request(Resource::source(url), [this](Response res) {
|
||||
if (res.error) {
|
||||
observer->onSourceError(*this, std::make_exception_ptr(std::runtime_error(res.error->message)));
|
||||
} else if (res.notModified) {
|
||||
return;
|
||||
} else if (res.noContent) {
|
||||
observer->onSourceError(*this, std::make_exception_ptr(std::runtime_error("unexpectedly empty source")));
|
||||
} else {
|
||||
bool reloadTiles = false;
|
||||
|
||||
if (type == SourceType::Vector || type == SourceType::Raster) {
|
||||
std::unique_ptr<Tileset> newTileset;
|
||||
|
||||
// Create a new copy of the Tileset object that holds the base values we've parsed
|
||||
// from the stylesheet. Then merge in the values parsed from the TileJSON we retrieved
|
||||
// via the URL.
|
||||
try {
|
||||
newTileset = style::parseTileJSON(*res.data, url, type, tileSize);
|
||||
} catch (...) {
|
||||
observer->onSourceError(*this, std::current_exception());
|
||||
return;
|
||||
}
|
||||
|
||||
// Check whether previous information specifies different tile
|
||||
if (tileset && tileset->tiles != newTileset->tiles) {
|
||||
reloadTiles = true;
|
||||
|
||||
// Tile size changed: We need to recalculate the tiles we need to load because we
|
||||
// might have to load tiles for a different zoom level
|
||||
// This is done automatically when we trigger the onSourceLoaded observer below.
|
||||
|
||||
// Min/Max zoom changed: We need to recalculate what tiles to load, if we have tiles
|
||||
// loaded that are outside the new zoom range
|
||||
// This is done automatically when we trigger the onSourceLoaded observer below.
|
||||
|
||||
// Attribution changed: We need to notify the embedding application that this
|
||||
// changed. See https://github.com/mapbox/mapbox-gl-native/issues/2723
|
||||
// This is not yet implemented.
|
||||
|
||||
// Center/bounds changed: We're not using these values currently
|
||||
}
|
||||
|
||||
tileset = std::move(newTileset);
|
||||
} else if (type == SourceType::GeoJSON) {
|
||||
std::unique_ptr<Tileset> newTileset = std::make_unique<Tileset>();
|
||||
|
||||
rapidjson::GenericDocument<rapidjson::UTF8<>, rapidjson::CrtAllocator> d;
|
||||
d.Parse<0>(res.data->c_str());
|
||||
|
||||
if (d.HasParseError()) {
|
||||
std::stringstream message;
|
||||
message << d.GetErrorOffset() << " - " << rapidjson::GetParseError_En(d.GetParseError());
|
||||
observer->onSourceError(*this, std::make_exception_ptr(std::runtime_error(message.str())));
|
||||
return;
|
||||
}
|
||||
|
||||
geojsonvt = style::parseGeoJSON(d);
|
||||
reloadTiles = true;
|
||||
|
||||
newTileset->maxZoom = geojsonvt->options.maxZoom;
|
||||
tileset = std::move(newTileset);
|
||||
}
|
||||
|
||||
if (reloadTiles) {
|
||||
// Tile information changed because we got new GeoJSON data, or a new tile URL.
|
||||
tiles.clear();
|
||||
renderTiles.clear();
|
||||
cache.clear();
|
||||
}
|
||||
|
||||
loaded = true;
|
||||
observer->onSourceLoaded(*this);
|
||||
}
|
||||
});
|
||||
void Source::invalidateTiles() {
|
||||
tiles.clear();
|
||||
renderTiles.clear();
|
||||
cache.clear();
|
||||
}
|
||||
|
||||
void Source::updateMatrices(const mat4 &projMatrix, const TransformState &transform) {
|
||||
|
||||
@@ -48,7 +48,7 @@ public:
|
||||
~Source() override;
|
||||
|
||||
bool loaded = false;
|
||||
void load(FileSource&);
|
||||
virtual void load(FileSource&) = 0;
|
||||
bool isLoading() const;
|
||||
bool isLoaded() const;
|
||||
|
||||
@@ -96,8 +96,13 @@ private:
|
||||
virtual std::unique_ptr<Tile> createTile(const OverscaledTileID&, const UpdateParameters&) = 0;
|
||||
|
||||
protected:
|
||||
void invalidateTiles();
|
||||
|
||||
std::unique_ptr<const Tileset> tileset;
|
||||
std::unique_ptr<mapbox::geojsonvt::GeoJSONVT> geojsonvt;
|
||||
std::unique_ptr<AsyncRequest> req;
|
||||
|
||||
SourceObserver* observer = nullptr;
|
||||
|
||||
private:
|
||||
// Stores the time when this source was most recently updated.
|
||||
@@ -106,10 +111,6 @@ private:
|
||||
std::map<OverscaledTileID, std::unique_ptr<Tile>> tiles;
|
||||
std::map<UnwrappedTileID, RenderTile> renderTiles;
|
||||
TileCache cache;
|
||||
|
||||
std::unique_ptr<AsyncRequest> req;
|
||||
|
||||
SourceObserver* observer = nullptr;
|
||||
};
|
||||
|
||||
} // namespace style
|
||||
|
||||
@@ -1,8 +1,15 @@
|
||||
#include <mbgl/style/sources/geojson_source.hpp>
|
||||
#include <mbgl/style/source_observer.hpp>
|
||||
#include <mbgl/style/parser.hpp>
|
||||
#include <mbgl/tile/geojson_tile.hpp>
|
||||
#include <mbgl/storage/file_source.hpp>
|
||||
|
||||
#include <mapbox/geojsonvt.hpp>
|
||||
|
||||
#include <rapidjson/error/en.h>
|
||||
|
||||
#include <sstream>
|
||||
|
||||
namespace mbgl {
|
||||
namespace style {
|
||||
|
||||
@@ -15,6 +22,49 @@ GeoJSONSource::GeoJSONSource(std::string id_,
|
||||
geojsonvt = std::move(geojsonvt_);
|
||||
}
|
||||
|
||||
void GeoJSONSource::load(FileSource& fileSource) {
|
||||
if (url.empty()) {
|
||||
// If the URL is empty, the GeoJSON was specified inline in the stylesheet.
|
||||
loaded = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (req) {
|
||||
return;
|
||||
}
|
||||
|
||||
req = fileSource.request(Resource::source(url), [this](Response res) {
|
||||
if (res.error) {
|
||||
observer->onSourceError(*this, std::make_exception_ptr(std::runtime_error(res.error->message)));
|
||||
} else if (res.notModified) {
|
||||
return;
|
||||
} else if (res.noContent) {
|
||||
observer->onSourceError(*this, std::make_exception_ptr(std::runtime_error("unexpectedly empty GeoJSON")));
|
||||
} else {
|
||||
std::unique_ptr<Tileset> newTileset = std::make_unique<Tileset>();
|
||||
|
||||
rapidjson::GenericDocument<rapidjson::UTF8<>, rapidjson::CrtAllocator> d;
|
||||
d.Parse<0>(res.data->c_str());
|
||||
|
||||
if (d.HasParseError()) {
|
||||
std::stringstream message;
|
||||
message << d.GetErrorOffset() << " - " << rapidjson::GetParseError_En(d.GetParseError());
|
||||
observer->onSourceError(*this, std::make_exception_ptr(std::runtime_error(message.str())));
|
||||
return;
|
||||
}
|
||||
|
||||
geojsonvt = style::parseGeoJSON(d);
|
||||
newTileset->maxZoom = geojsonvt->options.maxZoom;
|
||||
|
||||
invalidateTiles();
|
||||
|
||||
tileset = std::move(newTileset);
|
||||
loaded = true;
|
||||
observer->onSourceLoaded(*this);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
std::unique_ptr<Tile> GeoJSONSource::createTile(const OverscaledTileID& tileID,
|
||||
const UpdateParameters& parameters) {
|
||||
return std::make_unique<GeoJSONTile>(tileID, id, parameters, geojsonvt.get());
|
||||
|
||||
@@ -13,6 +13,8 @@ public:
|
||||
std::unique_ptr<Tileset>&&,
|
||||
std::unique_ptr<mapbox::geojsonvt::GeoJSONVT>&&);
|
||||
|
||||
void load(FileSource&) final;
|
||||
|
||||
private:
|
||||
std::unique_ptr<Tile> createTile(const OverscaledTileID&, const UpdateParameters&) final;
|
||||
};
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
#include <mbgl/style/tile_source.hpp>
|
||||
#include <mbgl/style/source_observer.hpp>
|
||||
#include <mbgl/style/parser.hpp>
|
||||
#include <mbgl/storage/file_source.hpp>
|
||||
|
||||
namespace mbgl {
|
||||
namespace style {
|
||||
@@ -11,5 +14,64 @@ TileSource::TileSource(SourceType type_,
|
||||
: Source(type_, std::move(id_), std::move(url_), tileSize_, std::move(tileset_)) {
|
||||
}
|
||||
|
||||
void TileSource::load(FileSource& fileSource) {
|
||||
if (url.empty()) {
|
||||
// If the URL is empty, the TileJSON was specified inline in the stylesheet.
|
||||
loaded = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (req) {
|
||||
return;
|
||||
}
|
||||
|
||||
// URL may either be a TileJSON file, or a GeoJSON file.
|
||||
req = fileSource.request(Resource::source(url), [this](Response res) {
|
||||
if (res.error) {
|
||||
observer->onSourceError(*this, std::make_exception_ptr(std::runtime_error(res.error->message)));
|
||||
} else if (res.notModified) {
|
||||
return;
|
||||
} else if (res.noContent) {
|
||||
observer->onSourceError(*this, std::make_exception_ptr(std::runtime_error("unexpectedly empty TileJSON")));
|
||||
} else {
|
||||
std::unique_ptr<Tileset> newTileset;
|
||||
|
||||
// Create a new copy of the Tileset object that holds the base values we've parsed
|
||||
// from the stylesheet. Then merge in the values parsed from the TileJSON we retrieved
|
||||
// via the URL.
|
||||
try {
|
||||
newTileset = style::parseTileJSON(*res.data, url, type, tileSize);
|
||||
} catch (...) {
|
||||
observer->onSourceError(*this, std::current_exception());
|
||||
return;
|
||||
}
|
||||
|
||||
// Check whether previous information specifies different tile
|
||||
if (tileset && tileset->tiles != newTileset->tiles) {
|
||||
// Tile URLs changed: force tiles to be reloaded.
|
||||
invalidateTiles();
|
||||
|
||||
// Tile size changed: We need to recalculate the tiles we need to load because we
|
||||
// might have to load tiles for a different zoom level
|
||||
// This is done automatically when we trigger the onSourceLoaded observer below.
|
||||
|
||||
// Min/Max zoom changed: We need to recalculate what tiles to load, if we have tiles
|
||||
// loaded that are outside the new zoom range
|
||||
// This is done automatically when we trigger the onSourceLoaded observer below.
|
||||
|
||||
// Attribution changed: We need to notify the embedding application that this
|
||||
// changed. See https://github.com/mapbox/mapbox-gl-native/issues/2723
|
||||
// This is not yet implemented.
|
||||
|
||||
// Center/bounds changed: We're not using these values currently
|
||||
}
|
||||
|
||||
tileset = std::move(newTileset);
|
||||
loaded = true;
|
||||
observer->onSourceLoaded(*this);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace style
|
||||
} // namespace mbgl
|
||||
|
||||
@@ -16,6 +16,8 @@ public:
|
||||
std::string url,
|
||||
uint16_t tileSize,
|
||||
std::unique_ptr<Tileset>&&);
|
||||
|
||||
void load(FileSource&) final;
|
||||
};
|
||||
|
||||
} // namespace style
|
||||
|
||||
Reference in New Issue
Block a user