From 50d067f4ad4388b39cb6081ab0dc8bf2250f71d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Minh=20Nguye=CC=82=CC=83n?= Date: Sun, 1 Mar 2020 03:36:38 -0800 Subject: [PATCH 1/2] [ios, macos] Allow specifying multiple fonts or font families for local font rendering Removed MGLIdeographicFontFamilyName validation from MGLRendererConfiguration, since mbgl::LocalGlyphRasterizer performs more robust validation. Removed C++ from MGLRendererConfiguration interface, implementation, and tests for simplicity. Pass all the specified font and font family names into mbgl so that mbgl::LocalGlyphRasterizer can form a full font cascade list. --- platform/darwin/src/MGLMapSnapshotter.mm | 3 +- .../darwin/src/MGLRendererConfiguration.h | 8 +- .../darwin/src/MGLRendererConfiguration.m | 66 ++++++ .../darwin/src/MGLRendererConfiguration.mm | 119 ----------- .../test/MGLRendererConfigurationTests.m | 162 ++++++++++++++ .../test/MGLRendererConfigurationTests.mm | 197 ------------------ platform/ios/CHANGELOG.md | 12 +- platform/ios/docs/guides/Info.plist Keys.md | 10 +- platform/ios/ios.xcodeproj/project.pbxproj | 20 +- platform/ios/src/MGLMapView.mm | 3 +- platform/macos/CHANGELOG.md | 16 +- platform/macos/docs/guides/Info.plist Keys.md | 10 +- .../macos/macos.xcodeproj/project.pbxproj | 16 +- platform/macos/src/MGLMapView.mm | 3 +- 14 files changed, 287 insertions(+), 358 deletions(-) create mode 100644 platform/darwin/src/MGLRendererConfiguration.m delete mode 100644 platform/darwin/src/MGLRendererConfiguration.mm create mode 100644 platform/darwin/test/MGLRendererConfigurationTests.m delete mode 100644 platform/darwin/test/MGLRendererConfigurationTests.mm diff --git a/platform/darwin/src/MGLMapSnapshotter.mm b/platform/darwin/src/MGLMapSnapshotter.mm index 53454f3657..4c62674225 100644 --- a/platform/darwin/src/MGLMapSnapshotter.mm +++ b/platform/darwin/src/MGLMapSnapshotter.mm @@ -725,9 +725,10 @@ - (void)configureWithOptions:(MGLMapSnapshotOptions *)options { .withAssetPath(NSBundle.mainBundle.resourceURL.path.UTF8String); // Create the snapshotter + auto localFontFamilyName = config.localFontFamilyName ? std::string(config.localFontFamilyName.UTF8String) : nullptr; _delegateHost = std::make_unique(self); _mbglMapSnapshotter = std::make_unique( - size, pixelRatio, resourceOptions, *_delegateHost, config.localFontFamilyName); + size, pixelRatio, resourceOptions, *_delegateHost, localFontFamilyName); _mbglMapSnapshotter->setStyleURL(std::string(options.styleURL.absoluteString.UTF8String)); diff --git a/platform/darwin/src/MGLRendererConfiguration.h b/platform/darwin/src/MGLRendererConfiguration.h index 0c539f86f1..f3a917c7e9 100644 --- a/platform/darwin/src/MGLRendererConfiguration.h +++ b/platform/darwin/src/MGLRendererConfiguration.h @@ -1,8 +1,6 @@ #import "MGLFoundation.h" #import -#include - NS_ASSUME_NONNULL_BEGIN /** @@ -34,7 +32,9 @@ MGL_EXPORT - A boolean value NO to disable client-side rendering of CJK glyphs — remote fonts specified in your style will be used instead. */ -@property (nonatomic, readonly) mbgl::optional localFontFamilyName; +@property (nonatomic, readonly, nullable) NSString *localFontFamilyName; + +- (nullable NSString *)localFontFamilyNameWithInfoDictionaryObject:(nullable id)infoDictionaryObject; /** A Boolean value indicating whether symbol layers may enable per-source symbol @@ -49,6 +49,8 @@ MGL_EXPORT */ @property (nonatomic, readonly) BOOL perSourceCollisions; +- (BOOL)perSourceCollisionsWithInfoDictionaryObject:(nullable id)infoDictionaryObject; + @end NS_ASSUME_NONNULL_END diff --git a/platform/darwin/src/MGLRendererConfiguration.m b/platform/darwin/src/MGLRendererConfiguration.m new file mode 100644 index 0000000000..1cc47e3224 --- /dev/null +++ b/platform/darwin/src/MGLRendererConfiguration.m @@ -0,0 +1,66 @@ +#import "MGLRendererConfiguration.h" + +#if TARGET_OS_IPHONE +#import +#else +#import +#endif + +static NSString * const MGLCollisionBehaviorPre4_0Key = @"MGLCollisionBehaviorPre4_0"; +static NSString * const MGLIdeographicFontFamilyNameKey = @"MGLIdeographicFontFamilyName"; + +@implementation MGLRendererConfiguration + ++ (instancetype)currentConfiguration { + return [[self alloc] init]; +} + +- (const float)scaleFactor { +#if TARGET_OS_IPHONE + return [UIScreen instancesRespondToSelector:@selector(nativeScale)] ? [[UIScreen mainScreen] nativeScale] : [[UIScreen mainScreen] scale]; +#else + return [NSScreen mainScreen].backingScaleFactor; +#endif +} + +- (nullable NSString *)localFontFamilyName { + id infoDictionaryObject = [NSBundle.mainBundle objectForInfoDictionaryKey:MGLIdeographicFontFamilyNameKey]; + return [self localFontFamilyNameWithInfoDictionaryObject:infoDictionaryObject]; +} + +- (nullable NSString *)localFontFamilyNameWithInfoDictionaryObject:(nullable id)infoDictionaryObject { + if ([infoDictionaryObject isKindOfClass:[NSNumber class]] && ![infoDictionaryObject boolValue]) { + // NO means don’t use local fonts. + return nil; + } else if ([infoDictionaryObject isKindOfClass:[NSString class]]) { + return infoDictionaryObject; + } else if ([infoDictionaryObject isKindOfClass:[NSArray class]]) { + // mbgl::LocalGlyphRasterizer::Impl accepts only a single string, but form a cascade list with one font on each line. + return [infoDictionaryObject componentsJoinedByString:@"\n"]; + } + +#if TARGET_OS_IPHONE + return [UIFont systemFontOfSize:0 weight:UIFontWeightRegular].familyName; +#else + return [NSFont systemFontOfSize:0 weight:NSFontWeightRegular].familyName; +#endif +} + +- (BOOL)perSourceCollisions { + id infoDictionaryObject = [NSBundle.mainBundle objectForInfoDictionaryKey:MGLCollisionBehaviorPre4_0Key]; + return [self perSourceCollisionsWithInfoDictionaryObject:infoDictionaryObject]; +} + +- (BOOL)perSourceCollisionsWithInfoDictionaryObject:(nullable id)infoDictionaryObject { + // Set the collision behaviour. A value set in `NSUserDefaults.standardUserDefaults` + // should override anything in the application's info.plist + if ([NSUserDefaults.standardUserDefaults objectForKey:MGLCollisionBehaviorPre4_0Key]) { + return [NSUserDefaults.standardUserDefaults boolForKey:MGLCollisionBehaviorPre4_0Key]; + } else if ([infoDictionaryObject isKindOfClass:[NSNumber class]] || [infoDictionaryObject isKindOfClass:[NSString class]]) { + // Also support NSString to correspond with the behavior of `-[NSUserDefaults boolForKey:]` + return [infoDictionaryObject boolValue]; + } + return NO; +} + +@end diff --git a/platform/darwin/src/MGLRendererConfiguration.mm b/platform/darwin/src/MGLRendererConfiguration.mm deleted file mode 100644 index 136dc929a6..0000000000 --- a/platform/darwin/src/MGLRendererConfiguration.mm +++ /dev/null @@ -1,119 +0,0 @@ -#import "MGLRendererConfiguration.h" -#import "MGLOfflineStorage_Private.h" -#import "MGLFoundation_Private.h" - -#if TARGET_OS_IPHONE -#import -#else -#import -#endif - -static NSString * const MGLCollisionBehaviorPre4_0Key = @"MGLCollisionBehaviorPre4_0"; -static NSString * const MGLIdeographicFontFamilyNameKey = @"MGLIdeographicFontFamilyName"; - -@interface MGLRendererConfiguration () -@property (nonatomic, readwrite) BOOL perSourceCollisions; -@end - - -@implementation MGLRendererConfiguration - -+ (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; -} - -- (const float)scaleFactor { -#if TARGET_OS_IPHONE - return [UIScreen instancesRespondToSelector:@selector(nativeScale)] ? [[UIScreen mainScreen] nativeScale] : [[UIScreen mainScreen] scale]; -#else - return [NSScreen mainScreen].backingScaleFactor; -#endif -} - -- (mbgl::optional)localFontFamilyName { - return [self _localFontFamilyNameWithPropertyDictionary:[[NSBundle mainBundle] infoDictionary]]; -} - -- (mbgl::optional)_localFontFamilyNameWithPropertyDictionary:(nonnull NSDictionary *)properties { - - std::string systemFontFamilyName; -#if TARGET_OS_IPHONE - systemFontFamilyName = std::string([[UIFont systemFontOfSize:0 weight:UIFontWeightRegular].familyName UTF8String]); -#else - systemFontFamilyName = std::string([[NSFont systemFontOfSize:0 weight:NSFontWeightRegular].familyName UTF8String]); -#endif - - id fontFamilyName = properties[MGLIdeographicFontFamilyNameKey]; - - if([fontFamilyName isKindOfClass:[NSNumber class]] && ![fontFamilyName boolValue]) - { - return mbgl::optional(); - } - else if([fontFamilyName isKindOfClass:[NSString class]]) - { - BOOL isValidFont = NO; -#if TARGET_OS_IPHONE - if([[UIFont familyNames] containsObject:fontFamilyName]){ - isValidFont = YES; - } -#else - if([[[NSFontManager sharedFontManager] availableFontFamilies] containsObject:fontFamilyName]){ - isValidFont = YES; - } -#endif - return (fontFamilyName && isValidFont) ? std::string([fontFamilyName UTF8String]) : systemFontFamilyName; - } - // Ability to specify an array of fonts for fallbacks for `localIdeographicFontFamily` - else if ([fontFamilyName isKindOfClass:[NSArray class]]){ - for(NSString *name in fontFamilyName){ -#if TARGET_OS_IPHONE - if([[UIFont familyNames] containsObject:name]){ - return std::string([name UTF8String]); - } -#else - if([[[NSFontManager sharedFontManager] availableFontFamilies] containsObject:name]){ - return std::string([name UTF8String]); - } -#endif - } - } - return systemFontFamilyName; -} - -@end diff --git a/platform/darwin/test/MGLRendererConfigurationTests.m b/platform/darwin/test/MGLRendererConfigurationTests.m new file mode 100644 index 0000000000..6cc16c56af --- /dev/null +++ b/platform/darwin/test/MGLRendererConfigurationTests.m @@ -0,0 +1,162 @@ +#import +#import +#import "MGLRendererConfiguration.h" + +static NSString * const MGLRendererConfigurationTests_collisionBehaviorKey = @"MGLCollisionBehaviorPre4_0"; + +@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)testSettingMGLCollisionBehaviorPre40 +{ + MGLRendererConfiguration *config = [[MGLRendererConfiguration alloc] init]; + XCTAssertFalse([config perSourceCollisionsWithInfoDictionaryObject:nil]); + XCTAssertFalse([config perSourceCollisionsWithInfoDictionaryObject:@(NO)]); + XCTAssertTrue([config perSourceCollisionsWithInfoDictionaryObject:@(YES)]); + XCTAssertFalse([config perSourceCollisionsWithInfoDictionaryObject:@"NO"]); + XCTAssertTrue([config perSourceCollisionsWithInfoDictionaryObject:@"YES"]); +} + +- (void)testSettingMGLCollisionBehaviorPre40InNSUserDefaults { + { + XCTAssertNil([[NSUserDefaults standardUserDefaults] objectForKey:MGLRendererConfigurationTests_collisionBehaviorKey]); + MGLRendererConfiguration *config = [MGLRendererConfiguration currentConfiguration]; + XCTAssertFalse(config.perSourceCollisions); + XCTAssertFalse([config perSourceCollisionsWithInfoDictionaryObject:nil]); + } + + [[NSUserDefaults standardUserDefaults] setObject:@(NO) forKey:MGLRendererConfigurationTests_collisionBehaviorKey]; + { + XCTAssertNotNil([[NSUserDefaults standardUserDefaults] objectForKey:MGLRendererConfigurationTests_collisionBehaviorKey]); + MGLRendererConfiguration *config = [MGLRendererConfiguration currentConfiguration]; + XCTAssertFalse(config.perSourceCollisions); + XCTAssertFalse([config perSourceCollisionsWithInfoDictionaryObject:@(NO)]); + XCTAssertFalse([config perSourceCollisionsWithInfoDictionaryObject:@(YES)]); + } + + [[NSUserDefaults standardUserDefaults] setObject:@(YES) forKey:MGLRendererConfigurationTests_collisionBehaviorKey]; + { + XCTAssertNotNil([[NSUserDefaults standardUserDefaults] objectForKey:MGLRendererConfigurationTests_collisionBehaviorKey]); + MGLRendererConfiguration *config = [MGLRendererConfiguration currentConfiguration]; + XCTAssert(config.perSourceCollisions); + XCTAssertTrue([config perSourceCollisionsWithInfoDictionaryObject:@(NO)]); + XCTAssertTrue([config perSourceCollisionsWithInfoDictionaryObject:@(YES)]); + } +} + +- (void)testOverridingMGLCollisionBehaviorPre40 { + // Dictionary = NO, NSUserDefaults = YES + { + [[NSUserDefaults standardUserDefaults] setObject:@(YES) forKey:MGLRendererConfigurationTests_collisionBehaviorKey]; + MGLRendererConfiguration *config = [[MGLRendererConfiguration alloc] init]; + XCTAssert([config perSourceCollisionsWithInfoDictionaryObject:@(NO)]); + } + // Dictionary = YES, NSUserDefaults = NO + { + [[NSUserDefaults standardUserDefaults] setObject:@(NO) forKey:MGLRendererConfigurationTests_collisionBehaviorKey]; + MGLRendererConfiguration *config = [[MGLRendererConfiguration alloc] init]; + XCTAssertFalse([config perSourceCollisionsWithInfoDictionaryObject:@(YES)]); + } +} + +- (void)testDefaultLocalFontFamilyName { + + MGLRendererConfiguration *config = [[MGLRendererConfiguration alloc] init]; + NSString *localFontFamilyName = config.localFontFamilyName; + + NSString *systemFontFamilyName; +#if TARGET_OS_IPHONE + systemFontFamilyName = [UIFont systemFontOfSize:0 weight:UIFontWeightRegular].familyName; +#else + systemFontFamilyName = [NSFont systemFontOfSize:0 weight:NSFontWeightRegular].familyName; +#endif + + XCTAssertEqualObjects(localFontFamilyName, systemFontFamilyName, @"Default local font family name should match default system font"); +} + +- (void)testSettingMGLIdeographicFontFamilyNameWithPlistValue { + + MGLRendererConfiguration *config = [[MGLRendererConfiguration alloc] init]; + + // `MGLIdeographicFontFamilyName` set to bool value `YES` + { + NSString *localFontFamilyName = [config localFontFamilyNameWithInfoDictionaryObject:@(YES)]; + + NSString *systemFontFamilyName; +#if TARGET_OS_IPHONE + systemFontFamilyName = [UIFont systemFontOfSize:0 weight:UIFontWeightRegular].familyName; +#else + systemFontFamilyName = [NSFont systemFontOfSize:0 weight:NSFontWeightRegular].familyName; +#endif + XCTAssertEqualObjects(localFontFamilyName, systemFontFamilyName, @"Local font family name should match default system font name when setting `YES`"); + } + + // `MGLIdeographicFontFamilyName` set to bool value `NO` + { + NSString *localFontFamilyName = [config localFontFamilyNameWithInfoDictionaryObject:@(NO)]; + XCTAssertNil(localFontFamilyName, @"Client rendering font should use remote font when setting `NO`"); + } + + // `MGLIdeographicFontFamilyName` set to a valid font string value + { + NSString *localFontFamilyName = [config localFontFamilyNameWithInfoDictionaryObject:@"PingFang TC"]; + XCTAssertEqualObjects(localFontFamilyName, @"PingFang TC", @"Local font family name should match a custom valid font name"); + } + + // `MGLIdeographicFontFamilyName` set to an invalid font string value + { + NSString *localFontFamilyName = [config localFontFamilyNameWithInfoDictionaryObject:@"test font"]; + + NSString *systemFontFamilyName; +#if TARGET_OS_IPHONE + systemFontFamilyName = [UIFont systemFontOfSize:0 weight:UIFontWeightRegular].familyName; +#else + systemFontFamilyName = [NSFont systemFontOfSize:0 weight:NSFontWeightRegular].familyName; +#endif + XCTAssertNotEqualObjects(localFontFamilyName, systemFontFamilyName, @"Local font family name should not be validated by MGLRenderConfiguration"); + } + + // `MGLIdeographicFontFamilyName` set to a valid font family names array value + { + NSString *localFontFamilyName = [config localFontFamilyNameWithInfoDictionaryObject:@[@"test font 1", @"PingFang TC", @"test font 2"]]; + XCTAssertEqualObjects(localFontFamilyName, @"test font 1\nPingFang TC\ntest font 2"); + } + + // `MGLIdeographicFontFamilyName` set to an invalid font family names array value + { + NSString *localFontFamilyName = [config localFontFamilyNameWithInfoDictionaryObject:@[@"test font 1", @"test font 2", @"test font 3"]]; + + NSString *systemFontFamilyName; +#if TARGET_OS_IPHONE + systemFontFamilyName = [UIFont systemFontOfSize:0 weight:UIFontWeightRegular].familyName; +#else + systemFontFamilyName = [NSFont systemFontOfSize:0 weight:NSFontWeightRegular].familyName; +#endif + XCTAssertEqualObjects(localFontFamilyName, @"test font 1\ntest font 2\ntest font 3", @"Local font family name should not be validated by MGLRendererConfiguration"); + } + + // `MGLIdeographicFontFamilyName` set to an invalid value type: NSDictionary, NSNumber, NSData, etc. + { + NSString *localFontFamilyName = [config localFontFamilyNameWithInfoDictionaryObject:[@"test font 1" dataUsingEncoding:NSUTF8StringEncoding]]; + + NSString *systemFontFamilyName; +#if TARGET_OS_IPHONE + systemFontFamilyName = [UIFont systemFontOfSize:0 weight:UIFontWeightRegular].familyName; +#else + systemFontFamilyName = [NSFont systemFontOfSize:0 weight:NSFontWeightRegular].familyName; +#endif + XCTAssertEqualObjects(localFontFamilyName, systemFontFamilyName, @"Local font family name should match default system font name when setting an invalid value type"); + } +} + +@end diff --git a/platform/darwin/test/MGLRendererConfigurationTests.mm b/platform/darwin/test/MGLRendererConfigurationTests.mm deleted file mode 100644 index 6483aa3587..0000000000 --- a/platform/darwin/test/MGLRendererConfigurationTests.mm +++ /dev/null @@ -1,197 +0,0 @@ -#import -#import -#import "MGLRendererConfiguration.h" - -static NSString * const MGLRendererConfigurationTests_collisionBehaviorKey = @"MGLCollisionBehaviorPre4_0"; - -@interface MGLRendererConfiguration (Tests) -- (instancetype)initWithPropertyDictionary:(nonnull NSDictionary*)bundle; -- (mbgl::optional)_localFontFamilyNameWithPropertyDictionary:(nonnull NSDictionary *)properties; -@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); - } -} - -- (void)testDefaultLocalFontFamilyName { - - MGLRendererConfiguration *config = [[MGLRendererConfiguration alloc] init]; - std::string localFontFamilyName = config.localFontFamilyName.value(); - - std::string systemFontFamilyName; -#if TARGET_OS_IPHONE - systemFontFamilyName = std::string([[UIFont systemFontOfSize:0 weight:UIFontWeightRegular].familyName UTF8String]); -#else - systemFontFamilyName = std::string([[NSFont systemFontOfSize:0 weight:NSFontWeightRegular].familyName UTF8String]); -#endif - - XCTAssertEqual(localFontFamilyName, systemFontFamilyName, @"Default local font family name should match default system font"); -} - -- (void)testSettingMGLIdeographicFontFamilyNameWithPlistValue { - - MGLRendererConfiguration *config = [[MGLRendererConfiguration alloc] init]; - NSDictionary *dic; - - // `MGLIdeographicFontFamilyName` set to bool value `YES` - { - dic = @{@"MGLIdeographicFontFamilyName": @(YES)}; - std::string localFontFamilyName = ([config _localFontFamilyNameWithPropertyDictionary:dic]).value(); - - std::string systemFontFamilyName; -#if TARGET_OS_IPHONE - systemFontFamilyName = std::string([[UIFont systemFontOfSize:0 weight:UIFontWeightRegular].familyName UTF8String]); -#else - systemFontFamilyName = std::string([[NSFont systemFontOfSize:0 weight:NSFontWeightRegular].familyName UTF8String]); -#endif - XCTAssertEqual(localFontFamilyName, systemFontFamilyName, @"Local font family name should match default system font name when setting `YES`"); - } - - // `MGLIdeographicFontFamilyName` set to bool value `NO` - { - dic = @{@"MGLIdeographicFontFamilyName": @(NO)}; - mbgl::optional localFontFamilyName = [config _localFontFamilyNameWithPropertyDictionary:dic]; - XCTAssertFalse(localFontFamilyName.has_value(), @"Client rendering font should use remote font when setting `NO`"); - } - - // `MGLIdeographicFontFamilyName` set to a valid font string value - { - dic = @{@"MGLIdeographicFontFamilyName": @"PingFang TC"}; - std::string localFontFamilyName = ([config _localFontFamilyNameWithPropertyDictionary:dic]).value(); - std::string targetFontFamilyName = std::string([@"PingFang TC" UTF8String]); - XCTAssertEqual(localFontFamilyName, targetFontFamilyName, @"Local font family name should match a custom valid font name"); - } - - // `MGLIdeographicFontFamilyName` set to an invalid font string value - { - dic = @{@"MGLIdeographicFontFamilyName": @"test font"}; - std::string localFontFamilyName = ([config _localFontFamilyNameWithPropertyDictionary:dic]).value(); - - std::string systemFontFamilyName; -#if TARGET_OS_IPHONE - systemFontFamilyName = std::string([[UIFont systemFontOfSize:0 weight:UIFontWeightRegular].familyName UTF8String]); -#else - systemFontFamilyName = std::string([[NSFont systemFontOfSize:0 weight:NSFontWeightRegular].familyName UTF8String]); -#endif - XCTAssertEqual(localFontFamilyName, systemFontFamilyName, @"Local font family name should match default system font name when setting an invalid font string"); - } - - // `MGLIdeographicFontFamilyName` set to a valid font family names array value - { - dic = @{@"MGLIdeographicFontFamilyName": @[@"test font 1", @"PingFang TC", @"test font 2"]}; - std::string localFontFamilyName = ([config _localFontFamilyNameWithPropertyDictionary:dic]).value(); - std::string targetFontFamilyName = std::string([@"PingFang TC" UTF8String]); - XCTAssertEqual(localFontFamilyName, targetFontFamilyName, @"Local font family name should match a custom valid font name in a font family names array"); - } - - // `MGLIdeographicFontFamilyName` set to an invalid font family names array value - { - dic = @{@"MGLIdeographicFontFamilyName": @[@"test font 1", @"test font 2", @"test font 3"]}; - std::string localFontFamilyName = ([config _localFontFamilyNameWithPropertyDictionary:dic]).value(); - - std::string systemFontFamilyName; -#if TARGET_OS_IPHONE - systemFontFamilyName = std::string([[UIFont systemFontOfSize:0 weight:UIFontWeightRegular].familyName UTF8String]); -#else - systemFontFamilyName = std::string([[NSFont systemFontOfSize:0 weight:NSFontWeightRegular].familyName UTF8String]); -#endif - XCTAssertEqual(localFontFamilyName, systemFontFamilyName, @"Local font family name should match default system font name when setting an invalid font family names array"); - } - - // `MGLIdeographicFontFamilyName` set to an invalid value type: NSDictionary, NSNumber, NSData, etc. - { - dic = @{@"MGLIdeographicFontFamilyName": [@"test font 1" dataUsingEncoding:NSUTF8StringEncoding]}; - std::string localFontFamilyName = ([config _localFontFamilyNameWithPropertyDictionary:dic]).value(); - - std::string systemFontFamilyName; -#if TARGET_OS_IPHONE - systemFontFamilyName = std::string([[UIFont systemFontOfSize:0 weight:UIFontWeightRegular].familyName UTF8String]); -#else - systemFontFamilyName = std::string([[NSFont systemFontOfSize:0 weight:NSFontWeightRegular].familyName UTF8String]); -#endif - XCTAssertEqual(localFontFamilyName, systemFontFamilyName, @"Local font family name should match default system font name when setting an invalid value type"); - } -} - - - -@end diff --git a/platform/ios/CHANGELOG.md b/platform/ios/CHANGELOG.md index ac9deaa6e1..4af4a943b8 100644 --- a/platform/ios/CHANGELOG.md +++ b/platform/ios/CHANGELOG.md @@ -2,12 +2,16 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONTRIBUTING.md](../../CONTRIBUTING.md) to get started. -## 5.9.0 +## master ### Styles and rendering * Added the `distance` expression function for calculating the shortest distance between the evaluated feature and a GeoJSON `Point`, `MultiPoint`, `LineString`, or `MultiLineString` geometry that you specify. Use this function in expressions in style JSON or with the `MGL_FUNCTION()` syntax in an `NSExpression` format string. ([mapbox/mapbox-gl-native#16397](https://github.com/mapbox/mapbox-gl-native/pull/16397)) * Added the `MGLCircleStyleLayer.circleSortKey` property. ([mapbox/mapbox-gl-native#15875](https://github.com/mapbox/mapbox-gl-native/pull/15875)) +* Chinese, Japanese, and Korean characters are now set in the font specified in style JSON or by the `MGLSymbolLayer.textFontNames` property. If the named font is not installed on the device or bundled with the application, the characters are set in a fallback font listed in the `MGLIdeographicFontFamilyName` key in the Info.plist file. ([#189](https://github.com/mapbox/mapbox-gl-native-ios/pull/189)) +* The `MGLIdeographicFontFamilyName` key in the Info.plist file can now specify the fallback fonts for CJK characters by their PostScript names or display names in addition to font family names. For example, you can specify `NotoSansCJKjp-Bold` or `Noto Sans CJK JP Bold`, which ensures that the characters are set in bold. You can alternatively specify these font names in the `MGLIdeographicFontFamilyName` key of `NSUserDefaults.standardUserDefaults`. ([#189](https://github.com/mapbox/mapbox-gl-native-ios/pull/189)) +* CJK characters are now laid out according to the font, so fonts with nonsquare glyphs have the correct kerning. ([#189](https://github.com/mapbox/mapbox-gl-native-ios/pull/189)) +* Fixed an issue where the baseline for CJK characters was too low compared to non-CJK characters. ([#189](https://github.com/mapbox/mapbox-gl-native-ios/pull/189)) * Fixed a crash when calling the `-[MGLStyle removeImageForName:]` method with the name of a nonexistent image. ([mapbox/mapbox-gl-native#16391](https://github.com/mapbox/mapbox-gl-native/pull/16391)) * Fixed an issue where properties such as `MGLFillStyleLayer.fillColor` and `MGLLineStyleLayer.lineColor` misinterpreted non-opaque `UIColor`s. ([#266](https://github.com/mapbox/mapbox-gl-native-ios/pull/266)) @@ -25,7 +29,6 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONT * The `IN` and `CONTAINS` predicate operators can now test whether a string is a substring of another string or whether the evaluated feature (`SELF`) lies within a given `MGLShape` or `MGLFeature`. ([#183](https://github.com/mapbox/mapbox-gl-native-ios/pull/183), [#184](https://github.com/mapbox/mapbox-gl-native-ios/pull/184]) * Added the `MGLLineStyleLayer.lineSortKey` and `MGLFillStyleLayer.fillSortKey` properties. ([#179](https://github.com/mapbox/mapbox-gl-native-ios/pull/179), [#16194](https://github.com/mapbox/mapbox-gl-native/pull/16194), [#16220](https://github.com/mapbox/mapbox-gl-native/pull/16220)) * The `MGLSymbolStyleLayer.iconTextFit` property now respects the cap insets of any [nine-part stretchable image](https://developer.apple.com/documentation/uikit/uiimage#1658362) passed into the `-[MGLStyle setImage:forName:]` method. You can define the stretchable area in Xcode’s asset catalog or by calling the `-[UIImage resizableImageWithCapInsets:]` method. ([#182](https://github.com/mapbox/mapbox-gl-native-ios/pull/182)) -* The `-[MGLStyle localizeLabelsIntoLocale:]` and `-[NSExpression mgl_expressionLocalizedIntoLocale:]` methods can now localize text into Traditional Chinese and Vietnamese. ([#173](https://github.com/mapbox/mapbox-gl-native-ios/pull/173)) * Fixed an issue where an `MGLSymbolStyleLayer.lineDashPattern` value of `{1, 0}` resulted in hairline gaps. ([#16202](https://github.com/mapbox/mapbox-gl-native/pull/16202)) * Improved the performance of loading a style that has many style images. ([#16187](https://github.com/mapbox/mapbox-gl-native/pull/16187)) @@ -36,6 +39,11 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONT * The `-[MGLMapSnapshotter cancel]` method no longer calls the completion handler passed into `-[MGLMapSnapshotter startWithCompletionHandler:]`. ([#210](https://github.com/mapbox/mapbox-gl-native-ios/pull/210)) * Fixed an issue where the `MGLMapSnapshotter.loading` property always returned `NO`, even while loading a snapshot. ([#210](https://github.com/mapbox/mapbox-gl-native-ios/pull/210)) +### Localization and internationalization + +* The `MGLIdeographicFontFamilyName` Info.plist key can now be set to the display names or PostScript names of individual fonts. ([#189](https://github.com/mapbox/mapbox-gl-native-ios/pull/189)) +* The `-[MGLStyle localizeLabelsIntoLocale:]` and `-[NSExpression mgl_expressionLocalizedIntoLocale:]` methods can now localize text into Traditional Chinese and Vietnamese. ([#173](https://github.com/mapbox/mapbox-gl-native-ios/pull/173)) + ### Networking and storage * Downloaded offline packs no longer reduce the storage space available for ambient caching of tiles and other resources. ([#15622](https://github.com/mapbox/mapbox-gl-native/pull/15622)) diff --git a/platform/ios/docs/guides/Info.plist Keys.md b/platform/ios/docs/guides/Info.plist Keys.md index 6322b42dc1..23179a51ea 100644 --- a/platform/ios/docs/guides/Info.plist Keys.md +++ b/platform/ios/docs/guides/Info.plist Keys.md @@ -22,15 +22,13 @@ If you have implemented custom opt-out of Mapbox Telemetry within the user inter ## MGLIdeographicFontFamilyName -The name of the font family to use for client-side text rendering of CJK ideographs. +This key configures client-side text rendering of Chinese hanzi, Japanese kana, and Korean hangul characters (CJK) that appear in text labels. Client-side text rendering uses less bandwidth than server-side text rendering, especially when viewing regions of the map that feature a wide variety of CJK characters. -Set `MGLIdeographicFontFamilyName` in your containing application's Info.plist to font family name(s) that will be available at run time, such as “PingFang TC” or “Marker Felt”. This plist key accepts: +By default, the map renders CJK characters using locally installed fonts as specified by the system’s font cascade list, which may vary from device to device, and ignores the `MGLSymbolStyleLayer.textFont` property for these characters. To customize the displayed font, set this key to a string containing a font family name (for example, “PingFang TC”) or an individual font’s display name (“PingFang TC Ultralight”) or PostScript name (“PingFangTC-Ultralight”). The key can name a font that is installed system-wide or bundled with the application. -- A string value of a single font family name. +In case your preferred font has glyphs for every character that may appear on the map, you can set this key to an array of font or font family names in order from most preferred to least preferred. Each character is rendered in the first font in the list that has a glyph for the character. If the entire font is exhausted, the map uses the system’s font cascade list. -- An array of font family names. Fonts will be used in the defined order, eventually falling back to default system font if none are available. - -- A boolean value `NO` to disable client-side rendering of CJK glyphs — remote fonts specified in your style will be used instead. +To disable client-side rendering of CJK characters, set this key to the Boolean value `NO`. Glyphs from the fonts specified by `MGLSymbolStyleLayer.textFont` will be downloaded and rendered instead. ## MGLCollisionBehaviorPre4_0 diff --git a/platform/ios/ios.xcodeproj/project.pbxproj b/platform/ios/ios.xcodeproj/project.pbxproj index 1594630593..88ddfc43ae 100644 --- a/platform/ios/ios.xcodeproj/project.pbxproj +++ b/platform/ios/ios.xcodeproj/project.pbxproj @@ -193,10 +193,10 @@ 35E79F211D41266300957B9E /* MGLStyleLayer_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 35E79F1F1D41266300957B9E /* MGLStyleLayer_Private.h */; }; 3E6465D62065767A00685536 /* LimeGreenStyleLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 3E6465D42065767A00685536 /* LimeGreenStyleLayer.m */; }; 3E8770612074297100B7E842 /* OpenGLES.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 554180411D2E97DE00012372 /* OpenGLES.framework */; }; - 3EA93369F61CF70AFA50465D /* MGLRendererConfiguration.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3EA931BC4F087E166D538F21 /* MGLRendererConfiguration.mm */; }; + 3EA93369F61CF70AFA50465D /* MGLRendererConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = 3EA931BC4F087E166D538F21 /* MGLRendererConfiguration.m */; }; 3EA934623AD0000B7D99C3FB /* MGLRendererConfiguration.h in Headers */ = {isa = PBXBuildFile; fileRef = 3EA9337830C7738BF7F5493C /* MGLRendererConfiguration.h */; }; 3EA9363147E77DD29FA06063 /* MGLRendererConfiguration.h in Headers */ = {isa = PBXBuildFile; fileRef = 3EA9337830C7738BF7F5493C /* MGLRendererConfiguration.h */; }; - 3EA9366247780E4F252652A8 /* MGLRendererConfiguration.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3EA931BC4F087E166D538F21 /* MGLRendererConfiguration.mm */; }; + 3EA9366247780E4F252652A8 /* MGLRendererConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = 3EA931BC4F087E166D538F21 /* MGLRendererConfiguration.m */; }; 400533011DB0862B0069F638 /* NSArray+MGLAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 400532FF1DB0862B0069F638 /* NSArray+MGLAdditions.h */; }; 400533021DB0862B0069F638 /* NSArray+MGLAdditions.mm in Sources */ = {isa = PBXBuildFile; fileRef = 400533001DB0862B0069F638 /* NSArray+MGLAdditions.mm */; }; 400533031DB086490069F638 /* NSArray+MGLAdditions.mm in Sources */ = {isa = PBXBuildFile; fileRef = 400533001DB0862B0069F638 /* NSArray+MGLAdditions.mm */; }; @@ -412,7 +412,7 @@ CA7766842229C11A0008DE9E /* SMCalloutView.m in Sources */ = {isa = PBXBuildFile; fileRef = DA88488A1CBB037E00AB86E3 /* SMCalloutView.m */; }; CA86FF0E22D8D5A0009EB14A /* MGLNetworkConfigurationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CA86FF0D22D8D5A0009EB14A /* MGLNetworkConfigurationTests.m */; }; CA88DC3021C85D900059ED5A /* MGLStyleURLIntegrationTest.m in Sources */ = {isa = PBXBuildFile; fileRef = CA88DC2F21C85D900059ED5A /* MGLStyleURLIntegrationTest.m */; }; - CA8FBC0921A47BB100D1203C /* MGLRendererConfigurationTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = CA8FBC0821A47BB100D1203C /* MGLRendererConfigurationTests.mm */; }; + CA8FBC0921A47BB100D1203C /* MGLRendererConfigurationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CA8FBC0821A47BB100D1203C /* MGLRendererConfigurationTests.m */; }; CA94E5FB237D21030037AEA0 /* Mapbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA8847D21CBAF91600AB86E3 /* Mapbox.framework */; }; CA94E5FC237D21030037AEA0 /* Mapbox.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = DA8847D21CBAF91600AB86E3 /* Mapbox.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; CA94E601237EF4110037AEA0 /* MapboxMobileEvents.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CA96299B23731199004F1330 /* MapboxMobileEvents.framework */; }; @@ -911,7 +911,7 @@ 35E79F1F1D41266300957B9E /* MGLStyleLayer_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLStyleLayer_Private.h; sourceTree = ""; }; 3E6465D42065767A00685536 /* LimeGreenStyleLayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = LimeGreenStyleLayer.m; path = ../../darwin/app/LimeGreenStyleLayer.m; sourceTree = ""; }; 3E6465D52065767A00685536 /* LimeGreenStyleLayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LimeGreenStyleLayer.h; path = ../../darwin/app/LimeGreenStyleLayer.h; sourceTree = ""; }; - 3EA931BC4F087E166D538F21 /* MGLRendererConfiguration.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLRendererConfiguration.mm; sourceTree = ""; }; + 3EA931BC4F087E166D538F21 /* MGLRendererConfiguration.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLRendererConfiguration.m; sourceTree = ""; }; 3EA9337830C7738BF7F5493C /* MGLRendererConfiguration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLRendererConfiguration.h; sourceTree = ""; }; 400532FF1DB0862B0069F638 /* NSArray+MGLAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSArray+MGLAdditions.h"; sourceTree = ""; }; 400533001DB0862B0069F638 /* NSArray+MGLAdditions.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = "NSArray+MGLAdditions.mm"; sourceTree = ""; }; @@ -1062,7 +1062,7 @@ CA6914B420E67F50002DB0EE /* MGLAnnotationViewIntegrationTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLAnnotationViewIntegrationTests.mm; path = "Annotation Tests/MGLAnnotationViewIntegrationTests.mm"; sourceTree = ""; }; CA86FF0D22D8D5A0009EB14A /* MGLNetworkConfigurationTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MGLNetworkConfigurationTests.m; sourceTree = ""; }; CA88DC2F21C85D900059ED5A /* MGLStyleURLIntegrationTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MGLStyleURLIntegrationTest.m; sourceTree = ""; }; - CA8FBC0821A47BB100D1203C /* MGLRendererConfigurationTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLRendererConfigurationTests.mm; path = ../../darwin/test/MGLRendererConfigurationTests.mm; sourceTree = ""; }; + CA8FBC0821A47BB100D1203C /* MGLRendererConfigurationTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = MGLRendererConfigurationTests.m; path = ../../darwin/test/MGLRendererConfigurationTests.m; sourceTree = ""; }; CA96299B23731199004F1330 /* MapboxMobileEvents.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = MapboxMobileEvents.framework; sourceTree = BUILT_PRODUCTS_DIR; }; CAAA65D72321BBA900F08A39 /* MGLTestAssertionHandler.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = MGLTestAssertionHandler.h; path = ../../darwin/test/MGLTestAssertionHandler.h; sourceTree = ""; }; CAAA65D82321BBA900F08A39 /* MGLTestAssertionHandler.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = MGLTestAssertionHandler.m; path = ../../darwin/test/MGLTestAssertionHandler.m; sourceTree = ""; }; @@ -1883,7 +1883,7 @@ DA2E885E1CC0382C00F24E7B /* MGLOfflineRegionTests.m */, 55E2AD121E5B125400E8C587 /* MGLOfflineStorageTests.mm */, 35B8E08B1D6C8B5100E768D2 /* MGLPredicateTests.mm */, - CA8FBC0821A47BB100D1203C /* MGLRendererConfigurationTests.mm */, + CA8FBC0821A47BB100D1203C /* MGLRendererConfigurationTests.m */, CAD9D0A922A86D6F001B25EE /* MGLResourceTests.mm */, DA2E88601CC0382C00F24E7B /* MGLStyleTests.mm */, 556660D71E1D085500E2C41B /* MGLVersionNumber.m */, @@ -1947,7 +1947,7 @@ DA35D9BF240916290013ECB0 /* MGLReachability.h */, DA35D9BE240916290013ECB0 /* MGLReachability.m */, 3EA9337830C7738BF7F5493C /* MGLRendererConfiguration.h */, - 3EA931BC4F087E166D538F21 /* MGLRendererConfiguration.mm */, + 3EA931BC4F087E166D538F21 /* MGLRendererConfiguration.m */, 92F2C3EC1F0E3C3A00268EC0 /* MGLRendererFrontend.h */, DA8847EC1CBAFA5100AB86E3 /* MGLStyle.h */, 35E0CFE51D3E501500188327 /* MGLStyle_Private.h */, @@ -3041,7 +3041,7 @@ 1F95931D1E6DE2E900D5B294 /* MGLNSDateAdditionsTests.mm in Sources */, DA695426215B1E76002041A4 /* MGLMapCameraTests.m in Sources */, 96381C0222C6F3950053497D /* MGLMapViewPitchTests.m in Sources */, - CA8FBC0921A47BB100D1203C /* MGLRendererConfigurationTests.mm in Sources */, + CA8FBC0921A47BB100D1203C /* MGLRendererConfigurationTests.m in Sources */, CAD9D0AA22A86D6F001B25EE /* MGLResourceTests.mm in Sources */, DD58A4C61D822BD000E1F038 /* MGLExpressionTests.mm in Sources */, 3575798B1D502B0C000B822E /* MGLBackgroundStyleLayerTests.mm in Sources */, @@ -3165,7 +3165,7 @@ AC518E03201BB56000EBC820 /* MGLTelemetryConfig.m in Sources */, DA8848271CBAFA6200AB86E3 /* MGLPolyline.mm in Sources */, 35CE61841D4165D9004F2359 /* UIColor+MGLAdditions.mm in Sources */, - 3EA93369F61CF70AFA50465D /* MGLRendererConfiguration.mm in Sources */, + 3EA93369F61CF70AFA50465D /* MGLRendererConfiguration.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -3265,7 +3265,7 @@ DAA4E41C1CBB730400178DFB /* MGLAccountManager.m in Sources */, 35CE61851D4165D9004F2359 /* UIColor+MGLAdditions.mm in Sources */, DAA4E4241CBB730400178DFB /* MGLPolyline.mm in Sources */, - 3EA9366247780E4F252652A8 /* MGLRendererConfiguration.mm in Sources */, + 3EA9366247780E4F252652A8 /* MGLRendererConfiguration.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/platform/ios/src/MGLMapView.mm b/platform/ios/src/MGLMapView.mm index f12354f4db..6b1977d833 100644 --- a/platform/ios/src/MGLMapView.mm +++ b/platform/ios/src/MGLMapView.mm @@ -480,7 +480,8 @@ - (void)commonInit // setup mbgl map MGLRendererConfiguration *config = [MGLRendererConfiguration currentConfiguration]; - auto renderer = std::make_unique(_mbglView->getRendererBackend(), config.scaleFactor, config.localFontFamilyName); + auto localFontFamilyName = config.localFontFamilyName ? std::string(config.localFontFamilyName.UTF8String) : nullptr; + auto renderer = std::make_unique(_mbglView->getRendererBackend(), config.scaleFactor, localFontFamilyName); BOOL enableCrossSourceCollisions = !config.perSourceCollisions; _rendererFrontend = std::make_unique(std::move(renderer), self, _mbglView->getRendererBackend()); diff --git a/platform/macos/CHANGELOG.md b/platform/macos/CHANGELOG.md index 75369dd374..519bae96ef 100644 --- a/platform/macos/CHANGELOG.md +++ b/platform/macos/CHANGELOG.md @@ -6,13 +6,18 @@ * Added the `distance` expression function for calculating the shortest distance between the evaluated feature and a GeoJSON `Point`, `MultiPoint`, `LineString`, or `MultiLineString` geometry that you specify. Use this function in expressions in style JSON or with the `MGL_FUNCTION()` syntax in an `NSExpression` format string. ([mapbox/mapbox-gl-native#16397](https://github.com/mapbox/mapbox-gl-native/pull/16397)) * Added the `MGLCircleStyleLayer.circleSortKey` property. ([mapbox/mapbox-gl-native#15875](https://github.com/mapbox/mapbox-gl-native/pull/15875)) +* Chinese, Japanese, and Korean characters are now set in the font specified in style JSON or by the `MGLSymbolLayer.textFontNames` property. If the named font is not installed on the device or bundled with the application, the characters are set in a fallback font listed in the `MGLIdeographicFontFamilyName` key in the Info.plist file. ([#189](https://github.com/mapbox/mapbox-gl-native-ios/pull/189)) +* The `MGLIdeographicFontFamilyName` key in the Info.plist file can now specify the fallback fonts for CJK characters by their PostScript names or display names in addition to font family names. For example, you can specify `NotoSansCJKjp-Bold` or `Noto Sans CJK JP Bold`, which ensures that the characters are set in bold. You can alternatively specify these font names in the `MGLIdeographicFontFamilyName` key of `NSUserDefaults.standardUserDefaults`. ([#189](https://github.com/mapbox/mapbox-gl-native-ios/pull/189)) +* CJK characters are now laid out according to the font, so fonts with nonsquare glyphs have the correct kerning. ([#189](https://github.com/mapbox/mapbox-gl-native-ios/pull/189)) +* Fixed an issue where the baseline for CJK characters was too low compared to non-CJK characters. ([#189](https://github.com/mapbox/mapbox-gl-native-ios/pull/189)) * Fixed a crash when calling the `-[MGLStyle removeImageForName:]` method with the name of a nonexistent image. ([mapbox/mapbox-gl-native#16391](https://github.com/mapbox/mapbox-gl-native/pull/16391)) -* Fixed an issue where an `MGLMapSnapshotOptions` with an invalid `MGLMapCamera.centerCoordinate`, negative `MGLMapCamera.heading`, negative `MGLMapCamera.pitch`, and negative `MGLMapSnapshotOptions.zoomLevel` resulted in a snapshot centered on Null Island at zoom level 0 even if the style specified a different initial center coordinate or zoom level. ([#280](https://github.com/mapbox/mapbox-gl-native-ios/pull/280)) +* Fixed an issue where properties such as `MGLFillStyleLayer.fillColor` and `MGLLineStyleLayer.lineColor` misinterpreted non-opaque `NSColor`s. ([#266](https://github.com/mapbox/mapbox-gl-native-ios/pull/266)) ### Other changes * Fixed various crashes, including crashes on launch, on macOS 10.11.0 through 10.14._x_. ([mapbox/mapbox-gl-native#16412](https://github.com/mapbox/mapbox-gl-native/pull/16412)) * Fixed a crash when encountering an invalid polyline. ([mapbox/mapbox-gl-native#16409](https://github.com/mapbox/mapbox-gl-native/pull/16409)) +* Fixed an issue where an `MGLMapSnapshotOptions` with an invalid `MGLMapCamera.centerCoordinate`, negative `MGLMapCamera.heading`, negative `MGLMapCamera.pitch`, and negative `MGLMapSnapshotOptions.zoomLevel` resulted in a snapshot centered on Null Island at zoom level 0 even if the style specified a different initial center coordinate or zoom level. ([#280](https://github.com/mapbox/mapbox-gl-native-ios/pull/280)) * Fixed an error that occurred if your implementation of the `-[MGLOfflineStorageDelegate offlineStorage:URLForResourceOfKind:]` method returned a local file URL. ([mapbox/mapbox-gl-native#16428](https://github.com/mapbox/mapbox-gl-native/pull/16428)) * Certain logging statements no longer run on the main thread. ([mapbox/mapbox-gl-native#16325](https://github.com/mapbox/mapbox-gl-native/pull/16325)) @@ -25,9 +30,7 @@ * The `IN` and `CONTAINS` predicate operators can now test whether a string is a substring of another string or whether the evaluated feature (`SELF`) lies within a given `MGLShape` or `MGLFeature`. ([#183](https://github.com/mapbox/mapbox-gl-native-ios/pull/183), [#184](https://github.com/mapbox/mapbox-gl-native-ios/pull/184)) * Added the `MGLSymbolStyleLayer.textWritingModes` layout property. This property can be set to `MGLTextWritingModeHorizontal` or `MGLTextWritingModeVertical`. ([#14932](https://github.com/mapbox/mapbox-gl-native/pull/14932)) * Added the `MGLLineStyleLayer.lineSortKey` and `MGLFillStyleLayer.fillSortKey` properties. ([#179](https://github.com/mapbox/mapbox-gl-native-ios/pull/179)) -* The `MGLIdeographicFontFamilyName` Info.plist key now also accepts an array of font family names, to customize font fallback behavior. It can also be set to a Boolean value of `NO` to force the SDK to typeset CJK characters in a remote font specified by `MGLSymbolStyleLayer.textFontNames`. ([#14862](https://github.com/mapbox/mapbox-gl-native/pull/14862)) * The `MGLSymbolStyleLayer.iconTextFit` property now respects the cap insets of any nine-part stretchable image passed into the `-[MGLStyle setImage:forName:]` method. You can define the stretchable area in Xcode’s asset catalog or by setting the `NSImage.capInsets` property. ([#182](https://github.com/mapbox/mapbox-gl-native-ios/pull/182)) -* The `-[MGLStyle localizeLabelsIntoLocale:]` and `-[NSExpression mgl_expressionLocalizedIntoLocale:]` methods can now localize text into Traditional Chinese and Vietnamese. ([#173](https://github.com/mapbox/mapbox-gl-native-ios/pull/173)) * Fixed crashes triggered when `MGLSource` and `MGLStyleLayer` objects are accessed after having been invalidated after a style change. ([#15539](https://github.com/mapbox/mapbox-gl-native/pull/15539)) * Fixed an issue where fill extrusion layers would be incorrectly rendered above other layers. ([#15065](https://github.com/mapbox/mapbox-gl-native/pull/15065)) * Fixed rendering and collision detection issues with using `MGLSymbolStyleLayer.textVariableAnchor` and `MGLSymbolStyleLayer.iconTextFit` properties on the same layer. ([#15367](https://github.com/mapbox/mapbox-gl-native/pull/15367)) @@ -39,7 +42,6 @@ * Fixed an issue where style layers backed by a shape source could flicker when transitioning between styles. ([#15907](https://github.com/mapbox/mapbox-gl-native/pull/15907), [#15941](https://github.com/mapbox/mapbox-gl-native/pull/15941)) * Improved the performance of loading a style that has many style images. ([#16187](https://github.com/mapbox/mapbox-gl-native/pull/16187)) * Updated “map ID” to the more accurate term “tileset ID” in documentation; updated “style's Map ID” to the more accurate term “style URL”. ([#15116](https://github.com/mapbox/mapbox-gl-native/pull/15116)) -* Fixed an issue where properties such as `MGLFillStyleLayer.fillColor` and `MGLLineStyleLayer.lineColor` misinterpreted non-opaque `NSColor`s. ([#266](https://github.com/mapbox/mapbox-gl-native-ios/pull/266)) ### Camera @@ -79,6 +81,12 @@ * When an offline pack encounters an HTTP 404 error, the `MGLOfflinePackUserInfoKeyError` user info key of the `MGLOfflinePackErrorNotification` now indicates the resource that could not be downloaded. ([#16240](https://github.com/mapbox/mapbox-gl-native/pull/16240)) * Expired resources are now fetched at a lower priority than new resources. ([#15950](https://github.com/mapbox/mapbox-gl-native/pull/15950)) +### Localization and internationalization + +* The `MGLIdeographicFontFamilyName` Info.plist key now also accepts an array of font family names, to customize font fallback behavior. It can also be set to a Boolean value of `NO` to force the SDK to typeset CJK characters in a remote font specified by `MGLSymbolStyleLayer.textFontNames`. ([#14862](https://github.com/mapbox/mapbox-gl-native/pull/14862)) +* The `MGLIdeographicFontFamilyName` Info.plist key can now be set to the display names or PostScript names of individual fonts. ([#189](https://github.com/mapbox/mapbox-gl-native-ios/pull/189)) +* The `-[MGLStyle localizeLabelsIntoLocale:]` and `-[NSExpression mgl_expressionLocalizedIntoLocale:]` methods can now localize text into Traditional Chinese and Vietnamese. ([#173](https://github.com/mapbox/mapbox-gl-native-ios/pull/173)) + ### Other changes * Fixed a memory leak when zooming with any options enabled in the `MGLMapView.debugMask` property. ([#15395](https://github.com/mapbox/mapbox-gl-native/pull/15395)) diff --git a/platform/macos/docs/guides/Info.plist Keys.md b/platform/macos/docs/guides/Info.plist Keys.md index 35ecf67e36..f373d8bea2 100644 --- a/platform/macos/docs/guides/Info.plist Keys.md +++ b/platform/macos/docs/guides/Info.plist Keys.md @@ -18,15 +18,13 @@ The default value is `https://api.mapbox.com`. ## MGLIdeographicFontFamilyName -The name of the font family to use for client-side text rendering of CJK ideographs. +This key configures client-side text rendering of Chinese hanzi, Japanese kana, and Korean hangul characters (CJK) that appear in text labels. Client-side text rendering uses less bandwidth than server-side text rendering, especially when viewing regions of the map that feature a wide variety of CJK characters. -Set `MGLIdeographicFontFamilyName` in your containing application's Info.plist to font family name(s) that will be available at run time, such as “PingFang TC” or “Marker Felt”. This plist key accepts: +By default, the map renders CJK characters using locally installed fonts as specified by the system’s font cascade list, which may vary from device to device, and ignores the `MGLSymbolStyleLayer.textFont` property for these characters. To customize the displayed font, set this key to a string containing a font family name (for example, “PingFang TC”) or an individual font’s display name (“PingFang TC Ultralight”) or PostScript name (“PingFangTC-Ultralight”). The key can name a font that is installed system-wide or bundled with the application. -- A string value of a single font family name. +In case your preferred font has glyphs for every character that may appear on the map, you can set this key to an array of font or font family names in order from most preferred to least preferred. Each character is rendered in the first font in the list that has a glyph for the character. If the entire font is exhausted, the map uses the system’s font cascade list. -- An array of font family names. Fonts will be used in the defined order, eventually falling back to default system font if none are available. - -- A boolean value `NO` to disable client-side rendering of CJK glyphs — remote fonts specified in your style will be used instead. +To disable client-side rendering of CJK characters, set this key to the Boolean value `NO`. Glyphs from the fonts specified by `MGLSymbolStyleLayer.textFont` will be downloaded and rendered instead. ## MGLCollisionBehaviorPre4_0 diff --git a/platform/macos/macos.xcodeproj/project.pbxproj b/platform/macos/macos.xcodeproj/project.pbxproj index bb532fe1c3..79d96223eb 100644 --- a/platform/macos/macos.xcodeproj/project.pbxproj +++ b/platform/macos/macos.xcodeproj/project.pbxproj @@ -74,7 +74,7 @@ 35D65C5B1D65AD5500722C23 /* NSDate+MGLAdditions.mm in Sources */ = {isa = PBXBuildFile; fileRef = 35D65C591D65AD5500722C23 /* NSDate+MGLAdditions.mm */; }; 3E6465D9206576A900685536 /* LimeGreenStyleLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 3E6465D7206576A800685536 /* LimeGreenStyleLayer.m */; }; 3EA9317388DC9A0BF46B7674 /* MGLRendererConfiguration.h in Headers */ = {isa = PBXBuildFile; fileRef = 3EA9369A4C46957566058822 /* MGLRendererConfiguration.h */; }; - 3EA93BA38DBB4B814B6C1FCC /* MGLRendererConfiguration.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3EA93B1B0864609938506E12 /* MGLRendererConfiguration.mm */; }; + 3EA93BA38DBB4B814B6C1FCC /* MGLRendererConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = 3EA93B1B0864609938506E12 /* MGLRendererConfiguration.m */; }; 4031ACFC1E9EB3C100A3EA26 /* MGLMapViewDelegateIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4031ACFB1E9EB3C100A3EA26 /* MGLMapViewDelegateIntegrationTests.swift */; }; 4031AD031E9FD6AA00A3EA26 /* MGLSDKTestHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4031AD011E9FD6A300A3EA26 /* MGLSDKTestHelpers.swift */; }; 4049C2A51DB6CE7F00B3F799 /* MGLPointCollection.h in Headers */ = {isa = PBXBuildFile; fileRef = 4049C2A11DB6CE7800B3F799 /* MGLPointCollection.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -127,7 +127,7 @@ CA0B3C072329F7E700E4B493 /* MGLTestAssertionHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = CA0B3C052329F7E600E4B493 /* MGLTestAssertionHandler.m */; }; CA0B3C092329FB4800E4B493 /* MGLOfflinePackTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = CA0B3C082329FB4800E4B493 /* MGLOfflinePackTests.mm */; }; CA4045C7216720D700B356E1 /* MGLCluster.h in Headers */ = {isa = PBXBuildFile; fileRef = CA4045C4216720D700B356E1 /* MGLCluster.h */; settings = {ATTRIBUTES = (Public, ); }; }; - CA8FBC0D21A4A74300D1203C /* MGLRendererConfigurationTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = CA8FBC0C21A4A74300D1203C /* MGLRendererConfigurationTests.mm */; }; + CA8FBC0D21A4A74300D1203C /* MGLRendererConfigurationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CA8FBC0C21A4A74300D1203C /* MGLRendererConfigurationTests.m */; }; CA9461A620884CCB0015EB12 /* MGLAnnotationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CA9461A520884CCB0015EB12 /* MGLAnnotationTests.m */; }; CAD9D0AC22A88A32001B25EE /* MGLResourceTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = CAD9D0AB22A88A32001B25EE /* MGLResourceTests.mm */; }; CF762DEF22DC7EFF00338472 /* MGLLoggingConfiguration.mm in Sources */ = {isa = PBXBuildFile; fileRef = CF762DEE22DC7EFF00338472 /* MGLLoggingConfiguration.mm */; }; @@ -406,7 +406,7 @@ 3E6465D7206576A800685536 /* LimeGreenStyleLayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = LimeGreenStyleLayer.m; path = ../../darwin/app/LimeGreenStyleLayer.m; sourceTree = ""; }; 3E6465D8206576A900685536 /* LimeGreenStyleLayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LimeGreenStyleLayer.h; path = ../../darwin/app/LimeGreenStyleLayer.h; sourceTree = ""; }; 3EA9369A4C46957566058822 /* MGLRendererConfiguration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLRendererConfiguration.h; sourceTree = ""; }; - 3EA93B1B0864609938506E12 /* MGLRendererConfiguration.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLRendererConfiguration.mm; sourceTree = ""; }; + 3EA93B1B0864609938506E12 /* MGLRendererConfiguration.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLRendererConfiguration.m; sourceTree = ""; }; 4031ACFB1E9EB3C100A3EA26 /* MGLMapViewDelegateIntegrationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MGLMapViewDelegateIntegrationTests.swift; sourceTree = ""; }; 4031AD011E9FD6A300A3EA26 /* MGLSDKTestHelpers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MGLSDKTestHelpers.swift; path = ../../darwin/test/MGLSDKTestHelpers.swift; sourceTree = ""; }; 4049C2A11DB6CE7800B3F799 /* MGLPointCollection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLPointCollection.h; sourceTree = ""; }; @@ -473,7 +473,7 @@ CA0B3C052329F7E600E4B493 /* MGLTestAssertionHandler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGLTestAssertionHandler.m; path = ../../darwin/test/MGLTestAssertionHandler.m; sourceTree = ""; }; CA0B3C082329FB4800E4B493 /* MGLOfflinePackTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLOfflinePackTests.mm; path = ../../darwin/test/MGLOfflinePackTests.mm; sourceTree = ""; }; CA4045C4216720D700B356E1 /* MGLCluster.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLCluster.h; sourceTree = ""; }; - CA8FBC0C21A4A74300D1203C /* MGLRendererConfigurationTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLRendererConfigurationTests.mm; path = ../../darwin/test/MGLRendererConfigurationTests.mm; sourceTree = ""; }; + CA8FBC0C21A4A74300D1203C /* MGLRendererConfigurationTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGLRendererConfigurationTests.m; path = ../../darwin/test/MGLRendererConfigurationTests.m; sourceTree = ""; }; CA9461A520884CCB0015EB12 /* MGLAnnotationTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGLAnnotationTests.m; path = test/MGLAnnotationTests.m; sourceTree = SOURCE_ROOT; }; CAD9D0AB22A88A32001B25EE /* MGLResourceTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLResourceTests.mm; path = ../../darwin/test/MGLResourceTests.mm; sourceTree = ""; }; CF762DEE22DC7EFF00338472 /* MGLLoggingConfiguration.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLLoggingConfiguration.mm; sourceTree = ""; }; @@ -1216,7 +1216,7 @@ DAE6C3CA1CC34BD800DB3429 /* MGLOfflineRegionTests.m */, 55E2AD101E5B0A6900E8C587 /* MGLOfflineStorageTests.mm */, 35C5D84B1D6DD75B00E95907 /* MGLPredicateTests.mm */, - CA8FBC0C21A4A74300D1203C /* MGLRendererConfigurationTests.mm */, + CA8FBC0C21A4A74300D1203C /* MGLRendererConfigurationTests.m */, CAD9D0AB22A88A32001B25EE /* MGLResourceTests.mm */, DAE6C3CC1CC34BD800DB3429 /* MGLStyleTests.mm */, 556660D51E1D07E400E2C41B /* MGLVersionNumber.m */, @@ -1262,7 +1262,7 @@ DA35D9C4240916370013ECB0 /* MGLReachability.h */, DA35D9C5240916380013ECB0 /* MGLReachability.m */, 3EA9369A4C46957566058822 /* MGLRendererConfiguration.h */, - 3EA93B1B0864609938506E12 /* MGLRendererConfiguration.mm */, + 3EA93B1B0864609938506E12 /* MGLRendererConfiguration.m */, 92F2C3EA1F0E3A1900268EC0 /* MGLRendererFrontend.h */, DAE6C3571CC31E0400DB3429 /* MGLStyle.h */, 3537CA731D3F93A600380318 /* MGLStyle_Private.h */, @@ -1748,7 +1748,7 @@ 3529039C1D6C63B80002C7DF /* NSPredicate+MGLAdditions.mm in Sources */, DA8F25981D51CAC70010E6B5 /* MGLVectorTileSource.mm in Sources */, 352742A11D4C25BD00A1ECE6 /* MGLStyleValue.mm in Sources */, - 3EA93BA38DBB4B814B6C1FCC /* MGLRendererConfiguration.mm in Sources */, + 3EA93BA38DBB4B814B6C1FCC /* MGLRendererConfiguration.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1782,7 +1782,7 @@ CA0B3C092329FB4800E4B493 /* MGLOfflinePackTests.mm in Sources */, 170A82C4201FB6EC00943087 /* MGLHeatmapColorTests.mm in Sources */, 4031ACFC1E9EB3C100A3EA26 /* MGLMapViewDelegateIntegrationTests.swift in Sources */, - CA8FBC0D21A4A74300D1203C /* MGLRendererConfigurationTests.mm in Sources */, + CA8FBC0D21A4A74300D1203C /* MGLRendererConfigurationTests.m in Sources */, 4031AD031E9FD6AA00A3EA26 /* MGLSDKTestHelpers.swift in Sources */, DAA4227C24294137008457DB /* MGLMapSnapshotterTests.m in Sources */, DA87A9A71DCACC5000810D09 /* MGLBackgroundStyleLayerTests.mm in Sources */, diff --git a/platform/macos/src/MGLMapView.mm b/platform/macos/src/MGLMapView.mm index 61f49c08f6..e434c8f7c9 100644 --- a/platform/macos/src/MGLMapView.mm +++ b/platform/macos/src/MGLMapView.mm @@ -279,7 +279,8 @@ - (void)commonInit { MGLRendererConfiguration *config = [MGLRendererConfiguration currentConfiguration]; - auto renderer = std::make_unique(_mbglView->getRendererBackend(), config.scaleFactor, config.localFontFamilyName); + auto localFontFamilyName = config.localFontFamilyName ? std::string(config.localFontFamilyName.UTF8String) : nullptr; + auto renderer = std::make_unique(_mbglView->getRendererBackend(), config.scaleFactor, localFontFamilyName); BOOL enableCrossSourceCollisions = !config.perSourceCollisions; _rendererFrontend = std::make_unique(std::move(renderer), self, _mbglView->getRendererBackend(), true); From 288194c9047d05a30c0591b537b5f98da28ddcbe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Minh=20Nguye=CC=82=CC=83n?= Date: Thu, 23 Apr 2020 20:43:49 -0700 Subject: [PATCH 2/2] [ios, macos] Added snapshot test of locally rendered font Disabled on iOS for now due to actual differences in Core Text behavior. Disabled on macOS because the test is too strict without any tolerance. --- platform/darwin/test/MGLMapSnapshotterTests.m | 38 ++++++++++++++---- .../PingFang.imageset/Contents.json | 22 ++++++++++ .../PingFang.imageset/actualImage.png | Bin 0 -> 63093 bytes .../PingFang.imageset/expected.png | Bin 0 -> 18292 bytes platform/darwin/test/one-liner.json | 2 +- platform/ios/ios.xcodeproj/project.pbxproj | 8 ++++ .../xcshareddata/xcschemes/CI.xcscheme | 5 +++ .../xcschemes/dynamic+static.xcscheme | 5 +++ .../xcshareddata/xcschemes/dynamic.xcscheme | 5 +++ .../macos/macos.xcodeproj/project.pbxproj | 8 ++++ .../xcshareddata/xcschemes/CI.xcscheme | 5 +++ .../xcshareddata/xcschemes/dynamic.xcscheme | 5 +++ .../xcshareddata/xcschemes/macosapp.xcscheme | 5 +++ 13 files changed, 100 insertions(+), 8 deletions(-) create mode 100644 platform/darwin/test/Media.xcassets/Fixtures/MGLMapSnapshotterTests/PingFang.imageset/Contents.json create mode 100644 platform/darwin/test/Media.xcassets/Fixtures/MGLMapSnapshotterTests/PingFang.imageset/actualImage.png create mode 100644 platform/darwin/test/Media.xcassets/Fixtures/MGLMapSnapshotterTests/PingFang.imageset/expected.png diff --git a/platform/darwin/test/MGLMapSnapshotterTests.m b/platform/darwin/test/MGLMapSnapshotterTests.m index ef5f35ea0f..8296940805 100644 --- a/platform/darwin/test/MGLMapSnapshotterTests.m +++ b/platform/darwin/test/MGLMapSnapshotterTests.m @@ -49,7 +49,7 @@ BOOL MGLEqualImages(MGLImage *leftImage, MGLImage *rightImage) { #endif } -@interface MGLMapSnapshotterTests : XCTestCase +@interface MGLMapSnapshotterTests : XCTestCase @property (nonatomic) XCTestExpectation *styleLoadingExpectation; @property (nonatomic, copy, nullable) void (^runtimeStylingActions)(MGLStyle *style); @@ -62,10 +62,13 @@ - (void)setUp { [super setUp]; [MGLAccountManager setAccessToken:@"pk.feedcafedeadbeefbadebede"]; + + [MGLOfflineStorage sharedOfflineStorage].delegate = self; } - (void)tearDown { [MGLAccountManager setAccessToken:nil]; + [MGLOfflineStorage sharedOfflineStorage].delegate = nil; self.styleLoadingExpectation = nil; self.runtimeStylingActions = nil; [super tearDown]; @@ -138,20 +141,26 @@ - (void)testDelegate { } - (void)testRuntimeStyling { - [self testRuntimeStylingActions:^(MGLStyle *style) { + [self testStyleURL:nil applyingRuntimeStylingActions:^(MGLStyle *style) { MGLBackgroundStyleLayer *backgroundLayer = [[MGLBackgroundStyleLayer alloc] initWithIdentifier:@"background"]; backgroundLayer.backgroundColor = [NSExpression expressionForConstantValue:[MGLColor orangeColor]]; [style addLayer:backgroundLayer]; } expectedImageName:@"Fixtures/MGLMapSnapshotterTests/background"]; } +- (void)testLocalGlyphRendering { + [[NSUserDefaults standardUserDefaults] setObject:@[@"PingFang TC"] forKey:@"MGLIdeographicFontFamilyName"]; + NSURL *styleURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"mixed" withExtension:@"json"]; + [self testStyleURL:styleURL applyingRuntimeStylingActions:^(MGLStyle *style) {} expectedImageName:@"Fixtures/MGLMapSnapshotterTests/PingFang"]; +} + /** Tests that applying the given runtime styling actions on a blank style results in a snapshot image that matches the image with the given name in the asset catalog. @param actions Runtime styling actions to apply to the blank style. @param expectedImageName Name of the test fixture image in Media.xcassets. */ -- (void)testRuntimeStylingActions:(void (^)(MGLStyle *style))actions expectedImageName:(NSString *)expectedImageName { +- (void)testStyleURL:(nullable NSURL *)styleURL applyingRuntimeStylingActions:(void (^)(MGLStyle *style))actions expectedImageName:(NSString *)expectedImageName { self.styleLoadingExpectation = [self expectationWithDescription:@"Style should finish loading."]; XCTestExpectation *overlayExpectation = [self expectationWithDescription:@"Overlay handler should get called."]; XCTestExpectation *completionExpectation = [self expectationWithDescription:@"Completion handler should get called."]; @@ -163,9 +172,15 @@ - (void)testRuntimeStylingActions:(void (^)(MGLStyle *style))actions expectedIma #endif XCTAssertNotNil(expectedImage, @"Image fixture “%@” missing from Media.xcassets.", expectedImageName); - NSURL *styleURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"one-liner" withExtension:@"json"]; + if (!styleURL) { + styleURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"one-liner" withExtension:@"json"]; + } MGLMapCamera *camera = [MGLMapCamera camera]; - MGLMapSnapshotOptions *options = [[MGLMapSnapshotOptions alloc] initWithStyleURL:styleURL camera:camera size:CGSizeMake(500, 500)]; + camera.centerCoordinate = kCLLocationCoordinate2DInvalid; + camera.heading = -1; + camera.pitch = -1; + MGLMapSnapshotOptions *options = [[MGLMapSnapshotOptions alloc] initWithStyleURL:styleURL camera:camera size:expectedImage.size]; + options.zoomLevel = -1; MGLMapSnapshotter *snapshotter = [[MGLMapSnapshotter alloc] initWithOptions:options]; snapshotter.delegate = self; @@ -183,8 +198,8 @@ - (void)testRuntimeStylingActions:(void (^)(MGLStyle *style))actions expectedIma XCTAssertNil(error); XCTAssertNotNil(snapshot); if (snapshot) { - XCTAssertEqual(snapshot.image.size.width, 500); - XCTAssertEqual(snapshot.image.size.height, 500); + XCTAssertEqual(snapshot.image.size.width, expectedImage.size.width); + XCTAssertEqual(snapshot.image.size.height, expectedImage.size.height); } [completionExpectation fulfill]; }]; @@ -205,4 +220,13 @@ - (void)mapSnapshotter:(MGLMapSnapshotter *)snapshotter didFinishLoadingStyle:(M [self.styleLoadingExpectation fulfill]; } +#pragma mark MGLOfflineStorageDelegate methods + +- (NSURL *)offlineStorage:(MGLOfflineStorage *)storage URLForResourceOfKind:(MGLResourceKind)kind withURL:(NSURL *)url { + if (kind == MGLResourceKindGlyphs && [url.scheme isEqualToString:@"local"]) { + return [[NSBundle bundleForClass:[self class]] URLForResource:@"glyphs" withExtension:@"pbf"]; + } + return url; +} + @end diff --git a/platform/darwin/test/Media.xcassets/Fixtures/MGLMapSnapshotterTests/PingFang.imageset/Contents.json b/platform/darwin/test/Media.xcassets/Fixtures/MGLMapSnapshotterTests/PingFang.imageset/Contents.json new file mode 100644 index 0000000000..42d77b97c9 --- /dev/null +++ b/platform/darwin/test/Media.xcassets/Fixtures/MGLMapSnapshotterTests/PingFang.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "filename" : "expected.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "actualImage.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/platform/darwin/test/Media.xcassets/Fixtures/MGLMapSnapshotterTests/PingFang.imageset/actualImage.png b/platform/darwin/test/Media.xcassets/Fixtures/MGLMapSnapshotterTests/PingFang.imageset/actualImage.png new file mode 100644 index 0000000000000000000000000000000000000000..01dae8b103e3e31843058b0c5e46c4a3b1f8f566 GIT binary patch literal 63093 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 literal 0 HcmV?d00001 diff --git a/platform/darwin/test/one-liner.json b/platform/darwin/test/one-liner.json index 23c546181f..7888811e92 100644 --- a/platform/darwin/test/one-liner.json +++ b/platform/darwin/test/one-liner.json @@ -1 +1 @@ -{"version":8,"sources":{},"layers":[]} \ No newline at end of file +{"version":8,"sources":{},"layers":[],"center":[0,0],"zoom":0} diff --git a/platform/ios/ios.xcodeproj/project.pbxproj b/platform/ios/ios.xcodeproj/project.pbxproj index 88ddfc43ae..ca1c7a8002 100644 --- a/platform/ios/ios.xcodeproj/project.pbxproj +++ b/platform/ios/ios.xcodeproj/project.pbxproj @@ -635,6 +635,8 @@ DAC25FCD200FD83F009BE98E /* NSExpression+MGLPrivateAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = DAC25FCB200FD83E009BE98E /* NSExpression+MGLPrivateAdditions.h */; }; DAC49C5C1CD02BC9009E1AA3 /* Localizable.stringsdict in Resources */ = {isa = PBXBuildFile; fileRef = DAC49C5F1CD02BC9009E1AA3 /* Localizable.stringsdict */; }; DAC49C5D1CD02BC9009E1AA3 /* Localizable.stringsdict in Resources */ = {isa = PBXBuildFile; fileRef = DAC49C5F1CD02BC9009E1AA3 /* Localizable.stringsdict */; }; + DAC8A48024527EDC00C795BB /* glyphs.pbf in Resources */ = {isa = PBXBuildFile; fileRef = DAC8A47F24527EDB00C795BB /* glyphs.pbf */; }; + DAC8A4822452971B00C795BB /* mixed.json in Resources */ = {isa = PBXBuildFile; fileRef = DAC8A4812452971B00C795BB /* mixed.json */; }; DACA86262019218600E9693A /* MGLRasterDEMSource.h in Headers */ = {isa = PBXBuildFile; fileRef = DACA86242019218500E9693A /* MGLRasterDEMSource.h */; settings = {ATTRIBUTES = (Public, ); }; }; DACA86272019218600E9693A /* MGLRasterDEMSource.h in Headers */ = {isa = PBXBuildFile; fileRef = DACA86242019218500E9693A /* MGLRasterDEMSource.h */; settings = {ATTRIBUTES = (Public, ); }; }; DACA86282019218600E9693A /* MGLRasterDEMSource.mm in Sources */ = {isa = PBXBuildFile; fileRef = DACA86252019218500E9693A /* MGLRasterDEMSource.mm */; }; @@ -1281,6 +1283,8 @@ DAC49C621CD07D74009E1AA3 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = en; path = en.lproj/Localizable.stringsdict; sourceTree = ""; }; DAC832642404AF9000A61BF8 /* darwin.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = darwin.xcconfig; path = ../darwin/darwin.xcconfig; sourceTree = ""; }; DAC832672404AFBB00A61BF8 /* ci.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = ci.xcconfig; path = ../darwin/ci.xcconfig; sourceTree = ""; }; + DAC8A47F24527EDB00C795BB /* glyphs.pbf */ = {isa = PBXFileReference; lastKnownFileType = file; name = glyphs.pbf; path = "../../../vendor/mapbox-gl-native/test/fixtures/resources/glyphs.pbf"; sourceTree = ""; }; + DAC8A4812452971B00C795BB /* mixed.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = mixed.json; path = "../../../vendor/mapbox-gl-native/test/fixtures/local_glyphs/mixed.json"; sourceTree = ""; }; DACA86242019218500E9693A /* MGLRasterDEMSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLRasterDEMSource.h; sourceTree = ""; }; DACA86252019218500E9693A /* MGLRasterDEMSource.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLRasterDEMSource.mm; sourceTree = ""; }; DACBC60B20118ABE00C4D7E2 /* he */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = he; path = he.lproj/Localizable.strings; sourceTree = ""; }; @@ -1888,6 +1892,8 @@ DA2E88601CC0382C00F24E7B /* MGLStyleTests.mm */, 556660D71E1D085500E2C41B /* MGLVersionNumber.m */, DA35D0871E1A6309007DED41 /* one-liner.json */, + DAC8A4812452971B00C795BB /* mixed.json */, + DAC8A47F24527EDB00C795BB /* glyphs.pbf */, 357579811D502AD4000B822E /* Styling */, 409F43FB1E9E77D10048729D /* Swift Integration */, 4031ACFD1E9FD26900A3EA26 /* Test Helpers */, @@ -2858,6 +2864,8 @@ DA2784FC1DF02FF4001D5B8D /* Media.xcassets in Resources */, 353BAEF71D646370009A8DA9 /* amsterdam.geojson in Resources */, DA35D0881E1A6309007DED41 /* one-liner.json in Resources */, + DAC8A4822452971B00C795BB /* mixed.json in Resources */, + DAC8A48024527EDC00C795BB /* glyphs.pbf in Resources */, 1F7839A6235E137000D4D606 /* sideload_sat.db in Resources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/platform/ios/ios.xcodeproj/xcshareddata/xcschemes/CI.xcscheme b/platform/ios/ios.xcodeproj/xcshareddata/xcschemes/CI.xcscheme index dc80638800..a659022100 100644 --- a/platform/ios/ios.xcodeproj/xcshareddata/xcschemes/CI.xcscheme +++ b/platform/ios/ios.xcodeproj/xcshareddata/xcschemes/CI.xcscheme @@ -71,6 +71,11 @@ BlueprintName = "test" ReferencedContainer = "container:ios.xcodeproj"> + + + + diff --git a/platform/ios/ios.xcodeproj/xcshareddata/xcschemes/dynamic+static.xcscheme b/platform/ios/ios.xcodeproj/xcshareddata/xcschemes/dynamic+static.xcscheme index 7f3eea47cd..9446478be5 100644 --- a/platform/ios/ios.xcodeproj/xcshareddata/xcschemes/dynamic+static.xcscheme +++ b/platform/ios/ios.xcodeproj/xcshareddata/xcschemes/dynamic+static.xcscheme @@ -74,6 +74,11 @@ BlueprintName = "test" ReferencedContainer = "container:ios.xcodeproj"> + + + + diff --git a/platform/ios/ios.xcodeproj/xcshareddata/xcschemes/dynamic.xcscheme b/platform/ios/ios.xcodeproj/xcshareddata/xcschemes/dynamic.xcscheme index 84f1427762..16b4bf1845 100644 --- a/platform/ios/ios.xcodeproj/xcshareddata/xcschemes/dynamic.xcscheme +++ b/platform/ios/ios.xcodeproj/xcshareddata/xcschemes/dynamic.xcscheme @@ -63,6 +63,11 @@ BlueprintName = "test" ReferencedContainer = "container:ios.xcodeproj"> + + + + diff --git a/platform/macos/macos.xcodeproj/project.pbxproj b/platform/macos/macos.xcodeproj/project.pbxproj index 79d96223eb..6b301ca71c 100644 --- a/platform/macos/macos.xcodeproj/project.pbxproj +++ b/platform/macos/macos.xcodeproj/project.pbxproj @@ -210,6 +210,8 @@ DAC2ABC51CC6D343006D18C4 /* MGLAnnotationImage_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = DAC2ABC41CC6D343006D18C4 /* MGLAnnotationImage_Private.h */; }; DAC8325F24049D8700A61BF8 /* libsqlite3.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = DAE6C3C61CC3499100DB3429 /* libsqlite3.tbd */; }; DAC8326024049D9C00A61BF8 /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 55D9B4B01D005D3900C1CCE2 /* libz.tbd */; }; + DAC8A47E24527EBB00C795BB /* glyphs.pbf in Resources */ = {isa = PBXBuildFile; fileRef = DAC8A47D24527EBB00C795BB /* glyphs.pbf */; }; + DAC8A4842452972F00C795BB /* mixed.json in Resources */ = {isa = PBXBuildFile; fileRef = DAC8A4832452972F00C795BB /* mixed.json */; }; DACA8622201920BE00E9693A /* MGLRasterDEMSource.h in Headers */ = {isa = PBXBuildFile; fileRef = DACA8620201920BE00E9693A /* MGLRasterDEMSource.h */; settings = {ATTRIBUTES = (Public, ); }; }; DACA8623201920BE00E9693A /* MGLRasterDEMSource.mm in Sources */ = {isa = PBXBuildFile; fileRef = DACA8621201920BE00E9693A /* MGLRasterDEMSource.mm */; }; DACB0C391E18DFFD005DDBEA /* MGLStyle+MBXAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = DACB0C381E18DFFD005DDBEA /* MGLStyle+MBXAdditions.m */; }; @@ -615,6 +617,8 @@ DAC832652404AF9E00A61BF8 /* Makefile */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.make; name = Makefile; path = ../../Makefile; sourceTree = ""; }; DAC832662404AFB400A61BF8 /* ci.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = ci.xcconfig; path = ../darwin/ci.xcconfig; sourceTree = ""; }; DAC832682404B26400A61BF8 /* jazzy.yml */ = {isa = PBXFileReference; lastKnownFileType = text.yaml; path = jazzy.yml; sourceTree = ""; }; + DAC8A47D24527EBB00C795BB /* glyphs.pbf */ = {isa = PBXFileReference; lastKnownFileType = file; name = glyphs.pbf; path = "../../../vendor/mapbox-gl-native/test/fixtures/resources/glyphs.pbf"; sourceTree = ""; }; + DAC8A4832452972F00C795BB /* mixed.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = mixed.json; path = "../../../vendor/mapbox-gl-native/test/fixtures/local_glyphs/mixed.json"; sourceTree = ""; }; DACA8620201920BE00E9693A /* MGLRasterDEMSource.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MGLRasterDEMSource.h; sourceTree = ""; }; DACA8621201920BE00E9693A /* MGLRasterDEMSource.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLRasterDEMSource.mm; sourceTree = ""; }; DACB0C371E18DFFD005DDBEA /* MGLStyle+MBXAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MGLStyle+MBXAdditions.h"; sourceTree = ""; }; @@ -1221,6 +1225,8 @@ DAE6C3CC1CC34BD800DB3429 /* MGLStyleTests.mm */, 556660D51E1D07E400E2C41B /* MGLVersionNumber.m */, DA35D0891E1A631B007DED41 /* one-liner.json */, + DAC8A4832452972F00C795BB /* mixed.json */, + DAC8A47D24527EBB00C795BB /* glyphs.pbf */, 1F8A59F921653483004DFE75 /* sideload_sat.db */, DA8F257D1D51C5F40010E6B5 /* Styling */, 4031ACFA1E9EB39A00A3EA26 /* Swift Integration */, @@ -1643,6 +1649,8 @@ 35724FC41D630502002A4AB4 /* amsterdam.geojson in Resources */, DA2784FE1DF03060001D5B8D /* Media.xcassets in Resources */, DA35D08A1E1A631B007DED41 /* one-liner.json in Resources */, + DAC8A4842452972F00C795BB /* mixed.json in Resources */, + DAC8A47E24527EBB00C795BB /* glyphs.pbf in Resources */, 1F8A59FA21653483004DFE75 /* sideload_sat.db in Resources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/platform/macos/macos.xcodeproj/xcshareddata/xcschemes/CI.xcscheme b/platform/macos/macos.xcodeproj/xcshareddata/xcschemes/CI.xcscheme index 5449adcb6d..601c152e85 100644 --- a/platform/macos/macos.xcodeproj/xcshareddata/xcschemes/CI.xcscheme +++ b/platform/macos/macos.xcodeproj/xcshareddata/xcschemes/CI.xcscheme @@ -62,6 +62,11 @@ BlueprintName = "test" ReferencedContainer = "container:macos.xcodeproj"> + + + + diff --git a/platform/macos/macos.xcodeproj/xcshareddata/xcschemes/dynamic.xcscheme b/platform/macos/macos.xcodeproj/xcshareddata/xcschemes/dynamic.xcscheme index 55a36344d5..5c8f95f9d1 100644 --- a/platform/macos/macos.xcodeproj/xcshareddata/xcschemes/dynamic.xcscheme +++ b/platform/macos/macos.xcodeproj/xcshareddata/xcschemes/dynamic.xcscheme @@ -62,6 +62,11 @@ BlueprintName = "test" ReferencedContainer = "container:macos.xcodeproj"> + + + + diff --git a/platform/macos/macos.xcodeproj/xcshareddata/xcschemes/macosapp.xcscheme b/platform/macos/macos.xcodeproj/xcshareddata/xcschemes/macosapp.xcscheme index 98e6c54a33..e94969afa9 100644 --- a/platform/macos/macos.xcodeproj/xcshareddata/xcschemes/macosapp.xcscheme +++ b/platform/macos/macos.xcodeproj/xcshareddata/xcschemes/macosapp.xcscheme @@ -48,6 +48,11 @@ BlueprintName = "test" ReferencedContainer = "container:macos.xcodeproj"> + + + +