diff options
author | Igor Tarasov <igor.tarasov@mapbox.com> | 2019-09-16 23:37:50 +0300 |
---|---|---|
committer | Igor Tarasov <igor.tarasov@mapbox.com> | 2019-09-16 23:37:50 +0300 |
commit | f4f7283515690ed0a24828745b6a407fa67929a0 (patch) | |
tree | 4994e87d72ba24c3181a2e07e734da2554373ac7 | |
parent | 2eed5486ffd4986331b8cd78d6181eb6478fb552 (diff) | |
download | qtlocation-mapboxgl-f4f7283515690ed0a24828745b6a407fa67929a0.tar.gz |
[android] Style sources - handle invalidated core source.
8 files changed, 62 insertions, 43 deletions
diff --git a/platform/android/src/style/sources/custom_geometry_source.cpp b/platform/android/src/style/sources/custom_geometry_source.cpp index 8a6d409158..da696e82b5 100644 --- a/platform/android/src/style/sources/custom_geometry_source.cpp +++ b/platform/android/src/style/sources/custom_geometry_source.cpp @@ -143,17 +143,17 @@ namespace android { // Update the core source if not cancelled if (!isCancelled(z, x ,y)) { - source->as<mbgl::style::CustomGeometrySource>()->CustomGeometrySource::setTileData(CanonicalTileID(z, x, y), GeoJSON(geometry)); + source(env)->as<mbgl::style::CustomGeometrySource>()->CustomGeometrySource::setTileData(CanonicalTileID(z, x, y), GeoJSON(geometry)); } } - void CustomGeometrySource::invalidateTile(jni::JNIEnv&, jni::jint z, jni::jint x, jni::jint y) { - source->as<mbgl::style::CustomGeometrySource>()->CustomGeometrySource::invalidateTile(CanonicalTileID(z, x, y)); + void CustomGeometrySource::invalidateTile(jni::JNIEnv& env, jni::jint z, jni::jint x, jni::jint y) { + source(env)->as<mbgl::style::CustomGeometrySource>()->CustomGeometrySource::invalidateTile(CanonicalTileID(z, x, y)); } void CustomGeometrySource::invalidateBounds(jni::JNIEnv& env, const jni::Object<LatLngBounds>& jBounds) { auto bounds = LatLngBounds::getLatLngBounds(env, jBounds); - source->as<mbgl::style::CustomGeometrySource>()->CustomGeometrySource::invalidateRegion(bounds); + source(env)->as<mbgl::style::CustomGeometrySource>()->CustomGeometrySource::invalidateRegion(bounds); } jni::Local<jni::Array<jni::Object<geojson::Feature>>> CustomGeometrySource::querySourceFeatures(jni::JNIEnv& env, @@ -163,7 +163,7 @@ namespace android { std::vector<mbgl::Feature> features; if (rendererFrontend) { - features = rendererFrontend->querySourceFeatures(source->getID(), { {}, toFilter(env, jfilter) }); + features = rendererFrontend->querySourceFeatures(source(env)->getID(), { {}, toFilter(env, jfilter) }); } return Feature::convert(env, features); } diff --git a/platform/android/src/style/sources/geojson_source.cpp b/platform/android/src/style/sources/geojson_source.cpp index 40e94efd97..aa05f9c912 100644 --- a/platform/android/src/style/sources/geojson_source.cpp +++ b/platform/android/src/style/sources/geojson_source.cpp @@ -84,11 +84,11 @@ namespace android { void GeoJSONSource::setURL(jni::JNIEnv& env, const jni::String& url) { // Update the core source - source->as<mbgl::style::GeoJSONSource>()->GeoJSONSource::setURL(jni::Make<std::string>(env, url)); + source(env)->as<mbgl::style::GeoJSONSource>()->GeoJSONSource::setURL(jni::Make<std::string>(env, url)); } jni::Local<jni::String> GeoJSONSource::getURL(jni::JNIEnv& env) { - optional<std::string> url = source->as<mbgl::style::GeoJSONSource>()->GeoJSONSource::getURL(); + optional<std::string> url = source(env)->as<mbgl::style::GeoJSONSource>()->GeoJSONSource::getURL(); return url ? jni::Make<jni::String>(env, *url) : jni::Local<jni::String>(); } @@ -99,7 +99,7 @@ namespace android { std::vector<mbgl::Feature> features; if (rendererFrontend) { - features = rendererFrontend->querySourceFeatures(source->getID(), + features = rendererFrontend->querySourceFeatures(source(env)->getID(), { {}, toFilter(env, jfilter) }); } return Feature::convert(env, features); @@ -112,7 +112,7 @@ namespace android { if (rendererFrontend) { mbgl::Feature _feature = Feature::convert(env, feature); _feature.properties["cluster_id"] = static_cast<uint64_t>(_feature.properties["cluster_id"].get<double>()); - const auto featureExtension = rendererFrontend->queryFeatureExtensions(source->getID(), _feature, "supercluster", "children", {}); + const auto featureExtension = rendererFrontend->queryFeatureExtensions(source(env)->getID(), _feature, "supercluster", "children", {}); if (featureExtension.is<mbgl::FeatureCollection>()) { return Feature::convert(env, featureExtension.get<mbgl::FeatureCollection>()); } @@ -129,7 +129,7 @@ namespace android { _feature.properties["cluster_id"] = static_cast<uint64_t>(_feature.properties["cluster_id"].get<double>()); const std::map<std::string, mbgl::Value> options = { {"limit", static_cast<uint64_t>(limit)}, {"offset", static_cast<uint64_t>(offset)} }; - auto featureExtension = rendererFrontend->queryFeatureExtensions(source->getID(), _feature, "supercluster", "leaves", options); + auto featureExtension = rendererFrontend->queryFeatureExtensions(source(env)->getID(), _feature, "supercluster", "leaves", options); if (featureExtension.is<mbgl::FeatureCollection>()) { return Feature::convert(env, featureExtension.get<mbgl::FeatureCollection>()); } @@ -144,7 +144,7 @@ namespace android { if (rendererFrontend) { mbgl::Feature _feature = Feature::convert(env, feature); _feature.properties["cluster_id"] = static_cast<uint64_t>(_feature.properties["cluster_id"].get<double>()); - auto featureExtension = rendererFrontend->queryFeatureExtensions(source->getID(), _feature, "supercluster", "expansion-zoom", {}); + auto featureExtension = rendererFrontend->queryFeatureExtensions(source(env)->getID(), _feature, "supercluster", "expansion-zoom", {}); if (featureExtension.is<mbgl::Value>()) { auto value = featureExtension.get<mbgl::Value>(); if (value.is<uint64_t>()) { @@ -183,7 +183,7 @@ namespace android { android::UniqueEnv _env = android::AttachEnv(); // Update the core source - source->as<mbgl::style::GeoJSONSource>()->GeoJSONSource::setGeoJSON(geoJSON); + source(*_env)->as<mbgl::style::GeoJSONSource>()->GeoJSONSource::setGeoJSON(geoJSON); // if there is an awaiting update, execute it, otherwise, release resources if (awaitingUpdate) { diff --git a/platform/android/src/style/sources/image_source.cpp b/platform/android/src/style/sources/image_source.cpp index 0986f74b35..b107fc94f2 100644 --- a/platform/android/src/style/sources/image_source.cpp +++ b/platform/android/src/style/sources/image_source.cpp @@ -33,20 +33,20 @@ namespace android { void ImageSource::setURL(jni::JNIEnv& env, const jni::String& url) { // Update the core source - source->as<mbgl::style::ImageSource>()->ImageSource::setURL(jni::Make<std::string>(env, url)); + source(env)->as<mbgl::style::ImageSource>()->ImageSource::setURL(jni::Make<std::string>(env, url)); } jni::Local<jni::String> ImageSource::getURL(jni::JNIEnv& env) { - optional<std::string> url = source->as<mbgl::style::ImageSource>()->ImageSource::getURL(); + optional<std::string> url = source(env)->as<mbgl::style::ImageSource>()->ImageSource::getURL(); return url ? jni::Make<jni::String>(env, *url) : jni::Local<jni::String>(); } void ImageSource::setImage(jni::JNIEnv& env, const jni::Object<Bitmap>& bitmap) { - source->as<mbgl::style::ImageSource>()->setImage(Bitmap::GetImage(env, bitmap)); + source(env)->as<mbgl::style::ImageSource>()->setImage(Bitmap::GetImage(env, bitmap)); } void ImageSource::setCoordinates(jni::JNIEnv& env, const jni::Object<LatLngQuad>& coordinatesObject) { - source->as<mbgl::style::ImageSource>()->setCoordinates( + source(env)->as<mbgl::style::ImageSource>()->setCoordinates( LatLngQuad::getLatLngArray(env, coordinatesObject)); } diff --git a/platform/android/src/style/sources/raster_dem_source.cpp b/platform/android/src/style/sources/raster_dem_source.cpp index dd98925d22..950fdde341 100644 --- a/platform/android/src/style/sources/raster_dem_source.cpp +++ b/platform/android/src/style/sources/raster_dem_source.cpp @@ -32,7 +32,7 @@ namespace android { RasterDEMSource::~RasterDEMSource() = default; jni::Local<jni::String> RasterDEMSource::getURL(jni::JNIEnv& env) { - optional<std::string> url = source->as<mbgl::style::RasterDEMSource>()->RasterDEMSource::getURL(); + optional<std::string> url = source(env)->as<mbgl::style::RasterDEMSource>()->RasterDEMSource::getURL(); return url ? jni::Make<jni::String>(env, *url) : jni::Local<jni::String>(); } diff --git a/platform/android/src/style/sources/raster_source.cpp b/platform/android/src/style/sources/raster_source.cpp index d643b8ac71..425e37c3da 100644 --- a/platform/android/src/style/sources/raster_source.cpp +++ b/platform/android/src/style/sources/raster_source.cpp @@ -31,7 +31,7 @@ namespace android { RasterSource::~RasterSource() = default; jni::Local<jni::String> RasterSource::getURL(jni::JNIEnv& env) { - optional<std::string> url = source->as<mbgl::style::RasterSource>()->RasterSource::getURL(); + optional<std::string> url = source(env)->as<mbgl::style::RasterSource>()->RasterSource::getURL(); return url ? jni::Make<jni::String>(env, *url) : jni::Local<jni::String>(); } diff --git a/platform/android/src/style/sources/source.cpp b/platform/android/src/style/sources/source.cpp index 6af30f2922..8f4e631e9a 100644 --- a/platform/android/src/style/sources/source.cpp +++ b/platform/android/src/style/sources/source.cpp @@ -56,14 +56,13 @@ namespace android { } Source::Source(jni::JNIEnv& env, mbgl::style::Source* coreSource, const jni::Object<Source>& obj, AndroidRendererFrontend& frontend) - : source(coreSource) - , javaPeer(jni::NewGlobal(env, obj)) + : javaPeer(jni::NewGlobal(env, obj)) , rendererFrontend(&frontend) { + source(coreSource); } - Source::Source(jni::JNIEnv&, std::unique_ptr<mbgl::style::Source> coreSource) - : ownedSource(std::move(coreSource)) - , source(ownedSource.get()) { + Source::Source(jni::JNIEnv&, std::unique_ptr<mbgl::style::Source> coreSource) { + source(std::move(coreSource)); } Source::~Source() { @@ -74,7 +73,7 @@ namespace android { // In this case, the core source initiates the destruction, which requires releasing the Java peer, // while also resetting it's nativePtr to 0 to prevent the subsequent GC of the Java peer from // re-entering this dtor. - if (ownedSource.get() == nullptr && javaPeer.get() != nullptr) { + if (ownedSource_ == nullptr && javaPeer.get() != nullptr) { // Manually clear the java peer android::UniqueEnv env = android::AttachEnv(); static auto& javaClass = jni::Class<Source>::Singleton(*env); @@ -85,25 +84,25 @@ namespace android { } jni::Local<jni::String> Source::getId(jni::JNIEnv& env) { - return jni::Make<jni::String>(env, source->getID()); + return jni::Make<jni::String>(env, source(env)->getID()); } jni::Local<jni::String> Source::getAttribution(jni::JNIEnv& env) { - auto attribution = source->getAttribution(); + auto attribution = source(env)->getAttribution(); return attribution ? jni::Make<jni::String>(env, attribution.value()) : jni::Make<jni::String>(env,""); } void Source::addToMap(JNIEnv& env, const jni::Object<Source>& obj, mbgl::Map& map, AndroidRendererFrontend& frontend) { // Check to see if we own the source first - if (!ownedSource) { + if (!ownedSource_) { throw std::runtime_error("Cannot add source twice"); } // Add source to map and release ownership - map.getStyle().addSource(std::move(ownedSource)); + map.getStyle().addSource(std::move(ownedSource_)); // Add peer to core source - source->peer = std::unique_ptr<Source>(this); + source(env)->peer = std::unique_ptr<Source>(this); // Add strong reference to java source javaPeer = jni::NewGlobal(env, obj); @@ -111,29 +110,29 @@ namespace android { rendererFrontend = &frontend; } - bool Source::removeFromMap(JNIEnv&, const jni::Object<Source>&, mbgl::Map& map) { + bool Source::removeFromMap(JNIEnv& env, const jni::Object<Source>&, mbgl::Map& map) { // Cannot remove if not attached yet - if (ownedSource) { + if (ownedSource_) { throw std::runtime_error("Cannot remove detached source"); } // Remove the source from the map and take ownership - ownedSource = map.getStyle().removeSource(source->getID()); + source(map.getStyle().removeSource(source(env)->getID())); // The source may not be removed if any layers still reference it - return ownedSource != nullptr; + return ownedSource_ != nullptr; } void Source::releaseJavaPeer() { // We can't release the peer if the source was not removed from the map - if (!ownedSource) { + if (!ownedSource_) { return; } // Release the peer relationships. These will be re-established when the source is added to a map - assert(ownedSource->peer.has_value()); - ownedSource->peer.get<std::unique_ptr<Source>>().release(); - ownedSource->peer = mapbox::base::TypeWrapper(); + assert(ownedSource_->peer.has_value()); + ownedSource_->peer.get<std::unique_ptr<Source>>().release(); + ownedSource_->peer = mapbox::base::TypeWrapper(); // Release the strong reference to the java peer assert(javaPeer); diff --git a/platform/android/src/style/sources/source.hpp b/platform/android/src/style/sources/source.hpp index 127de0bb9d..6217b909f3 100644 --- a/platform/android/src/style/sources/source.hpp +++ b/platform/android/src/style/sources/source.hpp @@ -7,6 +7,8 @@ #include "../value.hpp" #include "../../android_renderer_frontend.hpp" +#include <mapbox/weak.hpp> + #include <jni/jni.hpp> namespace mbgl { @@ -44,17 +46,35 @@ public: jni::Local<jni::String> getAttribution(jni::JNIEnv&); protected: - // Set on newly created sources until added to the map. - std::unique_ptr<mbgl::style::Source> ownedSource; - // Raw pointer that is valid at all times. - mbgl::style::Source *source; + inline void source(std::unique_ptr<mbgl::style::Source> ownedSource) noexcept { + ownedSource_ = std::move(ownedSource); + } + + inline void source(mbgl::style::Source *coreSource) noexcept { + coreSource_ = coreSource->makeWeakPtr(); + } + + inline mbgl::style::Source *source(jni::JNIEnv& env) { + if (ownedSource_) return ownedSource_.get(); + if (!coreSource_) { + jni::ThrowNew(env, jni::FindClass(env, "java/lang/IllegalStateException"), + "This source got invalidated after the style change"); + } + return coreSource_.get(); + } // Set when the source is added to a map. jni::Global<jni::Object<Source>> javaPeer; // RendererFrontend pointer is valid only when added to the map. AndroidRendererFrontend* rendererFrontend { nullptr }; + +private: + // Set on newly created sources until added to the map. + std::unique_ptr<mbgl::style::Source> ownedSource_; + + mapbox::base::WeakPtr<mbgl::style::Source> coreSource_; }; } // namespace android diff --git a/platform/android/src/style/sources/vector_source.cpp b/platform/android/src/style/sources/vector_source.cpp index 04952c456e..bc66b2e318 100644 --- a/platform/android/src/style/sources/vector_source.cpp +++ b/platform/android/src/style/sources/vector_source.cpp @@ -39,7 +39,7 @@ namespace android { VectorSource::~VectorSource() = default; jni::Local<jni::String> VectorSource::getURL(jni::JNIEnv& env) { - optional<std::string> url = source->as<mbgl::style::VectorSource>()->VectorSource::getURL(); + optional<std::string> url = source(env)->as<mbgl::style::VectorSource>()->VectorSource::getURL(); return url ? jni::Make<jni::String>(env, *url) : jni::Local<jni::String>(); } @@ -51,7 +51,7 @@ namespace android { std::vector<mbgl::Feature> features; if (rendererFrontend) { - features = rendererFrontend->querySourceFeatures(source->getID(), + features = rendererFrontend->querySourceFeatures(source(env)->getID(), { toVector(env, jSourceLayerIds), toFilter(env, jfilter) }); } return Feature::convert(env, features); |