diff options
author | Fabian Guerra <fabian.guerra@mapbox.com> | 2019-03-12 16:08:08 -0700 |
---|---|---|
committer | Fabian Guerra <fabian.guerra@mapbox.com> | 2019-03-14 12:59:45 -0700 |
commit | a76a9c749480864b92e0b81c40733a752816ba51 (patch) | |
tree | 957b3e0b89fe120d8e135f7f73fe80401c3ecc70 | |
parent | f693a72ca37029b014850f99a0c0fe9ba57fd593 (diff) | |
download | qtlocation-mapboxgl-a76a9c749480864b92e0b81c40733a752816ba51.tar.gz |
[ios, macos] Add format expression support.
-rw-r--r-- | platform/darwin/src/NSExpression+MGLAdditions.h | 2 | ||||
-rw-r--r-- | platform/darwin/src/NSExpression+MGLAdditions.mm | 57 | ||||
-rw-r--r-- | platform/darwin/test/MGLExpressionTests.mm | 39 |
3 files changed, 80 insertions, 18 deletions
diff --git a/platform/darwin/src/NSExpression+MGLAdditions.h b/platform/darwin/src/NSExpression+MGLAdditions.h index 1e6fd6fc46..c7a5f5a969 100644 --- a/platform/darwin/src/NSExpression+MGLAdditions.h +++ b/platform/darwin/src/NSExpression+MGLAdditions.h @@ -7,6 +7,8 @@ #import "MGLTypes.h" +@class MGLAttributedExpression; + NS_ASSUME_NONNULL_BEGIN typedef NSString *MGLExpressionInterpolationMode NS_TYPED_ENUM; diff --git a/platform/darwin/src/NSExpression+MGLAdditions.mm b/platform/darwin/src/NSExpression+MGLAdditions.mm index 6aaba4dd90..b53fe63d55 100644 --- a/platform/darwin/src/NSExpression+MGLAdditions.mm +++ b/platform/darwin/src/NSExpression+MGLAdditions.mm @@ -11,6 +11,7 @@ #import "NSPredicate+MGLAdditions.h" #import "NSValue+MGLStyleAttributeAdditions.h" #import "MGLVectorTileSource_Private.h" +#import "MGLAttributedExpression.h" #import <objc/runtime.h> @@ -75,6 +76,7 @@ const MGLExpressionInterpolationMode MGLExpressionInterpolationModeCubicBezier = INSTALL_METHOD(mgl_atan:); INSTALL_METHOD(mgl_tan:); INSTALL_METHOD(mgl_log2:); + INSTALL_METHOD(mgl_attributed:); // Install functions that resemble control structures, taking arbitrary // numbers of arguments. Vararg aftermarket functions need to be declared @@ -96,6 +98,12 @@ const MGLExpressionInterpolationMode MGLExpressionInterpolationModeCubicBezier = return [components componentsJoinedByString:@""]; } +- (NSString *)mgl_attributed:(NSArray<MGLAttributedExpression *> *)attributedExpressions { + [NSException raise:NSInvalidArgumentException + format:@"Text format expressions lack underlying Objective-C implementations."]; + return nil; +} + /** Rounds the given number to the nearest integer. If the number is halfway between two integers, this method rounds it away from zero. @@ -229,7 +237,6 @@ const MGLExpressionInterpolationMode MGLExpressionInterpolationModeCubicBezier = return nil; } - /** A placeholder for a catch-all method that evaluates an arbitrary number of arguments as an expression according to the Mapbox Style Specification’s @@ -860,6 +867,23 @@ NSArray *MGLSubexpressionsWithJSONObjects(NSArray *objects) { return [NSExpression expressionForFunction:@"MGL_MATCH" arguments:optionsArray]; + } else if ([op isEqualToString:@"format"]) { + NSMutableArray *attributedExpressions = [NSMutableArray array]; + + for (NSUInteger index = 0; index < argumentObjects.count; index+=2) { + NSExpression *expression = [NSExpression expressionWithMGLJSONObject:argumentObjects[index]]; + NSMutableDictionary *attrs = [NSMutableDictionary dictionary]; + if ((index + 1) < argumentObjects.count) { + attrs = argumentObjects[index + 1]; + } + + MGLAttributedExpression *attributedExpression = [[MGLAttributedExpression alloc] initWithExpression:expression attributes:attrs]; + + [attributedExpressions addObject:attributedExpression]; + } + NSExpression *subexpression = [NSExpression expressionForConstantValue:attributedExpressions]; + return [NSExpression expressionForFunction:@"mgl_attributed:" arguments:@[subexpression]]; + } else if ([op isEqualToString:@"coalesce"]) { NSMutableArray *expressions = [NSMutableArray array]; for (id operand in argumentObjects) { @@ -1115,6 +1139,11 @@ NSArray *MGLSubexpressionsWithJSONObjects(NSArray *objects) { } [NSException raise:NSInvalidArgumentException format:@"Casting expression to %@ not yet implemented.", type]; + } else if ([function isEqualToString:@"mgl_attributed:"] || + [function isEqualToString:@"MGL_FORMAT:"] || + [function isEqualToString:@"MGL_FORMAT"]) { + return [self mgl_jsonFormatExpressionObject]; + } else if ([function isEqualToString:@"MGL_FUNCTION"] || [function isEqualToString:@"MGL_FUNCTION:"]) { NSExpression *firstOp = self.arguments.firstObject; @@ -1363,6 +1392,32 @@ NSArray *MGLSubexpressionsWithJSONObjects(NSArray *objects) { return expressionObject; } +- (id)mgl_jsonFormatExpressionObject { + BOOL isAftermarketFunction = [self.function hasPrefix:@"mgl_attributed:"]; + NSExpression *formatParameter; + NSArray<MGLAttributedExpression *> *attributedExpressions; + + if (isAftermarketFunction) { + formatParameter = self.arguments.firstObject; + } else { + formatParameter = self.operand; + } + + if ([formatParameter respondsToSelector:@selector(constantValue)] && [formatParameter.constantValue isKindOfClass:[NSArray class]]) { + attributedExpressions = (NSArray *)formatParameter.constantValue; + } + + NSMutableArray *expressionObject = [NSMutableArray arrayWithObjects:@"format", nil]; + + for (NSUInteger index = 0; index < attributedExpressions.count; index++) { + MGLAttributedExpression *attributedExpression = attributedExpressions[index]; + [expressionObject addObject:attributedExpression.expression.mgl_jsonExpressionObject]; + [expressionObject addObject:attributedExpression.attributes]; + } + + return expressionObject; +} + #pragma mark Localization /** diff --git a/platform/darwin/test/MGLExpressionTests.mm b/platform/darwin/test/MGLExpressionTests.mm index bcc30e49fd..1152ed3c13 100644 --- a/platform/darwin/test/MGLExpressionTests.mm +++ b/platform/darwin/test/MGLExpressionTests.mm @@ -12,6 +12,7 @@ #else #import "NSColor+MGLAdditions.h" #endif +#import "MGLAttributedExpression.h" #define MGLAssertEqualValues(actual, expected, ...) \ XCTAssertTrue(actual.is<__typeof__(expected)>()); \ @@ -990,6 +991,27 @@ using namespace std::string_literals; } } +- (void)testFormatExpressionObject { + { + MGLAttributedExpression *attribute1 = [MGLAttributedExpression initWithExpression:[NSExpression expressionForConstantValue:@"foo"] + fontNames:nil + fontSize:@(1.2)]; + MGLAttributedExpression *attribute2 = [MGLAttributedExpression initWithExpression:[NSExpression expressionForConstantValue:@"biz"] + fontNames:nil + fontSize:@(1.0)]; + MGLAttributedExpression *attribute3 = [MGLAttributedExpression initWithExpression:[NSExpression expressionForConstantValue:@"bar"] + fontNames:nil + fontSize:@(0.8)]; + MGLAttributedExpression *attribute4 = [MGLAttributedExpression initWithExpression:[NSExpression expressionForConstantValue:@"\r"] + fontNames:@[] + fontSize:nil]; + NSExpression *expression = [NSExpression expressionWithFormat:@"mgl_attributed(%@)", @[attribute1, attribute4, attribute2, attribute3]]; + NSArray *jsonExpression = @[@"format", @"foo", @{@"font-scale": @1.2}, @"\r", @{}, @"biz", @{@"font-scale": @1.0}, @"bar", @{@"font-scale": @0.8}]; + XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression); + XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression); + } +} + - (void)testGenericExpressionObject { { NSExpression *expression = [NSExpression expressionWithFormat:@"MGL_FUNCTION('random', 1, 2, 3, 4, 5)"]; @@ -1002,23 +1024,6 @@ using namespace std::string_literals; XCTAssertThrowsSpecificNamed([expression expressionValueWithObject:nil context:nil], NSException, NSInvalidArgumentException); } { - NSExpression *expression = [NSExpression expressionWithFormat:@"MGL_FUNCTION('format', 'foo', %@, '\r', %@, 'biz', %@, 'bar', %@)", @{@"font-scale": @1.2}, @{}, @{@"font-scale": @1.0}, @{@"font-scale": @0.8}]; - NSArray *jsonExpression = @[@"format", @"foo", @{@"font-scale": @1.2}, @"\r", @{}, @"biz", @{@"font-scale": @1.0}, @"bar", @{@"font-scale": @0.8}]; - - XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression); - - NSExpression *encodedExpression = [NSExpression expressionWithMGLJSONObject:jsonExpression]; - - // Expressions encoded from a json create a different constant abstract type - // thus even tho knowing that the constant values are the same, the base - // class is not. This compares the resulting array which is type agnostic encoding. - for (NSUInteger index = 0; index < jsonExpression.count; index++) { - NSExpression *left = encodedExpression.mgl_jsonExpressionObject[index]; - NSExpression *right = expression.mgl_jsonExpressionObject[index]; - XCTAssertEqualObjects(left.mgl_jsonExpressionObject, right.mgl_jsonExpressionObject); - } - } - { NSArray *arguments = @[ MGLConstantExpression(@"one"), MGLConstantExpression(@1), [NSExpression expressionForVariable:@"one"], |