diff options
author | Fabian Guerra <fabian.guerra@mapbox.com> | 2018-01-04 12:55:19 -0600 |
---|---|---|
committer | Fabian Guerra <fabian.guerra@mapbox.com> | 2018-01-04 12:55:19 -0600 |
commit | 187b6dc31cf281b5157de1acd92f3e8ef9d0acf9 (patch) | |
tree | 1d9eaac5d1e8393d8fd665aa678581a6086a9eb6 /platform/darwin/src | |
parent | c62b0af24fc76b4bb2eb34100611dd3ee9ee5536 (diff) | |
parent | 760ef23ac3faf4437cadb52983383c9501336964 (diff) | |
download | qtlocation-mapboxgl-187b6dc31cf281b5157de1acd92f3e8ef9d0acf9.tar.gz |
Merge branch 'release-agua' into masterupstream/fabian-merge-release-agua
# Conflicts:
# circle.yml
# cmake/core-files.cmake
# platform/android/CHANGELOG.md
# platform/android/MapboxGLAndroidSDK/build.gradle
# platform/android/MapboxGLAndroidSDK/gradle.properties
# platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/CameraChangeDispatcher.java
# platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java
# platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java
# platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/text/LocalGlyphRasterizer.java
# platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/BitmapUtils.java
# platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml
# platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/DebugModeActivity.java
# platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/LocalGlyphActivity.java
# platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MyLocationTintActivity.java
# platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_local_glyph.xml
# platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml
# platform/darwin/src/MGLMapSnapshotter.mm
# platform/darwin/src/MGLRendererConfiguration.h
# platform/ios/CHANGELOG.md
# platform/ios/DEVELOPING.md
# platform/ios/INSTALL.md
# platform/ios/README.md
# platform/ios/resources/bg.lproj/Localizable.strings
# platform/ios/resources/es.lproj/Localizable.strings
# platform/ios/resources/vi.lproj/Localizable.strings
# platform/ios/src/MGLMapView.mm
# platform/macos/macos.xcodeproj/project.pbxproj
# src/mbgl/text/glyph_manager.cpp
Diffstat (limited to 'platform/darwin/src')
-rw-r--r-- | platform/darwin/src/MGLAttributionInfo.h | 30 | ||||
-rw-r--r-- | platform/darwin/src/MGLAttributionInfo.mm | 28 | ||||
-rw-r--r-- | platform/darwin/src/MGLImageSource.h | 5 | ||||
-rw-r--r-- | platform/darwin/src/MGLMapSnapshotter.h | 114 | ||||
-rw-r--r-- | platform/darwin/src/MGLMapSnapshotter.mm | 267 | ||||
-rw-r--r-- | platform/darwin/src/MGLOpenGLStyleLayer.mm | 6 | ||||
-rw-r--r-- | platform/darwin/src/MGLStyle.mm | 2 | ||||
-rw-r--r-- | platform/darwin/src/MGLStyle_Private.h | 2 |
8 files changed, 263 insertions, 191 deletions
diff --git a/platform/darwin/src/MGLAttributionInfo.h b/platform/darwin/src/MGLAttributionInfo.h index 031a10060f..1de37c3b24 100644 --- a/platform/darwin/src/MGLAttributionInfo.h +++ b/platform/darwin/src/MGLAttributionInfo.h @@ -8,6 +8,24 @@ NS_ASSUME_NONNULL_BEGIN /** + The attribution info is represented in the longest format available. + */ +typedef NS_ENUM(NSUInteger, MGLAttributionInfoStyle) { + /** + Specifies a short attribution info style. + */ + MGLAttributionInfoStyleShort = 1, + /** + Specifies a medium attribution info style. + */ + MGLAttributionInfoStyleMedium, + /** + Specifies a long attribution info style. + */ + MGLAttributionInfoStyleLong +}; + +/** Information about an attribution statement, usually a copyright or trademark statement, associated with a map content source. */ @@ -59,6 +77,18 @@ MGL_EXPORT */ - (nullable NSURL *)feedbackURLAtCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate zoomLevel:(double)zoomLevel; +/** + Returns a copy of the current `title` formatted accordingly to `style`. + + Example: If the `style` property is set to `MGLAttributionInfoStyleShort` and the + `title` property is set to `OpenStreetMap`, then this method returns `OSM`. + + @param style The attribution info style. + + @return The `NSAttributedString` styled title. + */ +- (NSAttributedString *)titleWithStyle:(MGLAttributionInfoStyle)style; + @end NS_ASSUME_NONNULL_END diff --git a/platform/darwin/src/MGLAttributionInfo.mm b/platform/darwin/src/MGLAttributionInfo.mm index ce63a25422..73147270c1 100644 --- a/platform/darwin/src/MGLAttributionInfo.mm +++ b/platform/darwin/src/MGLAttributionInfo.mm @@ -127,6 +127,15 @@ return self; } +- (id)copyWithZone:(nullable NSZone *)zone +{ + MGLAttributionInfo *info = [[[self class] allocWithZone:zone] initWithTitle:_title + URL:_URL]; + info.feedbackLink = _feedbackLink; + + return info; +} + - (nullable NSURL *)feedbackURLAtCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate zoomLevel:(double)zoomLevel { return [self feedbackURLForStyleURL:nil atCenterCoordinate:centerCoordinate zoomLevel:zoomLevel direction:0 pitch:0]; } @@ -160,6 +169,25 @@ return components.URL; } +- (NSAttributedString *)titleWithStyle:(MGLAttributionInfoStyle)style +{ + NSString *openStreetMap = NSLocalizedStringWithDefaultValue(@"OSM_FULL_NAME", @"Foundation", nil, @"OpenStreetMap", @"OpenStreetMap full name attribution"); + NSString *OSM = NSLocalizedStringWithDefaultValue(@"OSM_SHORT_NAME", @"Foundation", nil, @"OSM", @"OpenStreetMap short name attribution"); + + NSMutableAttributedString *title = [[NSMutableAttributedString alloc] initWithAttributedString:self.title]; + [title removeAttribute:NSUnderlineStyleAttributeName range:NSMakeRange(0, [title.string length])]; + + BOOL isAbbreviated = (style == MGLAttributionInfoStyleShort); + + if ([title.string rangeOfString:@"OpenStreetMap"].location != NSNotFound) { + [title.mutableString replaceOccurrencesOfString:@"OpenStreetMap" withString:isAbbreviated ? OSM : openStreetMap + options:NSCaseInsensitiveSearch + range:NSMakeRange(0, [title.mutableString length])]; + } + + return title; +} + - (BOOL)isEqual:(id)object { return [object isKindOfClass:[self class]] && [[object title] isEqual:self.title] && [[object URL] isEqual:self.URL]; } diff --git a/platform/darwin/src/MGLImageSource.h b/platform/darwin/src/MGLImageSource.h index 5088f6bac0..21487d9739 100644 --- a/platform/darwin/src/MGLImageSource.h +++ b/platform/darwin/src/MGLImageSource.h @@ -38,11 +38,8 @@ MGL_EXPORT bottomLeft: CLLocationCoordinate2D(latitude: 37.936, longitude: -80.425), bottomRight: CLLocationCoordinate2D(latitude: 37.936, longitude: -71.516), topRight: CLLocationCoordinate2D(latitude: 46.437, longitude: -71.516)) - let source = MGLImageSource(identifier: "radar-source", coordinateQuad: coordinates, url: URL(string: "https://www.mapbox.com/mapbox-gl-js/assets/radar.gif")!) + let source = MGLImageSource(identifier: "radar", coordinateQuad: coordinates, url: URL(string: "https://www.mapbox.com/mapbox-gl-js/assets/radar.gif")!) mapView.style?.addSource(source) - - let layer = MGLRasterStyleLayer(identifier: "radar-layer", source: source) - style.addLayer(layer) ``` */ MGL_EXPORT diff --git a/platform/darwin/src/MGLMapSnapshotter.h b/platform/darwin/src/MGLMapSnapshotter.h index 541bc68b93..426ab1bb00 100644 --- a/platform/darwin/src/MGLMapSnapshotter.h +++ b/platform/darwin/src/MGLMapSnapshotter.h @@ -14,9 +14,10 @@ MGL_EXPORT /** Creates a set of options with the minimum required information. - @param styleURL URL of the map style to snapshot. The URL may be a full HTTP or HTTPS URL, - a Mapbox URL indicating the style’s map ID (`mapbox://styles/{user}/{style`}), or a path - to a local file relative to the application’s resource path. Specify `nil` for the default style. + @param styleURL URL of the map style to snapshot. The URL may be a full HTTP or + HTTPS URL, a Mapbox URL indicating the style’s map ID + (`mapbox://styles/{user}/{style}`), or a path to a local file relative to + the application’s resource path. Specify `nil` for the default style. @param size The image size. */ - (instancetype)initWithStyleURL:(nullable NSURL *)styleURL camera:(MGLMapCamera *)camera size:(CGSize)size; @@ -31,17 +32,18 @@ MGL_EXPORT /** The zoom level. - The default zoom level is 0. If this property is non-zero and the camera property - is non-nil, the camera’s altitude is ignored in favor of this property’s value. + The default zoom level is 0. If this property is non-zero and the camera + property is non-nil, the camera’s altitude is ignored in favor of this + property’s value. */ @property (nonatomic) double zoomLevel; /** A camera representing the viewport visible in the snapshot. - If this property is non-nil and the `coordinateBounds` property is set to a non-empty - coordinate bounds, the camera’s center coordinate and altitude are ignored in favor - of the `coordinateBounds` property. + If this property is non-nil and the `coordinateBounds` property is set to a + non-empty coordinate bounds, the camera’s center coordinate and altitude are + ignored in favor of the `coordinateBounds` property. */ @property (nonatomic) MGLMapCamera *camera; @@ -78,24 +80,26 @@ MGL_EXPORT #if TARGET_OS_IPHONE /** - Converts the specified map coordinate to a point in the coordinate space of the image. + Converts the specified map coordinate to a point in the coordinate space of the + image. */ - (CGPoint)pointForCoordinate:(CLLocationCoordinate2D)coordinate; /** The image of the map’s content. */ -@property(nonatomic, readonly) UIImage *image; +@property (nonatomic, readonly) UIImage *image; #else /** - Converts the specified map coordinate to a point in the coordinate space of the image. + Converts the specified map coordinate to a point in the coordinate space of the + image. */ - (NSPoint)pointForCoordinate:(CLLocationCoordinate2D)coordinate; /** The image of the map’s content. */ -@property(nonatomic, readonly) NSImage *image; +@property (nonatomic, readonly) NSImage *image; #endif @end @@ -103,13 +107,33 @@ MGL_EXPORT /** A block to processes the result or error of a snapshot request. - @param snapshot The `MGLMapSnapshot` that was generated or `nil` if an error occurred. + @param snapshot The `MGLMapSnapshot` that was generated or `nil` if an error + occurred. @param error The error that occured or `nil` when successful. */ typedef void (^MGLMapSnapshotCompletionHandler)(MGLMapSnapshot* _Nullable snapshot, NSError* _Nullable error); /** - An immutable utility object for capturing map-based images. + 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. + + 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 + snapshot at a time. If you need to generate multiple snapshots concurrently, + create multiple snapshotter objects. + + For an interactive map, use the `MGLMapView` class. Both `MGLMapSnapshotter` + and `MGLMapView` are compatible with offline packs managed by the + `MGLOfflineStorage` class. + + From a snapshot, you can obtain an image and convert geographic coordinates to + the image’s coordinate space in order to superimpose markers and overlays. If + you do not need offline map functionality, you can use the `Snapshot` class in + [MapboxStatic.swift](https://github.com/mapbox/MapboxStatic.swift/) to generate + static map images with overlays. ### Example @@ -121,18 +145,25 @@ typedef void (^MGLMapSnapshotCompletionHandler)(MGLMapSnapshot* _Nullable snapsh let snapshotter = MGLMapSnapshotter(options: options) snapshotter.start { (snapshot, error) in - if error != nil { - // error handler - } else { - // image handler + if let error = error { + fatalError(error.localizedDescription) } + + image = snapshot?.image } ``` */ MGL_EXPORT @interface MGLMapSnapshotter : NSObject -- (instancetype)initWithOptions:(MGLMapSnapshotOptions*)options; +/** + Initializes and returns a map snapshotter object that produces snapshots + according to the given options. + + @param options The options to use when generating a map snapshot. + @return An initialized map snapshotter. + */ +- (instancetype)initWithOptions:(MGLMapSnapshotOptions *)options; /** Starts the snapshot creation and executes the specified block with the result. @@ -142,7 +173,8 @@ MGL_EXPORT - (void)startWithCompletionHandler:(MGLMapSnapshotCompletionHandler)completionHandler; /** - Starts the snapshot creation and executes the specified block with the result on the specified queue. + Starts the snapshot creation and executes the specified block with the result + on the specified queue. @param queue The queue to handle the result on. @param completionHandler The block to handle the result in. @@ -152,49 +184,15 @@ MGL_EXPORT /** Cancels the snapshot creation request, if any. - Once you call this method, you cannot resume the snapshot. In order to obtain the - snapshot, create a new `MGLMapSnapshotter` object. + Once you call this method, you cannot resume the snapshot. In order to obtain + the snapshot, create a new `MGLMapSnapshotter` object. */ - (void)cancel; /** - The zoom level. - - The default zoom level is 0. If this property is non-zero and the camera property - is non-nil, the camera’s altitude is ignored in favor of this property’s value. - */ -@property (nonatomic) double zoomLevel; - -/** - A camera representing the viewport visible in the snapshot. - - If this property is non-nil and the `coordinateBounds` property is set to a non-empty - coordinate bounds, the camera’s center coordinate and altitude are ignored in favor - of the `coordinateBounds` property. - */ -@property (nonatomic) MGLMapCamera *camera; - -/** - The coordinate rectangle that encompasses the bounds to capture. - - If this property is non-empty and the camera property is non-nil, the camera’s - center coordinate and altitude are ignored in favor of this property’s value. - */ -@property (nonatomic) MGLCoordinateBounds coordinateBounds; - -/** - URL of the map style to snapshot. - - The URL may be a full HTTP or HTTPS URL, a Mapbox URL indicating the style’s - map ID (`mapbox://styles/{user}/{style`}), or a path to a local file relative - to the application’s resource path. Specify `nil` for the default style. - */ -@property (nonatomic, nullable) NSURL *styleURL; - -/** - The size of the output image, measured in points. + The options to use when generating a map snapshot. */ -@property (nonatomic) CGSize size; +@property (nonatomic) MGLMapSnapshotOptions *options; /** Indicates whether a snapshot is currently being generated. 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 diff --git a/platform/darwin/src/MGLOpenGLStyleLayer.mm b/platform/darwin/src/MGLOpenGLStyleLayer.mm index 36a3c20c97..8933a77382 100644 --- a/platform/darwin/src/MGLOpenGLStyleLayer.mm +++ b/platform/darwin/src/MGLOpenGLStyleLayer.mm @@ -47,7 +47,7 @@ void MGLDrawCustomStyleLayer(void *context, const mbgl::style::CustomLayerRender when creating an OpenGL style layer. */ void MGLFinishCustomStyleLayer(void *context) { - MGLOpenGLStyleLayer *layer = (__bridge MGLOpenGLStyleLayer *)context; + MGLOpenGLStyleLayer *layer = (__bridge_transfer MGLOpenGLStyleLayer *)context; [layer willMoveFromMapView:layer.style.mapView]; } @@ -101,7 +101,7 @@ void MGLFinishCustomStyleLayer(void *context) { MGLPrepareCustomStyleLayer, MGLDrawCustomStyleLayer, MGLFinishCustomStyleLayer, - (__bridge void *)self); + (__bridge_retained void *)self); return self = [super initWithPendingLayer:std::move(layer)]; } @@ -116,9 +116,7 @@ void MGLFinishCustomStyleLayer(void *context) { [NSException raise:@"MGLLayerReuseException" format:@"%@ cannot be added to more than one MGLStyle at a time.", self]; } - _style.openGLLayers[self.identifier] = nil; _style = style; - _style.openGLLayers[self.identifier] = self; } - (void)addToStyle:(MGLStyle *)style belowLayer:(MGLStyleLayer *)otherLayer { diff --git a/platform/darwin/src/MGLStyle.mm b/platform/darwin/src/MGLStyle.mm index f04ae2b104..5221e838f8 100644 --- a/platform/darwin/src/MGLStyle.mm +++ b/platform/darwin/src/MGLStyle.mm @@ -77,7 +77,6 @@ @property (nonatomic, readonly, weak) MGLMapView *mapView; @property (nonatomic, readonly) mbgl::style::Style *rawStyle; @property (readonly, copy, nullable) NSURL *URL; -@property (nonatomic, readwrite, strong) NS_MUTABLE_DICTIONARY_OF(NSString *, MGLOpenGLStyleLayer *) *openGLLayers; @property (nonatomic) NS_MUTABLE_DICTIONARY_OF(NSString *, NS_DICTIONARY_OF(NSObject *, MGLTextLanguage *) *) *localizedLayersByIdentifier; @end @@ -169,7 +168,6 @@ static NSURL *MGLStyleURL_trafficNight; if (self = [super init]) { _mapView = mapView; _rawStyle = rawStyle; - _openGLLayers = [NSMutableDictionary dictionary]; _localizedLayersByIdentifier = [NSMutableDictionary dictionary]; } return self; diff --git a/platform/darwin/src/MGLStyle_Private.h b/platform/darwin/src/MGLStyle_Private.h index e5bd79dc02..4cbe953a44 100644 --- a/platform/darwin/src/MGLStyle_Private.h +++ b/platform/darwin/src/MGLStyle_Private.h @@ -26,8 +26,6 @@ namespace mbgl { - (nullable NS_ARRAY_OF(MGLAttributionInfo *) *)attributionInfosWithFontSize:(CGFloat)fontSize linkColor:(nullable MGLColor *)linkColor; -@property (nonatomic, readonly, strong) NS_MUTABLE_DICTIONARY_OF(NSString *, MGLOpenGLStyleLayer *) *openGLLayers; - - (void)setStyleClasses:(NS_ARRAY_OF(NSString *) *)appliedClasses transitionDuration:(NSTimeInterval)transitionDuration; @end |