[core, darwin] Object identity for MGLSource*, MGLStyleLayer*
All `MGLSource` pointers referencing the same logical source will now be object identical; similarly for `MGLStyleLayer`.
This commit is contained in:
@@ -40,6 +40,7 @@ set_source_files_properties(src/mbgl/util/version.cpp PROPERTIES COMPILE_DEFINIT
|
||||
|
||||
mason_use(geometry VERSION 0.9.0 HEADER_ONLY)
|
||||
mason_use(variant VERSION 1.1.4 HEADER_ONLY)
|
||||
mason_use(any VERSION 8fef1e9 HEADER_ONLY)
|
||||
mason_use(unique_resource VERSION cba309e HEADER_ONLY)
|
||||
mason_use(rapidjson VERSION 1.1.0 HEADER_ONLY)
|
||||
mason_use(boost VERSION 1.62.0 HEADER_ONLY)
|
||||
|
||||
@@ -14,6 +14,7 @@ target_include_directories(mbgl-core
|
||||
|
||||
target_add_mason_package(mbgl-core PUBLIC geometry)
|
||||
target_add_mason_package(mbgl-core PUBLIC variant)
|
||||
target_add_mason_package(mbgl-core PUBLIC any)
|
||||
target_add_mason_package(mbgl-core PRIVATE unique_resource)
|
||||
target_add_mason_package(mbgl-core PRIVATE rapidjson)
|
||||
target_add_mason_package(mbgl-core PRIVATE boost)
|
||||
|
||||
@@ -27,6 +27,7 @@ target_link_libraries(mbgl-test
|
||||
|
||||
target_add_mason_package(mbgl-test PRIVATE geometry)
|
||||
target_add_mason_package(mbgl-test PRIVATE variant)
|
||||
target_add_mason_package(mbgl-test PRIVATE any)
|
||||
target_add_mason_package(mbgl-test PRIVATE unique_resource)
|
||||
target_add_mason_package(mbgl-test PRIVATE rapidjson)
|
||||
target_add_mason_package(mbgl-test PRIVATE gtest)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <mbgl/util/noncopyable.hpp>
|
||||
#include <mbgl/util/any.hpp>
|
||||
#include <mbgl/style/types.hpp>
|
||||
|
||||
#include <memory>
|
||||
@@ -118,6 +119,11 @@ public:
|
||||
// Private implementation
|
||||
const std::unique_ptr<Impl> baseImpl;
|
||||
|
||||
// For use in SDK bindings, which store a reference to a platform-native peer
|
||||
// object here, so that separately-obtained references to this object share
|
||||
// identical platform-native peers.
|
||||
any peer;
|
||||
|
||||
friend std::string layoutKey(const Layer&);
|
||||
};
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <mbgl/util/noncopyable.hpp>
|
||||
#include <mbgl/util/optional.hpp>
|
||||
#include <mbgl/util/range.hpp>
|
||||
#include <mbgl/util/any.hpp>
|
||||
#include <mbgl/style/types.hpp>
|
||||
#include <mbgl/style/query.hpp>
|
||||
|
||||
@@ -64,6 +65,11 @@ public:
|
||||
class Impl;
|
||||
const std::unique_ptr<Impl> baseImpl;
|
||||
|
||||
// For use in SDK bindings, which store a reference to a platform-native peer
|
||||
// object here, so that separately-obtained references to this object share
|
||||
// identical platform-native peers.
|
||||
any peer;
|
||||
|
||||
protected:
|
||||
const SourceType type;
|
||||
Source(SourceType, std::unique_ptr<Impl>);
|
||||
|
||||
10
include/mbgl/util/any.hpp
Normal file
10
include/mbgl/util/any.hpp
Normal file
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <linb/any.hpp>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
using linb::any;
|
||||
using linb::any_cast;
|
||||
|
||||
} // namespace mbgl
|
||||
@@ -29,6 +29,7 @@
|
||||
NSString *identifier = @(rawSource->getID().c_str());
|
||||
if (self = [self initWithIdentifier:identifier]) {
|
||||
_rawSource = rawSource;
|
||||
_rawSource->peer = SourceWrapper { self };
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -10,6 +10,14 @@ namespace mbgl {
|
||||
}
|
||||
}
|
||||
|
||||
// A struct to be stored in the `peer` member of mbgl::style::Source, in order to implement
|
||||
// object identity. We don't store a MGLSource pointer directly because that doesn't
|
||||
// interoperate with ARC. The inner pointer is weak in order to avoid a reference cycle for
|
||||
// "pending" MGLSources, which have a strong owning pointer to the mbgl::style::Source.
|
||||
struct SourceWrapper {
|
||||
__weak MGLSource *source;
|
||||
};
|
||||
|
||||
@class MGLMapView;
|
||||
|
||||
@interface MGLSource (Private)
|
||||
|
||||
@@ -166,17 +166,21 @@ static NSURL *MGLStyleURL_emerald;
|
||||
return rawSource ? [self sourceFromMBGLSource:rawSource] : nil;
|
||||
}
|
||||
|
||||
- (MGLSource *)sourceFromMBGLSource:(mbgl::style::Source *)source {
|
||||
- (MGLSource *)sourceFromMBGLSource:(mbgl::style::Source *)rawSource {
|
||||
if (MGLSource *source = rawSource->peer.empty() ? nil : mbgl::any_cast<SourceWrapper>(rawSource->peer).source) {
|
||||
return source;
|
||||
}
|
||||
|
||||
// TODO: Fill in options specific to the respective source classes
|
||||
// https://github.com/mapbox/mapbox-gl-native/issues/6584
|
||||
if (auto vectorSource = source->as<mbgl::style::VectorSource>()) {
|
||||
if (auto vectorSource = rawSource->as<mbgl::style::VectorSource>()) {
|
||||
return [[MGLVectorSource alloc] initWithRawSource:vectorSource];
|
||||
} else if (auto geoJSONSource = source->as<mbgl::style::GeoJSONSource>()) {
|
||||
} else if (auto geoJSONSource = rawSource->as<mbgl::style::GeoJSONSource>()) {
|
||||
return [[MGLShapeSource alloc] initWithRawSource:geoJSONSource];
|
||||
} else if (auto rasterSource = source->as<mbgl::style::RasterSource>()) {
|
||||
} else if (auto rasterSource = rawSource->as<mbgl::style::RasterSource>()) {
|
||||
return [[MGLRasterSource alloc] initWithRawSource:rasterSource];
|
||||
} else {
|
||||
return [[MGLSource alloc] initWithRawSource:source];
|
||||
return [[MGLSource alloc] initWithRawSource:rawSource];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -319,35 +323,32 @@ static NSURL *MGLStyleURL_emerald;
|
||||
[styleLayer removeFromMapView:self.mapView];
|
||||
}
|
||||
|
||||
- (MGLStyleLayer *)layerFromMBGLLayer:(mbgl::style::Layer *)mbglLayer
|
||||
- (MGLStyleLayer *)layerFromMBGLLayer:(mbgl::style::Layer *)rawLayer
|
||||
{
|
||||
NSParameterAssert(mbglLayer);
|
||||
NSParameterAssert(rawLayer);
|
||||
|
||||
NSString *identifier = @(mbglLayer->getID().c_str());
|
||||
if (MGLStyleLayer *layer = rawLayer->peer.empty() ? nil : mbgl::any_cast<LayerWrapper>(rawLayer->peer).layer) {
|
||||
return layer;
|
||||
}
|
||||
|
||||
if (auto fillLayer = mbglLayer->as<mbgl::style::FillLayer>()) {
|
||||
if (auto fillLayer = rawLayer->as<mbgl::style::FillLayer>()) {
|
||||
MGLSource *source = [self sourceWithIdentifier:@(fillLayer->getSourceID().c_str())];
|
||||
return [[MGLFillStyleLayer alloc] initWithRawLayer:fillLayer source:source];
|
||||
} else if (auto lineLayer = mbglLayer->as<mbgl::style::LineLayer>()) {
|
||||
} else if (auto lineLayer = rawLayer->as<mbgl::style::LineLayer>()) {
|
||||
MGLSource *source = [self sourceWithIdentifier:@(lineLayer->getSourceID().c_str())];
|
||||
return [[MGLLineStyleLayer alloc] initWithRawLayer:lineLayer source:source];
|
||||
} else if (auto symbolLayer = mbglLayer->as<mbgl::style::SymbolLayer>()) {
|
||||
} else if (auto symbolLayer = rawLayer->as<mbgl::style::SymbolLayer>()) {
|
||||
MGLSource *source = [self sourceWithIdentifier:@(symbolLayer->getSourceID().c_str())];
|
||||
return [[MGLSymbolStyleLayer alloc] initWithRawLayer:symbolLayer source:source];
|
||||
} else if (auto rasterLayer = mbglLayer->as<mbgl::style::RasterLayer>()) {
|
||||
} else if (auto rasterLayer = rawLayer->as<mbgl::style::RasterLayer>()) {
|
||||
MGLSource *source = [self sourceWithIdentifier:@(rasterLayer->getSourceID().c_str())];
|
||||
return [[MGLRasterStyleLayer alloc] initWithRawLayer:rasterLayer source:source];
|
||||
} else if (auto circleLayer = mbglLayer->as<mbgl::style::CircleLayer>()) {
|
||||
} else if (auto circleLayer = rawLayer->as<mbgl::style::CircleLayer>()) {
|
||||
MGLSource *source = [self sourceWithIdentifier:@(circleLayer->getSourceID().c_str())];
|
||||
return [[MGLCircleStyleLayer alloc] initWithRawLayer:circleLayer source:source];
|
||||
} else if (auto backgroundLayer = mbglLayer->as<mbgl::style::BackgroundLayer>()) {
|
||||
} else if (auto backgroundLayer = rawLayer->as<mbgl::style::BackgroundLayer>()) {
|
||||
return [[MGLBackgroundStyleLayer alloc] initWithRawLayer:backgroundLayer];
|
||||
} else if (auto customLayer = mbglLayer->as<mbgl::style::CustomLayer>()) {
|
||||
MGLStyleLayer *styleLayer = self.openGLLayers[identifier];
|
||||
if (styleLayer) {
|
||||
NSAssert(styleLayer.rawLayer == customLayer, @"%@ wraps a CustomLayer that differs from the one associated with the underlying style.", styleLayer);
|
||||
return styleLayer;
|
||||
}
|
||||
} else if (auto customLayer = rawLayer->as<mbgl::style::CustomLayer>()) {
|
||||
return [[MGLOpenGLStyleLayer alloc] initWithRawLayer:customLayer];
|
||||
} else {
|
||||
NSAssert(NO, @"Unrecognized layer type");
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
if (self = [super init]) {
|
||||
_identifier = @(rawLayer->getID().c_str());
|
||||
_rawLayer = rawLayer;
|
||||
_rawLayer->peer = LayerWrapper { self };
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -7,6 +7,14 @@
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
// A struct to be stored in the `peer` member of mbgl::style::Layer, in order to implement
|
||||
// object identity. We don't store a MGLStyleLayer pointer directly because that doesn't
|
||||
// interoperate with ARC. The inner pointer is weak in order to avoid a reference cycle for
|
||||
// "pending" MGLStyleLayers, which have a strong owning pointer to the mbgl::style::Layer.
|
||||
struct LayerWrapper {
|
||||
__weak MGLStyleLayer *layer;
|
||||
};
|
||||
|
||||
/**
|
||||
Assert that the style layer is valid.
|
||||
|
||||
|
||||
@@ -148,6 +148,7 @@
|
||||
MGLShapeSource *shapeSource = [[MGLShapeSource alloc] initWithIdentifier:@"shapeSource" shape:nil options:nil];
|
||||
[self.style addSource:shapeSource];
|
||||
XCTAssertEqual(self.style.sources.count, initialSources.count + 1);
|
||||
XCTAssertEqual(shapeSource, [self.style sourceWithIdentifier:@"shapeSource"]);
|
||||
[self.style removeSource:shapeSource];
|
||||
XCTAssertEqual(self.style.sources.count, initialSources.count);
|
||||
}
|
||||
@@ -238,6 +239,7 @@
|
||||
MGLFillStyleLayer *fillLayer = [[MGLFillStyleLayer alloc] initWithIdentifier:@"fillLayer" source:shapeSource];
|
||||
[self.style addLayer:fillLayer];
|
||||
XCTAssertEqual(self.style.layers.count, initialLayers.count + 1);
|
||||
XCTAssertEqual(fillLayer, [self.style layerWithIdentifier:@"fillLayer"]);
|
||||
[self.style removeLayer:fillLayer];
|
||||
XCTAssertEqual(self.style.layers.count, initialLayers.count);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user