summaryrefslogtreecommitdiff
path: root/platform/android/src/style/sources/source.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'platform/android/src/style/sources/source.cpp')
-rw-r--r--platform/android/src/style/sources/source.cpp114
1 files changed, 94 insertions, 20 deletions
diff --git a/platform/android/src/style/sources/source.cpp b/platform/android/src/style/sources/source.cpp
index 05f981953a..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::Map& coreMap, mbgl::style::Source& coreSource) : source(coreSource) , map(&coreMap) {
+ 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() {
+ 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,22 +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);
- // Save pointer to the map
- this->map = &_map;
+ 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;
@@ -81,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