summaryrefslogtreecommitdiff
path: root/platform/darwin/src/MGLMapSnapshotter.mm
diff options
context:
space:
mode:
Diffstat (limited to 'platform/darwin/src/MGLMapSnapshotter.mm')
-rw-r--r--platform/darwin/src/MGLMapSnapshotter.mm267
1 files changed, 146 insertions, 121 deletions
diff --git a/platform/darwin/src/MGLMapSnapshotter.mm b/platform/darwin/src/MGLMapSnapshotter.mm
index 346666cf80..967706ac2e 100644
--- a/platform/darwin/src/MGLMapSnapshotter.mm
+++ b/platform/darwin/src/MGLMapSnapshotter.mm
@@ -61,6 +61,7 @@ const CGFloat MGLSnapshotterMinimumPixelSize = 64;
@implementation MGLMapSnapshot {
mbgl::MapSnapshotter::PointForFn _pointForFn;
}
+
- (instancetype)initWithImage:(nullable MGLImage *)image scale:(CGFloat)scale pointForFn:(mbgl::MapSnapshotter::PointForFn)pointForFn
{
self = [super init];
@@ -80,7 +81,7 @@ const CGFloat MGLSnapshotterMinimumPixelSize = 64;
@end
@interface MGLMapSnapshotter()
-@property (nonatomic) MGLMapSnapshotOptions *options;
+
@end
@implementation MGLMapSnapshotter {
@@ -88,46 +89,16 @@ const CGFloat MGLSnapshotterMinimumPixelSize = 64;
std::shared_ptr<mbgl::ThreadPool> _mbglThreadPool;
std::unique_ptr<mbgl::MapSnapshotter> _mbglMapSnapshotter;
std::unique_ptr<mbgl::Actor<mbgl::MapSnapshotter::Callback>> _snapshotCallback;
+ NS_ARRAY_OF(MGLAttributionInfo *) *_attributionInfo;
}
- (instancetype)initWithOptions:(MGLMapSnapshotOptions *)options
{
self = [super init];
if (self) {
- _options = options;
+ [self setOptions:options];
_loading = false;
-
- mbgl::DefaultFileSource *mbglFileSource = [MGLOfflineStorage sharedOfflineStorage].mbglFileSource;
- _mbglThreadPool = mbgl::sharedThreadPool();
-
- std::string styleURL = std::string([options.styleURL.absoluteString UTF8String]);
-
- // Size; taking into account the minimum texture size for OpenGL ES
- // For non retina screens the ratio is 1:1 MGLSnapshotterMinimumPixelSize
- mbgl::Size size = {
- static_cast<uint32_t>(MAX(options.size.width, MGLSnapshotterMinimumPixelSize)),
- static_cast<uint32_t>(MAX(options.size.height, MGLSnapshotterMinimumPixelSize))
- };
-
- float pixelRatio = MAX(options.scale, 1);
-
- // Camera options
- mbgl::CameraOptions cameraOptions;
- if (CLLocationCoordinate2DIsValid(options.camera.centerCoordinate)) {
- cameraOptions.center = MGLLatLngFromLocationCoordinate2D(options.camera.centerCoordinate);
- }
- cameraOptions.angle = MAX(0, options.camera.heading) * mbgl::util::DEG2RAD;
- cameraOptions.zoom = MAX(0, options.zoomLevel);
- cameraOptions.pitch = MAX(0, options.camera.pitch);
-
- // Region
- mbgl::optional<mbgl::LatLngBounds> coordinateBounds;
- if (!MGLCoordinateBoundsIsEmpty(options.coordinateBounds)) {
- coordinateBounds = MGLLatLngBoundsFromCoordinateBounds(options.coordinateBounds);
- }
-
- // Create the snapshotter
- _mbglMapSnapshotter = std::make_unique<mbgl::MapSnapshotter>(*mbglFileSource, *_mbglThreadPool, styleURL, size, pixelRatio, cameraOptions, coordinateBounds);
+
}
return self;
}
@@ -167,14 +138,7 @@ const CGFloat MGLSnapshotterMinimumPixelSize = 64;
[infos growArrayByAddingAttributionInfosFromArray:tileSetInfos];
}
- CGSize attributionBackgroundSize = CGSizeMake(10, 0);
- for (MGLAttributionInfo *info in infos) {
- if (info.isFeedbackLink) {
- continue;
- }
- attributionBackgroundSize.width += [info.title size].width + 10;
- attributionBackgroundSize.height = MAX([info.title size].height, attributionBackgroundSize.height);
- }
+ _attributionInfo = infos;
if (mbglError) {
NSString *description = @(mbgl::util::toString(mbglError).c_str());
@@ -198,11 +162,29 @@ const CGFloat MGLSnapshotterMinimumPixelSize = 64;
dispatch_queue_t workQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(workQueue, ^{
#if TARGET_OS_IPHONE
- UIImage *logoImage = [UIImage imageNamed:@"mapbox" inBundle:[NSBundle mgl_frameworkBundle] compatibleWithTraitCollection:nil];
+ MGLAttributionInfoStyle attributionInfoStyle = MGLAttributionInfoStyleLong;
+ for (NSUInteger styleValue = MGLAttributionInfoStyleLong; styleValue >= MGLAttributionInfoStyleShort; styleValue--) {
+ attributionInfoStyle = (MGLAttributionInfoStyle)styleValue;
+ CGSize attributionSize = [self attributionSizeWithLogoStyle:attributionInfoStyle sourceAttributionStyle:attributionInfoStyle];
+ if (attributionSize.width <= mglImage.size.width) {
+ break;
+ }
+ }
+
+ UIImage *logoImage = [self logoImageWithStyle:attributionInfoStyle];
+ CGSize attributionBackgroundSize = [self attributionTextSizeWithStyle:attributionInfoStyle];
CGRect logoImageRect = CGRectMake(MGLLogoImagePosition.x, mglImage.size.height - (MGLLogoImagePosition.y + logoImage.size.height), logoImage.size.width, logoImage.size.height);
- CGRect attributionBackgroundFrame = CGRectMake(mglImage.size.width - 10 - attributionBackgroundSize.width,
- logoImageRect.origin.y + (logoImageRect.size.height / 2) - (attributionBackgroundSize.height / 2) + 1,
+ CGPoint attributionOrigin = CGPointMake(mglImage.size.width - 10 - attributionBackgroundSize.width,
+ logoImageRect.origin.y + (logoImageRect.size.height / 2) - (attributionBackgroundSize.height / 2) + 1);
+ if (!logoImage) {
+ CGSize defaultLogoSize = [self mapboxLongStyleLogo].size;
+ logoImageRect = CGRectMake(0, mglImage.size.height - (MGLLogoImagePosition.y + defaultLogoSize.height), 0, defaultLogoSize.height);
+ attributionOrigin = CGPointMake(10, logoImageRect.origin.y + (logoImageRect.size.height / 2) - (attributionBackgroundSize.height / 2) + 1);
+ }
+
+ CGRect attributionBackgroundFrame = CGRectMake(attributionOrigin.x,
+ attributionOrigin.y,
attributionBackgroundSize.width,
attributionBackgroundSize.height);
CGPoint attributionTextPosition = CGPointMake(attributionBackgroundFrame.origin.x + 10,
@@ -231,20 +213,39 @@ const CGFloat MGLSnapshotterMinimumPixelSize = 64;
[blurredAttributionBackground drawInRect:attributionBackgroundFrame];
- [self drawAttributionText:infos origin:attributionTextPosition];
+ [self drawAttributionTextWithStyle:attributionInfoStyle origin:attributionTextPosition];
UIImage *compositedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
#else
- NSImage *logoImage = [[NSImage alloc] initWithContentsOfFile:[[NSBundle mgl_frameworkBundle] pathForResource:@"mapbox" ofType:@"pdf"]];
- NSImage *sourceImage = mglImage;
-
NSSize targetSize = NSMakeSize(self.options.size.width, self.options.size.height);
NSRect targetFrame = NSMakeRect(0, 0, targetSize.width, targetSize.height);
+
+ MGLAttributionInfoStyle attributionInfoStyle = MGLAttributionInfoStyleLong;
+ for (NSUInteger styleValue = MGLAttributionInfoStyleLong; styleValue >= MGLAttributionInfoStyleShort; styleValue--) {
+ attributionInfoStyle = (MGLAttributionInfoStyle)styleValue;
+ CGSize attributionSize = [self attributionSizeWithLogoStyle:attributionInfoStyle sourceAttributionStyle:attributionInfoStyle];
+ if (attributionSize.width <= mglImage.size.width) {
+ break;
+ }
+ }
+
+ NSImage *logoImage = [self logoImageWithStyle:attributionInfoStyle];
+ CGSize attributionBackgroundSize = [self attributionTextSizeWithStyle:attributionInfoStyle];
+ NSImage *sourceImage = mglImage;
+
CGRect logoImageRect = CGRectMake(MGLLogoImagePosition.x, MGLLogoImagePosition.y, logoImage.size.width, logoImage.size.height);
- CGRect attributionBackgroundFrame = CGRectMake(targetFrame.size.width - 10 - attributionBackgroundSize.width,
- MGLLogoImagePosition.y + 1,
+ CGPoint attributionOrigin = CGPointMake(targetFrame.size.width - 10 - attributionBackgroundSize.width,
+ MGLLogoImagePosition.y + 1);
+ if (!logoImage) {
+ CGSize defaultLogoSize = [self mapboxLongStyleLogo].size;
+ logoImageRect = CGRectMake(0, MGLLogoImagePosition.y, 0, defaultLogoSize.height);
+ attributionOrigin = CGPointMake(10, attributionOrigin.y);
+ }
+
+ CGRect attributionBackgroundFrame = CGRectMake(attributionOrigin.x,
+ attributionOrigin.y,
attributionBackgroundSize.width,
attributionBackgroundSize.height);
CGPoint attributionTextPosition = CGPointMake(attributionBackgroundFrame.origin.x + 10,
@@ -261,7 +262,9 @@ const CGFloat MGLSnapshotterMinimumPixelSize = 64;
[sourceImageRep drawInRect: targetFrame];
- [logoImage drawInRect:logoImageRect];
+ if (logoImage) {
+ [logoImage drawInRect:logoImageRect];
+ }
NSBitmapImageRep *attributionBackground = [[NSBitmapImageRep alloc] initWithFocusedViewRect:attributionBackgroundFrame];
@@ -271,7 +274,7 @@ const CGFloat MGLSnapshotterMinimumPixelSize = 64;
[blurredAttributionBackground drawInRect:attributionBackgroundFrame];
- [self drawAttributionText:infos origin:attributionTextPosition];
+ [self drawAttributionTextWithStyle:attributionInfoStyle origin:attributionTextPosition];
[compositedImage unlockFocus];
@@ -290,15 +293,16 @@ const CGFloat MGLSnapshotterMinimumPixelSize = 64;
});
}
-- (void)drawAttributionText:(NSArray *)attributionInfo origin:(CGPoint)origin
+- (void)drawAttributionTextWithStyle:(MGLAttributionInfoStyle)attributionInfoStyle origin:(CGPoint)origin
{
- for (MGLAttributionInfo *info in attributionInfo) {
+ for (MGLAttributionInfo *info in _attributionInfo) {
if (info.isFeedbackLink) {
continue;
}
- [info.title drawAtPoint:origin];
+ NSAttributedString *attribution = [info titleWithStyle:attributionInfoStyle];
+ [attribution drawAtPoint:origin];
- origin.x += [info.title size].width + 10;
+ origin.x += [attribution size].width + 10;
}
}
@@ -324,10 +328,8 @@ const CGFloat MGLSnapshotterMinimumPixelSize = 64;
MGLImage *image;
#if TARGET_OS_IPHONE
-
image = [UIImage imageWithCGImage:cgimg];
#else
-
image = [[NSImage alloc] initWithCGImage:cgimg size:[backgroundImage extent].size];
#endif
@@ -335,87 +337,110 @@ const CGFloat MGLSnapshotterMinimumPixelSize = 64;
return image;
}
-- (void)cancel
+- (MGLImage *)logoImageWithStyle:(MGLAttributionInfoStyle)style
{
- _snapshotCallback.reset();
- _mbglMapSnapshotter.reset();
-}
-
-- (NSURL *)styleURL
-{
- NSString *styleURLString = @(_mbglMapSnapshotter->getStyleURL().c_str());
- return styleURLString.length ? [NSURL URLWithString:styleURLString] : nil;
+ MGLImage *logoImage;
+ switch (style) {
+ case MGLAttributionInfoStyleLong:
+ logoImage = [self mapboxLongStyleLogo];
+ break;
+ case MGLAttributionInfoStyleMedium:
+#if TARGET_OS_IPHONE
+ logoImage = [UIImage imageNamed:@"mapbox_helmet" inBundle:[NSBundle mgl_frameworkBundle] compatibleWithTraitCollection:nil];
+#else
+ logoImage = [[NSImage alloc] initWithContentsOfFile:[[NSBundle mgl_frameworkBundle] pathForResource:@"mapbox_helmet" ofType:@"pdf"]];
+#endif
+ break;
+ case MGLAttributionInfoStyleShort:
+ logoImage = nil;
+ break;
+ }
+ return logoImage;
}
-- (void)setStyleURL:(NSURL *)url
+- (MGLImage *)mapboxLongStyleLogo
{
- _mbglMapSnapshotter->setStyleURL(std::string([url.absoluteString UTF8String]));
+ MGLImage *logoImage;
+#if TARGET_OS_IPHONE
+ logoImage =[UIImage imageNamed:@"mapbox" inBundle:[NSBundle mgl_frameworkBundle] compatibleWithTraitCollection:nil];
+#else
+ logoImage = [[NSImage alloc] initWithContentsOfFile:[[NSBundle mgl_frameworkBundle] pathForResource:@"mapbox" ofType:@"pdf"]];
+#endif
+ return logoImage;
}
-- (CGSize)size
+- (CGSize)attributionSizeWithLogoStyle:(MGLAttributionInfoStyle)logoStyle sourceAttributionStyle:(MGLAttributionInfoStyle)attributionStyle
{
- mbgl::Size size = _mbglMapSnapshotter->getSize();
- return CGSizeMake(size.width, size.height);
+ MGLImage *logoImage = [self logoImageWithStyle:logoStyle];
+
+ CGSize attributionBackgroundSize = [self attributionTextSizeWithStyle:attributionStyle];
+
+ CGSize attributionSize = CGSizeZero;
+
+ if (logoImage) {
+ attributionSize.width = MGLLogoImagePosition.x + logoImage.size.width + 10;
+ }
+ attributionSize.width = attributionSize.width + 10 + attributionBackgroundSize.width + 10;
+ attributionSize.height = MAX(logoImage.size.height, attributionBackgroundSize.height);
+
+ return attributionSize;
}
-- (void)setSize:(CGSize)size
+- (CGSize)attributionTextSizeWithStyle:(MGLAttributionInfoStyle)attributionStyle
{
- _mbglMapSnapshotter->setSize({
- static_cast<uint32_t>(MAX(size.width, MGLSnapshotterMinimumPixelSize)),
- static_cast<uint32_t>(MAX(size.height, MGLSnapshotterMinimumPixelSize))
- });
+ CGSize attributionBackgroundSize = CGSizeMake(10, 0);
+ for (MGLAttributionInfo *info in _attributionInfo) {
+ if (info.isFeedbackLink) {
+ continue;
+ }
+ CGSize attributionSize = [info titleWithStyle:attributionStyle].size;
+ attributionBackgroundSize.width += attributionSize.width + 10;
+ attributionBackgroundSize.height = MAX(attributionSize.height, attributionBackgroundSize.height);
+ }
+
+ return attributionBackgroundSize;
}
-- (MGLMapCamera *)camera
+- (void)cancel
{
- mbgl::CameraOptions cameraOptions = _mbglMapSnapshotter->getCameraOptions();
- CGFloat pitch = *cameraOptions.pitch;
- CLLocationDirection heading = mbgl::util::wrap(*cameraOptions.angle, 0., 360.);
- CLLocationDistance distance = MGLAltitudeForZoomLevel(*cameraOptions.zoom, pitch, cameraOptions.center->latitude(), [self size]);
- return [MGLMapCamera cameraLookingAtCenterCoordinate:MGLLocationCoordinate2DFromLatLng(*cameraOptions.center)
- fromDistance:distance
- pitch:pitch
- heading:heading];
+ _snapshotCallback.reset();
+ _mbglMapSnapshotter.reset();
}
-- (void)setCamera:(MGLMapCamera *)camera
+- (void)setOptions:(MGLMapSnapshotOptions *)options
{
+ _options = options;
+ mbgl::DefaultFileSource *mbglFileSource = [MGLOfflineStorage sharedOfflineStorage].mbglFileSource;
+ _mbglThreadPool = mbgl::sharedThreadPool();
+
+ std::string styleURL = std::string([options.styleURL.absoluteString UTF8String]);
+
+ // Size; taking into account the minimum texture size for OpenGL ES
+ // For non retina screens the ratio is 1:1 MGLSnapshotterMinimumPixelSize
+ mbgl::Size size = {
+ static_cast<uint32_t>(MAX(options.size.width, MGLSnapshotterMinimumPixelSize)),
+ static_cast<uint32_t>(MAX(options.size.height, MGLSnapshotterMinimumPixelSize))
+ };
+
+ float pixelRatio = MAX(options.scale, 1);
+
+ // Camera options
mbgl::CameraOptions cameraOptions;
- CLLocationCoordinate2D center;
- if (CLLocationCoordinate2DIsValid(camera.centerCoordinate)) {
- cameraOptions.center = MGLLatLngFromLocationCoordinate2D(camera.centerCoordinate);
- center = camera.centerCoordinate;
- } else {
- // Center is optional, but always set.
- center = MGLLocationCoordinate2DFromLatLng(*_mbglMapSnapshotter->getCameraOptions().center);
+ if (CLLocationCoordinate2DIsValid(options.camera.centerCoordinate)) {
+ cameraOptions.center = MGLLatLngFromLocationCoordinate2D(options.camera.centerCoordinate);
}
+ cameraOptions.angle = MAX(0, options.camera.heading) * mbgl::util::DEG2RAD;
+ cameraOptions.zoom = MAX(0, options.zoomLevel);
+ cameraOptions.pitch = MAX(0, options.camera.pitch);
- cameraOptions.angle = MAX(0, camera.heading) * mbgl::util::DEG2RAD;
- cameraOptions.zoom = MAX(0, MGLZoomLevelForAltitude(camera.altitude, camera.pitch, center.latitude, [self size]));
- cameraOptions.pitch = MAX(0, camera.pitch);
-}
-
-- (double)zoomLevel
-{
- mbgl::CameraOptions cameraOptions = _mbglMapSnapshotter->getCameraOptions();
- return MGLAltitudeForZoomLevel(*cameraOptions.zoom, *cameraOptions.pitch, cameraOptions.center->latitude(), [self size]);
-}
-
-- (void)setZoomLevel:(double)zoomLevel
-{
- mbgl::CameraOptions cameraOptions = _mbglMapSnapshotter->getCameraOptions();
- cameraOptions.zoom = zoomLevel;
- _mbglMapSnapshotter->setCameraOptions(cameraOptions);
-}
-
-- (MGLCoordinateBounds)coordinateBounds
-{
- return MGLCoordinateBoundsFromLatLngBounds(_mbglMapSnapshotter->getRegion());
-}
-
-- (void)setCoordinateBounds:(MGLCoordinateBounds)coordinateBounds
-{
- _mbglMapSnapshotter->setRegion(MGLLatLngBoundsFromCoordinateBounds(coordinateBounds));
+ // Region
+ mbgl::optional<mbgl::LatLngBounds> coordinateBounds;
+ if (!MGLCoordinateBoundsIsEmpty(options.coordinateBounds)) {
+ coordinateBounds = MGLLatLngBoundsFromCoordinateBounds(options.coordinateBounds);
+ }
+
+ // Create the snapshotter
+ _mbglMapSnapshotter = std::make_unique<mbgl::MapSnapshotter>(*mbglFileSource, *_mbglThreadPool, styleURL, size, pixelRatio, cameraOptions, coordinateBounds);
}
@end