diff options
author | John Firebaugh <john.firebaugh@gmail.com> | 2016-06-23 12:00:25 -0700 |
---|---|---|
committer | John Firebaugh <john.firebaugh@gmail.com> | 2016-06-24 09:39:51 -0700 |
commit | 021d4199cb9ee754e9f0f5bc42f7f75285afd405 (patch) | |
tree | 9396f291348c0ab5f3a75e1a217a78fc4dbff4b2 | |
parent | 16c435b1517b15a5ea8654987979ef58800b838b (diff) | |
download | qtlocation-mapboxgl-021d4199cb9ee754e9f0f5bc42f7f75285afd405.tar.gz |
[core, node] Implement bindings for addSource
24 files changed, 360 insertions, 250 deletions
diff --git a/include/mbgl/style/conversion.hpp b/include/mbgl/style/conversion.hpp index 2cb3ced376..bd7db3adfb 100644 --- a/include/mbgl/style/conversion.hpp +++ b/include/mbgl/style/conversion.hpp @@ -83,9 +83,9 @@ public: template <class T, class Enable = void> struct Converter; -template <class T, class V> -Result<T> convert(const V& value) { - return Converter<T>()(value); +template <class T, class V, class...Args> +Result<T> convert(const V& value, Args&&...args) { + return Converter<T>()(value, std::forward<Args>(args)...); } } // namespace conversion diff --git a/include/mbgl/style/conversion/geojson.hpp b/include/mbgl/style/conversion/geojson.hpp new file mode 100644 index 0000000000..ba10b3ecc8 --- /dev/null +++ b/include/mbgl/style/conversion/geojson.hpp @@ -0,0 +1,15 @@ +#pragma once + +#include <mbgl/style/conversion.hpp> +#include <mbgl/style/sources/geojson_source.hpp> + +namespace mbgl { +namespace style { +namespace conversion { + +template <class V> +Result<GeoJSON> convertGeoJSON(const V& value); + +} // namespace conversion +} // namespace style +} // namespace mbgl diff --git a/include/mbgl/style/conversion/source.hpp b/include/mbgl/style/conversion/source.hpp new file mode 100644 index 0000000000..00c6afb9fe --- /dev/null +++ b/include/mbgl/style/conversion/source.hpp @@ -0,0 +1,123 @@ +#pragma once + +#include <mbgl/style/source.hpp> +#include <mbgl/style/sources/geojson_source.hpp> +#include <mbgl/style/sources/raster_source.hpp> +#include <mbgl/style/sources/vector_source.hpp> +#include <mbgl/style/conversion.hpp> +#include <mbgl/style/conversion/tileset.hpp> +#include <mbgl/style/conversion/geojson.hpp> + +namespace mbgl { +namespace style { +namespace conversion { + +template <> +struct Converter<std::unique_ptr<Source>> { +public: + template <class V> + Result<std::unique_ptr<Source>> operator()(const V& value, const std::string& id) const { + if (!isObject(value)) { + return Error { "source must be an object" }; + } + + auto typeValue = objectMember(value, "type"); + if (!typeValue) { + return Error { "source must have a type" }; + } + + optional<std::string> type = toString(*typeValue); + if (!type) { + return Error { "source type must be a string" }; + } + + if (*type == "raster") { + return convertRasterSource(id, value); + } else if (*type == "vector") { + return convertVectorSource(id, value); + } else if (*type == "geojson") { + return convertGeoJSONSource(id, value); + } else { + return Error { "invalid source type" }; + } + } + +private: + // A tile source can either specify a URL to TileJSON, or inline TileJSON. + template <class V> + Result<variant<std::string, Tileset>> convertURLOrTileset(const V& value) const { + auto urlVal = objectMember(value, "url"); + if (!urlVal) { + Result<Tileset> tileset = convert<Tileset>(value); + if (!tileset) { + return tileset.error(); + } + return *tileset; + } + + optional<std::string> url = toString(*urlVal); + if (!url) { + return Error { "source url must be a string" }; + } + + return *url; + } + + template <class V> + Result<std::unique_ptr<Source>> convertRasterSource(const std::string& id, const V& value) const { + Result<variant<std::string, Tileset>> urlOrTileset = convertURLOrTileset(value); + if (!urlOrTileset) { + return urlOrTileset.error(); + } + + uint16_t tileSize = util::tileSize; + auto tileSizeValue = objectMember(value, "tileSize"); + if (tileSizeValue) { + optional<float> size = toNumber(*tileSizeValue); + if (!size || *size < 0 || *size > std::numeric_limits<uint16_t>::max()) { + return Error { "invalid tileSize" }; + } + tileSize = *size; + } + + return std::make_unique<RasterSource>(id, std::move(*urlOrTileset), tileSize); + } + + template <class V> + Result<std::unique_ptr<Source>> convertVectorSource(const std::string& id, const V& value) const { + Result<variant<std::string, Tileset>> urlOrTileset = convertURLOrTileset(value); + if (!urlOrTileset) { + return urlOrTileset.error(); + } + + return std::make_unique<VectorSource>(id, std::move(*urlOrTileset)); + } + + template <class V> + Result<std::unique_ptr<Source>> convertGeoJSONSource(const std::string& id, const V& value) const { + auto dataValue = objectMember(value, "data"); + if (!dataValue) { + return Error { "GeoJSON source must have a data value" }; + } + + auto result = std::make_unique<GeoJSONSource>(id); + + if (isObject(*dataValue)) { + Result<GeoJSON> geoJSON = convertGeoJSON(*dataValue); + if (!geoJSON) { + return geoJSON.error(); + } + result->setGeoJSON(std::move(*geoJSON)); + } else if (toString(*dataValue)) { + result->setURL(*toString(*dataValue)); + } else { + return Error { "GeoJSON data must be a URL or an object" }; + } + + return std::move(result); + } +}; + +} // namespace conversion +} // namespace style +} // namespace mbgl diff --git a/include/mbgl/style/conversion/tileset.hpp b/include/mbgl/style/conversion/tileset.hpp new file mode 100644 index 0000000000..46425597af --- /dev/null +++ b/include/mbgl/style/conversion/tileset.hpp @@ -0,0 +1,67 @@ +#pragma once + +#include <mbgl/util/tileset.hpp> +#include <mbgl/style/conversion.hpp> + +namespace mbgl { +namespace style { +namespace conversion { + +template <> +struct Converter<Tileset> { +public: + template <class V> + Result<Tileset> operator()(const V& value) const { + Tileset result; + + auto tiles = objectMember(value, "tiles"); + if (!tiles) { + return Error { "source must have tiles" }; + } + + if (!isArray(*tiles)) { + return Error { "source tiles must be an array" }; + } + + for (std::size_t i = 0; i < arrayLength(*tiles); i++) { + optional<std::string> urlTemplate = toString(arrayMember(*tiles, i)); + if (!urlTemplate) { + return Error { "source tiles member must be a string" }; + } + result.tiles.push_back(std::move(*urlTemplate)); + } + + auto minzoomValue = objectMember(value, "minzoom"); + if (minzoomValue) { + optional<float> minzoom = toNumber(*minzoomValue); + if (!minzoom || *minzoom < 0 || *minzoom > std::numeric_limits<uint8_t>::max()) { + return Error { "invalid minzoom" }; + } + result.zoomRange.min = *minzoom; + } + + auto maxzoomValue = objectMember(value, "maxzoom"); + if (maxzoomValue) { + optional<float> maxzoom = toNumber(*maxzoomValue); + if (!maxzoom || *maxzoom < 0 || *maxzoom > std::numeric_limits<uint8_t>::max()) { + return Error { "invalid maxzoom" }; + } + result.zoomRange.max = *maxzoom; + } + + auto attributionValue = objectMember(value, "attribution"); + if (attributionValue) { + optional<std::string> attribution = toString(*attributionValue); + if (!attribution) { + return Error { "source attribution must be a string" }; + } + result.attribution = std::move(*attribution); + } + + return result; + } +}; + +} // namespace conversion +} // namespace style +} // namespace mbgl diff --git a/include/mbgl/style/sources/geojson_source.hpp b/include/mbgl/style/sources/geojson_source.hpp index 96b9a99606..3736dd44bc 100644 --- a/include/mbgl/style/sources/geojson_source.hpp +++ b/include/mbgl/style/sources/geojson_source.hpp @@ -1,26 +1,22 @@ #pragma once #include <mbgl/style/source.hpp> +#include <mbgl/util/geojson.hpp> namespace mbgl { namespace style { class GeoJSONSource : public Source { public: - // Future public API: - // void setData(FeatureCollection&&); - // void setJSON(const std::string& json); - // void loadData(const std::string& url); + GeoJSONSource(const std::string& id); + void setURL(const std::string& url); + void setGeoJSON(GeoJSON&&); // Private implementation class Impl; - - template <class Fn> - GeoJSONSource(Fn&& fn) - : Source(SourceType::GeoJSON, fn(*this)) { - } + Impl* const impl; }; } // namespace style diff --git a/include/mbgl/util/geojson.hpp b/include/mbgl/util/geojson.hpp new file mode 100644 index 0000000000..3fd8c6ac4b --- /dev/null +++ b/include/mbgl/util/geojson.hpp @@ -0,0 +1,22 @@ +#pragma once + +#include <memory> + +namespace mapbox { +namespace geojsonvt { +class GeoJSONVT; +} // namespace geojsonvt +} // namespace mapbox + +namespace mbgl { + +class GeoJSON { +public: + GeoJSON(std::unique_ptr<mapbox::geojsonvt::GeoJSONVT>); + GeoJSON(GeoJSON&&); + ~GeoJSON(); + + std::unique_ptr<mapbox::geojsonvt::GeoJSONVT> impl; +}; + +} // namespace mbgl diff --git a/package.json b/package.json index 97edceb9c9..4ca0cd119a 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "express": "^4.11.1", "mapbox-gl-shaders": "mapbox/mapbox-gl-shaders#59e998295d548f208ee3ec10cdd21ff2630e2079", "mapbox-gl-style-spec": "mapbox/mapbox-gl-style-spec#194fc55b6a7dd54c1e2cf2dd9048fbb5e836716d", - "mapbox-gl-test-suite": "mapbox/mapbox-gl-test-suite#1633d164231dddf006777366de82178bf34fe866", + "mapbox-gl-test-suite": "mapbox/mapbox-gl-test-suite#cb733d358a95d46344c2212f1546ed94022718f7", "node-gyp": "^3.3.1", "request": "^2.72.0", "tape": "^4.5.1" diff --git a/platform/default/mbgl/storage/offline_download.cpp b/platform/default/mbgl/storage/offline_download.cpp index 2aaeb30fab..bad23cadbe 100644 --- a/platform/default/mbgl/storage/offline_download.cpp +++ b/platform/default/mbgl/storage/offline_download.cpp @@ -127,7 +127,7 @@ OfflineRegionStatus OfflineDownload::getStatus() const { case SourceType::GeoJSON: { style::GeoJSONSource::Impl* geojsonSource = static_cast<style::GeoJSONSource::Impl*>(source->baseImpl.get()); - const variant<std::string, style::GeoJSONSource::Impl::GeoJSON>& urlOrGeoJSON = geojsonSource->getURLOrGeoJSON(); + const variant<std::string, GeoJSON>& urlOrGeoJSON = geojsonSource->getURLOrGeoJSON(); if (urlOrGeoJSON.is<std::string>()) { result.requiredResourceCount += 1; @@ -190,7 +190,7 @@ void OfflineDownload::activateDownload() { case SourceType::GeoJSON: { style::GeoJSONSource::Impl* geojsonSource = static_cast<style::GeoJSONSource::Impl*>(source->baseImpl.get()); - const variant<std::string, style::GeoJSONSource::Impl::GeoJSON>& urlOrGeoJSON = geojsonSource->getURLOrGeoJSON(); + const variant<std::string, GeoJSON>& urlOrGeoJSON = geojsonSource->getURLOrGeoJSON(); if (urlOrGeoJSON.is<std::string>()) { ensureResource(Resource::source(urlOrGeoJSON.get<std::string>())); diff --git a/platform/node/src/node_geojson.hpp b/platform/node/src/node_geojson.hpp new file mode 100644 index 0000000000..ace4c91426 --- /dev/null +++ b/platform/node/src/node_geojson.hpp @@ -0,0 +1,14 @@ +#include <mbgl/style/conversion/geojson.hpp> + +namespace mbgl { +namespace style { +namespace conversion { + +template <> +Result<GeoJSON> convertGeoJSON(const v8::Local<v8::Value>&) { + return Error { "not implemented" }; +} + +} // namespace conversion +} // namespace style +} // namespace mbgl diff --git a/platform/node/src/node_map.cpp b/platform/node/src/node_map.cpp index c73d3850f2..7bcdd9cdda 100644 --- a/platform/node/src/node_map.cpp +++ b/platform/node/src/node_map.cpp @@ -2,9 +2,11 @@ #include "node_request.hpp" #include "node_feature.hpp" #include "node_conversion.hpp" +#include "node_geojson.hpp" #include <mbgl/platform/default/headless_display.hpp> #include <mbgl/util/exception.hpp> +#include <mbgl/style/conversion/source.hpp> #include <mbgl/style/conversion/layer.hpp> #include <mbgl/style/conversion/filter.hpp> @@ -56,6 +58,7 @@ NAN_MODULE_INIT(NodeMap::Init) { Nan::SetPrototypeMethod(tpl, "release", Release); Nan::SetPrototypeMethod(tpl, "addClass", AddClass); + Nan::SetPrototypeMethod(tpl, "addSource", AddSource); Nan::SetPrototypeMethod(tpl, "addLayer", AddLayer); Nan::SetPrototypeMethod(tpl, "setLayoutProperty", SetLayoutProperty); Nan::SetPrototypeMethod(tpl, "setPaintProperty", SetPaintProperty); @@ -484,6 +487,30 @@ NAN_METHOD(NodeMap::AddClass) { info.GetReturnValue().SetUndefined(); } +NAN_METHOD(NodeMap::AddSource) { + using namespace mbgl::style; + using namespace mbgl::style::conversion; + + auto nodeMap = Nan::ObjectWrap::Unwrap<NodeMap>(info.Holder()); + if (!nodeMap->map) return Nan::ThrowError(releasedMessage()); + + if (info.Length() != 2) { + return Nan::ThrowTypeError("Two argument required"); + } + + if (!info[0]->IsString()) { + return Nan::ThrowTypeError("First argument must be a string"); + } + + Result<std::unique_ptr<Source>> source = convert<std::unique_ptr<Source>>(info[1], *Nan::Utf8String(info[0])); + if (!source) { + Nan::ThrowTypeError(source.error().message); + return; + } + + nodeMap->map->addSource(std::move(*source)); +} + NAN_METHOD(NodeMap::AddLayer) { using namespace mbgl::style; using namespace mbgl::style::conversion; diff --git a/platform/node/src/node_map.hpp b/platform/node/src/node_map.hpp index 8e4b073134..d64d58013d 100644 --- a/platform/node/src/node_map.hpp +++ b/platform/node/src/node_map.hpp @@ -26,6 +26,7 @@ public: static NAN_METHOD(Render); static NAN_METHOD(Release); static NAN_METHOD(AddClass); + static NAN_METHOD(AddSource); static NAN_METHOD(AddLayer); static NAN_METHOD(SetLayoutProperty); static NAN_METHOD(SetPaintProperty); diff --git a/src/mbgl/style/parser.cpp b/src/mbgl/style/parser.cpp index ac263dbc57..41b23c1bae 100644 --- a/src/mbgl/style/parser.cpp +++ b/src/mbgl/style/parser.cpp @@ -1,23 +1,13 @@ #include <mbgl/style/parser.hpp> -#include <mbgl/style/sources/raster_source_impl.hpp> -#include <mbgl/style/sources/vector_source_impl.hpp> -#include <mbgl/style/sources/geojson_source_impl.hpp> #include <mbgl/style/layer_impl.hpp> -#include <mbgl/style/layers/fill_layer.hpp> -#include <mbgl/style/layers/line_layer.hpp> -#include <mbgl/style/layers/circle_layer.hpp> -#include <mbgl/style/layers/symbol_layer.hpp> -#include <mbgl/style/layers/raster_layer.hpp> -#include <mbgl/style/layers/background_layer.hpp> #include <mbgl/style/rapidjson_conversion.hpp> #include <mbgl/style/conversion.hpp> +#include <mbgl/style/conversion/source.hpp> #include <mbgl/style/conversion/layer.hpp> #include <mbgl/platform/log.hpp> -#include <mbgl/tile/geometry_tile_data.hpp> -#include <mbgl/util/enum.hpp> -#include <mbgl/util/tileset.hpp> +#include <mapbox/geojsonvt.hpp> #include <rapidjson/document.h> #include <rapidjson/error/en.h> @@ -75,54 +65,18 @@ void Parser::parseSources(const JSValue& value) { return; } - JSValue::ConstMemberIterator itr = value.MemberBegin(); - for (; itr != value.MemberEnd(); ++itr) { - const JSValue& nameVal = itr->name; - const JSValue& sourceVal = itr->value; + for (auto it = value.MemberBegin(); it != value.MemberEnd(); ++it) { + std::string id = *conversion::toString(it->name); - if (!sourceVal.HasMember("type")) { - Log::Warning(Event::ParseStyle, "source must have a type"); + conversion::Result<std::unique_ptr<Source>> source + = conversion::convert<std::unique_ptr<Source>>(it->value, id); + if (!source) { + Log::Warning(Event::ParseStyle, source.error().message); continue; } - const JSValue& typeVal = sourceVal["type"]; - if (!typeVal.IsString()) { - Log::Warning(Event::ParseStyle, "source type must be a string"); - continue; - } - - const auto type = Enum<SourceType>::toEnum({ typeVal.GetString(), typeVal.GetStringLength() }); - if (!type) { - Log::Warning(Event::ParseStyle, "source type must have one of the enum values"); - continue; - } - - const std::string id { nameVal.GetString(), nameVal.GetStringLength() }; - std::unique_ptr<Source> source; - - switch (*type) { - case SourceType::Raster: { - source = RasterSource::Impl::parse(id, sourceVal); - break; - } - - case SourceType::Vector: - source = VectorSource::Impl::parse(id, sourceVal); - break; - - case SourceType::GeoJSON: - source = GeoJSONSource::Impl::parse(id, sourceVal); - break; - - default: - Log::Error(Event::ParseStyle, "source type '%s' is not supported", typeVal.GetString()); - continue; - } - - if (source) { - sourcesMap.emplace(id, source.get()); - sources.emplace_back(std::move(source)); - } + sourcesMap.emplace(id, (*source).get()); + sources.emplace_back(std::move(*source)); } } diff --git a/src/mbgl/style/sources/geojson_source.cpp b/src/mbgl/style/sources/geojson_source.cpp index b5932581dd..a3eec4f4ef 100644 --- a/src/mbgl/style/sources/geojson_source.cpp +++ b/src/mbgl/style/sources/geojson_source.cpp @@ -4,5 +4,18 @@ namespace mbgl { namespace style { +GeoJSONSource::GeoJSONSource(const std::string& id) + : Source(SourceType::GeoJSON, std::make_unique<GeoJSONSource::Impl>(std::move(id), *this)) + , impl(static_cast<Impl*>(baseImpl.get())) { +} + +void GeoJSONSource::setURL(const std::string& url) { + impl->setURL(url); +} + +void GeoJSONSource::setGeoJSON(GeoJSON&& geoJSON) { + impl->setGeoJSON(std::move(geoJSON)); +} + } // namespace style } // namespace mbgl diff --git a/src/mbgl/style/sources/geojson_source_impl.cpp b/src/mbgl/style/sources/geojson_source_impl.cpp index f58e0fc62b..b9744d193a 100644 --- a/src/mbgl/style/sources/geojson_source_impl.cpp +++ b/src/mbgl/style/sources/geojson_source_impl.cpp @@ -1,9 +1,10 @@ #include <mbgl/style/sources/geojson_source_impl.hpp> #include <mbgl/style/source_observer.hpp> -#include <mbgl/style/parser.hpp> +#include <mbgl/style/conversion/geojson.hpp> #include <mbgl/tile/geojson_tile.hpp> #include <mbgl/storage/file_source.hpp> #include <mbgl/platform/log.hpp> +#include <mbgl/util/rapidjson.hpp> #include <mapbox/geojsonvt.hpp> #include <mapbox/geojsonvt/convert.hpp> @@ -12,56 +13,38 @@ #include <sstream> +using namespace mapbox::geojsonvt; + namespace mbgl { namespace style { - -std::unique_ptr<mapbox::geojsonvt::GeoJSONVT> GeoJSONSource::Impl::parseGeoJSON(const JSValue& value) { - using namespace mapbox::geojsonvt; - +namespace conversion { +template <> +Result<GeoJSON> convertGeoJSON(const JSValue& value) { Options options; options.buffer = util::EXTENT / util::tileSize * 128; options.extent = util::EXTENT; try { - return std::make_unique<GeoJSONVT>(Convert::convert(value, 0), options); + return GeoJSON { std::make_unique<GeoJSONVT>(Convert::convert(value, 0), options) }; } catch (const std::exception& ex) { - Log::Error(Event::ParseStyle, "Failed to parse GeoJSON data: %s", ex.what()); - // Create an empty GeoJSON VT object to make sure we're not infinitely waiting for - // tiles to load. - return std::make_unique<GeoJSONVT>(std::vector<ProjectedFeature>{}, options); + return Error { ex.what() }; } } +} // namespace conversion -std::unique_ptr<GeoJSONSource> GeoJSONSource::Impl::parse(const std::string& id, const JSValue& value) { - // We should probably split this up to have URLs in the url property, and actual data - // in the data property. Until then, we're going to detect the content based on the - // object type. - if (!value.HasMember("data")) { - Log::Error(Event::ParseStyle, "GeoJSON source must have a data value"); - return nullptr; - } - - const JSValue& dataVal = value["data"]; - if (dataVal.IsString()) { - return std::make_unique<GeoJSONSource>([&] (Source& base) { - return std::make_unique<Impl>(id, base, std::string(dataVal.GetString(), dataVal.GetStringLength())); - }); - } else if (dataVal.IsObject()) { - return std::make_unique<GeoJSONSource>([&] (Source& base) { - return std::make_unique<Impl>(id, base, parseGeoJSON(dataVal)); - }); - } else { - Log::Error(Event::ParseStyle, "GeoJSON data must be a URL or an object"); - return nullptr; - } +GeoJSONSource::Impl::Impl(std::string id_, Source& base_) + : Source::Impl(SourceType::GeoJSON, std::move(id_), base_) { } -GeoJSONSource::Impl::Impl(std::string id_, Source& base_, variant<std::string, GeoJSON> urlOrGeoJSON_) - : Source::Impl(SourceType::GeoJSON, std::move(id_), base_), - urlOrGeoJSON(std::move(urlOrGeoJSON_)) { +GeoJSONSource::Impl::~Impl() = default; + +void GeoJSONSource::Impl::setURL(std::string url) { + urlOrGeoJSON = std::move(url); } -GeoJSONSource::Impl::~Impl() = default; +void GeoJSONSource::Impl::setGeoJSON(GeoJSON&& geoJSON) { + urlOrGeoJSON = std::move(geoJSON); +} void GeoJSONSource::Impl::load(FileSource& fileSource) { if (urlOrGeoJSON.is<GeoJSON>()) { @@ -94,9 +77,17 @@ void GeoJSONSource::Impl::load(FileSource& fileSource) { invalidateTiles(); - urlOrGeoJSON = parseGeoJSON(d); - loaded = true; + conversion::Result<GeoJSON> geoJSON = conversion::convertGeoJSON<JSValue>(d); + if (!geoJSON) { + Log::Error(Event::ParseStyle, "Failed to parse GeoJSON data: %s", geoJSON.error().message); + // Create an empty GeoJSON VT object to make sure we're not infinitely waiting for + // tiles to load. + urlOrGeoJSON = GeoJSON { std::make_unique<GeoJSONVT>(std::vector<ProjectedFeature>()) }; + } else { + urlOrGeoJSON = std::move(*geoJSON); + } + loaded = true; observer->onSourceLoaded(base); } }); @@ -104,13 +95,13 @@ void GeoJSONSource::Impl::load(FileSource& fileSource) { Range<uint8_t> GeoJSONSource::Impl::getZoomRange() { assert(loaded); - return { 0, urlOrGeoJSON.get<GeoJSON>()->options.maxZoom }; + return { 0, urlOrGeoJSON.get<GeoJSON>().impl->options.maxZoom }; } std::unique_ptr<Tile> GeoJSONSource::Impl::createTile(const OverscaledTileID& tileID, - const UpdateParameters& parameters) { + const UpdateParameters& parameters) { assert(loaded); - return std::make_unique<GeoJSONTile>(tileID, base.getID(), parameters, *urlOrGeoJSON.get<GeoJSON>()); + return std::make_unique<GeoJSONTile>(tileID, base.getID(), parameters, *urlOrGeoJSON.get<GeoJSON>().impl); } } // namespace style diff --git a/src/mbgl/style/sources/geojson_source_impl.hpp b/src/mbgl/style/sources/geojson_source_impl.hpp index 350045b27c..e6e01c06e9 100644 --- a/src/mbgl/style/sources/geojson_source_impl.hpp +++ b/src/mbgl/style/sources/geojson_source_impl.hpp @@ -2,15 +2,8 @@ #include <mbgl/style/sources/geojson_source.hpp> #include <mbgl/style/source_impl.hpp> -#include <mbgl/util/rapidjson.hpp> #include <mbgl/util/variant.hpp> -namespace mapbox { -namespace geojsonvt { -class GeoJSONVT; -} // namespace geojsonvt -} // namespace mapbox - namespace mbgl { class AsyncRequest; @@ -19,15 +12,12 @@ namespace style { class GeoJSONSource::Impl : public Source::Impl { public: - using GeoJSON = std::unique_ptr<mapbox::geojsonvt::GeoJSONVT>; - - static std::unique_ptr<GeoJSONSource> parse(const std::string& id, const JSValue&); - static GeoJSON parseGeoJSON(const JSValue&); - - Impl(std::string id, Source&, - variant<std::string, GeoJSON> urlOrGeoJSON); + Impl(std::string id, Source&); ~Impl() final; + void setURL(std::string); + void setGeoJSON(GeoJSON&&); + void load(FileSource&) final; uint16_t getTileSize() const final { diff --git a/src/mbgl/style/sources/raster_source_impl.cpp b/src/mbgl/style/sources/raster_source_impl.cpp index a6e19b4757..b727651260 100644 --- a/src/mbgl/style/sources/raster_source_impl.cpp +++ b/src/mbgl/style/sources/raster_source_impl.cpp @@ -1,30 +1,9 @@ #include <mbgl/style/sources/raster_source_impl.hpp> #include <mbgl/tile/raster_tile.hpp> -#include <mbgl/platform/log.hpp> namespace mbgl { namespace style { -std::unique_ptr<RasterSource> RasterSource::Impl::parse(std::string id, const JSValue& value) { - optional<variant<std::string, Tileset>> urlOrTileset = TileSourceImpl::parseURLOrTileset(value); - if (!urlOrTileset) { - return nullptr; - } - - uint16_t tileSize = util::tileSize; - if (value.HasMember("tileSize")) { - const JSValue& tileSizeVal = value["tileSize"]; - if (tileSizeVal.IsNumber() && tileSizeVal.GetUint64() <= std::numeric_limits<uint16_t>::max()) { - tileSize = tileSizeVal.GetUint64(); - } else { - Log::Error(Event::ParseStyle, "invalid tileSize"); - return nullptr; - } - } - - return std::make_unique<RasterSource>(std::move(id), std::move(*urlOrTileset), tileSize); -} - RasterSource::Impl::Impl(std::string id_, Source& base_, variant<std::string, Tileset> urlOrTileset_, uint16_t tileSize_) diff --git a/src/mbgl/style/sources/raster_source_impl.hpp b/src/mbgl/style/sources/raster_source_impl.hpp index 2222b13082..6f34a050bb 100644 --- a/src/mbgl/style/sources/raster_source_impl.hpp +++ b/src/mbgl/style/sources/raster_source_impl.hpp @@ -8,8 +8,6 @@ namespace style { class RasterSource::Impl : public TileSourceImpl { public: - static std::unique_ptr<RasterSource> parse(std::string id, const JSValue&); - Impl(std::string id, Source&, variant<std::string, Tileset>, uint16_t tileSize); private: diff --git a/src/mbgl/style/sources/vector_source_impl.cpp b/src/mbgl/style/sources/vector_source_impl.cpp index 28e14f3e16..efe8afbbea 100644 --- a/src/mbgl/style/sources/vector_source_impl.cpp +++ b/src/mbgl/style/sources/vector_source_impl.cpp @@ -4,14 +4,6 @@ namespace mbgl { namespace style { -std::unique_ptr<VectorSource> VectorSource::Impl::parse(std::string id, const JSValue& value) { - optional<variant<std::string, Tileset>> urlOrTileset = TileSourceImpl::parseURLOrTileset(value); - if (!urlOrTileset) { - return nullptr; - } - return std::make_unique<VectorSource>(std::move(id), std::move(*urlOrTileset)); -} - VectorSource::Impl::Impl(std::string id_, Source& base_, variant<std::string, Tileset> urlOrTileset_) : TileSourceImpl(SourceType::Vector, std::move(id_), base_, std::move(urlOrTileset_), util::tileSize) { } diff --git a/src/mbgl/style/sources/vector_source_impl.hpp b/src/mbgl/style/sources/vector_source_impl.hpp index 4a6703e5c0..6726fa6955 100644 --- a/src/mbgl/style/sources/vector_source_impl.hpp +++ b/src/mbgl/style/sources/vector_source_impl.hpp @@ -8,8 +8,6 @@ namespace style { class VectorSource::Impl : public TileSourceImpl { public: - static std::unique_ptr<VectorSource> parse(std::string id, const JSValue&); - Impl(std::string id, Source&, variant<std::string, Tileset>); private: diff --git a/src/mbgl/style/tile_source_impl.cpp b/src/mbgl/style/tile_source_impl.cpp index 634ef39808..3999a88a07 100644 --- a/src/mbgl/style/tile_source_impl.cpp +++ b/src/mbgl/style/tile_source_impl.cpp @@ -1,10 +1,10 @@ #include <mbgl/style/tile_source_impl.hpp> #include <mbgl/style/source_observer.hpp> -#include <mbgl/style/parser.hpp> +#include <mbgl/style/rapidjson_conversion.hpp> +#include <mbgl/style/conversion/tileset.hpp> #include <mbgl/util/tileset.hpp> #include <mbgl/util/mapbox.hpp> #include <mbgl/storage/file_source.hpp> -#include <mbgl/platform/log.hpp> #include <rapidjson/document.h> #include <rapidjson/error/en.h> @@ -14,73 +14,6 @@ namespace mbgl { namespace style { -namespace { - -void parseTileJSONMember(const JSValue& value, std::vector<std::string>& target, const char* name) { - if (!value.HasMember(name)) { - return; - } - - const JSValue& property = value[name]; - if (!property.IsArray()) { - return; - } - - for (rapidjson::SizeType i = 0; i < property.Size(); i++) { - if (!property[i].IsString()) { - return; - } - } - - for (rapidjson::SizeType i = 0; i < property.Size(); i++) { - target.emplace_back(std::string(property[i].GetString(), property[i].GetStringLength())); - } -} - -void parseTileJSONMember(const JSValue& value, std::string& target, const char* name) { - if (!value.HasMember(name)) { - return; - } - - const JSValue& property = value[name]; - if (!property.IsString()) { - return; - } - - target = { property.GetString(), property.GetStringLength() }; -} - -void parseTileJSONMember(const JSValue& value, uint8_t& target, const char* name) { - if (!value.HasMember(name)) { - return; - } - - const JSValue& property = value[name]; - if (!property.IsUint()) { - return; - } - - unsigned int uint = property.GetUint(); - if (uint > std::numeric_limits<uint8_t>::max()) { - return; - } - - target = uint; -} - -Tileset parseTileJSON(const JSValue& value) { - Tileset result; - - parseTileJSONMember(value, result.tiles, "tiles"); - parseTileJSONMember(value, result.zoomRange.min, "minzoom"); - parseTileJSONMember(value, result.zoomRange.max, "maxzoom"); - parseTileJSONMember(value, result.attribution, "attribution"); - - return result; -} - -} // end namespace - Tileset TileSourceImpl::parseTileJSON(const std::string& json, const std::string& sourceURL, SourceType type, uint16_t tileSize) { rapidjson::GenericDocument<rapidjson::UTF8<>, rapidjson::CrtAllocator> document; document.Parse<0>(json.c_str()); @@ -91,30 +24,19 @@ Tileset TileSourceImpl::parseTileJSON(const std::string& json, const std::string throw std::runtime_error(message.str()); } - Tileset result = mbgl::style::parseTileJSON(document); + conversion::Result<Tileset> result = conversion::convert<Tileset>(document); + if (!result) { + throw std::runtime_error(result.error().message); + } // TODO: Remove this hack by delivering proper URLs in the TileJSON to begin with. if (util::mapbox::isMapboxURL(sourceURL)) { - for (auto& url : result.tiles) { + for (auto& url : (*result).tiles) { url = util::mapbox::canonicalizeTileURL(url, type, tileSize); } } - return result; -} - -optional<variant<std::string, Tileset>> TileSourceImpl::parseURLOrTileset(const JSValue& value) { - if (!value.HasMember("url")) { - return { mbgl::style::parseTileJSON(value) }; - } - - const JSValue& urlVal = value["url"]; - if (!urlVal.IsString()) { - Log::Error(Event::ParseStyle, "source url must be a string"); - return {}; - } - - return { std::string(urlVal.GetString(), urlVal.GetStringLength()) }; + return *result; } TileSourceImpl::TileSourceImpl(SourceType type_, std::string id_, Source& base_, diff --git a/src/mbgl/style/tile_source_impl.hpp b/src/mbgl/style/tile_source_impl.hpp index 1ceb1188db..8f420a15d5 100644 --- a/src/mbgl/style/tile_source_impl.hpp +++ b/src/mbgl/style/tile_source_impl.hpp @@ -4,7 +4,6 @@ #include <mbgl/util/tileset.hpp> #include <mbgl/util/variant.hpp> #include <mbgl/util/optional.hpp> -#include <mbgl/util/rapidjson.hpp> namespace mbgl { @@ -18,8 +17,6 @@ namespace style { */ class TileSourceImpl : public Source::Impl { public: - // A tile source can either specify a URL to TileJSON, or inline TileJSON. - static optional<variant<std::string, Tileset>> parseURLOrTileset(const JSValue&); static Tileset parseTileJSON(const std::string& json, const std::string& sourceURL, SourceType, uint16_t tileSize); TileSourceImpl(SourceType, std::string id, Source&, diff --git a/src/mbgl/util/geojson.cpp b/src/mbgl/util/geojson.cpp new file mode 100644 index 0000000000..a17d01f933 --- /dev/null +++ b/src/mbgl/util/geojson.cpp @@ -0,0 +1,11 @@ +#include <mbgl/util/geojson.hpp> + +#include <mapbox/geojsonvt.hpp> + +namespace mbgl { + +GeoJSON::GeoJSON(std::unique_ptr<mapbox::geojsonvt::GeoJSONVT> impl_) : impl(std::move(impl_)) {} +GeoJSON::GeoJSON(GeoJSON&&) = default; +GeoJSON::~GeoJSON() = default; + +} // namespace mbgl diff --git a/test/fixtures/style_parser/geojson-invalid-data.info.json b/test/fixtures/style_parser/geojson-invalid-data.info.json index ec4a7e2b75..86f1ef6edd 100644 --- a/test/fixtures/style_parser/geojson-invalid-data.info.json +++ b/test/fixtures/style_parser/geojson-invalid-data.info.json @@ -1,7 +1,7 @@ { "default": { "log": [ - [1, "ERROR", "ParseStyle", "GeoJSON data must be a URL or an object"] + [1, "WARNING", "ParseStyle", "GeoJSON data must be a URL or an object"] ] } } diff --git a/test/fixtures/style_parser/geojson-missing-data.info.json b/test/fixtures/style_parser/geojson-missing-data.info.json index 2c4806c3cf..594d01d19d 100644 --- a/test/fixtures/style_parser/geojson-missing-data.info.json +++ b/test/fixtures/style_parser/geojson-missing-data.info.json @@ -1,7 +1,7 @@ { "default": { "log": [ - [1, "ERROR", "ParseStyle", "GeoJSON source must have a data value"] + [1, "WARNING", "ParseStyle", "GeoJSON source must have a data value"] ] } } |