diff options
Diffstat (limited to 'platform/android/src/style/sources/source.cpp')
-rw-r--r-- | platform/android/src/style/sources/source.cpp | 117 |
1 files changed, 95 insertions, 22 deletions
diff --git a/platform/android/src/style/sources/source.cpp b/platform/android/src/style/sources/source.cpp index 447b13019d..3b89b25d7d 100644 --- a/platform/android/src/style/sources/source.cpp +++ b/platform/android/src/style/sources/source.cpp @@ -15,29 +15,70 @@ #include <string> +// Core Sources +#include <mbgl/style/sources/geojson_source.hpp> +#include <mbgl/style/sources/image_source.hpp> +#include <mbgl/style/sources/raster_source.hpp> +#include <mbgl/style/sources/vector_source.hpp> + +// Android Source peers +#include "geojson_source.hpp" +#include "image_source.hpp" +#include "raster_source.hpp" +#include "unknown_source.hpp" +#include "vector_source.hpp" +#include "custom_geometry_source.hpp" + namespace mbgl { namespace android { - /** - * Invoked when the construction is initiated from the jvm through a subclass - */ - Source::Source(jni::JNIEnv&, std::unique_ptr<mbgl::style::Source> coreSource) - : ownedSource(std::move(coreSource)) - , source(*ownedSource) { + static std::unique_ptr<Source> createSourcePeer(jni::JNIEnv& env, mbgl::style::Source& coreSource, AndroidRendererFrontend& frontend) { + if (coreSource.is<mbgl::style::VectorSource>()) { + return std::make_unique<VectorSource>(env, *coreSource.as<mbgl::style::VectorSource>(), frontend); + } else if (coreSource.is<mbgl::style::RasterSource>()) { + return std::make_unique<RasterSource>(env, *coreSource.as<mbgl::style::RasterSource>(), frontend); + } else if (coreSource.is<mbgl::style::GeoJSONSource>()) { + return std::make_unique<GeoJSONSource>(env, *coreSource.as<mbgl::style::GeoJSONSource>(), frontend); + } else if (coreSource.is<mbgl::style::ImageSource>()) { + return std::make_unique<ImageSource>(env, *coreSource.as<mbgl::style::ImageSource>(), frontend); + } else { + return std::make_unique<UnknownSource>(env, coreSource, frontend); + } } - Source::Source(mbgl::style::Source& coreSource) - : source(coreSource) { + jni::Object<Source> Source::peerForCoreSource(jni::JNIEnv& env, mbgl::style::Source& coreSource, AndroidRendererFrontend& frontend) { + if (!coreSource.peer.has_value()) { + coreSource.peer = createSourcePeer(env, coreSource, frontend); + } + return *mbgl::util::any_cast<std::unique_ptr<Source>>(&coreSource.peer)->get()->javaPeer; } - Source::~Source() = default; + Source::Source(jni::JNIEnv& env, mbgl::style::Source& coreSource, jni::Object<Source> obj, AndroidRendererFrontend& frontend) + : source(coreSource) + , javaPeer(obj.NewGlobalRef(env)) + , rendererFrontend(&frontend) { + } - style::Source& Source::get() { - return source; + Source::Source(jni::JNIEnv&, std::unique_ptr<mbgl::style::Source> coreSource) + : ownedSource(std::move(coreSource)) + , source(*ownedSource) { } - void Source::setSource(std::unique_ptr<style::Source> coreSource) { - this->ownedSource = std::move(coreSource); + Source::~Source() { + // Before being added to a map, the Java peer owns this C++ peer and cleans + // up after itself correctly through the jni native peer bindings. + // After being added to the map, the ownership is flipped and the C++ peer has a strong reference + // to it's Java peer, preventing the Java peer from being GC'ed. + // 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) { + // Manually clear the java peer + android::UniqueEnv env = android::AttachEnv(); + static auto nativePtrField = javaClass.GetField<jlong>(*env, "nativePtr"); + javaPeer->Set(*env, nativePtrField, (jlong) 0); + javaPeer.reset(); + } } jni::String Source::getId(jni::JNIEnv& env) { @@ -49,23 +90,48 @@ namespace android { return attribution ? jni::Make<jni::String>(env, attribution.value()) : jni::Make<jni::String>(env,""); } - void Source::addToMap(mbgl::Map& _map) { + void Source::addToMap(JNIEnv& env, jni::Object<Source> obj, mbgl::Map& map, AndroidRendererFrontend& frontend) { // Check to see if we own the source first if (!ownedSource) { throw std::runtime_error("Cannot add source twice"); } - // Add source to map - _map.getStyle().addSource(releaseCoreSource()); - } + // Add source to map and release ownership + map.getStyle().addSource(std::move(ownedSource)); + + // Add peer to core source + source.peer = std::unique_ptr<Source>(this); + + // Add strong reference to java source + javaPeer = obj.NewGlobalRef(env); - void Source::setRendererFrontend(AndroidRendererFrontend& frontend_) { - rendererFrontend = &frontend_; + rendererFrontend = &frontend; } - std::unique_ptr<mbgl::style::Source> Source::releaseCoreSource() { - assert(ownedSource != nullptr); - return std::move(ownedSource); + void Source::removeFromMap(JNIEnv&, jni::Object<Source>, mbgl::Map& map) { + // Cannot remove if not attached yet + 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()); + + // The source may not be removed if any layers still reference it + 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()); + util::any_cast<std::unique_ptr<Source>>(&(ownedSource->peer))->release(); + ownedSource->peer.reset(); + + // Release the strong reference to the java peer + assert(javaPeer); + javaPeer.release(); + + rendererFrontend = nullptr; } jni::Class<Source> Source::javaClass; @@ -82,6 +148,13 @@ namespace android { METHOD(&Source::getAttribution, "nativeGetAttribution") ); + // Register subclasses + GeoJSONSource::registerNative(env); + ImageSource::registerNative(env); + RasterSource::registerNative(env); + UnknownSource::registerNative(env); + VectorSource::registerNative(env); + CustomGeometrySource::registerNative(env); } } // namespace android |