From fd4b4701587c90271978b5f24d9a9355989182e0 Mon Sep 17 00:00:00 2001 From: Julian Rex Date: Wed, 21 Nov 2018 13:56:41 -0500 Subject: [PATCH] [ios] Adds support for MGLCollisionBehaviorPre4_0 in NSUserDefaults (#13426) --- platform/darwin/src/MGLFoundation.h | 7 -- platform/darwin/src/MGLFoundation_Private.h | 8 ++ .../darwin/src/MGLRendererConfiguration.h | 6 +- .../darwin/src/MGLRendererConfiguration.mm | 49 ++++++++-- .../test/MGLRendererConfigurationTests.mm | 96 +++++++++++++++++++ platform/ios/CHANGELOG.md | 2 + platform/ios/ios.xcodeproj/project.pbxproj | 4 + platform/macos/CHANGELOG.md | 1 + .../macos/macos.xcodeproj/project.pbxproj | 4 + 9 files changed, 163 insertions(+), 14 deletions(-) create mode 100644 platform/darwin/test/MGLRendererConfigurationTests.mm diff --git a/platform/darwin/src/MGLFoundation.h b/platform/darwin/src/MGLFoundation.h index be86bb92f9d..3400c63979f 100644 --- a/platform/darwin/src/MGLFoundation.h +++ b/platform/darwin/src/MGLFoundation.h @@ -3,10 +3,3 @@ #import #define MGL_EXPORT __attribute__((visibility ("default"))) - -/* Using a compound statement (GNU Extension, supported by clang) */ -#define MGL_OBJC_DYNAMIC_CAST(object, type) \ - ({ \ - __typeof__( object ) temp##__LINE__ = (object); \ - (type *)([temp##__LINE__ isKindOfClass:[type class]] ? temp##__LINE__ : nil); \ - }) diff --git a/platform/darwin/src/MGLFoundation_Private.h b/platform/darwin/src/MGLFoundation_Private.h index f231628756f..71737c2cf90 100644 --- a/platform/darwin/src/MGLFoundation_Private.h +++ b/platform/darwin/src/MGLFoundation_Private.h @@ -3,3 +3,11 @@ #include void MGLInitializeRunLoop(); + +/* Using a compound statement (GNU Extension, supported by clang) */ +#define MGL_OBJC_DYNAMIC_CAST(object, type) \ + ({ \ + __typeof__( object ) temp##__LINE__ = (object); \ + (type *)([temp##__LINE__ isKindOfClass:[type class]] ? temp##__LINE__ : nil); \ + }) + diff --git a/platform/darwin/src/MGLRendererConfiguration.h b/platform/darwin/src/MGLRendererConfiguration.h index d5b6527d7ed..ea13582488f 100644 --- a/platform/darwin/src/MGLRendererConfiguration.h +++ b/platform/darwin/src/MGLRendererConfiguration.h @@ -1,3 +1,4 @@ +#import "MGLFoundation.h" #import #import #import @@ -8,6 +9,7 @@ NS_ASSUME_NONNULL_BEGIN The MGLRendererConfiguration object represents configuration values for the renderer. */ +MGL_EXPORT @interface MGLRendererConfiguration : NSObject /** Returns an instance of the current renderer configuration. */ @@ -39,7 +41,9 @@ NS_ASSUME_NONNULL_BEGIN A Boolean value indicating whether symbol layers may enable per-source symbol collision detection. - Set `MGLCollisionBehaviorPre4_0` in your containing app's Info.plist. + Set `MGLCollisionBehaviorPre4_0` in your containing app's Info.plist or by using + `[[NSUserDefaults standardUserDefaults] setObject:@(YES) forKey:@"MGLCollisionBehaviorPre4_0"]`. + If both are set, the value from `NSUserDefaults` takes priority. Setting this property to `YES` in the plist results in symbol layers only running collision detection against other symbol layers that are part of the same source. diff --git a/platform/darwin/src/MGLRendererConfiguration.mm b/platform/darwin/src/MGLRendererConfiguration.mm index b31da674cfb..90778ea86d0 100644 --- a/platform/darwin/src/MGLRendererConfiguration.mm +++ b/platform/darwin/src/MGLRendererConfiguration.mm @@ -1,5 +1,6 @@ #import "MGLRendererConfiguration.h" #import "MGLOfflineStorage_Private.h" +#import "MGLFoundation_Private.h" #if TARGET_OS_IPHONE #import @@ -7,6 +8,12 @@ #import #endif +static NSString * const MGLCollisionBehaviorPre4_0Key = @"MGLCollisionBehaviorPre4_0"; + +@interface MGLRendererConfiguration () +@property (nonatomic, readwrite) BOOL perSourceCollisions; +@end + @implementation MGLRendererConfiguration @@ -14,6 +21,42 @@ + (instancetype)currentConfiguration { return [[self alloc] init]; } +- (instancetype)init { + return [self initWithPropertyDictionary:[[NSBundle mainBundle] infoDictionary]]; +} + +- (instancetype)initWithPropertyDictionary:(nonnull NSDictionary *)properties { + self = [super init]; + + if (self) { + // Set the collision behaviour. A value set in `NSUserDefaults.standardUserDefaults` + // should override anything in the application's info.plist + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + + if ([defaults objectForKey:MGLCollisionBehaviorPre4_0Key]) { + _perSourceCollisions = [defaults boolForKey:MGLCollisionBehaviorPre4_0Key]; + } + else { + id collisionBehaviourValue = properties[MGLCollisionBehaviorPre4_0Key]; + + NSNumber *collisionBehaviourNumber = MGL_OBJC_DYNAMIC_CAST(collisionBehaviourValue, NSNumber); + + if (collisionBehaviourNumber) { + _perSourceCollisions = collisionBehaviourNumber.boolValue; + } else { + // Also support NSString to correspond with the behavior of `-[NSUserDefaults boolForKey:]` + NSString *collisionBehaviourString = MGL_OBJC_DYNAMIC_CAST(collisionBehaviourValue, NSString); + + if (collisionBehaviourString) { + _perSourceCollisions = collisionBehaviourString.boolValue; + } + } + } + } + + return self; +} + - (mbgl::DefaultFileSource *)fileSource { return [MGLOfflineStorage sharedOfflineStorage].mbglFileSource; } @@ -40,10 +83,4 @@ - (const float)scaleFactor { return fontFamilyName ? std::string([fontFamilyName UTF8String]) : mbgl::optional(); } -- (BOOL)perSourceCollisions { - NSNumber *boolWrapper = [[[NSBundle mainBundle] infoDictionary] valueForKey:@"MGLCollisionBehaviorPre4_0"]; - - return boolWrapper.boolValue; -} - @end diff --git a/platform/darwin/test/MGLRendererConfigurationTests.mm b/platform/darwin/test/MGLRendererConfigurationTests.mm new file mode 100644 index 00000000000..a0c630ebb59 --- /dev/null +++ b/platform/darwin/test/MGLRendererConfigurationTests.mm @@ -0,0 +1,96 @@ +#import +#import +#import "MGLRendererConfiguration.h" + +static NSString * const MGLRendererConfigurationTests_collisionBehaviorKey = @"MGLCollisionBehaviorPre4_0"; + +@interface MGLRendererConfiguration (Tests) +- (instancetype)initWithPropertyDictionary:(nonnull NSDictionary*)bundle; +@end + + +@interface MGLRendererConfigurationTests : XCTestCase +@end + +@implementation MGLRendererConfigurationTests +- (void)setUp { + [[NSUserDefaults standardUserDefaults] removeObjectForKey:MGLRendererConfigurationTests_collisionBehaviorKey]; +} + +- (void)tearDown { + [[NSUserDefaults standardUserDefaults] removeObjectForKey:MGLRendererConfigurationTests_collisionBehaviorKey]; +} + +// Emulate what would happen with an Info.plist. +- (void)testSettingMGLCollisionBehaviorPre40WithEmptyDictionary +{ + MGLRendererConfiguration *config = [[MGLRendererConfiguration alloc] initWithPropertyDictionary:@{}]; + XCTAssertFalse(config.perSourceCollisions); +} + +- (void)testSettingMGLCollisionBehaviorPre40WithYESDictionary +{ + MGLRendererConfiguration *config = [[MGLRendererConfiguration alloc] initWithPropertyDictionary:@{MGLRendererConfigurationTests_collisionBehaviorKey:@(NO)}]; + XCTAssertFalse(config.perSourceCollisions); +} + +- (void)testSettingMGLCollisionBehaviorPre40WithNODictionary +{ + MGLRendererConfiguration *config = [[MGLRendererConfiguration alloc] initWithPropertyDictionary:@{MGLRendererConfigurationTests_collisionBehaviorKey:@(YES)}]; + XCTAssert(config.perSourceCollisions); +} + +- (void)testSettingMGLCollisionBehaviorPre40InNSUserDefaults { + { + XCTAssertNil([[NSUserDefaults standardUserDefaults] objectForKey:MGLRendererConfigurationTests_collisionBehaviorKey]); + MGLRendererConfiguration *config = [MGLRendererConfiguration currentConfiguration]; + XCTAssertFalse(config.perSourceCollisions); + } + + [[NSUserDefaults standardUserDefaults] setObject:@(NO) forKey:MGLRendererConfigurationTests_collisionBehaviorKey]; + { + XCTAssertNotNil([[NSUserDefaults standardUserDefaults] objectForKey:MGLRendererConfigurationTests_collisionBehaviorKey]); + MGLRendererConfiguration *config = [MGLRendererConfiguration currentConfiguration]; + XCTAssertFalse(config.perSourceCollisions); + } + + [[NSUserDefaults standardUserDefaults] setObject:@(YES) forKey:MGLRendererConfigurationTests_collisionBehaviorKey]; + { + XCTAssertNotNil([[NSUserDefaults standardUserDefaults] objectForKey:MGLRendererConfigurationTests_collisionBehaviorKey]); + MGLRendererConfiguration *config = [MGLRendererConfiguration currentConfiguration]; + XCTAssert(config.perSourceCollisions); + } +} + +- (void)testSettingMGLCollisionBehaviorPre40PListValueUsingString { + // Dictionary = "NO" + { + MGLRendererConfiguration *config = [[MGLRendererConfiguration alloc] initWithPropertyDictionary:@{MGLRendererConfigurationTests_collisionBehaviorKey:@"NO"}]; + XCTAssertFalse(config.perSourceCollisions); + } + + // Dictionary = "YES" + { + MGLRendererConfiguration *config = [[MGLRendererConfiguration alloc] initWithPropertyDictionary:@{MGLRendererConfigurationTests_collisionBehaviorKey:@"YES"}]; + XCTAssert(config.perSourceCollisions); + } +} + +- (void)testOverridingMGLCollisionBehaviorPre40 { + + // Dictionary = NO, NSUserDefaults = YES + { + [[NSUserDefaults standardUserDefaults] setObject:@(YES) forKey:MGLRendererConfigurationTests_collisionBehaviorKey]; + MGLRendererConfiguration *config = [[MGLRendererConfiguration alloc] initWithPropertyDictionary:@{MGLRendererConfigurationTests_collisionBehaviorKey:@(NO)}]; + XCTAssert(config.perSourceCollisions); + } + + // Dictionary = YES, NSUserDefaults = NO + { + [[NSUserDefaults standardUserDefaults] setObject:@(NO) forKey:MGLRendererConfigurationTests_collisionBehaviorKey]; + MGLRendererConfiguration *config = [[MGLRendererConfiguration alloc] initWithPropertyDictionary:@{MGLRendererConfigurationTests_collisionBehaviorKey:@(YES)}]; + XCTAssertFalse(config.perSourceCollisions); + } +} + +@end diff --git a/platform/ios/CHANGELOG.md b/platform/ios/CHANGELOG.md index 706ebdb4282..fb039e9d661 100644 --- a/platform/ios/CHANGELOG.md +++ b/platform/ios/CHANGELOG.md @@ -12,6 +12,8 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONT * Modified the behavior of the map view so that programmatic camera transitions can no longer be interrupted by user interaction when `MGLMapView.zoomEnabled`, `MGLMapView.rotateEnabled`, `MGLMapView.scrollEnabled`, and `MGLMapView.pitchEnabled` are set to false. ([#13362](https://github.com/mapbox/mapbox-gl-native/pull/13362)) * Fixed random crashes during app termination. ([#13367](https://github.com/mapbox/mapbox-gl-native/pull/13367)) * Added `-[MGLStyle removeSource:error:]` that returns a `BOOL` indicating success (and an optional `NSError` in case of failure). ([#13399](https://github.com/mapbox/mapbox-gl-native/pull/13399)) +* Added support for setting `MGLCollisionBehaviorPre4_0` in `NSUserDefaults`. ([#13426](https://github.com/mapbox/mapbox-gl-native/pull/13426)) + ## 4.6.0 - November 7, 2018 diff --git a/platform/ios/ios.xcodeproj/project.pbxproj b/platform/ios/ios.xcodeproj/project.pbxproj index e8e9f66f902..1b2334c657a 100644 --- a/platform/ios/ios.xcodeproj/project.pbxproj +++ b/platform/ios/ios.xcodeproj/project.pbxproj @@ -430,6 +430,7 @@ CA55CD41202C16AA00CE7095 /* MGLCameraChangeReason.h in Headers */ = {isa = PBXBuildFile; fileRef = CA55CD3E202C16AA00CE7095 /* MGLCameraChangeReason.h */; settings = {ATTRIBUTES = (Public, ); }; }; CA55CD42202C16AA00CE7095 /* MGLCameraChangeReason.h in Headers */ = {isa = PBXBuildFile; fileRef = CA55CD3E202C16AA00CE7095 /* MGLCameraChangeReason.h */; settings = {ATTRIBUTES = (Public, ); }; }; CA6914B520E67F50002DB0EE /* MGLAnnotationViewIntegrationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CA6914B420E67F50002DB0EE /* MGLAnnotationViewIntegrationTests.m */; }; + CA8FBC0921A47BB100D1203C /* MGLRendererConfigurationTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = CA8FBC0821A47BB100D1203C /* MGLRendererConfigurationTests.mm */; }; CAA69DA4206DCD0E007279CD /* Mapbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA4A26961CB6E795000B7809 /* Mapbox.framework */; }; CAA69DA5206DCD0E007279CD /* Mapbox.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = DA4A26961CB6E795000B7809 /* Mapbox.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; CABE5DAD2072FAB40003AF3C /* Mapbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA8847D21CBAF91600AB86E3 /* Mapbox.framework */; }; @@ -1092,6 +1093,7 @@ CA55CD3E202C16AA00CE7095 /* MGLCameraChangeReason.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLCameraChangeReason.h; sourceTree = ""; }; CA5E5042209BDC5F001A8A81 /* MGLTestUtility.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = MGLTestUtility.h; path = ../../darwin/test/MGLTestUtility.h; sourceTree = ""; }; CA6914B420E67F50002DB0EE /* MGLAnnotationViewIntegrationTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = MGLAnnotationViewIntegrationTests.m; path = "Annotation Tests/MGLAnnotationViewIntegrationTests.m"; sourceTree = ""; }; + CA8FBC0821A47BB100D1203C /* MGLRendererConfigurationTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLRendererConfigurationTests.mm; path = ../../darwin/test/MGLRendererConfigurationTests.mm; sourceTree = ""; }; CAE7AD5320F46EF5003B6782 /* integration-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "integration-Bridging-Header.h"; sourceTree = ""; }; CAE7AD5420F46EF5003B6782 /* MGLMapSnapshotterSwiftTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MGLMapSnapshotterSwiftTests.swift; sourceTree = ""; }; DA00FC8C1D5EEB0D009AABC8 /* MGLAttributionInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLAttributionInfo.h; sourceTree = ""; }; @@ -1947,6 +1949,7 @@ DA2E885E1CC0382C00F24E7B /* MGLOfflineRegionTests.m */, 55E2AD121E5B125400E8C587 /* MGLOfflineStorageTests.mm */, 35B8E08B1D6C8B5100E768D2 /* MGLPredicateTests.mm */, + CA8FBC0821A47BB100D1203C /* MGLRendererConfigurationTests.mm */, DA2E88601CC0382C00F24E7B /* MGLStyleTests.mm */, 556660D71E1D085500E2C41B /* MGLVersionNumber.m */, DA2E88551CC036F400F24E7B /* Info.plist */, @@ -2993,6 +2996,7 @@ 96036A0620059BBA00510F3D /* MGLNSOrthographyAdditionsTests.m in Sources */, 1F95931D1E6DE2E900D5B294 /* MGLNSDateAdditionsTests.mm in Sources */, DA695426215B1E76002041A4 /* MGLMapCameraTests.m in Sources */, + CA8FBC0921A47BB100D1203C /* MGLRendererConfigurationTests.mm in Sources */, DD58A4C61D822BD000E1F038 /* MGLExpressionTests.mm in Sources */, 3575798B1D502B0C000B822E /* MGLBackgroundStyleLayerTests.mm in Sources */, 9658C155204761FC00D8A674 /* MGLMapViewScaleBarTests.m in Sources */, diff --git a/platform/macos/CHANGELOG.md b/platform/macos/CHANGELOG.md index cad40033050..9ae80c4d162 100644 --- a/platform/macos/CHANGELOG.md +++ b/platform/macos/CHANGELOG.md @@ -4,6 +4,7 @@ * Fixed an issue where the `{prefix}` token in tile URL templates was evaluated incorrectly when requesting a source’s tiles. ([#13429](https://github.com/mapbox/mapbox-gl-native/pull/13429)) * Added `-[MGLStyle removeSource:error:]` that returns a `BOOL` indicating success (and an optional `NSError` in case of failure). ([#13399](https://github.com/mapbox/mapbox-gl-native/pull/13399)) +* Added support for setting `MGLCollisionBehaviorPre4_0` in `NSUserDefaults`. ([#13426](https://github.com/mapbox/mapbox-gl-native/pull/13426)) ## 0.12.0 - November 8, 2018 diff --git a/platform/macos/macos.xcodeproj/project.pbxproj b/platform/macos/macos.xcodeproj/project.pbxproj index 902edbc5f66..60ac8e68435 100644 --- a/platform/macos/macos.xcodeproj/project.pbxproj +++ b/platform/macos/macos.xcodeproj/project.pbxproj @@ -119,6 +119,7 @@ 9654C12B1FFC38E000DB6A19 /* MGLPolyline_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 9654C12A1FFC38E000DB6A19 /* MGLPolyline_Private.h */; }; 9654C12D1FFC394700DB6A19 /* MGLPolygon_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 9654C12C1FFC394700DB6A19 /* MGLPolygon_Private.h */; }; 96E027311E57C9A7004B8E66 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 96E027331E57C9A7004B8E66 /* Localizable.strings */; }; + CA8FBC0D21A4A74300D1203C /* MGLRendererConfigurationTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = CA8FBC0C21A4A74300D1203C /* MGLRendererConfigurationTests.mm */; }; CA9461A620884CCB0015EB12 /* MGLAnnotationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CA9461A520884CCB0015EB12 /* MGLAnnotationTests.m */; }; DA00FC8A1D5EEAC3009AABC8 /* MGLAttributionInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = DA00FC881D5EEAC3009AABC8 /* MGLAttributionInfo.h */; settings = {ATTRIBUTES = (Public, ); }; }; DA00FC8B1D5EEAC3009AABC8 /* MGLAttributionInfo.mm in Sources */ = {isa = PBXBuildFile; fileRef = DA00FC891D5EEAC3009AABC8 /* MGLAttributionInfo.mm */; }; @@ -443,6 +444,7 @@ 96E027391E57C9B9004B8E66 /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sv; path = sv.lproj/Localizable.strings; sourceTree = ""; }; 96E0273A1E57C9BB004B8E66 /* vi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = vi; path = vi.lproj/Localizable.strings; sourceTree = ""; }; 96E0273B1E57C9BC004B8E66 /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = "pt-BR.lproj/Localizable.strings"; sourceTree = ""; }; + CA8FBC0C21A4A74300D1203C /* MGLRendererConfigurationTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLRendererConfigurationTests.mm; path = ../../darwin/test/MGLRendererConfigurationTests.mm; sourceTree = ""; }; CA9461A520884CCB0015EB12 /* MGLAnnotationTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGLAnnotationTests.m; path = test/MGLAnnotationTests.m; sourceTree = SOURCE_ROOT; }; DA00FC881D5EEAC3009AABC8 /* MGLAttributionInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLAttributionInfo.h; sourceTree = ""; }; DA00FC891D5EEAC3009AABC8 /* MGLAttributionInfo.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLAttributionInfo.mm; sourceTree = ""; }; @@ -1167,6 +1169,7 @@ DAE6C3CA1CC34BD800DB3429 /* MGLOfflineRegionTests.m */, 55E2AD101E5B0A6900E8C587 /* MGLOfflineStorageTests.mm */, 35C5D84B1D6DD75B00E95907 /* MGLPredicateTests.mm */, + CA8FBC0C21A4A74300D1203C /* MGLRendererConfigurationTests.mm */, DAE6C3CC1CC34BD800DB3429 /* MGLStyleTests.mm */, 556660D51E1D07E400E2C41B /* MGLVersionNumber.m */, DAE6C33A1CC30DB200DB3429 /* Info.plist */, @@ -1694,6 +1697,7 @@ DD58A4C91D822C6700E1F038 /* MGLExpressionTests.mm in Sources */, 170A82C4201FB6EC00943087 /* MGLHeatmapColorTests.mm in Sources */, 4031ACFC1E9EB3C100A3EA26 /* MGLMapViewDelegateIntegrationTests.swift in Sources */, + CA8FBC0D21A4A74300D1203C /* MGLRendererConfigurationTests.mm in Sources */, 4031AD031E9FD6AA00A3EA26 /* MGLSDKTestHelpers.swift in Sources */, DA87A9A71DCACC5000810D09 /* MGLBackgroundStyleLayerTests.mm in Sources */, DAA999011E9F5EC5002E6EA6 /* MGLFillExtrusionStyleLayerTests.mm in Sources */,