diff options
Diffstat (limited to 'platform/darwin')
39 files changed, 939 insertions, 511 deletions
diff --git a/platform/darwin/docs/theme/assets/css/jazzy.css.scss b/platform/darwin/docs/theme/assets/css/jazzy.css.scss index ad0a3b7082..103ba601dc 100644 --- a/platform/darwin/docs/theme/assets/css/jazzy.css.scss +++ b/platform/darwin/docs/theme/assets/css/jazzy.css.scss @@ -386,6 +386,7 @@ pre code { .nav-group-task[data-name="MGLStyleFunction"], .nav-group-task[data-name="MGLStyleLayer"], .nav-group-task[data-name="MGLTileSource"], +.nav-group-task[data-name="MGLAbstractShapeSource"], .nav-group-task[data-name="MGLVectorStyleLayer"] { .nav-group-task-link::after { @extend %nav-group-task-gloss; diff --git a/platform/darwin/mbgl/gl/gl_impl.hpp b/platform/darwin/mbgl/gl/gl_impl.hpp new file mode 100644 index 0000000000..b4c062a474 --- /dev/null +++ b/platform/darwin/mbgl/gl/gl_impl.hpp @@ -0,0 +1,16 @@ +#pragma once + +#include "TargetConditionals.h" +#if TARGET_OS_IPHONE + #include <OpenGLES/ES2/gl.h> + #include <OpenGLES/ES2/glext.h> +#elif TARGET_IPHONE_SIMULATOR + #include <OpenGLES/ES2/gl.h> + #include <OpenGLES/ES2/glext.h> +#elif TARGET_OS_MAC + #include <OpenGL/OpenGL.h> + #include <OpenGL/gl.h> + #include <OpenGL/glext.h> +#else + #error Unsupported Apple platform +#endif diff --git a/platform/darwin/mbgl/util/image+MGLAdditions.hpp b/platform/darwin/mbgl/util/image+MGLAdditions.hpp index c738b4523d..c5343af4de 100644 --- a/platform/darwin/mbgl/util/image+MGLAdditions.hpp +++ b/platform/darwin/mbgl/util/image+MGLAdditions.hpp @@ -5,7 +5,7 @@ #include <CoreGraphics/CGImage.h> // Creates a CGImage from a PremultipliedImage, taking over the memory ownership. -CGImageRef CGImageFromMGLPremultipliedImage(mbgl::PremultipliedImage&&); +CGImageRef CGImageCreateWithMGLPremultipliedImage(mbgl::PremultipliedImage&&); // Creates a PremultipliedImage by copying the pixels of the CGImage. // Does not alter the retain count of the supplied CGImage. diff --git a/platform/darwin/src/MGLAbstractShapeSource.h b/platform/darwin/src/MGLAbstractShapeSource.h new file mode 100644 index 0000000000..3b35986b3f --- /dev/null +++ b/platform/darwin/src/MGLAbstractShapeSource.h @@ -0,0 +1,99 @@ +#import "MGLSource.h" + +/** + Options for `MGLShapeSource` objects. + */ +typedef NSString *MGLShapeSourceOption NS_STRING_ENUM; + +/** + An `NSNumber` object containing a Boolean enabling or disabling clustering. + If the `shape` property contains point shapes, setting this option to + `YES` clusters the points by radius into groups. The default value is `NO`. + + This attribute corresponds to the + <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources-geojson-cluster"><code>cluster</code></a> + source property in the Mapbox Style Specification. + + This option only affects point features within a shape source. + */ +extern MGL_EXPORT const MGLShapeSourceOption MGLShapeSourceOptionClustered; + +/** + An `NSNumber` object containing an integer; specifies the radius of each + cluster if clustering is enabled. A value of 512 produces a radius equal to + the width of a tile. The default value is 50. + */ +extern MGL_EXPORT const MGLShapeSourceOption MGLShapeSourceOptionClusterRadius; + +/** + An `NSNumber` object containing an integer; specifies the maximum zoom level at + which to cluster points if clustering is enabled. Defaults to one zoom level + less than the value of `MGLShapeSourceOptionMaximumZoomLevel` so that, at the + maximum zoom level, the shapes are not clustered. + + This attribute corresponds to the + <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources-geojson-clusterMaxZoom"><code>clusterMaxZoom</code></a> + source property in the Mapbox Style Specification. + */ +extern MGL_EXPORT const MGLShapeSourceOption MGLShapeSourceOptionMaximumZoomLevelForClustering; + +/** + An `NSNumber` object containing an integer; specifies the minimum zoom level at + which to create vector tiles. The default value is 0. + + This attribute corresponds to the + <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources-geojson-minzoom"><code>minzoom</code></a> + source property in the Mapbox Style Specification. + */ +extern MGL_EXPORT const MGLShapeSourceOption MGLShapeSourceOptionMinimumZoomLevel; + +/** + An `NSNumber` object containing an integer; specifies the maximum zoom level at + which to create vector tiles. A greater value produces greater detail at high + zoom levels. The default value is 18. + + This attribute corresponds to the + <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources-geojson-maxzoom"><code>maxzoom</code></a> + source property in the Mapbox Style Specification. + */ +extern MGL_EXPORT const MGLShapeSourceOption MGLShapeSourceOptionMaximumZoomLevel; + +/** + An `NSNumber` object containing an integer; specifies the size of the tile + buffer on each side. A value of 0 produces no buffer. A value of 512 produces a + buffer as wide as the tile itself. Larger values produce fewer rendering + artifacts near tile edges and slower performance. The default value is 128. + + This attribute corresponds to the + <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources-geojson-buffer"><code>buffer</code></a> + source property in the Mapbox Style Specification. + */ +extern MGL_EXPORT const MGLShapeSourceOption MGLShapeSourceOptionBuffer; + +/** + An `NSNumber` object containing a double; specifies the Douglas-Peucker + simplification tolerance. A greater value produces simpler geometries and + improves performance. The default value is 0.375. + + This attribute corresponds to the + <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources-geojson-tolerance"><code>tolerance</code></a> + source property in the Mapbox Style Specification. + */ +extern MGL_EXPORT const MGLShapeSourceOption MGLShapeSourceOptionSimplificationTolerance; + +/** + `MGLAbstractShapeSource` is an abstract base class for map content sources that + supply vector shapes to be shown on the map. A shape source is added to an + `MGLStyle` object along with an `MGLVectorStyleLayer` object. The vector style + layer defines the appearance of any content supplied by the shape source. + + + Do not create instances of this class directly, and do not create your own + subclasses of this class. Instead, create instances of `MGLShapeSource` or + `MGLComputedShapeSource`. + */ +MGL_EXPORT +@interface MGLAbstractShapeSource : MGLSource + + +@end diff --git a/platform/darwin/src/MGLAbstractShapeSource.mm b/platform/darwin/src/MGLAbstractShapeSource.mm new file mode 100644 index 0000000000..755d040387 --- /dev/null +++ b/platform/darwin/src/MGLAbstractShapeSource.mm @@ -0,0 +1,117 @@ +#import "MGLAbstractShapeSource.h" +#import "MGLAbstractShapeSource_Private.h" + +const MGLShapeSourceOption MGLShapeSourceOptionBuffer = @"MGLShapeSourceOptionBuffer"; +const MGLShapeSourceOption MGLShapeSourceOptionClusterRadius = @"MGLShapeSourceOptionClusterRadius"; +const MGLShapeSourceOption MGLShapeSourceOptionClustered = @"MGLShapeSourceOptionClustered"; +const MGLShapeSourceOption MGLShapeSourceOptionMaximumZoomLevel = @"MGLShapeSourceOptionMaximumZoomLevel"; +const MGLShapeSourceOption MGLShapeSourceOptionMaximumZoomLevelForClustering = @"MGLShapeSourceOptionMaximumZoomLevelForClustering"; +const MGLShapeSourceOption MGLShapeSourceOptionMinimumZoomLevel = @"MGLShapeSourceOptionMinimumZoomLevel"; +const MGLShapeSourceOption MGLShapeSourceOptionSimplificationTolerance = @"MGLShapeSourceOptionSimplificationTolerance"; + +@interface MGLAbstractShapeSource () + +@end + +@implementation MGLAbstractShapeSource + +@end + +mbgl::style::GeoJSONOptions MGLGeoJSONOptionsFromDictionary(NS_DICTIONARY_OF(MGLShapeSourceOption, id) *options) { + auto geoJSONOptions = mbgl::style::GeoJSONOptions(); + + if (NSNumber *value = options[MGLShapeSourceOptionMinimumZoomLevel]) { + if (![value isKindOfClass:[NSNumber class]]) { + [NSException raise:NSInvalidArgumentException + format:@"MGLShapeSourceOptionMaximumZoomLevel must be an NSNumber."]; + } + geoJSONOptions.minzoom = value.integerValue; + } + + if (NSNumber *value = options[MGLShapeSourceOptionMaximumZoomLevel]) { + if (![value isKindOfClass:[NSNumber class]]) { + [NSException raise:NSInvalidArgumentException + format:@"MGLShapeSourceOptionMaximumZoomLevel must be an NSNumber."]; + } + geoJSONOptions.maxzoom = value.integerValue; + } + + if (NSNumber *value = options[MGLShapeSourceOptionBuffer]) { + if (![value isKindOfClass:[NSNumber class]]) { + [NSException raise:NSInvalidArgumentException + format:@"MGLShapeSourceOptionBuffer must be an NSNumber."]; + } + geoJSONOptions.buffer = value.integerValue; + } + + if (NSNumber *value = options[MGLShapeSourceOptionSimplificationTolerance]) { + if (![value isKindOfClass:[NSNumber class]]) { + [NSException raise:NSInvalidArgumentException + format:@"MGLShapeSourceOptionSimplificationTolerance must be an NSNumber."]; + } + geoJSONOptions.tolerance = value.doubleValue; + } + + if (NSNumber *value = options[MGLShapeSourceOptionClusterRadius]) { + if (![value isKindOfClass:[NSNumber class]]) { + [NSException raise:NSInvalidArgumentException + format:@"MGLShapeSourceOptionClusterRadius must be an NSNumber."]; + } + geoJSONOptions.clusterRadius = value.integerValue; + } + + if (NSNumber *value = options[MGLShapeSourceOptionMaximumZoomLevelForClustering]) { + if (![value isKindOfClass:[NSNumber class]]) { + [NSException raise:NSInvalidArgumentException + format:@"MGLShapeSourceOptionMaximumZoomLevelForClustering must be an NSNumber."]; + } + geoJSONOptions.clusterMaxZoom = value.integerValue; + } + + if (NSNumber *value = options[MGLShapeSourceOptionClustered]) { + if (![value isKindOfClass:[NSNumber class]]) { + [NSException raise:NSInvalidArgumentException + format:@"MGLShapeSourceOptionClustered must be an NSNumber."]; + } + geoJSONOptions.cluster = value.boolValue; + } + + return geoJSONOptions; +} + +mbgl::style::CustomGeometrySource::Options MBGLCustomGeometrySourceOptionsFromDictionary(NS_DICTIONARY_OF(MGLShapeSourceOption, id) *options) { + mbgl::style::CustomGeometrySource::Options sourceOptions; + + if (NSNumber *value = options[MGLShapeSourceOptionMinimumZoomLevel]) { + if (![value isKindOfClass:[NSNumber class]]) { + [NSException raise:NSInvalidArgumentException + format:@"MGLShapeSourceOptionMaximumZoomLevelForClustering must be an NSNumber."]; + } + sourceOptions.zoomRange.min = value.integerValue; + } + + if (NSNumber *value = options[MGLShapeSourceOptionMaximumZoomLevel]) { + if (![value isKindOfClass:[NSNumber class]]) { + [NSException raise:NSInvalidArgumentException + format:@"MGLShapeSourceOptionMaximumZoomLevel must be an NSNumber."]; + } + sourceOptions.zoomRange.max = value.integerValue; + } + + if (NSNumber *value = options[MGLShapeSourceOptionBuffer]) { + if (![value isKindOfClass:[NSNumber class]]) { + [NSException raise:NSInvalidArgumentException + format:@"MGLShapeSourceOptionBuffer must be an NSNumber."]; + } + sourceOptions.tileOptions.buffer = value.integerValue; + } + + if (NSNumber *value = options[MGLShapeSourceOptionSimplificationTolerance]) { + if (![value isKindOfClass:[NSNumber class]]) { + [NSException raise:NSInvalidArgumentException + format:@"MGLShapeSourceOptionSimplificationTolerance must be an NSNumber."]; + } + sourceOptions.tileOptions.tolerance = value.doubleValue; + } + return sourceOptions; +} diff --git a/platform/darwin/src/MGLAbstractShapeSource_Private.h b/platform/darwin/src/MGLAbstractShapeSource_Private.h new file mode 100644 index 0000000000..ddde55b149 --- /dev/null +++ b/platform/darwin/src/MGLAbstractShapeSource_Private.h @@ -0,0 +1,22 @@ +#import "MGLAbstractShapeSource.h" + +#import "MGLFoundation.h" +#import "MGLTypes.h" +#import "MGLShape.h" + +#include <mbgl/style/sources/geojson_source.hpp> +#include <mbgl/style/sources/custom_geometry_source.hpp> + +NS_ASSUME_NONNULL_BEGIN + +@interface MGLAbstractShapeSource (Private) + +MGL_EXPORT + +mbgl::style::GeoJSONOptions MGLGeoJSONOptionsFromDictionary(NS_DICTIONARY_OF(MGLShapeSourceOption, id) *options); + +MGL_EXPORT +mbgl::style::CustomGeometrySource::Options MBGLCustomGeometrySourceOptionsFromDictionary(NS_DICTIONARY_OF(MGLShapeSourceOption, id) *options); + +@end +NS_ASSUME_NONNULL_END diff --git a/platform/darwin/src/MGLAccountManager.m b/platform/darwin/src/MGLAccountManager.m index 7e55779d04..729caeaa31 100644 --- a/platform/darwin/src/MGLAccountManager.m +++ b/platform/darwin/src/MGLAccountManager.m @@ -39,7 +39,7 @@ } static dispatch_once_t onceToken; static MGLAccountManager *_sharedManager; - void (^setupBlock)() = ^{ + void (^setupBlock)(void) = ^{ dispatch_once(&onceToken, ^{ _sharedManager = [[self alloc] init]; }); diff --git a/platform/darwin/src/MGLAttributionInfo.mm b/platform/darwin/src/MGLAttributionInfo.mm index 52a83fd18e..73147270c1 100644 --- a/platform/darwin/src/MGLAttributionInfo.mm +++ b/platform/darwin/src/MGLAttributionInfo.mm @@ -160,6 +160,7 @@ [NSURLQueryItem queryItemWithName:@"owner" value:stylePathComponents[1]], [NSURLQueryItem queryItemWithName:@"id" value:stylePathComponents[2]], [NSURLQueryItem queryItemWithName:@"access_token" value:[MGLAccountManager accessToken]], + [NSURLQueryItem queryItemWithName:@"map_sdk_version" value:[NSBundle mgl_frameworkInfoDictionary][@"MGLSemanticVersionString"]], ]]; } } diff --git a/platform/darwin/src/MGLComputedShapeSource.h b/platform/darwin/src/MGLComputedShapeSource.h new file mode 100644 index 0000000000..f90f2c94b1 --- /dev/null +++ b/platform/darwin/src/MGLComputedShapeSource.h @@ -0,0 +1,113 @@ +#import "MGLAbstractShapeSource.h" + +#import "MGLFoundation.h" +#import "MGLGeometry.h" +#import "MGLTypes.h" +#import "MGLShape.h" + +NS_ASSUME_NONNULL_BEGIN + +@protocol MGLFeature; + +/** + Data source for `MGLComputedShapeSource`. This protocol defines two optional methods for fetching + data, one based on tile coordinates, and one based on a bounding box. Classes that implement this + protocol must implement one, and only one of the methods. Methods on this protocol will not be + called on main thread, they will be called on the caller's `requestQueue`. + */ +@protocol MGLComputedShapeSourceDataSource <NSObject> + +@optional +/** + Fetch features for a tile. This method will not be invoked on the main queue, it + will be invoked on the caller's `requestQueue`. + @param x Tile X coordinate. + @param y Tile Y coordinate. + @param zoomLevel Tile zoom level. + */ +- (NSArray<MGLShape <MGLFeature> *>*)featuresInTileAtX:(NSUInteger)x y:(NSUInteger)y zoomLevel:(NSUInteger)zoomLevel; + +/** + Fetch features for a tile. This method will not be invoked on the main queue, it + will be invoked on the caller's `requestQueue`. + @param bounds The bounds to fetch data for. + @param zoomLevel Tile zoom level. + */ +- (NSArray<MGLShape <MGLFeature> *>*)featuresInCoordinateBounds:(MGLCoordinateBounds)bounds zoomLevel:(NSUInteger)zoomLevel; + +@end + +/** + A source for vector data that is fetched one tile at a time. Useful for sources that are + too large to fit in memory, or are already divided into tiles, but not in Mapbox Vector Tile format. + + Supported options are `MGLShapeSourceOptionMinimumZoomLevel`, `MGLShapeSourceOptionMaximumZoomLevel`, + `MGLShapeSourceOptionBuffer`, and `MGLShapeSourceOptionSimplificationTolerance.` This source does + not support clustering. + */ +MGL_EXPORT +@interface MGLComputedShapeSource : MGLAbstractShapeSource + +/** + Returns a custom shape data source initialized with an identifier, and a + dictionary of options for the source according to the + <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources-geojson">style + specification</a>. + + @param identifier A string that uniquely identifies the source. + @param options An `NSDictionary` of options for this source. + */ +- (instancetype)initWithIdentifier:(NSString *)identifier options:(nullable NS_DICTIONARY_OF(MGLShapeSourceOption, id) *)options NS_DESIGNATED_INITIALIZER; + +/** + Returns a custom shape data source initialized with an identifier, data source, and a + dictionary of options for the source according to the + <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources-geojson">style + specification</a>. + + @param identifier A string that uniquely identifies the source. + @param options An `NSDictionary` of options for this source. + */ +- (instancetype)initWithIdentifier:(NSString *)identifier dataSource:(id<MGLComputedShapeSourceDataSource>)dataSource options:(nullable NS_DICTIONARY_OF(MGLShapeSourceOption, id) *)options; + +/** + Invalidates all the features and properties intersecting with or contained in + the specified bounds. New fetch requests will immediately be invoked on the + `MGLComputedShapeSourceDataSource`. + @param bounds Coordinate bounds to invalidate. + */ +- (void) invalidateBounds:(MGLCoordinateBounds)bounds; + +/** + Invalidates all the feautres and properties of a given tile. A new fetch request + will immediately be invoked on the `MGLComputedShapeSourceDataSource`. + @param x Tile X coordinate. + @param y Tile Y coordinate. + @param zoomLevel Tile zoom level. + */ +- (void) invalidateTileAtX:(NSUInteger)x y:(NSUInteger)y zoomLevel:(NSUInteger)zoomLevel; + +/** + Set a new set of features for a tile. This method can be invkoed from background threads. + For best performance, use this method only to update tiles that have already been requested + through `MGLComputedShapeSourceDataSource.` + @param features Features for the tile. + @param x Tile X coordinate. + @param y Tile Y coordinate. + @param zoomLevel Tile zoom level. + */ +- (void) setFeatures:(NSArray<MGLShape <MGLFeature> *>*)features inTileAtX:(NSUInteger)x y:(NSUInteger)y zoomLevel:(NSUInteger)zoomLevel; + +/** + An object that implements the `MGLComputedShapeSourceDataSource` protocol that will be queried for tile data. + */ +@property (nonatomic, weak, nullable) id<MGLComputedShapeSourceDataSource> dataSource; + +/** + A queue that calls to the data source will be made on. + */ +@property (nonatomic, readonly) NSOperationQueue *requestQueue; + +@end + +NS_ASSUME_NONNULL_END diff --git a/platform/darwin/src/MGLComputedShapeSource.mm b/platform/darwin/src/MGLComputedShapeSource.mm new file mode 100644 index 0000000000..0a3c92bb97 --- /dev/null +++ b/platform/darwin/src/MGLComputedShapeSource.mm @@ -0,0 +1,169 @@ +#import "MGLComputedShapeSource.h" + +#import "MGLMapView_Private.h" +#import "MGLSource_Private.h" +#import "MGLShape_Private.h" +#import "MGLAbstractShapeSource_Private.h" +#import "MGLGeometry_Private.h" + +#include <mbgl/map/map.hpp> +#include <mbgl/style/sources/custom_geometry_source.hpp> +#include <mbgl/tile/tile_id.hpp> +#include <mbgl/util/geojson.hpp> + +@interface MGLComputedShapeSource () { + std::unique_ptr<mbgl::style::CustomGeometrySource> _pendingSource; +} + +@property (nonatomic, readwrite) NSDictionary *options; +@property (nonatomic, assign) BOOL dataSourceImplementsFeaturesForTile; +@property (nonatomic, assign) BOOL dataSourceImplementsFeaturesForBounds; + +@end + +@interface MGLComputedShapeSourceFetchOperation : NSOperation + +@property (nonatomic, readonly) uint8_t z; +@property (nonatomic, readonly) uint32_t x; +@property (nonatomic, readonly) uint32_t y; +@property (nonatomic, assign) BOOL dataSourceImplementsFeaturesForTile; +@property (nonatomic, assign) BOOL dataSourceImplementsFeaturesForBounds; +@property (nonatomic, weak, nullable) id<MGLComputedShapeSourceDataSource> dataSource; +@property (nonatomic, nullable) mbgl::style::CustomGeometrySource *rawSource; + +- (instancetype)initForSource:(MGLComputedShapeSource*)source tile:(const mbgl::CanonicalTileID&)tileId; + +@end + +@implementation MGLComputedShapeSourceFetchOperation + +- (instancetype)initForSource:(MGLComputedShapeSource*)source tile:(const mbgl::CanonicalTileID&)tileID { + self = [super init]; + _z = tileID.z; + _x = tileID.x; + _y = tileID.y; + _dataSourceImplementsFeaturesForTile = source.dataSourceImplementsFeaturesForTile; + _dataSourceImplementsFeaturesForBounds = source.dataSourceImplementsFeaturesForBounds; + _dataSource = source.dataSource; + mbgl::style::CustomGeometrySource *rawSource = static_cast<mbgl::style::CustomGeometrySource *>(source.rawSource); + _rawSource = rawSource; + return self; +} + +- (void)main { + if ([self isCancelled]) { + return; + } + + NSArray<MGLShape <MGLFeature> *> *data; + if(!self.dataSource) { + data = nil; + } else if(self.dataSourceImplementsFeaturesForTile) { + data = [self.dataSource featuresInTileAtX:self.x + y:self.y + zoomLevel:self.z]; + } else { + mbgl::CanonicalTileID tileID = mbgl::CanonicalTileID(self.z, self.x, self.y); + mbgl::LatLngBounds tileBounds = mbgl::LatLngBounds(tileID); + data = [self.dataSource featuresInCoordinateBounds:MGLCoordinateBoundsFromLatLngBounds(tileBounds) + zoomLevel:self.z]; + } + + if(![self isCancelled]) { + mbgl::FeatureCollection featureCollection; + featureCollection.reserve(data.count); + for (MGLShape <MGLFeature> * feature in data) { + mbgl::Feature geoJsonObject = [feature geoJSONObject].get<mbgl::Feature>(); + featureCollection.push_back(geoJsonObject); + } + const auto geojson = mbgl::GeoJSON{featureCollection}; + if(![self isCancelled] && self.rawSource) { + self.rawSource->setTileData(mbgl::CanonicalTileID(self.z, self.x, self.y), geojson); + } + } +} + +- (void)cancel { + [super cancel]; + self.rawSource = NULL; +} + +@end + +@implementation MGLComputedShapeSource + +- (instancetype)initWithIdentifier:(NSString *)identifier options:(NS_DICTIONARY_OF(MGLShapeSourceOption, id) *)options { + NSOperationQueue *requestQueue = [[NSOperationQueue alloc] init]; + requestQueue.name = [NSString stringWithFormat:@"mgl.MGLComputedShapeSource.%@", identifier]; + requestQueue.qualityOfService = NSQualityOfServiceUtility; + requestQueue.maxConcurrentOperationCount = 4; + + auto sourceOptions = MBGLCustomGeometrySourceOptionsFromDictionary(options); + sourceOptions.fetchTileFunction = ^void(const mbgl::CanonicalTileID& tileID) { + NSOperation *operation = [[MGLComputedShapeSourceFetchOperation alloc] initForSource:self tile:tileID]; + [requestQueue addOperation:operation]; + }; + + sourceOptions.cancelTileFunction = ^void(const mbgl::CanonicalTileID& tileID) { + for (MGLComputedShapeSourceFetchOperation *operation in requestQueue.operations) { + if (operation.x == tileID.x && operation.y == tileID.y && operation.z == tileID.z) { + [operation cancel]; + } + } + }; + + auto source = std::make_unique<mbgl::style::CustomGeometrySource>(identifier.UTF8String, sourceOptions); + + if (self = [super initWithPendingSource:std::move(source)]) { + _requestQueue = requestQueue; + } + return self; +} + +- (instancetype)initWithIdentifier:(NSString *)identifier dataSource:(id<MGLComputedShapeSourceDataSource>)dataSource options:(NS_DICTIONARY_OF(MGLShapeSourceOption, id) *)options { + if (self = [self initWithIdentifier:identifier options:options]) { + [self setDataSource:dataSource]; + } + return self; +} + +- (void)dealloc { + [self.requestQueue cancelAllOperations]; +} + +- (void)setFeatures:(NSArray<MGLShape <MGLFeature> *>*)features inTileAtX:(NSUInteger)x y:(NSUInteger)y zoomLevel:(NSUInteger)zoomLevel { + mbgl::CanonicalTileID tileID = mbgl::CanonicalTileID((uint8_t)zoomLevel, (uint32_t)x, (uint32_t)y); + mbgl::FeatureCollection featureCollection; + featureCollection.reserve(features.count); + for (MGLShape <MGLFeature> * feature in features) { + mbgl::Feature geoJsonObject = [feature geoJSONObject].get<mbgl::Feature>(); + featureCollection.push_back(geoJsonObject); + } + const auto geojson = mbgl::GeoJSON{featureCollection}; + static_cast<mbgl::style::CustomGeometrySource *>(self.rawSource)->setTileData(tileID, geojson); +} + +- (void)setDataSource:(id<MGLComputedShapeSourceDataSource>)dataSource { + [self.requestQueue cancelAllOperations]; + // Check which method the datasource implements, to avoid having to check for each tile + self.dataSourceImplementsFeaturesForTile = [dataSource respondsToSelector:@selector(featuresInTileAtX:y:zoomLevel:)]; + self.dataSourceImplementsFeaturesForBounds = [dataSource respondsToSelector:@selector(featuresInCoordinateBounds:zoomLevel:)]; + + if(!self.dataSourceImplementsFeaturesForBounds && !self.dataSourceImplementsFeaturesForTile) { + [NSException raise:@"Invalid Datasource" format:@"Datasource does not implement any MGLComputedShapeSourceDataSource methods"]; + } else if(self.dataSourceImplementsFeaturesForBounds && self.dataSourceImplementsFeaturesForTile) { + [NSException raise:@"Invalid Datasource" format:@"Datasource implements multiple MGLComputedShapeSourceDataSource methods"]; + } + + _dataSource = dataSource; +} + +- (void) invalidateBounds:(MGLCoordinateBounds)bounds { + ((mbgl::style::CustomGeometrySource *)self.rawSource)->invalidateRegion(MGLLatLngBoundsFromCoordinateBounds(bounds)); +} + +- (void) invalidateTileAtX:(NSUInteger)x y:(NSUInteger)y zoomLevel:(NSUInteger)z { + ((mbgl::style::CustomGeometrySource *)self.rawSource)->invalidateTile(mbgl::CanonicalTileID(z, (unsigned int)x, (unsigned int)y)); +} + +@end diff --git a/platform/darwin/src/MGLConversion.h b/platform/darwin/src/MGLConversion.h index d6363b28eb..0d18d4e716 100644 --- a/platform/darwin/src/MGLConversion.h +++ b/platform/darwin/src/MGLConversion.h @@ -1,9 +1,4 @@ -#import <Foundation/Foundation.h> - -#include <mbgl/util/logging.hpp> #include <mbgl/style/conversion.hpp> -#include <mbgl/util/feature.hpp> -#include <mbgl/util/optional.hpp> NS_ASSUME_NONNULL_BEGIN @@ -11,128 +6,147 @@ namespace mbgl { namespace style { namespace conversion { -/** - A minimal wrapper class conforming to the requirements for `objectMember(v, name)` (see mbgl/style/conversion.hpp) - This is necessary because using `NSObject*` as the value type in `optional<NSObject*>` causes problems for the ARC, - due to things like `optional(const value_type& __v)` - */ -class OptionalNSObjectValue { +// A wrapper class for `id`, so as not to confuse ARC. +class Holder { public: - OptionalNSObjectValue(NSObject * _Nullable _value) : value(_value) {} - - explicit operator bool() const { - return value; + Holder(const id v) : value(v) {} + const id value; +}; + +template <> +class ConversionTraits<Holder> { +public: + static bool isUndefined(const Holder& holder) { + const id value = holder.value; + return !value || value == [NSNull null]; } - - NSObject * _Nullable operator*() { - NSCAssert(this, @"Expected non-null value."); - return value; + + static bool isArray(const Holder& holder) { + const id value = holder.value; + return [value isKindOfClass:[NSArray class]]; } -private: - NSObject * _Nullable value; -}; -inline bool isUndefined(const id value) { - return !value || value == [NSNull null]; -} + static bool isObject(const Holder& holder) { + const id value = holder.value; + return [value isKindOfClass:[NSDictionary class]]; + } -inline bool isArray(const id value) { - return [value isKindOfClass:[NSArray class]]; -} + static std::size_t arrayLength(const Holder& holder) { + const id value = holder.value; + NSCAssert([value isKindOfClass:[NSArray class]], @"Value must be an NSArray for getLength()."); + NSArray *array = value; + auto length = [array count]; + NSCAssert(length <= std::numeric_limits<size_t>::max(), @"Array length out of bounds."); + return length; + } -inline bool isObject(const id value) { - return [value isKindOfClass:[NSDictionary class]]; -} + static Holder arrayMember(const Holder& holder, std::size_t i) { + const id value = holder.value; + NSCAssert([value isKindOfClass:[NSArray class]], @"Value must be an NSArray for get(int)."); + NSCAssert(i < NSUIntegerMax, @"Index must be less than NSUIntegerMax"); + return {[value objectAtIndex: i]}; + } -inline std::size_t arrayLength(const id value) { - NSCAssert([value isKindOfClass:[NSArray class]], @"Value must be an NSArray for getLength()."); - NSArray *array = value; - auto length = [array count]; - NSCAssert(length <= std::numeric_limits<size_t>::max(), @"Array length out of bounds."); - return length; -} + static optional<Holder> objectMember(const Holder& holder, const char *key) { + const id value = holder.value; + NSCAssert([value isKindOfClass:[NSDictionary class]], @"Value must be an NSDictionary for get(string)."); + NSObject *member = [value objectForKey: @(key)]; + if (member && member != [NSNull null]) { + return {member}; + } else { + return {}; + } + } -inline NSObject *arrayMember(const id value, std::size_t i) { - NSCAssert([value isKindOfClass:[NSArray class]], @"Value must be an NSArray for get(int)."); - NSCAssert(i < NSUIntegerMax, @"Index must be less than NSUIntegerMax"); - return [value objectAtIndex: i]; -} +// Compiler is wrong about `Fn` parameter missing a nullability specifier. +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wnullability-completeness" + template <class Fn> + static optional<Error> eachMember(const Holder&, Fn&&) { +#pragma clang diagnostic pop + // Not implemented (unneeded for MGLStyleFunction conversion). + NSCAssert(NO, @"eachMember not implemented"); + return {}; + } -inline OptionalNSObjectValue objectMember(const id value, const char *key) { - NSCAssert([value isKindOfClass:[NSDictionary class]], @"Value must be an NSDictionary for get(string)."); - NSObject *member = [value objectForKey: @(key)]; - if (member && member != [NSNull null]) { - return { member }; - } else { - return { nullptr }; + static optional<bool> toBool(const Holder& holder) { + const id value = holder.value; + if (_isBool(value)) { + return ((NSNumber *)value).boolValue; + } else { + return {}; + } } -} -// Not implemented (unneeded for MGLStyleFunction conversion): -// optional<Error> eachMember(const NSObject*, Fn&&) + static optional<float> toNumber(const Holder& holder) { + const id value = holder.value; + if (_isNumber(value)) { + return ((NSNumber *)value).floatValue; + } else { + return {}; + } + } -inline bool _isBool(const id value) { - if (![value isKindOfClass:[NSNumber class]]) return false; - // char: 32-bit boolean - // BOOL: 64-bit boolean - NSNumber *number = value; - return ((strcmp([number objCType], @encode(char)) == 0) || - (strcmp([number objCType], @encode(BOOL)) == 0)); -} - -inline bool _isNumber(const id value) { - return [value isKindOfClass:[NSNumber class]] && !_isBool(value); -} - -inline bool _isString(const id value) { - return [value isKindOfClass:[NSString class]]; -} + static optional<double> toDouble(const Holder& holder) { + const id value = holder.value; + if (_isNumber(value)) { + return ((NSNumber *)value).doubleValue; + } else { + return {}; + } + } -inline optional<bool> toBool(const id value) { - if (_isBool(value)) { - return ((NSNumber *)value).boolValue; - } else { - return {}; + static optional<std::string> toString(const Holder& holder) { + const id value = holder.value; + if (_isString(value)) { + return std::string(static_cast<const char *>([value UTF8String])); + } else { + return {}; + } } -} -inline optional<float> toNumber(const id value) { - if (_isNumber(value)) { - return ((NSNumber *)value).floatValue; - } else { - return {}; + static optional<mbgl::Value> toValue(const Holder& holder) { + const id value = holder.value; + if (isUndefined(value)) { + return {}; + } else if (_isBool(value)) { + return { *toBool(holder) }; + } else if ( _isString(value)) { + return { *toString(holder) }; + } else if (_isNumber(value)) { + // Need to cast to a double here as the float is otherwise considered a bool... + return { static_cast<double>(*toNumber(holder)) }; + } else { + return {}; + } } -} -inline optional<double> toDouble(const id value) { - if (_isNumber(value)) { - return ((NSNumber *)value).doubleValue; - } else { + static optional<GeoJSON> toGeoJSON(const Holder& holder, Error& error) { + error = { "toGeoJSON not implemented" }; return {}; } -} -inline optional<std::string> toString(const id value) { - if (_isString(value)) { - return std::string(static_cast<const char *>([value UTF8String])); - } else { - return {}; +private: + static bool _isBool(const id value) { + if (![value isKindOfClass:[NSNumber class]]) return false; + // char: 32-bit boolean + // BOOL: 64-bit boolean + NSNumber *number = value; + return ((strcmp([number objCType], @encode(char)) == 0) || + (strcmp([number objCType], @encode(BOOL)) == 0)); } -} -inline optional<mbgl::Value> toValue(const id value) { - if (isUndefined(value)) { - return {}; - } else if (_isBool(value)) { - return { *toBool(value) }; - } else if ( _isString(value)) { - return { *toString(value) }; - } else if (_isNumber(value)) { - // Need to cast to a double here as the float is otherwise considered a bool... - return { static_cast<double>(*toNumber(value)) }; - } else { - return {}; + static bool _isNumber(const id value) { + return [value isKindOfClass:[NSNumber class]] && !_isBool(value); } + + static bool _isString(const id value) { + return [value isKindOfClass:[NSString class]]; + } +}; + +inline Convertible makeConvertible(const id value) { + return Convertible(Holder(value)); } } // namespace conversion @@ -140,4 +154,3 @@ inline optional<mbgl::Value> toValue(const id value) { } // namespace mbgl NS_ASSUME_NONNULL_END - diff --git a/platform/darwin/src/MGLFeature.mm b/platform/darwin/src/MGLFeature.mm index 84f1a1ff25..033052bda8 100644 --- a/platform/darwin/src/MGLFeature.mm +++ b/platform/darwin/src/MGLFeature.mm @@ -7,11 +7,11 @@ #import "MGLShape_Private.h" #import "MGLPointCollection_Private.h" -#import "MGLPolyline+MGLAdditions.h" -#import "MGLPolygon+MGLAdditions.h" +#import "MGLPolyline_Private.h" +#import "MGLPolygon_Private.h" + #import "NSDictionary+MGLAdditions.h" #import "NSArray+MGLAdditions.h" - #import "NSExpression+MGLAdditions.h" #import <mbgl/util/geometry.hpp> diff --git a/platform/darwin/src/MGLMapSnapshotter.mm b/platform/darwin/src/MGLMapSnapshotter.mm index 15a8f6c8ca..967706ac2e 100644 --- a/platform/darwin/src/MGLMapSnapshotter.mm +++ b/platform/darwin/src/MGLMapSnapshotter.mm @@ -332,6 +332,7 @@ const CGFloat MGLSnapshotterMinimumPixelSize = 64; #else image = [[NSImage alloc] initWithCGImage:cgimg size:[backgroundImage extent].size]; #endif + CGImageRelease(cgimg); return image; } diff --git a/platform/darwin/src/MGLNetworkConfiguration.m b/platform/darwin/src/MGLNetworkConfiguration.m index 82d333dc99..4cfa405a1a 100644 --- a/platform/darwin/src/MGLNetworkConfiguration.m +++ b/platform/darwin/src/MGLNetworkConfiguration.m @@ -13,7 +13,7 @@ + (instancetype)sharedManager { static dispatch_once_t onceToken; static MGLNetworkConfiguration *_sharedManager; - void (^setupBlock)() = ^{ + void (^setupBlock)(void) = ^{ dispatch_once(&onceToken, ^{ _sharedManager = [[self alloc] init]; }); diff --git a/platform/darwin/src/MGLPolygon+MGLAdditions.h b/platform/darwin/src/MGLPolygon+MGLAdditions.h deleted file mode 100644 index f409fb96ca..0000000000 --- a/platform/darwin/src/MGLPolygon+MGLAdditions.h +++ /dev/null @@ -1,7 +0,0 @@ -#import <Mapbox/Mapbox.h> - -@interface MGLPolygon (MGLAdditions) - -- (NS_ARRAY_OF(id) *)mgl_coordinates; - -@end diff --git a/platform/darwin/src/MGLPolygon+MGLAdditions.m b/platform/darwin/src/MGLPolygon+MGLAdditions.m deleted file mode 100644 index 3e76a37157..0000000000 --- a/platform/darwin/src/MGLPolygon+MGLAdditions.m +++ /dev/null @@ -1,27 +0,0 @@ -#import "MGLPolygon+MGLAdditions.h" - -@implementation MGLPolygon (MGLAdditions) - -- (NS_ARRAY_OF(id) *)mgl_coordinates { - NSMutableArray *coordinates = [NSMutableArray array]; - - NSMutableArray *exteriorRing = [NSMutableArray array]; - for (NSUInteger index = 0; index < self.pointCount; index++) { - CLLocationCoordinate2D coordinate = self.coordinates[index]; - [exteriorRing addObject:@[@(coordinate.longitude), @(coordinate.latitude)]]; - } - [coordinates addObject:exteriorRing]; - - for (MGLPolygon *interiorPolygon in self.interiorPolygons) { - NSMutableArray *interiorRing = [NSMutableArray array]; - for (int index = 0; index < interiorPolygon.pointCount; index++) { - CLLocationCoordinate2D coordinate = interiorPolygon.coordinates[index]; - [interiorRing addObject:@[@(coordinate.longitude), @(coordinate.latitude)]]; - } - [coordinates addObject:interiorRing]; - } - - return [coordinates copy]; -} - -@end diff --git a/platform/darwin/src/MGLPolygon.mm b/platform/darwin/src/MGLPolygon.mm index e7843224e9..2af768d514 100644 --- a/platform/darwin/src/MGLPolygon.mm +++ b/platform/darwin/src/MGLPolygon.mm @@ -1,9 +1,9 @@ -#import "MGLPolygon.h" +#import "MGLPolygon_Private.h" #import "MGLMultiPoint_Private.h" #import "MGLGeometry_Private.h" -#import "MGLPolygon+MGLAdditions.h" +#import "MGLFeature.h" #import <mbgl/util/geojson.hpp> #import <mapbox/polylabel.hpp> @@ -102,6 +102,28 @@ @"coordinates": self.mgl_coordinates}; } +- (NS_ARRAY_OF(id) *)mgl_coordinates { + NSMutableArray *coordinates = [NSMutableArray array]; + + NSMutableArray *exteriorRing = [NSMutableArray array]; + for (NSUInteger index = 0; index < self.pointCount; index++) { + CLLocationCoordinate2D coordinate = self.coordinates[index]; + [exteriorRing addObject:@[@(coordinate.longitude), @(coordinate.latitude)]]; + } + [coordinates addObject:exteriorRing]; + + for (MGLPolygon *interiorPolygon in self.interiorPolygons) { + NSMutableArray *interiorRing = [NSMutableArray array]; + for (int index = 0; index < interiorPolygon.pointCount; index++) { + CLLocationCoordinate2D coordinate = interiorPolygon.coordinates[index]; + [interiorRing addObject:@[@(coordinate.longitude), @(coordinate.latitude)]]; + } + [coordinates addObject:interiorRing]; + } + + return [coordinates copy]; +} + @end @interface MGLMultiPolygon () diff --git a/platform/darwin/src/MGLPolygon_Private.h b/platform/darwin/src/MGLPolygon_Private.h new file mode 100644 index 0000000000..75afcd61f6 --- /dev/null +++ b/platform/darwin/src/MGLPolygon_Private.h @@ -0,0 +1,11 @@ +#import "MGLPolygon.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface MGLPolygon (Private) + +- (NS_ARRAY_OF(id) *)mgl_coordinates; + +@end + +NS_ASSUME_NONNULL_END diff --git a/platform/darwin/src/MGLPolyline+MGLAdditions.h b/platform/darwin/src/MGLPolyline+MGLAdditions.h deleted file mode 100644 index 4cdbbf17f9..0000000000 --- a/platform/darwin/src/MGLPolyline+MGLAdditions.h +++ /dev/null @@ -1,7 +0,0 @@ -#import <Mapbox/Mapbox.h> - -@interface MGLPolyline (MGLAdditions) - -- (NS_ARRAY_OF(id) *)mgl_coordinates; - -@end diff --git a/platform/darwin/src/MGLPolyline+MGLAdditions.m b/platform/darwin/src/MGLPolyline+MGLAdditions.m deleted file mode 100644 index d1db2c58a0..0000000000 --- a/platform/darwin/src/MGLPolyline+MGLAdditions.m +++ /dev/null @@ -1,14 +0,0 @@ -#import "MGLPolyline+MGLAdditions.h" - -@implementation MGLPolyline (MGLAdditions) - -- (NS_ARRAY_OF(id) *)mgl_coordinates { - NSMutableArray *coordinates = [[NSMutableArray alloc] initWithCapacity:self.pointCount]; - for (NSUInteger index = 0; index < self.pointCount; index++) { - CLLocationCoordinate2D coordinate = self.coordinates[index]; - [coordinates addObject:@[@(coordinate.longitude), @(coordinate.latitude)]]; - } - return [coordinates copy]; -} - -@end diff --git a/platform/darwin/src/MGLPolyline.mm b/platform/darwin/src/MGLPolyline.mm index 0e371a4dda..e011d09215 100644 --- a/platform/darwin/src/MGLPolyline.mm +++ b/platform/darwin/src/MGLPolyline.mm @@ -1,9 +1,9 @@ -#import "MGLPolyline.h" +#import "MGLPolyline_Private.h" #import "MGLMultiPoint_Private.h" #import "MGLGeometry_Private.h" -#import "MGLPolyline+MGLAdditions.h" +#import "MGLFeature.h" #import <mbgl/util/geojson.hpp> #import <mapbox/polylabel.hpp> @@ -49,6 +49,15 @@ @"coordinates": self.mgl_coordinates}; } +- (NS_ARRAY_OF(id) *)mgl_coordinates { + NSMutableArray *coordinates = [[NSMutableArray alloc] initWithCapacity:self.pointCount]; + for (NSUInteger index = 0; index < self.pointCount; index++) { + CLLocationCoordinate2D coordinate = self.coordinates[index]; + [coordinates addObject:@[@(coordinate.longitude), @(coordinate.latitude)]]; + } + return [coordinates copy]; +} + - (BOOL)isEqual:(id)other { return self == other || ([other isKindOfClass:[MGLPolyline class]] && [super isEqual:other]); } diff --git a/platform/darwin/src/MGLPolyline_Private.h b/platform/darwin/src/MGLPolyline_Private.h new file mode 100644 index 0000000000..405a0c5bc9 --- /dev/null +++ b/platform/darwin/src/MGLPolyline_Private.h @@ -0,0 +1,12 @@ +#import "MGLPolyline.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface MGLPolyline (Private) + +- (NS_ARRAY_OF(id) *)mgl_coordinates; + +@end + +NS_ASSUME_NONNULL_END + diff --git a/platform/darwin/src/MGLRendererConfiguration.h b/platform/darwin/src/MGLRendererConfiguration.h index fbc6fc564d..31aad0a742 100644 --- a/platform/darwin/src/MGLRendererConfiguration.h +++ b/platform/darwin/src/MGLRendererConfiguration.h @@ -1,6 +1,6 @@ #import <Foundation/Foundation.h> #import <mbgl/storage/default_file_source.hpp> -#import <mbgl/map/mode.hpp> +#import <mbgl/renderer/mode.hpp> NS_ASSUME_NONNULL_BEGIN diff --git a/platform/darwin/src/MGLShapeSource.h b/platform/darwin/src/MGLShapeSource.h index 7460c83f50..ca150edac1 100644 --- a/platform/darwin/src/MGLShapeSource.h +++ b/platform/darwin/src/MGLShapeSource.h @@ -1,4 +1,4 @@ -#import "MGLSource.h" +#import "MGLAbstractShapeSource.h" #import "MGLFoundation.h" #import "MGLTypes.h" @@ -14,72 +14,6 @@ NS_ASSUME_NONNULL_BEGIN typedef NSString *MGLShapeSourceOption NS_STRING_ENUM; /** - An `NSNumber` object containing a Boolean enabling or disabling clustering. - If the `shape` property contains point shapes, setting this option to - `YES` clusters the points by radius into groups. The default value is `NO`. - - This attribute corresponds to the - <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources-geojson-cluster"><code>cluster</code></a> - source property in the Mapbox Style Specification. - - This option only affects point features within a shape source. - */ -extern MGL_EXPORT const MGLShapeSourceOption MGLShapeSourceOptionClustered; - -/** - An `NSNumber` object containing an integer; specifies the radius of each - cluster if clustering is enabled. A value of 512 produces a radius equal to - the width of a tile. The default value is 50. - */ -extern MGL_EXPORT const MGLShapeSourceOption MGLShapeSourceOptionClusterRadius; - -/** - An `NSNumber` object containing an integer; specifies the maximum zoom level at - which to cluster points if clustering is enabled. Defaults to one zoom level - less than the value of `MGLShapeSourceOptionMaximumZoomLevel` so that, at the - maximum zoom level, the shapes are not clustered. - - This attribute corresponds to the - <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources-geojson-clusterMaxZoom"><code>clusterMaxZoom</code></a> - source property in the Mapbox Style Specification. - */ -extern MGL_EXPORT const MGLShapeSourceOption MGLShapeSourceOptionMaximumZoomLevelForClustering; - -/** - An `NSNumber` object containing an integer; specifies the maximum zoom level at - which to create vector tiles. A greater value produces greater detail at high - zoom levels. The default value is 18. - - This attribute corresponds to the - <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources-geojson-maxzoom"><code>maxzoom</code></a> - source property in the Mapbox Style Specification. - */ -extern MGL_EXPORT const MGLShapeSourceOption MGLShapeSourceOptionMaximumZoomLevel; - -/** - An `NSNumber` object containing an integer; specifies the size of the tile - buffer on each side. A value of 0 produces no buffer. A value of 512 produces a - buffer as wide as the tile itself. Larger values produce fewer rendering - artifacts near tile edges and slower performance. The default value is 128. - - This attribute corresponds to the - <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources-geojson-buffer"><code>buffer</code></a> - source property in the Mapbox Style Specification. - */ -extern MGL_EXPORT const MGLShapeSourceOption MGLShapeSourceOptionBuffer; - -/** - An `NSNumber` object containing a double; specifies the Douglas-Peucker - simplification tolerance. A greater value produces simpler geometries and - improves performance. The default value is 0.375. - - This attribute corresponds to the - <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources-geojson-tolerance"><code>tolerance</code></a> - source property in the Mapbox Style Specification. - */ -extern MGL_EXPORT const MGLShapeSourceOption MGLShapeSourceOptionSimplificationTolerance; - -/** `MGLShapeSource` is a map content source that supplies vector shapes to be shown on the map. The shapes may be instances of `MGLShape` or `MGLFeature`, or they may be defined by local or external @@ -112,7 +46,7 @@ extern MGL_EXPORT const MGLShapeSourceOption MGLShapeSourceOptionSimplificationT ``` */ MGL_EXPORT -@interface MGLShapeSource : MGLSource +@interface MGLShapeSource : MGLAbstractShapeSource #pragma mark Initializing a Source diff --git a/platform/darwin/src/MGLShapeSource.mm b/platform/darwin/src/MGLShapeSource.mm index 571cbdcc62..8fbb9a18ef 100644 --- a/platform/darwin/src/MGLShapeSource.mm +++ b/platform/darwin/src/MGLShapeSource.mm @@ -1,4 +1,5 @@ #import "MGLShapeSource_Private.h" +#import "MGLAbstractShapeSource_Private.h" #import "MGLStyle_Private.h" #import "MGLMapView_Private.h" @@ -13,12 +14,7 @@ #include <mbgl/style/sources/geojson_source.hpp> #include <mbgl/renderer/renderer.hpp> -const MGLShapeSourceOption MGLShapeSourceOptionClustered = @"MGLShapeSourceOptionClustered"; -const MGLShapeSourceOption MGLShapeSourceOptionClusterRadius = @"MGLShapeSourceOptionClusterRadius"; -const MGLShapeSourceOption MGLShapeSourceOptionMaximumZoomLevelForClustering = @"MGLShapeSourceOptionMaximumZoomLevelForClustering"; -const MGLShapeSourceOption MGLShapeSourceOptionMaximumZoomLevel = @"MGLShapeSourceOptionMaximumZoomLevel"; -const MGLShapeSourceOption MGLShapeSourceOptionBuffer = @"MGLShapeSourceOptionBuffer"; -const MGLShapeSourceOption MGLShapeSourceOptionSimplificationTolerance = @"MGLShapeSourceOptionSimplificationTolerance"; + @interface MGLShapeSource () @@ -105,57 +101,3 @@ const MGLShapeSourceOption MGLShapeSourceOptionSimplificationTolerance = @"MGLSh } @end - -mbgl::style::GeoJSONOptions MGLGeoJSONOptionsFromDictionary(NS_DICTIONARY_OF(MGLShapeSourceOption, id) *options) { - auto geoJSONOptions = mbgl::style::GeoJSONOptions(); - - if (NSNumber *value = options[MGLShapeSourceOptionMaximumZoomLevel]) { - if (![value isKindOfClass:[NSNumber class]]) { - [NSException raise:NSInvalidArgumentException - format:@"MGLShapeSourceOptionMaximumZoomLevel must be an NSNumber."]; - } - geoJSONOptions.maxzoom = value.integerValue; - } - - if (NSNumber *value = options[MGLShapeSourceOptionBuffer]) { - if (![value isKindOfClass:[NSNumber class]]) { - [NSException raise:NSInvalidArgumentException - format:@"MGLShapeSourceOptionBuffer must be an NSNumber."]; - } - geoJSONOptions.buffer = value.integerValue; - } - - if (NSNumber *value = options[MGLShapeSourceOptionSimplificationTolerance]) { - if (![value isKindOfClass:[NSNumber class]]) { - [NSException raise:NSInvalidArgumentException - format:@"MGLShapeSourceOptionSimplificationTolerance must be an NSNumber."]; - } - geoJSONOptions.tolerance = value.doubleValue; - } - - if (NSNumber *value = options[MGLShapeSourceOptionClusterRadius]) { - if (![value isKindOfClass:[NSNumber class]]) { - [NSException raise:NSInvalidArgumentException - format:@"MGLShapeSourceOptionClusterRadius must be an NSNumber."]; - } - geoJSONOptions.clusterRadius = value.integerValue; - } - - if (NSNumber *value = options[MGLShapeSourceOptionMaximumZoomLevelForClustering]) { - if (![value isKindOfClass:[NSNumber class]]) { - [NSException raise:NSInvalidArgumentException - format:@"MGLShapeSourceOptionMaximumZoomLevelForClustering must be an NSNumber."]; - } - geoJSONOptions.clusterMaxZoom = value.integerValue; - } - - if (NSNumber *value = options[MGLShapeSourceOptionClustered]) { - if (![value isKindOfClass:[NSNumber class]]) { - [NSException raise:NSInvalidArgumentException - format:@"MGLShapeSourceOptionClustered must be an NSNumber."]; - } - geoJSONOptions.cluster = value.boolValue; - } - - return geoJSONOptions; -} diff --git a/platform/darwin/src/MGLShapeSource_Private.h b/platform/darwin/src/MGLShapeSource_Private.h index 84eb5deed4..1ea2c39b8e 100644 --- a/platform/darwin/src/MGLShapeSource_Private.h +++ b/platform/darwin/src/MGLShapeSource_Private.h @@ -12,7 +12,4 @@ namespace mbgl { @interface MGLShapeSource (Private) @end -MGL_EXPORT -mbgl::style::GeoJSONOptions MGLGeoJSONOptionsFromDictionary(NS_DICTIONARY_OF(MGLShapeSourceOption, id) *options); - NS_ASSUME_NONNULL_END diff --git a/platform/darwin/src/MGLStyle.mm b/platform/darwin/src/MGLStyle.mm index 987ae5f063..5221e838f8 100644 --- a/platform/darwin/src/MGLStyle.mm +++ b/platform/darwin/src/MGLStyle.mm @@ -17,7 +17,7 @@ #import "MGLLight_Private.h" #import "MGLTileSource_Private.h" #import "MGLVectorSource.h" -#import "MGLVectorSource+MGLAdditions.h" +#import "MGLVectorSource_Private.h" #import "MGLRasterSource.h" #import "MGLShapeSource.h" #import "MGLImageSource.h" @@ -219,7 +219,7 @@ static NSURL *MGLStyleURL_trafficNight; } - (MGLSource *)sourceFromMBGLSource:(mbgl::style::Source *)rawSource { - if (MGLSource *source = rawSource->peer.empty() ? nil : mbgl::any_cast<SourceWrapper>(rawSource->peer).source) { + if (MGLSource *source = rawSource->peer.has_value() ? mbgl::util::any_cast<SourceWrapper>(rawSource->peer).source : nil) { return source; } @@ -381,7 +381,7 @@ static NSURL *MGLStyleURL_trafficNight; { NSParameterAssert(rawLayer); - if (MGLStyleLayer *layer = rawLayer->peer.empty() ? nil : mbgl::any_cast<LayerWrapper>(rawLayer->peer).layer) { + if (MGLStyleLayer *layer = rawLayer->peer.has_value() ? mbgl::util::any_cast<LayerWrapper>(&(rawLayer->peer))->layer : nil) { return layer; } diff --git a/platform/darwin/src/MGLStyleValue_Private.h b/platform/darwin/src/MGLStyleValue_Private.h index 2155c657bd..5914e0a2aa 100644 --- a/platform/darwin/src/MGLStyleValue_Private.h +++ b/platform/darwin/src/MGLStyleValue_Private.h @@ -124,9 +124,9 @@ public: if ([value isKindOfClass:[MGLConstantStyleValue class]]) { return toMBGLConstantValue((MGLConstantStyleValue<ObjCType> *)value); } else if ([value isKindOfClass:[MGLStyleFunction class]]) { - auto rawValue = toRawStyleSpecValue((MGLStyleFunction<ObjCType> *) value); mbgl::style::conversion::Error error; - auto result = mbgl::style::conversion::convert<mbgl::style::DataDrivenPropertyValue<MBGLType>>(rawValue, error); + auto result = mbgl::style::conversion::convert<mbgl::style::DataDrivenPropertyValue<MBGLType>>( + mbgl::style::conversion::makeConvertible(toRawStyleSpecValue((MGLStyleFunction<ObjCType> *) value)), error); NSCAssert(result, @(error.message.c_str())); return *result; } else { diff --git a/platform/darwin/src/MGLVectorSource+MGLAdditions.h b/platform/darwin/src/MGLVectorSource+MGLAdditions.h deleted file mode 100644 index 43b0aba747..0000000000 --- a/platform/darwin/src/MGLVectorSource+MGLAdditions.h +++ /dev/null @@ -1,15 +0,0 @@ -#import <Mapbox/Mapbox.h> - -NS_ASSUME_NONNULL_BEGIN - -@interface MGLVectorSource (MGLAdditions) - -+ (NSString *)preferredMapboxStreetsLanguage; - -- (NS_DICTIONARY_OF(NSString *, NSString *) *)localizedKeysByKeyForPreferredLanguage:(nullable NSString *)preferredLanguage; - -@property (nonatomic, readonly, getter=isMapboxStreets) BOOL mapboxStreets; - -@end - -NS_ASSUME_NONNULL_END diff --git a/platform/darwin/src/MGLVectorSource+MGLAdditions.m b/platform/darwin/src/MGLVectorSource+MGLAdditions.m deleted file mode 100644 index a305388117..0000000000 --- a/platform/darwin/src/MGLVectorSource+MGLAdditions.m +++ /dev/null @@ -1,53 +0,0 @@ -#import "MGLVectorSource+MGLAdditions.h" - -@implementation MGLVectorSource (MGLAdditions) - -+ (NS_SET_OF(NSString *) *)mapboxStreetsLanguages { - // https://www.mapbox.com/vector-tiles/mapbox-streets-v7/#overview - static dispatch_once_t onceToken; - static NS_SET_OF(NSString *) *mapboxStreetsLanguages; - dispatch_once(&onceToken, ^{ - // https://www.mapbox.com/vector-tiles/mapbox-streets-v7/#overview - mapboxStreetsLanguages = [NSSet setWithObjects:@"ar", @"de", @"en", @"es", @"fr", @"pt", @"ru", @"zh", @"zh-Hans", nil]; - }); - return mapboxStreetsLanguages; -} - -+ (NSString *)preferredMapboxStreetsLanguage { - NSArray<NSString *> *supportedLanguages = [MGLVectorSource mapboxStreetsLanguages].allObjects; - NSArray<NSString *> *preferredLanguages = [NSBundle preferredLocalizationsFromArray:supportedLanguages - forPreferences:[NSLocale preferredLanguages]]; - NSString *mostSpecificLanguage; - for (NSString *language in preferredLanguages) { - if (language.length > mostSpecificLanguage.length) { - mostSpecificLanguage = language; - } - } - return mostSpecificLanguage ?: @"en"; -} - -- (BOOL)isMapboxStreets { - NSURL *url = self.configurationURL; - if (![url.scheme isEqualToString:@"mapbox"]) { - return NO; - } - NSArray *identifiers = [url.host componentsSeparatedByString:@","]; - return [identifiers containsObject:@"mapbox.mapbox-streets-v7"] || [identifiers containsObject:@"mapbox.mapbox-streets-v6"]; -} - -- (NS_DICTIONARY_OF(NSString *, NSString *) *)localizedKeysByKeyForPreferredLanguage:(nullable NSString *)preferredLanguage { - if (!self.mapboxStreets) { - return @{}; - } - - // Replace {name} and {name_*} with the matching localized name tag. - NSString *localizedKey = preferredLanguage ? [NSString stringWithFormat:@"name_%@", preferredLanguage] : @"name"; - NSMutableDictionary *localizedKeysByKey = [NSMutableDictionary dictionaryWithObject:localizedKey forKey:@"name"]; - for (NSString *languageCode in [MGLVectorSource mapboxStreetsLanguages]) { - NSString *key = [NSString stringWithFormat:@"name_%@", languageCode]; - localizedKeysByKey[key] = localizedKey; - } - return localizedKeysByKey; -} - -@end diff --git a/platform/darwin/src/MGLVectorSource.mm b/platform/darwin/src/MGLVectorSource.mm index b1bda56f2d..90ffe6f98b 100644 --- a/platform/darwin/src/MGLVectorSource.mm +++ b/platform/darwin/src/MGLVectorSource.mm @@ -5,6 +5,7 @@ #import "MGLTileSource_Private.h" #import "MGLStyle_Private.h" #import "MGLMapView_Private.h" + #import "NSPredicate+MGLAdditions.h" #import "NSURL+MGLAdditions.h" @@ -71,3 +72,55 @@ } @end + +@implementation MGLVectorSource (Private) + ++ (NS_SET_OF(NSString *) *)mapboxStreetsLanguages { + // https://www.mapbox.com/vector-tiles/mapbox-streets-v7/#overview + static dispatch_once_t onceToken; + static NS_SET_OF(NSString *) *mapboxStreetsLanguages; + dispatch_once(&onceToken, ^{ + // https://www.mapbox.com/vector-tiles/mapbox-streets-v7/#overview + mapboxStreetsLanguages = [NSSet setWithObjects:@"ar", @"de", @"en", @"es", @"fr", @"pt", @"ru", @"zh", @"zh-Hans", nil]; + }); + return mapboxStreetsLanguages; +} + ++ (NSString *)preferredMapboxStreetsLanguage { + NSArray<NSString *> *supportedLanguages = [MGLVectorSource mapboxStreetsLanguages].allObjects; + NSArray<NSString *> *preferredLanguages = [NSBundle preferredLocalizationsFromArray:supportedLanguages + forPreferences:[NSLocale preferredLanguages]]; + NSString *mostSpecificLanguage; + for (NSString *language in preferredLanguages) { + if (language.length > mostSpecificLanguage.length) { + mostSpecificLanguage = language; + } + } + return mostSpecificLanguage ?: @"en"; +} + +- (BOOL)isMapboxStreets { + NSURL *url = self.configurationURL; + if (![url.scheme isEqualToString:@"mapbox"]) { + return NO; + } + NSArray *identifiers = [url.host componentsSeparatedByString:@","]; + return [identifiers containsObject:@"mapbox.mapbox-streets-v7"] || [identifiers containsObject:@"mapbox.mapbox-streets-v6"]; +} + +- (NS_DICTIONARY_OF(NSString *, NSString *) *)localizedKeysByKeyForPreferredLanguage:(nullable NSString *)preferredLanguage { + if (!self.mapboxStreets) { + return @{}; + } + + // Replace {name} and {name_*} with the matching localized name tag. + NSString *localizedKey = preferredLanguage ? [NSString stringWithFormat:@"name_%@", preferredLanguage] : @"name"; + NSMutableDictionary *localizedKeysByKey = [NSMutableDictionary dictionaryWithObject:localizedKey forKey:@"name"]; + for (NSString *languageCode in [MGLVectorSource mapboxStreetsLanguages]) { + NSString *key = [NSString stringWithFormat:@"name_%@", languageCode]; + localizedKeysByKey[key] = localizedKey; + } + return localizedKeysByKey; +} + +@end diff --git a/platform/darwin/src/MGLVectorSource_Private.h b/platform/darwin/src/MGLVectorSource_Private.h index 335743173e..233809aea2 100644 --- a/platform/darwin/src/MGLVectorSource_Private.h +++ b/platform/darwin/src/MGLVectorSource_Private.h @@ -3,6 +3,13 @@ NS_ASSUME_NONNULL_BEGIN @interface MGLVectorSource (Private) + +@property (nonatomic, readonly, getter=isMapboxStreets) BOOL mapboxStreets; + ++ (NSString *)preferredMapboxStreetsLanguage; + +- (NS_DICTIONARY_OF(NSString *, NSString *) *)localizedKeysByKeyForPreferredLanguage:(nullable NSString *)preferredLanguage; + @end NS_ASSUME_NONNULL_END diff --git a/platform/darwin/src/headless_backend_cgl.cpp b/platform/darwin/src/headless_backend_cgl.cpp index 3b0c3aaf35..46a5beb870 100644 --- a/platform/darwin/src/headless_backend_cgl.cpp +++ b/platform/darwin/src/headless_backend_cgl.cpp @@ -1,5 +1,5 @@ #include <mbgl/gl/headless_backend.hpp> -#include <mbgl/gl/headless_display.hpp> +#include <mbgl/util/logging.hpp> #include <OpenGL/OpenGL.h> #include <CoreFoundation/CoreFoundation.h> @@ -9,14 +9,96 @@ namespace mbgl { -struct CGLImpl : public HeadlessBackend::Impl { - CGLImpl(CGLContextObj glContext_) : glContext(glContext_) { +// This class provides a singleton that contains information about the pixel format used for +// instantiating new headless rendering contexts. +class CGLDisplayConfig { +private: + // Key for singleton construction. + struct Key { explicit Key() = default; }; + +public: + CGLDisplayConfig(Key) { + // TODO: test if OpenGL 4.1 with GL_ARB_ES2_compatibility is supported + // If it is, use kCGLOGLPVersion_3_2_Core and enable that extension. + CGLPixelFormatAttribute attributes[] = { + kCGLPFAOpenGLProfile, static_cast<CGLPixelFormatAttribute>(kCGLOGLPVersion_Legacy), + // Not adding kCGLPFAAccelerated, as this will make headless rendering impossible when running in VMs. + kCGLPFAClosestPolicy, + kCGLPFAAccumSize, static_cast<CGLPixelFormatAttribute>(32), + kCGLPFAColorSize, static_cast<CGLPixelFormatAttribute>(24), + kCGLPFAAlphaSize, static_cast<CGLPixelFormatAttribute>(8), + kCGLPFADepthSize, static_cast<CGLPixelFormatAttribute>(16), + kCGLPFAStencilSize, static_cast<CGLPixelFormatAttribute>(8), + kCGLPFASupportsAutomaticGraphicsSwitching, + kCGLPFAAllowOfflineRenderers, // Allows using the integrated GPU + static_cast<CGLPixelFormatAttribute>(0) + }; + + GLint num; + // TODO: obtain all configurations and choose the best one. + const CGLError error = CGLChoosePixelFormat(attributes, &pixelFormat, &num); + if (error != kCGLNoError) { + throw std::runtime_error(std::string("Error choosing pixel format:") + CGLErrorString(error) + "\n"); + } + if (num <= 0) { + throw std::runtime_error("No pixel formats found."); + } + } + + ~CGLDisplayConfig() { + const CGLError error = CGLDestroyPixelFormat(pixelFormat); + if (error != kCGLNoError) { + Log::Error(Event::OpenGL, std::string("Error destroying pixel format:") + CGLErrorString(error)); + } + } + + static std::shared_ptr<const CGLDisplayConfig> create() { + static std::weak_ptr<const CGLDisplayConfig> instance; + auto shared = instance.lock(); + if (!shared) { + instance = shared = std::make_shared<CGLDisplayConfig>(Key{}); + } + return shared; + } + +public: + CGLPixelFormatObj pixelFormat = nullptr; +}; + +class CGLBackendImpl : public HeadlessBackend::Impl { +public: + CGLBackendImpl() { + CGLError error = CGLCreateContext(cglDisplay->pixelFormat, nullptr, &glContext); + if (error != kCGLNoError) { + throw std::runtime_error(std::string("Error creating GL context object:") + + CGLErrorString(error) + "\n"); + } + + error = CGLEnable(glContext, kCGLCEMPEngine); + if (error != kCGLNoError) { + throw std::runtime_error(std::string("Error enabling OpenGL multithreading:") + + CGLErrorString(error) + "\n"); + } } - ~CGLImpl() { + ~CGLBackendImpl() final { CGLDestroyContext(glContext); } + gl::ProcAddress getExtensionFunctionPointer(const char* name) final { + static CFBundleRef framework = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengl")); + if (!framework) { + throw std::runtime_error("Failed to load OpenGL framework."); + } + + CFStringRef str = + CFStringCreateWithCString(kCFAllocatorDefault, name, kCFStringEncodingASCII); + void* symbol = CFBundleGetFunctionPointerForName(framework, str); + CFRelease(str); + + return reinterpret_cast<gl::ProcAddress>(symbol); + } + void activateContext() final { CGLError error = CGLSetCurrentContext(glContext); if (error != kCGLNoError) { @@ -33,46 +115,14 @@ struct CGLImpl : public HeadlessBackend::Impl { } } +private: + const std::shared_ptr<const CGLDisplayConfig> cglDisplay = CGLDisplayConfig::create(); CGLContextObj glContext = nullptr; }; -gl::ProcAddress HeadlessBackend::initializeExtension(const char* name) { - static CFBundleRef framework = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengl")); - if (!framework) { - throw std::runtime_error("Failed to load OpenGL framework."); - } - - CFStringRef str = CFStringCreateWithCString(kCFAllocatorDefault, name, kCFStringEncodingASCII); - void* symbol = CFBundleGetFunctionPointerForName(framework, str); - CFRelease(str); - - return reinterpret_cast<gl::ProcAddress>(symbol); -} - -bool HeadlessBackend::hasDisplay() { - if (!display) { - display = HeadlessDisplay::create(); - } - return bool(display); -} - -void HeadlessBackend::createContext() { - assert(!hasContext()); - - CGLContextObj glContext = nullptr; - CGLError error = CGLCreateContext(display->attribute<CGLPixelFormatObj>(), nullptr, &glContext); - if (error != kCGLNoError) { - throw std::runtime_error(std::string("Error creating GL context object:") + - CGLErrorString(error) + "\n"); - } - - error = CGLEnable(glContext, kCGLCEMPEngine); - if (error != kCGLNoError) { - throw std::runtime_error(std::string("Error enabling OpenGL multithreading:") + - CGLErrorString(error) + "\n"); - } - - impl.reset(new CGLImpl(glContext)); +void HeadlessBackend::createImpl() { + assert(!impl); + impl = std::make_unique<CGLBackendImpl>(); } } // namespace mbgl diff --git a/platform/darwin/src/headless_backend_eagl.mm b/platform/darwin/src/headless_backend_eagl.mm index 1daaeaf54c..050fa62c78 100644 --- a/platform/darwin/src/headless_backend_eagl.mm +++ b/platform/darwin/src/headless_backend_eagl.mm @@ -6,51 +6,48 @@ namespace mbgl { -struct EAGLImpl : public HeadlessBackend::Impl { - EAGLImpl(EAGLContext* glContext_) : glContext(glContext_) { - [reinterpret_cast<EAGLContext*>(glContext) retain]; - reinterpret_cast<EAGLContext*>(glContext).multiThreaded = YES; +class EAGLBackendImpl : public HeadlessBackend::Impl { +public: + EAGLBackendImpl() { + glContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]; + if (glContext == nil) { + throw std::runtime_error("Error creating GL context object"); + } + glContext.multiThreaded = YES; } - ~EAGLImpl() { - [glContext release]; + // Required for ARC to deallocate correctly. + ~EAGLBackendImpl() final = default; + + gl::ProcAddress getExtensionFunctionPointer(const char* name) final { + static CFBundleRef framework = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengles")); + if (!framework) { + throw std::runtime_error("Failed to load OpenGL framework."); + } + + CFStringRef str = + CFStringCreateWithCString(kCFAllocatorDefault, name, kCFStringEncodingASCII); + void* symbol = CFBundleGetFunctionPointerForName(framework, str); + CFRelease(str); + + return reinterpret_cast<gl::ProcAddress>(symbol); } - void activateContext() { + void activateContext() final { [EAGLContext setCurrentContext:glContext]; } - void deactivateContext() { + void deactivateContext() final { [EAGLContext setCurrentContext:nil]; } +private: EAGLContext* glContext = nullptr; }; -gl::ProcAddress HeadlessBackend::initializeExtension(const char* name) { - static CFBundleRef framework = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengles")); - if (!framework) { - throw std::runtime_error("Failed to load OpenGL framework."); - } - - CFStringRef str = CFStringCreateWithCString(kCFAllocatorDefault, name, kCFStringEncodingASCII); - void* symbol = CFBundleGetFunctionPointerForName(framework, str); - CFRelease(str); - - return reinterpret_cast<gl::ProcAddress>(symbol); -} - -bool HeadlessBackend::hasDisplay() { - return true; -} - -void HeadlessBackend::createContext() { - EAGLContext* glContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]; - if (glContext == nil) { - throw std::runtime_error("Error creating GL context object"); - } - - impl.reset(new EAGLImpl(glContext)); +void HeadlessBackend::createImpl() { + assert(!impl); + impl = std::make_unique<EAGLBackendImpl>(); } } // namespace mbgl diff --git a/platform/darwin/src/headless_display_cgl.cpp b/platform/darwin/src/headless_display_cgl.cpp deleted file mode 100644 index 5b7a1f2bac..0000000000 --- a/platform/darwin/src/headless_display_cgl.cpp +++ /dev/null @@ -1,60 +0,0 @@ -#include <mbgl/gl/headless_display.hpp> - -#include <OpenGL/OpenGL.h> - -#include <stdexcept> -#include <string> - -namespace mbgl { - -class HeadlessDisplay::Impl { -public: - Impl(); - ~Impl(); - CGLPixelFormatObj pixelFormat = nullptr; -}; - -HeadlessDisplay::Impl::Impl() { - // TODO: test if OpenGL 4.1 with GL_ARB_ES2_compatibility is supported - // If it is, use kCGLOGLPVersion_3_2_Core and enable that extension. - CGLPixelFormatAttribute attributes[] = { - kCGLPFAOpenGLProfile, static_cast<CGLPixelFormatAttribute>(kCGLOGLPVersion_Legacy), - // Not adding kCGLPFAAccelerated, as this will make headless rendering impossible when running in VMs. - kCGLPFAClosestPolicy, - kCGLPFAAccumSize, static_cast<CGLPixelFormatAttribute>(32), - kCGLPFAColorSize, static_cast<CGLPixelFormatAttribute>(24), - kCGLPFAAlphaSize, static_cast<CGLPixelFormatAttribute>(8), - kCGLPFADepthSize, static_cast<CGLPixelFormatAttribute>(16), - kCGLPFAStencilSize, static_cast<CGLPixelFormatAttribute>(8), - kCGLPFASupportsAutomaticGraphicsSwitching, - kCGLPFAAllowOfflineRenderers, // Allows using the integrated GPU - static_cast<CGLPixelFormatAttribute>(0) - }; - - GLint num; - CGLError error = CGLChoosePixelFormat(attributes, &pixelFormat, &num); - if (error != kCGLNoError) { - throw std::runtime_error(std::string("Error choosing pixel format:") + CGLErrorString(error) + "\n"); - } - if (num <= 0) { - throw std::runtime_error("No pixel formats found."); - } -} - -HeadlessDisplay::Impl::~Impl() { - CGLDestroyPixelFormat(pixelFormat); -} - -template <> -CGLPixelFormatObj HeadlessDisplay::attribute() const { - return impl->pixelFormat; -} - -HeadlessDisplay::HeadlessDisplay() - : impl(std::make_unique<Impl>()) { -} - -HeadlessDisplay::~HeadlessDisplay() { -} - -} // namespace mbgl diff --git a/platform/darwin/src/image.mm b/platform/darwin/src/image.mm index 8c0d5fa484..3a5adcca0a 100644 --- a/platform/darwin/src/image.mm +++ b/platform/darwin/src/image.mm @@ -11,7 +11,7 @@ using CGDataProviderHandle = CFHandle<CGDataProviderRef, CGDataProviderRef, CGDa using CGColorSpaceHandle = CFHandle<CGColorSpaceRef, CGColorSpaceRef, CGColorSpaceRelease>; using CGContextHandle = CFHandle<CGContextRef, CGContextRef, CGContextRelease>; -CGImageRef CGImageFromMGLPremultipliedImage(mbgl::PremultipliedImage&& src) { +CGImageRef CGImageCreateWithMGLPremultipliedImage(mbgl::PremultipliedImage&& src) { // We're converting the PremultipliedImage's backing store to a CGDataProvider, and are taking // over ownership of the memory. CGDataProviderHandle provider(CGDataProviderCreateWithData( diff --git a/platform/darwin/test/MGLAttributionInfoTests.m b/platform/darwin/test/MGLAttributionInfoTests.m index ed4927d44b..eccc6ceece 100644 --- a/platform/darwin/test/MGLAttributionInfoTests.m +++ b/platform/darwin/test/MGLAttributionInfoTests.m @@ -51,12 +51,12 @@ XCTAssertEqualObjects([infos[3] feedbackURLAtCenterCoordinate:mapbox zoomLevel:14], [NSURL URLWithString:@"https://www.mapbox.com/feedback/?referrer=com.mapbox.sdk.ios#/77.63680/12.98108/14.00/0.0/0"]); XCTAssertEqualObjects([infos[3] feedbackURLForStyleURL:styleURL atCenterCoordinate:mapbox zoomLevel:3.14159 direction:90.9 pitch:12.5], - [NSURL URLWithString:@"https://www.mapbox.com/feedback/?referrer=com.mapbox.sdk.ios&owner=mapbox&id=satellite-streets-v99&access_token#/77.63680/12.98108/3.14/90.9/13"]); + [NSURL URLWithString:@"https://www.mapbox.com/feedback/?referrer=com.mapbox.sdk.ios&owner=mapbox&id=satellite-streets-v99&access_token&map_sdk_version=1.0.0#/77.63680/12.98108/3.14/90.9/13"]); #else XCTAssertEqualObjects([infos[3] feedbackURLAtCenterCoordinate:mapbox zoomLevel:14], [NSURL URLWithString:@"https://www.mapbox.com/feedback/?referrer=com.mapbox.MapboxGL#/77.63680/12.98108/14.00/0.0/0"]); XCTAssertEqualObjects([infos[3] feedbackURLForStyleURL:styleURL atCenterCoordinate:mapbox zoomLevel:3.14159 direction:90.9 pitch:12.5], - [NSURL URLWithString:@"https://www.mapbox.com/feedback/?referrer=com.mapbox.MapboxGL&owner=mapbox&id=satellite-streets-v99&access_token#/77.63680/12.98108/3.14/90.9/13"]); + [NSURL URLWithString:@"https://www.mapbox.com/feedback/?referrer=com.mapbox.MapboxGL&owner=mapbox&id=satellite-streets-v99&access_token&map_sdk_version=1.0.0#/77.63680/12.98108/3.14/90.9/13"]); #endif } diff --git a/platform/darwin/test/MGLComputedShapeSourceTests.m b/platform/darwin/test/MGLComputedShapeSourceTests.m new file mode 100644 index 0000000000..6eb45913d6 --- /dev/null +++ b/platform/darwin/test/MGLComputedShapeSourceTests.m @@ -0,0 +1,24 @@ +#import <XCTest/XCTest.h> + +#import <Mapbox/Mapbox.h> + + +@interface MGLComputedShapeSourceTests : XCTestCase +@end + +@implementation MGLComputedShapeSourceTests + +- (void)testInitializer { + MGLComputedShapeSource *source = [[MGLComputedShapeSource alloc] initWithIdentifier:@"id" options:@{}]; + XCTAssertNotNil(source); + XCTAssertNotNil(source.requestQueue); + XCTAssertNil(source.dataSource); +} + +- (void)testNilOptions { + MGLComputedShapeSource *source = [[MGLComputedShapeSource alloc] initWithIdentifier:@"id" options:nil]; + XCTAssertNotNil(source); +} + + +@end diff --git a/platform/darwin/test/MGLShapeSourceTests.mm b/platform/darwin/test/MGLShapeSourceTests.mm index 561af7f3d0..60500959b6 100644 --- a/platform/darwin/test/MGLShapeSourceTests.mm +++ b/platform/darwin/test/MGLShapeSourceTests.mm @@ -2,6 +2,7 @@ #import <Mapbox/Mapbox.h> #import "MGLFeature_Private.h" +#import "MGLAbstractShapeSource_Private.h" #import "MGLShapeSource_Private.h" #import "MGLSource_Private.h" |