// // LOTCompositionContainer.m // Lottie // // Created by brandon_withrow on 7/18/17. // Copyright © 2017 Airbnb. All rights reserved. // #import "LOTCompositionContainer.h" #import "LOTAsset.h" #import "CGGeometry+LOTAdditions.h" #import "LOTHelpers.h" @implementation LOTCompositionContainer { NSArray *_childLayers; NSNumber *_frameOffset; CALayer *DEBUG_Center; } - (instancetype)initWithModel:(LOTLayer *)layer inLayerGroup:(LOTLayerGroup *)layerGroup withLayerGroup:(LOTLayerGroup *)childLayerGroup withAssestGroup:(LOTAssetGroup *)assetGroup { self = [super initWithModel:layer inLayerGroup:layerGroup]; if (self) { DEBUG_Center = [CALayer layer]; DEBUG_Center.bounds = CGRectMake(0, 0, 20, 20); DEBUG_Center.borderColor = [UIColor orangeColor].CGColor; DEBUG_Center.borderWidth = 2; DEBUG_Center.masksToBounds = YES; if (ENABLE_DEBUG_SHAPES) { [self.wrapperLayer addSublayer:DEBUG_Center]; } if (layer.startFrame) { _frameOffset = layer.startFrame; } else { _frameOffset = @0; } [self intializeWithChildGroup:childLayerGroup withAssetGroup:assetGroup]; } return self; } - (void)intializeWithChildGroup:(LOTLayerGroup *)childGroup withAssetGroup:(LOTAssetGroup *)assetGroup { NSMutableArray *children = [NSMutableArray array]; NSArray *reversedItems = [[childGroup.layers reverseObjectEnumerator] allObjects]; CALayer *maskedLayer = nil; for (LOTLayer *layer in reversedItems) { LOTAsset *asset; if (layer.referenceID) { // Get relevant Asset asset = [assetGroup assetModelForID:layer.referenceID]; } LOTLayerContainer *child = nil; if (asset.layerGroup) { // Layer is a precomp LOTCompositionContainer *compLayer = [[LOTCompositionContainer alloc] initWithModel:layer inLayerGroup:childGroup withLayerGroup:asset.layerGroup withAssestGroup:assetGroup]; child = compLayer; } else { child = [[LOTLayerContainer alloc] initWithModel:layer inLayerGroup:childGroup]; } if (maskedLayer) { maskedLayer.mask = child; maskedLayer = nil; } else { if (layer.matteType == LOTMatteTypeAdd) { maskedLayer = child; } [self.wrapperLayer addSublayer:child]; } [children addObject:child]; } _childLayers = children; } - (void)displayWithFrame:(NSNumber *)frame forceUpdate:(BOOL)forceUpdate { if (ENABLE_DEBUG_LOGGING) NSLog(@"-------------------- Composition Displaying Frame %@ --------------------", frame); [super displayWithFrame:frame forceUpdate:forceUpdate]; NSNumber *childFrame = @(frame.floatValue - _frameOffset.floatValue); for (LOTLayerContainer *child in _childLayers) { [child displayWithFrame:childFrame forceUpdate:forceUpdate]; } if (ENABLE_DEBUG_LOGGING) NSLog(@"-------------------- ------------------------------- --------------------"); if (ENABLE_DEBUG_LOGGING) NSLog(@"-------------------- ------------------------------- --------------------"); } - (BOOL)setValue:(nonnull id)value forKeypath:(nonnull NSString *)keypath atFrame:(nullable NSNumber *)frame { BOOL transformSet = [super setValue:value forKeypath:keypath atFrame:frame]; if (transformSet) { return transformSet; } NSString *childKey = nil; if (self.layerName == nil) { childKey = keypath; } else { NSArray *components = [keypath componentsSeparatedByString:@"."]; NSString *firstKey = components.firstObject; if ([firstKey isEqualToString:self.layerName]) { childKey = [keypath stringByReplacingCharactersInRange:NSMakeRange(0, firstKey.length + 1) withString:@""]; } } if (childKey) { for (LOTLayerContainer *child in _childLayers) { BOOL childHasKey = [child setValue:value forKeypath:childKey atFrame:frame]; if (childHasKey) { return childHasKey; } } } return NO; } - (void)addSublayer:(nonnull CALayer *)subLayer toLayerNamed:(nonnull NSString *)layerName applyTransform:(BOOL)applyTransform { for (LOTLayerContainer *child in _childLayers) { if ([child.layerName isEqualToString:layerName]) { if (applyTransform) { [child addAndMaskSublayer:subLayer]; } else { CALayer *maskWrapper = [CALayer new]; [maskWrapper addSublayer:subLayer]; [self.wrapperLayer insertSublayer:maskWrapper below:child]; [child removeFromSuperlayer]; maskWrapper.mask = child; } } } } - (CGRect)convertRect:(CGRect)rect fromLayer:(CALayer *_Nonnull)fromlayer toLayerNamed:(NSString *_Nonnull)layerName { CGRect xRect = rect; for (LOTLayerContainer *child in _childLayers) { if ([child.layerName isEqualToString:layerName]) { xRect = [fromlayer convertRect:rect toLayer:child]; } } return xRect; } - (void)setViewportBounds:(CGRect)viewportBounds { [super setViewportBounds:viewportBounds]; for (LOTLayerContainer *layer in _childLayers) { layer.viewportBounds = viewportBounds; } } - (void)logHierarchyKeypathsWithParent:(NSString * _Nullable)parent { NSString *keypath = parent; if (parent && self.layerName) { keypath = [NSString stringWithFormat:@"%@.%@", parent, self.layerName]; } for (LOTLayerContainer *layer in _childLayers) { [layer logHierarchyKeypathsWithParent:keypath]; } } @end