summaryrefslogtreecommitdiff
path: root/platform/darwin/src
diff options
context:
space:
mode:
Diffstat (limited to 'platform/darwin/src')
-rw-r--r--platform/darwin/src/MGLAttributionInfo.h58
-rw-r--r--platform/darwin/src/MGLAttributionInfo.mm178
-rw-r--r--platform/darwin/src/MGLGeoJSONSource.mm6
-rw-r--r--platform/darwin/src/MGLGeoJSONSource_Private.h3
-rw-r--r--platform/darwin/src/MGLRasterSource.mm14
-rw-r--r--platform/darwin/src/MGLRasterSource_Private.h13
-rw-r--r--platform/darwin/src/MGLSource.mm8
-rw-r--r--platform/darwin/src/MGLSource_Private.h12
-rw-r--r--platform/darwin/src/MGLStyle.mm47
-rw-r--r--platform/darwin/src/MGLStyle_Private.h5
-rw-r--r--platform/darwin/src/MGLTileSet.h48
-rw-r--r--platform/darwin/src/MGLTileSet.mm8
-rw-r--r--platform/darwin/src/MGLTileSet_Private.h17
-rw-r--r--platform/darwin/src/MGLVectorSource.mm14
-rw-r--r--platform/darwin/src/MGLVectorSource_Private.h13
-rw-r--r--platform/darwin/src/NSString+MGLAdditions.h13
-rw-r--r--platform/darwin/src/NSString+MGLAdditions.m25
17 files changed, 434 insertions, 48 deletions
diff --git a/platform/darwin/src/MGLAttributionInfo.h b/platform/darwin/src/MGLAttributionInfo.h
new file mode 100644
index 0000000000..c0cb1578b5
--- /dev/null
+++ b/platform/darwin/src/MGLAttributionInfo.h
@@ -0,0 +1,58 @@
+#import <Foundation/Foundation.h>
+#import <CoreGraphics/CoreGraphics.h>
+#import <CoreLocation/CoreLocation.h>
+
+#import "MGLTypes.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ Information about an attribution statement, usually a copyright or trademark
+ statement, associated with a map source.
+ */
+@interface MGLAttributionInfo : NSObject
+
+/**
+ Parses and returns the attribution infos contained in the given HTML source
+ code string.
+
+ @param htmlString The HTML source code to parse.
+ @param fontSize The default text size in points.
+ @param linkColor The default link color.
+ */
++ (NS_ARRAY_OF(MGLAttributionInfo *) *)attributionInfosFromHTMLString:(NSString *)htmlString fontSize:(CGFloat)fontSize linkColor:(nullable MGLColor *)linkColor;
+
+- (instancetype)initWithTitle:(NSAttributedString *)title URL:(nullable NSURL *)URL;
+
+@property (nonatomic) NSAttributedString *title;
+@property (nonatomic, nullable) NSURL *URL;
+@property (nonatomic, getter=isFeedbackLink) BOOL feedbackLink;
+
+- (nullable NSURL *)feedbackURLAtCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate zoomLevel:(double)zoomLevel;
+
+@end
+
+@interface NSMutableArray (MGLAttributionInfoAdditions)
+
+/**
+ Adds the given attribution info object to the receiver as long as it isn’t
+ redundant to any object already in the receiver. Any existing object that is
+ redundant to the given object is replaced by the given object.
+
+ @param info The info object to add to the receiver.
+ @return True if the given info object was added to the receiver.
+ */
+- (void)growArrayByAddingAttributionInfo:(MGLAttributionInfo *)info;
+
+/**
+ Adds each of the given attribution info objects to the receiver as long as it
+ isn’t redundant to any object already in the receiver. Any existing object that
+ is redundant to the given object is replaced by the given object.
+
+ @param infos An array of info objects to add to the receiver.
+ */
+- (void)growArrayByAddingAttributionInfosFromArray:(NS_ARRAY_OF(MGLAttributionInfo *) *)infos;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/platform/darwin/src/MGLAttributionInfo.mm b/platform/darwin/src/MGLAttributionInfo.mm
new file mode 100644
index 0000000000..2719aef7ca
--- /dev/null
+++ b/platform/darwin/src/MGLAttributionInfo.mm
@@ -0,0 +1,178 @@
+#import "MGLAttributionInfo.h"
+
+#if TARGET_OS_IPHONE
+ #import <UIKit/UIKit.h>
+#else
+ #import <Cocoa/Cocoa.h>
+#endif
+
+#import "MGLMapCamera.h"
+#import "NSString+MGLAdditions.h"
+
+#include <string>
+
+@implementation MGLAttributionInfo
+
++ (NS_ARRAY_OF(MGLAttributionInfo *) *)attributionInfosFromHTMLString:(NSString *)htmlString fontSize:(CGFloat)fontSize linkColor:(nullable MGLColor *)linkColor {
+ NSDictionary *options = @{
+ NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType,
+ NSCharacterEncodingDocumentAttribute: @(NSUTF8StringEncoding),
+ };
+ // Apply a bogus, easily detectable style rule to any feedback link, since
+ // NSAttributedString doesn’t preserve the class attribute.
+ NSMutableString *css = [NSMutableString stringWithString:
+ @".mapbox-improve-map { -webkit-text-stroke-width: 1000px; }"];
+ if (fontSize) {
+ [css appendFormat:@"html { font-size: %.1fpx; }", fontSize];
+ }
+ if (linkColor) {
+ CGFloat red;
+ CGFloat green;
+ CGFloat blue;
+ CGFloat alpha;
+#if !TARGET_OS_IPHONE
+ linkColor = [linkColor colorUsingColorSpaceName:NSCalibratedRGBColorSpace];
+#endif
+ [linkColor getRed:&red green:&green blue:&blue alpha:&alpha];
+ [css appendFormat:
+ @"a:link { color: rgba(%f%%, %f%%, %f%%, %f); }",
+ red * 100, green * 100, blue * 100, alpha];
+ }
+ NSString *styledHTML = [NSString stringWithFormat:@"<style type='text/css'>%@</style>%@", css, htmlString];
+ NSData *htmlData = [styledHTML dataUsingEncoding:NSUTF8StringEncoding];
+
+#if TARGET_OS_IPHONE
+ NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithData:htmlData
+ options:options
+ documentAttributes:nil
+ error:NULL];
+#else
+ NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithHTML:htmlData
+ options:options
+ documentAttributes:nil];
+#endif
+
+ NSMutableArray *infos = [NSMutableArray array];
+ [attributedString enumerateAttribute:NSLinkAttributeName
+ inRange:attributedString.mgl_wholeRange
+ options:0
+ usingBlock:
+ ^(id _Nullable value, NSRange range, BOOL * _Nonnull stop) {
+ NSCAssert(!value || [value isKindOfClass:[NSURL class]], @"If present, URL attribute must be an NSURL.");
+
+ // Detect feedback links by the bogus style rule applied above.
+ NSNumber *strokeWidth = [attributedString attribute:NSStrokeWidthAttributeName
+ atIndex:range.location
+ effectiveRange:NULL];
+ BOOL isFeedbackLink = NO;
+ if ([strokeWidth floatValue] > 100) {
+ isFeedbackLink = YES;
+ [attributedString removeAttribute:NSStrokeWidthAttributeName range:range];
+ }
+
+ // Omit whitespace-only strings.
+ NSAttributedString *title = [[attributedString attributedSubstringFromRange:range]
+ mgl_attributedStringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
+ if (!title.length) {
+ return;
+ }
+
+ MGLAttributionInfo *info = [[MGLAttributionInfo alloc] initWithTitle:title URL:value];
+ info.feedbackLink = isFeedbackLink;
+ [infos addObject:info];
+ }];
+ return infos;
+}
+
+- (instancetype)initWithTitle:(NSAttributedString *)title URL:(NSURL *)URL {
+ if (self = [super init]) {
+ _title = title;
+ _URL = URL;
+ }
+ return self;
+}
+
+- (nullable NSURL *)feedbackURLAtCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate zoomLevel:(double)zoomLevel {
+ if (!self.feedbackLink) {
+ return nil;
+ }
+
+ NSURLComponents *components = [NSURLComponents componentsWithURL:self.URL resolvingAgainstBaseURL:NO];
+ components.fragment = [NSString stringWithFormat:@"/%.5f/%.5f/%i",
+ centerCoordinate.longitude, centerCoordinate.latitude, (int)round(zoomLevel + 1)];
+ return components.URL;
+}
+
+- (BOOL)isEqual:(id)object {
+ return [object isKindOfClass:[self class]] && [[object title] isEqual:self.title] && [[object URL] isEqual:self.URL];
+}
+
+- (NSUInteger)hash {
+ return self.title.hash + self.URL.hash;
+}
+
+/**
+ Returns whether the given attribution info object overlaps with the receiver by
+ its plain text title.
+
+ @return `NSOrderedAscending` if the given object is a superset of the receiver,
+ `NSOrderedDescending` if it is a subset of the receiver, or `NSOrderedSame`
+ if there is no overlap.
+ */
+- (NSComparisonResult)subsetCompare:(MGLAttributionInfo *)otherInfo {
+ NSString *title = self.title.string;
+ NSString *otherTitle = otherInfo.title.string;
+ if ([title containsString:otherTitle]) {
+ return NSOrderedDescending;
+ }
+ if ([otherTitle containsString:title]) {
+ return NSOrderedAscending;
+ }
+ return NSOrderedSame;
+}
+
+@end
+
+@implementation NSMutableArray (MGLAttributionInfoAdditions)
+
+- (void)growArrayByAddingAttributionInfo:(MGLAttributionInfo *)info {
+ __block BOOL didInsertInfo = NO;
+ __block BOOL shouldAddInfo = YES;
+ [self enumerateObjectsUsingBlock:^(MGLAttributionInfo * _Nonnull existingInfo, NSUInteger idx, BOOL * _Nonnull stop) {
+ switch ([info subsetCompare:existingInfo]) {
+ case NSOrderedDescending:
+ // The existing info object is a subset of the one we’re adding.
+ // Replace the existing object the first time we find a subset;
+ // remove the existing object every time after that.
+ if (didInsertInfo) {
+ [self removeObjectAtIndex:idx];
+ } else {
+ [self replaceObjectAtIndex:idx withObject:info];
+ didInsertInfo = YES;
+ }
+ break;
+
+ case NSOrderedAscending:
+ // The info object we’re adding is a subset of the existing one.
+ // Don’t add the object and stop looking.
+ shouldAddInfo = NO;
+ *stop = YES;
+ break;
+
+ default:
+ break;
+ }
+ }];
+ if (shouldAddInfo && !didInsertInfo) {
+ // No overlapping infos were found, so append the info object.
+ [self addObject:info];
+ }
+}
+
+- (void)growArrayByAddingAttributionInfosFromArray:(NS_ARRAY_OF(MGLAttributionInfo *) *)infos {
+ for (MGLAttributionInfo *info in infos) {
+ [self growArrayByAddingAttributionInfo:info];
+ }
+}
+
+@end
diff --git a/platform/darwin/src/MGLGeoJSONSource.mm b/platform/darwin/src/MGLGeoJSONSource.mm
index 7fd89ddc74..570b884149 100644
--- a/platform/darwin/src/MGLGeoJSONSource.mm
+++ b/platform/darwin/src/MGLGeoJSONSource.mm
@@ -18,6 +18,8 @@ const MGLGeoJSONSourceOption MGLGeoJSONSourceOptionSimplificationTolerance = @"M
@interface MGLGeoJSONSource ()
+- (instancetype)initWithRawSource:(mbgl::style::GeoJSONSource *)rawSource NS_DESIGNATED_INITIALIZER;
+
@property (nonatomic, readwrite) NSDictionary *options;
@property (nonatomic) mbgl::style::GeoJSONSource *rawSource;
@@ -60,6 +62,10 @@ const MGLGeoJSONSourceOption MGLGeoJSONSourceOptionSimplificationTolerance = @"M
return self;
}
+- (instancetype)initWithRawSource:(mbgl::style::GeoJSONSource *)rawSource {
+ return [super initWithRawSource:rawSource];
+}
+
- (void)addToMapView:(MGLMapView *)mapView
{
if (_pendingSource == nullptr) {
diff --git a/platform/darwin/src/MGLGeoJSONSource_Private.h b/platform/darwin/src/MGLGeoJSONSource_Private.h
index de5bb10fac..9d67deee34 100644
--- a/platform/darwin/src/MGLGeoJSONSource_Private.h
+++ b/platform/darwin/src/MGLGeoJSONSource_Private.h
@@ -1,10 +1,11 @@
#import "MGLGeoJSONSource.h"
-#import "MGLGeoJSONSource_Private.h"
#include <mbgl/style/sources/geojson_source.hpp>
@interface MGLGeoJSONSource (Private)
+- (instancetype)initWithRawSource:(mbgl::style::GeoJSONSource *)rawSource;
+
- (mbgl::style::GeoJSONOptions)geoJSONOptions;
@end
diff --git a/platform/darwin/src/MGLRasterSource.mm b/platform/darwin/src/MGLRasterSource.mm
index 62472050e3..1671e1decd 100644
--- a/platform/darwin/src/MGLRasterSource.mm
+++ b/platform/darwin/src/MGLRasterSource.mm
@@ -1,4 +1,4 @@
-#import "MGLRasterSource.h"
+#import "MGLRasterSource_Private.h"
#import "MGLMapView_Private.h"
#import "MGLSource_Private.h"
@@ -9,6 +9,8 @@
@interface MGLRasterSource ()
+- (instancetype)initWithRawSource:(mbgl::style::RasterSource *)rawSource NS_DESIGNATED_INITIALIZER;
+
@property (nonatomic) mbgl::style::RasterSource *rawSource;
@end
@@ -39,6 +41,16 @@
return self;
}
+- (instancetype)initWithRawSource:(mbgl::style::RasterSource *)rawSource {
+ if (self = [super initWithRawSource:rawSource]) {
+ if (auto attribution = rawSource->getAttribution()) {
+ _tileSet = [[MGLTileSet alloc] initWithTileURLTemplates:@[]];
+ _tileSet.attribution = @(attribution->c_str());
+ }
+ }
+ return self;
+}
+
- (void)commonInit
{
std::unique_ptr<mbgl::style::RasterSource> source;
diff --git a/platform/darwin/src/MGLRasterSource_Private.h b/platform/darwin/src/MGLRasterSource_Private.h
new file mode 100644
index 0000000000..4a367cf8f8
--- /dev/null
+++ b/platform/darwin/src/MGLRasterSource_Private.h
@@ -0,0 +1,13 @@
+#import "MGLRasterSource.h"
+
+namespace mbgl {
+ namespace style {
+ class RasterSource;
+ }
+}
+
+@interface MGLRasterSource (Private)
+
+- (instancetype)initWithRawSource:(mbgl::style::RasterSource *)rawSource;
+
+@end
diff --git a/platform/darwin/src/MGLSource.mm b/platform/darwin/src/MGLSource.mm
index 2fa580df89..c96b6c41c6 100644
--- a/platform/darwin/src/MGLSource.mm
+++ b/platform/darwin/src/MGLSource.mm
@@ -20,6 +20,14 @@
return self;
}
+- (instancetype)initWithRawSource:(mbgl::style::Source *)rawSource {
+ NSString *identifier = @(rawSource->getID().c_str());
+ if (self = [self initWithIdentifier:identifier]) {
+ _rawSource = rawSource;
+ }
+ return self;
+}
+
- (void)addToMapView:(MGLMapView *)mapView {
[NSException raise:NSInvalidArgumentException format:
@"The source %@ cannot be added to the style. "
diff --git a/platform/darwin/src/MGLSource_Private.h b/platform/darwin/src/MGLSource_Private.h
index d360e71f3c..3100e0ae6e 100644
--- a/platform/darwin/src/MGLSource_Private.h
+++ b/platform/darwin/src/MGLSource_Private.h
@@ -1,13 +1,21 @@
#import "MGLSource.h"
-#include <mbgl/mbgl.hpp>
-#include <mbgl/style/source.hpp>
+namespace mbgl {
+ namespace style {
+ class Source;
+ }
+}
@class MGLMapView;
@interface MGLSource (Private)
/**
+ Initializes and returns a source with a raw pointer to the backing store.
+ */
+- (instancetype)initWithRawSource:(mbgl::style::Source *)rawSource;
+
+/**
A raw pointer to the mbgl object, which is always initialized, either to the
value returned by `mbgl::Map getSource`, or for independently created objects,
to the pointer value held in `pendingSource`. In the latter case, this raw
diff --git a/platform/darwin/src/MGLStyle.mm b/platform/darwin/src/MGLStyle.mm
index a6de4e798d..ee0bb286ba 100644
--- a/platform/darwin/src/MGLStyle.mm
+++ b/platform/darwin/src/MGLStyle.mm
@@ -17,10 +17,13 @@
#import "NSDate+MGLAdditions.h"
#import "MGLSource.h"
-#import "MGLVectorSource.h"
+#import "MGLVectorSource_Private.h"
#import "MGLRasterSource.h"
#import "MGLGeoJSONSource.h"
+#import "MGLAttributionInfo.h"
+#import "MGLTileSet_Private.h"
+
#include <mbgl/util/default_styles.hpp>
#include <mbgl/sprite/sprite_image.hpp>
#include <mbgl/style/layers/fill_layer.hpp>
@@ -158,25 +161,18 @@ static NSURL *MGLStyleURL_emerald;
return rawSource ? [self sourceFromMBGLSource:rawSource] : nil;
}
-- (MGLSource *)sourceFromMBGLSource:(mbgl::style::Source *)mbglSource {
- NSString *identifier = @(mbglSource->getID().c_str());
-
+- (MGLSource *)sourceFromMBGLSource:(mbgl::style::Source *)source {
// TODO: Fill in options specific to the respective source classes
// https://github.com/mapbox/mapbox-gl-native/issues/6584
- MGLSource *source;
- if (mbglSource->is<mbgl::style::VectorSource>()) {
- source = [[MGLVectorSource alloc] initWithIdentifier:identifier];
- } else if (mbglSource->is<mbgl::style::GeoJSONSource>()) {
- source = [[MGLGeoJSONSource alloc] initWithIdentifier:identifier];
- } else if (mbglSource->is<mbgl::style::RasterSource>()) {
- source = [[MGLRasterSource alloc] initWithIdentifier:identifier];
+ if (auto vectorSource = source->as<mbgl::style::VectorSource>()) {
+ return [[MGLVectorSource alloc] initWithRawSource:vectorSource];
+ } else if (auto geoJSONSource = source->as<mbgl::style::GeoJSONSource>()) {
+ return [[MGLGeoJSONSource alloc] initWithRawSource:geoJSONSource];
+ } else if (auto rasterSource = source->as<mbgl::style::RasterSource>()) {
+ return [[MGLRasterSource alloc] initWithRawSource:rasterSource];
} else {
- source = [[MGLSource alloc] initWithIdentifier:identifier];
+ return [[MGLSource alloc] initWithRawSource:source];
}
-
- source.rawSource = mbglSource;
-
- return source;
}
- (void)addSource:(MGLSource *)source
@@ -206,6 +202,25 @@ static NSURL *MGLStyleURL_emerald;
[source removeFromMapView:self.mapView];
}
+- (nullable NS_ARRAY_OF(MGLAttributionInfo *) *)attributionInfosWithFontSize:(CGFloat)fontSize linkColor:(nullable MGLColor *)linkColor {
+ // It’d be incredibly convenient to use -sources here, but this operation
+ // depends on the sources being sorted in ascending order by creation, as
+ // with the std::vector used in mbgl.
+ auto rawSources = self.mapView.mbglMap->getSources();
+ NSMutableArray *infos = [NSMutableArray arrayWithCapacity:rawSources.size()];
+ for (auto rawSource = rawSources.begin(); rawSource != rawSources.end(); ++rawSource) {
+ MGLSource *source = [self sourceFromMBGLSource:*rawSource];
+ if (![source isKindOfClass:[MGLVectorSource class]]
+ && ![source isKindOfClass:[MGLRasterSource class]]) {
+ continue;
+ }
+
+ NSArray *tileSetInfos = [[(id)source tileSet] attributionInfosWithFontSize:fontSize linkColor:linkColor];
+ [infos growArrayByAddingAttributionInfosFromArray:tileSetInfos];
+ }
+ return infos;
+}
+
#pragma mark Style layers
- (NS_MUTABLE_ARRAY_OF(MGLStyleLayer *) *)layers
diff --git a/platform/darwin/src/MGLStyle_Private.h b/platform/darwin/src/MGLStyle_Private.h
index ee4a30c887..23ce8fbee0 100644
--- a/platform/darwin/src/MGLStyle_Private.h
+++ b/platform/darwin/src/MGLStyle_Private.h
@@ -2,11 +2,10 @@
#import "MGLStyleLayer.h"
#import "MGLFillStyleLayer.h"
-#import <mbgl/util/default_styles.hpp>
-#include <mbgl/mbgl.hpp>
NS_ASSUME_NONNULL_BEGIN
+@class MGLAttributionInfo;
@class MGLMapView;
@class MGLOpenGLStyleLayer;
@@ -16,6 +15,8 @@ NS_ASSUME_NONNULL_BEGIN
@property (nonatomic, readonly, weak) MGLMapView *mapView;
+- (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;
diff --git a/platform/darwin/src/MGLTileSet.h b/platform/darwin/src/MGLTileSet.h
index 08a34338b1..88bc7e4ae0 100644
--- a/platform/darwin/src/MGLTileSet.h
+++ b/platform/darwin/src/MGLTileSet.h
@@ -17,6 +17,32 @@ typedef NS_ENUM(NSUInteger, MGLTileSetScheme) {
*/
@interface MGLTileSet : NSObject
+#pragma mark Creating a Tile Set
+
+/**
+ Initializes and returns a new tile set object.
+
+ @param tileURLTemplates An `NSArray` of `NSString` objects that represent the
+ tile templates.
+ @return The initialized tile set object.
+ */
+- (instancetype)initWithTileURLTemplates:(NS_ARRAY_OF(NSString *) *)tileURLTemplates;
+
+/**
+ Initializes and returns a new tile set object.
+
+ @param tileURLTemplates An `NSArray` of `NSString` objects that represent the
+ tile templates.
+ @param minimumZoomLevel An `NSUInteger`; specifies the minimum zoom level at
+ which to display tiles.
+ @param maximumZoomLevel An `NSUInteger`; specifies the maximum zoom level at
+ which to display tiles.
+ @return The initialized tile set object.
+ */
+- (instancetype)initWithTileURLTemplates:(NS_ARRAY_OF(NSString *) *)tileURLTemplates minimumZoomLevel:(NSUInteger)minimumZoomLevel maximumZoomLevel:(NSUInteger)maximumZoomLevel;
+
+#pragma mark Accessing Tile Set Metadata
+
/**
An `NSArray` of `NSString` objects that represent the tile templates.
*/
@@ -51,28 +77,6 @@ typedef NS_ENUM(NSUInteger, MGLTileSetScheme) {
*/
@property (nonatomic) MGLTileSetScheme scheme;
-/**
- Initializes and returns a new tile set object.
-
- @param tileURLTemplates An `NSArray` of `NSString` objects that represent the
- tile templates.
- @return The initialized tile set object.
- */
-- (instancetype)initWithTileURLTemplates:(NS_ARRAY_OF(NSString *) *)tileURLTemplates;
-
-/**
- Initializes and returns a new tile set object.
-
- @param tileURLTemplates An `NSArray` of `NSString` objects that represent the
- tile templates.
- @param minimumZoomLevel An `NSUInteger`; specifies the minimum zoom level at
- which to display tiles.
- @param maximumZoomLevel An `NSUInteger`; specifies the maximum zoom level at
- which to display tiles.
- @return The initialized tile set object.
- */
-- (instancetype)initWithTileURLTemplates:(NS_ARRAY_OF(NSString *) *)tileURLTemplates minimumZoomLevel:(NSUInteger)minimumZoomLevel maximumZoomLevel:(NSUInteger)maximumZoomLevel;
-
@end
NS_ASSUME_NONNULL_END
diff --git a/platform/darwin/src/MGLTileSet.mm b/platform/darwin/src/MGLTileSet.mm
index f795545eed..6afc6c19af 100644
--- a/platform/darwin/src/MGLTileSet.mm
+++ b/platform/darwin/src/MGLTileSet.mm
@@ -1,5 +1,7 @@
#import "MGLTileSet.h"
+#import "MGLAttributionInfo.h"
+
#include <mbgl/util/tileset.hpp>
@implementation MGLTileSet
@@ -57,6 +59,12 @@
_maximumZoomLevel = maximumZoomLevel;
}
+- (nullable NS_ARRAY_OF(MGLAttributionInfo *) *)attributionInfosWithFontSize:(CGFloat)fontSize linkColor:(nullable MGLColor *)linkColor {
+ return [MGLAttributionInfo attributionInfosFromHTMLString:self.attribution
+ fontSize:fontSize
+ linkColor:linkColor];
+}
+
- (mbgl::Tileset)mbglTileset
{
mbgl::Tileset tileset;
diff --git a/platform/darwin/src/MGLTileSet_Private.h b/platform/darwin/src/MGLTileSet_Private.h
index 6a14d428db..038fe57fa2 100644
--- a/platform/darwin/src/MGLTileSet_Private.h
+++ b/platform/darwin/src/MGLTileSet_Private.h
@@ -2,8 +2,23 @@
#include <mbgl/util/tileset.hpp>
+NS_ASSUME_NONNULL_BEGIN
+
+@class MGLAttributionInfo;
+
@interface MGLTileSet (Private)
+/**
+ A structured representation of the `attribution` property. The default value is
+ `nil`.
+
+ @param fontSize The default text size in points.
+ @param linkColor The default link color.
+ */
+- (nullable NS_ARRAY_OF(MGLAttributionInfo *) *)attributionInfosWithFontSize:(CGFloat)fontSize linkColor:(nullable MGLColor *)linkColor;
+
- (mbgl::Tileset)mbglTileset;
-@end \ No newline at end of file
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/platform/darwin/src/MGLVectorSource.mm b/platform/darwin/src/MGLVectorSource.mm
index ab68d45ba1..b5ec0b33be 100644
--- a/platform/darwin/src/MGLVectorSource.mm
+++ b/platform/darwin/src/MGLVectorSource.mm
@@ -1,4 +1,4 @@
-#import "MGLVectorSource.h"
+#import "MGLVectorSource_Private.h"
#import "MGLMapView_Private.h"
#import "MGLSource_Private.h"
@@ -9,6 +9,8 @@
@interface MGLVectorSource ()
+- (instancetype)initWithRawSource:(mbgl::style::VectorSource *)rawSource NS_DESIGNATED_INITIALIZER;
+
@property (nonatomic) mbgl::style::VectorSource *rawSource;
@end
@@ -38,6 +40,16 @@
return self;
}
+- (instancetype)initWithRawSource:(mbgl::style::VectorSource *)rawSource {
+ if (self = [super initWithRawSource:rawSource]) {
+ if (auto attribution = rawSource->getAttribution()) {
+ _tileSet = [[MGLTileSet alloc] initWithTileURLTemplates:@[]];
+ _tileSet.attribution = @(attribution->c_str());
+ }
+ }
+ return self;
+}
+
- (void)commonInit
{
std::unique_ptr<mbgl::style::VectorSource> source;
diff --git a/platform/darwin/src/MGLVectorSource_Private.h b/platform/darwin/src/MGLVectorSource_Private.h
new file mode 100644
index 0000000000..ce6bccdbae
--- /dev/null
+++ b/platform/darwin/src/MGLVectorSource_Private.h
@@ -0,0 +1,13 @@
+#import "MGLVectorSource.h"
+
+namespace mbgl {
+ namespace style {
+ class VectorSource;
+ }
+}
+
+@interface MGLVectorSource (Private)
+
+- (instancetype)initWithRawSource:(mbgl::style::VectorSource *)rawSource;
+
+@end
diff --git a/platform/darwin/src/NSString+MGLAdditions.h b/platform/darwin/src/NSString+MGLAdditions.h
index 5b549affd5..45fea25588 100644
--- a/platform/darwin/src/NSString+MGLAdditions.h
+++ b/platform/darwin/src/NSString+MGLAdditions.h
@@ -4,9 +4,22 @@ NS_ASSUME_NONNULL_BEGIN
@interface NSString (MGLAdditions)
+/** Returns the range spanning the entire receiver. */
+- (NSRange)mgl_wholeRange;
+
/** Returns the receiver if non-empty or nil if empty. */
- (nullable NSString *)mgl_stringOrNilIfEmpty;
@end
+@interface NSAttributedString (MGLAdditions)
+
+/** Returns the range spanning the entire receiver. */
+- (NSRange)mgl_wholeRange;
+
+/** Returns a copy of the receiver with leading and trailing members of the given set removed. */
+- (NSAttributedString *)mgl_attributedStringByTrimmingCharactersInSet:(NSCharacterSet *)set;
+
+@end
+
NS_ASSUME_NONNULL_END
diff --git a/platform/darwin/src/NSString+MGLAdditions.m b/platform/darwin/src/NSString+MGLAdditions.m
index 969886651b..04a65dc5e2 100644
--- a/platform/darwin/src/NSString+MGLAdditions.m
+++ b/platform/darwin/src/NSString+MGLAdditions.m
@@ -2,9 +2,30 @@
@implementation NSString (MGLAdditions)
-- (nullable NSString *)mgl_stringOrNilIfEmpty
-{
+- (NSRange)mgl_wholeRange {
+ return NSMakeRange(0, self.length);
+}
+
+- (nullable NSString *)mgl_stringOrNilIfEmpty {
return self.length ? self : nil;
}
@end
+
+@implementation NSAttributedString (MGLAdditions)
+
+- (NSRange)mgl_wholeRange {
+ return NSMakeRange(0, self.length);
+}
+
+- (NSAttributedString *)mgl_attributedStringByTrimmingCharactersInSet:(NSCharacterSet *)set {
+ NSScanner *scanner = [NSScanner scannerWithString:self.string];
+ scanner.charactersToBeSkipped = nil;
+ NSString *prefix;
+ [scanner scanCharactersFromSet:set intoString:&prefix];
+
+ NSString *trimmedString = [self.string stringByTrimmingCharactersInSet:set];
+ return [self attributedSubstringFromRange:NSMakeRange(prefix.length, trimmedString.length)];
+}
+
+@end