[ios, macos] Snapshotter (runtime styling) delegates

Added a protocol and property for MGLMapSnapshotter’s delegate, which it uses for runtime styling. Generalized MGLStyle to be usable in the absence of MGLMapView. Moved MGLOpenGLStyleLayer code around to compile.
This commit is contained in:
Minh Nguyễn
2020-03-23 02:12:38 -07:00
committed by Minh Nguyễn
parent 180ab72055
commit 63bf91125a
17 changed files with 269 additions and 100 deletions

View File

@@ -2,9 +2,12 @@
#import "MGLTypes.h"
#import "MGLGeometry.h"
#import "MGLMapCamera.h"
#import "MGLStyle.h"
NS_ASSUME_NONNULL_BEGIN
@protocol MGLMapSnapshotterDelegate;
/**
An overlay that is placed within a `MGLMapSnapshot`.
To access this object, use `-[MGLMapSnapshotter startWithOverlayHandler:completionHandler:]`.
@@ -177,8 +180,9 @@ typedef void (^MGLMapSnapshotCompletionHandler)(MGLMapSnapshot* _Nullable snapsh
An `MGLMapSnapshotter` generates static raster images of the map. Each snapshot
image depicts a portion of a map defined by an `MGLMapSnapshotOptions` object
you provide. The snapshotter generates an `MGLMapSnapshot` object
asynchronously, passing it into a completion handler once tiles and other
resources needed for the snapshot are finished loading.
asynchronously, calling `MGLMapSnapshotterDelegate` methods if defined, then
passing it into a completion handler once tiles and other resources needed for
the snapshot are finished loading.
You can change the snapshotter’s options at any time and reuse the snapshotter
for multiple distinct snapshots; however, the snapshotter can only generate one
@@ -220,7 +224,7 @@ typedef void (^MGLMapSnapshotCompletionHandler)(MGLMapSnapshot* _Nullable snapsh
object's style, camera, and view bounds.
*/
MGL_EXPORT
@interface MGLMapSnapshotter : NSObject
@interface MGLMapSnapshotter : NSObject <MGLStylable>
- (instancetype)init NS_UNAVAILABLE;
@@ -284,6 +288,78 @@ MGL_EXPORT
*/
@property (nonatomic, readonly, getter=isLoading) BOOL loading;
/**
The snapshotter’s delegate.
The delegate is responsible for responding to significant changes during the
snapshotting process, such as the style loading. Implement a delegate to
customize the style that is depicted by the snapshot.
You set the delegate after initializing the snapshotter but before receiving
the snapshot, typically before starting the snapshot. The snapshotter keeps a
weak reference to its delegate, so you must keep a strong reference to it to
ensure that your style customizations apply.
*/
@property (nonatomic, weak) id <MGLMapSnapshotterDelegate> delegate;
/**
The style displayed in the resulting snapshot.
Unlike the `MGLMapSnapshotOptions.styleURL` property, this property is set to
an object that allows you to manipulate every aspect of the style locally.
This property is set to `nil` until the style finishes loading. If the style
has failed to load, this property is set to `nil`. Because the style loads
asynchronously, you should manipulate it in the
`-[MGLMapSnapshotterDelegate mapSnapshotter:didFinishLoadingStyle:]` method. It
is not possible to manipulate the style before it has finished loading.
@note The default styles provided by Mapbox contain sources and layers with
identifiers that will change over time. Applications that use APIs that
manipulate a style’s sources and layers must first set the style URL to an
explicitly versioned style using a convenience method like
`+[MGLStyle outdoorsStyleURLWithVersion:]` or a manually constructed
`NSURL`.
*/
@property (nonatomic, readonly, nullable) MGLStyle *style;
@end
/**
Optional methods about significant events when creating a snapshot using an
`MGLMapSnapshotter` object.
*/
@protocol MGLMapSnapshotterDelegate <NSObject>
@optional
/**
Tells the delegate that the snapshotter was unable to load data needed for
snapshotting the map.
This method may be called for a variety of reasons, including a network
connection failure or a failure to fetch the style from the server. You can use
the given error message to notify the user that map data is unavailable.
@param snapshotter The snapshotter that is unable to load the data.
@param error The reason the data could not be loaded.
*/
- (void)mapSnapshotterDidFail:(MGLMapSnapshotter *)snapshotter withError:(NSError *)error;
/**
Tells the delegate that the snapshotter has just finished loading a style.
This method is called in response to
`-[MGLMapSnapshotter startWithQueue:completionHandler:]` as long as the
`MGLMapSnapshotter.delegate` property is set. Changes to sources or layers of
the style being snapshotted do not cause this method to be called.
@param snapshotter The snapshotter that has just loaded a style.
@param style The style that was loaded.
*/
- (void)mapSnapshotter:(MGLMapSnapshotter *)snapshotter didFinishLoadingStyle:(MGLStyle *)style;
- (void)mapSnapshotter:(MGLMapSnapshotter *)snapshotter didFailLoadingImageNamed:(NSString *)name;
@end
NS_ASSUME_NONNULL_END

View File

@@ -11,8 +11,7 @@
#import "MGLOfflineStorage_Private.h"
#import "MGLGeometry_Private.h"
#import "NSBundle+MGLAdditions.h"
#import "MGLStyle.h"
#import "MGLStyle_Private.h"
#import "MGLAttributionInfo_Private.h"
#import "MGLLoggingConfiguration_Private.h"
#import "MGLRendererConfiguration.h"
@@ -30,6 +29,8 @@
#import <QuartzCore/QuartzCore.h>
#endif
#import "NSBundle+MGLAdditions.h"
const CGPoint MGLLogoImagePosition = CGPointMake(8, 8);
const CGFloat MGLSnapshotterMinimumPixelSize = 64;
@@ -37,6 +38,41 @@ MGLImage *MGLAttributedSnapshot(mbgl::MapSnapshotter::Attributions attributions,
MGLMapSnapshot *MGLSnapshotWithDecoratedImage(MGLImage *mglImage, MGLMapSnapshotOptions *options, mbgl::MapSnapshotter::Attributions attributions, mbgl::MapSnapshotter::PointForFn pointForFn, mbgl::MapSnapshotter::LatLngForFn latLngForFn, MGLMapSnapshotOverlayHandler overlayHandler, NSError * _Nullable *outError);
NSArray<MGLAttributionInfo *> *MGLAttributionInfosFromAttributions(mbgl::MapSnapshotter::Attributions attributions);
class MGLMapSnapshotterDelegateHost: public mbgl::MapSnapshotterObserver {
public:
MGLMapSnapshotterDelegateHost(MGLMapSnapshotter *snapshotter_) : snapshotter(snapshotter_) {}
void onDidFailLoadingStyle(const std::string& errorMessage) {
MGLMapSnapshotter *strongSnapshotter = snapshotter;
if ([strongSnapshotter.delegate respondsToSelector:@selector(mapSnapshotterDidFail:withError:)]) {
NSString *description = @(errorMessage.c_str());
NSDictionary *userInfo = @{
NSLocalizedDescriptionKey: NSLocalizedStringWithDefaultValue(@"SNAPSHOT_LOAD_STYLE_FAILED_DESC", nil, nil, @"The snapshot failed because the style can’t be loaded.", @"User-friendly error description"),
NSLocalizedFailureReasonErrorKey: description,
};
NSError *error = [NSError errorWithDomain:MGLErrorDomain code:MGLErrorCodeLoadStyleFailed userInfo:userInfo];
[strongSnapshotter.delegate mapSnapshotterDidFail:snapshotter withError:error];
}
}
void onDidFinishLoadingStyle() {
MGLMapSnapshotter *strongSnapshotter = snapshotter;
if ([strongSnapshotter.delegate respondsToSelector:@selector(mapSnapshotter:didFinishLoadingStyle:)]) {
[strongSnapshotter.delegate mapSnapshotter:snapshotter didFinishLoadingStyle:snapshotter.style];
}
}
void onStyleImageMissing(const std::string& imageName) {
MGLMapSnapshotter *strongSnapshotter = snapshotter;
if ([strongSnapshotter.delegate respondsToSelector:@selector(mapSnapshotter:didFailLoadingImageNamed:)]) {
[strongSnapshotter.delegate mapSnapshotter:snapshotter didFailLoadingImageNamed:@(imageName.c_str())];
}
}
private:
__weak MGLMapSnapshotter *snapshotter;
};
@interface MGLMapSnapshotOverlay() <MGLMapSnapshotProtocol>
@property (nonatomic, assign) CGFloat scale;
- (instancetype)initWithContext:(CGContextRef)context scale:(CGFloat)scale pointForFn:(mbgl::MapSnapshotter::PointForFn)pointForFn latLngForFn:(mbgl::MapSnapshotter::LatLngForFn)latLngForFn;
@@ -208,6 +244,7 @@ NSArray<MGLAttributionInfo *> *MGLAttributionInfosFromAttributions(mbgl::MapSnap
@implementation MGLMapSnapshotter {
std::unique_ptr<mbgl::MapSnapshotter> _mbglMapSnapshotter;
std::unique_ptr<MGLMapSnapshotterDelegateHost> _delegateHost;
}
- (void)dealloc {
@@ -660,6 +697,7 @@ NSArray<MGLAttributionInfo *> *MGLAttributionInfosFromAttributions(mbgl::MapSnap
_mbglMapSnapshotter->cancel();
}
_mbglMapSnapshotter.reset();
_delegateHost.reset();
}
- (void)configureWithOptions:(MGLMapSnapshotOptions *)options {
@@ -682,8 +720,9 @@ NSArray<MGLAttributionInfo *> *MGLAttributionInfosFromAttributions(mbgl::MapSnap
.withAssetPath(NSBundle.mainBundle.resourceURL.path.UTF8String);
// Create the snapshotter
_delegateHost = std::make_unique<MGLMapSnapshotterDelegateHost>(self);
_mbglMapSnapshotter = std::make_unique<mbgl::MapSnapshotter>(
size, pixelRatio, resourceOptions, mbgl::MapSnapshotterObserver::nullObserver(), config.localFontFamilyName);
size, pixelRatio, resourceOptions, *_delegateHost, config.localFontFamilyName);
_mbglMapSnapshotter->setStyleURL(std::string(options.styleURL.absoluteString.UTF8String));
@@ -703,4 +742,11 @@ NSArray<MGLAttributionInfo *> *MGLAttributionInfosFromAttributions(mbgl::MapSnap
}
}
- (MGLStyle *)style {
if (!_mbglMapSnapshotter) {
return nil;
}
return [[MGLStyle alloc] initWithRawStyle:&_mbglMapSnapshotter->getStyle() stylable:self];
}
@end

View File

@@ -9,48 +9,7 @@
#include <mbgl/gl/custom_layer.hpp>
#include <mbgl/math/wrap.hpp>
class MGLOpenGLLayerHost : public mbgl::style::CustomLayerHost {
public:
MGLOpenGLLayerHost(MGLOpenGLStyleLayer *styleLayer) {
layerRef = styleLayer;
layer = nil;
}
void initialize() {
if (layerRef == nil) return;
else if (layer == nil) layer = layerRef;
[layer didMoveToMapView:layer.style.mapView];
}
void render(const mbgl::style::CustomLayerRenderParameters &params) {
if(!layer) return;
MGLStyleLayerDrawingContext drawingContext = {
.size = CGSizeMake(params.width, params.height),
.centerCoordinate = CLLocationCoordinate2DMake(params.latitude, params.longitude),
.zoomLevel = params.zoom,
.direction = mbgl::util::wrap(params.bearing, 0., 360.),
.pitch = static_cast<CGFloat>(params.pitch),
.fieldOfView = static_cast<CGFloat>(params.fieldOfView),
.projectionMatrix = MGLMatrix4Make(params.projectionMatrix)
};
[layer drawInMapView:layer.style.mapView withContext:drawingContext];
}
void contextLost() {}
void deinitialize() {
if (layer == nil) return;
[layer willMoveFromMapView:layer.style.mapView];
layerRef = layer;
layer = nil;
}
private:
__weak MGLOpenGLStyleLayer * layerRef;
MGLOpenGLStyleLayer * layer = nil;
};
class MGLOpenGLLayerHost;
/**
An `MGLOpenGLStyleLayer` is a style layer that is rendered by OpenGL code that
@@ -74,6 +33,8 @@ private:
@property (nonatomic, readonly) mbgl::style::CustomLayer *rawLayer;
@property (nonatomic, readonly, nullable) MGLMapView *mapView;
/**
The style currently containing the layer.
@@ -107,13 +68,20 @@ private:
return (mbgl::style::CustomLayer *)super.rawLayer;
}
- (MGLMapView *)mapView {
if ([self.style.stylable isKindOfClass:[MGLMapView class]]) {
return (MGLMapView *)self.style.stylable;
}
return nil;
}
#if TARGET_OS_IPHONE
- (EAGLContext *)context {
return self.style.mapView.context;
return self.mapView.context;
}
#else
- (CGLContextObj)context {
return self.style.mapView.context;
return self.mapView.context;
}
#endif
@@ -191,11 +159,60 @@ private:
causing the `-drawInMapView:withContext:` method to be called.
*/
- (void)setNeedsDisplay {
[self.style.mapView setNeedsRerender];
[self.mapView setNeedsRerender];
}
@end
class MGLOpenGLLayerHost : public mbgl::style::CustomLayerHost {
public:
MGLOpenGLLayerHost(MGLOpenGLStyleLayer *styleLayer) {
layerRef = styleLayer;
layer = nil;
}
void initialize() {
if (layerRef == nil) return;
else if (layer == nil) layer = layerRef;
if (layer.mapView) {
[layer didMoveToMapView:layer.mapView];
}
}
void render(const mbgl::style::CustomLayerRenderParameters &params) {
if(!layer) return;
MGLStyleLayerDrawingContext drawingContext = {
.size = CGSizeMake(params.width, params.height),
.centerCoordinate = CLLocationCoordinate2DMake(params.latitude, params.longitude),
.zoomLevel = params.zoom,
.direction = mbgl::util::wrap(params.bearing, 0., 360.),
.pitch = static_cast<CGFloat>(params.pitch),
.fieldOfView = static_cast<CGFloat>(params.fieldOfView),
.projectionMatrix = MGLMatrix4Make(params.projectionMatrix)
};
if (layer.mapView) {
[layer drawInMapView:layer.mapView withContext:drawingContext];
}
}
void contextLost() {}
void deinitialize() {
if (layer == nil) return;
if (layer.mapView) {
[layer willMoveFromMapView:layer.mapView];
}
layerRef = layer;
layer = nil;
}
private:
__weak MGLOpenGLStyleLayer * layerRef;
MGLOpenGLStyleLayer * layer = nil;
};
namespace mbgl {
MGLStyleLayer* OpenGLStyleLayerPeerFactory::createPeer(style::Layer* rawLayer) {

View File

@@ -243,8 +243,9 @@ mbgl::Immutable<mbgl::style::GeoJSONOptions> MGLGeoJSONOptionsFromDictionary(NSD
}
std::vector<mbgl::Feature> features;
if (self.mapView) {
features = self.mapView.renderer->querySourceFeatures(self.rawSource->getID(), { {}, optionalFilter });
if ([self.stylable isKindOfClass:[MGLMapView class]]) {
MGLMapView *mapView = (MGLMapView *)self.stylable;
features = mapView.renderer->querySourceFeatures(self.rawSource->getID(), { {}, optionalFilter });
}
return MGLFeaturesFromMBGLFeatures(features);
}
@@ -256,7 +257,7 @@ mbgl::Immutable<mbgl::style::GeoJSONOptions> MGLGeoJSONOptionsFromDictionary(NSD
mbgl::optional<mbgl::FeatureExtensionValue> extensionValue;
// Check parameters
if (!self.rawSource || !self.mapView || !cluster) {
if (!self.rawSource || !self.stylable || !cluster) {
return extensionValue;
}
@@ -269,11 +270,14 @@ mbgl::Immutable<mbgl::style::GeoJSONOptions> MGLGeoJSONOptionsFromDictionary(NSD
auto clusterFeature = geoJSON.get<mbgl::GeoJSONFeature>();
extensionValue = self.mapView.renderer->queryFeatureExtensions(self.rawSource->getID(),
clusterFeature,
"supercluster",
extension,
options);
if ([self.stylable isKindOfClass:[MGLMapView class]]) {
MGLMapView *mapView = (MGLMapView *)self.stylable;
extensionValue = mapView.renderer->queryFeatureExtensions(self.rawSource->getID(),
clusterFeature,
"supercluster",
extension,
options);
}
return extensionValue;
}

View File

@@ -19,7 +19,7 @@ const MGLExceptionName MGLInvalidStyleSourceException = @"MGLInvalidStyleSourceE
// special internal source types like mbgl::AnnotationSource.
@property (nonatomic, readonly) mbgl::style::Source *rawSource;
@property (nonatomic, readonly, weak) MGLMapView *mapView;
@property (nonatomic, readonly, weak) id <MGLStylable> stylable;
@end
@@ -37,12 +37,12 @@ const MGLExceptionName MGLInvalidStyleSourceException = @"MGLInvalidStyleSourceE
return self;
}
- (instancetype)initWithRawSource:(mbgl::style::Source *)rawSource mapView:(MGLMapView *)mapView {
- (instancetype)initWithRawSource:(mbgl::style::Source *)rawSource stylable:(id <MGLStylable>)stylable {
NSString *identifier = @(rawSource->getID().c_str());
if (self = [self initWithIdentifier:identifier]) {
_weakSource = rawSource->makeWeakPtr();
rawSource->peer = SourceWrapper { self };
_mapView = mapView;
_stylable = stylable;
}
return self;
}
@@ -53,24 +53,24 @@ const MGLExceptionName MGLInvalidStyleSourceException = @"MGLInvalidStyleSourceE
}
- (instancetype)initWithPendingSource:(std::unique_ptr<mbgl::style::Source>)pendingSource {
if (self = [self initWithRawSource:pendingSource.get() mapView:nil]) {
if (self = [self initWithRawSource:pendingSource.get() stylable:nil]) {
_pendingSource = std::move(pendingSource);
}
return self;
}
- (void)addToMapView:(MGLMapView *)mapView {
- (void)addToStylable:(id <MGLStylable>)stylable {
if (_pendingSource == nullptr) {
[NSException raise:MGLRedundantSourceException
format:@"This instance %@ was already added to %@. Adding the same source instance " \
"to the style more than once is invalid.", self, mapView.style];
"to the style more than once is invalid.", self, stylable.style];
}
_mapView = mapView;
_mapView.style.rawStyle->addSource(std::move(_pendingSource));
_stylable = stylable;
_stylable.style.rawStyle->addSource(std::move(_pendingSource));
}
- (BOOL)removeFromMapView:(MGLMapView *)mapView error:(NSError * __nullable * __nullable)outError {
- (BOOL)removeFromStylable:(id <MGLStylable>)mapView error:(NSError * __nullable * __nullable)outError {
MGLAssertStyleSourceIsValid();
BOOL removed = NO;
@@ -81,7 +81,7 @@ const MGLExceptionName MGLInvalidStyleSourceException = @"MGLInvalidStyleSourceE
if (removedSource) {
removed = YES;
_pendingSource = std::move(removedSource);
_mapView = nil;
_stylable = nil;
} else if (outError) {
NSString *localizedDescription = [NSString stringWithFormat:
NSLocalizedStringWithDefaultValue(@"REMOVE_SRC_FAIL_IN_USE_FMT", @"Foundation", nil, @"The source “%@” can’t be removed while it is in use.", @"User-friendly error description; first placeholder is the source’s identifier"),

View File

@@ -5,6 +5,8 @@
NS_ASSUME_NONNULL_BEGIN
@protocol MGLStylable;
namespace mbgl {
namespace style {
class Source;
@@ -41,7 +43,7 @@ do { \
Initializes and returns a source with a raw pointer to the backing store,
associated with a style.
*/
- (instancetype)initWithRawSource:(mbgl::style::Source *)rawSource mapView:(nullable MGLMapView *)mapView;
- (instancetype)initWithRawSource:(mbgl::style::Source *)rawSource stylable:(nullable id <MGLStylable>)stylable;
/**
Initializes and returns a source with an owning pointer to the backing store,
@@ -59,11 +61,12 @@ do { \
@property (nonatomic, readonly) mbgl::style::Source *rawSource;
/**
The map view whose style currently contains the source.
If the source is not currently part of any map view’s style, this property is
set to `nil`.
The stylable object whose style currently contains the source.
If the source is not currently part of any stylable object’s style, this
property is set to `nil`.
*/
@property (nonatomic, readonly, weak) MGLMapView *mapView;
@property (nonatomic, readonly, weak) id <MGLStylable> stylable;
/**
Adds the mbgl source that this object represents to the mbgl map.
@@ -74,7 +77,7 @@ do { \
is added back to the map via `-[MGLStyle addSource:]` and styled with a
`MGLLayer`.
*/
- (void)addToMapView:(MGLMapView *)mapView;
- (void)addToStylable:(id <MGLStylable>)mapView;
/**
Removes the mbgl source that this object represents from the mbgl map.
@@ -82,7 +85,7 @@ do { \
to the `MGLSource` instance and the unique_ptr reference is valid again. It is
safe to add the source back to the style after it is removed.
*/
- (BOOL)removeFromMapView:(MGLMapView *)mapView error:(NSError * __nullable * __nullable)outError;
- (BOOL)removeFromStylable:(id <MGLStylable>)mapView error:(NSError * __nullable * __nullable)outError;
@end

View File

@@ -539,4 +539,24 @@ MGL_EXPORT
@end
/**
An object whose contents are represented by an `MGLStyle` object that you
configure.
*/
@protocol MGLStylable <NSObject>
/**
The style currently displayed in the receiver.
@note The default styles provided by Mapbox contain sources and layers with
identifiers that will change over time. Applications that use APIs that
manipulate a style’s sources and layers must first set the style URL to an
explicitly versioned style using a convenience method like
`+[MGLStyle outdoorsStyleURLWithVersion:]` or a manually constructed
`NSURL`.
*/
@property (nonatomic, readonly, nullable) MGLStyle *style;
@end
NS_ASSUME_NONNULL_END

View File

@@ -77,7 +77,7 @@ const MGLExceptionName MGLRedundantSourceIdentifierException = @"MGLRedundantSou
@interface MGLStyle()
@property (nonatomic, readonly, weak) MGLMapView *mapView;
@property (nonatomic, readonly, weak) id <MGLStylable> stylable;
@property (nonatomic, readonly) mbgl::style::Style *rawStyle;
@property (readonly, copy, nullable) NSURL *URL;
@property (nonatomic, readwrite, strong) NSMutableDictionary<NSString *, MGLOpenGLStyleLayer *> *openGLLayers;
@@ -119,14 +119,14 @@ static_assert(6 == mbgl::util::default_styles::numOrderedStyles,
#pragma mark -
- (instancetype)initWithRawStyle:(mbgl::style::Style *)rawStyle mapView:(MGLMapView *)mapView {
MGLLogInfo(@"Initializing %@ with mapView: %@", NSStringFromClass([self class]), mapView);
- (instancetype)initWithRawStyle:(mbgl::style::Style *)rawStyle stylable:(id <MGLStylable>)stylable {
MGLLogInfo(@"Initializing %@ with stylable: %@", NSStringFromClass([self class]), stylable);
if (self = [super init]) {
_mapView = mapView;
_stylable = stylable;
_rawStyle = rawStyle;
_openGLLayers = [NSMutableDictionary dictionary];
_localizedLayersByIdentifier = [NSMutableDictionary dictionary];
MGLLogDebug(@"Initializing with style name: %@ mapView: %@", self.name, mapView);
MGLLogDebug(@"Initializing with style name: %@ stylable: %@", self.name, stylable);
}
return self;
}
@@ -186,17 +186,17 @@ static_assert(6 == mbgl::util::default_styles::numOrderedStyles,
// TODO: Fill in options specific to the respective source classes
// https://github.com/mapbox/mapbox-gl-native/issues/6584
if (auto vectorSource = rawSource->as<mbgl::style::VectorSource>()) {
return [[MGLVectorTileSource alloc] initWithRawSource:vectorSource mapView:self.mapView];
return [[MGLVectorTileSource alloc] initWithRawSource:vectorSource stylable:self.stylable];
} else if (auto geoJSONSource = rawSource->as<mbgl::style::GeoJSONSource>()) {
return [[MGLShapeSource alloc] initWithRawSource:geoJSONSource mapView:self.mapView];
return [[MGLShapeSource alloc] initWithRawSource:geoJSONSource stylable:self.stylable];
} else if (auto rasterSource = rawSource->as<mbgl::style::RasterSource>()) {
return [[MGLRasterTileSource alloc] initWithRawSource:rasterSource mapView:self.mapView];
return [[MGLRasterTileSource alloc] initWithRawSource:rasterSource stylable:self.stylable];
} else if (auto rasterDEMSource = rawSource->as<mbgl::style::RasterDEMSource>()) {
return [[MGLRasterDEMSource alloc] initWithRawSource:rasterDEMSource mapView:self.mapView];
return [[MGLRasterDEMSource alloc] initWithRawSource:rasterDEMSource stylable:self.stylable];
} else if (auto imageSource = rawSource->as<mbgl::style::ImageSource>()) {
return [[MGLImageSource alloc] initWithRawSource:imageSource mapView:self.mapView];
return [[MGLImageSource alloc] initWithRawSource:imageSource stylable:self.stylable];
} else {
return [[MGLSource alloc] initWithRawSource:rawSource mapView:self.mapView];
return [[MGLSource alloc] initWithRawSource:rawSource stylable:self.stylable];
}
}
@@ -211,7 +211,7 @@ static_assert(6 == mbgl::util::default_styles::numOrderedStyles,
}
try {
[source addToMapView:self.mapView];
[source addToStylable:self.stylable];
} catch (std::runtime_error & err) {
[NSException raise:MGLRedundantSourceIdentifierException format:@"%s", err.what()];
}
@@ -243,7 +243,7 @@ static_assert(6 == mbgl::util::default_styles::numOrderedStyles,
}
}
return [source removeFromMapView:self.mapView error:outError];
return [source removeFromStylable:self.stylable error:outError];
}

View File

@@ -19,9 +19,9 @@ namespace mbgl {
@interface MGLStyle (Private)
- (instancetype)initWithRawStyle:(mbgl::style::Style *)rawStyle mapView:(MGLMapView *)mapView;
- (instancetype)initWithRawStyle:(mbgl::style::Style *)rawStyle stylable:(id <MGLStylable>)stylable;
@property (nonatomic, readonly, weak) MGLMapView *mapView;
@property (nonatomic, readonly, weak) id <MGLStylable> stylable;
@property (nonatomic, readonly) mbgl::style::Style *rawStyle;
- (nullable NSArray<MGLAttributionInfo *> *)attributionInfosWithFontSize:(CGFloat)fontSize linkColor:(nullable MGLColor *)linkColor;

View File

@@ -72,8 +72,9 @@
}
std::vector<mbgl::Feature> features;
if (self.mapView) {
features = self.mapView.renderer->querySourceFeatures(self.rawSource->getID(), { optionalSourceLayerIDs, optionalFilter });
if ([self.stylable isKindOfClass:[MGLMapView class]]) {
MGLMapView *mapView = (MGLMapView *)self.stylable;
features = mapView.renderer->querySourceFeatures(self.rawSource->getID(), { optionalSourceLayerIDs, optionalFilter });
}
return MGLFeaturesFromMBGLFeatures(features);
}

View File

@@ -15,6 +15,7 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONT
### Snapshots
* Added the `MGLMapSnapshotter.delegate` property and `MGLMapSnapshotterDelegate` protocol for customizing the style before taking a snapshot. ([#235](https://github.com/mapbox/mapbox-gl-native-ios/pull/235))
* You no longer need to explicitly capture the `MGLMapSnapshotter` object in the completion handler that you specify in `-[MGLMapSnapshotter startWithCompletionHandler:]`. Even if you declare the snapshotter locally without holding a strong reference to it, the snapshotter is only deallocated after the completion handler finishes, and the completion handler generally receives a valid snapshot. ([#210](https://github.com/mapbox/mapbox-gl-native-ios/pull/210))
* The `-[MGLMapSnapshotter cancel]` method no longer calls the completion handler passed into `-[MGLMapSnapshotter startWithCompletionHandler:]`. ([#210](https://github.com/mapbox/mapbox-gl-native-ios/pull/210))
* Fixed an issue where the `MGLMapSnapshotter.loading` property always returned `NO`, even while loading a snapshot. ([#210](https://github.com/mapbox/mapbox-gl-native-ios/pull/210))

View File

@@ -50,7 +50,7 @@ void MGLMapViewImpl::onDidFailLoadingMap(mbgl::MapLoadError mapError, const std:
break;
case mbgl::MapLoadError::StyleLoadError:
code = MGLErrorCodeLoadStyleFailed;
description = NSLocalizedStringWithDefaultValue(@"LOAD_STYLE_FAILED_DESC", nil, nil, @"The map failed to load because the style can't be loaded.", @"User-friendly error description");
description = NSLocalizedStringWithDefaultValue(@"LOAD_STYLE_FAILED_DESC", nil, nil, @"The map failed to load because the style can’t be loaded.", @"User-friendly error description");
break;
case mbgl::MapLoadError::NotFoundError:
code = MGLErrorCodeNotFound;

View File

@@ -5,6 +5,7 @@
#import "MGLGeometry.h"
#import "MGLMapCamera.h"
#import "MGLTypes.h"
#import "MGLStyle.h"
NS_ASSUME_NONNULL_BEGIN
@@ -14,7 +15,6 @@ NS_ASSUME_NONNULL_BEGIN
@class MGLPolyline;
@class MGLPolygon;
@class MGLShape;
@class MGLStyle;
@protocol MGLMapViewDelegate;
@protocol MGLAnnotation;
@@ -188,7 +188,7 @@ FOUNDATION_EXTERN MGL_EXPORT MGLExceptionName const MGLUserLocationAnnotationTyp
Simple map view</a> example to learn how to initialize a basic `MGLMapView`.
*/
MGL_EXPORT
@interface MGLMapView : UIView
@interface MGLMapView : UIView <MGLStylable>
#pragma mark Creating Instances

View File

@@ -6459,7 +6459,7 @@ public:
return;
}
self.style = [[MGLStyle alloc] initWithRawStyle:&self.mbglMap.getStyle() mapView:self];
self.style = [[MGLStyle alloc] initWithRawStyle:&self.mbglMap.getStyle() stylable:self];
if ([self.delegate respondsToSelector:@selector(mapView:didFinishLoadingStyle:)])
{
[self.delegate mapView:self didFinishLoadingStyle:self.style];

View File

@@ -46,6 +46,7 @@
### Snapshots
* Added an `-[MGLMapSnapshotter startWithOverlayHandler:completionHandler:]` method to provide the snapshot's current `CGContext` in order to perform custom drawing on `MGLMapSnapshot` objects. ([#15530](https://github.com/mapbox/mapbox-gl-native/pull/15530))
* Added the `MGLMapSnapshotter.delegate` property and `MGLMapSnapshotterDelegate` protocol for customizing the style before taking a snapshot. ([#235](https://github.com/mapbox/mapbox-gl-native-ios/pull/235))
* You no longer need to explicitly capture the `MGLMapSnapshotter` object in the completion handler that you specify in `-[MGLMapSnapshotter startWithCompletionHandler:]`. Even if you declare the snapshotter locally without holding a strong reference to it, the snapshotter is only deallocated after the completion handler finishes, and the completion handler generally receives a valid snapshot. ([#210](https://github.com/mapbox/mapbox-gl-native-ios/pull/210))
* The `-[MGLMapSnapshotter cancel]` method no longer calls the completion handler passed into `-[MGLMapSnapshotter startWithCompletionHandler:]`. ([#210](https://github.com/mapbox/mapbox-gl-native-ios/pull/210))
* Fixed an issue where the `MGLMapSnapshotter.loading` property always returned `NO`, even while loading a snapshot. ([#210](https://github.com/mapbox/mapbox-gl-native-ios/pull/210))

View File

@@ -4,12 +4,12 @@
#import "MGLFoundation.h"
#import "MGLTypes.h"
#import "MGLGeometry.h"
#import "MGLStyle.h"
NS_ASSUME_NONNULL_BEGIN
@class MGLAnnotationImage;
@class MGLMapCamera;
@class MGLStyle;
@class MGLShape;
@protocol MGLAnnotation;
@@ -65,7 +65,7 @@ NS_ASSUME_NONNULL_BEGIN
ensuring that your use adheres to the relevant terms of use.
*/
MGL_EXPORT IB_DESIGNABLE
@interface MGLMapView : NSView
@interface MGLMapView : NSView <MGLStylable>
#pragma mark Creating Instances

View File

@@ -961,7 +961,7 @@ public:
return;
}
self.style = [[MGLStyle alloc] initWithRawStyle:&_mbglMap->getStyle() mapView:self];
self.style = [[MGLStyle alloc] initWithRawStyle:&_mbglMap->getStyle() stylable:self];
if ([self.delegate respondsToSelector:@selector(mapView:didFinishLoadingStyle:)])
{
[self.delegate mapView:self didFinishLoadingStyle:self.style];