diff --git a/src/mbgl/annotation/annotation_source.cpp b/src/mbgl/annotation/annotation_source.cpp index 50fa7a2c0..aa52e2e43 100644 --- a/src/mbgl/annotation/annotation_source.cpp +++ b/src/mbgl/annotation/annotation_source.cpp @@ -8,6 +8,10 @@ AnnotationSource::AnnotationSource() : Source(SourceType::Annotations, AnnotationManager::SourceID, "", util::tileSize, std::make_unique()) { } +void AnnotationSource::load(FileSource&) { + loaded = true; +} + std::unique_ptr AnnotationSource::createTile(const OverscaledTileID& tileID, const style::UpdateParameters& parameters) { return std::make_unique(tileID, id, parameters); diff --git a/src/mbgl/annotation/annotation_source.hpp b/src/mbgl/annotation/annotation_source.hpp index 033580b64..565b9273d 100644 --- a/src/mbgl/annotation/annotation_source.hpp +++ b/src/mbgl/annotation/annotation_source.hpp @@ -8,6 +8,8 @@ class AnnotationSource : public style::Source { public: AnnotationSource(); + void load(FileSource&) final; + private: std::unique_ptr createTile(const OverscaledTileID&, const style::UpdateParameters&) final; }; diff --git a/src/mbgl/style/source.cpp b/src/mbgl/style/source.cpp index 35acf3dd5..41c1d0d22 100644 --- a/src/mbgl/style/source.cpp +++ b/src/mbgl/style/source.cpp @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include @@ -20,7 +19,6 @@ #include #include -#include #include #include @@ -29,10 +27,7 @@ #include #include -#include - #include -#include 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 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 newTileset = std::make_unique(); - - rapidjson::GenericDocument, 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) { diff --git a/src/mbgl/style/source.hpp b/src/mbgl/style/source.hpp index 51a9ba5c7..92ca808af 100644 --- a/src/mbgl/style/source.hpp +++ b/src/mbgl/style/source.hpp @@ -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 createTile(const OverscaledTileID&, const UpdateParameters&) = 0; protected: + void invalidateTiles(); + std::unique_ptr tileset; std::unique_ptr geojsonvt; + std::unique_ptr req; + + SourceObserver* observer = nullptr; private: // Stores the time when this source was most recently updated. @@ -106,10 +111,6 @@ private: std::map> tiles; std::map renderTiles; TileCache cache; - - std::unique_ptr req; - - SourceObserver* observer = nullptr; }; } // namespace style diff --git a/src/mbgl/style/sources/geojson_source.cpp b/src/mbgl/style/sources/geojson_source.cpp index caedcffcd..6ece894e2 100644 --- a/src/mbgl/style/sources/geojson_source.cpp +++ b/src/mbgl/style/sources/geojson_source.cpp @@ -1,8 +1,15 @@ #include +#include +#include #include +#include #include +#include + +#include + 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 newTileset = std::make_unique(); + + rapidjson::GenericDocument, 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 GeoJSONSource::createTile(const OverscaledTileID& tileID, const UpdateParameters& parameters) { return std::make_unique(tileID, id, parameters, geojsonvt.get()); diff --git a/src/mbgl/style/sources/geojson_source.hpp b/src/mbgl/style/sources/geojson_source.hpp index c9262f22b..47984ff9d 100644 --- a/src/mbgl/style/sources/geojson_source.hpp +++ b/src/mbgl/style/sources/geojson_source.hpp @@ -13,6 +13,8 @@ public: std::unique_ptr&&, std::unique_ptr&&); + void load(FileSource&) final; + private: std::unique_ptr createTile(const OverscaledTileID&, const UpdateParameters&) final; }; diff --git a/src/mbgl/style/tile_source.cpp b/src/mbgl/style/tile_source.cpp index 22739035a..90f4b54d9 100644 --- a/src/mbgl/style/tile_source.cpp +++ b/src/mbgl/style/tile_source.cpp @@ -1,4 +1,7 @@ #include +#include +#include +#include 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 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 diff --git a/src/mbgl/style/tile_source.hpp b/src/mbgl/style/tile_source.hpp index 8c69ad451..dc48080ea 100644 --- a/src/mbgl/style/tile_source.hpp +++ b/src/mbgl/style/tile_source.hpp @@ -16,6 +16,8 @@ public: std::string url, uint16_t tileSize, std::unique_ptr&&); + + void load(FileSource&) final; }; } // namespace style