Skip to content

Commit

Permalink
Fix issue where inverted mask layer was clipped incorrectly (airbnb#1763
Browse files Browse the repository at this point in the history
)
  • Loading branch information
calda authored and Igor Moroz committed May 22, 2024
1 parent ffb31f6 commit 460376b
Show file tree
Hide file tree
Showing 16 changed files with 82 additions and 11 deletions.
8 changes: 8 additions & 0 deletions Lottie.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@
08F8B20F2898A7B100CB5323 /* RepeaterLayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 08F8B20C2898A7B100CB5323 /* RepeaterLayer.swift */; };
08F8B211289990B700CB5323 /* Samples in Resources */ = {isa = PBXBuildFile; fileRef = 08F8B210289990B700CB5323 /* Samples */; };
08F8B213289990CB00CB5323 /* SnapshotTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 08F8B212289990CB00CB5323 /* SnapshotTests.swift */; };
08FE934E28F4CCAC00D3A7E6 /* InfiniteOpaqueAnimationLayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 08FE934D28F4CCAC00D3A7E6 /* InfiniteOpaqueAnimationLayer.swift */; };
08FE934F28F4CCAC00D3A7E6 /* InfiniteOpaqueAnimationLayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 08FE934D28F4CCAC00D3A7E6 /* InfiniteOpaqueAnimationLayer.swift */; };
08FE935028F4CCAC00D3A7E6 /* InfiniteOpaqueAnimationLayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 08FE934D28F4CCAC00D3A7E6 /* InfiniteOpaqueAnimationLayer.swift */; };
19465F52282F998B00BB2C97 /* CachedImageProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19465F51282F998B00BB2C97 /* CachedImageProvider.swift */; };
19465F53282F998B00BB2C97 /* CachedImageProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19465F51282F998B00BB2C97 /* CachedImageProvider.swift */; };
19465F54282F998B00BB2C97 /* CachedImageProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19465F51282F998B00BB2C97 /* CachedImageProvider.swift */; };
Expand Down Expand Up @@ -600,6 +603,7 @@
08F8B20C2898A7B100CB5323 /* RepeaterLayer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RepeaterLayer.swift; sourceTree = "<group>"; };
08F8B210289990B700CB5323 /* Samples */ = {isa = PBXFileReference; lastKnownFileType = folder; path = Samples; sourceTree = "<group>"; };
08F8B212289990CB00CB5323 /* SnapshotTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SnapshotTests.swift; sourceTree = "<group>"; };
08FE934D28F4CCAC00D3A7E6 /* InfiniteOpaqueAnimationLayer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InfiniteOpaqueAnimationLayer.swift; sourceTree = "<group>"; };
19465F51282F998B00BB2C97 /* CachedImageProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CachedImageProvider.swift; sourceTree = "<group>"; };
2E044E262820536800FA773B /* AutomaticEngineTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutomaticEngineTests.swift; sourceTree = "<group>"; };
2E09FA0527B6CEB600BA84E5 /* HardcodedFontProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HardcodedFontProvider.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1216,6 +1220,7 @@
2E9C95A42822F43100677516 /* BaseAnimationLayer.swift */,
2E9C95A52822F43100677516 /* PreCompLayer.swift */,
08F8B20C2898A7B100CB5323 /* RepeaterLayer.swift */,
08FE934D28F4CCAC00D3A7E6 /* InfiniteOpaqueAnimationLayer.swift */,
);
path = Layers;
sourceTree = "<group>";
Expand Down Expand Up @@ -1815,6 +1820,7 @@
2E9C96842822F43100677516 /* StrokeRenderer.swift in Sources */,
2E9C965A2822F43100677516 /* MaskContainerLayer.swift in Sources */,
2E9C96452822F43100677516 /* CompositionLayer.swift in Sources */,
08FE934E28F4CCAC00D3A7E6 /* InfiniteOpaqueAnimationLayer.swift in Sources */,
2E9C95F42822F43100677516 /* Stroke.swift in Sources */,
2E9C96722822F43100677516 /* CompositionLayersInitializer.swift in Sources */,
2EAF5A9E27A0798700E00531 /* LottieAnimationViewBase.macOS.swift in Sources */,
Expand Down Expand Up @@ -2027,6 +2033,7 @@
2E9C96852822F43100677516 /* StrokeRenderer.swift in Sources */,
2E9C965B2822F43100677516 /* MaskContainerLayer.swift in Sources */,
2E9C96462822F43100677516 /* CompositionLayer.swift in Sources */,
08FE934F28F4CCAC00D3A7E6 /* InfiniteOpaqueAnimationLayer.swift in Sources */,
2E9C95F52822F43100677516 /* Stroke.swift in Sources */,
2E9C96732822F43100677516 /* CompositionLayersInitializer.swift in Sources */,
2EAF5A9F27A0798700E00531 /* LottieAnimationViewBase.macOS.swift in Sources */,
Expand Down Expand Up @@ -2218,6 +2225,7 @@
2E9C96862822F43100677516 /* StrokeRenderer.swift in Sources */,
2E9C965C2822F43100677516 /* MaskContainerLayer.swift in Sources */,
2E9C96472822F43100677516 /* CompositionLayer.swift in Sources */,
08FE935028F4CCAC00D3A7E6 /* InfiniteOpaqueAnimationLayer.swift in Sources */,
2E9C95F62822F43100677516 /* Stroke.swift in Sources */,
2E9C96742822F43100677516 /* CompositionLayersInitializer.swift in Sources */,
2EAF5AA027A0798700E00531 /* LottieAnimationViewBase.macOS.swift in Sources */,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,9 @@ extension CALayer {
// layer being masked, this creates an inverted mask where only areas _outside_
// of the mask layer are visible.
// https://developer.apple.com/documentation/coregraphics/cgblendmode/xor
let base = BaseAnimationLayer()
// - The inverted mask is supposed to expand infinitely around the shape,
// so we use `InfiniteOpaqueAnimationLayer`
let base = InfiniteOpaqueAnimationLayer()
base.backgroundColor = .rgb(0, 0, 0)
base.addSublayer(maskLayer)
maskLayer.compositingFilter = "xor"
Expand Down
23 changes: 13 additions & 10 deletions Sources/Private/CoreAnimation/Layers/GradientRenderLayer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ final class GradientRenderLayer: CAGradientLayer {
}

let pointInBounds = CGPoint(
x: referencePoint.x + gradientPadding,
y: referencePoint.y + gradientPadding)
x: referencePoint.x + CALayer.veryLargeLayerPadding,
y: referencePoint.y + CALayer.veryLargeLayerPadding)

return CGPoint(
x: CGFloat(pointInBounds.x) / bounds.width,
Expand All @@ -55,20 +55,14 @@ final class GradientRenderLayer: CAGradientLayer {

// MARK: Private

/// Extra padding around the `gradientReferenceBounds` where the gradient is also rendered
/// - This specific value is arbitrary and can be increased if necessary.
/// Theoretically this should be "infinite", to match the behavior of
/// `CGContext.drawLinearGradient` with `[.drawsAfterEndLocation, .drawsBeforeStartLocation]`.
private let gradientPadding: CGFloat = 10_000

private func updateLayout() {
anchorPoint = .zero

bounds = CGRect(
x: gradientReferenceBounds.origin.x,
y: gradientReferenceBounds.origin.y,
width: gradientPadding + gradientReferenceBounds.width + gradientPadding,
height: gradientPadding + gradientReferenceBounds.height + gradientPadding)
width: CALayer.veryLargeLayerPadding + gradientReferenceBounds.width + CALayer.veryLargeLayerPadding,
height: CALayer.veryLargeLayerPadding + gradientReferenceBounds.height + CALayer.veryLargeLayerPadding)

// Align the center of this layer to be at the center point of its parent layer
let superlayerSize = superlayer?.frame.size ?? gradientReferenceBounds.size
Expand All @@ -92,3 +86,12 @@ extension GradientRenderLayer: CustomLayoutLayer {
}
}
}

extension CALayer {
/// Extra padding to add around layers that should be very large or "infinite" in size.
/// Examples include `GradientRenderLayer` and `InfiniteOpaqueAnimationLayer`.
/// - This specific value is arbitrary and can be increased if necessary.
/// - Theoretically this should be "infinite", to match the behavior of
/// `CGContext.drawLinearGradient` with `[.drawsAfterEndLocation, .drawsBeforeStartLocation]` etc.
static let veryLargeLayerPadding: CGFloat = 10_000
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Created by Cal Stephens on 10/10/22.
// Copyright © 2022 Airbnb Inc. All rights reserved.

import QuartzCore

// MARK: - ExpandedAnimationLayer

/// A `BaseAnimationLayer` subclass that renders its background color
/// as if the layer is infinitely large, without affecting its bounds
/// or the bounds of its sublayers
final class InfiniteOpaqueAnimationLayer: BaseAnimationLayer {

// MARK: Lifecycle

override init() {
super.init()
addSublayer(additionalPaddingLayer)
}

required init?(coder _: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

/// Called by CoreAnimation to create a shadow copy of this layer
/// More details: https://developer.apple.com/documentation/quartzcore/calayer/1410842-init
override init(layer: Any) {
super.init(layer: layer)
}

// MARK: Internal

override func layoutSublayers() {
super.layoutSublayers()

masksToBounds = false
additionalPaddingLayer.backgroundColor = backgroundColor

// Scale `additionalPaddingLayer` to be larger than this layer
// by `additionalPadding` at each size, and centered at the center
// of this layer. Since `additionalPadding` is very large, this has
// the affect of making `additionalPaddingLayer` appear infinite.
let scaleRatioX = (bounds.width + (CALayer.veryLargeLayerPadding * 2)) / bounds.width
let scaleRatioY = (bounds.height + (CALayer.veryLargeLayerPadding * 2)) / bounds.height

additionalPaddingLayer.transform = CATransform3DScale(
CATransform3DMakeTranslation(-CALayer.veryLargeLayerPadding, -CALayer.veryLargeLayerPadding, 0),
scaleRatioX,
scaleRatioY,
1)
}

// MARK: Private

private let additionalPaddingLayer = CALayer()

}
1 change: 1 addition & 0 deletions Tests/Samples/Issues/pr_1763.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"v":"5.8.1","fr":30,"ip":35,"op":42,"w":72,"h":72,"nm":"WEB MOBILE LOTTIE FILE 1_72px centered","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":5,"ty":4,"nm":"Front-Thumb 3","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":5,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":7,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":37,"s":[100]},{"t":39,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"s":true,"x":{"a":1,"k":[{"i":{"x":[0],"y":[0.772]},"o":{"x":[0.377],"y":[-1.852]},"t":0,"s":[31.489]},{"i":{"x":[0.599],"y":[1.406]},"o":{"x":[1],"y":[0.334]},"t":20,"s":[29.086]},{"t":34,"s":[31.489]}],"ix":3},"y":{"a":1,"k":[{"i":{"x":[0.008],"y":[0.791]},"o":{"x":[0.403],"y":[-1.827]},"t":0,"s":[37.263]},{"i":{"x":[0.6],"y":[1.496]},"o":{"x":[1],"y":[0.399]},"t":20,"s":[25.376]},{"t":34,"s":[37.263]}],"ix":4}},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.1,0.1,0.1],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.5],"y":[0,0,0]},"t":36,"s":[100,100,100]},{"t":42,"s":[60,60,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.179,-1.431],[0,0],[0.095,-0.572],[0,0],[0,0],[0,-0.828],[0.404,-0.269],[0,0],[0,-0.828],[0.691,-0.134],[0,-0.54],[0.828,0],[0,0],[0,-0.384],[0.828,0],[0,0],[1.147,0.655],[0,0],[1.19,0],[0,0.378],[0,0],[-0.429,0.123],[0,0],[-0.262,0.42],[0,0],[0,0.187],[0,0],[-0.263,0]],"o":[[0,0],[0.072,0.576],[0,0],[0,0],[0.828,0],[0,0.522],[0,0],[0.828,0],[0,0.73],[0.428,0.264],[0,0.828],[0,0],[0.238,0.265],[0,0.828],[0,0],[-1.321,0],[0,0],[-1.033,-0.59],[-0.378,0],[0,0],[0,-0.446],[0,0],[0.476,-0.136],[0,0],[0.099,-0.159],[0,0],[0,-0.263],[1.442,0]],"v":[[1.313,-6.496],[1.392,-5.868],[1.356,-4.137],[1,-2],[5.5,-2],[7,-0.5],[6.329,0.75],[6.5,0.75],[8,2.25],[6.787,3.723],[7.5,5],[6,6.5],[5.618,6.5],[6,7.5],[4.5,9],[0.016,9],[-3.75,8],[-3.923,7.901],[-7.316,7],[-8,6.316],[-8,0.754],[-7.275,-0.207],[-5.239,-0.789],[-4.093,-1.652],[-2.152,-4.757],[-2,-5.287],[-2,-8.524],[-1.524,-9]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Front-Thumb","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":67,"st":-1,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"Mask 2","parent":5,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0.011,-0.231,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[1.449,0.828],[0,0],[0.842,0],[0,1.482],[0,0],[-1.288,0.368],[0,0],[0,0],[0,0],[-1.368,0],[-0.304,-2.431],[0,0],[0.099,-0.701],[0,0],[0,-1.933],[0.008,-0.095],[0,-0.96],[0.374,-0.557],[0,-0.276],[0.919,-0.631],[1.802,0],[0,0]],"o":[[0,0],[-0.731,-0.418],[-1.482,0],[0,0],[0,-1.339],[0,0],[0,0],[0,0],[0,-1.368],[2.45,0],[0,0],[0.088,0.703],[0,0],[1.933,0],[0,0.097],[0.626,0.632],[0,0.722],[0.06,0.257],[0,1.199],[-0.193,1.751],[0,0],[-1.669,0]],"v":[[-4.742,9.736],[-4.915,9.638],[-7.316,9],[-10,6.316],[-10,0.754],[-7.824,-2.13],[-5.789,-2.712],[-4,-5.574],[-4,-8.524],[-1.524,-11],[3.298,-6.744],[3.376,-6.116],[3.359,-4],[5.5,-4],[9,-0.5],[8.988,-0.211],[10,2.25],[9.408,4.199],[9.5,5],[7.979,7.887],[4.5,11],[0.016,11]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-3.75,8],[-4.742,9.736]],"c":false},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ind":2,"ty":"sh","ix":3,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-7.275,-0.207],[-7.824,-2.13]],"c":false},"ix":2},"nm":"Path 3","mn":"ADBE Vector Shape - Group","hd":false},{"ind":3,"ty":"sh","ix":4,"ks":{"a":0,"k":{"i":[[0,0],[0.012,-0.027]],"o":[[-0.011,0.028],[0,0]],"v":[[7.4,5.54],[7.365,5.622]],"c":false},"ix":2},"nm":"Path 4","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0.247058823705,0.329411774874,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Mask","np":6,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":67,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":"Back-Thumb 3","tt":2,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":5,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":7,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":37,"s":[100]},{"t":39,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"s":true,"x":{"a":1,"k":[{"i":{"x":[0],"y":[0.36]},"o":{"x":[0.875],"y":[1.017]},"t":0,"s":[39.309]},{"i":{"x":[0.6],"y":[1.351]},"o":{"x":[1],"y":[0.283]},"t":20,"s":[42.625]},{"t":32,"s":[39.309]}],"ix":3},"y":{"a":1,"k":[{"i":{"x":[0],"y":[0.974]},"o":{"x":[0.576],"y":[-1.955]},"t":0,"s":[33.829]},{"i":{"x":[0.6],"y":[1.456]},"o":{"x":[1],"y":[0.367]},"t":20,"s":[21.179]},{"t":32,"s":[33.829]}],"ix":4}},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.1,0.1,0.1],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.5],"y":[0,0,0]},"t":36,"s":[100,100,100]},{"t":41,"s":[60,60,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.179,-1.431],[0,0],[0.095,-0.572],[0,0],[0,0],[0,-0.828],[0.404,-0.269],[0,0],[0,-0.828],[0.691,-0.134],[0,-0.54],[0.828,0],[0,0],[0,-0.384],[0.828,0],[0,0],[1.147,0.655],[0,0],[1.19,0],[0,0.378],[0,0],[-0.429,0.123],[0,0],[-0.262,0.42],[0,0],[0,0.187],[0,0],[-0.263,0]],"o":[[0,0],[0.072,0.576],[0,0],[0,0],[0.828,0],[0,0.522],[0,0],[0.828,0],[0,0.73],[0.428,0.264],[0,0.828],[0,0],[0.238,0.265],[0,0.828],[0,0],[-1.321,0],[0,0],[-1.033,-0.59],[-0.378,0],[0,0],[0,-0.446],[0,0],[0.476,-0.136],[0,0],[0.099,-0.159],[0,0],[0,-0.263],[1.442,0]],"v":[[1.313,-6.496],[1.392,-5.868],[1.356,-4.137],[1,-2],[5.5,-2],[7,-0.5],[6.329,0.75],[6.5,0.75],[8,2.25],[6.787,3.723],[7.5,5],[6,6.5],[5.618,6.5],[6,7.5],[4.5,9],[0.016,9],[-3.75,8],[-3.923,7.901],[-7.316,7],[-8,6.316],[-8,0.754],[-7.275,-0.207],[-5.239,-0.789],[-4.093,-1.652],[-2.152,-4.757],[-2,-5.287],[-2,-8.524],[-1.524,-9]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Back-Thumb","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":67,"st":-2,"bm":0}],"markers":[]}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Supports Core Animation engine
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 460376b

Please sign in to comment.