summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNadia Barbosa <nadiabarbosa@me.com>2019-09-09 16:17:58 -0700
committerNadia Barbosa <nadiabarbosa@me.com>2019-09-13 12:11:23 -0700
commit3be0f9bc269804781a44bfcf294e22878bef9cb4 (patch)
tree2bd656312d2e2bcd1b16ca4072c136cf09474c14
parent69bc5244eaaecb708e8a492f7017a451245d92bb (diff)
downloadqtlocation-mapboxgl-upstream/nb-snapshot-overlay-with-example.tar.gz
[ios, macos] Introduce custom drawing overlays for MGLMapSnapshotterupstream/nb-snapshot-overlay-with-example
-rw-r--r--platform/darwin/src/MGLMapSnapshotter.h33
-rw-r--r--platform/darwin/src/MGLMapSnapshotter.mm79
-rw-r--r--platform/ios/CHANGELOG.md3
-rw-r--r--platform/ios/Integration Tests/Snapshotter Tests/MGLMapSnapshotterTest.m57
-rw-r--r--platform/ios/MBXContextSnapshotViewController.m77
-rw-r--r--platform/ios/app/MBXContextSnapshotViewController.h17
-rw-r--r--platform/ios/app/MBXContextSnapshotViewController.m92
-rw-r--r--platform/ios/app/Main.storyboard25
-rw-r--r--platform/ios/ios.xcodeproj/project.pbxproj6
-rw-r--r--platform/macos/CHANGELOG.md1
10 files changed, 374 insertions, 16 deletions
diff --git a/platform/darwin/src/MGLMapSnapshotter.h b/platform/darwin/src/MGLMapSnapshotter.h
index 1ee9bd99bb..79767a8110 100644
--- a/platform/darwin/src/MGLMapSnapshotter.h
+++ b/platform/darwin/src/MGLMapSnapshotter.h
@@ -5,6 +5,27 @@
NS_ASSUME_NONNULL_BEGIN
+MGL_EXPORT
+
+/**
+ An overlay that is placed within a `MGLMapSnapshot`.
+
+ To access this object, use `-[MGLMapSnapshotter startWithOverlayHandler:completionHandler:]`.
+ */
+
+@interface MGLMapSnapshotOverlay : NSObject
+
+/**
+ The current `CGContext` that snapshot is drawing within. You may use this context
+ to perform additional custom drawing.
+ */
+@property CGContextRef context;
+
+@end
+
+
+typedef void (^MGLMapSnapshotOverlayHandler)(MGLMapSnapshotOverlay * _Nullable snapshotOverlay);
+
/**
The options to use when creating images with the `MGLMapSnapshotter`.
*/
@@ -200,6 +221,18 @@ MGL_EXPORT
*/
- (void)startWithQueue:(dispatch_queue_t)queue completionHandler:(MGLMapSnapshotCompletionHandler)completionHandler;
+
+/*
+ Starts the snapshot creation and executes the specified blocks with the result
+ on the specified queue. Use this option if you want to add custom drawing on top of the
+ resulting `MGLMapSnapShot`.
+
+ @param queue The queue to handle the result on.
+ @param overlayHandler The block to handle manipulation of the `MGLMapSnapshotter`'s `CGContext`.
+ @param completionHandler The block to handle the result in.
+ */
+- (void)startWithOverlayHandler:(MGLMapSnapshotOverlayHandler)overlayHandler completionHandler:(MGLMapSnapshotCompletionHandler)completionHandler;
+
/**
Cancels the snapshot creation request, if any.
diff --git a/platform/darwin/src/MGLMapSnapshotter.mm b/platform/darwin/src/MGLMapSnapshotter.mm
index 0001ebcb86..cd0ede0a97 100644
--- a/platform/darwin/src/MGLMapSnapshotter.mm
+++ b/platform/darwin/src/MGLMapSnapshotter.mm
@@ -32,6 +32,26 @@
const CGPoint MGLLogoImagePosition = CGPointMake(8, 8);
const CGFloat MGLSnapshotterMinimumPixelSize = 64;
+
+@interface MGLMapSnapshotOverlay()
+
+- (instancetype)initWithContext:(CGContextRef)context;
+
+@end
+
+@implementation MGLMapSnapshotOverlay
+
+- (instancetype) initWithContext:(CGContextRef)context {
+ self = [super init];
+ if (self) {
+ _context = context;
+ }
+
+ return self;
+}
+
+@end
+
@implementation MGLMapSnapshotOptions
- (instancetype _Nonnull)initWithStyleURL:(nullable NSURL *)styleURL camera:(MGLMapCamera *)camera size:(CGSize)size
@@ -183,7 +203,15 @@ const CGFloat MGLSnapshotterMinimumPixelSize = 64;
[self startWithQueue:dispatch_get_main_queue() completionHandler:completion];
}
-- (void)startWithQueue:(dispatch_queue_t)queue completionHandler:(MGLMapSnapshotCompletionHandler)completion
+- (void)startWithQueue:(dispatch_queue_t)queue completionHandler:(MGLMapSnapshotCompletionHandler)completionHandler {
+ [self startWithQueue:queue overlayHandler:nil completionHandler:completionHandler];
+}
+
+- (void)startWithOverlayHandler:(MGLMapSnapshotOverlayHandler)overlayHandler completionHandler:(MGLMapSnapshotCompletionHandler)completion {
+ [self startWithQueue:dispatch_get_main_queue() overlayHandler:overlayHandler completionHandler:completion];
+}
+
+- (void)startWithQueue:(dispatch_queue_t)queue overlayHandler:(MGLMapSnapshotOverlayHandler)overlayHandler completionHandler:(MGLMapSnapshotCompletionHandler)completion
{
if (!mbgl::Scheduler::GetCurrent()) {
[NSException raise:NSInvalidArgumentException
@@ -206,6 +234,7 @@ const CGFloat MGLSnapshotterMinimumPixelSize = 64;
self.cancelled = NO;
__weak __typeof__(self) weakSelf = self;
+
// mbgl::Scheduler::GetCurrent() scheduler means "run callback on current (ie UI/main) thread"
// capture weakSelf to avoid retain cycle if callback is never called (ie snapshot cancelled)
@@ -238,7 +267,8 @@ const CGFloat MGLSnapshotterMinimumPixelSize = 64;
mglImage.size = NSMakeSize(mglImage.size.width / strongSelf.options.scale,
mglImage.size.height / strongSelf.options.scale);
#endif
- [strongSelf drawAttributedSnapshot:attributions snapshotImage:mglImage pointForFn:pointForFn latLngForFn:latLngForFn];
+
+ [strongSelf drawAttributedSnapshot:attributions snapshotImage:mglImage pointForFn:pointForFn latLngForFn:latLngForFn overlayHandler:overlayHandler];
}
strongSelf->_snapshotCallback = NULL;
@@ -250,7 +280,7 @@ const CGFloat MGLSnapshotterMinimumPixelSize = 64;
_mbglMapSnapshotter->snapshot(_snapshotCallback->self());
}
-+ (MGLImage*)drawAttributedSnapshotWorker:(mbgl::MapSnapshotter::Attributions)attributions snapshotImage:(MGLImage *)mglImage pointForFn:(mbgl::MapSnapshotter::PointForFn)pointForFn latLngForFn:(mbgl::MapSnapshotter::LatLngForFn)latLngForFn scale:(CGFloat)scale size:(CGSize)size {
++ (MGLImage*)drawAttributedSnapshotWorker:(mbgl::MapSnapshotter::Attributions)attributions snapshotImage:(MGLImage *)mglImage pointForFn:(mbgl::MapSnapshotter::PointForFn)pointForFn latLngForFn:(mbgl::MapSnapshotter::LatLngForFn)latLngForFn scale:(CGFloat)scale size:(CGSize)size overlayHandler:(MGLMapSnapshotOverlayHandler)overlayHandler {
NSArray<MGLAttributionInfo *>* attributionInfo = [MGLMapSnapshotter generateAttributionInfos:attributions];
@@ -292,6 +322,22 @@ const CGFloat MGLSnapshotterMinimumPixelSize = 64;
UIGraphicsBeginImageContextWithOptions(mglImage.size, NO, scale);
[mglImage drawInRect:CGRectMake(0, 0, mglImage.size.width, mglImage.size.height)];
+
+ CGContextRef currentContext = UIGraphicsGetCurrentContext();
+
+ if (currentContext && overlayHandler) {
+ MGLMapSnapshotOverlay *snapshotOverlay = [[MGLMapSnapshotOverlay alloc] initWithContext:currentContext];
+ CGContextSaveGState(snapshotOverlay.context);
+ overlayHandler(snapshotOverlay);
+ CGContextRestoreGState(snapshotOverlay.context);
+ currentContext = UIGraphicsGetCurrentContext();
+ }
+
+ if (!currentContext && overlayHandler) {
+ // If the current context has been corrupted by the user,
+ // return nil so we can generate an error later.
+ return nil;
+ }
[logoImage drawInRect:logoImageRect];
@@ -379,7 +425,7 @@ const CGFloat MGLSnapshotterMinimumPixelSize = 64;
#endif
}
-- (void)drawAttributedSnapshot:(mbgl::MapSnapshotter::Attributions)attributions snapshotImage:(MGLImage *)mglImage pointForFn:(mbgl::MapSnapshotter::PointForFn)pointForFn latLngForFn:(mbgl::MapSnapshotter::LatLngForFn)latLngForFn {
+- (void)drawAttributedSnapshot:(mbgl::MapSnapshotter::Attributions)attributions snapshotImage:(MGLImage *)mglImage pointForFn:(mbgl::MapSnapshotter::PointForFn)pointForFn latLngForFn:(mbgl::MapSnapshotter::LatLngForFn)latLngForFn overlayHandler:(MGLMapSnapshotOverlayHandler)overlayHandler {
// Process image watermark in a work queue
dispatch_queue_t workQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
@@ -394,19 +440,30 @@ const CGFloat MGLSnapshotterMinimumPixelSize = 64;
dispatch_async(workQueue, ^{
// Call a class method to ensure we're not accidentally capturing self
- MGLImage *compositedImage = [MGLMapSnapshotter drawAttributedSnapshotWorker:attributions snapshotImage:mglImage pointForFn:pointForFn latLngForFn:latLngForFn scale:scale size:size];
+ MGLImage *compositedImage = [MGLMapSnapshotter drawAttributedSnapshotWorker:attributions snapshotImage:mglImage pointForFn:pointForFn latLngForFn:latLngForFn scale:scale size:size overlayHandler:overlayHandler];
// Dispatch result to origin queue
dispatch_async(resultQueue, ^{
__typeof__(self) strongself = weakself;
if (strongself.completion) {
- MGLMapSnapshot* snapshot = [[MGLMapSnapshot alloc] initWithImage:compositedImage
- scale:scale
- pointForFn:pointForFn
- latLngForFn:latLngForFn];
- strongself.completion(snapshot, nil);
- strongself.completion = nil;
+
+ if (!compositedImage) {
+ NSDictionary *userInfo = @{NSLocalizedDescriptionKey: @"Failed to generate composited snapshot."};
+ NSError *error = [NSError errorWithDomain:MGLErrorDomain
+ code:MGLErrorCodeSnapshotFailed
+ userInfo:userInfo];
+
+ strongself.completion(nil, error);
+ strongself.completion = nil;
+ } else {
+ MGLMapSnapshot* snapshot = [[MGLMapSnapshot alloc] initWithImage:compositedImage
+ scale:scale
+ pointForFn:pointForFn
+ latLngForFn:latLngForFn];
+ strongself.completion(snapshot, nil);
+ strongself.completion = nil;
+ }
}
});
});
diff --git a/platform/ios/CHANGELOG.md b/platform/ios/CHANGELOG.md
index 15f5904b5d..9c8ae88e79 100644
--- a/platform/ios/CHANGELOG.md
+++ b/platform/ios/CHANGELOG.md
@@ -2,6 +2,9 @@
Mapbox welcomes participation and contributions from everyone. Please read [CONTRIBUTING.md](../../CONTRIBUTING.md) to get started.
+## master
+* 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))
+
## 5.4.0
### Styles and rendering
diff --git a/platform/ios/Integration Tests/Snapshotter Tests/MGLMapSnapshotterTest.m b/platform/ios/Integration Tests/Snapshotter Tests/MGLMapSnapshotterTest.m
index 32e5fc782d..29014035a8 100644
--- a/platform/ios/Integration Tests/Snapshotter Tests/MGLMapSnapshotterTest.m
+++ b/platform/ios/Integration Tests/Snapshotter Tests/MGLMapSnapshotterTest.m
@@ -429,5 +429,62 @@ MGLMapSnapshotter* snapshotterWithCoordinates(CLLocationCoordinate2D coordinates
[self waitForExpectations:@[expectation] timeout:10.0];
}
+- (void)testSnapshotWithOverlayHandlerFailure {
+ if (![self validAccessToken]) {
+ return;
+ }
+
+ CGSize size = self.mapView.bounds.size;
+
+ XCTestExpectation *expectation = [self expectationWithDescription:@"snapshot with overlay fails"];
+ expectation.expectedFulfillmentCount = 2;
+
+ CLLocationCoordinate2D coord = CLLocationCoordinate2DMake(30.0, 30.0);
+
+ MGLMapSnapshotter *snapshotter = snapshotterWithCoordinates(coord, size);
+ XCTAssertNotNil(snapshotter);
+
+ [snapshotter startWithOverlayHandler:^(MGLMapSnapshotOverlay * _Nullable snapshotOverlay) {
+ UIGraphicsEndImageContext();
+ [expectation fulfill];
+ } completionHandler:^(MGLMapSnapshot * _Nullable snapshot, NSError * _Nullable error) {
+ XCTAssertNil(snapshot);
+ XCTAssertNotNil(error);
+ [expectation fulfill];
+ }];
+
+ [self waitForExpectations:@[expectation] timeout:10.0];
+}
+
+- (void)testSnapshotWithOverlayHandlerSuccess {
+ if (![self validAccessToken]) {
+ return;
+ }
+
+ CGSize size = self.mapView.bounds.size;
+ CGRect snapshotRect = CGRectMake(0, 0, size.width, size.height);
+
+ XCTestExpectation *expectation = [self expectationWithDescription:@"snapshot with overlay succeeds"];
+ expectation.expectedFulfillmentCount = 2;
+
+ CLLocationCoordinate2D coord = CLLocationCoordinate2DMake(30.0, 30.0);
+
+ MGLMapSnapshotter *snapshotter = snapshotterWithCoordinates(coord, size);
+ XCTAssertNotNil(snapshotter);
+
+ [snapshotter startWithOverlayHandler:^(MGLMapSnapshotOverlay * _Nullable snapshotOverlay) {
+ CGContextSetFillColorWithColor(snapshotOverlay.context, [UIColor.greenColor CGColor]);
+ CGContextSetAlpha(snapshotOverlay.context, 0.2);
+ CGContextAddRect(snapshotOverlay.context, snapshotRect);
+ CGContextFillRect(snapshotOverlay.context, snapshotRect);
+ [expectation fulfill];
+ } completionHandler:^(MGLMapSnapshot * _Nullable snapshot, NSError * _Nullable error) {
+ XCTAssertNil(error);
+ XCTAssertNotNil(snapshot);
+ [expectation fulfill];
+ }];
+
+ [self waitForExpectations:@[expectation] timeout:10.0];
+}
@end
diff --git a/platform/ios/MBXContextSnapshotViewController.m b/platform/ios/MBXContextSnapshotViewController.m
new file mode 100644
index 0000000000..61504f94a5
--- /dev/null
+++ b/platform/ios/MBXContextSnapshotViewController.m
@@ -0,0 +1,77 @@
+#import "MBXContextSnapshotViewController.h"
+#import <Mapbox/Mapbox.h>
+
+@interface MBXContextSnapshotViewController () <MGLMapViewDelegate>
+@property MGLMapView *mapView;
+@property UIButton *button;
+@property UIImageView *imageView;
+@end
+
+@implementation MBXContextSnapshotViewController
+
+- (void)viewDidLoad {
+ [super viewDidLoad];
+
+ _mapView = [[MGLMapView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height / 2) styleURL:[MGLStyle lightStyleURL]];
+ _mapView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
+
+
+ [_mapView setCenterCoordinate:_mapView.centerCoordinate zoomLevel:1 animated:NO];
+ [self.view addSubview:_mapView];
+
+
+ _button = [[UIButton alloc] initWithFrame:CGRectMake(_mapView.frame.origin.x + 100, _mapView.frame.origin.y + 45, 170, 30)];
+ _button.layer.cornerRadius = 15;
+ _button.backgroundColor = [UIColor blueColor];
+ [_button setTitle:@"Create snapshot" forState:UIControlStateNormal];
+ [_button addTarget:self action:@selector(createSnapshot) forControlEvents:UIControlEventTouchUpInside];
+ [self.view addSubview:_button];
+
+ _imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, self.view.bounds.size.height / 2, self.view.bounds.size.width, self.view.bounds.size.height / 2)];
+ _imageView.backgroundColor = [UIColor blackColor];
+ _imageView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
+ [self.view addSubview:_imageView];
+}
+
+- (void)createSnapshot {
+
+ MGLMapSnapshotOptions *options = [[MGLMapSnapshotOptions alloc] initWithStyleURL:_mapView.styleURL camera:_mapView.camera size:_mapView.bounds.size];
+
+ options.zoomLevel = _mapView.zoomLevel;
+
+ UIActivityIndicatorView *indicator = [[UIActivityIndicatorView alloc] initWithFrame:CGRectMake(_imageView.center.x - 30, _imageView.center.y - 30, 60, 60)];
+ [self.view addSubview:indicator];
+ [indicator startAnimating];
+
+ __block MGLMapSnapshotter *snapshotter = [[MGLMapSnapshotter alloc] initWithOptions:options];
+
+// [snapshotter startWithCompletionHandler:^(MGLMapSnapshot * _Nullable snapshot, NSError * _Nullable error) {
+// if (error != nil) {
+// NSLog(@"Unable to create a map snapshot.");
+// } else if (snapshot != nil) {
+// // Add the map snapshot's image to the image view.
+// [indicator stopAnimating];
+// self.imageView.image = snapshot.image;
+// }
+//
+// snapshotter = nil;
+// }];
+
+ [snapshotter startWithOverlayHandler:^(NSString * _Nullable testString) {
+ NSLog(@"STRING: %@", testString);
+ } completionHandler:^(MGLMapSnapshot * _Nullable snapshot, NSError * _Nullable error) {
+ if (error != nil) {
+ NSLog(@"Unable to create a map snapshot.");
+ } else if (snapshot != nil) {
+ // Add the map snapshot's image to the image view.
+ [indicator stopAnimating];
+ self.imageView.image = snapshot.image;
+ }
+
+ snapshotter = nil;
+ }];
+
+
+}
+
+@end
diff --git a/platform/ios/app/MBXContextSnapshotViewController.h b/platform/ios/app/MBXContextSnapshotViewController.h
new file mode 100644
index 0000000000..69793e5c7e
--- /dev/null
+++ b/platform/ios/app/MBXContextSnapshotViewController.h
@@ -0,0 +1,17 @@
+//
+// MBXContextSnapshotViewController.h
+// iosapp
+//
+// Created by Nadia Barbosa on 9/9/19.
+// Copyright © 2019 Mapbox. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface MBXContextSnapshotViewController : UIViewController
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/platform/ios/app/MBXContextSnapshotViewController.m b/platform/ios/app/MBXContextSnapshotViewController.m
new file mode 100644
index 0000000000..09640ca95b
--- /dev/null
+++ b/platform/ios/app/MBXContextSnapshotViewController.m
@@ -0,0 +1,92 @@
+#import "MBXContextSnapshotViewController.h"
+#import <Mapbox/Mapbox.h>
+
+@interface MBXContextSnapshotViewController () <MGLMapViewDelegate>
+@property MGLMapView *mapView;
+@property UIButton *button;
+@property UIImageView *imageView;
+@end
+
+@implementation MBXContextSnapshotViewController
+
+- (void)viewDidLoad {
+ [super viewDidLoad];
+
+ _mapView = [[MGLMapView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height / 2) styleURL:[MGLStyle lightStyleURL]];
+ _mapView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
+
+
+ [_mapView setCenterCoordinate:_mapView.centerCoordinate zoomLevel:1 animated:NO];
+ [self.view addSubview:_mapView];
+
+ _button = [[UIButton alloc] initWithFrame:CGRectMake(_mapView.frame.origin.x + 100, _mapView.frame.origin.y + 45, 170, 30)];
+ _button.layer.cornerRadius = 15;
+ _button.backgroundColor = [UIColor blueColor];
+ [_button setTitle:@"Create snapshot" forState:UIControlStateNormal];
+ [_button addTarget:self action:@selector(createSnapshot) forControlEvents:UIControlEventTouchUpInside];
+ [self.view addSubview:_button];
+
+ _imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, self.view.bounds.size.height / 2, self.view.bounds.size.width, self.view.bounds.size.height / 2)];
+ _imageView.backgroundColor = [UIColor blackColor];
+ _imageView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
+ [self.view addSubview:_imageView];
+}
+
+- (void)createSnapshot {
+
+ MGLMapSnapshotOptions *options = [[MGLMapSnapshotOptions alloc] initWithStyleURL:_mapView.styleURL camera:_mapView.camera size:_mapView.bounds.size];
+
+ options.zoomLevel = _mapView.zoomLevel;
+
+ UIActivityIndicatorView *indicator = [[UIActivityIndicatorView alloc] initWithFrame:CGRectMake(_imageView.center.x - 30, _imageView.center.y - 30, 60, 60)];
+ [self.view addSubview:indicator];
+ [indicator startAnimating];
+
+ CGRect imageRect = _imageView.bounds;
+
+ __block MGLMapSnapshotter *snapshotter = [[MGLMapSnapshotter alloc] initWithOptions:options];
+
+ [snapshotter startWithOverlayHandler:^(MGLMapSnapshotOverlay * _Nullable snapshotOverlay) {
+ // Overlays red square over snapshot (but below attribution)
+// CGContextSetFillColorWithColor(snapshotOverlay.context, [UIColor.greenColor CGColor]);
+// CGContextSetAlpha(snapshotOverlay.context, 0.2);
+// CGContextAddRect(snapshotOverlay.context, imageRect);
+// CGContextFillRect(snapshotOverlay.context, imageRect);
+
+ // Slick drawing, but pushes attribution out of the way
+ CGContextSetStrokeColorWithColor(snapshotOverlay.context, [UIColor.redColor CGColor]);
+ CGContextTranslateCTM(snapshotOverlay.context, imageRect.size.width / 2, imageRect.size.height / 2);
+ BOOL first = YES;
+ CGFloat length = 256;
+
+ for (int i = 1; i <= length; i++)
+ {
+ CGContextRotateCTM(snapshotOverlay.context, M_PI / 2);
+
+ if (first) {
+ CGContextMoveToPoint(snapshotOverlay.context, length, 50);
+ first = NO;
+ } else {
+ CGContextAddLineToPoint(snapshotOverlay.context, length, 50);
+ }
+
+ length *= 0.99;
+ }
+
+ CGContextStrokePath(snapshotOverlay.context);
+
+ } completionHandler:^(MGLMapSnapshot * _Nullable snapshot, NSError * _Nullable error) {
+ if (error != nil) {
+ NSLog(@"Unable to create a map snapshot.");
+ } else if (snapshot != nil) {
+ // Add the map snapshot's image to the image view.
+ [indicator stopAnimating];
+ self.imageView.image = snapshot.image;
+ }
+
+ snapshotter = nil;
+ }];
+}
+
+@end
+
diff --git a/platform/ios/app/Main.storyboard b/platform/ios/app/Main.storyboard
index ac83bd968f..04cda22eff 100644
--- a/platform/ios/app/Main.storyboard
+++ b/platform/ios/app/Main.storyboard
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
-<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14865.1" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="PSe-Ot-7Ff">
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14810.11" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="0Nh-jr-UFF">
<device id="retina4_7" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
- <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14819.2"/>
+ <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14766.13"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
@@ -13,11 +13,11 @@
<objects>
<viewController id="WaX-pd-UZQ" userLabel="Map View Controller" customClass="MBXViewController" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="Z9X-fc-PUC">
- <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
+ <rect key="frame" x="0.0" y="0.0" width="148" height="33"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="kNe-zV-9ha" customClass="MGLMapView">
- <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
+ <rect key="frame" x="0.0" y="0.0" width="148" height="33"/>
<subviews>
<button hidden="YES" opaque="NO" userInteractionEnabled="NO" alpha="0.69999999999999996" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="tailTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="58y-pX-YyB">
<rect key="frame" x="8" y="82" width="40" height="20"/>
@@ -38,7 +38,7 @@
</userDefinedRuntimeAttributes>
</button>
<view hidden="YES" opaque="NO" userInteractionEnabled="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="BHE-Wn-x69" customClass="MBXFrameTimeGraphView">
- <rect key="frame" x="0.0" y="467" width="375" height="200"/>
+ <rect key="frame" x="0.0" y="-167" width="148" height="200"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<accessibility key="accessibilityConfiguration">
<accessibilityTraits key="traits" notEnabled="YES"/>
@@ -214,6 +214,21 @@
</objects>
<point key="canvasLocation" x="2075" y="350"/>
</scene>
+ <!--Context Snapshot View Controller-->
+ <scene sceneID="hFh-b6-g0M">
+ <objects>
+ <viewController id="0Nh-jr-UFF" customClass="MBXContextSnapshotViewController" sceneMemberID="viewController">
+ <view key="view" contentMode="scaleToFill" id="5Wv-sh-k8L">
+ <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+ <color key="backgroundColor" xcode11CocoaTouchSystemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
+ <viewLayoutGuide key="safeArea" id="qNT-d8-dSI"/>
+ </view>
+ </viewController>
+ <placeholder placeholderIdentifier="IBFirstResponder" id="Cpl-dC-mUb" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
+ </objects>
+ <point key="canvasLocation" x="3131" y="459"/>
+ </scene>
<!--Navigation Controller-->
<scene sceneID="LFg-oU-zTK">
<objects>
diff --git a/platform/ios/ios.xcodeproj/project.pbxproj b/platform/ios/ios.xcodeproj/project.pbxproj
index 7712c332c4..bf575c44a8 100644
--- a/platform/ios/ios.xcodeproj/project.pbxproj
+++ b/platform/ios/ios.xcodeproj/project.pbxproj
@@ -12,6 +12,7 @@
071BBB031EE76146001FB02A /* MGLImageSource.h in Headers */ = {isa = PBXBuildFile; fileRef = 071BBAFC1EE75CD4001FB02A /* MGLImageSource.h */; settings = {ATTRIBUTES = (Public, ); }; };
071BBB041EE76147001FB02A /* MGLImageSource.h in Headers */ = {isa = PBXBuildFile; fileRef = 071BBAFC1EE75CD4001FB02A /* MGLImageSource.h */; settings = {ATTRIBUTES = (Public, ); }; };
071BBB071EE77631001FB02A /* MGLImageSourceTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 071BBB051EE7761A001FB02A /* MGLImageSourceTests.m */; };
+ 0723AB85232717AB0095FD55 /* MBXContextSnapshotViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 0723AB84232717AB0095FD55 /* MBXContextSnapshotViewController.m */; };
075AF842227B6762008D7A4C /* MBXState.m in Sources */ = {isa = PBXBuildFile; fileRef = 075AF841227B6762008D7A4C /* MBXState.m */; };
075AF845227B67C6008D7A4C /* MBXStateManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 075AF844227B67C6008D7A4C /* MBXStateManager.m */; };
076171C32139C70900668A35 /* MGLMapViewTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 076171C22139C70900668A35 /* MGLMapViewTests.m */; };
@@ -868,6 +869,8 @@
071BBAFC1EE75CD4001FB02A /* MGLImageSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLImageSource.h; sourceTree = "<group>"; };
071BBAFD1EE75CD4001FB02A /* MGLImageSource.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLImageSource.mm; sourceTree = "<group>"; };
071BBB051EE7761A001FB02A /* MGLImageSourceTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGLImageSourceTests.m; path = ../../darwin/test/MGLImageSourceTests.m; sourceTree = "<group>"; };
+ 0723AB83232717AB0095FD55 /* MBXContextSnapshotViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MBXContextSnapshotViewController.h; sourceTree = "<group>"; };
+ 0723AB84232717AB0095FD55 /* MBXContextSnapshotViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MBXContextSnapshotViewController.m; sourceTree = "<group>"; };
074A7F0C2277C093001A62D1 /* insert_access_token.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = insert_access_token.sh; sourceTree = "<group>"; };
075AF840227B6762008D7A4C /* MBXState.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MBXState.h; sourceTree = "<group>"; };
075AF841227B6762008D7A4C /* MBXState.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MBXState.m; sourceTree = "<group>"; };
@@ -1983,6 +1986,8 @@
DA1DC94C1CB6C1C2006E619F /* Demo App */ = {
isa = PBXGroup;
children = (
+ 0723AB83232717AB0095FD55 /* MBXContextSnapshotViewController.h */,
+ 0723AB84232717AB0095FD55 /* MBXContextSnapshotViewController.m */,
3E6465D52065767A00685536 /* LimeGreenStyleLayer.h */,
3E6465D42065767A00685536 /* LimeGreenStyleLayer.m */,
DA1DC9501CB6C1C2006E619F /* MBXAppDelegate.h */,
@@ -3248,6 +3253,7 @@
DA1DC96B1CB6C6B7006E619F /* MBXOfflinePacksTableViewController.m in Sources */,
075AF845227B67C6008D7A4C /* MBXStateManager.m in Sources */,
DA1DC96A1CB6C6B7006E619F /* MBXCustomCalloutView.m in Sources */,
+ 0723AB85232717AB0095FD55 /* MBXContextSnapshotViewController.m in Sources */,
075AF842227B6762008D7A4C /* MBXState.m in Sources */,
927FBCFC1F4DAA8300F8BF1F /* MBXSnapshotsViewController.m in Sources */,
DA1DC99B1CB6E064006E619F /* MBXViewController.m in Sources */,
diff --git a/platform/macos/CHANGELOG.md b/platform/macos/CHANGELOG.md
index cbf08f7dd3..da9a179ad3 100644
--- a/platform/macos/CHANGELOG.md
+++ b/platform/macos/CHANGELOG.md
@@ -17,6 +17,7 @@
* Fixed a rendering issue that non-SDF icon would be treated as SDF icon if they are in the same layer. ([#15456](https://github.com/mapbox/mapbox-gl-native/pull/15456))
* Fixed a rendering issue of `collisionBox` when `text-translate` or `icon-translate` is enabled. ([#15467](https://github.com/mapbox/mapbox-gl-native/pull/15467))
* Fixed an issue of integer overflow when converting `tileCoordinates` to `LatLon`, which caused issues such as `queryRenderedFeatures` and `querySourceFeatures` returning incorrect coordinates at zoom levels 20 and higher. ([#15560](https://github.com/mapbox/mapbox-gl-native/pull/15560))
+* 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))
### Styles and rendering