diff --git a/.github/workflows/ci-master-only.yml b/.github/workflows/ci-master-only.yml index dc78d17e..9f6a4a8b 100644 --- a/.github/workflows/ci-master-only.yml +++ b/.github/workflows/ci-master-only.yml @@ -7,10 +7,12 @@ on: jobs: cocoapods-lint: + env: + DEVELOPER_DIR: /Applications/Xcode_11.4.1.app/Contents/Developer name: Verify that podspec lints - runs-on: macOS-10.14 + runs-on: macOS-latest steps: - name: Checkout the Git repository - uses: actions/checkout@v1 + uses: actions/checkout@v2 - name: Run build.sh with cocoapods-lint mode run: ./build.sh cocoapods-lint diff --git a/.github/workflows/ci-pull-requests-only.yml b/.github/workflows/ci-pull-requests-only.yml new file mode 100644 index 00000000..6dbf42b0 --- /dev/null +++ b/.github/workflows/ci-pull-requests-only.yml @@ -0,0 +1,26 @@ +name: CI (pull-requests-only jobs) + +on: + pull_request: + branches: + - master + +jobs: + buildsh: + env: + DEVELOPER_DIR: /Applications/Xcode_11.4.1.app/Contents/Developer + strategy: + matrix: + mode: [cocoapods-lint-default-subspecs, cocoapods-lint-other-subspecs] + include: + - mode: cocoapods-lint-default-subspecs + name: Verify that default subspecs lint + - mode: cocoapods-lint-other-subspecs + name: Verify that other subspecs lint + name: ${{ matrix.name }} + runs-on: macOS-latest + steps: + - name: Checkout the Git repository + uses: actions/checkout@v2 + - name: Run build script + run: ./build.sh ${{ matrix.mode }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cf9ce035..72b78d44 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,6 +4,8 @@ on: [push, pull_request] jobs: buildsh: + env: + DEVELOPER_DIR: /Applications/Xcode_11.4.1.app/Contents/Developer strategy: matrix: mode: [tests, framework, life-without-cocoapods, carthage, examples-pt1, examples-pt2, examples-pt3, examples-pt4] @@ -25,8 +27,9 @@ jobs: - mode: examples-pt4 name: Build examples (examples-pt4) name: ${{ matrix.name }} - runs-on: macOS-10.14 + runs-on: macOS-latest steps: - name: Checkout the Git repository - uses: actions/checkout@v1 - - run: ./build.sh ${{ matrix.mode }} + uses: actions/checkout@v2 + - name: Run build script + run: ./build.sh ${{ matrix.mode }} diff --git a/.github/workflows/danger.yml b/.github/workflows/danger.yml deleted file mode 100644 index 6d2a2e83..00000000 --- a/.github/workflows/danger.yml +++ /dev/null @@ -1,28 +0,0 @@ -name: Danger - -on: [pull_request] - -jobs: - danger: - name: Danger JS - runs-on: ubuntu-latest - steps: - - name: Checkout the Git repository - uses: actions/checkout@v1 - # TODO: Figure out why GITHUB_TOKEN isn't enough for Danger JS to create a comment. - # Our dangerfile.js escalates any warnings as failures to get more attention. - # - # Here is the error response from GitHub API: - # - # Request failed [403]: https://api.github.com/repos/TextureGroup/Texture/issues/1635/comments - # Response: { - # "message": "Resource not accessible by integration", - # "documentation_url": "https://developer.github.com/v3/issues/comments/#create-a-comment" - # } - # - # https://github.com/TextureGroup/Texture/pull/1635/checks?check_run_id=200541353 - - name: Danger - uses: danger/danger-js@9.1.8 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - DANGER_DISABLE_TRANSPILATION: true diff --git a/AsyncDisplayKit.xcodeproj/project.pbxproj b/AsyncDisplayKit.xcodeproj/project.pbxproj index 1123a0ed..4f8b9a3c 100644 --- a/AsyncDisplayKit.xcodeproj/project.pbxproj +++ b/AsyncDisplayKit.xcodeproj/project.pbxproj @@ -30,8 +30,6 @@ 058D0A40195D057000B7D73C /* ASTextNodeTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 058D0A36195D057000B7D73C /* ASTextNodeTests.mm */; }; 058D0A41195D057000B7D73C /* ASTextNodeWordKernerTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 058D0A37195D057000B7D73C /* ASTextNodeWordKernerTests.mm */; }; 05EA6FE71AC0966E00E35788 /* ASSnapshotTestCase.mm in Sources */ = {isa = PBXBuildFile; fileRef = 05EA6FE61AC0966E00E35788 /* ASSnapshotTestCase.mm */; }; - 0FAFDF7520EC1C90003A51C0 /* ASLayout+IGListKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FAFDF7320EC1C8F003A51C0 /* ASLayout+IGListKit.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 0FAFDF7620EC1C90003A51C0 /* ASLayout+IGListKit.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0FAFDF7420EC1C90003A51C0 /* ASLayout+IGListKit.mm */; }; 18C2ED7F1B9B7DE800F627B3 /* ASCollectionNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 18C2ED7C1B9B7DE800F627B3 /* ASCollectionNode.h */; settings = {ATTRIBUTES = (Public, ); }; }; 18C2ED831B9B7DE800F627B3 /* ASCollectionNode.mm in Sources */ = {isa = PBXBuildFile; fileRef = 18C2ED7D1B9B7DE800F627B3 /* ASCollectionNode.mm */; }; 1A6C000D1FAB4E2100D05926 /* ASCornerLayoutSpec.h in Headers */ = {isa = PBXBuildFile; fileRef = 1A6C000B1FAB4E2000D05926 /* ASCornerLayoutSpec.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -100,8 +98,11 @@ 3917EBD41E9C2FC400D04A01 /* _ASCollectionReusableView.h in Headers */ = {isa = PBXBuildFile; fileRef = 3917EBD21E9C2FC400D04A01 /* _ASCollectionReusableView.h */; settings = {ATTRIBUTES = (Private, ); }; }; 3917EBD51E9C2FC400D04A01 /* _ASCollectionReusableView.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3917EBD31E9C2FC400D04A01 /* _ASCollectionReusableView.mm */; }; 3C9C128519E616EF00E942A0 /* ASTableViewTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3C9C128419E616EF00E942A0 /* ASTableViewTests.mm */; }; + 407B8BAE2310E2ED00CB979E /* ASLayoutSpecUtilitiesTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 407B8BAD2310E2ED00CB979E /* ASLayoutSpecUtilitiesTests.mm */; }; + 4080D66C2350384400CDC199 /* ASPINRemoteImageDownloader.h in Headers */ = {isa = PBXBuildFile; fileRef = 68355B391CB57A5A001D4E68 /* ASPINRemoteImageDownloader.h */; settings = {ATTRIBUTES = (Public, ); }; }; 471D04B1224CB98600649215 /* ASImageNodeBackingSizeTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 471D04B0224CB98600649215 /* ASImageNodeBackingSizeTests.mm */; }; 4E9127691F64157600499623 /* ASRunLoopQueueTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4E9127681F64157600499623 /* ASRunLoopQueueTests.mm */; }; + 4EE3813FF44E20C399ACB962 /* Pods_AsyncDisplayKitTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5039B74209A895E07057081C /* Pods_AsyncDisplayKitTests.framework */; }; 509E68601B3AED8E009B9150 /* ASScrollDirection.mm in Sources */ = {isa = PBXBuildFile; fileRef = 205F0E111B371BD7007741D0 /* ASScrollDirection.mm */; }; 509E68611B3AEDA0009B9150 /* ASAbstractLayoutController.h in Headers */ = {isa = PBXBuildFile; fileRef = 205F0E171B37339C007741D0 /* ASAbstractLayoutController.h */; }; 509E68621B3AEDA5009B9150 /* ASAbstractLayoutController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 205F0E181B37339C007741D0 /* ASAbstractLayoutController.mm */; }; @@ -215,7 +216,6 @@ 9F06E5CD1B4CAF4200F015D8 /* ASCollectionViewTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9F06E5CC1B4CAF4200F015D8 /* ASCollectionViewTests.mm */; }; 9F98C0261DBE29E000476D92 /* ASControlTargetAction.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9F98C0241DBDF2A300476D92 /* ASControlTargetAction.mm */; }; 9F98C0271DBE29FC00476D92 /* ASControlTargetAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 9F98C0231DBDF2A300476D92 /* ASControlTargetAction.h */; settings = {ATTRIBUTES = (Private, ); }; }; - A2763D7A1CBDD57D00A9ADBD /* ASPINRemoteImageDownloader.h in Headers */ = {isa = PBXBuildFile; fileRef = A2763D771CBDD57D00A9ADBD /* ASPINRemoteImageDownloader.h */; settings = {ATTRIBUTES = (Public, ); }; }; A37320101C571B740011FC94 /* ASTextNode+Beta.h in Headers */ = {isa = PBXBuildFile; fileRef = A373200E1C571B050011FC94 /* ASTextNode+Beta.h */; settings = {ATTRIBUTES = (Public, ); }; }; AC026B581BD3F61800BBC17E /* ASAbsoluteLayoutSpecSnapshotTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = AC026B571BD3F61800BBC17E /* ASAbsoluteLayoutSpecSnapshotTests.mm */; }; AC026B701BD57DBF00BBC17E /* _ASHierarchyChangeSet.h in Headers */ = {isa = PBXBuildFile; fileRef = AC026B6D1BD57DBF00BBC17E /* _ASHierarchyChangeSet.h */; settings = {ATTRIBUTES = (Private, ); }; }; @@ -337,7 +337,6 @@ CC0F88621E4281E200576FED /* ASSectionController.h in Headers */ = {isa = PBXBuildFile; fileRef = CCE04B1E1E313EA7006AEBBB /* ASSectionController.h */; settings = {ATTRIBUTES = (Public, ); }; }; CC0F88631E4281E700576FED /* ASSupplementaryNodeSource.h in Headers */ = {isa = PBXBuildFile; fileRef = CCE04B2B1E314A32006AEBBB /* ASSupplementaryNodeSource.h */; settings = {ATTRIBUTES = (Public, ); }; }; CC0F886C1E4286FA00576FED /* ReferenceImages_64 in Resources */ = {isa = PBXBuildFile; fileRef = CC0F88691E4286FA00576FED /* ReferenceImages_64 */; }; - CC0F886D1E4286FA00576FED /* ReferenceImages_iOS_10 in Resources */ = {isa = PBXBuildFile; fileRef = CC0F886A1E4286FA00576FED /* ReferenceImages_iOS_10 */; }; CC11F97A1DB181180024D77B /* ASNetworkImageNodeTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = CC11F9791DB181180024D77B /* ASNetworkImageNodeTests.mm */; }; CC18248C200D49C800875940 /* ASTextNodeCommon.h in Headers */ = {isa = PBXBuildFile; fileRef = CC18248B200D49C800875940 /* ASTextNodeCommon.h */; settings = {ATTRIBUTES = (Public, ); }; }; CC224E962066CA6D00BBA57F /* configuration.json in Resources */ = {isa = PBXBuildFile; fileRef = CC224E952066CA6D00BBA57F /* configuration.json */; }; @@ -364,6 +363,7 @@ CC3B208E1C3F7D0A00798563 /* ASWeakSetTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = CC3B208D1C3F7D0A00798563 /* ASWeakSetTests.mm */; }; CC3B20901C3F892D00798563 /* ASBridgedPropertiesTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = CC3B208F1C3F892D00798563 /* ASBridgedPropertiesTests.mm */; }; CC4981B31D1A02BE004E13CC /* ASTableViewThrashTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = CC4981B21D1A02BE004E13CC /* ASTableViewThrashTests.mm */; }; + CC4E8DAF232C2883007C3182 /* ASGraphicsContextTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = CC4E8DAE232C2882007C3182 /* ASGraphicsContextTests.mm */; }; CC54A81C1D70079800296A24 /* ASDispatch.h in Headers */ = {isa = PBXBuildFile; fileRef = CC54A81B1D70077A00296A24 /* ASDispatch.h */; settings = {ATTRIBUTES = (Private, ); }; }; CC54A81E1D7008B300296A24 /* ASDispatchTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = CC54A81D1D7008B300296A24 /* ASDispatchTests.mm */; }; CC55A70D1E529FA200594372 /* UIResponder+AsyncDisplayKit.h in Headers */ = {isa = PBXBuildFile; fileRef = CC55A70B1E529FA200594372 /* UIResponder+AsyncDisplayKit.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -379,6 +379,7 @@ CC583AD81EF9BDC300134156 /* OCMockObject+ASAdditions.mm in Sources */ = {isa = PBXBuildFile; fileRef = CC583AC71EF9BAB400134156 /* OCMockObject+ASAdditions.mm */; }; CC583AD91EF9BDC600134156 /* ASDisplayNode+OCMock.mm in Sources */ = {isa = PBXBuildFile; fileRef = CC583AC01EF9BAB400134156 /* ASDisplayNode+OCMock.mm */; }; CC58AA4B1E398E1D002C8CB4 /* ASBlockTypes.h in Headers */ = {isa = PBXBuildFile; fileRef = CC58AA4A1E398E1D002C8CB4 /* ASBlockTypes.h */; settings = {ATTRIBUTES = (Public, ); }; }; + CC698827247855F200487428 /* UIImage+ASConvenienceTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = CC698826247855F200487428 /* UIImage+ASConvenienceTests.mm */; }; CC6AA2DA1E9F03B900978E87 /* ASDisplayNode+Ancestry.h in Headers */ = {isa = PBXBuildFile; fileRef = CC6AA2D81E9F03B900978E87 /* ASDisplayNode+Ancestry.h */; settings = {ATTRIBUTES = (Public, ); }; }; CC6AA2DB1E9F03B900978E87 /* ASDisplayNode+Ancestry.mm in Sources */ = {isa = PBXBuildFile; fileRef = CC6AA2D91E9F03B900978E87 /* ASDisplayNode+Ancestry.mm */; }; CC7AF196200D9BD500A21BDE /* ASExperimentalFeatures.h in Headers */ = {isa = PBXBuildFile; fileRef = CC7AF195200D9BD500A21BDE /* ASExperimentalFeatures.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -434,7 +435,7 @@ CCCCCCE41EC3EF060087FE10 /* NSParagraphStyle+ASText.mm in Sources */ = {isa = PBXBuildFile; fileRef = CCCCCCD41EC3EF060087FE10 /* NSParagraphStyle+ASText.mm */; }; CCCCCCE71EC3F0FC0087FE10 /* NSAttributedString+ASText.h in Headers */ = {isa = PBXBuildFile; fileRef = CCCCCCE51EC3F0FC0087FE10 /* NSAttributedString+ASText.h */; }; CCCCCCE81EC3F0FC0087FE10 /* NSAttributedString+ASText.mm in Sources */ = {isa = PBXBuildFile; fileRef = CCCCCCE61EC3F0FC0087FE10 /* NSAttributedString+ASText.mm */; }; - CCDC9B4D200991D10063C1F8 /* ASGraphicsContext.h in Headers */ = {isa = PBXBuildFile; fileRef = CCDC9B4B200991D10063C1F8 /* ASGraphicsContext.h */; }; + CCDC9B4D200991D10063C1F8 /* ASGraphicsContext.h in Headers */ = {isa = PBXBuildFile; fileRef = CCDC9B4B200991D10063C1F8 /* ASGraphicsContext.h */; settings = {ATTRIBUTES = (Public, ); }; }; CCDC9B4E200991D10063C1F8 /* ASGraphicsContext.mm in Sources */ = {isa = PBXBuildFile; fileRef = CCDC9B4C200991D10063C1F8 /* ASGraphicsContext.mm */; }; CCDD148B1EEDCD9D0020834E /* ASCollectionModernDataSourceTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = CCDD148A1EEDCD9D0020834E /* ASCollectionModernDataSourceTests.mm */; }; CCE4F9B31F0D60AC00062E4E /* ASIntegerMapTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = CCE4F9B21F0D60AC00062E4E /* ASIntegerMapTests.mm */; }; @@ -453,8 +454,8 @@ CCF18FF41D2575E300DF5895 /* NSIndexSet+ASHelpers.h in Headers */ = {isa = PBXBuildFile; fileRef = CC4981BA1D1C7F65004E13CC /* NSIndexSet+ASHelpers.h */; settings = {ATTRIBUTES = (Private, ); }; }; CCF1FF5E20C4785000AAD8FC /* ASLocking.h in Headers */ = {isa = PBXBuildFile; fileRef = CCF1FF5D20C4785000AAD8FC /* ASLocking.h */; settings = {ATTRIBUTES = (Public, ); }; }; D933F041224AD17F00FF495E /* ASTransactionTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = D933F040224AD17F00FF495E /* ASTransactionTests.mm */; }; + D99F9158232990F30083CC8E /* ASImageNodeTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D99F9157232990F30083CC8E /* ASImageNodeTests.m */; }; DB55C2671C641AE4004EDCF5 /* ASContextTransitioning.h in Headers */ = {isa = PBXBuildFile; fileRef = DB55C2651C641AE4004EDCF5 /* ASContextTransitioning.h */; settings = {ATTRIBUTES = (Public, ); }; }; - DB7121BCD50849C498C886FB /* libPods-AsyncDisplayKitTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = EFA731F0396842FF8AB635EE /* libPods-AsyncDisplayKitTests.a */; }; DB78412E1C6BCE1600A9E2B4 /* _ASTransitionContext.mm in Sources */ = {isa = PBXBuildFile; fileRef = DB55C2601C6408D6004EDCF5 /* _ASTransitionContext.mm */; }; DBABFAFC1C6A8D2F0039EA4A /* _ASTransitionContext.h in Headers */ = {isa = PBXBuildFile; fileRef = DB55C25F1C6408D6004EDCF5 /* _ASTransitionContext.h */; settings = {ATTRIBUTES = (Private, ); }; }; DBC452DE1C5C6A6A00B16017 /* ArrayDiffingTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = DBC452DD1C5C6A6A00B16017 /* ArrayDiffingTests.mm */; }; @@ -472,6 +473,8 @@ DECBD6E81BE56E1900CF4905 /* ASButtonNode.h in Headers */ = {isa = PBXBuildFile; fileRef = DECBD6E51BE56E1900CF4905 /* ASButtonNode.h */; settings = {ATTRIBUTES = (Public, ); }; }; DECBD6EA1BE56E1900CF4905 /* ASButtonNode.mm in Sources */ = {isa = PBXBuildFile; fileRef = DECBD6E61BE56E1900CF4905 /* ASButtonNode.mm */; }; DEFAD8131CC48914000527C4 /* ASVideoNode.mm in Sources */ = {isa = PBXBuildFile; fileRef = AEEC47E01C20C2DD00EC1693 /* ASVideoNode.mm */; }; + E517F9C823BF14BC006E40E0 /* ASLayout+IGListDiffKit.mm in Sources */ = {isa = PBXBuildFile; fileRef = E517F9C623BF14BC006E40E0 /* ASLayout+IGListDiffKit.mm */; }; + E517F9C923BF14BC006E40E0 /* ASLayout+IGListDiffKit.h in Headers */ = {isa = PBXBuildFile; fileRef = E517F9C723BF14BC006E40E0 /* ASLayout+IGListDiffKit.h */; settings = {ATTRIBUTES = (Public, ); }; }; E51B78BF1F028ABF00E32604 /* ASLayoutFlatteningTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = E51B78BD1F01A0EE00E32604 /* ASLayoutFlatteningTests.mm */; }; E54E00721F1D3828000B30D7 /* ASPagerNode+Beta.h in Headers */ = {isa = PBXBuildFile; fileRef = E54E00711F1D3828000B30D7 /* ASPagerNode+Beta.h */; settings = {ATTRIBUTES = (Public, ); }; }; E54E81FC1EB357BD00FFE8E1 /* ASPageTable.h in Headers */ = {isa = PBXBuildFile; fileRef = E54E81FA1EB357BD00FFE8E1 /* ASPageTable.h */; }; @@ -620,8 +623,6 @@ 058D0A44195D058D00B7D73C /* ASBaseDefines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASBaseDefines.h; sourceTree = ""; }; 05EA6FE61AC0966E00E35788 /* ASSnapshotTestCase.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASSnapshotTestCase.mm; sourceTree = ""; }; 05F20AA31A15733C00DCA68A /* ASImageProtocols.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASImageProtocols.h; sourceTree = ""; }; - 0FAFDF7320EC1C8F003A51C0 /* ASLayout+IGListKit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ASLayout+IGListKit.h"; sourceTree = ""; }; - 0FAFDF7420EC1C90003A51C0 /* ASLayout+IGListKit.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = "ASLayout+IGListKit.mm"; sourceTree = ""; }; 18C2ED7C1B9B7DE800F627B3 /* ASCollectionNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASCollectionNode.h; sourceTree = ""; }; 18C2ED7D1B9B7DE800F627B3 /* ASCollectionNode.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASCollectionNode.mm; sourceTree = ""; }; 1950C4481A3BB5C1005C8279 /* ASEqualityHelpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASEqualityHelpers.h; sourceTree = ""; }; @@ -677,6 +678,7 @@ 3917EBD21E9C2FC400D04A01 /* _ASCollectionReusableView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = _ASCollectionReusableView.h; sourceTree = ""; }; 3917EBD31E9C2FC400D04A01 /* _ASCollectionReusableView.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = _ASCollectionReusableView.mm; sourceTree = ""; }; 3C9C128419E616EF00E942A0 /* ASTableViewTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; path = ASTableViewTests.mm; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; + 407B8BAD2310E2ED00CB979E /* ASLayoutSpecUtilitiesTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = ASLayoutSpecUtilitiesTests.mm; sourceTree = ""; }; 464052191A3F83C40061C0BA /* ASDataController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = ASDataController.h; sourceTree = ""; }; 4640521A1A3F83C40061C0BA /* ASDataController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; path = ASDataController.mm; sourceTree = ""; }; 4640521B1A3F83C40061C0BA /* ASTableLayoutController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASTableLayoutController.h; sourceTree = ""; }; @@ -684,6 +686,7 @@ 4640521D1A3F83C40061C0BA /* ASLayoutController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASLayoutController.h; sourceTree = ""; }; 471D04B0224CB98600649215 /* ASImageNodeBackingSizeTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = ASImageNodeBackingSizeTests.mm; sourceTree = ""; }; 4E9127681F64157600499623 /* ASRunLoopQueueTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASRunLoopQueueTests.mm; sourceTree = ""; }; + 5039B74209A895E07057081C /* Pods_AsyncDisplayKitTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_AsyncDisplayKitTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 68355B2E1CB5799E001D4E68 /* ASImageNode+AnimatedImage.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = "ASImageNode+AnimatedImage.mm"; sourceTree = ""; }; 68355B361CB57A5A001D4E68 /* ASPINRemoteImageDownloader.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASPINRemoteImageDownloader.mm; sourceTree = ""; }; 68355B371CB57A5A001D4E68 /* ASImageContainerProtocolCategories.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASImageContainerProtocolCategories.h; sourceTree = ""; }; @@ -787,8 +790,6 @@ 9F06E5CC1B4CAF4200F015D8 /* ASCollectionViewTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; path = ASCollectionViewTests.mm; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; 9F98C0231DBDF2A300476D92 /* ASControlTargetAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASControlTargetAction.h; sourceTree = ""; }; 9F98C0241DBDF2A300476D92 /* ASControlTargetAction.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASControlTargetAction.mm; sourceTree = ""; }; - A2763D771CBDD57D00A9ADBD /* ASPINRemoteImageDownloader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASPINRemoteImageDownloader.h; path = Details/ASPINRemoteImageDownloader.h; sourceTree = ""; }; - A2763D781CBDD57D00A9ADBD /* ASPINRemoteImageDownloader.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = ASPINRemoteImageDownloader.mm; path = Details/ASPINRemoteImageDownloader.mm; sourceTree = ""; }; A32FEDD31C501B6A004F642A /* ASTextKitFontSizeAdjuster.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASTextKitFontSizeAdjuster.h; path = TextKit/ASTextKitFontSizeAdjuster.h; sourceTree = ""; }; A373200E1C571B050011FC94 /* ASTextNode+Beta.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "ASTextNode+Beta.h"; sourceTree = ""; }; AC026B571BD3F61800BBC17E /* ASAbsoluteLayoutSpecSnapshotTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; path = ASAbsoluteLayoutSpecSnapshotTests.mm; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; @@ -865,7 +866,6 @@ CC0F885D1E4280B800576FED /* _ASCollectionViewCell.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = _ASCollectionViewCell.mm; sourceTree = ""; }; CC0F885E1E4280B800576FED /* _ASCollectionViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = _ASCollectionViewCell.h; sourceTree = ""; }; CC0F88691E4286FA00576FED /* ReferenceImages_64 */ = {isa = PBXFileReference; lastKnownFileType = folder; path = ReferenceImages_64; sourceTree = ""; }; - CC0F886A1E4286FA00576FED /* ReferenceImages_iOS_10 */ = {isa = PBXFileReference; lastKnownFileType = folder; path = ReferenceImages_iOS_10; sourceTree = ""; }; CC11F9791DB181180024D77B /* ASNetworkImageNodeTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASNetworkImageNodeTests.mm; sourceTree = ""; }; CC18248B200D49C800875940 /* ASTextNodeCommon.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ASTextNodeCommon.h; sourceTree = ""; }; CC224E952066CA6D00BBA57F /* configuration.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = configuration.json; sourceTree = ""; }; @@ -891,6 +891,7 @@ CC4981B21D1A02BE004E13CC /* ASTableViewThrashTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASTableViewThrashTests.mm; sourceTree = ""; }; CC4981BA1D1C7F65004E13CC /* NSIndexSet+ASHelpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSIndexSet+ASHelpers.h"; sourceTree = ""; }; CC4981BB1D1C7F65004E13CC /* NSIndexSet+ASHelpers.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = "NSIndexSet+ASHelpers.mm"; sourceTree = ""; }; + CC4E8DAE232C2882007C3182 /* ASGraphicsContextTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASGraphicsContextTests.mm; sourceTree = ""; }; CC512B841DAC45C60054848E /* ASTableView+Undeprecated.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ASTableView+Undeprecated.h"; sourceTree = ""; }; CC54A81B1D70077A00296A24 /* ASDispatch.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ASDispatch.h; sourceTree = ""; }; CC54A81D1D7008B300296A24 /* ASDispatchTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; path = ASDispatchTests.mm; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; @@ -910,6 +911,7 @@ CC583AC61EF9BAB400134156 /* OCMockObject+ASAdditions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "OCMockObject+ASAdditions.h"; sourceTree = ""; }; CC583AC71EF9BAB400134156 /* OCMockObject+ASAdditions.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = "OCMockObject+ASAdditions.mm"; sourceTree = ""; }; CC58AA4A1E398E1D002C8CB4 /* ASBlockTypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASBlockTypes.h; sourceTree = ""; }; + CC698826247855F200487428 /* UIImage+ASConvenienceTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = "UIImage+ASConvenienceTests.mm"; sourceTree = ""; }; CC6AA2D81E9F03B900978E87 /* ASDisplayNode+Ancestry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "ASDisplayNode+Ancestry.h"; path = "Base/ASDisplayNode+Ancestry.h"; sourceTree = ""; }; CC6AA2D91E9F03B900978E87 /* ASDisplayNode+Ancestry.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = "ASDisplayNode+Ancestry.mm"; path = "Base/ASDisplayNode+Ancestry.mm"; sourceTree = ""; }; CC7AF195200D9BD500A21BDE /* ASExperimentalFeatures.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ASExperimentalFeatures.h; sourceTree = ""; }; @@ -996,6 +998,7 @@ D785F6601A74327E00291744 /* ASScrollNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASScrollNode.h; sourceTree = ""; }; D785F6611A74327E00291744 /* ASScrollNode.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASScrollNode.mm; sourceTree = ""; }; D933F040224AD17F00FF495E /* ASTransactionTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = ASTransactionTests.mm; sourceTree = ""; }; + D99F9157232990F30083CC8E /* ASImageNodeTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ASImageNodeTests.m; sourceTree = ""; }; DB55C25F1C6408D6004EDCF5 /* _ASTransitionContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = _ASTransitionContext.h; path = ../_ASTransitionContext.h; sourceTree = ""; }; DB55C2601C6408D6004EDCF5 /* _ASTransitionContext.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = _ASTransitionContext.mm; path = ../_ASTransitionContext.mm; sourceTree = ""; }; DB55C2651C641AE4004EDCF5 /* ASContextTransitioning.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASContextTransitioning.h; sourceTree = ""; }; @@ -1011,6 +1014,8 @@ DEC146B41C37A16A004A0EE7 /* ASCollectionInternal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASCollectionInternal.h; path = Details/ASCollectionInternal.h; sourceTree = ""; }; DECBD6E51BE56E1900CF4905 /* ASButtonNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASButtonNode.h; sourceTree = ""; }; DECBD6E61BE56E1900CF4905 /* ASButtonNode.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASButtonNode.mm; sourceTree = ""; }; + E517F9C623BF14BC006E40E0 /* ASLayout+IGListDiffKit.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = "ASLayout+IGListDiffKit.mm"; sourceTree = ""; }; + E517F9C723BF14BC006E40E0 /* ASLayout+IGListDiffKit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ASLayout+IGListDiffKit.h"; sourceTree = ""; }; E51B78BD1F01A0EE00E32604 /* ASLayoutFlatteningTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASLayoutFlatteningTests.mm; sourceTree = ""; }; E52405B21C8FEF03004DC8E7 /* ASLayoutTransition.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASLayoutTransition.mm; sourceTree = ""; }; E52405B41C8FEF16004DC8E7 /* ASLayoutTransition.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASLayoutTransition.h; sourceTree = ""; }; @@ -1049,7 +1054,6 @@ E5E281751E71C845006B67C2 /* ASCollectionLayoutState.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASCollectionLayoutState.mm; sourceTree = ""; }; E5E2D72D1EA780C4005C24C6 /* ASCollectionGalleryLayoutDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASCollectionGalleryLayoutDelegate.h; sourceTree = ""; }; E5E2D72F1EA780DF005C24C6 /* ASCollectionGalleryLayoutDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; path = ASCollectionGalleryLayoutDelegate.mm; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; - EFA731F0396842FF8AB635EE /* libPods-AsyncDisplayKitTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-AsyncDisplayKitTests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; F325E48B21745F9E00AC93A4 /* ASButtonNodeTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = ASButtonNodeTests.mm; sourceTree = ""; }; F325E48F217460B000AC93A4 /* ASTextNode2Tests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = ASTextNode2Tests.mm; sourceTree = ""; }; F3F698D1211CAD4600800CB1 /* ASDisplayViewAccessibilityTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = ASDisplayViewAccessibilityTests.mm; sourceTree = ""; }; @@ -1077,7 +1081,7 @@ 058D09BE195D04C000B7D73C /* XCTest.framework in Frameworks */, 058D09C1195D04C000B7D73C /* UIKit.framework in Frameworks */, 058D09BF195D04C000B7D73C /* Foundation.framework in Frameworks */, - DB7121BCD50849C498C886FB /* libPods-AsyncDisplayKitTests.a in Frameworks */, + 4EE3813FF44E20C399ACB962 /* Pods_AsyncDisplayKitTests.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1164,7 +1168,7 @@ 058D09AF195D04C000B7D73C /* Foundation.framework */, 058D09BD195D04C000B7D73C /* XCTest.framework */, 058D09C0195D04C000B7D73C /* UIKit.framework */, - EFA731F0396842FF8AB635EE /* libPods-AsyncDisplayKitTests.a */, + 5039B74209A895E07057081C /* Pods_AsyncDisplayKitTests.framework */, ); name = Frameworks; sourceTree = ""; @@ -1248,8 +1252,6 @@ 25E327541C16819500A2170C /* ASPagerNode.h */, 25E327551C16819500A2170C /* ASPagerNode.mm */, E54E00711F1D3828000B30D7 /* ASPagerNode+Beta.h */, - A2763D771CBDD57D00A9ADBD /* ASPINRemoteImageDownloader.h */, - A2763D781CBDD57D00A9ADBD /* ASPINRemoteImageDownloader.mm */, CCBBBF5C1EB161760069AA91 /* ASRangeManagingNode.h */, D785F6601A74327E00291744 /* ASScrollNode.h */, D785F6611A74327E00291744 /* ASScrollNode.mm */, @@ -1333,8 +1335,10 @@ 058D0A31195D057000B7D73C /* ASDisplayNodeTestsHelper.mm */, F3F698D1211CAD4600800CB1 /* ASDisplayViewAccessibilityTests.mm */, 697B31591CFE4B410049936F /* ASEditableTextNodeTests.mm */, + CC4E8DAE232C2882007C3182 /* ASGraphicsContextTests.mm */, 471D04B0224CB98600649215 /* ASImageNodeBackingSizeTests.mm */, 056D21541ABCEF50001107EF /* ASImageNodeSnapshotTests.mm */, + D99F9157232990F30083CC8E /* ASImageNodeTests.m */, ACF6ED551B178DC700DA7C62 /* ASInsetLayoutSpecSnapshotTests.mm */, CCE4F9B21F0D60AC00062E4E /* ASIntegerMapTests.mm */, 69FEE53C1D95A9AF0086F066 /* ASLayoutElementStyleTests.mm */, @@ -1386,6 +1390,8 @@ 83A7D95D1D446A6E00BF333E /* ASWeakMapTests.mm */, CC3B208D1C3F7D0A00798563 /* ASWeakSetTests.mm */, 695BE2541DC1245C008E6EA5 /* ASWrapperSpecSnapshotTests.mm */, + 407B8BAD2310E2ED00CB979E /* ASLayoutSpecUtilitiesTests.mm */, + CC698826247855F200487428 /* UIImage+ASConvenienceTests.mm */, 057D02C01AC0A66700C7AC3C /* AsyncDisplayKitTestHost */, CC583ABF1EF9BAB400134156 /* Common */, 058D09C6195D04C000B7D73C /* Supporting Files */, @@ -1399,7 +1405,6 @@ children = ( CC01EB6C23105C2000CDB61A /* TestAsset.xcassets */, CC0F88691E4286FA00576FED /* ReferenceImages_64 */, - CC0F886A1E4286FA00576FED /* ReferenceImages_iOS_10 */, 058D09C7195D04C000B7D73C /* AsyncDisplayKitTests-Info.plist */, 058D09C8195D04C000B7D73C /* InfoPlist.strings */, ); @@ -1695,8 +1700,8 @@ ACF6ED0A1B17843500DA7C62 /* ASInsetLayoutSpec.mm */, ACF6ED0B1B17843500DA7C62 /* ASLayout.h */, ACF6ED0C1B17843500DA7C62 /* ASLayout.mm */, - 0FAFDF7320EC1C8F003A51C0 /* ASLayout+IGListKit.h */, - 0FAFDF7420EC1C90003A51C0 /* ASLayout+IGListKit.mm */, + E517F9C723BF14BC006E40E0 /* ASLayout+IGListDiffKit.h */, + E517F9C623BF14BC006E40E0 /* ASLayout+IGListDiffKit.mm */, ACF6ED111B17843500DA7C62 /* ASLayoutElement.h */, E55D86311CA8A14000A0C26F /* ASLayoutElement.mm */, 698C8B601CAB49FC0052DC3F /* ASLayoutElementExtensibility.h */, @@ -1891,6 +1896,7 @@ files = ( 1A6C000D1FAB4E2100D05926 /* ASCornerLayoutSpec.h in Headers */, E54E00721F1D3828000B30D7 /* ASPagerNode+Beta.h in Headers */, + E517F9C923BF14BC006E40E0 /* ASLayout+IGListDiffKit.h in Headers */, E5B225281F1790D6001E1431 /* ASHashing.h in Headers */, CC034A131E649F1300626263 /* AsyncDisplayKit+IGListKitMethods.h in Headers */, 693A1DCA1ECC944E00D0C9D2 /* IGListAdapter+AsyncDisplayKit.h in Headers */, @@ -1912,7 +1918,6 @@ 69E0E8A71D356C9400627613 /* ASEqualityHelpers.h in Headers */, 698C8B621CAB49FC0052DC3F /* ASLayoutElementExtensibility.h in Headers */, 69F10C871C84C35D0026140C /* ASRangeControllerUpdateRangeProtocol+Beta.h in Headers */, - 0FAFDF7520EC1C90003A51C0 /* ASLayout+IGListKit.h in Headers */, B350623C1B010EFD0018CF92 /* _ASAsyncTransaction.h in Headers */, 68355B411CB57A6C001D4E68 /* ASImageContainerProtocolCategories.h in Headers */, 7630FFA81C9E267E007A7C0E /* ASVideoNode.h in Headers */, @@ -1934,7 +1939,6 @@ DE84918D1C8FFF2B003D89E9 /* ASRunLoopQueue.h in Headers */, CC0F88621E4281E200576FED /* ASSectionController.h in Headers */, CCB1F95C1EFB6350009C7475 /* ASSignpost.h in Headers */, - A2763D7A1CBDD57D00A9ADBD /* ASPINRemoteImageDownloader.h in Headers */, C018DF21216BF26700181FDA /* ASAbstractLayoutController+FrameworkPrivate.h in Headers */, 34EFC7611B701C9C00AD841F /* ASBackgroundLayoutSpec.h in Headers */, B35062591B010F070018CF92 /* ASBaseDefines.h in Headers */, @@ -2013,6 +2017,7 @@ CC87BB951DA8193C0090E380 /* ASCellNode+Internal.h in Headers */, E5775B021F16759300CAC9BC /* ASCollectionLayoutCache.h in Headers */, E5775B001F13D25400CAC9BC /* ASCollectionLayoutState+Private.h in Headers */, + 4080D66C2350384400CDC199 /* ASPINRemoteImageDownloader.h in Headers */, E5667E8C1F33871300FA6FC0 /* _ASCollectionGalleryLayoutInfo.h in Headers */, E5775AFC1F13CE9F00CAC9BC /* _ASCollectionGalleryLayoutItem.h in Headers */, E5855DF01EBB4D83003639AE /* ASCollectionLayoutDefines.h in Headers */, @@ -2148,6 +2153,7 @@ 058D09B8195D04C000B7D73C /* Sources */, 058D09B9195D04C000B7D73C /* Frameworks */, 058D09BA195D04C000B7D73C /* Resources */, + 572FAC967DD43A0D06367D02 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -2184,7 +2190,7 @@ isa = PBXProject; attributes = { CLASSPREFIX = AS; - LastUpgradeCheck = 0940; + LastUpgradeCheck = 1140; ORGANIZATIONNAME = Pinterest; TargetAttributes = { 057D02BE1AC0A66700C7AC3C = { @@ -2200,10 +2206,9 @@ }; buildConfigurationList = 058D09A7195D04C000B7D73C /* Build configuration list for PBXProject "AsyncDisplayKit" */; compatibilityVersion = "Xcode 6.3"; - developmentRegion = English; + developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( - English, en, Base, ); @@ -2233,7 +2238,6 @@ buildActionMask = 2147483647; files = ( CC0F886C1E4286FA00576FED /* ReferenceImages_64 in Resources */, - CC0F886D1E4286FA00576FED /* ReferenceImages_iOS_10 in Resources */, 052EE06B1A15A0D8002C6279 /* TestResources in Resources */, CC01EB6D23105C2000CDB61A /* TestAsset.xcassets in Resources */, 058D09CA195D04C000B7D73C /* InfoPlist.strings in Resources */, @@ -2269,6 +2273,26 @@ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; + 572FAC967DD43A0D06367D02 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-AsyncDisplayKitTests/Pods-AsyncDisplayKitTests-frameworks.sh", + "${BUILT_PRODUCTS_DIR}/OCMock/OCMock.framework", + "${BUILT_PRODUCTS_DIR}/iOSSnapshotTestCase/FBSnapshotTestCase.framework", + ); + name = "[CP] Embed Pods Frameworks"; + outputPaths = ( + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/OCMock.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FBSnapshotTestCase.framework", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-AsyncDisplayKitTests/Pods-AsyncDisplayKitTests-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -2297,6 +2321,7 @@ ACF6ED5C1B178DC700DA7C62 /* ASCenterLayoutSpecSnapshotTests.mm in Sources */, 9F06E5CD1B4CAF4200F015D8 /* ASCollectionViewTests.mm in Sources */, 2911485C1A77147A005D0878 /* ASControlNodeTests.mm in Sources */, + CC698827247855F200487428 /* UIImage+ASConvenienceTests.mm in Sources */, CC01EB6F23105C7F00CDB61A /* ASImageNodeSnapshotTests.mm in Sources */, CC3B208E1C3F7D0A00798563 /* ASWeakSetTests.mm in Sources */, F711994E1D20C21100568860 /* ASDisplayNodeExtrasTests.mm in Sources */, @@ -2321,6 +2346,7 @@ 4E9127691F64157600499623 /* ASRunLoopQueueTests.mm in Sources */, CC4981B31D1A02BE004E13CC /* ASTableViewThrashTests.mm in Sources */, CC54A81E1D7008B300296A24 /* ASDispatchTests.mm in Sources */, + CC4E8DAF232C2883007C3182 /* ASGraphicsContextTests.mm in Sources */, F3F698D2211CAD4600800CB1 /* ASDisplayViewAccessibilityTests.mm in Sources */, CCE4F9B31F0D60AC00062E4E /* ASIntegerMapTests.mm in Sources */, 058D0A3B195D057000B7D73C /* ASDisplayNodeTestsHelper.mm in Sources */, @@ -2330,6 +2356,7 @@ ACF6ED601B178DC700DA7C62 /* ASLayoutSpecSnapshotTestsHelper.mm in Sources */, CC7FD9E11BB5F750005CCB2B /* ASPhotosFrameworkImageRequestTests.mm in Sources */, 052EE0661A159FEF002C6279 /* ASMultiplexImageNodeTests.mm in Sources */, + 407B8BAE2310E2ED00CB979E /* ASLayoutSpecUtilitiesTests.mm in Sources */, 058D0A3C195D057000B7D73C /* ASMutableAttributedStringBuilderTests.mm in Sources */, F325E48C21745F9E00AC93A4 /* ASButtonNodeTests.mm in Sources */, 9692B4FF219E12370060C2C3 /* ASCollectionViewThrashTests.mm in Sources */, @@ -2352,6 +2379,7 @@ CC35CEC620DD87280006448D /* ASCollectionsTests.mm in Sources */, ACF6ED631B178DC700DA7C62 /* ASStackLayoutSpecSnapshotTests.mm in Sources */, CCE4F9BA1F0DBB5000062E4E /* ASLayoutTestNode.mm in Sources */, + D99F9158232990F30083CC8E /* ASImageNodeTests.m in Sources */, CCAA0B82206ADECB0057B336 /* ASRecursiveUnfairLockTests.mm in Sources */, 81E95C141D62639600336598 /* ASTextNodeSnapshotTests.mm in Sources */, 3C9C128519E616EF00E942A0 /* ASTableViewTests.mm in Sources */, @@ -2409,7 +2437,6 @@ E5B078001E69F4EB00C24B5B /* ASElementMap.mm in Sources */, 9C8898BC1C738BA800D6B02E /* ASTextKitFontSizeAdjuster.mm in Sources */, 690ED59B1E36D118000627C0 /* ASImageNode+tvOS.mm in Sources */, - 0FAFDF7620EC1C90003A51C0 /* ASLayout+IGListKit.mm in Sources */, CCDC9B4E200991D10063C1F8 /* ASGraphicsContext.mm in Sources */, CCCCCCD81EC3EF060087FE10 /* ASTextInput.mm in Sources */, 34EFC7621B701CA400AD841F /* ASBackgroundLayoutSpec.mm in Sources */, @@ -2503,6 +2530,7 @@ 90FC784F1E4BFE1B00383C5A /* ASDisplayNode+Yoga.mm in Sources */, CCA282C91E9EB64B0037E8B7 /* ASDisplayNodeTipState.mm in Sources */, 509E68601B3AED8E009B9150 /* ASScrollDirection.mm in Sources */, + E517F9C823BF14BC006E40E0 /* ASLayout+IGListDiffKit.mm in Sources */, B35062091B010EFD0018CF92 /* ASScrollNode.mm in Sources */, 69BCE3D91EC6513B007DCCAD /* ASDisplayNode+Layout.mm in Sources */, 8BDA5FC81CDBDF95007D13B2 /* ASVideoPlayerNode.mm in Sources */, @@ -2616,6 +2644,7 @@ CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; @@ -2623,6 +2652,7 @@ CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES_ERROR; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES_ERROR; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; @@ -2674,6 +2704,7 @@ CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; @@ -2681,6 +2712,7 @@ CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES_ERROR; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES_ERROR; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; @@ -2832,6 +2864,7 @@ CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; @@ -2839,6 +2872,7 @@ CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES_ERROR; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES_ERROR; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; diff --git a/AsyncDisplayKit.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/AsyncDisplayKit.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/AsyncDisplayKit.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/AsyncDisplayKit.xcodeproj/xcshareddata/xcschemes/AsyncDisplayKit.xcscheme b/AsyncDisplayKit.xcodeproj/xcshareddata/xcschemes/AsyncDisplayKit.xcscheme index f06fd13c..717ca42d 100644 --- a/AsyncDisplayKit.xcodeproj/xcshareddata/xcschemes/AsyncDisplayKit.xcscheme +++ b/AsyncDisplayKit.xcodeproj/xcshareddata/xcschemes/AsyncDisplayKit.xcscheme @@ -1,6 +1,6 @@ + + + + @@ -38,23 +47,15 @@ ReferencedContainer = "container:AsyncDisplayKit.xcodeproj"> + + - - - - - - - - 2.1' - pod 'JGMethodSwizzler', :git => 'https://github.com/JonasGessner/JGMethodSwizzler', :branch => 'master' + platform :ios, '10.0' + use_frameworks! + pod 'OCMock', '~>3.6' + pod 'iOSSnapshotTestCase/Core', '~> 6.2' end diff --git a/Podfile.lock b/Podfile.lock index df3c6fcb..95acfcef 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -1,55 +1,20 @@ PODS: - - FBSnapshotTestCase/Core (2.1.4) - - JGMethodSwizzler (2.0.1) - - OCMock (3.4.1) - - PINCache (3.0.1-beta.7): - - PINCache/Arc-exception-safe (= 3.0.1-beta.7) - - PINCache/Core (= 3.0.1-beta.7) - - PINCache/Arc-exception-safe (3.0.1-beta.7): - - PINCache/Core - - PINCache/Core (3.0.1-beta.7): - - PINOperation (~> 1.1.1) - - PINOperation (1.1.1) - - PINRemoteImage (3.0.0-beta.14): - - PINRemoteImage/PINCache (= 3.0.0-beta.14) - - PINRemoteImage/Core (3.0.0-beta.14): - - PINOperation - - PINRemoteImage/PINCache (3.0.0-beta.14): - - PINCache (= 3.0.1-beta.7) - - PINRemoteImage/Core + - iOSSnapshotTestCase/Core (6.2.0) + - OCMock (3.6) DEPENDENCIES: - - FBSnapshotTestCase/Core (~> 2.1) - - JGMethodSwizzler (from `https://github.com/JonasGessner/JGMethodSwizzler`, branch `master`) - - OCMock (= 3.4.1) - - PINRemoteImage (= 3.0.0-beta.14) + - iOSSnapshotTestCase/Core (~> 6.2) + - OCMock (~> 3.6) SPEC REPOS: - https://github.com/cocoapods/specs.git: - - FBSnapshotTestCase + https://github.com/CocoaPods/Specs.git: + - iOSSnapshotTestCase - OCMock - - PINCache - - PINOperation - - PINRemoteImage - -EXTERNAL SOURCES: - JGMethodSwizzler: - :branch: master - :git: https://github.com/JonasGessner/JGMethodSwizzler - -CHECKOUT OPTIONS: - JGMethodSwizzler: - :commit: 8791eccc5342224bd293b5867348657e3a240c7f - :git: https://github.com/JonasGessner/JGMethodSwizzler SPEC CHECKSUMS: - FBSnapshotTestCase: 094f9f314decbabe373b87cc339bea235a63e07a - JGMethodSwizzler: 7328146117fffa8a4038c42eb7cd3d4c75006f97 - OCMock: 2cd0716969bab32a2283ff3a46fd26a8c8b4c5e3 - PINCache: 7cb9ae068c8f655717f7c644ef1dff9fd573e979 - PINOperation: a6219e6fc9db9c269eb7a7b871ac193bcf400aac - PINRemoteImage: 81bbff853acc71c6de9e106e9e489a791b8bbb08 + iOSSnapshotTestCase: 9ab44cb5aa62b84d31847f40680112e15ec579a6 + OCMock: 5ea90566be239f179ba766fd9fbae5885040b992 -PODFILE CHECKSUM: 445046ac151568c694ff286684322273f0b597d6 +PODFILE CHECKSUM: ff1a1777e31f49e6e4b7b148d0f10e504db7fa26 -COCOAPODS: 1.6.0 +COCOAPODS: 1.9.1 diff --git a/Schemas/configuration.json b/Schemas/configuration.json index bffa63b7..4ce900e5 100644 --- a/Schemas/configuration.json +++ b/Schemas/configuration.json @@ -16,7 +16,6 @@ "exp_graphics_contexts", "exp_text_node", "exp_interface_state_coalesce", - "exp_unfair_lock", "exp_infer_layer_defaults", "exp_collection_teardown", "exp_framesetter_cache", @@ -24,7 +23,7 @@ "exp_did_enter_preload_skip_asm_layout", "exp_dispatch_apply", "exp_oom_bg_dealloc_disable", - "exp_remove_textkit_initialising_lock" + "exp_do_not_cache_accessibility_elements", ] } } diff --git a/Source/ASButtonNode.mm b/Source/ASButtonNode.mm index 5e420792..66b9cd33 100644 --- a/Source/ASButtonNode.mm +++ b/Source/ASButtonNode.mm @@ -140,9 +140,12 @@ // UIButton documentation states that it tints the image and title of buttons when tintColor is set. // | "The tint color to apply to the button title and image." // | From: https://developer.apple.com/documentation/uikit/uibutton/1624025-tintcolor + [self lock]; UIColor *tintColor = self.tintColor; self.imageNode.tintColor = tintColor; self.titleNode.tintColor = tintColor; + [self unlock]; + [self setNeedsDisplay]; } - (void)updateImage diff --git a/Source/ASCellNode.mm b/Source/ASCellNode.mm index 54cf94a1..5bf648ca 100644 --- a/Source/ASCellNode.mm +++ b/Source/ASCellNode.mm @@ -137,7 +137,7 @@ if (ASLockedSelfCompareAssign(_selected, selected)) { if (!_suspendInteractionDelegate) { ASPerformBlockOnMainThread(^{ - [_interactionDelegate nodeSelectedStateDidChange:self]; + [self->_interactionDelegate nodeSelectedStateDidChange:self]; }); } } @@ -153,7 +153,7 @@ if (ASLockedSelfCompareAssign(_highlighted, highlighted)) { if (!_suspendInteractionDelegate) { ASPerformBlockOnMainThread(^{ - [_interactionDelegate nodeHighlightedStateDidChange:self]; + [self->_interactionDelegate nodeHighlightedStateDidChange:self]; }); } } diff --git a/Source/ASCollectionNode.h b/Source/ASCollectionNode.h index 521922a5..fde5a130 100644 --- a/Source/ASCollectionNode.h +++ b/Source/ASCollectionNode.h @@ -121,7 +121,7 @@ NS_ASSUME_NONNULL_BEGIN /** * A Boolean value that controls whether the horizontal scroll indicator is visible. - * The default value of this property is NO. + * The default value of this property is YES. */ @property (nonatomic) BOOL showsHorizontalScrollIndicator; diff --git a/Source/ASCollectionView.mm b/Source/ASCollectionView.mm index 032f68bb..afe9716c 100644 --- a/Source/ASCollectionView.mm +++ b/Source/ASCollectionView.mm @@ -63,7 +63,7 @@ // ASCellLayoutMode is an NSUInteger-based NS_OPTIONS field. Be careful with BOOL handling on the // 32-bit Objective-C runtime, and pattern after ASInterfaceStateIncludesVisible() & friends. -#define ASCellLayoutModeIncludes(layoutMode) ((_cellLayoutMode & layoutMode) == layoutMode) +#define ASCellLayoutModeIncludes(layoutMode) ((self->_cellLayoutMode & layoutMode) == layoutMode) /// What, if any, invalidation should we perform during the next -layoutSubviews. typedef NS_ENUM(NSUInteger, ASCollectionViewInvalidationStyle) { @@ -331,12 +331,6 @@ static NSString * const kReuseIdentifier = @"_ASCollectionReuseIdentifier"; [self setAsyncDelegate:nil]; [self setAsyncDataSource:nil]; } - - // Data controller & range controller may own a ton of nodes, let's deallocate those off-main. - if (ASActivateExperimentalFeature(ASExperimentalOOMBackgroundDeallocDisable) == NO) { - ASPerformBackgroundDeallocation(&_dataController); - ASPerformBackgroundDeallocation(&_rangeController); - } } #pragma mark - @@ -1875,14 +1869,14 @@ static NSString * const kReuseIdentifier = @"_ASCollectionReuseIdentifier"; if (_asyncDelegateFlags.collectionNodeWillBeginBatchFetch) { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ GET_COLLECTIONNODE_OR_RETURN(collectionNode, (void)0); - os_log_debug(ASCollectionLog(), "Beginning batch fetch for %@ with context %@", collectionNode, _batchContext); - [_asyncDelegate collectionNode:collectionNode willBeginBatchFetchWithContext:_batchContext]; + os_log_debug(ASCollectionLog(), "Beginning batch fetch for %@ with context %@", collectionNode, self->_batchContext); + [self->_asyncDelegate collectionNode:collectionNode willBeginBatchFetchWithContext:self->_batchContext]; }); } else if (_asyncDelegateFlags.collectionViewWillBeginBatchFetch) { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" - [_asyncDelegate collectionView:self willBeginBatchFetchWithContext:_batchContext]; + [self->_asyncDelegate collectionView:self willBeginBatchFetchWithContext:self->_batchContext]; #pragma clang diagnostic pop }); } @@ -2248,20 +2242,20 @@ static NSString * const kReuseIdentifier = @"_ASCollectionReuseIdentifier"; ASPerformBlockWithoutAnimation(!changeSet.animated, ^{ as_activity_scope(as_activity_create("Commit collection update", changeSet.rootActivity, OS_ACTIVITY_FLAG_DEFAULT)); if (changeSet.includesReloadData) { - _superIsPendingDataLoad = YES; + self->_superIsPendingDataLoad = YES; updates(); [self _superReloadData:nil completion:nil]; os_log_debug(ASCollectionLog(), "Did reloadData %@", self.collectionNode); [changeSet executeCompletionHandlerWithFinished:YES]; } else { - [_layoutFacilitator collectionViewWillPerformBatchUpdates]; + [self->_layoutFacilitator collectionViewWillPerformBatchUpdates]; __block NSUInteger numberOfUpdates = 0; const auto completion = ^(BOOL finished) { as_activity_scope(as_activity_create("Handle collection update completion", changeSet.rootActivity, OS_ACTIVITY_FLAG_DEFAULT)); as_log_verbose(ASCollectionLog(), "Update animation finished %{public}@", self.collectionNode); // Flush any range changes that happened as part of the update animations ending. - [_rangeController updateIfNeeded]; + [self->_rangeController updateIfNeeded]; [self _scheduleCheckForBatchFetchingForNumberOfChanges:numberOfUpdates]; [changeSet executeCompletionHandlerWithFinished:finished]; }; @@ -2317,7 +2311,7 @@ static NSString * const kReuseIdentifier = @"_ASCollectionReuseIdentifier"; // Flush any range changes that happened as part of submitting the update. as_activity_scope(changeSet.rootActivity); - [_rangeController updateIfNeeded]; + [self->_rangeController updateIfNeeded]; } }); } diff --git a/Source/ASControlNode.mm b/Source/ASControlNode.mm index b5497034..6336d994 100644 --- a/Source/ASControlNode.mm +++ b/Source/ASControlNode.mm @@ -23,7 +23,6 @@ // Initial capacities for dispatch tables. #define kASControlNodeEventDispatchTableInitialCapacity 4 -#define kASControlNodeActionDispatchTableInitialCapacity 4 @interface ASControlNode () { @@ -298,10 +297,10 @@ CGRect _ASControlNodeGetExpandedBounds(ASControlNode *controlNode); dispatch_async(dispatch_get_main_queue(), ^{ // add a highlight overlay node with area of ASControlNode + UIEdgeInsets self.clipsToBounds = NO; - _debugHighlightOverlay = [[ASImageNode alloc] init]; - _debugHighlightOverlay.zPosition = 1000; // ensure we're over the top of any siblings - _debugHighlightOverlay.layerBacked = YES; - [self addSubnode:_debugHighlightOverlay]; + self->_debugHighlightOverlay = [[ASImageNode alloc] init]; + self->_debugHighlightOverlay.zPosition = 1000; // ensure we're over the top of any siblings + self->_debugHighlightOverlay.layerBacked = YES; + [self addSubnode:self->_debugHighlightOverlay]; }); } } @@ -317,7 +316,7 @@ CGRect _ASControlNodeGetExpandedBounds(ASControlNode *controlNode); { // Do we already have an event table for this control event? id eventKey = _ASControlNodeEventKeyForControlEvent(controlEvent); - NSMutableArray *eventTargetActionArray = _controlEventDispatchTable[eventKey]; + NSMutableArray *eventTargetActionArray = self->_controlEventDispatchTable[eventKey]; if (!eventTargetActionArray) { eventTargetActionArray = [[NSMutableArray alloc] init]; @@ -330,7 +329,7 @@ CGRect _ASControlNodeGetExpandedBounds(ASControlNode *controlNode); [eventTargetActionArray addObject:targetAction]; if (eventKey) { - [_controlEventDispatchTable setObject:eventTargetActionArray forKey:eventKey]; + [self->_controlEventDispatchTable setObject:eventTargetActionArray forKey:eventKey]; } }); @@ -391,7 +390,7 @@ CGRect _ASControlNodeGetExpandedBounds(ASControlNode *controlNode); { // Grab the dispatch table for this event (if we have it). id eventKey = _ASControlNodeEventKeyForControlEvent(controlEvent); - NSMutableArray *eventTargetActionArray = _controlEventDispatchTable[eventKey]; + NSMutableArray *eventTargetActionArray = self->_controlEventDispatchTable[eventKey]; if (!eventTargetActionArray) { return; } @@ -411,7 +410,7 @@ CGRect _ASControlNodeGetExpandedBounds(ASControlNode *controlNode); if (eventTargetActionArray.count == 0) { // If there are no targets for this event anymore, remove it. - [_controlEventDispatchTable removeObjectForKey:eventKey]; + [self->_controlEventDispatchTable removeObjectForKey:eventKey]; } }); } @@ -433,7 +432,7 @@ CGRect _ASControlNodeGetExpandedBounds(ASControlNode *controlNode); (ASControlNodeEvent controlEvent) { // Iterate on each target action pair - for (ASControlTargetAction *targetAction in _controlEventDispatchTable[_ASControlNodeEventKeyForControlEvent(controlEvent)]) { + for (ASControlTargetAction *targetAction in self->_controlEventDispatchTable[_ASControlNodeEventKeyForControlEvent(controlEvent)]) { ASControlTargetAction *resolvedTargetAction = [[ASControlTargetAction alloc] init]; resolvedTargetAction.action = targetAction.action; resolvedTargetAction.target = targetAction.target; diff --git a/Source/ASDisplayNode+Layout.mm b/Source/ASDisplayNode+Layout.mm index 4d95cd2d..25d44b87 100644 --- a/Source/ASDisplayNode+Layout.mm +++ b/Source/ASDisplayNode+Layout.mm @@ -137,12 +137,7 @@ ASLayoutElementStyleExtensibilityForwarding _primitiveTraitCollection = traitCollection; l.unlock(); - if (ASActivateExperimentalFeature(ASExperimentalTraitCollectionDidChangeWithPreviousCollection)) { [self asyncTraitCollectionDidChangeWithPreviousTraitCollection:previousTraitCollection]; - } else { - [self asyncTraitCollectionDidChange]; - } - } } @@ -386,7 +381,7 @@ ASLayoutElementStyleExtensibilityForwarding // Figure out previous and pending layouts for layout transition ASDisplayNodeLayout nextLayout = _pendingDisplayNodeLayout; - #define layoutSizeDifferentFromBounds !CGSizeEqualToSize(nextLayout.layout.size, boundsSizeForLayout) + BOOL isLayoutSizeDifferentFromBounds = !CGSizeEqualToSize(nextLayout.layout.size, boundsSizeForLayout); // nextLayout was likely created by a call to layoutThatFits:, check if it is valid and can be applied. // If our bounds size is different than it, or invalid, recalculate. Use #define to avoid nullptr-> @@ -395,7 +390,7 @@ ASLayoutElementStyleExtensibilityForwarding as_log_verbose(ASLayoutLog(), "No pending layout."); } else if (!nextLayout.isValid(_layoutVersion)) { as_log_verbose(ASLayoutLog(), "Pending layout is stale."); - } else if (layoutSizeDifferentFromBounds) { + } else if (isLayoutSizeDifferentFromBounds) { as_log_verbose(ASLayoutLog(), "Pending layout size %@ doesn't match bounds size.", NSStringFromCGSize(nextLayout.layout.size)); } else { as_log_verbose(ASLayoutLog(), "Using pending layout %@.", nextLayout.layout); @@ -656,7 +651,7 @@ ASLayoutElementStyleExtensibilityForwarding as_log_verbose(ASLayoutLog(), "Transition ID is %d", transitionID); // NOTE: This block captures self. It's cheaper than hitting the weak table. asdisplaynode_iscancelled_block_t isCancelled = ^{ - BOOL result = (_transitionID != transitionID); + BOOL result = (self->_transitionID != transitionID); if (result) { as_log_verbose(ASLayoutLog(), "Transition %d canceled, superseded by %d", transitionID, _transitionID.load()); } @@ -677,7 +672,7 @@ ASLayoutElementStyleExtensibilityForwarding } // Perform a full layout creation pass with passed in constrained size to create the new layout for the transition - NSUInteger newLayoutVersion = _layoutVersion; + NSUInteger newLayoutVersion = self->_layoutVersion; ASLayout *newLayout; { ASScopedLockSelfOrToRoot(); @@ -712,10 +707,10 @@ ASLayoutElementStyleExtensibilityForwarding { // Grab __instanceLock__ here to make sure this transition isn't invalidated // right after it passed the validation test and before it proceeds - MutexLocker l(__instanceLock__); + MutexLocker l(self->__instanceLock__); // Update calculated layout - const auto previousLayout = _calculatedDisplayNodeLayout; + const auto previousLayout = self->_calculatedDisplayNodeLayout; const auto pendingLayout = ASDisplayNodeLayout(newLayout, constrainedSize, constrainedSize.max, @@ -723,12 +718,12 @@ ASLayoutElementStyleExtensibilityForwarding [self _locked_setCalculatedDisplayNodeLayout:pendingLayout]; // Setup pending layout transition for animation - _pendingLayoutTransition = pendingLayoutTransition = [[ASLayoutTransition alloc] initWithNode:self + self->_pendingLayoutTransition = pendingLayoutTransition = [[ASLayoutTransition alloc] initWithNode:self pendingLayout:pendingLayout previousLayout:previousLayout]; // Setup context for pending layout transition. we need to hold a strong reference to the context - _pendingLayoutTransitionContext = pendingLayoutTransitionContext = [[_ASTransitionContext alloc] initWithAnimation:animated - layoutDelegate:_pendingLayoutTransition + self->_pendingLayoutTransitionContext = pendingLayoutTransitionContext = [[_ASTransitionContext alloc] initWithAnimation:animated + layoutDelegate:self->_pendingLayoutTransition completionDelegate:self]; } @@ -1043,7 +1038,7 @@ ASLayoutElementStyleExtensibilityForwarding if (self.isNodeLoaded) { ASPerformBlockOnMainThread(^{ if (self.contents == nil) { - _placeholderImage = [self placeholderImage]; + self->_placeholderImage = [self placeholderImage]; } }); } else { diff --git a/Source/ASDisplayNode+Subclasses.h b/Source/ASDisplayNode+Subclasses.h index 99317737..9adb9336 100644 --- a/Source/ASDisplayNode+Subclasses.h +++ b/Source/ASDisplayNode+Subclasses.h @@ -205,15 +205,6 @@ AS_CATEGORY_IMPLEMENTABLE * @abstract Called when the node's ASTraitCollection changes * * @discussion Subclasses can override this method to react to a trait collection change. - */ -AS_CATEGORY_IMPLEMENTABLE -- (void)asyncTraitCollectionDidChange ASDISPLAYNODE_REQUIRES_SUPER; - - -/** - * @abstract Called when the node's ASTraitCollection changes - * - * @discussion Subclasses can override this method to react to a trait collection change. Use `ASExperimentalTraitCollectionDidChangeWithPreviousCollection` to have this method called instead of `asyncTraitCollectionDidChange`. * * @param previousTraitCollection The ASPrimitiveTraitCollection object before the interface environment changed. */ diff --git a/Source/ASDisplayNode.h b/Source/ASDisplayNode.h index 35dfe3c3..84ca49c5 100644 --- a/Source/ASDisplayNode.h +++ b/Source/ASDisplayNode.h @@ -734,7 +734,7 @@ AS_EXTERN NSInteger const ASDefaultDrawingPriority; @property BOOL allowsGroupOpacity; @property BOOL allowsEdgeAntialiasing; -@property unsigned int edgeAntialiasingMask; // default==all values from CAEdgeAntialiasingMask +@property CAEdgeAntialiasingMask edgeAntialiasingMask; // default==all values from CAEdgeAntialiasingMask @property BOOL needsDisplayOnBoundsChange; // default==NO @property BOOL autoresizesSubviews; // default==YES (undefined for layer-backed nodes) diff --git a/Source/ASDisplayNode.mm b/Source/ASDisplayNode.mm index 9ed2a0c6..45f3df87 100644 --- a/Source/ASDisplayNode.mm +++ b/Source/ASDisplayNode.mm @@ -241,7 +241,6 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c) class_addMethod(self, @selector(didEnterVisibleState), noArgsImp, "v@:"); class_addMethod(self, @selector(didExitVisibleState), noArgsImp, "v@:"); class_addMethod(self, @selector(hierarchyDisplayDidFinish), noArgsImp, "v@:"); - class_addMethod(self, @selector(asyncTraitCollectionDidChange), noArgsImp, "v@:"); class_addMethod(self, @selector(calculatedLayoutDidChange), noArgsImp, "v@:"); auto type0 = "v@:" + std::string(@encode(ASSizeRange)); @@ -438,24 +437,42 @@ ASSynthesizeLockingMethodsWithMutex(__instanceLock__); - (void)asyncTraitCollectionDidChangeWithPreviousTraitCollection:(ASPrimitiveTraitCollection)previousTraitCollection { if (@available(iOS 13.0, *)) { + // When changing between light and dark mode, often the entire node needs to re-render. + // This change doesn't happen frequently so it's fairly safe to render nodes again __instanceLock__.lock(); - if (self.primitiveTraitCollection.userInterfaceStyle != previousTraitCollection.userInterfaceStyle) { - // When changing between light and dark mode, often the entire node needs to re-render. - // This change doesn't happen frequently so it's fairly safe to render nodes again - if (_loaded(self) && self.isLayerBacked) { - // Background colors do not dynamically update for layer backed nodes since they utilize CGColorRef - // instead of UIColor. We utilize the _backgroundColor instance variable to track the full dynamic color - // and apply any changes here when trait collection updates occur. - CGColorRef cgBackgroundColor = _backgroundColor.CGColor; - if (!CGColorEqualToColor(_layer.backgroundColor, cgBackgroundColor)) { - _layer.backgroundColor = cgBackgroundColor; - } - } - __instanceLock__.unlock(); - [self setNeedsDisplay]; - return; - } + BOOL loaded = _loaded(self); + ASPrimitiveTraitCollection primitiveTraitCollection = _primitiveTraitCollection; __instanceLock__.unlock(); + if (primitiveTraitCollection.userInterfaceStyle != previousTraitCollection.userInterfaceStyle) { + if (loaded) { + // we need to run that on main thread, cause accessing CALayer properties. + // It seems than in iOS 13 sometimes it causes deadlock. + ASPerformBlockOnMainThread(^{ + self->__instanceLock__.lock(); + CGFloat cornerRadius = self->_cornerRadius; + ASCornerRoundingType cornerRoundingType = self->_cornerRoundingType; + UIColor *backgroundColor = self->_backgroundColor; + self->__instanceLock__.unlock(); + // TODO: we should resolve color using node's trait collection + // but Texture changes it from many places, so we may receive the wrong one. + CGColorRef cgBackgroundColor = backgroundColor.CGColor; + if (!CGColorEqualToColor(self->_layer.backgroundColor, cgBackgroundColor)) { + // Background colors do not dynamically update for layer backed nodes since they utilize CGColorRef + // instead of UIColor. Non layer backed node also receive color to the layer (see [_ASPendingState -applyToView:withSpecialPropertiesHandling:]). + // We utilize the _backgroundColor instance variable to track the full dynamic color + // and apply any changes here when trait collection updates occur. + self->_layer.backgroundColor = cgBackgroundColor; + } + + // If we have clipping corners, re-render the clipping corner layer upon user interface style change + if (cornerRoundingType == ASCornerRoundingTypeClipping && cornerRadius > 0.0f) { + [self _updateClipCornerLayerContentsWithRadius:cornerRadius backgroundColor:backgroundColor]; + } + + [self setNeedsDisplay]; + }); + } + } } } @@ -1331,7 +1348,7 @@ NSString * const ASRenderingEngineDidDisplayNodesScheduledBeforeTimestamp = @"AS __instanceLock__.lock(); if (_placeholderLayer.superlayer && !placeholderShouldPersist) { void (^cleanupBlock)() = ^{ - [_placeholderLayer removeFromSuperlayer]; + [self->_placeholderLayer removeFromSuperlayer]; }; if (_placeholderFadeDuration > 0.0 && ASInterfaceStateIncludesVisible(self.interfaceState)) { @@ -1477,7 +1494,7 @@ void recursivelyTriggerDisplayForLayer(CALayer *layer, BOOL shouldBlock) ASPerformBlockOnMainThread(^{ for (int idx = 0; idx < NUM_CLIP_CORNER_LAYERS; idx++) { // Skip corners that aren't clipped (we have already set up & torn down layers based on maskedCorners.) - if (_clipCornerLayers[idx] == nil) { + if (self->_clipCornerLayers[idx] == nil) { continue; } @@ -1487,7 +1504,7 @@ void recursivelyTriggerDisplayForLayer(CALayer *layer, BOOL shouldBlock) BOOL isRight = (idx == 1 || idx == 3); CGSize size = CGSizeMake(radius + 1, radius + 1); - UIImage *newContents = ASGraphicsCreateImageWithOptions(size, NO, self.contentsScaleForDisplay, nil, nil, ^{ + UIImage *newContents = ASGraphicsCreateImage(self.primitiveTraitCollection, size, NO, self.contentsScaleForDisplay, nil, nil, ^{ CGContextRef ctx = UIGraphicsGetCurrentContext(); if (isRight == YES) { CGContextTranslateCTM(ctx, -radius + 1, 0); @@ -1503,7 +1520,7 @@ void recursivelyTriggerDisplayForLayer(CALayer *layer, BOOL shouldBlock) }); // No lock needed, as _clipCornerLayers is only modified on the main thread. - unowned CALayer *clipCornerLayer = _clipCornerLayers[idx]; + unowned CALayer *clipCornerLayer = self->_clipCornerLayers[idx]; clipCornerLayer.contents = (id)(newContents.CGImage); clipCornerLayer.bounds = CGRectMake(0.0, 0.0, size.width, size.height); clipCornerLayer.anchorPoint = CGPointMake(isRight ? 1.0 : 0.0, isTop ? 0.0 : 1.0); @@ -1518,7 +1535,7 @@ void recursivelyTriggerDisplayForLayer(CALayer *layer, BOOL shouldBlock) ASDisplayNodeAssertMainThread(); for (int idx = 0; idx < NUM_CLIP_CORNER_LAYERS; idx++) { BOOL visible = (0 != (visibleCornerLayers & (1 << idx))); - if (visible == (_clipCornerLayers[idx] != nil)) { + if (visible == (self->_clipCornerLayers[idx] != nil)) { continue; } else if (visible) { static ASDisplayNodeCornerLayerDelegate *clipCornerLayers; @@ -1526,15 +1543,15 @@ void recursivelyTriggerDisplayForLayer(CALayer *layer, BOOL shouldBlock) dispatch_once(&onceToken, ^{ clipCornerLayers = [[ASDisplayNodeCornerLayerDelegate alloc] init]; }); - _clipCornerLayers[idx] = [[CALayer alloc] init]; - _clipCornerLayers[idx].zPosition = 99999; - _clipCornerLayers[idx].delegate = clipCornerLayers; + self->_clipCornerLayers[idx] = [[CALayer alloc] init]; + self->_clipCornerLayers[idx].zPosition = 99999; + self->_clipCornerLayers[idx].delegate = clipCornerLayers; } else { - [_clipCornerLayers[idx] removeFromSuperlayer]; - _clipCornerLayers[idx] = nil; + [self->_clipCornerLayers[idx] removeFromSuperlayer]; + self->_clipCornerLayers[idx] = nil; } } - [self _updateClipCornerLayerContentsWithRadius:_cornerRadius backgroundColor:self.backgroundColor]; + [self _updateClipCornerLayerContentsWithRadius:self->_cornerRadius backgroundColor:self.backgroundColor]; }); } @@ -2791,13 +2808,13 @@ ASDISPLAYNODE_INLINE BOOL subtreeIsRasterized(ASDisplayNode *node) { if (ASInterfaceStateIncludesVisible(self.pendingInterfaceState)) { void(^exitVisibleInterfaceState)(void) = ^{ // This block intentionally retains self. - __instanceLock__.lock(); - unsigned isStillInHierarchy = _flags.isInHierarchy; - BOOL isVisible = ASInterfaceStateIncludesVisible(_pendingInterfaceState); - ASInterfaceState newState = (_pendingInterfaceState & ~ASInterfaceStateVisible); + self->__instanceLock__.lock(); + unsigned isStillInHierarchy = self->_flags.isInHierarchy; + BOOL isVisible = ASInterfaceStateIncludesVisible(self->_pendingInterfaceState); + ASInterfaceState newState = (self->_pendingInterfaceState & ~ASInterfaceStateVisible); // layer may be thrashed, we need to remember the state so we can reset if it enters in same runloop later. - _preExitingInterfaceState = _pendingInterfaceState; - __instanceLock__.unlock(); + self->_preExitingInterfaceState = self->_pendingInterfaceState; + self->__instanceLock__.unlock(); if (!isStillInHierarchy && isVisible) { #if ENABLE_NEW_EXIT_HIERARCHY_BEHAVIOR if (![self supportsRangeManagedInterfaceState]) { @@ -2956,9 +2973,9 @@ ASDISPLAYNODE_INLINE BOOL subtreeIsRasterized(ASDisplayNode *node) { [self setDisplaySuspended:YES]; //schedule clear contents on next runloop dispatch_async(dispatch_get_main_queue(), ^{ - __instanceLock__.lock(); - ASInterfaceState interfaceState = _interfaceState; - __instanceLock__.unlock(); + self->__instanceLock__.lock(); + ASInterfaceState interfaceState = self->_interfaceState; + self->__instanceLock__.unlock(); if (ASInterfaceStateIncludesDisplay(interfaceState) == NO) { [self clearContents]; } @@ -2976,9 +2993,9 @@ ASDISPLAYNODE_INLINE BOOL subtreeIsRasterized(ASDisplayNode *node) { [[self asyncLayer] cancelAsyncDisplay]; //schedule clear contents on next runloop dispatch_async(dispatch_get_main_queue(), ^{ - __instanceLock__.lock(); - ASInterfaceState interfaceState = _interfaceState; - __instanceLock__.unlock(); + self->__instanceLock__.lock(); + ASInterfaceState interfaceState = self->_interfaceState; + self->__instanceLock__.unlock(); if (ASInterfaceStateIncludesDisplay(interfaceState) == NO) { [self clearContents]; } diff --git a/Source/ASEditableTextNode.mm b/Source/ASEditableTextNode.mm index 0c9cd413..60be21f9 100644 --- a/Source/ASEditableTextNode.mm +++ b/Source/ASEditableTextNode.mm @@ -176,11 +176,11 @@ [super didLoad]; void (^configureTextView)(UITextView *) = ^(UITextView *textView) { - if (!_displayingPlaceholder || textView != _textKitComponents.textView) { + if (!self->_displayingPlaceholder || textView != self->_textKitComponents.textView) { // If showing the placeholder, don't propagate backgroundColor/opaque to the editable textView. It is positioned over the placeholder to accept taps to begin editing, and if it's opaque/colored then it'll obscure the placeholder. textView.backgroundColor = self.backgroundColor; textView.opaque = self.opaque; - } else if (_displayingPlaceholder && textView == _textKitComponents.textView) { + } else if (self->_displayingPlaceholder && textView == self->_textKitComponents.textView) { // The default backgroundColor for a textView is white. Due to the reason described above, make sure the editable textView starts out transparent. textView.backgroundColor = nil; textView.opaque = NO; @@ -189,16 +189,16 @@ // Configure textView with UITextInputTraits { - AS::MutexLocker l(_textInputTraitsLock); - if (_textInputTraits) { - textView.autocapitalizationType = _textInputTraits.autocapitalizationType; - textView.autocorrectionType = _textInputTraits.autocorrectionType; - textView.spellCheckingType = _textInputTraits.spellCheckingType; - textView.keyboardType = _textInputTraits.keyboardType; - textView.keyboardAppearance = _textInputTraits.keyboardAppearance; - textView.returnKeyType = _textInputTraits.returnKeyType; - textView.enablesReturnKeyAutomatically = _textInputTraits.enablesReturnKeyAutomatically; - textView.secureTextEntry = _textInputTraits.isSecureTextEntry; + AS::MutexLocker l(self->_textInputTraitsLock); + if (self->_textInputTraits) { + textView.autocapitalizationType = self->_textInputTraits.autocapitalizationType; + textView.autocorrectionType = self->_textInputTraits.autocorrectionType; + textView.spellCheckingType = self->_textInputTraits.spellCheckingType; + textView.keyboardType = self->_textInputTraits.keyboardType; + textView.keyboardAppearance = self->_textInputTraits.keyboardAppearance; + textView.returnKeyType = self->_textInputTraits.returnKeyType; + textView.enablesReturnKeyAutomatically = self->_textInputTraits.enablesReturnKeyAutomatically; + textView.secureTextEntry = self->_textInputTraits.isSecureTextEntry; } } @@ -815,8 +815,8 @@ // 2. This delegate method (-textViewDidChangeSelection:) is called both before -textViewDidChange: and before the layout manager/etc. has necessarily generated+laid out its glyphs. Because of the former, we need to wait until -textViewDidChange: has had an opportunity to be called so can accurately determine whether this selection change is due to editing (_selectionChangedForEditedText). // Thus, to avoid calling out to client code in the middle of UITextView's processing, we call the delegate on the next run of the runloop, when all such internal processing is surely done. dispatch_async(dispatch_get_main_queue(), ^{ - if ([_delegate respondsToSelector:@selector(editableTextNodeDidChangeSelection:fromSelectedRange:toSelectedRange:dueToEditing:)]) - [_delegate editableTextNodeDidChangeSelection:self fromSelectedRange:fromSelectedRange toSelectedRange:toSelectedRange dueToEditing:_selectionChangedForEditedText]; + if ([self->_delegate respondsToSelector:@selector(editableTextNodeDidChangeSelection:fromSelectedRange:toSelectedRange:dueToEditing:)]) + [self->_delegate editableTextNodeDidChangeSelection:self fromSelectedRange:fromSelectedRange toSelectedRange:toSelectedRange dueToEditing:self->_selectionChangedForEditedText]; }); } @@ -831,9 +831,9 @@ // UITextView invokes its delegate methods when it's in the middle of text-processing. For example, -textViewDidChange: is invoked before you can truly rely on the changes being propagated throughout the Text Kit hierarchy. // Thus, to avoid calling out to client code in the middle of UITextView's processing, we call the delegate on the next run of the runloop, when all such internal processing is surely done. dispatch_async(dispatch_get_main_queue(), ^{ - _delegateDidUpdateEnqueued = NO; - if ([_delegate respondsToSelector:@selector(editableTextNodeDidUpdateText:)]) - [_delegate editableTextNodeDidUpdateText:self]; + self->_delegateDidUpdateEnqueued = NO; + if ([self->_delegate respondsToSelector:@selector(editableTextNodeDidUpdateText:)]) + [self->_delegate editableTextNodeDidUpdateText:self]; }); } diff --git a/Source/ASExperimentalFeatures.h b/Source/ASExperimentalFeatures.h index 7c2e8487..306c57d4 100644 --- a/Source/ASExperimentalFeatures.h +++ b/Source/ASExperimentalFeatures.h @@ -20,18 +20,15 @@ typedef NS_OPTIONS(NSUInteger, ASExperimentalFeatures) { // will be used in all cases ASExperimentalTextNode = 1 << 0, // exp_text_node ASExperimentalInterfaceStateCoalescing = 1 << 1, // exp_interface_state_coalesce - ASExperimentalUnfairLock = 1 << 2, // exp_unfair_lock - ASExperimentalLayerDefaults = 1 << 3, // exp_infer_layer_defaults - ASExperimentalCollectionTeardown = 1 << 4, // exp_collection_teardown - ASExperimentalFramesetterCache = 1 << 5, // exp_framesetter_cache - ASExperimentalSkipClearData = 1 << 6, // exp_skip_clear_data - ASExperimentalDidEnterPreloadSkipASMLayout = 1 << 7, // exp_did_enter_preload_skip_asm_layout - ASExperimentalDispatchApply = 1 << 8, // exp_dispatch_apply - ASExperimentalOOMBackgroundDeallocDisable = 1 << 9, // exp_oom_bg_dealloc_disable - ASExperimentalRemoveTextKitInitialisingLock = 1 << 10, // exp_remove_textkit_initialising_lock - ASExperimentalDrawingGlobal = 1 << 11, // exp_drawing_global - ASExperimentalOptimizeDataControllerPipeline = 1 << 12, // exp_optimize_data_controller_pipeline - ASExperimentalTraitCollectionDidChangeWithPreviousCollection = 1 << 13, // exp_trait_collection_did_change_with_previous_collection + ASExperimentalLayerDefaults = 1 << 2, // exp_infer_layer_defaults + ASExperimentalCollectionTeardown = 1 << 3, // exp_collection_teardown + ASExperimentalFramesetterCache = 1 << 4, // exp_framesetter_cache + ASExperimentalSkipClearData = 1 << 5, // exp_skip_clear_data + ASExperimentalDidEnterPreloadSkipASMLayout = 1 << 6, // exp_did_enter_preload_skip_asm_layout + ASExperimentalDispatchApply = 1 << 7, // exp_dispatch_apply + ASExperimentalDrawingGlobal = 1 << 8, // exp_drawing_global + ASExperimentalOptimizeDataControllerPipeline = 1 << 9, // exp_optimize_data_controller_pipeline + ASExperimentalDoNotCacheAccessibilityElements = 1 << 10, // exp_do_not_cache_accessibility_elements ASExperimentalFeatureAll = 0xFFFFFFFF }; diff --git a/Source/ASExperimentalFeatures.mm b/Source/ASExperimentalFeatures.mm index 7637481b..fef124b4 100644 --- a/Source/ASExperimentalFeatures.mm +++ b/Source/ASExperimentalFeatures.mm @@ -14,18 +14,15 @@ NSArray *ASExperimentalFeaturesGetNames(ASExperimentalFeatures flags { NSArray *allNames = ASCreateOnce((@[@"exp_text_node", @"exp_interface_state_coalesce", - @"exp_unfair_lock", @"exp_infer_layer_defaults", @"exp_collection_teardown", @"exp_framesetter_cache", @"exp_skip_clear_data", @"exp_did_enter_preload_skip_asm_layout", @"exp_dispatch_apply", - @"exp_oom_bg_dealloc_disable", - @"exp_remove_textkit_initialising_lock", @"exp_drawing_global", @"exp_optimize_data_controller_pipeline", - @"exp_trait_collection_did_change_with_previous_collection"])); + @"exp_do_not_cache_accessibility_elements"])); if (flags == ASExperimentalFeatureAll) { return allNames; } diff --git a/Source/ASImageNode+AnimatedImage.mm b/Source/ASImageNode+AnimatedImage.mm index b2ad4032..9716f852 100644 --- a/Source/ASImageNode+AnimatedImage.mm +++ b/Source/ASImageNode+AnimatedImage.mm @@ -79,11 +79,6 @@ // not fire e.g. while scrolling down CFRunLoopPerformBlock(CFRunLoopGetCurrent(), kCFRunLoopCommonModes, ^(void) { [self animatedImageSet:animatedImage previousAnimatedImage:previousAnimatedImage]; - - // Animated image can take while to dealloc, do it off the main queue - if (previousAnimatedImage != nil && ASActivateExperimentalFeature(ASExperimentalOOMBackgroundDeallocDisable) == NO) { - ASPerformBackgroundDeallocation(&previousAnimatedImage); - } }); // Don't need to wakeup the runloop as the current is already running // CFRunLoopWakeUp(runLoop); // Should not be necessary diff --git a/Source/ASImageNode.h b/Source/ASImageNode.h index d6271f55..6c71eaa0 100644 --- a/Source/ASImageNode.h +++ b/Source/ASImageNode.h @@ -21,8 +21,7 @@ NS_ASSUME_NONNULL_BEGIN * * @return A transformed image. */ -typedef UIImage * _Nullable (^asimagenode_modification_block_t)(UIImage *image); - +typedef UIImage * _Nullable (^asimagenode_modification_block_t)(UIImage *image, ASPrimitiveTraitCollection traitCollection); /** * @abstract Draws images. diff --git a/Source/ASImageNode.mm b/Source/ASImageNode.mm index 447d431b..95ac2014 100644 --- a/Source/ASImageNode.mm +++ b/Source/ASImageNode.mm @@ -30,8 +30,6 @@ // TODO: It would be nice to remove this dependency; it's the only subclass using more than +FrameworkSubclasses.h #import -static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0}; - typedef void (^ASImageNodeDrawParametersBlock)(ASWeakMapEntry *entry); @interface ASImageNodeDrawParameters : NSObject { @@ -52,9 +50,7 @@ typedef void (^ASImageNodeDrawParametersBlock)(ASWeakMapEntry *entry); ASDisplayNodeContextModifier _willDisplayNodeContentWithRenderingContext; ASDisplayNodeContextModifier _didDisplayNodeContentWithRenderingContext; ASImageNodeDrawParametersBlock _didDrawBlock; - #if AS_BUILD_UIUSERINTERFACESTYLE - UIUserInterfaceStyle userInterfaceStyle; - #endif + ASPrimitiveTraitCollection _traitCollection; } @end @@ -77,9 +73,7 @@ typedef void (^ASImageNodeDrawParametersBlock)(ASWeakMapEntry *entry); @property (nonatomic) ASDisplayNodeContextModifier willDisplayNodeContentWithRenderingContext; @property (nonatomic) ASDisplayNodeContextModifier didDisplayNodeContentWithRenderingContext; @property (nonatomic) asimagenode_modification_block_t imageModificationBlock; -#if AS_BUILD_UIUSERINTERFACESTYLE @property UIUserInterfaceStyle userInterfaceStyle API_AVAILABLE(tvos(10.0), ios(12.0)); -#endif @end @implementation ASImageNodeContentsKey @@ -96,7 +90,7 @@ typedef void (^ASImageNodeDrawParametersBlock)(ASWeakMapEntry *entry); // overheard of our caching, so it's likely not high-impact. if ([object isKindOfClass:[ASImageNodeContentsKey class]]) { ASImageNodeContentsKey *other = (ASImageNodeContentsKey *)object; - return [_image isEqual:other.image] + BOOL areKeysEqual = [_image isEqual:other.image] && CGSizeEqualToSize(_backingSize, other.backingSize) && CGRectEqualToRect(_imageDrawRect, other.imageDrawRect) && _isOpaque == other.isOpaque @@ -104,10 +98,12 @@ typedef void (^ASImageNodeDrawParametersBlock)(ASWeakMapEntry *entry); && [_tintColor isEqual:other.tintColor] && _willDisplayNodeContentWithRenderingContext == other.willDisplayNodeContentWithRenderingContext && _didDisplayNodeContentWithRenderingContext == other.didDisplayNodeContentWithRenderingContext -#if AS_BUILD_UIUSERINTERFACESTYLE - && _userInterfaceStyle == other.userInterfaceStyle -#endif && _imageModificationBlock == other.imageModificationBlock; + if (AS_AVAILABLE_IOS_TVOS(12, 10)) { + // iOS 12, tvOS 10 and later (userInterfaceStyle only available in iOS12+) + areKeysEqual = areKeysEqual && _userInterfaceStyle == other.userInterfaceStyle; + } + return areKeysEqual; } else { return NO; } @@ -150,13 +146,12 @@ typedef void (^ASImageNodeDrawParametersBlock)(ASWeakMapEntry *entry); UIImage *_image; ASWeakMapEntry *_weakCacheEntry; // Holds a reference that keeps our contents in cache. UIColor *_placeholderColor; - UIColor *_tintColor; // Used to cache color information for layer backed nodes. View backed will use UIViewBridge void (^_displayCompletionBlock)(BOOL canceled); - + // Drawing ASTextNode *_debugLabelNode; - + // Cropping. CGSize _forcedSize; //Defaults to CGSizeZero, indicating no forced size. CGRect _cropRect; // Defaults to CGRectMake(0.5, 0.5, 0, 0) @@ -186,11 +181,12 @@ typedef void (^ASImageNodeDrawParametersBlock)(ASWeakMapEntry *entry); _imageNodeFlags.cropEnabled = YES; _imageNodeFlags.forceUpscaling = NO; + _imageNodeFlags.regenerateFromImageAsset = NO; _cropRect = CGRectMake(0.5, 0.5, 0, 0); _cropDisplayBounds = CGRectNull; _placeholderColor = ASDisplayNodeDefaultPlaceholderColor(); _animatedImageRunLoopMode = ASAnimatedImageDefaultRunLoopMode; - + return self; } @@ -210,8 +206,11 @@ typedef void (^ASImageNodeDrawParametersBlock)(ASWeakMapEntry *entry); if ((size.width * size.height) < CGFLOAT_EPSILON) { return nil; } - - return ASGraphicsCreateImageWithOptions(size, NO, 1, nil, nil, ^{ + + __instanceLock__.lock(); + ASPrimitiveTraitCollection tc = _primitiveTraitCollection; + __instanceLock__.unlock(); + return ASGraphicsCreateImage(tc, size, NO, 1, nil, nil, ^{ AS::MutexLocker l(__instanceLock__); [_placeholderColor setFill]; UIRectFill(CGRectMake(0, 0, size.width, size.height)); @@ -246,37 +245,26 @@ typedef void (^ASImageNodeDrawParametersBlock)(ASWeakMapEntry *entry); return; } - UIImage *oldImage = _image; _image = image; - + if (image != nil) { // We explicitly call setNeedsDisplay in this case, although we know setNeedsDisplay will be called with lock held. // Therefore we have to be careful in methods that are involved with setNeedsDisplay to not run into a deadlock [self setNeedsDisplay]; - + // For debugging purposes we don't care about locking for now if ([ASImageNode shouldShowImageScalingOverlay] && _debugLabelNode == nil) { // do not use ASPerformBlockOnMainThread here, if it performs the block synchronously it will continue // holding the lock while calling addSubnode. dispatch_async(dispatch_get_main_queue(), ^{ - _debugLabelNode = [[ASTextNode alloc] init]; - _debugLabelNode.layerBacked = YES; - [self addSubnode:_debugLabelNode]; + self->_debugLabelNode = [[ASTextNode alloc] init]; + self->_debugLabelNode.layerBacked = YES; + [self addSubnode:self->_debugLabelNode]; }); } } else { self.contents = nil; } - - // Destruction of bigger images on the main thread can be expensive - // and can take some time, so we dispatch onto a bg queue to - // actually dealloc. - CGSize oldImageSize = oldImage.size; - BOOL shouldReleaseImageOnBackgroundThread = oldImageSize.width > kMinReleaseImageOnBackgroundSize.width - || oldImageSize.height > kMinReleaseImageOnBackgroundSize.height; - if (shouldReleaseImageOnBackgroundThread && ASActivateExperimentalFeature(ASExperimentalOOMBackgroundDeallocDisable) == NO) { - ASPerformBackgroundDeallocation(&oldImage); - } } - (UIImage *)image @@ -301,35 +289,49 @@ typedef void (^ASImageNodeDrawParametersBlock)(ASWeakMapEntry *entry); - (NSObject *)drawParametersForAsyncLayer:(_ASDisplayLayer *)layer { - ASLockScopeSelf(); - ASImageNodeDrawParameters *drawParameters = [[ASImageNodeDrawParameters alloc] init]; - drawParameters->_image = _image; + + { + ASLockScopeSelf(); + UIImage *drawImage = _image; + if (AS_AVAILABLE_IOS_TVOS(13, 10)) { + if (_imageNodeFlags.regenerateFromImageAsset && drawImage != nil) { + _imageNodeFlags.regenerateFromImageAsset = NO; + UITraitCollection *tc = [UITraitCollection traitCollectionWithUserInterfaceStyle:_primitiveTraitCollection.userInterfaceStyle]; + UIImage *generatedImage = [drawImage.imageAsset imageWithTraitCollection:tc]; + if ( generatedImage != nil ) { + drawImage = generatedImage; + } + } + } + + drawParameters->_image = drawImage; + drawParameters->_contentsScale = _contentsScaleForDisplay; + drawParameters->_cropEnabled = _imageNodeFlags.cropEnabled; + drawParameters->_forceUpscaling = _imageNodeFlags.forceUpscaling; + drawParameters->_forcedSize = _forcedSize; + drawParameters->_cropRect = _cropRect; + drawParameters->_cropDisplayBounds = _cropDisplayBounds; + drawParameters->_imageModificationBlock = _imageModificationBlock; + drawParameters->_willDisplayNodeContentWithRenderingContext = _willDisplayNodeContentWithRenderingContext; + drawParameters->_didDisplayNodeContentWithRenderingContext = _didDisplayNodeContentWithRenderingContext; + drawParameters->_traitCollection = _primitiveTraitCollection; + + // Hack for now to retain the weak entry that was created while this drawing happened + drawParameters->_didDrawBlock = ^(ASWeakMapEntry *entry){ + ASLockScopeSelf(); + self->_weakCacheEntry = entry; + }; + } + + // We need to unlock before we access the other accessor. + // Especially tintColor because it needs to walk up the view hierarchy drawParameters->_bounds = [self threadSafeBounds]; drawParameters->_opaque = self.opaque; - drawParameters->_contentsScale = _contentsScaleForDisplay; drawParameters->_backgroundColor = self.backgroundColor; - drawParameters->_tintColor = self.tintColor; drawParameters->_contentMode = self.contentMode; - drawParameters->_cropEnabled = _imageNodeFlags.cropEnabled; - drawParameters->_forceUpscaling = _imageNodeFlags.forceUpscaling; - drawParameters->_forcedSize = _forcedSize; - drawParameters->_cropRect = _cropRect; - drawParameters->_cropDisplayBounds = _cropDisplayBounds; - drawParameters->_imageModificationBlock = _imageModificationBlock; - drawParameters->_willDisplayNodeContentWithRenderingContext = _willDisplayNodeContentWithRenderingContext; - drawParameters->_didDisplayNodeContentWithRenderingContext = _didDisplayNodeContentWithRenderingContext; -#if AS_BUILD_UIUSERINTERFACESTYLE - drawParameters->userInterfaceStyle = self.primitiveTraitCollection.userInterfaceStyle; -#endif + drawParameters->_tintColor = self.tintColor; - - // Hack for now to retain the weak entry that was created while this drawing happened - drawParameters->_didDrawBlock = ^(ASWeakMapEntry *entry){ - ASLockScopeSelf(); - _weakCacheEntry = entry; - }; - return drawParameters; } @@ -341,7 +343,7 @@ typedef void (^ASImageNodeDrawParametersBlock)(ASWeakMapEntry *entry); if (image == nil) { return nil; } - + CGRect drawParameterBounds = drawParameter->_bounds; BOOL forceUpscaling = drawParameter->_forceUpscaling; CGSize forcedSize = drawParameter->_forcedSize; @@ -356,39 +358,39 @@ typedef void (^ASImageNodeDrawParametersBlock)(ASWeakMapEntry *entry); asimagenode_modification_block_t imageModificationBlock = drawParameter->_imageModificationBlock; ASDisplayNodeContextModifier willDisplayNodeContentWithRenderingContext = drawParameter->_willDisplayNodeContentWithRenderingContext; ASDisplayNodeContextModifier didDisplayNodeContentWithRenderingContext = drawParameter->_didDisplayNodeContentWithRenderingContext; - + BOOL hasValidCropBounds = cropEnabled && !CGRectIsEmpty(cropDisplayBounds); CGRect bounds = (hasValidCropBounds ? cropDisplayBounds : drawParameterBounds); - - + + ASDisplayNodeAssert(contentsScale > 0, @"invalid contentsScale at display time"); - + // if the image is resizable, bail early since the image has likely already been configured BOOL stretchable = !UIEdgeInsetsEqualToEdgeInsets(image.capInsets, UIEdgeInsetsZero); if (stretchable) { if (imageModificationBlock != NULL) { - image = imageModificationBlock(image); + image = imageModificationBlock(image, drawParameter->_traitCollection); } return image; } - + CGSize imageSize = image.size; CGSize imageSizeInPixels = CGSizeMake(imageSize.width * image.scale, imageSize.height * image.scale); CGSize boundsSizeInPixels = CGSizeMake(std::floor(bounds.size.width * contentsScale), std::floor(bounds.size.height * contentsScale)); - + BOOL contentModeSupported = contentMode == UIViewContentModeScaleAspectFill || contentMode == UIViewContentModeScaleAspectFit || contentMode == UIViewContentModeCenter; - + CGSize backingSize = CGSizeZero; CGRect imageDrawRect = CGRectZero; - + if (boundsSizeInPixels.width * contentsScale < 1.0f || boundsSizeInPixels.height * contentsScale < 1.0f || imageSizeInPixels.width < 1.0f || imageSizeInPixels.height < 1.0f) { return nil; } - - + + // If we're not supposed to do any cropping, just decode image at original size if (!cropEnabled || !contentModeSupported) { backingSize = imageSizeInPixels; @@ -408,18 +410,12 @@ typedef void (^ASImageNodeDrawParametersBlock)(ASWeakMapEntry *entry); &backingSize, &imageDrawRect); } - + if (backingSize.width <= 0.0f || backingSize.height <= 0.0f || imageDrawRect.size.width <= 0.0f || imageDrawRect.size.height <= 0.0f) { return nil; } -#if AS_BUILD_UIUSERINTERFACESTYLE - UIUserInterfaceStyle userInterfaceStyle = drawParameter->userInterfaceStyle; -#endif - - - ASImageNodeContentsKey *contentsKey = [[ASImageNodeContentsKey alloc] init]; contentsKey.image = image; contentsKey.backingSize = backingSize; @@ -430,9 +426,11 @@ typedef void (^ASImageNodeDrawParametersBlock)(ASWeakMapEntry *entry); contentsKey.willDisplayNodeContentWithRenderingContext = willDisplayNodeContentWithRenderingContext; contentsKey.didDisplayNodeContentWithRenderingContext = didDisplayNodeContentWithRenderingContext; contentsKey.imageModificationBlock = imageModificationBlock; -#if AS_BUILD_UIUSERINTERFACESTYLE - contentsKey.userInterfaceStyle = userInterfaceStyle; -#endif + + if (AS_AVAILABLE_IOS_TVOS(12, 10)) { + contentsKey.userInterfaceStyle = drawParameter->_traitCollection.userInterfaceStyle; + } + if (isCancelled()) { return nil; } @@ -444,7 +442,7 @@ typedef void (^ASImageNodeDrawParametersBlock)(ASWeakMapEntry *entry); if (entry == nil) { return nil; } - + if (drawParameter->_didDrawBlock) { drawParameter->_didDrawBlock(entry); } @@ -461,7 +459,7 @@ static ASWeakMap *cache = nil; dispatch_once(&onceToken, ^{ cacheLock = new AS::Mutex(); }); - + { AS::MutexLocker l(*cacheLock); if (!cache) { @@ -485,18 +483,20 @@ static ASWeakMap *cache = nil; } } -+ (UIImage *)createContentsForkey:(ASImageNodeContentsKey *)key drawParameters:(id)drawParameters isCancelled:(asdisplaynode_iscancelled_block_t)isCancelled ++ (UIImage *)createContentsForkey:(ASImageNodeContentsKey *)key drawParameters:(id)parameter isCancelled:(asdisplaynode_iscancelled_block_t)isCancelled { - // The following `ASGraphicsCreateImageWithOptions` call will sometimes take take longer than 5ms on an + // The following `ASGraphicsCreateImage` call will sometimes take take longer than 5ms on an // A5 processor for a 400x800 backingSize. // Check for cancellation before we call it. if (isCancelled()) { return nil; } + + ASImageNodeDrawParameters *drawParameters = (ASImageNodeDrawParameters *)parameter; // Use contentsScale of 1.0 and do the contentsScale handling in boundsSizeInPixels so ASCroppedImageBackingSizeAndDrawRectInBounds // will do its rounding on pixel instead of point boundaries - UIImage *result = ASGraphicsCreateImageWithOptions(key.backingSize, key.isOpaque, 1.0, key.image, isCancelled, ^{ + UIImage *result = ASGraphicsCreateImage(drawParameters->_traitCollection, key.backingSize, key.isOpaque, 1.0, key.image, isCancelled, ^{ BOOL contextIsClean = YES; CGContextRef context = UIGraphicsGetCurrentContext(); @@ -548,9 +548,9 @@ static ASWeakMap *cache = nil; } if (key.imageModificationBlock) { - result = key.imageModificationBlock(result); + result = key.imageModificationBlock(result, drawParameters->_traitCollection); } - + return result; } @@ -587,7 +587,7 @@ static ASWeakMap *cache = nil; _debugLabelNode.attributedText = nil; } } - + // If we've got a block to perform after displaying, do it. if (shouldPerformDisplayCompletionBlock) { displayCompletionBlock(NO); @@ -613,20 +613,39 @@ static ASWeakMap *cache = nil; [self setNeedsDisplay]; } -- (void)tintColorDidChange +- (void)_setNeedsDisplayOnTemplatedImages { - [super tintColorDidChange]; - if (_image.renderingMode == UIImageRenderingModeAlwaysTemplate) { + BOOL isTemplateImage = NO; + { + AS::MutexLocker l(__instanceLock__); + isTemplateImage = (_image.renderingMode == UIImageRenderingModeAlwaysTemplate); + } + + if (isTemplateImage) { [self setNeedsDisplay]; } } +- (void)tintColorDidChange +{ + [super tintColorDidChange]; + + [self _setNeedsDisplayOnTemplatedImages]; +} + #pragma mark Interface State +- (void)didEnterHierarchy +{ + [super didEnterHierarchy]; + + [self _setNeedsDisplayOnTemplatedImages]; +} + - (void)clearContents { [super clearContents]; - + AS::MutexLocker l(__instanceLock__); _weakCacheEntry = nil; // release contents from the cache. } @@ -654,7 +673,7 @@ static ASWeakMap *cache = nil; _imageNodeFlags.cropEnabled = cropEnabled; _cropDisplayBounds = cropBounds; - + UIImage *image = _image; __instanceLock__.unlock(); @@ -740,7 +759,7 @@ static ASWeakMap *cache = nil; - (void)layout { [super layout]; - + if (_debugLabelNode) { CGSize boundsSize = self.bounds.size; CGSize debugLabelSize = [_debugLabelNode layoutThatFits:ASSizeRangeMake(CGSizeZero, boundsSize)].size; @@ -758,33 +777,28 @@ static ASWeakMap *cache = nil; }; } -#if AS_BUILD_UIUSERINTERFACESTYLE - (void)asyncTraitCollectionDidChangeWithPreviousTraitCollection:(ASPrimitiveTraitCollection)previousTraitCollection { [super asyncTraitCollectionDidChangeWithPreviousTraitCollection:previousTraitCollection]; - - if (AS_AVAILABLE_IOS_TVOS(12, 10)) { + + if (AS_AVAILABLE_IOS_TVOS(13, 10)) { + AS::MutexLocker l(__instanceLock__); // update image if userInterfaceStyle was changed (dark mode) - if (_image != nil && self.primitiveTraitCollection.userInterfaceStyle != previousTraitCollection.userInterfaceStyle) { - UITraitCollection *tc = [UITraitCollection traitCollectionWithUserInterfaceStyle:self.primitiveTraitCollection.userInterfaceStyle]; - // get an updated image from asset catalog - UIImage *updatedImage = [self.image.imageAsset imageWithTraitCollection:tc]; - if ( updatedImage != nil ) { - _image = updatedImage; - } - // trigger needs display anyway, cause image might be dynamic itself (e.g. dynamic tint color) - [self setNeedsDisplay]; + if (_image != nil + && _primitiveTraitCollection.userInterfaceStyle != previousTraitCollection.userInterfaceStyle) { + _imageNodeFlags.regenerateFromImageAsset = YES; } } } -#endif + + @end #pragma mark - Extras asimagenode_modification_block_t ASImageNodeRoundBorderModificationBlock(CGFloat borderWidth, UIColor *borderColor) { - return ^(UIImage *originalImage) { - return ASGraphicsCreateImageWithOptions(originalImage.size, NO, originalImage.scale, originalImage, nil, ^{ + return ^(UIImage *originalImage, ASPrimitiveTraitCollection traitCollection) { + return ASGraphicsCreateImage(traitCollection, originalImage.size, NO, originalImage.scale, originalImage, nil, ^{ UIBezierPath *roundOutline = [UIBezierPath bezierPathWithOvalInRect:(CGRect){CGPointZero, originalImage.size}]; // Make the image round @@ -805,8 +819,8 @@ asimagenode_modification_block_t ASImageNodeRoundBorderModificationBlock(CGFloat asimagenode_modification_block_t ASImageNodeTintColorModificationBlock(UIColor *color) { - return ^(UIImage *originalImage) { - UIImage *modifiedImage = ASGraphicsCreateImageWithOptions(originalImage.size, NO, originalImage.scale, originalImage, nil, ^{ + return ^(UIImage *originalImage, ASPrimitiveTraitCollection traitCollection) { + UIImage *modifiedImage = ASGraphicsCreateImage(traitCollection, originalImage.size, NO, originalImage.scale, originalImage, nil, ^{ // Set color and render template [color setFill]; UIImage *templateImage = [originalImage imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; diff --git a/Source/ASMapNode.mm b/Source/ASMapNode.mm index c41141c0..599851e9 100644 --- a/Source/ASMapNode.mm +++ b/Source/ASMapNode.mm @@ -221,7 +221,7 @@ CGRect finalImageRect = CGRectMake(0, 0, image.size.width, image.size.height); - image = ASGraphicsCreateImageWithOptions(image.size, YES, image.scale, image, nil, ^{ + image = ASGraphicsCreateImage(strongSelf.primitiveTraitCollection, image.size, YES, image.scale, image, nil, ^{ [image drawAtPoint:CGPointZero]; UIImage *pinImage; diff --git a/Source/ASMultiplexImageNode.mm b/Source/ASMultiplexImageNode.mm index 7c3bd881..55de28dd 100644 --- a/Source/ASMultiplexImageNode.mm +++ b/Source/ASMultiplexImageNode.mm @@ -39,8 +39,6 @@ NSString *const ASMultiplexImageNodeErrorDomain = @"ASMultiplexImageNodeErrorDom static NSString *const kAssetsLibraryURLScheme = @"assets-library"; #endif -static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0}; - /** @abstract Signature for the block to be performed after an image has loaded. @param image The image that was loaded, or nil if no image was loaded. @@ -533,17 +531,7 @@ typedef void(^ASMultiplexImageLoadCompletionBlock)(UIImage *image, id imageIdent - (void)_clearImage { - // Destruction of bigger images on the main thread can be expensive - // and can take some time, so we dispatch onto a bg queue to - // actually dealloc. - UIImage *image = self.image; - CGSize imageSize = image.size; - BOOL shouldReleaseImageOnBackgroundThread = imageSize.width > kMinReleaseImageOnBackgroundSize.width || - imageSize.height > kMinReleaseImageOnBackgroundSize.height; [self _setImage:nil]; - if (shouldReleaseImageOnBackgroundThread && ASActivateExperimentalFeature(ASExperimentalOOMBackgroundDeallocDisable) == NO) { - ASPerformBackgroundDeallocation(&image); - } } #pragma mark - @@ -742,7 +730,7 @@ typedef void(^ASMultiplexImageLoadCompletionBlock)(UIImage *image, id imageIdent PHAsset *imageAsset = nil; // Try to get the asset immediately from the data source. - if (_dataSourceFlags.asset) { + if (strongSelf->_dataSourceFlags.asset) { imageAsset = [strongSelf.dataSource multiplexImageNode:strongSelf assetForLocalIdentifier:request.assetIdentifier]; } @@ -806,7 +794,7 @@ typedef void(^ASMultiplexImageLoadCompletionBlock)(UIImage *image, id imageIdent ASDisplayNodeAssertNotNil(completionBlock, @"completionBlock is required"); if (_cache) { - [_cache cachedImageWithURL:imageURL callbackQueue:dispatch_get_main_queue() completion:^(id imageContainer) { + [_cache cachedImageWithURL:imageURL callbackQueue:dispatch_get_main_queue() completion:^(id imageContainer, __unused ASImageCacheType cacheType ) { completionBlock([imageContainer asdk_image]); }]; } diff --git a/Source/ASNetworkImageNode.mm b/Source/ASNetworkImageNode.mm index f3a9638c..daf3a47c 100644 --- a/Source/ASNetworkImageNode.mm +++ b/Source/ASNetworkImageNode.mm @@ -867,7 +867,7 @@ static std::atomic_bool _useMainThreadDelegateCallbacks(true); as_log_verbose(ASImageLoadingLog(), "Decaching image for %@ url: %@", self, URL); - ASImageCacherCompletion completion = ^(id imageContainer) { + ASImageCacherCompletion completion = ^(id imageContainer, ASImageCacheType cacheType) { // If the cache sentinel changed, that means this request was cancelled. if (ASLockedSelf(self->_cacheSentinel != cacheSentinel)) { return; @@ -887,8 +887,8 @@ static std::atomic_bool _useMainThreadDelegateCallbacks(true); if (delegateDidLoadImageFromCache) { [delegate imageNodeDidLoadImageFromCache:self]; } - as_log_verbose(ASImageLoadingLog(), "Decached image for %@ img: %@ url: %@", self, [imageContainer asdk_image], URL); - finished(imageContainer, nil, nil, ASNetworkImageSourceAsynchronousCache, nil); + as_log_verbose(ASImageLoadingLog(), "Decached image for %@ img: %@ url: %@ cacheType: %@", self, [imageContainer asdk_image], URL, cacheType); + finished(imageContainer, nil, nil, cacheType == ASImageCacheTypeSynchronous ? ASNetworkImageSourceSynchronousCache : ASNetworkImageSourceAsynchronousCache, nil); } }; diff --git a/Source/ASPagerNode.mm b/Source/ASPagerNode.mm index e6912dd5..7ad8f1ad 100644 --- a/Source/ASPagerNode.mm +++ b/Source/ASPagerNode.mm @@ -17,6 +17,7 @@ #import #import #import +#import @interface ASPagerNode () { diff --git a/Source/ASRunLoopQueue.h b/Source/ASRunLoopQueue.h index 07f3682b..298fe76c 100644 --- a/Source/ASRunLoopQueue.h +++ b/Source/ASRunLoopQueue.h @@ -80,7 +80,6 @@ NS_INLINE ASCATransactionQueue *ASCATransactionQueueGet(void) { @interface ASDeallocQueue : NSObject -@property (class, readonly) ASDeallocQueue *sharedDeallocationQueue; + (ASDeallocQueue *)sharedDeallocationQueue NS_RETURNS_RETAINED; - (void)drain; diff --git a/Source/ASRunLoopQueue.mm b/Source/ASRunLoopQueue.mm index 43763f36..fd896af8 100644 --- a/Source/ASRunLoopQueue.mm +++ b/Source/ASRunLoopQueue.mm @@ -13,7 +13,6 @@ #import #import #import -#import #import #define ASRunLoopQueueLoggingEnabled 0 diff --git a/Source/ASTableNode.mm b/Source/ASTableNode.mm index 6d67f405..d8acc8a3 100644 --- a/Source/ASTableNode.mm +++ b/Source/ASTableNode.mm @@ -20,6 +20,7 @@ #import #import #import +#import #pragma mark - _ASTablePendingState diff --git a/Source/ASTableView.mm b/Source/ASTableView.mm index 98e3c830..97eb09f2 100644 --- a/Source/ASTableView.mm +++ b/Source/ASTableView.mm @@ -20,6 +20,7 @@ #import #import #import +#import #import #import #import @@ -27,6 +28,8 @@ #import #import #import +#import + static NSString * const kCellReuseIdentifier = @"_ASTableViewCell"; @@ -113,12 +116,14 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell"; self.selectionStyle = node.selectionStyle; self.focusStyle = node.focusStyle; self.accessoryType = node.accessoryType; - self.tintColor = node.tintColor; // the following ensures that we clip the entire cell to it's bounds if node.clipsToBounds is set (the default) // This is actually a workaround for a bug we are seeing in some rare cases (selected background view // overlaps other cells if size of ASCellNode has changed.) self.clipsToBounds = node.clipsToBounds; + + // If the cell node has been explicitly configured with a tint color, we can apply that directly to the cell view to preserve the previous behavior + self.tintColor = node->_tintColor; } [node __setSelectedFromUIKit:self.selected]; @@ -368,12 +373,6 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell"; [self setAsyncDelegate:nil]; [self setAsyncDataSource:nil]; } - - // Data controller & range controller may own a ton of nodes, let's deallocate those off-main - if (ASActivateExperimentalFeature(ASExperimentalOOMBackgroundDeallocDisable) == NO) { - ASPerformBackgroundDeallocation(&_dataController); - ASPerformBackgroundDeallocation(&_rangeController); - } } #pragma mark - @@ -1497,13 +1496,13 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell"; if (_asyncDelegateFlags.tableNodeWillBeginBatchFetch) { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ GET_TABLENODE_OR_RETURN(tableNode, (void)0); - [_asyncDelegate tableNode:tableNode willBeginBatchFetchWithContext:_batchContext]; + [self->_asyncDelegate tableNode:tableNode willBeginBatchFetchWithContext:self->_batchContext]; }); } else if (_asyncDelegateFlags.tableViewWillBeginBatchFetch) { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" - [_asyncDelegate tableView:self willBeginBatchFetchWithContext:_batchContext]; + [self->_asyncDelegate tableView:self willBeginBatchFetchWithContext:self->_batchContext]; #pragma clang diagnostic pop }); } @@ -1561,7 +1560,7 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell"; updates(); [super reloadData]; // Flush any range changes that happened as part of submitting the reload. - [_rangeController updateIfNeeded]; + [self->_rangeController updateIfNeeded]; [self _scheduleCheckForBatchFetchingForNumberOfChanges:1]; [changeSet executeCompletionHandlerWithFinished:YES]; }); @@ -1679,7 +1678,7 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell"; LOG(@"--- UITableView endUpdates"); ASPerformBlockWithoutAnimation(!changeSet.animated, ^{ [super endUpdates]; - [_rangeController updateIfNeeded]; + [self->_rangeController updateIfNeeded]; [self _scheduleCheckForBatchFetchingForNumberOfChanges:numberOfUpdates]; }); if (shouldAdjustContentOffset) { @@ -1784,7 +1783,7 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell"; if (node.interactionDelegate == nil) { node.interactionDelegate = strongSelf; } - if (_inverted) { + if (self->_inverted) { node.transform = CATransform3DMakeScale(1, -1, 1) ; } return node; diff --git a/Source/ASTableViewProtocols.h b/Source/ASTableViewProtocols.h index 969a5c61..ea392e2f 100644 --- a/Source/ASTableViewProtocols.h +++ b/Source/ASTableViewProtocols.h @@ -75,7 +75,13 @@ NS_ASSUME_NONNULL_BEGIN - (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath; - (nullable NSString *)tableView:(UITableView *)tableView titleForDeleteConfirmationButtonForRowAtIndexPath:(NSIndexPath *)indexPath; #if TARGET_OS_IOS -- (nullable NSArray *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath; +- (nullable NSArray *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath API_DEPRECATED_WITH_REPLACEMENT("tableView:trailingSwipeActionsConfigurationForRowAtIndexPath:", ios(8.0, 13.0)); +- (nullable UISwipeActionsConfiguration *)tableView:(UITableView *)tableView leadingSwipeActionsConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath API_AVAILABLE(ios(11.0)); +- (nullable UISwipeActionsConfiguration *)tableView:(UITableView *)tableView trailingSwipeActionsConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath API_AVAILABLE(ios(11.0)); +- (nullable UIContextMenuConfiguration *)tableView:(UITableView *)tableView contextMenuConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath point:(CGPoint)point API_AVAILABLE(ios(13.0)); +- (nullable UITargetedPreview *)tableView:(UITableView *)tableView previewForHighlightingContextMenuWithConfiguration:(UIContextMenuConfiguration *)configuration API_AVAILABLE(ios(13.0)); +- (nullable UITargetedPreview *)tableView:(UITableView *)tableView previewForDismissingContextMenuWithConfiguration:(UIContextMenuConfiguration *)configuration API_AVAILABLE(ios(13.0)); +- (void)tableView:(UITableView *)tableView willPerformPreviewActionForMenuWithConfiguration:(UIContextMenuConfiguration *)configuration animator:(id)animator API_AVAILABLE(ios(13.0)); #endif - (BOOL)tableView:(UITableView *)tableView shouldIndentWhileEditingRowAtIndexPath:(NSIndexPath *)indexPath; diff --git a/Source/ASTextNode.mm b/Source/ASTextNode.mm index ae613305..afffba50 100644 --- a/Source/ASTextNode.mm +++ b/Source/ASTextNode.mm @@ -140,6 +140,7 @@ static ASTextKitRenderer *rendererForAttributes(ASTextKitAttributes attributes, CGFloat _contentScale; BOOL _opaque; CGRect _bounds; + ASPrimitiveTraitCollection _traitCollection; } @end @@ -151,6 +152,7 @@ static ASTextKitRenderer *rendererForAttributes(ASTextKitAttributes attributes, contentScale:(CGFloat)contentScale opaque:(BOOL)opaque bounds:(CGRect)bounds + traitCollection: (ASPrimitiveTraitCollection)traitCollection { self = [super init]; if (self != nil) { @@ -160,6 +162,7 @@ static ASTextKitRenderer *rendererForAttributes(ASTextKitAttributes attributes, _contentScale = contentScale; _opaque = opaque; _bounds = bounds; + _traitCollection = traitCollection; } return self; } @@ -183,6 +186,7 @@ static ASTextKitRenderer *rendererForAttributes(ASTextKitAttributes attributes, CGSize _shadowOffset; CGColorRef _shadowColor; UIColor *_cachedShadowUIColor; + UIColor *_cachedTintColor; UIColor *_placeholderColor; CGFloat _shadowOpacity; CGFloat _shadowRadius; @@ -382,7 +386,7 @@ static NSArray *DefaultLinkAttributeNames() { .shadowColor = _cachedShadowUIColor, .shadowOpacity = _shadowOpacity, .shadowRadius = _shadowRadius, - .tintColor = self.textColorFollowsTintColor ? self.tintColor : nil + .tintColor = _cachedTintColor }; } @@ -542,14 +546,21 @@ static NSArray *DefaultLinkAttributeNames() { - (NSObject *)drawParametersForAsyncLayer:(_ASDisplayLayer *)layer { + /// have to access tintColor outside of the lock to prevent dead lock when accessing up the view hierarchy + UIColor *tintColor = self.tintColor; ASLockScopeSelf(); - + if (_textColorFollowsTintColor) { + _cachedTintColor = tintColor; + } else { + _cachedTintColor = nil; + } return [[ASTextNodeDrawParameter alloc] initWithRendererAttributes:[self _locked_rendererAttributes] backgroundColor:self.backgroundColor textContainerInsets:_textContainerInset contentScale:_contentsScaleForDisplay opaque:self.isOpaque - bounds:[self threadSafeBounds]]; + bounds:[self threadSafeBounds] + traitCollection:self.primitiveTraitCollection]; } + (UIImage *)displayWithParameters:(id)parameters isCancelled:(NS_NOESCAPE asdisplaynode_iscancelled_block_t)isCancelled @@ -564,7 +575,7 @@ static NSArray *DefaultLinkAttributeNames() { UIEdgeInsets textContainerInsets = drawParameter ? drawParameter->_textContainerInsets : UIEdgeInsetsZero; ASTextKitRenderer *renderer = [drawParameter rendererForBounds:drawParameter->_bounds]; - UIImage *result = ASGraphicsCreateImageWithOptions(CGSizeMake(drawParameter->_bounds.size.width, drawParameter->_bounds.size.height), drawParameter->_opaque, drawParameter->_contentScale, nil, nil, ^{ + UIImage *result = ASGraphicsCreateImage(drawParameter->_traitCollection, CGSizeMake(drawParameter->_bounds.size.width, drawParameter->_bounds.size.height), drawParameter->_opaque, drawParameter->_contentScale, nil, nil, ^{ CGContextRef context = UIGraphicsGetCurrentContext(); ASDisplayNodeAssert(context, @"This is no good without a context."); @@ -945,6 +956,39 @@ static CGRect ASTextNodeAdjustRenderRectForShadowPadding(CGRect rendererRect, UI return ASTextNodeAdjustRenderRectForShadowPadding(frame, self.shadowPadding); } +#pragma mark - Tint Colors + + +- (void)tintColorDidChange +{ + [super tintColorDidChange]; + + [self _setNeedsDisplayOnTintedTextColor]; +} + +- (void)_setNeedsDisplayOnTintedTextColor +{ + BOOL textColorFollowsTintColor = NO; + { + AS::MutexLocker l(__instanceLock__); + textColorFollowsTintColor = _textColorFollowsTintColor; + } + + if (textColorFollowsTintColor) { + [self setNeedsDisplay]; + } +} + + +#pragma mark Interface State + +- (void)didEnterHierarchy +{ + [super didEnterHierarchy]; + + [self _setNeedsDisplayOnTintedTextColor]; +} + #pragma mark - Placeholders - (UIColor *)placeholderColor @@ -1311,6 +1355,11 @@ static NSAttributedString *DefaultTruncationAttributedString() return ASLockedSelf([[self _locked_renderer] lineCount]); } +- (BOOL)textColorFollowsTintColor +{ + return ASLockedSelf(_textColorFollowsTintColor); +} + #pragma mark - Truncation Message - (void)_invalidateTruncationText diff --git a/Source/ASTextNode2.mm b/Source/ASTextNode2.mm index 1d589503..e268eca2 100644 --- a/Source/ASTextNode2.mm +++ b/Source/ASTextNode2.mm @@ -511,40 +511,51 @@ static NSArray *DefaultLinkAttributeNames() { shadow.shadowBlurRadius = _shadowRadius; [attributedString addAttribute:NSShadowAttributeName value:shadow range:NSMakeRange(0, attributedString.length)]; } - - // Apply tint color if needed and foreground color is not already specified - if (self.textColorFollowsTintColor && attributedString.length > 0) { - // Apply tint color if specified and if foreground color is undefined for attributedString - NSRange limit = NSMakeRange(0, attributedString.length); - // Look for previous attributes that define foreground color - UIColor *attributeValue = (UIColor *)[attributedString attribute:NSForegroundColorAttributeName atIndex:limit.location effectiveRange:NULL]; - UIColor *tintColor = self.tintColor; - if (attributeValue == nil && tintColor) { - // None are found, apply tint color if available. Fallback to "black" text color - [attributedString addAttributes:@{ NSForegroundColorAttributeName : tintColor } range:limit]; - } - } } #pragma mark - Drawing - (NSObject *)drawParametersForAsyncLayer:(_ASDisplayLayer *)layer { - ASLockScopeSelf(); - [self _ensureTruncationText]; + ASTextContainer *copiedContainer; + NSMutableAttributedString *mutableText; + BOOL needsTintColor; + id bgColor; + { + // Wrapping all the other access here, because we can't lock while accessing tintColor. + ASLockScopeSelf(); + [self _ensureTruncationText]; - // Unlike layout, here we must copy the container since drawing is asynchronous. - ASTextContainer *copiedContainer = [_textContainer copy]; - copiedContainer.size = self.bounds.size; - [copiedContainer makeImmutable]; - NSMutableAttributedString *mutableText = [_attributedText mutableCopy] ?: [[NSMutableAttributedString alloc] init]; + // Unlike layout, here we must copy the container since drawing is asynchronous. + copiedContainer = [_textContainer copy]; + copiedContainer.size = self.bounds.size; + [copiedContainer makeImmutable]; + mutableText = [_attributedText mutableCopy] ?: [[NSMutableAttributedString alloc] init]; - [self prepareAttributedString:mutableText isForIntrinsicSize:NO]; + [self prepareAttributedString:mutableText isForIntrinsicSize:NO]; + needsTintColor = self.textColorFollowsTintColor && mutableText.length > 0; + bgColor = self.backgroundColor ?: [NSNull null]; + } + // After all other attributes are set, apply tint color if needed and foreground color is not already specified + if (needsTintColor) { + // Apply tint color if specified and if foreground color is undefined for attributedString + NSRange limit = NSMakeRange(0, mutableText.length); + // Look for previous attributes that define foreground color + UIColor *attributeValue = (UIColor *)[mutableText attribute:NSForegroundColorAttributeName atIndex:limit.location effectiveRange:NULL]; + + // we need to unlock before accessing tintColor + UIColor *tintColor = self.tintColor; + if (attributeValue == nil && tintColor) { + // None are found, apply tint color if available. Fallback to "black" text color + [mutableText addAttributes:@{ NSForegroundColorAttributeName : tintColor } range:limit]; + } + } + return @{ @"container": copiedContainer, @"text": mutableText, - @"bgColor": self.backgroundColor ?: [NSNull null] + @"bgColor": bgColor }; } @@ -577,6 +588,38 @@ static NSArray *DefaultLinkAttributeNames() { [layout drawInContext:context size:bounds.size point:bounds.origin view:nil layer:nil debug:[ASTextDebugOption sharedDebugOption] cancel:isCancelledBlock]; } +#pragma mark - Tint Color + +- (void)tintColorDidChange +{ + [super tintColorDidChange]; + + [self _setNeedsDisplayOnTintedTextColor]; +} + +- (void)_setNeedsDisplayOnTintedTextColor +{ + BOOL textColorFollowsTintColor = NO; + { + AS::MutexLocker l(__instanceLock__); + textColorFollowsTintColor = _textColorFollowsTintColor; + } + + if (textColorFollowsTintColor) { + [self setNeedsDisplay]; + } +} + + +#pragma mark Interface State + +- (void)didEnterHierarchy +{ + [super didEnterHierarchy]; + + [self _setNeedsDisplayOnTintedTextColor]; +} + #pragma mark - Attributes - (id)linkAttributeValueAtPoint:(CGPoint)point @@ -674,11 +717,17 @@ static NSArray *DefaultLinkAttributeNames() { CTLineRef truncationTokenLine = CTLineCreateWithAttributedString((CFAttributedStringRef)_truncationAttributedText); CFIndex truncationTokenLineGlyphCount = truncationTokenLine ? CTLineGetGlyphCount(truncationTokenLine) : 0; - CFRelease(truncationTokenLine); + + if (truncationTokenLine) { + CFRelease(truncationTokenLine); + } CTLineRef additionalTruncationTokenLine = CTLineCreateWithAttributedString((CFAttributedStringRef)_additionalTruncationMessage); - CFIndex additionalTruncationTokenLineGlyphCount = additionalTruncationTokenLine ? CTLineGetGlyphCount(additionalTruncationTokenLine) : 0; - CFRelease(additionalTruncationTokenLine); + CFIndex additionalTruncationTokenLineGlyphCount = additionalTruncationTokenLine ? CTLineGetGlyphCount(additionalTruncationTokenLine) : 0; + + if (additionalTruncationTokenLine) { + CFRelease(additionalTruncationTokenLine); + } switch (_textContainer.truncationType) { case ASTextTruncationTypeStart: { diff --git a/Source/ASVideoNode.h b/Source/ASVideoNode.h index 9c36214c..440c71c5 100644 --- a/Source/ASVideoNode.h +++ b/Source/ASVideoNode.h @@ -106,7 +106,7 @@ NS_ASSUME_NONNULL_BEGIN */ - (void)videoNode:(ASVideoNode *)videoNode willChangePlayerState:(ASVideoNodePlayerState)state toState:(ASVideoNodePlayerState)toState; /** - * @abstract Ssks delegate if state change is allowed + * @abstract Asks delegate if state change is allowed * ASVideoNodePlayerStatePlaying or ASVideoNodePlayerStatePaused. * asks delegate if state change is allowed. * @param videoNode The video node. diff --git a/Source/ASVideoNode.mm b/Source/ASVideoNode.mm index 6646c3db..141ca2ea 100644 --- a/Source/ASVideoNode.mm +++ b/Source/ASVideoNode.mm @@ -289,7 +289,7 @@ static NSString * const kRate = @"rate"; - (void)imageAtTime:(CMTime)imageTime completionHandler:(void(^)(UIImage *image))completionHandler { ASPerformBlockOnBackgroundThread(^{ - AVAsset *asset = self.asset; + AVAsset *asset = self->_asset; // Skip the asset image generation if we don't have any tracks available that are capable of supporting it NSArray* visualAssetArray = [asset tracksWithMediaCharacteristic:AVMediaCharacteristicVisual]; @@ -300,7 +300,7 @@ static NSString * const kRate = @"rate"; AVAssetImageGenerator *previewImageGenerator = [AVAssetImageGenerator assetImageGeneratorWithAsset:asset]; previewImageGenerator.appliesPreferredTrackTransform = YES; - previewImageGenerator.videoComposition = _videoComposition; + previewImageGenerator.videoComposition = self->_videoComposition; [previewImageGenerator generateCGImagesAsynchronouslyForTimes:@[[NSValue valueWithCMTime:imageTime]] completionHandler:^(CMTime requestedTime, CGImageRef image, CMTime actualTime, AVAssetImageGeneratorResult result, NSError *error) { @@ -415,7 +415,7 @@ static NSString * const kRate = @"rate"; NSArray *requestedKeys = @[@"playable"]; [asset loadValuesAsynchronouslyForKeys:requestedKeys completionHandler:^{ ASPerformBlockOnMainThread(^{ - if (_delegateFlags.delegateVideoNodeDidFinishInitialLoading) { + if (self->_delegateFlags.delegateVideoNodeDidFinishInitialLoading) { [self.delegate videoNodeDidFinishInitialLoading:self]; } [self prepareToPlayAsset:asset withKeys:requestedKeys]; diff --git a/Source/ASVideoPlayerNode.mm b/Source/ASVideoPlayerNode.mm index 696531c7..36b4a3fb 100644 --- a/Source/ASVideoPlayerNode.mm +++ b/Source/ASVideoPlayerNode.mm @@ -435,19 +435,19 @@ static void *ASVideoPlayerNodeContext = &ASVideoPlayerNodeContext; slider.minimumValue = 0.0; slider.maximumValue = 1.0; - if (_delegateFlags.delegateScrubberMinimumTrackTintColor) { + if (strongSelf->_delegateFlags.delegateScrubberMinimumTrackTintColor) { slider.minimumTrackTintColor = [strongSelf.delegate videoPlayerNodeScrubberMinimumTrackTint:strongSelf]; } - if (_delegateFlags.delegateScrubberMaximumTrackTintColor) { + if (strongSelf->_delegateFlags.delegateScrubberMaximumTrackTintColor) { slider.maximumTrackTintColor = [strongSelf.delegate videoPlayerNodeScrubberMaximumTrackTint:strongSelf]; } - if (_delegateFlags.delegateScrubberThumbTintColor) { + if (strongSelf->_delegateFlags.delegateScrubberThumbTintColor) { slider.thumbTintColor = [strongSelf.delegate videoPlayerNodeScrubberThumbTint:strongSelf]; } - if (_delegateFlags.delegateScrubberThumbImage) { + if (strongSelf->_delegateFlags.delegateScrubberThumbImage) { UIImage *thumbImage = [strongSelf.delegate videoPlayerNodeScrubberThumbImage:strongSelf]; [slider setThumbImage:thumbImage forState:UIControlStateNormal]; } @@ -645,14 +645,14 @@ static void *ASVideoPlayerNodeContext = &ASVideoPlayerNodeContext; UIActivityIndicatorView *spinnnerView = [[UIActivityIndicatorView alloc] init]; spinnnerView.backgroundColor = [UIColor clearColor]; - if (_delegateFlags.delegateSpinnerTintColor) { - spinnnerView.color = [_delegate videoPlayerNodeSpinnerTint:strongSelf]; + if (strongSelf->_delegateFlags.delegateSpinnerTintColor) { + spinnnerView.color = [strongSelf->_delegate videoPlayerNodeSpinnerTint:strongSelf]; } else { - spinnnerView.color = _defaultControlsColor; + spinnnerView.color = strongSelf->_defaultControlsColor; } - if (_delegateFlags.delegateSpinnerStyle) { - spinnnerView.activityIndicatorViewStyle = [_delegate videoPlayerNodeSpinnerStyle:strongSelf]; + if (strongSelf->_delegateFlags.delegateSpinnerStyle) { + spinnnerView.activityIndicatorViewStyle = [strongSelf->_delegate videoPlayerNodeSpinnerStyle:strongSelf]; } return spinnnerView; diff --git a/Source/ASViewController.h b/Source/ASViewController.h index 94863298..89c02d6f 100644 --- a/Source/ASViewController.h +++ b/Source/ASViewController.h @@ -38,6 +38,15 @@ typedef ASTraitCollection * _Nonnull (^ASDisplayTraitsForTraitWindowSizeBlock)(C */ - (instancetype)initWithNode:(DisplayNodeType)node NS_DESIGNATED_INITIALIZER; +/** +* ASViewController initializer. Useful for interoperability with normal UIViewControllers. +* +* @return An ASViewController instance with a nil node whose root view will be backed by a standard UIView as with a normal UIViewController. +* +* @see ASVisibilityDepth +*/ +- (instancetype)init NS_DESIGNATED_INITIALIZER; + NS_ASSUME_NONNULL_END /** diff --git a/Source/ASViewController.mm b/Source/ASViewController.mm index a15a2144..672d9042 100644 --- a/Source/ASViewController.mm +++ b/Source/ASViewController.mm @@ -64,6 +64,17 @@ return self; } +- (instancetype)init +{ + if (!(self = [super initWithNibName:nil bundle:nil])) { + return nil; + } + + [self _initializeInstance]; + + return self; +} + - (void)_initializeInstance { if (_node == nil) { @@ -94,14 +105,6 @@ } } -- (void)dealloc -{ - if (ASActivateExperimentalFeature(ASExperimentalOOMBackgroundDeallocDisable)) { - return; - } - ASPerformBackgroundDeallocation(&_node); -} - - (void)loadView { // Apple applies a frame and autoresizing masks we need. Allocating a view is not diff --git a/Source/AsyncDisplayKit.h b/Source/AsyncDisplayKit.h index eaab7784..59e9aeec 100644 --- a/Source/AsyncDisplayKit.h +++ b/Source/AsyncDisplayKit.h @@ -129,4 +129,5 @@ #import #import -#import +#import +#import diff --git a/Source/Base/ASAvailability.h b/Source/Base/ASAvailability.h index c6e0fcf8..b210397f 100644 --- a/Source/Base/ASAvailability.h +++ b/Source/Base/ASAvailability.h @@ -86,6 +86,7 @@ #define AS_PIN_REMOTE_IMAGE __has_include() #define AS_IG_LIST_KIT __has_include() +#define AS_IG_LIST_DIFF_KIT __has_include() /** * For IGListKit versions < 3.0, you have to use IGListCollectionView. diff --git a/Source/Base/ASBaseDefines.h b/Source/Base/ASBaseDefines.h index 19c0f5b1..92b6d8fa 100644 --- a/Source/Base/ASBaseDefines.h +++ b/Source/Base/ASBaseDefines.h @@ -12,18 +12,6 @@ #define AS_EXTERN FOUNDATION_EXTERN #define unowned __unsafe_unretained -/** - * Hack to support building for iOS with Xcode 9. UIUserInterfaceStyle was previously tvOS-only, - * and it was added to iOS 12. Xcode 9 (iOS 11 SDK) will flat-out refuse to build anything that - * references this enum targeting iOS, even if it's guarded with the right availability macros, - * because it thinks the entire platform isn't compatible with the enum. - */ -#if TARGET_OS_TV || (defined(__IPHONE_12_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_12_0) -#define AS_BUILD_UIUSERINTERFACESTYLE 1 -#else -#define AS_BUILD_UIUSERINTERFACESTYLE 0 -#endif - /** * Decorates methods that clients can implement in categories on our base class. These methods * will be stubbed with an empty implementation if no implementation is provided. diff --git a/Source/Debug/AsyncDisplayKit+Debug.mm b/Source/Debug/AsyncDisplayKit+Debug.mm index 0e834e4e..965b265c 100644 --- a/Source/Debug/AsyncDisplayKit+Debug.mm +++ b/Source/Debug/AsyncDisplayKit+Debug.mm @@ -140,7 +140,7 @@ static BOOL __enableHitTestDebug = NO; UIColor *clipsBorderColor = [UIColor colorWithRed:30/255.0 green:90/255.0 blue:50/255.0 alpha:0.7]; CGRect imgRect = CGRectMake(0, 0, 2.0 * borderWidth + 1.0, 2.0 * borderWidth + 1.0); - UIImage *debugHighlightImage = ASGraphicsCreateImageWithOptions(imgRect.size, NO, 1, nil, nil, ^{ + UIImage *debugHighlightImage = ASGraphicsCreateImage(self.primitiveTraitCollection, imgRect.size, NO, 1, nil, nil, ^{ [fillColor setFill]; UIRectFill(imgRect); @@ -424,10 +424,10 @@ static BOOL __shouldShowRangeDebugOverlay = NO; } [UIView animateWithDuration:0.2 delay:0.0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{ - _animating = YES; + self->_animating = YES; [self layoutToFitAllBarsExcept:0]; } completion:^(BOOL finished) { - _animating = NO; + self->_animating = NO; }]; } @@ -653,15 +653,15 @@ static BOOL __shouldShowRangeDebugOverlay = NO; BOOL animate = !_firstLayoutOfRects; [UIView animateWithDuration:animate ? 0.3 : 0.0 delay:0.0 options:UIViewAnimationOptionLayoutSubviews animations:^{ - _visibleRect.frame = CGRectMake(HORIZONTAL_INSET + visiblePoint, rect.origin.y, visibleDimension, subCellHeight); - _displayRect.frame = CGRectMake(HORIZONTAL_INSET + displayPoint, rect.origin.y, displayDimension, subCellHeight); - _preloadRect.frame = CGRectMake(HORIZONTAL_INSET + preloadPoint, rect.origin.y, preloadDimension, subCellHeight); + self->_visibleRect.frame = CGRectMake(HORIZONTAL_INSET + visiblePoint, rect.origin.y, visibleDimension, subCellHeight); + self->_displayRect.frame = CGRectMake(HORIZONTAL_INSET + displayPoint, rect.origin.y, displayDimension, subCellHeight); + self->_preloadRect.frame = CGRectMake(HORIZONTAL_INSET + preloadPoint, rect.origin.y, preloadDimension, subCellHeight); } completion:^(BOOL finished) {}]; if (!animate) { _visibleRect.alpha = _displayRect.alpha = _preloadRect.alpha = 0; [UIView animateWithDuration:0.3 animations:^{ - _visibleRect.alpha = _displayRect.alpha = _preloadRect.alpha = 1; + self->_visibleRect.alpha = self->_displayRect.alpha = self->_preloadRect.alpha = 1; }]; } @@ -729,13 +729,15 @@ static BOOL __shouldShowRangeDebugOverlay = NO; - (ASImageNode *)createRangeNodeWithColor:(UIColor *)color { ASImageNode *rangeBarImageNode = [[ASImageNode alloc] init]; + ASPrimitiveTraitCollection primitiveTraitCollection = ASPrimitiveTraitCollectionFromUITraitCollection(self.traitCollection); rangeBarImageNode.image = [UIImage as_resizableRoundedImageWithCornerRadius:RANGE_BAR_CORNER_RADIUS cornerColor:[UIColor clearColor] fillColor:[color colorWithAlphaComponent:0.5] borderColor:[[UIColor blackColor] colorWithAlphaComponent:0.9] borderWidth:RANGE_BAR_BORDER_WIDTH roundedCorners:UIRectCornerAllCorners - scale:[[UIScreen mainScreen] scale]]; + scale:[[UIScreen mainScreen] scale] + traitCollection:primitiveTraitCollection]; [self addSubnode:rangeBarImageNode]; return rangeBarImageNode; diff --git a/Source/Details/ASBasicImageDownloader.mm b/Source/Details/ASBasicImageDownloader.mm index 927a2d0a..f577eb1e 100644 --- a/Source/Details/ASBasicImageDownloader.mm +++ b/Source/Details/ASBasicImageDownloader.mm @@ -290,7 +290,7 @@ static const void *ContextKey() { [context addCallbackData:[[NSDictionary alloc] initWithDictionary:callbackData]]; // Create new task if necessary - NSURLSessionDownloadTask *task = (NSURLSessionDownloadTask *)[context createSessionTaskIfNecessaryWithBlock:^(){return [_session downloadTaskWithURL:URL];}]; + NSURLSessionDownloadTask *task = (NSURLSessionDownloadTask *)[context createSessionTaskIfNecessaryWithBlock:^(){return [self->_session downloadTaskWithURL:URL];}]; if (task) { task.priority = NSURLSessionTaskPriorityWithImageDownloaderPriority(priority); diff --git a/Source/Details/ASCollectionViewLayoutInspector.mm b/Source/Details/ASCollectionViewLayoutInspector.mm index eb8375b0..1747c464 100644 --- a/Source/Details/ASCollectionViewLayoutInspector.mm +++ b/Source/Details/ASCollectionViewLayoutInspector.mm @@ -11,6 +11,7 @@ #import #import +#import #pragma mark - Helper Functions diff --git a/Source/Details/ASDataController.mm b/Source/Details/ASDataController.mm index 2ec2eb69..76e58d8b 100644 --- a/Source/Details/ASDataController.mm +++ b/Source/Details/ASDataController.mm @@ -533,13 +533,13 @@ typedef void (^ASDataControllerSynchronizationBlock)(); _synchronized = NO; [changeSet addCompletionHandler:^(BOOL finished) { - _synchronized = YES; + self->_synchronized = YES; [self onDidFinishProcessingUpdates:^{ - if (_synchronized) { - for (ASDataControllerSynchronizationBlock block in _onDidFinishSynchronizingBlocks) { + if (self->_synchronized) { + for (ASDataControllerSynchronizationBlock block in self->_onDidFinishSynchronizingBlocks) { block(); } - [_onDidFinishSynchronizingBlocks removeAllObjects]; + [self->_onDidFinishSynchronizingBlocks removeAllObjects]; } }]; }]; @@ -646,9 +646,9 @@ typedef void (^ASDataControllerSynchronizationBlock)(); } // Step 4: Inform the delegate on main thread - [_mainSerialQueue performBlockOnMainThread:^{ + [self->_mainSerialQueue performBlockOnMainThread:^{ as_activity_scope_leave(&preparationScope); - [_delegate dataController:self updateWithChangeSet:changeSet updates:^{ + [self->_delegate dataController:self updateWithChangeSet:changeSet updates:^{ // Step 5: Deploy the new data as "completed" // // Note that since the backing collection view might be busy responding to user events (e.g scrolling), @@ -659,7 +659,7 @@ typedef void (^ASDataControllerSynchronizationBlock)(); self.visibleMap = newMap; }]; }]; - --_editingTransactionGroupCount; + --self->_editingTransactionGroupCount; }); // We've now dispatched node allocation and layout to a concurrent background queue. @@ -898,7 +898,7 @@ typedef void (^ASDataControllerSynchronizationBlock)(); - (void)environmentDidChange { ASPerformBlockOnMainThread(^{ - if (!_initialReloadDataHasBeenCalled) { + if (!self->_initialReloadDataHasBeenCalled) { return; } @@ -906,7 +906,7 @@ typedef void (^ASDataControllerSynchronizationBlock)(); // i.e there might be some elements that were allocated using the old trait collection but haven't been added to _visibleMap [self _scheduleBlockOnMainSerialQueue:^{ ASPrimitiveTraitCollection newTraitCollection = [self.node primitiveTraitCollection]; - for (ASCollectionElement *element in _visibleMap) { + for (ASCollectionElement *element in self->_visibleMap) { element.traitCollection = newTraitCollection; } }]; diff --git a/Source/Details/ASGraphicsContext.h b/Source/Details/ASGraphicsContext.h index 8d08b600..02c18f1a 100644 --- a/Source/Details/ASGraphicsContext.h +++ b/Source/Details/ASGraphicsContext.h @@ -9,6 +9,7 @@ #import #import #import +#import NS_ASSUME_NONNULL_BEGIN @@ -27,6 +28,38 @@ NS_ASSUME_NONNULL_BEGIN * * @return The rendered image. You can also render intermediary images using UIGraphicsGetImageFromCurrentImageContext. */ -AS_EXTERN UIImage *ASGraphicsCreateImageWithOptions(CGSize size, BOOL opaque, CGFloat scale, UIImage * _Nullable sourceImage, asdisplaynode_iscancelled_block_t NS_NOESCAPE _Nullable isCancelled, void (NS_NOESCAPE ^work)()); +AS_EXTERN UIImage *ASGraphicsCreateImageWithOptions(CGSize size, BOOL opaque, CGFloat scale, UIImage * _Nullable sourceImage, asdisplaynode_iscancelled_block_t NS_NOESCAPE _Nullable isCancelled, void (NS_NOESCAPE ^work)(void)) ASDISPLAYNODE_DEPRECATED_MSG("Use ASGraphicsCreateImageWithTraitCollectionAndOptions instead"); + +/** +* A wrapper for the UIKit drawing APIs. If you are in ASExperimentalDrawingGlobal, and you have iOS >= 10, we will create +* a UIGraphicsRenderer with an appropriate format. Otherwise, we will use UIGraphicsBeginImageContext et al. +* +* @param traitCollection Trait collection. The `work` block will be executed with this trait collection, so it will affect dynamic colors, etc. +* @param size The size of the context. +* @param opaque Whether the context should be opaque or not. +* @param scale The scale of the context. 0 uses main screen scale. +* @param sourceImage If you are planning to render a UIImage into this context, provide it here and we will use its +* preferred renderer format if we are using UIGraphicsImageRenderer. +* @param isCancelled An optional block for canceling the drawing before forming the image. +* @param work A block, wherein the current UIGraphics context is set based on the arguments. +* +* @return The rendered image. You can also render intermediary images using UIGraphicsGetImageFromCurrentImageContext. +*/ +AS_EXTERN UIImage *ASGraphicsCreateImage(ASPrimitiveTraitCollection traitCollection, CGSize size, BOOL opaque, CGFloat scale, UIImage * _Nullable sourceImage, asdisplaynode_iscancelled_block_t _Nullable NS_NOESCAPE isCancelled, void (NS_NOESCAPE ^work)(void)); + +/** +* A wrapper for the UIKit drawing APIs. +* +* @param traitCollection Trait collection. The `work` block will be executed with this trait collection, so it will affect dynamic colors, etc. +* @param size The size of the context. +* @param opaque Whether the context should be opaque or not. +* @param scale The scale of the context. 0 uses main screen scale. +* @param sourceImage If you are planning to render a UIImage into this context, provide it here and we will use its +* preferred renderer format if we are using UIGraphicsImageRenderer. +* @param work A block, wherein the current UIGraphics context is set based on the arguments. +* +* @return The rendered image. You can also render intermediary images using UIGraphicsGetImageFromCurrentImageContext. +*/ +AS_EXTERN UIImage *ASGraphicsCreateImageWithTraitCollectionAndOptions(ASPrimitiveTraitCollection traitCollection, CGSize size, BOOL opaque, CGFloat scale, UIImage * _Nullable sourceImage, void (NS_NOESCAPE ^work)(void)) ASDISPLAYNODE_DEPRECATED_MSG("Use ASGraphicsCreateImage instead"); NS_ASSUME_NONNULL_END diff --git a/Source/Details/ASGraphicsContext.mm b/Source/Details/ASGraphicsContext.mm index 8591f567..fbd23ddc 100644 --- a/Source/Details/ASGraphicsContext.mm +++ b/Source/Details/ASGraphicsContext.mm @@ -10,6 +10,23 @@ #import #import #import +#import + + +#if AS_AT_LEAST_IOS13 +#define ASPerformBlockWithTraitCollection(work, traitCollection) \ + if (@available(iOS 13.0, *)) { \ + UITraitCollection *uiTraitCollection = ASPrimitiveTraitCollectionToUITraitCollection(traitCollection); \ + [uiTraitCollection performAsCurrentTraitCollection:^{ \ + work(); \ + }];\ + } else { \ + work(); \ + } +#else +#define ASPerformBlockWithTraitCollection(work, traitCollection) work(); +#endif + NS_AVAILABLE_IOS(10) NS_INLINE void ASConfigureExtendedRange(UIGraphicsImageRendererFormat *format) @@ -26,6 +43,10 @@ UIImage *ASGraphicsCreateImageWithOptions(CGSize size, BOOL opaque, CGFloat scal asdisplaynode_iscancelled_block_t NS_NOESCAPE isCancelled, void (^NS_NOESCAPE work)()) { + return ASGraphicsCreateImage(ASPrimitiveTraitCollectionMakeDefault(), size, opaque, scale, sourceImage, isCancelled, work); +} + +UIImage *ASGraphicsCreateImage(ASPrimitiveTraitCollection traitCollection, CGSize size, BOOL opaque, CGFloat scale, UIImage * sourceImage, asdisplaynode_iscancelled_block_t NS_NOESCAPE isCancelled, void (NS_NOESCAPE ^work)()) { if (AS_AVAILABLE_IOS_TVOS(10, 10)) { if (ASActivateExperimentalFeature(ASExperimentalDrawingGlobal)) { // If they used default scale, reuse one of two preferred formats. @@ -76,17 +97,32 @@ UIImage *ASGraphicsCreateImageWithOptions(CGSize size, BOOL opaque, CGFloat scal format.scale = scale; ASConfigureExtendedRange(format); } - - return [[[UIGraphicsImageRenderer alloc] initWithSize:size format:format] imageWithActions:^(UIGraphicsImageRendererContext *rendererContext) { - ASDisplayNodeCAssert(UIGraphicsGetCurrentContext(), @"Should have a context!"); - work(); - }]; + + // Avoid using the imageWithActions: method because it does not support cancellation at the + // last moment i.e. before actually creating the resulting image. + __block UIImage *image; + NSError *error; + [[[UIGraphicsImageRenderer alloc] initWithSize:size format:format] + runDrawingActions:^(UIGraphicsImageRendererContext *rendererContext) { + ASDisplayNodeCAssert(UIGraphicsGetCurrentContext(), @"Should have a context!"); + ASPerformBlockWithTraitCollection(work, traitCollection); + } + completionActions:^(UIGraphicsImageRendererContext *rendererContext) { + if (isCancelled == nil || !isCancelled()) { + image = rendererContext.currentImage; + } + } + error:&error]; + if (error) { + NSCAssert(NO, @"Error drawing: %@", error); + } + return image; } } // Bad OS or experiment flag. Use UIGraphics* API. UIGraphicsBeginImageContextWithOptions(size, opaque, scale); - work(); + ASPerformBlockWithTraitCollection(work, traitCollection) UIImage *image = nil; if (isCancelled == nil || !isCancelled()) { image = UIGraphicsGetImageFromCurrentImageContext(); @@ -94,3 +130,7 @@ UIImage *ASGraphicsCreateImageWithOptions(CGSize size, BOOL opaque, CGFloat scal UIGraphicsEndImageContext(); return image; } + +UIImage *ASGraphicsCreateImageWithTraitCollectionAndOptions(ASPrimitiveTraitCollection traitCollection, CGSize size, BOOL opaque, CGFloat scale, UIImage * sourceImage, void (NS_NOESCAPE ^work)()) { + return ASGraphicsCreateImage(traitCollection, size, opaque, scale, sourceImage, nil, work); +} diff --git a/Source/Details/ASImageProtocols.h b/Source/Details/ASImageProtocols.h index fae3b9f5..d91b8a77 100644 --- a/Source/Details/ASImageProtocols.h +++ b/Source/Details/ASImageProtocols.h @@ -20,7 +20,12 @@ NS_ASSUME_NONNULL_BEGIN @end -typedef void(^ASImageCacherCompletion)(id _Nullable imageFromCache); +typedef NS_ENUM(NSInteger, ASImageCacheType) { + ASImageCacheTypeAsynchronous = 0, + ASImageCacheTypeSynchronous, +}; + +typedef void(^ASImageCacherCompletion)(id _Nullable imageFromCache, ASImageCacheType cacheType); @protocol ASImageCacheProtocol diff --git a/Source/Details/ASMainSerialQueue.mm b/Source/Details/ASMainSerialQueue.mm index 8b77c654..ba2c7434 100644 --- a/Source/Details/ASMainSerialQueue.mm +++ b/Source/Details/ASMainSerialQueue.mm @@ -11,38 +11,29 @@ #import #import +#import @interface ASMainSerialQueue () { AS::Mutex _serialQueueLock; - NSMutableArray *_blocks; + std::queue _blocks; } @end @implementation ASMainSerialQueue -- (instancetype)init -{ - if (!(self = [super init])) { - return nil; - } - - _blocks = [[NSMutableArray alloc] init]; - return self; -} - - (NSUInteger)numberOfScheduledBlocks { AS::MutexLocker l(_serialQueueLock); - return _blocks.count; + return _blocks.size(); } - (void)performBlockOnMainThread:(dispatch_block_t)block { { AS::MutexLocker l(_serialQueueLock); - [_blocks addObject:block]; + _blocks.push(block); } [self runBlocks]; @@ -53,13 +44,11 @@ dispatch_block_t mainThread = ^{ AS::UniqueLock l(self->_serialQueueLock); do { - dispatch_block_t block; - if (self->_blocks.count > 0) { - block = _blocks[0]; - [self->_blocks removeObjectAtIndex:0]; - } else { + if (self->_blocks.empty()) { break; } + dispatch_block_t block = self->_blocks.front(); + self->_blocks.pop(); { l.unlock(); block(); @@ -73,7 +62,15 @@ - (NSString *)description { - return [[super description] stringByAppendingFormat:@" Blocks: %@", _blocks]; + NSString *desc = [super description]; + std::queue blocks = _blocks; + [desc stringByAppendingString:@" Blocks: "]; + while (!blocks.empty()) { + dispatch_block_t block = blocks.front(); + [desc stringByAppendingFormat:@"%@", block]; + blocks.pop(); + } + return desc; } @end diff --git a/Source/Details/ASPINRemoteImageDownloader.mm b/Source/Details/ASPINRemoteImageDownloader.mm index 3daf06e3..df538f01 100644 --- a/Source/Details/ASPINRemoteImageDownloader.mm +++ b/Source/Details/ASPINRemoteImageDownloader.mm @@ -231,14 +231,15 @@ static dispatch_once_t shared_init_predicate; { [[self sharedPINRemoteImageManager] imageFromCacheWithURL:URL processorKey:nil options:PINRemoteImageManagerDownloadOptionsSkipDecode completion:^(PINRemoteImageManagerResult * _Nonnull result) { [ASPINRemoteImageDownloader _performWithCallbackQueue:callbackQueue work:^{ + ASImageCacheType cacheType = (result.resultType == PINRemoteImageResultTypeMemoryCache ? ASImageCacheTypeSynchronous : ASImageCacheTypeAsynchronous); #if PIN_ANIMATED_AVAILABLE if (result.alternativeRepresentation) { - completion(result.alternativeRepresentation); + completion(result.alternativeRepresentation, cacheType); } else { - completion(result.image); + completion(result.image, cacheType); } #else - completion(result.image); + completion(result.image, cacheType); #endif }]; }]; diff --git a/Source/Details/ASRangeController.mm b/Source/Details/ASRangeController.mm index 83bc2628..1dcd062a 100644 --- a/Source/Details/ASRangeController.mm +++ b/Source/Details/ASRangeController.mm @@ -20,6 +20,7 @@ #import #import +#import #define AS_RANGECONTROLLER_LOG_UPDATE_FREQ 0 diff --git a/Source/Details/ASRecursiveUnfairLock.h b/Source/Details/ASRecursiveUnfairLock.h index d705e4d3..fad7c5c6 100644 --- a/Source/Details/ASRecursiveUnfairLock.h +++ b/Source/Details/ASRecursiveUnfairLock.h @@ -20,7 +20,7 @@ NS_ASSUME_NONNULL_BEGIN OS_UNFAIR_LOCK_AVAILABILITY typedef struct { os_unfair_lock _lock OS_UNFAIR_LOCK_AVAILABILITY; - _Atomic(pthread_t) _thread; // Write-protected by lock + _Atomic(pthread_t) _thread; int _count; // Protected by lock } ASRecursiveUnfairLock; diff --git a/Source/Details/ASRecursiveUnfairLock.mm b/Source/Details/ASRecursiveUnfairLock.mm index 9e4a29d4..b3297333 100644 --- a/Source/Details/ASRecursiveUnfairLock.mm +++ b/Source/Details/ASRecursiveUnfairLock.mm @@ -11,57 +11,58 @@ #import /** - * For our atomic _thread, we use acquire/release memory order so that we can have - * the minimum possible constraint on the hardware. The default, `memory_order_seq_cst` - * demands that there be a total order of all such modifications as seen by all threads. - * Acquire/release only requires that modifications to this specific atomic are - * synchronized across acquire/release pairs. - * http://en.cppreference.com/w/cpp/atomic/memory_order - * - * Note also that the unfair_lock involves a thread fence as well, so we don't need to - * take care of synchronizing other values. Just the thread value. + * Since the lock itself is a memory barrier, we only need memory_order_relaxed for our + * thread atomic. That guarantees we won't have torn writes, but otherwise no ordering + * is required. */ -#define rul_set_thread(l, t) atomic_store_explicit(&l->_thread, t, memory_order_release) -#define rul_get_thread(l) atomic_load_explicit(&l->_thread, memory_order_acquire) +#define rul_set_thread(l, t) atomic_store_explicit(&l->_thread, t, memory_order_relaxed) +#define rul_get_thread(l) atomic_load_explicit(&l->_thread, memory_order_relaxed) + +NS_INLINE void ASRecursiveUnfairLockDidAcquire(ASRecursiveUnfairLock *l, pthread_t tid) { + NSCAssert(pthread_equal(rul_get_thread(l), NULL) && l->_count == 0, @"Unfair lock error"); + rul_set_thread(l, tid); +} + +NS_INLINE void ASRecursiveUnfairLockWillRelease(ASRecursiveUnfairLock *l) { + NSCAssert(pthread_equal(rul_get_thread(l), pthread_self()) && l->_count == 0, @"Unfair lock error"); + rul_set_thread(l, NULL); +} + +NS_INLINE void ASRecursiveUnfairLockAssertHeld(ASRecursiveUnfairLock *l) { + NSCAssert(pthread_equal(rul_get_thread(l), pthread_self()) && l->_count > 0, @"Unfair lock error"); +} void ASRecursiveUnfairLockLock(ASRecursiveUnfairLock *l) { // Try to lock without blocking. If we fail, check what thread owns it. - // Note that the owning thread CAN CHANGE freely, but it can't become `self` - // because only we are `self`. And if it's already `self` then we already have - // the lock, because we reset it to NULL before we unlock. So (thread == self) is - // invariant. - + // Note that the owning thread CAN CHANGE freely, but if the thread is specifically `self` then we know + // it is a recursive call, because we clear it before unlocking, and only `self` can set it + // to `self`. + const pthread_t s = pthread_self(); - if (os_unfair_lock_trylock(&l->_lock)) { - // Owned by nobody. We now have the lock. Assign self. - rul_set_thread(l, s); - } else if (rul_get_thread(l) == s) { - // Owned by self (recursive lock). nop. + if (pthread_equal(rul_get_thread(l), s)) { + // Owned by self (recursive lock.) nop. + ASRecursiveUnfairLockAssertHeld(l); } else { - // Owned by other thread. Block and then set thread to self. os_unfair_lock_lock(&l->_lock); - rul_set_thread(l, s); + ASRecursiveUnfairLockDidAcquire(l, s); } - + l->_count++; } -BOOL ASRecursiveUnfairLockTryLock(ASRecursiveUnfairLock *l) -{ +BOOL ASRecursiveUnfairLockTryLock(ASRecursiveUnfairLock *l) { // Same as Lock above. See comments there. - const pthread_t s = pthread_self(); - if (os_unfair_lock_trylock(&l->_lock)) { - // Owned by nobody. We now have the lock. Assign self. - rul_set_thread(l, s); - } else if (rul_get_thread(l) == s) { - // Owned by self (recursive lock). nop. + if (pthread_equal(rul_get_thread(l), s)) { + ASRecursiveUnfairLockAssertHeld(l); + } else if (os_unfair_lock_trylock(&l->_lock)) { + ASRecursiveUnfairLockDidAcquire(l, s); } else { // Owned by other thread. Fail. return NO; } - + l->_count++; return YES; } @@ -70,14 +71,14 @@ void ASRecursiveUnfairLockUnlock(ASRecursiveUnfairLock *l) { // Ensure we have the lock. This check may miss some pathological cases, // but it'll catch 99.999999% of this serious programmer error. - NSCAssert(rul_get_thread(l) == pthread_self(), @"Unlocking from a different thread than locked."); + NSCAssert(pthread_equal(rul_get_thread(l), pthread_self()), @"Unlocking from a different thread than locked."); if (0 == --l->_count) { // Note that we have to clear this before unlocking because, if another thread // succeeds in locking above, but hasn't managed to update _thread, and we // try to re-lock, and fail the -tryLock, and read _thread, then we'll mistakenly // think that we still own the lock and proceed without blocking. - rul_set_thread(l, NULL); + ASRecursiveUnfairLockWillRelease(l); os_unfair_lock_unlock(&l->_lock); } } diff --git a/Source/Details/ASThread.h b/Source/Details/ASThread.h index 501022e8..cb840e16 100644 --- a/Source/Details/ASThread.h +++ b/Source/Details/ASThread.h @@ -218,7 +218,7 @@ namespace AS { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ if (AS_AVAILABLE_IOS_TVOS(10, 10)) { - gMutex_unfair = ASActivateExperimentalFeature(ASExperimentalUnfairLock); + gMutex_unfair = YES; } }); diff --git a/Source/Details/ASTraitCollection.h b/Source/Details/ASTraitCollection.h index 17e1740c..f6ca9541 100644 --- a/Source/Details/ASTraitCollection.h +++ b/Source/Details/ASTraitCollection.h @@ -40,14 +40,19 @@ typedef struct { UIUserInterfaceIdiom userInterfaceIdiom; UIForceTouchCapability forceTouchCapability; UITraitEnvironmentLayoutDirection layoutDirection API_AVAILABLE(ios(10.0)); -#if AS_BUILD_UIUSERINTERFACESTYLE UIUserInterfaceStyle userInterfaceStyle API_AVAILABLE(tvos(10.0), ios(12.0)); -#endif + // NOTE: This must be a constant. We will assert. unowned UIContentSizeCategory preferredContentSizeCategory API_AVAILABLE(ios(10.0)); CGSize containerSize; + +#if TARGET_OS_IOS + UIUserInterfaceLevel userInterfaceLevel API_AVAILABLE(ios(13.0)) API_UNAVAILABLE(tvos); +#endif + UIAccessibilityContrast accessibilityContrast API_AVAILABLE(ios(13.0)); + UILegibilityWeight legibilityWeight API_AVAILABLE(ios(13.0)); } ASPrimitiveTraitCollection; #pragma clang diagnostic pop @@ -61,6 +66,11 @@ AS_EXTERN ASPrimitiveTraitCollection ASPrimitiveTraitCollectionMakeDefault(void) */ AS_EXTERN ASPrimitiveTraitCollection ASPrimitiveTraitCollectionFromUITraitCollection(UITraitCollection *traitCollection); +/** + * Creates a UITraitCollection from a given ASPrimitiveTraitCollection. + */ +AS_EXTERN UITraitCollection * ASPrimitiveTraitCollectionToUITraitCollection(ASPrimitiveTraitCollection traitCollection); + /** * Compares two ASPrimitiveTraitCollection to determine if they are the same. @@ -139,13 +149,18 @@ AS_SUBCLASSING_RESTRICTED @property (readonly) UIUserInterfaceIdiom userInterfaceIdiom; @property (readonly) UIForceTouchCapability forceTouchCapability; @property (readonly) UITraitEnvironmentLayoutDirection layoutDirection API_AVAILABLE(ios(10.0)); -#if AS_BUILD_UIUSERINTERFACESTYLE @property (readonly) UIUserInterfaceStyle userInterfaceStyle API_AVAILABLE(tvos(10.0), ios(12.0)); -#endif @property (readonly) UIContentSizeCategory preferredContentSizeCategory API_AVAILABLE(ios(10.0)); @property (readonly) CGSize containerSize; +#if TARGET_OS_IOS +@property (readonly) UIUserInterfaceLevel userInterfaceLevel API_AVAILABLE(ios(13.0)) API_UNAVAILABLE(tvos); +#endif + +@property (readonly) UIAccessibilityContrast accessibilityContrast API_AVAILABLE(ios(13.0)); +@property (readonly) UILegibilityWeight legibilityWeight API_AVAILABLE(ios(13.0)); + - (BOOL)isEqualToTraitCollection:(ASTraitCollection *)traitCollection; @end diff --git a/Source/Details/ASTraitCollection.mm b/Source/Details/ASTraitCollection.mm index e8852392..39c1615d 100644 --- a/Source/Details/ASTraitCollection.mm +++ b/Source/Details/ASTraitCollection.mm @@ -38,11 +38,20 @@ ASPrimitiveTraitCollection ASPrimitiveTraitCollectionMakeDefault() { tc.preferredContentSizeCategory = UIContentSizeCategoryUnspecified; tc.layoutDirection = UITraitEnvironmentLayoutDirectionUnspecified; } -#if AS_BUILD_UIUSERINTERFACESTYLE if (AS_AVAILABLE_IOS_TVOS(12, 10)) { tc.userInterfaceStyle = UIUserInterfaceStyleUnspecified; } + +#if TARGET_OS_IOS + if(AS_AVAILABLE_IOS(13)){ + tc.userInterfaceLevel = UIUserInterfaceLevelUnspecified; + } #endif + + if (AS_AVAILABLE_IOS(13)) { + tc.accessibilityContrast = UIAccessibilityContrastUnspecified; + tc.legibilityWeight = UILegibilityWeightUnspecified; + } return tc; } @@ -60,14 +69,45 @@ ASPrimitiveTraitCollection ASPrimitiveTraitCollectionFromUITraitCollection(UITra ASDisplayNodeCAssertPermanent(traitCollection.preferredContentSizeCategory); environmentTraitCollection.preferredContentSizeCategory = traitCollection.preferredContentSizeCategory; } -#if AS_BUILD_UIUSERINTERFACESTYLE if (AS_AVAILABLE_IOS_TVOS(12, 10)) { environmentTraitCollection.userInterfaceStyle = traitCollection.userInterfaceStyle; } + +#if TARGET_OS_IOS + if(AS_AVAILABLE_IOS(13)){ + environmentTraitCollection.userInterfaceLevel = traitCollection.userInterfaceLevel; + } #endif + + if (AS_AVAILABLE_IOS(13)) { + environmentTraitCollection.accessibilityContrast = traitCollection.accessibilityContrast; + environmentTraitCollection.legibilityWeight = traitCollection.legibilityWeight; + } return environmentTraitCollection; } +AS_EXTERN UITraitCollection * ASPrimitiveTraitCollectionToUITraitCollection(ASPrimitiveTraitCollection traitCollection) { + NSMutableArray *collections = [[NSMutableArray alloc] initWithArray:@[ + [UITraitCollection traitCollectionWithHorizontalSizeClass:traitCollection.horizontalSizeClass], + [UITraitCollection traitCollectionWithVerticalSizeClass:traitCollection.verticalSizeClass], + [UITraitCollection traitCollectionWithDisplayScale:traitCollection.displayScale], + [UITraitCollection traitCollectionWithUserInterfaceIdiom:traitCollection.userInterfaceIdiom], + [UITraitCollection traitCollectionWithForceTouchCapability:traitCollection.forceTouchCapability], + ]]; + + if (AS_AVAILABLE_IOS(10)) { + [collections addObject:[UITraitCollection traitCollectionWithDisplayGamut:traitCollection.displayGamut]]; + [collections addObject:[UITraitCollection traitCollectionWithLayoutDirection:traitCollection.layoutDirection]]; + [collections addObject:[UITraitCollection traitCollectionWithPreferredContentSizeCategory:traitCollection.preferredContentSizeCategory]]; + } + if (AS_AVAILABLE_IOS_TVOS(12, 10)) { + [collections addObject:[UITraitCollection traitCollectionWithUserInterfaceStyle:traitCollection.userInterfaceStyle]]; + } + + UITraitCollection *result = [UITraitCollection traitCollectionWithTraitsFromCollections:collections]; + return result; +} + BOOL ASPrimitiveTraitCollectionIsEqualToASPrimitiveTraitCollection(ASPrimitiveTraitCollection lhs, ASPrimitiveTraitCollection rhs) { return !memcmp(&lhs, &rhs, sizeof(ASPrimitiveTraitCollection)); } @@ -139,7 +179,6 @@ ASDISPLAYNODE_INLINE NSString *AS_NSStringFromUITraitEnvironmentLayoutDirection( } // Named so as not to conflict with a hidden Apple function, in case compiler decides not to inline -#if AS_BUILD_UIUSERINTERFACESTYLE API_AVAILABLE(tvos(10.0), ios(12.0)) ASDISPLAYNODE_INLINE NSString *AS_NSStringFromUIUserInterfaceStyle(UIUserInterfaceStyle userInterfaceStyle) { switch (userInterfaceStyle) { @@ -151,7 +190,47 @@ ASDISPLAYNODE_INLINE NSString *AS_NSStringFromUIUserInterfaceStyle(UIUserInterfa return @"Unspecified"; } } -#endif + +// Named so as not to conflict with a hidden Apple function, in case compiler decides not to inline +API_AVAILABLE(ios(13)) API_UNAVAILABLE(tvos) +ASDISPLAYNODE_INLINE NSString *AS_NSStringFromUITraitEnvironmentUserInterfaceLevel(UIUserInterfaceLevel userInterfaceLevel) { + switch (userInterfaceLevel) { + case UIUserInterfaceLevelBase: + return @"Base"; + case UIUserInterfaceLevelElevated: + return @"Elevated"; + default: + return @"Unspecified"; + } +} + +// Named so as not to conflict with a hidden Apple function, in case compiler decides not to inline +API_AVAILABLE(ios(13)) +ASDISPLAYNODE_INLINE NSString *AS_NSStringFromUITraitEnvironmentAccessibilityContrast(UIAccessibilityContrast accessibilityContrast) { + switch (accessibilityContrast) { + case UIAccessibilityContrastNormal: + return @"Normal"; + case UIAccessibilityContrastHigh: + return @"High"; + default: + return @"Unspecified"; + } +} + +// Named so as not to conflict with a hidden Apple function, in case compiler decides not to inline +API_AVAILABLE(ios(13)) +ASDISPLAYNODE_INLINE NSString *AS_NSStringFromUITraitEnvironmentLegibilityWeight(UILegibilityWeight legibilityWeight) { + switch (legibilityWeight) { + case UILegibilityWeightRegular: + return @"Regular"; + case UILegibilityWeightBold: + return @"Bold"; + default: + return @"Unspecified"; + } +} + + NSString *NSStringFromASPrimitiveTraitCollection(ASPrimitiveTraitCollection traits) { NSMutableArray *props = [NSMutableArray array]; @@ -160,16 +239,27 @@ NSString *NSStringFromASPrimitiveTraitCollection(ASPrimitiveTraitCollection trai [props addObject:@{ @"displayScale": [NSString stringWithFormat: @"%.0lf", (double)traits.displayScale] }]; [props addObject:@{ @"userInterfaceIdiom": AS_NSStringFromUIUserInterfaceIdiom(traits.userInterfaceIdiom) }]; [props addObject:@{ @"forceTouchCapability": AS_NSStringFromUIForceTouchCapability(traits.forceTouchCapability) }]; -#if AS_BUILD_UIUSERINTERFACESTYLE if (AS_AVAILABLE_IOS_TVOS(12, 10)) { [props addObject:@{ @"userInterfaceStyle": AS_NSStringFromUIUserInterfaceStyle(traits.userInterfaceStyle) }]; } -#endif if (AS_AVAILABLE_IOS(10)) { [props addObject:@{ @"layoutDirection": AS_NSStringFromUITraitEnvironmentLayoutDirection(traits.layoutDirection) }]; - [props addObject:@{ @"preferredContentSizeCategory": traits.preferredContentSizeCategory }]; + if (traits.preferredContentSizeCategory != nil) { + [props addObject:@{ @"preferredContentSizeCategory": traits.preferredContentSizeCategory }]; + } [props addObject:@{ @"displayGamut": AS_NSStringFromUIDisplayGamut(traits.displayGamut) }]; } + +#if TARGET_OS_IOS + if (AS_AVAILABLE_IOS(13)){ + [props addObject:@{ @"userInterfaceLevel": AS_NSStringFromUITraitEnvironmentUserInterfaceLevel(traits.userInterfaceLevel) }]; + } +#endif + + if (AS_AVAILABLE_IOS(13)) { + [props addObject:@{ @"accessibilityContrast": AS_NSStringFromUITraitEnvironmentAccessibilityContrast(traits.accessibilityContrast) }]; + [props addObject:@{ @"legibilityWeight": AS_NSStringFromUITraitEnvironmentLegibilityWeight(traits.legibilityWeight) }]; + } [props addObject:@{ @"containerSize": NSStringFromCGSize(traits.containerSize) }]; return ASObjectDescriptionMakeWithoutObject(props); } @@ -220,16 +310,34 @@ NSString *NSStringFromASPrimitiveTraitCollection(ASPrimitiveTraitCollection trai { return _prim.containerSize; } -#if AS_BUILD_UIUSERINTERFACESTYLE + - (UIUserInterfaceStyle)userInterfaceStyle { return _prim.userInterfaceStyle; } -#endif + - (UIContentSizeCategory)preferredContentSizeCategory { return _prim.preferredContentSizeCategory; } + +#if TARGET_OS_IOS +- (UIUserInterfaceLevel)userInterfaceLevel +{ + return _prim.userInterfaceLevel; +} +#endif + +- (UIAccessibilityContrast)accessibilityContrast +{ + return _prim.accessibilityContrast; +} + +- (UILegibilityWeight)legibilityWeight +{ + return _prim.legibilityWeight; +} + - (NSUInteger)hash { return ASHashBytes(&_prim, sizeof(ASPrimitiveTraitCollection)); } diff --git a/Source/Details/Transactions/_ASAsyncTransaction.mm b/Source/Details/Transactions/_ASAsyncTransaction.mm index a852eafc..c23cad34 100644 --- a/Source/Details/Transactions/_ASAsyncTransaction.mm +++ b/Source/Details/Transactions/_ASAsyncTransaction.mm @@ -268,10 +268,7 @@ void ASAsyncTransactionQueue::GroupImpl::notify(dispatch_queue_t queue, dispatch if (_pendingOperations == 0) { dispatch_async(queue, block); } else { - GroupNotify notify; - notify._block = block; - notify._queue = queue; - _notifyList.push_back(notify); + _notifyList.push_back({block, queue}); } } @@ -333,7 +330,7 @@ ASAsyncTransactionQueue & ASAsyncTransactionQueue::instance() - (instancetype)initWithCompletionBlock:(void(^)(_ASAsyncTransaction *, BOOL))completionBlock { - if ((self = [self init])) { + if ((self = [super init])) { _completionBlock = completionBlock; self.state = ASAsyncTransactionStateOpen; } diff --git a/Source/Details/UIView+ASConvenience.h b/Source/Details/UIView+ASConvenience.h index 7d34340b..870793bd 100644 --- a/Source/Details/UIView+ASConvenience.h +++ b/Source/Details/UIView+ASConvenience.h @@ -42,7 +42,7 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic) UIColor *backgroundColor; @property (nonatomic) BOOL allowsGroupOpacity; @property (nonatomic) BOOL allowsEdgeAntialiasing; -@property (nonatomic) unsigned int edgeAntialiasingMask; +@property (nonatomic) CAEdgeAntialiasingMask edgeAntialiasingMask; @property (nonatomic, nullable, copy) NSDictionary> *actions; - (void)setNeedsDisplay; diff --git a/Source/Details/_ASDisplayViewAccessiblity.h b/Source/Details/_ASDisplayViewAccessiblity.h index 192b24d2..7f159d1d 100644 --- a/Source/Details/_ASDisplayViewAccessiblity.h +++ b/Source/Details/_ASDisplayViewAccessiblity.h @@ -14,3 +14,17 @@ // should still work as long as accessibility is enabled, this framework provides no guarantees on // their correctness. For details, see // https://developer.apple.com/documentation/objectivec/nsobject/1615147-accessibilityelements + +// After recusively collecting all of the accessibility elements of a node, they get sorted. This sort determines +// the order that a screen reader will traverse the elements. By default, we sort these elements based on their +// origin: lower y origin comes first, then lower x origin. If 2 nodes have an equal origin, the node with the smaller +// height is placed before the node with the smaller width. If two nodes have the exact same rect, we throw up our hands +// and return NSOrderedSame. +// +// In general this seems to work fairly well. However, if you want to provide a custom sort you can do so via +// setUserDefinedAccessibilitySortComparator(). The two elements you are comparing are NSObjects, which conforms to the +// informal UIAccessibility protocol, so you can safely compare properties like accessibilityFrame. +typedef NSComparisonResult (^ASSortAccessibilityElementsComparator)(NSObject *, NSObject *); + +// Use this method to supply your own custom sort comparator used to determine the order of the accessibility elements +void setUserDefinedAccessibilitySortComparator(ASSortAccessibilityElementsComparator userDefinedComparator); diff --git a/Source/Details/_ASDisplayViewAccessiblity.mm b/Source/Details/_ASDisplayViewAccessiblity.mm index 858fd5dd..367f5368 100644 --- a/Source/Details/_ASDisplayViewAccessiblity.mm +++ b/Source/Details/_ASDisplayViewAccessiblity.mm @@ -10,6 +10,7 @@ #ifndef ASDK_ACCESSIBILITY_DISABLE #import +#import #import #import #import @@ -21,35 +22,47 @@ #pragma mark - UIAccessibilityElement -@protocol ASAccessibilityElementPositioning +static ASSortAccessibilityElementsComparator currentAccessibilityComparator = nil; +static ASSortAccessibilityElementsComparator defaultAccessibilityComparator = nil; -@property (nonatomic, readonly) CGRect accessibilityFrame; - -@end - -typedef NSComparisonResult (^SortAccessibilityElementsComparator)(id, id); +void setUserDefinedAccessibilitySortComparator(ASSortAccessibilityElementsComparator userDefinedComparator) { + currentAccessibilityComparator = userDefinedComparator ?: defaultAccessibilityComparator; +} /// Sort accessiblity elements first by y and than by x origin. -static void SortAccessibilityElements(NSMutableArray *elements) +void SortAccessibilityElements(NSMutableArray *elements) { ASDisplayNodeCAssertNotNil(elements, @"Should pass in a NSMutableArray"); - - static SortAccessibilityElementsComparator comparator = nil; + static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ - comparator = ^NSComparisonResult(id a, id b) { - CGPoint originA = a.accessibilityFrame.origin; - CGPoint originB = b.accessibilityFrame.origin; - if (originA.y == originB.y) { - if (originA.x == originB.x) { - return NSOrderedSame; + defaultAccessibilityComparator = ^NSComparisonResult(NSObject *a, NSObject *b) { + CGPoint originA = a.accessibilityFrame.origin; + CGPoint originB = b.accessibilityFrame.origin; + if (originA.y == originB.y) { + if (originA.x == originB.x) { + // if we have the same origin, favor shorter items. If heights are the same, favor thinner items. If size is the same ¯\_(ツ)_/¯ + CGSize sizeA = a.accessibilityFrame.size; + CGSize sizeB = b.accessibilityFrame.size; + if (sizeA.height == sizeB.height) { + if (sizeA.width == sizeB.width) { + return NSOrderedSame; + } + return (sizeA.width < sizeB.width) ? NSOrderedAscending : NSOrderedDescending; } - return (originA.x < originB.x) ? NSOrderedAscending : NSOrderedDescending; + return (sizeA.height < sizeB.height) ? NSOrderedAscending : NSOrderedDescending; } - return (originA.y < originB.y) ? NSOrderedAscending : NSOrderedDescending; - }; + return (originA.x < originB.x) ? NSOrderedAscending : NSOrderedDescending; + } + return (originA.y < originB.y) ? NSOrderedAscending : NSOrderedDescending; + }; + + if (!currentAccessibilityComparator) { + currentAccessibilityComparator = defaultAccessibilityComparator; + } }); - [elements sortUsingComparator:comparator]; + + [elements sortUsingComparator:currentAccessibilityComparator]; } static CGRect ASAccessibilityFrameForNode(ASDisplayNode *node) { @@ -57,7 +70,7 @@ static CGRect ASAccessibilityFrameForNode(ASDisplayNode *node) { return [layer convertRect:node.bounds toLayer:ASFindWindowOfLayer(layer).layer]; } -@interface ASAccessibilityElement : UIAccessibilityElement +@interface ASAccessibilityElement : UIAccessibilityElement @property (nonatomic) ASDisplayNode *node; @@ -93,7 +106,7 @@ static CGRect ASAccessibilityFrameForNode(ASDisplayNode *node) { #pragma mark - _ASDisplayView / UIAccessibilityContainer -@interface ASAccessibilityCustomAction : UIAccessibilityCustomAction +@interface ASAccessibilityCustomAction : UIAccessibilityCustomAction @property (nonatomic) ASDisplayNode *node; @@ -197,6 +210,17 @@ static void CollectAccessibilityElementsForContainer(ASDisplayNode *container, U [elements addObject:accessiblityElement]; } +/// Check if a view is a subviews of an UIScrollView. This is used to determine whether to enforce that +/// accessibility elements must be on screen +static BOOL recusivelyCheckSuperviewsForScrollView(UIView *view) { + if (!view) { + return NO; + } else if ([view isKindOfClass:[UIScrollView class]]) { + return YES; + } + return recusivelyCheckSuperviewsForScrollView(view.superview); +} + /// Collect all accessibliity elements for a given view and view node static void CollectAccessibilityElements(ASDisplayNode *node, NSMutableArray *elements) { @@ -213,6 +237,11 @@ static void CollectAccessibilityElements(ASDisplayNode *node, NSMutableArray *el })); UIView *view = node.view; + + // If we don't have a window, let's just bail out + if (!view.window) { + return; + } if (node.isAccessibilityContainer && !anySubNodeIsCollection) { CollectAccessibilityElementsForContainer(node, view, elements); @@ -224,8 +253,20 @@ static void CollectAccessibilityElements(ASDisplayNode *node, NSMutableArray *el CollectUIAccessibilityElementsForNode(node, node, view, elements); return; } - + for (ASDisplayNode *subnode in node.subnodes) { + // If a node is hidden or has an alpha of 0.0 we should not include it + if (subnode.hidden || subnode.alpha == 0.0) { + continue; + } + + // If a subnode is outside of the view's window, exclude it UNLESS it is a subview of an UIScrollView. + // In this case UIKit will return the element even if it is outside of the window or the scrollView's visible rect (contentOffset + contentSize) + CGRect nodeInWindowCoords = [node convertRect:subnode.frame toNode:nil]; + if (!CGRectIntersectsRect(view.window.frame, nodeInWindowCoords) && !recusivelyCheckSuperviewsForScrollView(view)) { + continue; + } + if (subnode.isAccessibilityElement) { // An accessiblityElement can either be a UIView or a UIAccessibilityElement if (subnode.isLayerBacked) { @@ -259,6 +300,10 @@ static void CollectAccessibilityElements(ASDisplayNode *node, NSMutableArray *el - (void)setAccessibilityElements:(NSArray *)accessibilityElements { ASDisplayNodeAssertMainThread(); + // While it looks very strange to ignore the accessibilyElements param and set _accessibilityElements to nil, it is actually on purpose. + // _ASDisplayView's accessibilityElements method will always defer to the node for accessibilityElements when _accessibilityElements is + // nil. Calling setAccessibilityElements on _ASDisplayView is basically clearing the cache and forcing _ASDisplayView to ask the node + // for its accessibilityElements the next time they are requested. _accessibilityElements = nil; } @@ -271,7 +316,9 @@ static void CollectAccessibilityElements(ASDisplayNode *node, NSMutableArray *el return @[]; } - if (_accessibilityElements == nil) { + // when items become hidden/visible we have to manually clear the _accessibilityElements in order to get an updated version + // Instead, let's try computing the elements every time and see how badly it affects performance. + if (_accessibilityElements == nil || ASActivateExperimentalFeature(ASExperimentalDoNotCacheAccessibilityElements)) { _accessibilityElements = [viewNode accessibilityElements]; } return _accessibilityElements; @@ -283,6 +330,14 @@ static void CollectAccessibilityElements(ASDisplayNode *node, NSMutableArray *el - (NSArray *)accessibilityElements { + // NSObject implements the informal accessibility protocol. This means that all ASDisplayNodes already have an accessibilityElements + // property. If an ASDisplayNode subclass has explicitly set the property, let's use that instead of traversing the node tree to try + // to create the elements automatically + NSArray *elements = [super accessibilityElements]; + if (elements.count) { + return elements; + } + if (!self.isNodeLoaded) { ASDisplayNodeFailAssert(@"Cannot access accessibilityElements since node is not loaded"); return @[]; diff --git a/Source/Layout/ASLayout+IGListKit.h b/Source/Layout/ASLayout+IGListDiffKit.h similarity index 52% rename from Source/Layout/ASLayout+IGListKit.h rename to Source/Layout/ASLayout+IGListDiffKit.h index 6f6753da..34636efa 100644 --- a/Source/Layout/ASLayout+IGListKit.h +++ b/Source/Layout/ASLayout+IGListDiffKit.h @@ -1,15 +1,15 @@ // -// ASLayout+IGListKit.h +// ASLayout+IGListDiffKit.h // Texture // // Copyright (c) Pinterest, Inc. All rights reserved. // Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0 // -#if AS_IG_LIST_KIT +#if AS_IG_LIST_DIFF_KIT #import -#import -@interface ASLayout(IGListKit) -@end +#import -#endif // AS_IG_LIST_KIT +@interface ASLayout(IGListDiffKit) +@end +#endif // AS_IG_LIST_DIFF_KIT diff --git a/Source/Layout/ASLayout+IGListKit.mm b/Source/Layout/ASLayout+IGListDiffKit.mm similarity index 73% rename from Source/Layout/ASLayout+IGListKit.mm rename to Source/Layout/ASLayout+IGListDiffKit.mm index f9cc139e..d6e57b21 100644 --- a/Source/Layout/ASLayout+IGListKit.mm +++ b/Source/Layout/ASLayout+IGListDiffKit.mm @@ -1,13 +1,13 @@ // -// ASLayout+IGListKit.mm +// ASLayout+IGListDiffKit.mm // Texture // // Copyright (c) Pinterest, Inc. All rights reserved. // Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0 // #import -#if AS_IG_LIST_KIT -#import "ASLayout+IGListKit.h" +#if AS_IG_LIST_DIFF_KIT +#import "ASLayout+IGListDiffKit.h" @interface ASLayout() { @public @@ -15,7 +15,7 @@ } @end -@implementation ASLayout(IGListKit) +@implementation ASLayout(IGListDiffKit) - (id )diffIdentifier { @@ -27,4 +27,4 @@ return [self isEqual:other]; } @end -#endif // AS_IG_LIST_KIT +#endif // AS_IG_LIST_DIFF_KIT diff --git a/Source/Private/ASCollectionLayout.mm b/Source/Private/ASCollectionLayout.mm index d6b27b17..e69baa48 100644 --- a/Source/Private/ASCollectionLayout.mm +++ b/Source/Private/ASCollectionLayout.mm @@ -338,7 +338,12 @@ static const ASScrollDirection kASStaticScrollDirection = (ASScrollDirectionRigh if (NSUInteger count = blockingAttrs.count) { ASDispatchApply(count, queue, 0, ^(size_t i) { UICollectionViewLayoutAttributes *attrs = blockingAttrs[i]; - ASCellNode *node = [elements elementForItemAtIndexPath:attrs.indexPath].node; + ASCellNode *node; + if (attrs.representedElementKind == nil) { + node = [elements elementForItemAtIndexPath:attrs.indexPath].node; + } else { + node = [elements supplementaryElementOfKind:attrs.representedElementKind atIndexPath:attrs.indexPath].node; + } CGSize expectedSize = attrs.frame.size; if (! CGSizeEqualToSize(expectedSize, node.calculatedSize)) { [node layoutThatFits:ASCollectionLayoutElementSizeRangeFromSize(expectedSize)]; @@ -353,7 +358,12 @@ static const ASScrollDirection kASStaticScrollDirection = (ASScrollDirectionRigh __strong ASElementMap *strongElements = weakElements; if (strongElements) { UICollectionViewLayoutAttributes *attrs = nonBlockingAttrs[i]; - ASCellNode *node = [elements elementForItemAtIndexPath:attrs.indexPath].node; + ASCellNode *node; + if (attrs.representedElementKind == nil) { + node = [elements elementForItemAtIndexPath:attrs.indexPath].node; + } else { + node = [elements supplementaryElementOfKind:attrs.representedElementKind atIndexPath:attrs.indexPath].node; + } CGSize expectedSize = attrs.frame.size; if (! CGSizeEqualToSize(expectedSize, node.calculatedSize)) { [node layoutThatFits:ASCollectionLayoutElementSizeRangeFromSize(expectedSize)]; diff --git a/Source/Private/ASCollectionViewFlowLayoutInspector.mm b/Source/Private/ASCollectionViewFlowLayoutInspector.mm index f4625b32..52d341c8 100644 --- a/Source/Private/ASCollectionViewFlowLayoutInspector.mm +++ b/Source/Private/ASCollectionViewFlowLayoutInspector.mm @@ -11,6 +11,7 @@ #import #import #import +#import #define kDefaultItemSize CGSizeMake(50, 50) diff --git a/Source/Private/ASDisplayNode+AsyncDisplay.mm b/Source/Private/ASDisplayNode+AsyncDisplay.mm index 983f6f88..fd77a069 100644 --- a/Source/Private/ASDisplayNode+AsyncDisplay.mm +++ b/Source/Private/ASDisplayNode+AsyncDisplay.mm @@ -209,7 +209,7 @@ using AS::MutexLocker; displayBlock = ^id{ CHECK_CANCELLED_AND_RETURN_NIL(); - UIImage *image = ASGraphicsCreateImageWithOptions(bounds.size, opaque, contentsScaleForDisplay, nil, isCancelledBlock, ^{ + UIImage *image = ASGraphicsCreateImage(self.primitiveTraitCollection, bounds.size, opaque, contentsScaleForDisplay, nil, isCancelledBlock, ^{ for (dispatch_block_t block in displayBlocks) { if (isCancelledBlock()) return; block(); @@ -247,7 +247,7 @@ using AS::MutexLocker; }; if (shouldCreateGraphicsContext) { - return ASGraphicsCreateImageWithOptions(bounds.size, opaque, contentsScaleForDisplay, nil, isCancelledBlock, workWithContext); + return ASGraphicsCreateImage(self.primitiveTraitCollection, bounds.size, opaque, contentsScaleForDisplay, nil, isCancelledBlock, workWithContext); } else { workWithContext(); return image; diff --git a/Source/Private/ASDisplayNode+UIViewBridge.mm b/Source/Private/ASDisplayNode+UIViewBridge.mm index 851e828c..32f95b98 100644 --- a/Source/Private/ASDisplayNode+UIViewBridge.mm +++ b/Source/Private/ASDisplayNode+UIViewBridge.mm @@ -823,6 +823,7 @@ if (shouldApply) { _layer.layerProperty = (layerValueExpr); } else { ASDisplayNo } } } else { + _tintColor = color; _setToViewOnly(tintColor, color); } __instanceLock__.unlock(); @@ -929,13 +930,13 @@ if (shouldApply) { _layer.layerProperty = (layerValueExpr); } else { ASDisplayNo _setToLayer(allowsEdgeAntialiasing, allowsEdgeAntialiasing); } -- (unsigned int)edgeAntialiasingMask +- (CAEdgeAntialiasingMask)edgeAntialiasingMask { _bridge_prologue_read; return _getFromLayer(edgeAntialiasingMask); } -- (void)setEdgeAntialiasingMask:(unsigned int)edgeAntialiasingMask +- (void)setEdgeAntialiasingMask:(CAEdgeAntialiasingMask)edgeAntialiasingMask { _bridge_prologue_write; _setToLayer(edgeAntialiasingMask, edgeAntialiasingMask); diff --git a/Source/Private/ASIGListAdapterBasedDataSource.mm b/Source/Private/ASIGListAdapterBasedDataSource.mm index 3cf77afc..2f89b42c 100644 --- a/Source/Private/ASIGListAdapterBasedDataSource.mm +++ b/Source/Private/ASIGListAdapterBasedDataSource.mm @@ -86,6 +86,21 @@ typedef struct { [self.delegate collectionView:collectionNode.view didSelectItemAtIndexPath:indexPath]; } +- (void)collectionNode:(ASCollectionNode *)collectionNode didDeselectItemAtIndexPath:(NSIndexPath *)indexPath +{ + [self.delegate collectionView:collectionNode.view didDeselectItemAtIndexPath:indexPath]; +} + +- (void)collectionNode:(ASCollectionNode *)collectionNode didHighlightItemAtIndexPath:(NSIndexPath *)indexPath +{ + [self.delegate collectionView:collectionNode.view didHighlightItemAtIndexPath:indexPath]; +} + +- (void)collectionNode:(ASCollectionNode *)collectionNode didUnhighlightItemAtIndexPath:(NSIndexPath *)indexPath +{ + [self.delegate collectionView:collectionNode.view didUnhighlightItemAtIndexPath:indexPath]; +} + - (void)scrollViewDidScroll:(UIScrollView *)scrollView { [self.delegate scrollViewDidScroll:scrollView]; @@ -147,6 +162,32 @@ typedef struct { [ctrl beginBatchFetchWithContext:context]; } +- (void)collectionNode:(ASCollectionNode *)collectionNode willDisplayItemWithNode:(ASCellNode *)node +{ + NSIndexPath *indexPath = [collectionNode.view indexPathForNode:node]; + UIView *contentView = node.view.superview; + UICollectionViewCell *cell = contentView.superview; + + if (cell == nil || indexPath == nil) { + return; + } + + [self.delegate collectionView:collectionNode.view willDisplayCell:cell forItemAtIndexPath:indexPath]; +} + +- (void)collectionNode:(ASCollectionNode *)collectionNode didEndDisplayingItemWithNode:(ASCellNode *)node +{ + NSIndexPath *indexPath = [collectionNode.view indexPathForNode:node]; + UIView *contentView = node.view.superview; + UICollectionViewCell *cell = contentView.superview; + + if (cell == nil || indexPath == nil) { + return; + } + + [self.delegate collectionView:collectionNode.view didEndDisplayingCell:cell forItemAtIndexPath:indexPath]; +} + /** * Note: It is not documented that ASCollectionNode will forward these UIKit delegate calls if they are implemented. * It is not considered harmful to do so, and adding them to documentation will confuse most users, who should diff --git a/Source/Private/ASImageNode+AnimatedImagePrivate.h b/Source/Private/ASImageNode+AnimatedImagePrivate.h index e41ba34e..917eb6fb 100644 --- a/Source/Private/ASImageNode+AnimatedImagePrivate.h +++ b/Source/Private/ASImageNode+AnimatedImagePrivate.h @@ -28,6 +28,7 @@ unsigned int animatedImagePaused:1; unsigned int cropEnabled:1; // Defaults to YES. unsigned int forceUpscaling:1; //Defaults to NO. + unsigned int regenerateFromImageAsset:1; //Defaults to NO. } _imageNodeFlags; } diff --git a/Source/Private/ASLayoutTransition.mm b/Source/Private/ASLayoutTransition.mm index c9511a92..588b2756 100644 --- a/Source/Private/ASLayoutTransition.mm +++ b/Source/Private/ASLayoutTransition.mm @@ -16,9 +16,8 @@ #import -#if AS_IG_LIST_KIT -#import -#import +#if AS_IG_LIST_DIFF_KIT +#import #endif using AS::MutexLocker; @@ -160,13 +159,13 @@ static inline BOOL ASLayoutCanTransitionAsynchronous(ASLayout *layout) { ASLayout *pendingLayout = _pendingLayout.layout; if (previousLayout) { -#if AS_IG_LIST_KIT +#if AS_IG_LIST_DIFF_KIT // IGListDiff completes in linear time O(m+n), so use it if we have it: IGListIndexSetResult *result = IGListDiff(previousLayout.sublayouts, pendingLayout.sublayouts, IGListDiffEquality); _insertedSubnodePositions = findNodesInLayoutAtIndexes(pendingLayout, result.inserts, &_insertedSubnodes); findNodesInLayoutAtIndexes(previousLayout, result.deletes, &_removedSubnodes); for (IGListMoveIndex *move in result.moves) { - _subnodeMoves.push_back(std::make_pair(previousLayout.sublayouts[move.from].layoutElement, move.to)); + _subnodeMoves.emplace_back(previousLayout.sublayouts[move.from].layoutElement, move.to); } // Sort by ascending order of move destinations, this will allow easy loop of `insertSubnode:AtIndex` later. @@ -188,8 +187,8 @@ static inline BOOL ASLayoutCanTransitionAsynchronous(ASLayout *layout) { _removedSubnodes = [previousNodes objectsAtIndexes:deletions]; // These should arrive sorted in ascending order of move destinations. for (NSIndexPath *move in moves) { - _subnodeMoves.push_back(std::make_pair(previousLayout.sublayouts[([move indexAtPosition:0])].layoutElement, - [move indexAtPosition:1])); + _subnodeMoves.emplace_back(previousLayout.sublayouts[([move indexAtPosition:0])].layoutElement, + [move indexAtPosition:1]); } #endif } else { diff --git a/Source/Private/Layout/ASLayoutSpecUtilities.h b/Source/Private/Layout/ASLayoutSpecUtilities.h index 62a3d917..82e07df1 100644 --- a/Source/Private/Layout/ASLayoutSpecUtilities.h +++ b/Source/Private/Layout/ASLayoutSpecUtilities.h @@ -24,17 +24,15 @@ namespace AS { { // Some convenience type definitions typedef decltype(func(std::declval())) value_type; - typedef std::vector result_type; // Prepares an output vector of the appropriate size - result_type res(iterable.size()); + std::vector res; + res.reserve(iterable.size()); // Let std::transform apply `func` to all elements // (use perfect forwarding for the function object) - std::transform( - begin(iterable), end(iterable), res.begin(), - std::forward(func) - ); + std::transform(std::begin(iterable), std::end(iterable), std::back_inserter(res), + std::forward(func)); return res; } diff --git a/Source/Private/TextExperiment/String/ASTextRunDelegate.h b/Source/Private/TextExperiment/String/ASTextRunDelegate.h index 3d3bf11c..973dc5ff 100644 --- a/Source/Private/TextExperiment/String/ASTextRunDelegate.h +++ b/Source/Private/TextExperiment/String/ASTextRunDelegate.h @@ -43,7 +43,7 @@ NS_ASSUME_NONNULL_BEGIN /** Additional information about the the run delegate. */ -@property (nullable, nonatomic) NSDictionary *userInfo; +@property (nullable, nonatomic, copy) NSDictionary *userInfo; /** The typographic ascent of glyphs in the run. diff --git a/Source/Private/_ASPendingState.mm b/Source/Private/_ASPendingState.mm index ca464bb3..8593bd58 100644 --- a/Source/Private/_ASPendingState.mm +++ b/Source/Private/_ASPendingState.mm @@ -15,7 +15,8 @@ #define __shouldSetNeedsDisplayForView(view) (flags.needsDisplay \ || (flags.setOpaque && _flags.opaque != (view).opaque)\ - || (flags.setBackgroundColor && ![backgroundColor isEqual:(view).backgroundColor])) + || (flags.setBackgroundColor && ![backgroundColor isEqual:(view).backgroundColor])\ + || (flags.setTintColor && ![tintColor isEqual:(view).tintColor])) #define __shouldSetNeedsDisplayForLayer(layer) (flags.needsDisplay \ || (flags.setOpaque && _flags.opaque != (layer).opaque)\ @@ -104,6 +105,7 @@ static constexpr ASPendingStateFlags kZeroFlags = {0}; CGRect frame; // Frame is only to be used for synchronous views wrapped by nodes (see setFrame:) CGRect bounds; UIColor *backgroundColor; + UIColor *tintColor; CGFloat alpha; CGFloat cornerRadius; UIViewContentMode contentMode; @@ -374,7 +376,7 @@ static CGColorRef blackColorRef = NULL; return _flags.allowsEdgeAntialiasing; } -- (void)setEdgeAntialiasingMask:(unsigned int)mask +- (void)setEdgeAntialiasingMask:(CAEdgeAntialiasingMask)mask { edgeAntialiasingMask = mask; _stateToApplyFlags.setEdgeAntialiasingMask = YES; @@ -428,8 +430,16 @@ static CGColorRef blackColorRef = NULL; _stateToApplyFlags.setBackgroundColor = YES; } +- (UIColor *)tintColor +{ + return tintColor; +} + - (void)setTintColor:(UIColor *)newTintColor { + if ([newTintColor isEqual:tintColor]) { + return; + } tintColor = newTintColor; _stateToApplyFlags.setTintColor = YES; } @@ -1097,7 +1107,7 @@ static CGColorRef blackColorRef = NULL; } if (flags.setTintColor) - view.tintColor = self.tintColor; + view.tintColor = tintColor; if (flags.setOpaque) { view.opaque = _flags.opaque; @@ -1324,7 +1334,7 @@ static CGColorRef blackColorRef = NULL; pendingState.contentsScale = layer.contentsScale; pendingState.rasterizationScale = layer.rasterizationScale; pendingState.clipsToBounds = view.clipsToBounds; - pendingState.backgroundColor = [UIColor colorWithCGColor:layer.backgroundColor]; + pendingState.backgroundColor = view.backgroundColor; pendingState.tintColor = view.tintColor; pendingState.opaque = layer.opaque; pendingState.hidden = view.hidden; diff --git a/Source/TextKit/ASTextKitContext.mm b/Source/TextKit/ASTextKitContext.mm index e5b16a69..8c24644d 100644 --- a/Source/TextKit/ASTextKitContext.mm +++ b/Source/TextKit/ASTextKitContext.mm @@ -37,9 +37,7 @@ static dispatch_once_t onceToken; // Concurrently initialising TextKit components crashes (rdar://18448377) so we use a global lock. dispatch_once(&onceToken, ^{ - if (!ASActivateExperimentalFeature(ASExperimentalRemoveTextKitInitialisingLock)) { mutex = new AS::Mutex(); - } }); if (mutex != NULL) { mutex->lock(); diff --git a/Source/UIImage+ASConvenience.h b/Source/UIImage+ASConvenience.h index b24c97d1..e662a6a5 100644 --- a/Source/UIImage+ASConvenience.h +++ b/Source/UIImage+ASConvenience.h @@ -9,6 +9,7 @@ #import #import +#import NS_ASSUME_NONNULL_BEGIN @@ -68,7 +69,20 @@ NS_ASSUME_NONNULL_BEGIN */ + (UIImage *)as_resizableRoundedImageWithCornerRadius:(CGFloat)cornerRadius cornerColor:(nullable UIColor *)cornerColor - fillColor:(UIColor *)fillColor NS_RETURNS_RETAINED AS_WARN_UNUSED_RESULT; + fillColor:(UIColor *)fillColor NS_RETURNS_RETAINED AS_WARN_UNUSED_RESULT ASDISPLAYNODE_DEPRECATED_MSG("Use as_resizableRoundedImageWithCornerRadius:cornerColor:fillColor:traitCollection: instead"); + +/** + * This generates a flat-color, rounded-corner resizeable image + * + * @param cornerRadius The radius of the rounded-corner + * @param cornerColor The fill color of the corners (For Alpha corners use clearColor) + * @param fillColor The fill color of the rounded-corner image + * @param traitCollection The trait collection. + */ ++ (UIImage *)as_resizableRoundedImageWithCornerRadius:(CGFloat)cornerRadius + cornerColor:(nullable UIColor *)cornerColor + fillColor:(UIColor *)fillColor + traitCollection:(ASPrimitiveTraitCollection) traitCollection NS_RETURNS_RETAINED AS_WARN_UNUSED_RESULT; /** * This generates a flat-color, rounded-corner resizeable image with a border @@ -83,7 +97,23 @@ NS_ASSUME_NONNULL_BEGIN cornerColor:(UIColor *)cornerColor fillColor:(UIColor *)fillColor borderColor:(nullable UIColor *)borderColor - borderWidth:(CGFloat)borderWidth NS_RETURNS_RETAINED AS_WARN_UNUSED_RESULT; + borderWidth:(CGFloat)borderWidth NS_RETURNS_RETAINED AS_WARN_UNUSED_RESULT ASDISPLAYNODE_DEPRECATED_MSG("Use as_resizableRoundedImageWithCornerRadius:cornerColor:fillColor:borderColor:borderWidth:traitCollection: instead"); + +/** + * This generates a flat-color, rounded-corner resizeable image with a border + * + * @param cornerRadius The radius of the rounded-corner + * @param cornerColor The fill color of the corners (For Alpha corners use clearColor) + * @param fillColor The fill color of the rounded-corner image + * @param borderColor The border color. Set to nil for no border. + * @param borderWidth The border width. Dummy value if borderColor = nil. + * @param traitCollection The trait collection. + */ ++ (UIImage *)as_resizableRoundedImageWithCornerRadius:(CGFloat)cornerRadius + cornerColor:(UIColor *)cornerColor + fillColor:(UIColor *)fillColor + borderColor:(nullable UIColor *)borderColor + borderWidth:(CGFloat)borderWidth traitCollection:(ASPrimitiveTraitCollection) traitCollection NS_RETURNS_RETAINED AS_WARN_UNUSED_RESULT; /** * This generates a flat-color, rounded-corner resizeable image with a border @@ -102,7 +132,30 @@ NS_ASSUME_NONNULL_BEGIN borderColor:(nullable UIColor *)borderColor borderWidth:(CGFloat)borderWidth roundedCorners:(UIRectCorner)roundedCorners - scale:(CGFloat)scale NS_RETURNS_RETAINED AS_WARN_UNUSED_RESULT; + scale:(CGFloat)scale NS_RETURNS_RETAINED AS_WARN_UNUSED_RESULT ASDISPLAYNODE_DEPRECATED_MSG("Use as_resizableRoundedImageWithCornerRadius:cornerColor:fillColor:borderColor:borderWidth:roundedCorners:traitCollection: instead"); +; + +/** + * This generates a flat-color, rounded-corner resizeable image with a border + * + * @param cornerRadius The radius of the rounded-corner + * @param cornerColor The fill color of the corners (For Alpha corners use clearColor) + * @param fillColor The fill color of the rounded-corner image + * @param borderColor The border color. Set to nil for no border. + * @param borderWidth The border width. Dummy value if borderColor = nil. + * @param roundedCorners Select individual or multiple corners to round. Set to UIRectCornerAllCorners to round all 4 corners. + * @param scale The number of pixels per point. Provide 0.0 to use the screen scale. + * @param traitCollection The trait collection. + */ ++ (UIImage *)as_resizableRoundedImageWithCornerRadius:(CGFloat)cornerRadius + cornerColor:(nullable UIColor *)cornerColor + fillColor:(UIColor *)fillColor + borderColor:(nullable UIColor *)borderColor + borderWidth:(CGFloat)borderWidth + roundedCorners:(UIRectCorner)roundedCorners + scale:(CGFloat)scale + traitCollection:(ASPrimitiveTraitCollection) traitCollection +NS_RETURNS_RETAINED AS_WARN_UNUSED_RESULT; @end diff --git a/Source/UIImage+ASConvenience.mm b/Source/UIImage+ASConvenience.mm index ea7267f6..567a377c 100644 --- a/Source/UIImage+ASConvenience.mm +++ b/Source/UIImage+ASConvenience.mm @@ -30,7 +30,12 @@ UIImage *cachedImageNamed(NSString *imageName, UITraitCollection *traitCollectio NSString *imageKey = imageName; if (traitCollection) { char imageKeyBuffer[256]; - snprintf(imageKeyBuffer, sizeof(imageKeyBuffer), "%s|%ld|%ld|%ld", imageName.UTF8String, (long)traitCollection.horizontalSizeClass, (long)traitCollection.verticalSizeClass, (long)traitCollection.userInterfaceStyle); + if (@available(iOS 12.0, *)) { + snprintf(imageKeyBuffer, sizeof(imageKeyBuffer), "%s|%ld|%ld|%ld", imageName.UTF8String, (long)traitCollection.horizontalSizeClass, (long)traitCollection.verticalSizeClass, (long)traitCollection.userInterfaceStyle); + } else { + // Fallback on earlier versions + snprintf(imageKeyBuffer, sizeof(imageKeyBuffer), "%s|%ld|%ld", imageName.UTF8String, (long)traitCollection.horizontalSizeClass, (long)traitCollection.verticalSizeClass); + } imageKey = [NSString stringWithUTF8String:imageKeyBuffer]; } @@ -74,6 +79,38 @@ UIImage *cachedImageNamed(NSString *imageName, UITraitCollection *traitCollectio scale:0.0]; } ++ (UIImage *)as_resizableRoundedImageWithCornerRadius:(CGFloat)cornerRadius + cornerColor:(UIColor *)cornerColor + fillColor:(UIColor *)fillColor + traitCollection:(ASPrimitiveTraitCollection) traitCollection NS_RETURNS_RETAINED +{ + return [self as_resizableRoundedImageWithCornerRadius:cornerRadius + cornerColor:cornerColor + fillColor:fillColor + borderColor:nil + borderWidth:1.0 + roundedCorners:UIRectCornerAllCorners + scale:0.0 + traitCollection:traitCollection]; +} + ++ (UIImage *)as_resizableRoundedImageWithCornerRadius:(CGFloat)cornerRadius + cornerColor:(UIColor *)cornerColor + fillColor:(UIColor *)fillColor + borderColor:(UIColor *)borderColor + borderWidth:(CGFloat)borderWidth + traitCollection:(ASPrimitiveTraitCollection) traitCollection NS_RETURNS_RETAINED { + return [self as_resizableRoundedImageWithCornerRadius:cornerRadius + cornerColor:cornerColor + fillColor:fillColor + borderColor:borderColor + borderWidth:borderWidth + roundedCorners:UIRectCornerAllCorners + scale:0.0 + traitCollection:traitCollection]; +} + + + (UIImage *)as_resizableRoundedImageWithCornerRadius:(CGFloat)cornerRadius cornerColor:(UIColor *)cornerColor fillColor:(UIColor *)fillColor @@ -95,7 +132,27 @@ UIImage *cachedImageNamed(NSString *imageName, UITraitCollection *traitCollectio borderColor:(UIColor *)borderColor borderWidth:(CGFloat)borderWidth roundedCorners:(UIRectCorner)roundedCorners - scale:(CGFloat)scale NS_RETURNS_RETAINED + scale:(CGFloat)scale NS_RETURNS_RETAINED { + + return [self as_resizableRoundedImageWithCornerRadius:cornerRadius + cornerColor:cornerColor + fillColor:fillColor + borderColor:borderColor + borderWidth:borderWidth + roundedCorners:roundedCorners + scale:scale + traitCollection:ASPrimitiveTraitCollectionMakeDefault()]; +} + + ++ (UIImage *)as_resizableRoundedImageWithCornerRadius:(CGFloat)cornerRadius + cornerColor:(UIColor *)cornerColor + fillColor:(UIColor *)fillColor + borderColor:(UIColor *)borderColor + borderWidth:(CGFloat)borderWidth + roundedCorners:(UIRectCorner)roundedCorners + scale:(CGFloat)scale + traitCollection:(ASPrimitiveTraitCollection) traitCollection NS_RETURNS_RETAINED { static NSCache *__pathCache = nil; static dispatch_once_t onceToken; @@ -129,7 +186,7 @@ UIImage *cachedImageNamed(NSString *imageName, UITraitCollection *traitCollectio // We should probably check if the background color has any alpha component but that // might be expensive due to needing to check mulitple color spaces. - UIImage *result = ASGraphicsCreateImageWithOptions(bounds.size, cornerColor != nil, scale, nil, nil, ^{ + UIImage *result = ASGraphicsCreateImage(traitCollection, bounds.size, cornerColor != nil, scale, nil, nil, ^{ BOOL contextIsClean = YES; if (cornerColor) { contextIsClean = NO; diff --git a/Tests/ASBridgedPropertiesTests.mm b/Tests/ASBridgedPropertiesTests.mm index 8e4a202e..1034cc3a 100644 --- a/Tests/ASBridgedPropertiesTests.mm +++ b/Tests/ASBridgedPropertiesTests.mm @@ -21,6 +21,7 @@ @interface ASBridgedPropertiesTestView : UIView @property (nonatomic, readonly) BOOL receivedSetNeedsLayout; +@property (nonatomic, readonly) NSUInteger setNeedsDisplayCount; @end @implementation ASBridgedPropertiesTestView @@ -31,6 +32,12 @@ [super setNeedsLayout]; } +- (void)setNeedsDisplay +{ + _setNeedsDisplayCount += 1; + [super setNeedsDisplay]; +} + @end @interface ASBridgedPropertiesTestNode : ASDisplayNode @@ -138,6 +145,32 @@ static inline void ASDispatchSyncOnOtherThread(dispatch_block_t block) { }); } +- (void)testThatSettingTintColorSetNeedsDisplayOnView +{ + ASPendingStateController *ctrl = [ASPendingStateController sharedInstance]; + + ASDisplayNode *node = [[ASDisplayNode alloc] initWithViewClass:ASBridgedPropertiesTestView.class]; + ASBridgedPropertiesTestView *view = (ASBridgedPropertiesTestView *)node.view; + NSUInteger initialSetNeedsDisplayCount = view.setNeedsDisplayCount; +#if AS_AT_LEAST_IOS13 + // This is called an extra time on iOS13 for unknown reasons. Need to Investigate. + if (@available(iOS 13.0, *)) { + XCTAssertEqual(initialSetNeedsDisplayCount, 2); + } else { + XCTAssertEqual(initialSetNeedsDisplayCount, 1); + } +#endif + + ASDispatchSyncOnOtherThread(^{ + node.tintColor = UIColor.orangeColor; + }); + XCTAssertNotEqualObjects(view.tintColor, UIColor.orangeColor); + XCTAssertEqual(view.setNeedsDisplayCount, initialSetNeedsDisplayCount); + [ctrl flush]; + XCTAssertEqualObjects(view.tintColor, UIColor.orangeColor); + XCTAssertEqual(view.setNeedsDisplayCount, initialSetNeedsDisplayCount + 1); +} + - (void)testThatManuallyFlushingTheSyncControllerImmediatelyAppliesChanges { ASPendingStateController *ctrl = [ASPendingStateController sharedInstance]; diff --git a/Tests/ASButtonNodeSnapshotTests.mm b/Tests/ASButtonNodeSnapshotTests.mm index ea8385f9..26ab279f 100644 --- a/Tests/ASButtonNodeSnapshotTests.mm +++ b/Tests/ASButtonNodeSnapshotTests.mm @@ -80,4 +80,36 @@ ASSnapshotVerifyNode(node, nil); } +- (void)testTintColorWithInheritedTintColor +{ + ASDisplayNode *container = [[ASDisplayNode alloc] init]; + container.tintColor = UIColor.redColor; + + // Add to hierarchy, assert new tint is picked up + ASButtonNode *node = [[ASButtonNode alloc] init]; + [container addSubnode:node]; + [node setImage:[[self testImage] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] forState:UIControlStateNormal]; + [node setTitle:@"Press Me" + withFont:[UIFont systemFontOfSize:48] + withColor:nil + forState:UIControlStateNormal]; + node.imageNode.style.width = ASDimensionMake(200); + node.imageNode.style.height = ASDimensionMake(200); + container.style.preferredSize = CGSizeMake(1000,1000); + ASDisplayNodeSizeToFitSize(node, CGSizeMake(1000, 1000)); + // Force load so the superview is set for the button _ASDisplayView + __unused UIView *v = container.view; + ASSnapshotVerifyNode(node, @"red_inherited_tint"); + + // Change hierarchy, assert new tint is picked up + ASDisplayNode *container2 = [[ASDisplayNode alloc] init]; + container2.tintColor = UIColor.greenColor; + container2.style.preferredSize = CGSizeMake(1000,1000); + [container2 addSubnode:node]; + ASDisplayNodeSizeToFitSize(node, CGSizeMake(1000, 1000)); + // Force load so the superview is set for the button _ASDisplayView + __unused UIView *v2 = container2.view; // Force load + ASSnapshotVerifyNode(node, @"green_inherited_tint"); +} + @end diff --git a/Tests/ASCollectionViewFlowLayoutInspectorTests.mm b/Tests/ASCollectionViewFlowLayoutInspectorTests.mm index 555fe211..df457448 100644 --- a/Tests/ASCollectionViewFlowLayoutInspectorTests.mm +++ b/Tests/ASCollectionViewFlowLayoutInspectorTests.mm @@ -32,22 +32,22 @@ @implementation InspectorTestDataSource -- (ASCellNode *)collectionView:(ASCollectionView *)collectionView nodeForItemAtIndexPath:(NSIndexPath *)indexPath +- (ASCellNode *)collectionNode:(ASCollectionNode *)collectionNode nodeForItemAtIndexPath:(NSIndexPath *)indexPath { return [[ASCellNode alloc] init]; } -- (ASCellNodeBlock)collectionView:(ASCollectionView *)collectionView nodeBlockForItemAtIndexPath:(NSIndexPath *)indexPath +- (ASCellNodeBlock)collectionNode:(ASCollectionNode *)collectionNode nodeBlockForItemAtIndexPath:(NSIndexPath *)indexPath { return ^{ return [[ASCellNode alloc] init]; }; } -- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section +- (NSInteger)collectionNode:(ASCollectionNode *)collectionNode numberOfItemsInSection:(NSInteger)section { return 0; } -- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView +- (NSInteger)numberOfSectionsInCollectionNode:(ASCollectionNode *)collectionNode { return 2; } @@ -63,12 +63,12 @@ @implementation InspectorTestDataSourceDelegateWithoutNodeConstrainedSize -- (ASCellNodeBlock)collectionView:(ASCollectionView *)collectionView nodeBlockForItemAtIndexPath:(NSIndexPath *)indexPath +- (ASCellNodeBlock)collectionNode:(ASCollectionNode *)collectionNode nodeBlockForItemAtIndexPath:(NSIndexPath *)indexPath { return ^{ return [[ASCellNode alloc] init]; }; } -- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section +- (NSInteger)collectionNode:(ASCollectionNode *)collectionNode numberOfItemsInSection:(NSInteger)section { return 0; } @@ -88,9 +88,9 @@ @implementation HeaderReferenceSizeTestDelegate -- (CGSize)collectionView:(ASCollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section +- (ASSizeRange)collectionNode:(ASCollectionNode *)collectionNode sizeRangeForHeaderInSection:(NSInteger)section { - return CGSizeMake(125.0, 125.0); + return ASSizeRangeMake(CGSizeMake(125.0, 125.0)); } @end @@ -104,9 +104,9 @@ @implementation FooterReferenceSizeTestDelegate -- (CGSize)collectionView:(ASCollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout referenceSizeForFooterInSection:(NSInteger)section +- (ASSizeRange)collectionNode:(ASCollectionNode *)collectionNode sizeRangeForFooterInSection:(NSInteger)section { - return CGSizeMake(125.0, 125.0); + return ASSizeRangeMake(CGSizeMake(125.0, 125.0)); } @end diff --git a/Tests/ASCollectionViewTests.mm b/Tests/ASCollectionViewTests.mm index 7359aadd..496c1feb 100644 --- a/Tests/ASCollectionViewTests.mm +++ b/Tests/ASCollectionViewTests.mm @@ -78,7 +78,7 @@ return self; } -- (ASCellNode *)collectionView:(ASCollectionView *)collectionView nodeForItemAtIndexPath:(NSIndexPath *)indexPath { +- (ASCellNode *)collectionNode:(ASCollectionNode *)collectionNode nodeForItemAtIndexPath:(NSIndexPath *)indexPath { ASTextCellNodeWithSetSelectedCounter *textCellNode = [ASTextCellNodeWithSetSelectedCounter new]; textCellNode.text = indexPath.description; @@ -86,7 +86,7 @@ } -- (ASCellNodeBlock)collectionView:(ASCollectionView *)collectionView nodeBlockForItemAtIndexPath:(NSIndexPath *)indexPath { +- (ASCellNodeBlock)collectionNode:(ASCollectionNode *)collectionNode nodeBlockForItemAtIndexPath:(NSIndexPath *)indexPath { return ^{ ASTextCellNodeWithSetSelectedCounter *textCellNode = [ASTextCellNodeWithSetSelectedCounter new]; textCellNode.text = indexPath.description; @@ -94,11 +94,11 @@ }; } -- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView { +- (NSInteger)numberOfSectionsInCollectionNode:(ASCollectionNode *)collectionNode { return _itemCounts.size(); } -- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { +- (NSInteger)collectionNode:(ASCollectionNode *)collectionNode numberOfItemsInSection:(NSInteger)section { return _itemCounts[section]; } @@ -115,7 +115,7 @@ return CGSizeMake(100, 100); } -- (ASCellNode *)collectionView:(ASCollectionView *)collectionView nodeForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath +- (ASCellNode *)collectionNode:(ASCollectionNode *)collectionNode nodeForSupplementaryElementOfKind:(nonnull NSString *)kind atIndexPath:(nonnull NSIndexPath *)indexPath { return [[ASTextCellNodeWithSetSelectedCounter alloc] init]; } @@ -147,8 +147,7 @@ // Populate these immediately so that they're not unexpectedly nil during tests. self.asyncDelegate = [[ASCollectionViewTestDelegate alloc] initWithNumberOfSections:10 numberOfItemsInSection:10]; id realLayout = [UICollectionViewFlowLayout new]; - id mockLayout = [OCMockObject partialMockForObject:realLayout]; - self.collectionNode = [[ASCollectionNode alloc] initWithFrame:self.view.bounds collectionViewLayout:mockLayout]; + self.collectionNode = [[ASCollectionNode alloc] initWithFrame:self.view.bounds collectionViewLayout:realLayout]; self.collectionView = self.collectionNode.view; self.collectionView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; self.collectionNode.dataSource = self.asyncDelegate; @@ -182,18 +181,6 @@ [ASConfigurationManager test_resetWithConfiguration:config]; } -- (void)tearDown -{ - // We can't prevent the system from retaining windows, but we can at least clear them out to avoid - // pollution between test cases. - for (UIWindow *window in [UIApplication sharedApplication].windows) { - for (UIView *subview in window.subviews) { - [subview removeFromSuperview]; - } - } - [super tearDown]; -} - - (void)testDataSourceImplementsNecessaryMethods { UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init]; @@ -648,14 +635,14 @@ - (void)testThatNodeCalculatedSizesAreUpdatedBeforeFirstPrepareLayoutAfterRotation { updateValidationTestPrologue - id layout = cv.collectionViewLayout; + id collectionViewLayoutMock = OCMPartialMock(cv.collectionViewLayout); CGSize initialItemSize = [cv nodeForItemAtIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]].calculatedSize; CGSize initialCVSize = cv.bounds.size; // Capture the node size before first call to prepareLayout after frame change. __block CGSize itemSizeAtFirstLayout = CGSizeZero; __block CGSize boundsSizeAtFirstLayout = CGSizeZero; - [[[[layout expect] andDo:^(NSInvocation *) { + [[[[collectionViewLayoutMock expect] andDo:^(NSInvocation *) { itemSizeAtFirstLayout = [cv nodeForItemAtIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]].calculatedSize; boundsSizeAtFirstLayout = [cv bounds].size; }] andForwardToRealObject] prepareLayout]; @@ -670,10 +657,12 @@ XCTAssertNotEqualObjects(NSStringFromCGSize(initialCVSize), NSStringFromCGSize(boundsSizeAtFirstLayout)); XCTAssertEqualObjects(NSStringFromCGSize(itemSizeAtFirstLayout), NSStringFromCGSize(finalItemSize)); XCTAssertEqualObjects(NSStringFromCGSize(boundsSizeAtFirstLayout), NSStringFromCGSize(finalCVSize)); - [layout verify]; + [collectionViewLayoutMock verify]; // Teardown [[UIDevice currentDevice] setValue:@(oldDeviceOrientation) forKey:@"orientation"]; + + [collectionViewLayoutMock stopMocking]; } /** @@ -1152,6 +1141,31 @@ } } +- (void)testASPrimitiveTraitCollectionToUITraitCollection { + ASPrimitiveTraitCollection collection = ASPrimitiveTraitCollectionMakeDefault(); + collection.displayGamut = UIDisplayGamutSRGB; + collection.displayScale = 11; + collection.forceTouchCapability = UIForceTouchCapabilityAvailable; + collection.horizontalSizeClass = UIUserInterfaceSizeClassRegular; + collection.layoutDirection = UITraitEnvironmentLayoutDirectionRightToLeft; + collection.preferredContentSizeCategory = UIContentSizeCategoryMedium; + collection.userInterfaceIdiom = UIUserInterfaceIdiomTV; + if (@available(iOS 12.0, *)) { + collection.userInterfaceStyle = UIUserInterfaceStyleDark; + } + collection.verticalSizeClass = UIUserInterfaceSizeClassRegular; + + // create `UITraitCollection` from `ASPrimitiveTraitCollection` + UITraitCollection *uiCollection = ASPrimitiveTraitCollectionToUITraitCollection(collection); + + // now convert it back to `ASPrimitiveTraitCollection` + ASPrimitiveTraitCollection newCollection = ASPrimitiveTraitCollectionFromUITraitCollection(uiCollection); + + // compare + XCTAssert(ASPrimitiveTraitCollectionIsEqualToASPrimitiveTraitCollection(collection, newCollection)); +} + + /** * This tests an issue where, since subnode insertions aren't applied until the UIKit layout pass, * which we trigger during the display phase, subnodes like network image nodes are not preloading diff --git a/Tests/ASCollectionViewThrashTests.mm b/Tests/ASCollectionViewThrashTests.mm index 368b33d6..b609cb2b 100644 --- a/Tests/ASCollectionViewThrashTests.mm +++ b/Tests/ASCollectionViewThrashTests.mm @@ -151,10 +151,10 @@ @autoreleasepool { dispatch_async(dispatch_get_main_queue(), ^{ NSArray *sections = [ASThrashTestSection sectionsWithCount:kInitialSectionCount]; - _update = [[ASThrashUpdate alloc] initWithData:sections]; + self->_update = [[ASThrashUpdate alloc] initWithData:sections]; ASThrashDataSource *ds = [[ASThrashDataSource alloc] initCollectionViewDataSourceWithData:sections]; - [self applyUpdateUsingBatchUpdates:_update + [self applyUpdateUsingBatchUpdates:self->_update toDataSource:ds animated:NO useXCTestWait:NO]; diff --git a/Tests/ASConfigurationTests.mm b/Tests/ASConfigurationTests.mm index c5e533e2..755375af 100644 --- a/Tests/ASConfigurationTests.mm +++ b/Tests/ASConfigurationTests.mm @@ -20,17 +20,15 @@ static ASExperimentalFeatures features[] = { ASExperimentalTextNode, #endif ASExperimentalInterfaceStateCoalescing, - ASExperimentalUnfairLock, ASExperimentalLayerDefaults, ASExperimentalCollectionTeardown, ASExperimentalFramesetterCache, ASExperimentalSkipClearData, ASExperimentalDidEnterPreloadSkipASMLayout, ASExperimentalDispatchApply, - ASExperimentalOOMBackgroundDeallocDisable, - ASExperimentalRemoveTextKitInitialisingLock, ASExperimentalDrawingGlobal, - ASExperimentalOptimizeDataControllerPipeline + ASExperimentalOptimizeDataControllerPipeline, + ASExperimentalDoNotCacheAccessibilityElements, }; @interface ASConfigurationTests : ASTestCase @@ -45,17 +43,15 @@ static ASExperimentalFeatures features[] = { return @[ @"exp_text_node", @"exp_interface_state_coalesce", - @"exp_unfair_lock", @"exp_infer_layer_defaults", @"exp_collection_teardown", @"exp_framesetter_cache", @"exp_skip_clear_data", @"exp_did_enter_preload_skip_asm_layout", @"exp_dispatch_apply", - @"exp_oom_bg_dealloc_disable", - @"exp_remove_textkit_initialising_lock", @"exp_drawing_global", - @"exp_optimize_data_controller_pipeline" + @"exp_optimize_data_controller_pipeline", + @"exp_do_not_cache_accessibility_elements", ]; } diff --git a/Tests/ASDisplayNodeAppearanceTests.mm b/Tests/ASDisplayNodeAppearanceTests.mm index 515bcf7c..b771da35 100644 --- a/Tests/ASDisplayNodeAppearanceTests.mm +++ b/Tests/ASDisplayNodeAppearanceTests.mm @@ -82,11 +82,11 @@ static dispatch_block_t modifyMethodByAddingPrologueBlockAndReturnCleanupBlock(C _didExitHierarchyCounts = [[NSCountedSet alloc] init]; dispatch_block_t cleanupBlock = modifyMethodByAddingPrologueBlockAndReturnCleanupBlock([ASDisplayNode class], @selector(willEnterHierarchy), ^(id blockSelf){ - [_willEnterHierarchyCounts addObject:blockSelf]; + [self->_willEnterHierarchyCounts addObject:blockSelf]; }); [_swizzleCleanupBlocks addObject:cleanupBlock]; cleanupBlock = modifyMethodByAddingPrologueBlockAndReturnCleanupBlock([ASDisplayNode class], @selector(didExitHierarchy), ^(id blockSelf){ - [_didExitHierarchyCounts addObject:blockSelf]; + [self->_didExitHierarchyCounts addObject:blockSelf]; }); [_swizzleCleanupBlocks addObject:cleanupBlock]; } @@ -117,6 +117,7 @@ static dispatch_block_t modifyMethodByAddingPrologueBlockAndReturnCleanupBlock(C { // ASDisplayNode visibility does not change if modifying a hierarchy that is not in a window. So create one and add the superview to it. UIWindow *window = [[UIWindow alloc] initWithFrame:CGRectZero]; + [window makeKeyAndVisible]; DeclareNodeNamed(n); DeclareViewNamed(superview); @@ -154,6 +155,7 @@ static dispatch_block_t modifyMethodByAddingPrologueBlockAndReturnCleanupBlock(C { // ASDisplayNode visibility does not change if modifying a hierarchy that is not in a window. So create one and add the superview to it. UIWindow *window = [[UIWindow alloc] initWithFrame:CGRectZero]; + [window makeKeyAndVisible]; DeclareNodeNamed(parent); DeclareNodeNamed(a); @@ -253,6 +255,7 @@ static dispatch_block_t modifyMethodByAddingPrologueBlockAndReturnCleanupBlock(C layerBackedNode.layerBacked = YES; UIWindow *window = [[UIWindow alloc] initWithFrame:CGRectZero]; + [window makeKeyAndVisible]; [parentSynchronousNode addSubnode:layerBackedNode]; [parentSynchronousNode addSubnode:viewBackedNode]; @@ -291,6 +294,7 @@ static dispatch_block_t modifyMethodByAddingPrologueBlockAndReturnCleanupBlock(C - (void)checkMoveAcrossHierarchyLayerBacked:(BOOL)isLayerBacked useManualCalls:(BOOL)useManualDisable useNodeAPI:(BOOL)useNodeAPI { UIWindow *window = [[UIWindow alloc] initWithFrame:CGRectZero]; + [window makeKeyAndVisible]; DeclareNodeNamed(parentA); DeclareNodeNamed(parentB); @@ -374,6 +378,8 @@ static dispatch_block_t modifyMethodByAddingPrologueBlockAndReturnCleanupBlock(C // Make sure that we don't leave these unbalanced XCTAssertFalse([child __visibilityNotificationsDisabled], @"Unbalanced visibility notifications calls"); XCTAssertFalse([child __selfOrParentHasVisibilityNotificationsDisabled], @"Should not have re-enabled yet"); + [parentA removeFromSupernode]; + [parentB removeFromSupernode]; } - (void)testMoveAcrossHierarchyLayer diff --git a/Tests/ASDisplayNodeSnapshotTests.mm b/Tests/ASDisplayNodeSnapshotTests.mm index e849ac07..964bbb50 100644 --- a/Tests/ASDisplayNodeSnapshotTests.mm +++ b/Tests/ASDisplayNodeSnapshotTests.mm @@ -67,12 +67,35 @@ NS_INLINE UIImage *BlueImageMake(CGRect bounds) node.image = BlueImageMake(bounds); node.frame = bounds; node.cornerRoundingType = ASCornerRoundingTypeClipping; +#if AS_AT_LEAST_IOS13 + if (@available(iOS 13.0, *)) { + node.backgroundColor = UIColor.systemBackgroundColor; + } else { + node.backgroundColor = UIColor.greenColor; + } +#else node.backgroundColor = UIColor.greenColor; +#endif node.maskedCorners = c; node.cornerRadius = 15; // A layout pass is required, because that's where we lay out the clip layers. [node.layer layoutIfNeeded]; + +#if AS_AT_LEAST_IOS13 + if (@available(iOS 13.0, *)) { + [[UITraitCollection traitCollectionWithUserInterfaceStyle:UIUserInterfaceStyleLight] performAsCurrentTraitCollection:^{ + ASSnapshotVerifyNode(node, ([NSString stringWithFormat:@"%d_light", (int)c])); + }]; + + [[UITraitCollection traitCollectionWithUserInterfaceStyle:UIUserInterfaceStyleDark] performAsCurrentTraitCollection:^{ + ASSnapshotVerifyNode(node, ([NSString stringWithFormat:@"%d_dark", (int)c])); + }]; + } else { + ASSnapshotVerifyNode(node, ([NSString stringWithFormat:@"%d", (int)c])); + } +#else ASSnapshotVerifyNode(node, ([NSString stringWithFormat:@"%d", (int)c])); +#endif } } @@ -81,10 +104,6 @@ NS_INLINE UIImage *BlueImageMake(CGRect bounds) - (void)testUserInterfaceStyleSnapshotTesting { if (@available(iOS 13.0, *)) { - ASConfiguration *config = [ASConfiguration new]; - config.experimentalFeatures = ASExperimentalTraitCollectionDidChangeWithPreviousCollection; - [ASConfigurationManager test_resetWithConfiguration:config]; - ASDisplayNode *node = [[ASDisplayNode alloc] init]; [node setLayerBacked:YES]; @@ -103,6 +122,45 @@ NS_INLINE UIImage *BlueImageMake(CGRect bounds) } } +- (void)testBackgroundDynamicColor { + if (@available(iOS 13.0, *)) { + ASDisplayNode *node = [[ASImageNode alloc] init]; + node.backgroundColor = [UIColor systemGray6Color]; + auto bounds = CGRectMake(0, 0, 100, 100); + node.frame = bounds; + + UITraitCollection *tcLight = [UITraitCollection traitCollectionWithUserInterfaceStyle:UIUserInterfaceStyleLight]; + [tcLight performAsCurrentTraitCollection: ^{ + ASSnapshotVerifyNode(node, @"light"); + }]; + + UITraitCollection *tcDark = [UITraitCollection traitCollectionWithUserInterfaceStyle:UIUserInterfaceStyleDark]; + [tcDark performAsCurrentTraitCollection: ^{ + ASSnapshotVerifyNode(node, @"dark"); + }]; + } +} + +- (void)testBackgroundDynamicColorLayerBacked { + if (@available(iOS 13.0, *)) { + ASDisplayNode *node = [[ASImageNode alloc] init]; + node.backgroundColor = [UIColor systemGray6Color]; + node.layerBacked = YES; + auto bounds = CGRectMake(0, 0, 100, 100); + node.frame = bounds; + + UITraitCollection *tcLight = [UITraitCollection traitCollectionWithUserInterfaceStyle:UIUserInterfaceStyleLight]; + [tcLight performAsCurrentTraitCollection: ^{ + ASSnapshotVerifyNode(node, @"light"); + }]; + + UITraitCollection *tcDark = [UITraitCollection traitCollectionWithUserInterfaceStyle:UIUserInterfaceStyleDark]; + [tcDark performAsCurrentTraitCollection: ^{ + ASSnapshotVerifyNode(node, @"dark"); + }]; + } +} + #endif // #if AS_AT_LEAST_IOS13 @end diff --git a/Tests/ASDisplayNodeTests.mm b/Tests/ASDisplayNodeTests.mm index 802b9ee3..e6ef1be3 100644 --- a/Tests/ASDisplayNodeTests.mm +++ b/Tests/ASDisplayNodeTests.mm @@ -465,14 +465,14 @@ for (ASDisplayNode *n in @[ nodes ]) {\ XCTAssertEqual(NO, node.needsDisplayOnBoundsChange, @"default needsDisplayOnBoundsChange broken %@", hasLoadedView); XCTAssertEqual(YES, node.allowsGroupOpacity, @"default allowsGroupOpacity broken %@", hasLoadedView); XCTAssertEqual(NO, node.allowsEdgeAntialiasing, @"default allowsEdgeAntialiasing broken %@", hasLoadedView); - XCTAssertEqual((unsigned int)(kCALayerLeftEdge | kCALayerRightEdge | kCALayerBottomEdge | kCALayerTopEdge), node.edgeAntialiasingMask, @"default edgeAntialisingMask broken %@", hasLoadedView); + XCTAssertEqual((kCALayerLeftEdge | kCALayerRightEdge | kCALayerBottomEdge | kCALayerTopEdge), node.edgeAntialiasingMask, @"default edgeAntialisingMask broken %@", hasLoadedView); XCTAssertEqual(NO, node.hidden, @"default hidden broken %@", hasLoadedView); XCTAssertEqual(1.0f, node.alpha, @"default alpha broken %@", hasLoadedView); XCTAssertTrue(CGRectEqualToRect(CGRectZero, node.bounds), @"default bounds broken %@", hasLoadedView); XCTAssertTrue(CGRectEqualToRect(CGRectZero, node.frame), @"default frame broken %@", hasLoadedView); XCTAssertTrue(CGPointEqualToPoint(CGPointZero, node.position), @"default position broken %@", hasLoadedView); XCTAssertEqual((CGFloat)0.0, node.zPosition, @"default zPosition broken %@", hasLoadedView); - XCTAssertEqual(1.0f, node.contentsScale, @"default contentsScale broken %@", hasLoadedView); + XCTAssertEqual(node.isNodeLoaded && !isLayerBacked ? 2.0f : 1.0f, node.contentsScale, @"default contentsScale broken %@", hasLoadedView); XCTAssertEqual([UIScreen mainScreen].scale, node.contentsScaleForDisplay, @"default contentsScaleForDisplay broken %@", hasLoadedView); XCTAssertTrue(CATransform3DEqualToTransform(CATransform3DIdentity, node.transform), @"default transform broken %@", hasLoadedView); XCTAssertTrue(CATransform3DEqualToTransform(CATransform3DIdentity, node.subnodeTransform), @"default subnodeTransform broken %@", hasLoadedView); @@ -515,9 +515,15 @@ for (ASDisplayNode *n in @[ nodes ]) {\ XCTAssertEqual(NO, node.preservesSuperviewLayoutMargins, @"default preservesSuperviewLayoutMargins broken %@", hasLoadedView); XCTAssertTrue(UIEdgeInsetsEqualToEdgeInsets(UIEdgeInsetsZero, node.safeAreaInsets), @"default safeAreaInsets broken %@", hasLoadedView); XCTAssertEqual(YES, node.insetsLayoutMarginsFromSafeArea, @"default insetsLayoutMarginsFromSafeArea broken %@", hasLoadedView); + if (node.nodeLoaded) { + XCTAssertNotNil(node.tintColor, @"default tintColor broken %@", hasLoadedView); // It has been populated by the UIView. + } else { + XCTAssertNil(node.tintColor, @"default tintColor broken %@", hasLoadedView); + } } else { XCTAssertEqual(NO, node.userInteractionEnabled, @"layer-backed nodes do not support userInteractionEnabled %@", hasLoadedView); XCTAssertEqual(NO, node.exclusiveTouch, @"layer-backed nodes do not support exclusiveTouch %@", hasLoadedView); + XCTAssertNil(node.tintColor, @"default tintColor broken %@", hasLoadedView); } } @@ -579,7 +585,7 @@ for (ASDisplayNode *n in @[ nodes ]) {\ XCTAssertEqual(YES, node.needsDisplayOnBoundsChange, @"needsDisplayOnBoundsChange broken %@", hasLoadedView); XCTAssertEqual(NO, node.allowsGroupOpacity, @"allowsGroupOpacity broken %@", hasLoadedView); XCTAssertEqual(YES, node.allowsEdgeAntialiasing, @"allowsEdgeAntialiasing broken %@", hasLoadedView); - XCTAssertTrue((unsigned int)(kCALayerLeftEdge | kCALayerTopEdge) == node.edgeAntialiasingMask, @"edgeAntialiasingMask broken: %@", hasLoadedView); + XCTAssertTrue((kCALayerLeftEdge | kCALayerTopEdge) == node.edgeAntialiasingMask, @"edgeAntialiasingMask broken: %@", hasLoadedView); XCTAssertEqual(YES, node.hidden, @"hidden broken %@", hasLoadedView); XCTAssertEqual(.5f, node.alpha, @"alpha broken %@", hasLoadedView); XCTAssertTrue(CGRectEqualToRect(CGRectMake(10, 15, 42, 115.2), node.bounds), @"bounds broken %@", hasLoadedView); @@ -589,6 +595,7 @@ for (ASDisplayNode *n in @[ nodes ]) {\ XCTAssertTrue(CATransform3DEqualToTransform(CATransform3DMakeScale(0.5, 0.5, 1.0), node.transform), @"transform broken %@", hasLoadedView); XCTAssertTrue(CATransform3DEqualToTransform(CATransform3DMakeTranslation(1337, 7357, 7007), node.subnodeTransform), @"subnodeTransform broken %@", hasLoadedView); XCTAssertEqualObjects([UIColor clearColor], node.backgroundColor, @"backgroundColor broken %@", hasLoadedView); + XCTAssertEqualObjects([UIColor orangeColor], node.tintColor, @"tintColor broken %@", hasLoadedView); XCTAssertEqual(UIViewContentModeBottom, node.contentMode, @"contentMode broken %@", hasLoadedView); XCTAssertEqual([[UIColor cyanColor] CGColor], node.shadowColor, @"shadowColor broken %@", hasLoadedView); XCTAssertEqual(.5f, node.shadowOpacity, @"shadowOpacity broken %@", hasLoadedView); @@ -663,6 +670,7 @@ for (ASDisplayNode *n in @[ nodes ]) {\ node.transform = CATransform3DMakeScale(0.5, 0.5, 1.0); node.subnodeTransform = CATransform3DMakeTranslation(1337, 7357, 7007); node.backgroundColor = [UIColor clearColor]; + node.tintColor = [UIColor orangeColor]; node.contentMode = UIViewContentModeBottom; node.shadowColor = [[UIColor cyanColor] CGColor]; node.shadowOpacity = .5f; @@ -753,6 +761,7 @@ for (ASDisplayNode *n in @[ nodes ]) {\ return view; }]; node.backgroundColor = [UIColor blueColor]; + node.tintColor = [UIColor orangeColor]; node.frame = CGRectMake(10, 20, 30, 40); node.autoresizingMask = UIViewAutoresizingFlexibleWidth; node.userInteractionEnabled = YES; @@ -772,6 +781,7 @@ for (ASDisplayNode *n in @[ nodes ]) {\ [node view]; node.backgroundColor = [UIColor blueColor]; + node.tintColor = [UIColor orangeColor]; node.frame = CGRectMake(10, 20, 30, 40); node.autoresizingMask = UIViewAutoresizingFlexibleWidth; node.userInteractionEnabled = YES; @@ -784,6 +794,7 @@ for (ASDisplayNode *n in @[ nodes ]) {\ UIView *view = node.view; XCTAssertEqualObjects([UIColor blueColor], view.backgroundColor, @"backgroundColor not propagated to view"); + XCTAssertEqualObjects([UIColor orangeColor], view.tintColor, @"tintColor not propagated to view"); XCTAssertTrue(CGRectEqualToRect(CGRectMake(10, 20, 30, 40), view.frame), @"frame not propagated to view"); XCTAssertEqual(UIViewAutoresizingFlexibleWidth, view.autoresizingMask, @"autoresizingMask not propagated to view"); XCTAssertEqual(YES, view.userInteractionEnabled, @"userInteractionEnabled not propagated to view"); @@ -2643,7 +2654,9 @@ static bool stringContainsPointer(NSString *description, id p) { ASXCTAssertEqualPoints([node convertPoint:node.bounds.origin toNode:nil], expectedOrigin); } -- (void)testThatItIsAllowedToRetrieveDebugDescriptionIncludingVCOffMainThread +// this test fails with assertion cause some data should be accessed from the main thread +// so it doesn't really work +- (void)DISABLED_testThatItIsAllowedToRetrieveDebugDescriptionIncludingVCOffMainThread { ASDisplayNode *node = [[ASDisplayNode alloc] init]; UIViewController *vc = [[UIViewController alloc] init]; @@ -2677,7 +2690,9 @@ static bool stringContainsPointer(NSString *description, id p) { UIWindow *window = [[UIWindow alloc] init]; window.rootViewController = viewController; [window setHidden:NO]; - [window layoutIfNeeded]; + + [window.rootViewController.view setNeedsLayout]; + [window.rootViewController.view layoutIfNeeded]; UIEdgeInsets expectedRootNodeSafeArea = UIEdgeInsetsMake(10, 10, 10, 10); UIEdgeInsets expectedSubnodeSafeArea = UIEdgeInsetsMake(9, 8, 7, 6); @@ -2736,6 +2751,7 @@ static bool stringContainsPointer(NSString *description, id p) { - (void)testLayerActionForKeyIsCalled { UIWindow *window = [[UIWindow alloc] init]; + [window makeKeyAndVisible]; ASDisplayNode *node = [[ASDisplayNode alloc] init]; id mockNode = OCMPartialMock(node); diff --git a/Tests/ASDisplayViewAccessibilityTests.mm b/Tests/ASDisplayViewAccessibilityTests.mm index 15d14c29..4dc68e37 100644 --- a/Tests/ASDisplayViewAccessibilityTests.mm +++ b/Tests/ASDisplayViewAccessibilityTests.mm @@ -12,14 +12,21 @@ #import +#import +#import +#import #import #import #import #import #import +#import +#import #import #import "ASDisplayNodeTestsHelper.h" +extern void SortAccessibilityElements(NSMutableArray *elements); + @interface ASDisplayViewAccessibilityTests : XCTestCase @end @@ -32,6 +39,11 @@ ASDisplayNode *subnode = nil; node = [[ASDisplayNode alloc] init]; subnode = [[ASDisplayNode alloc] init]; + + UIWindow *window = [[UIWindow alloc] initWithFrame:CGRectMake(0, 0, 320, 560)]; + [window addSubnode:node]; + [window makeKeyAndVisible]; + NSString *label = @"foo"; subnode.isAccessibilityElement = YES; subnode.accessibilityLabel = label; @@ -54,6 +66,10 @@ innerNode1 = [[ASDisplayNode alloc] init]; innerNode2 = [[ASDisplayNode alloc] init]; + UIWindow *window = [[UIWindow alloc] initWithFrame:CGRectMake(0, 0, 320, 560)]; + [window addSubnode:node]; + [window makeKeyAndVisible]; + // Initialize nodes with relevant accessibility data node.isAccessibilityContainer = YES; innerNode1.accessibilityLabel = @"hello"; @@ -76,6 +92,10 @@ node = [[ASDisplayNode alloc] init]; innerNode = [[ASDisplayNode alloc] init]; + UIWindow *window = [[UIWindow alloc] initWithFrame:CGRectMake(0, 0, 320, 560)]; + [window addSubnode:node]; + [window makeKeyAndVisible]; + // Initialize nodes with relevant accessibility data node.isAccessibilityContainer = YES; node.accessibilityLabel = @"hello"; @@ -92,6 +112,10 @@ - (void)testAccessibilityLayerBackedContainerWithinAccessibilityContainer { ASDisplayNode *container = [[ASDisplayNode alloc] init]; + UIWindow *window = [[UIWindow alloc] initWithFrame:CGRectMake(0, 0, 320, 560)]; + [window addSubnode:container]; + [window makeKeyAndVisible]; + container.frame = CGRectMake(50, 50, 200, 600); container.isAccessibilityContainer = YES; @@ -193,4 +217,276 @@ OCMVerifyAll(mockNode); } +#pragma mark - +#pragma mark AccessibilityElements + +// dummy action for a button +- (void)fakeSelector:(id)sender { } + +- (void)testThatAccessibilityElementsWorks { + + ASDisplayNode *containerNode = [[ASDisplayNode alloc] init]; + UIWindow *window = [[UIWindow alloc] initWithFrame:CGRectMake(0, 0, 320, 560)]; + [window addSubnode:containerNode]; + [window makeKeyAndVisible]; + + containerNode.frame = CGRectMake(0, 0, 100, 200); + + ASTextNode *label = [[ASTextNode alloc] init]; + label.attributedText = [[NSAttributedString alloc] initWithString:@"test label"]; + label.frame = CGRectMake(0, 0, 100, 20); + + ASButtonNode *button = [[ASButtonNode alloc] init]; + [button setTitle:@"tap me" withFont:[UIFont systemFontOfSize:17] withColor:nil forState:UIControlStateNormal]; + [button addTarget:self action:@selector(fakeSelector:) forControlEvents:ASControlNodeEventTouchUpInside]; + button.frame = CGRectMake(0, 25, 100, 20); + + [containerNode addSubnode:label]; + [containerNode addSubnode:button]; + + // force load + __unused UIView *view = containerNode.view; + + NSArray *elements = [containerNode accessibilityElements]; + XCTAssertTrue(elements.count == 2); + XCTAssertEqual([elements.firstObject asyncdisplaykit_node], label); + XCTAssertEqual([elements.lastObject asyncdisplaykit_node], button); +} + +- (void)testThatAccessibilityElementsOverrideWorks { + ASDisplayNode *containerNode = [[ASDisplayNode alloc] init]; + containerNode.frame = CGRectMake(0, 0, 100, 200); + + ASTextNode *label = [[ASTextNode alloc] init]; + label.attributedText = [[NSAttributedString alloc] initWithString:@"test label"]; + label.frame = CGRectMake(0, 0, 100, 20); + + ASButtonNode *button = [[ASButtonNode alloc] init]; + [button setTitle:@"tap me" withFont:[UIFont systemFontOfSize:17] withColor:nil forState:UIControlStateNormal]; + [button addTarget:self action:@selector(fakeSelector:) forControlEvents:ASControlNodeEventTouchUpInside]; + button.frame = CGRectMake(0, 25, 100, 20); + + [containerNode addSubnode:label]; + [containerNode addSubnode:button]; + containerNode.accessibilityElements = @[ label ]; + + // force load + __unused UIView *view = containerNode.view; + + NSArray *elements = [containerNode accessibilityElements]; + XCTAssertTrue(elements.count == 1); + XCTAssertEqual(elements.firstObject, label); +} + +- (void)testHiddenAccessibilityElements { + ASDisplayNode *containerNode = [[ASDisplayNode alloc] init]; + UIWindow *window = [[UIWindow alloc] initWithFrame:CGRectMake(0, 0, 320, 560)]; + [window addSubnode:containerNode]; + [window makeKeyAndVisible]; + + containerNode.frame = CGRectMake(0, 0, 100, 200); + + ASTextNode *label = [[ASTextNode alloc] init]; + label.attributedText = [[NSAttributedString alloc] initWithString:@"test label"]; + label.frame = CGRectMake(0, 0, 100, 20); + + ASTextNode *hiddenLabel = [[ASTextNode alloc] init]; + hiddenLabel.attributedText = [[NSAttributedString alloc] initWithString:@"hidden label"]; + hiddenLabel.frame = CGRectMake(0, 24, 100, 20); + hiddenLabel.hidden = YES; + + [containerNode addSubnode:label]; + [containerNode addSubnode:hiddenLabel]; + + // force load + __unused UIView *view = containerNode.view; + + NSArray *elements = [containerNode accessibilityElements]; + XCTAssertTrue(elements.count == 1); + XCTAssertEqual(elements.firstObject, label.view); +} + +- (void)testTransparentAccessibilityElements { + ASDisplayNode *containerNode = [[ASDisplayNode alloc] init]; + UIWindow *window = [[UIWindow alloc] initWithFrame:CGRectMake(0, 0, 320, 560)]; + [window addSubnode:containerNode]; + [window makeKeyAndVisible]; + containerNode.frame = CGRectMake(0, 0, 100, 200); + + ASTextNode *label = [[ASTextNode alloc] init]; + label.attributedText = [[NSAttributedString alloc] initWithString:@"test label"]; + label.frame = CGRectMake(0, 0, 100, 20); + + ASTextNode *hiddenLabel = [[ASTextNode alloc] init]; + hiddenLabel.attributedText = [[NSAttributedString alloc] initWithString:@"hidden label"]; + hiddenLabel.frame = CGRectMake(0, 24, 100, 20); + hiddenLabel.alpha = 0.0; + + [containerNode addSubnode:label]; + [containerNode addSubnode:hiddenLabel]; + + // force load + __unused UIView *view = containerNode.view; + + NSArray *elements = [containerNode accessibilityElements]; + XCTAssertTrue(elements.count == 1); + XCTAssertEqual(elements.firstObject, label.view); +} + +- (void)testAccessibilityElementsNotInAppWindow { + + UIWindow *window = [[UIWindow alloc] initWithFrame:CGRectMake(0, 0, 320, 568)]; + ASDisplayNode *node = [[ASDisplayNode alloc] init]; + node.automaticallyManagesSubnodes = YES; + + ASViewController *vc = [[ASViewController alloc] initWithNode:node]; + window.rootViewController = vc; + [window makeKeyAndVisible]; + [window layoutIfNeeded]; + + CGSize windowSize = window.frame.size; + ASTextNode *label = [[ASTextNode alloc] init]; + label.attributedText = [[NSAttributedString alloc] initWithString:@"on screen"]; + label.frame = CGRectMake(0, 0, 100, 20); + + ASTextNode *partiallyOnScreenNodeY = [[ASTextNode alloc] init]; + partiallyOnScreenNodeY.attributedText = [[NSAttributedString alloc] initWithString:@"partially on screen y"]; + partiallyOnScreenNodeY.frame = CGRectMake(0, windowSize.height - 10, 100, 20); + + ASTextNode *partiallyOnScreenNodeX = [[ASTextNode alloc] init]; + partiallyOnScreenNodeX.attributedText = [[NSAttributedString alloc] initWithString:@"partially on screen x"]; + partiallyOnScreenNodeX.frame = CGRectMake(windowSize.width - 10, 100, 100, 20); + + ASTextNode *offScreenNodeY = [[ASTextNode alloc] init]; + offScreenNodeY.attributedText = [[NSAttributedString alloc] initWithString:@"off screen y"]; + offScreenNodeY.frame = CGRectMake(0, windowSize.height + 10, 100, 20); + + ASTextNode *offScreenNodeX = [[ASTextNode alloc] init]; + offScreenNodeX.attributedText = [[NSAttributedString alloc] initWithString:@"off screen x"]; + offScreenNodeX.frame = CGRectMake(windowSize.width + 1, 200, 100, 20); + + ASTextNode *offScreenNode = [[ASTextNode alloc] init]; + offScreenNode.attributedText = [[NSAttributedString alloc] initWithString:@"off screen"]; + offScreenNode.frame = CGRectMake(windowSize.width + 1, windowSize.height + 1, 100, 20); + + [node addSubnode:label]; + [node addSubnode:partiallyOnScreenNodeY]; + [node addSubnode:partiallyOnScreenNodeX]; + [node addSubnode:offScreenNodeY]; + [node addSubnode:offScreenNodeX]; + [node addSubnode:offScreenNode]; + + NSArray *elements = [node accessibilityElements]; + XCTAssertTrue(elements.count == 3); + XCTAssertTrue([elements containsObject:label.view]); + XCTAssertTrue([elements containsObject:partiallyOnScreenNodeX.view]); + XCTAssertTrue([elements containsObject:partiallyOnScreenNodeY.view]); +} + +- (void)testAccessibilityElementsNotInAppWindowButInScrollView { + + UIWindow *window = [[UIWindow alloc] initWithFrame:CGRectMake(0, 0, 320, 568)]; + ASScrollNode *node = [[ASScrollNode alloc] init]; + node.automaticallyManagesSubnodes = YES; + + ASViewController *vc = [[ASViewController alloc] initWithNode:node]; + window.rootViewController = vc; + [window makeKeyAndVisible]; + [window layoutIfNeeded]; + + CGSize windowSize = window.frame.size; + node.view.contentSize = CGSizeMake(window.frame.size.width, window.frame.size.height * 2.0); + ASTextNode *label = [[ASTextNode alloc] init]; + label.attributedText = [[NSAttributedString alloc] initWithString:@"on screen"]; + label.frame = CGRectMake(0, 0, 100, 20); + + ASTextNode *partiallyOnScreenNodeY = [[ASTextNode alloc] init]; + partiallyOnScreenNodeY.attributedText = [[NSAttributedString alloc] initWithString:@"partially on screen y"]; + partiallyOnScreenNodeY.frame = CGRectMake(0, windowSize.height - 10, 100, 20); + + ASTextNode *partiallyOnScreenNodeX = [[ASTextNode alloc] init]; + partiallyOnScreenNodeX.attributedText = [[NSAttributedString alloc] initWithString:@"partially on screen x"]; + partiallyOnScreenNodeX.frame = CGRectMake(windowSize.width - 10, 100, 100, 20); + + ASTextNode *offScreenNodeY = [[ASTextNode alloc] init]; + offScreenNodeY.attributedText = [[NSAttributedString alloc] initWithString:@"off screen y"]; + offScreenNodeY.frame = CGRectMake(0, windowSize.height + 10, 100, 20); + + ASTextNode *offScreenNodeX = [[ASTextNode alloc] init]; + offScreenNodeX.attributedText = [[NSAttributedString alloc] initWithString:@"off screen x"]; + offScreenNodeX.frame = CGRectMake(windowSize.width + 1, 200, 100, 20); + + ASTextNode *offScreenNode = [[ASTextNode alloc] init]; + offScreenNode.attributedText = [[NSAttributedString alloc] initWithString:@"off screen"]; + offScreenNode.frame = CGRectMake(windowSize.width + 1, windowSize.height + 1, 100, 20); + + [node addSubnode:label]; + [node addSubnode:partiallyOnScreenNodeY]; + [node addSubnode:partiallyOnScreenNodeX]; + [node addSubnode:offScreenNodeY]; + [node addSubnode:offScreenNodeX]; + [node addSubnode:offScreenNode]; + + NSArray *elements = [node accessibilityElements]; + XCTAssertTrue(elements.count == 6); + XCTAssertTrue([elements containsObject:label.view]); + XCTAssertTrue([elements containsObject:partiallyOnScreenNodeX.view]); + XCTAssertTrue([elements containsObject:partiallyOnScreenNodeY.view]); + XCTAssertTrue([elements containsObject:offScreenNodeY.view]); + XCTAssertTrue([elements containsObject:offScreenNodeX.view]); + XCTAssertTrue([elements containsObject:offScreenNode.view]); +} + +- (void)testAccessibilitySort { + ASDisplayNode *node1 = [[ASDisplayNode alloc] init]; + node1.accessibilityFrame = CGRectMake(0, 0, 50, 200); + + ASDisplayNode *node2 = [[ASDisplayNode alloc] init]; + node2.accessibilityFrame = CGRectMake(0, 0, 100, 200); + + ASDisplayNode *node3 = [[ASDisplayNode alloc] init]; + node3.accessibilityFrame = CGRectMake(0, 1, 100, 200); + + ASDisplayNode *node4 = [[ASDisplayNode alloc] init]; + node4.accessibilityFrame = CGRectMake(1, 1, 100, 200); + + NSMutableArray *elements = [@[node2, node4, node3, node1] mutableCopy]; + SortAccessibilityElements(elements); + XCTAssertEqual(elements[0], node1); + XCTAssertEqual(elements[1], node2); + XCTAssertEqual(elements[2], node3); + XCTAssertEqual(elements[3], node4); +} + +- (void)testCustomAccessibilitySort { + + // silly custom sorter that puts items with the largest height first. + setUserDefinedAccessibilitySortComparator(^NSComparisonResult(NSObject *a, NSObject *b) { + if (a.accessibilityFrame.size.height == b.accessibilityFrame.size.height) { + return NSOrderedSame; + } + return a.accessibilityFrame.size.height > b.accessibilityFrame.size.height ? NSOrderedAscending : NSOrderedDescending; + }); + + ASDisplayNode *node1 = [[ASDisplayNode alloc] init]; + node1.accessibilityFrame = CGRectMake(0, 0, 50, 300); + + ASDisplayNode *node2 = [[ASDisplayNode alloc] init]; + node2.accessibilityFrame = CGRectMake(0, 0, 100, 250); + + ASDisplayNode *node3 = [[ASDisplayNode alloc] init]; + node3.accessibilityFrame = CGRectMake(0, 0, 100, 200); + + ASDisplayNode *node4 = [[ASDisplayNode alloc] init]; + node4.accessibilityFrame = CGRectMake(0, 0, 100, 150); + + NSMutableArray *elements = [@[node2, node4, node3, node1] mutableCopy]; + SortAccessibilityElements(elements); + XCTAssertEqual(elements[0], node1); + XCTAssertEqual(elements[1], node2); + XCTAssertEqual(elements[2], node3); + XCTAssertEqual(elements[3], node4); +} + + @end diff --git a/Tests/ASGraphicsContextTests.mm b/Tests/ASGraphicsContextTests.mm new file mode 100644 index 00000000..1a937341 --- /dev/null +++ b/Tests/ASGraphicsContextTests.mm @@ -0,0 +1,96 @@ +// +// ASGraphicsContextTests.mm +// Texture +// +// Copyright (c) Pinterest, Inc. All rights reserved. +// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0 +// + + +#import +#import +#import +#import +#import + +@interface ASGraphicsContextTests : XCTestCase +@end + +@implementation ASGraphicsContextTests + +- (void)setUp +{ + [super setUp]; + ASConfiguration *config = [ASConfiguration new]; + config.experimentalFeatures = ASExperimentalDrawingGlobal; + [ASConfigurationManager test_resetWithConfiguration:config]; +} + + +#if AS_AT_LEAST_IOS13 +- (void)testCanceled +{ + if (AS_AVAILABLE_IOS_TVOS(13, 13)) { + CGSize size = CGSize{.width=100, .height=100}; + + XCTestExpectation *expectationCancelled = [self expectationWithDescription:@"canceled"]; + + asdisplaynode_iscancelled_block_t isCancelledBlock =^BOOL{ + [expectationCancelled fulfill]; + return true; + }; + + ASPrimitiveTraitCollection traitCollection = ASPrimitiveTraitCollectionMakeDefault(); + UIImage *canceledImage = ASGraphicsCreateImage(traitCollection, size, false, 0, nil, isCancelledBlock, ^{}); + + XCTAssertNil(canceledImage); + + [self waitForExpectations:@[expectationCancelled] timeout:1]; + } +} + +- (void)testCanceledNil +{ + if (AS_AVAILABLE_IOS_TVOS(13, 13)) { + CGSize size = CGSize{.width=100, .height=100}; + ASPrimitiveTraitCollection traitCollection = ASPrimitiveTraitCollectionMakeDefault(); + + XCTestExpectation *expectation = [self expectationWithDescription:@"normal"]; + UIImage *image = ASGraphicsCreateImage(traitCollection, size, false, 0, nil, nil, ^{ + [expectation fulfill]; + }); + + XCTAssert(image); + + [self waitForExpectations:@[expectation] timeout:1]; + } +} + +- (void)testTraitCollectionPassedToWork +{ + if (AS_AVAILABLE_IOS_TVOS(13, 13)) { + CGSize size = CGSize{.width=100, .height=100}; + + XCTestExpectation *expectationDark = [self expectationWithDescription:@"trait collection dark"]; + ASPrimitiveTraitCollection traitCollectionDark = ASPrimitiveTraitCollectionMakeDefault(); + traitCollectionDark.userInterfaceStyle = UIUserInterfaceStyleDark; + ASGraphicsCreateImage(traitCollectionDark, size, false, 0, nil, nil, ^{ + UITraitCollection *currentTraitCollection = [UITraitCollection currentTraitCollection]; + XCTAssertEqual(currentTraitCollection.userInterfaceStyle, UIUserInterfaceStyleDark); + [expectationDark fulfill]; + }); + + XCTestExpectation *expectationLight = [self expectationWithDescription:@"trait collection light"]; + ASPrimitiveTraitCollection traitCollectionLight = ASPrimitiveTraitCollectionMakeDefault(); + traitCollectionLight.userInterfaceStyle = UIUserInterfaceStyleLight; + ASGraphicsCreateImage(traitCollectionLight, size, false, 0, nil, nil, ^{ + UITraitCollection *currentTraitCollection = [UITraitCollection currentTraitCollection]; + XCTAssertEqual(currentTraitCollection.userInterfaceStyle, UIUserInterfaceStyleLight); + [expectationLight fulfill]; + }); + + [self waitForExpectations:@[expectationDark, expectationLight] timeout:1]; + } +} +#endif +@end diff --git a/Tests/ASImageNodeSnapshotTests.mm b/Tests/ASImageNodeSnapshotTests.mm index a1d190a9..13364930 100644 --- a/Tests/ASImageNodeSnapshotTests.mm +++ b/Tests/ASImageNodeSnapshotTests.mm @@ -11,6 +11,18 @@ #import +#if AS_AT_LEAST_IOS13 +static UIImage* makeImageWithColor(UIColor *color, CGSize size) { + CGRect rect = CGRect{.origin = CGPointZero, .size = size}; + UIGraphicsBeginImageContextWithOptions(size, false, 0); + [color setFill]; + UIRectFill(rect); + UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + return image; +} +#endif + @interface ASImageNodeSnapshotTests : ASSnapshotTestCase @end @@ -182,7 +194,31 @@ UIRectFill(CGRectMake(0, 0, 100, 100)); UIImage *result = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); - UIImage *rounded = ASImageNodeRoundBorderModificationBlock(2, [UIColor redColor])(result); + + ASPrimitiveTraitCollection traitCollection; + + if (@available(iOS 13.0, *)) { + traitCollection = ASPrimitiveTraitCollectionFromUITraitCollection(UITraitCollection.currentTraitCollection); + } else { + traitCollection = ASPrimitiveTraitCollectionMakeDefault(); + } + + UIImage *rounded = ASImageNodeRoundBorderModificationBlock(2, [UIColor redColor])(result, traitCollection); + ASImageNode *node = [[ASImageNode alloc] init]; + node.image = rounded; + ASDisplayNodeSizeToFitSize(node, rounded.size); + ASSnapshotVerifyNode(node, nil); +} + +- (void)testTintColorBlock +{ + UIGraphicsBeginImageContext(CGSizeMake(100, 100)); + [[UIColor blueColor] setFill]; + UIRectFill(CGRectMake(0, 0, 100, 100)); + UIImage *result = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + + UIImage *rounded = ASImageNodeTintColorModificationBlock([UIColor redColor])(result, ASPrimitiveTraitCollectionMakeDefault()); ASImageNode *node = [[ASImageNode alloc] init]; node.image = rounded; ASDisplayNodeSizeToFitSize(node, rounded.size); @@ -206,10 +242,6 @@ - (void)testDynamicAssetImage { if (@available(iOS 13.0, *)) { - ASConfiguration *config = [ASConfiguration new]; - config.experimentalFeatures = ASExperimentalTraitCollectionDidChangeWithPreviousCollection; - [ASConfigurationManager test_resetWithConfiguration:config]; - UIImage *image = [UIImage imageNamed:@"light-dark" inBundle:[NSBundle bundleForClass:[self class]] compatibleWithTraitCollection:nil]; ASImageNode *node = [[ASImageNode alloc] init]; node.image = image; @@ -222,8 +254,29 @@ [[UITraitCollection traitCollectionWithUserInterfaceStyle:UIUserInterfaceStyleDark] performAsCurrentTraitCollection:^{ ASSnapshotVerifyNode(node, @"user_interface_style_dark"); }]; + } +} + +- (void)testDynamicTintColor +{ + if (@available(iOS 13.0, *)) { + UIImage *image = makeImageWithColor(UIColor.redColor, CGSize{.width = 100, .height = 100}); + image = [image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + UIColor* tintColor = UIColor.systemBackgroundColor; + ASImageNode *node = [[ASImageNode alloc] init]; - NSLog(@"%@", image); + node.image = image; + node.tintColor = tintColor; + + ASDisplayNodeSizeToFitSize(node, image.size); + + [[UITraitCollection traitCollectionWithUserInterfaceStyle:UIUserInterfaceStyleLight] performAsCurrentTraitCollection:^{ + ASSnapshotVerifyNode(node, @"user_interface_style_light"); + }]; + + [[UITraitCollection traitCollectionWithUserInterfaceStyle:UIUserInterfaceStyleDark] performAsCurrentTraitCollection:^{ + ASSnapshotVerifyNode(node, @"user_interface_style_dark"); + }]; } } #endif // #if AS_AT_LEAST_IOS13 diff --git a/Tests/ASImageNodeTests.m b/Tests/ASImageNodeTests.m new file mode 100644 index 00000000..1ec5a343 --- /dev/null +++ b/Tests/ASImageNodeTests.m @@ -0,0 +1,116 @@ +// +// ASImageNodeTests.m +// Texture +// +// Copyright (c) Pinterest, Inc. All rights reserved. +// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0 +// + +#import +#import +#import +#import + +@interface ASImageTestNode : ASImageNode +@property (nonatomic, readonly) NSUInteger setNeedsDisplayCount; +@end + +@implementation ASImageTestNode + +- (void)setNeedsDisplay +{ + // Do not call super so that the background mechanics do not fire up. + _setNeedsDisplayCount += 1; +} + +@end + +@interface ASImageNodeTests : XCTestCase + +@end + +@implementation ASImageNodeTests + +- (void)testImage_didEnterHierarchy +{ + id imageMock = OCMClassMock(UIImage.class); + + ASImageTestNode *imageNode = [[ASImageTestNode alloc] init]; + imageNode.layerBacked = YES; + imageNode.image = imageMock; + + CALayer *layer = imageNode.layer; + XCTAssertNotNil(layer); + id layerDelegate = layer.delegate; + + NSUInteger initialSetNeedsDisplayCount = imageNode.setNeedsDisplayCount; + XCTAssertEqual(initialSetNeedsDisplayCount, 1); + + [layerDelegate actionForLayer:layer forKey:kCAOnOrderIn]; + + XCTAssertEqual(imageNode.setNeedsDisplayCount, initialSetNeedsDisplayCount); + + [layerDelegate actionForLayer:layer forKey:kCAOnOrderOut]; + + [imageMock stopMocking]; +} + +- (void)testTemplateImage_didEnterHierarchy +{ + id imageMock = OCMClassMock(UIImage.class); + OCMStub([imageMock renderingMode]).andReturn(UIImageRenderingModeAlwaysTemplate); + + ASImageTestNode *imageNode = [[ASImageTestNode alloc] init]; + imageNode.layerBacked = YES; + imageNode.image = imageMock; + + CALayer *layer = imageNode.layer; + XCTAssertNotNil(layer); + id layerDelegate = layer.delegate; + + NSUInteger initialSetNeedsDisplayCount = imageNode.setNeedsDisplayCount; + XCTAssertEqual(initialSetNeedsDisplayCount, 1); + + [layerDelegate actionForLayer:layer forKey:kCAOnOrderIn]; + + XCTAssertEqual(imageNode.setNeedsDisplayCount, initialSetNeedsDisplayCount + 1); + + [layerDelegate actionForLayer:layer forKey:kCAOnOrderOut]; + + [imageMock stopMocking]; +} + +- (void)testImage_tintColorDidChange +{ + id imageMock = OCMClassMock(UIImage.class); + + ASImageTestNode *imageNode = [[ASImageTestNode alloc] init]; + imageNode.image = imageMock; + + NSUInteger initialSetNeedsDisplayCount = imageNode.setNeedsDisplayCount; + XCTAssertEqual(initialSetNeedsDisplayCount, 1); + + [imageNode tintColorDidChange]; + XCTAssertEqual(imageNode.setNeedsDisplayCount, initialSetNeedsDisplayCount); + + [imageMock stopMocking]; +} + +- (void)testTemplateImage_tintColorDidChange +{ + id imageMock = OCMClassMock(UIImage.class); + OCMStub([imageMock renderingMode]).andReturn(UIImageRenderingModeAlwaysTemplate); + + ASImageTestNode *imageNode = [[ASImageTestNode alloc] init]; + imageNode.image = imageMock; + + NSUInteger initialSetNeedsDisplayCount = imageNode.setNeedsDisplayCount; + XCTAssertEqual(initialSetNeedsDisplayCount, 1); + + [imageNode tintColorDidChange]; + XCTAssertEqual(imageNode.setNeedsDisplayCount, initialSetNeedsDisplayCount + 1); + + [imageMock stopMocking]; +} + +@end diff --git a/Tests/ASInsetLayoutSpecSnapshotTests.mm b/Tests/ASInsetLayoutSpecSnapshotTests.mm index d6047d35..99ffa6e8 100644 --- a/Tests/ASInsetLayoutSpecSnapshotTests.mm +++ b/Tests/ASInsetLayoutSpecSnapshotTests.mm @@ -36,7 +36,7 @@ static UIEdgeInsets insetsForCombination(NSUInteger combination, CGFloat insetVa static NSString *nameForInsets(UIEdgeInsets insets) { - return [NSString stringWithFormat:@"%.f-%.f-%.f-%.f", insets.top, insets.left, insets.bottom, insets.right]; + return [NSString stringWithFormat:@"%.f_%.f_%.f_%.f", insets.top, insets.left, insets.bottom, insets.right]; } @interface ASInsetLayoutSpecSnapshotTests : ASLayoutSpecSnapshotTestCase diff --git a/Tests/ASLayoutEngineTests.mm b/Tests/ASLayoutEngineTests.mm index 3222f78b..7a0b8759 100644 --- a/Tests/ASLayoutEngineTests.mm +++ b/Tests/ASLayoutEngineTests.mm @@ -63,7 +63,7 @@ allNodes = @[ nodeA, nodeB, nodeC, nodeD, nodeE ]; ASSetDebugNames(nodeA, nodeB, nodeC, nodeD, nodeE); ASLayoutSpecBlock b = ^ASLayoutSpec * _Nonnull(__kindof ASDisplayNode * _Nonnull node, ASSizeRange constrainedSize) { - return [ASStackLayoutSpec stackLayoutSpecWithDirection:ASStackLayoutDirectionHorizontal spacing:0 justifyContent:ASStackLayoutJustifyContentSpaceBetween alignItems:ASStackLayoutAlignItemsStart children:@[ nodeB, nodeC, nodeD ]]; + return [ASStackLayoutSpec stackLayoutSpecWithDirection:ASStackLayoutDirectionHorizontal spacing:0 justifyContent:ASStackLayoutJustifyContentSpaceBetween alignItems:ASStackLayoutAlignItemsStart children:@[ self->nodeB, self->nodeC, self->nodeD ]]; }; fixture1and3and5NodeALayoutSpecBlock = b; fixture1 = [self createFixture1]; @@ -162,10 +162,10 @@ injectedMainThreadWork = ^{ injectedMainThreadWorkDone = YES; - [window layoutIfNeeded]; + [self->window layoutIfNeeded]; // Ensure we're still on the old layout. We should stay on this until the transition completes. - [self verifyFixture:fixture1]; + [self verifyFixture:self->fixture1]; }; measurementCompletionBlock = ^{ @@ -286,7 +286,7 @@ as_log_verbose(OS_LOG_DEFAULT, "Begin injectedMainThreadWork"); injectedMainThreadWorkDone = YES; - [fixture4 apply]; + [self->fixture4 apply]; as_log_verbose(OS_LOG_DEFAULT, "Did apply new fixture"); if (enforceCorrectBehavior) { @@ -294,10 +294,10 @@ // are common to both fixture2 and fixture4 are available from the cache. } else { // Incorrect behavior: nodeC will get measured against its new bounds on main. - const auto cPendingSize = [fixture2 layoutForNode:nodeC].size; - OCMExpect([nodeC.mock calculateLayoutThatFits:ASSizeRangeMake(cPendingSize)]).onMainThread(); + const auto cPendingSize = [self->fixture2 layoutForNode:self->nodeC].size; + OCMExpect([self->nodeC.mock calculateLayoutThatFits:ASSizeRangeMake(cPendingSize)]).onMainThread(); } - [window layoutIfNeeded]; + [self->window layoutIfNeeded]; as_log_verbose(OS_LOG_DEFAULT, "End injectedMainThreadWork"); }; @@ -342,7 +342,7 @@ OCMExpect([nodeB.mock calculateLayoutThatFits:[fixture3 firstSizeRangeForNode:nodeB]]); [fixture1 withSizeRangesForNode:nodeA block:^(ASSizeRange sizeRange) { - OCMExpect([nodeA.mock calculateLayoutThatFits:sizeRange]); + OCMExpect([self->nodeA.mock calculateLayoutThatFits:sizeRange]); }]; [window layoutIfNeeded]; @@ -456,7 +456,7 @@ fixture.layout = layoutA; ASLayoutSpecBlock specBlockA = ^ASLayoutSpec * _Nonnull(__kindof ASDisplayNode * _Nonnull node, ASSizeRange constrainedSize) { - return [ASStackLayoutSpec stackLayoutSpecWithDirection:ASStackLayoutDirectionHorizontal spacing:0 justifyContent:ASStackLayoutJustifyContentSpaceBetween alignItems:ASStackLayoutAlignItemsStart children:@[ nodeB, nodeC, nodeE ]]; + return [ASStackLayoutSpec stackLayoutSpecWithDirection:ASStackLayoutDirectionHorizontal spacing:0 justifyContent:ASStackLayoutJustifyContentSpaceBetween alignItems:ASStackLayoutAlignItemsStart children:@[ self->nodeB, self->nodeC, self->nodeE ]]; }; [fixture.layoutSpecBlocks setObject:specBlockA forKey:nodeA]; return fixture; @@ -535,7 +535,7 @@ fixture.layout = layoutA; ASLayoutSpecBlock specBlockA = ^ASLayoutSpec * _Nonnull(__kindof ASDisplayNode * _Nonnull node, ASSizeRange constrainedSize) { - return [ASStackLayoutSpec stackLayoutSpecWithDirection:ASStackLayoutDirectionHorizontal spacing:0 justifyContent:ASStackLayoutJustifyContentSpaceBetween alignItems:ASStackLayoutAlignItemsStart children:@[ nodeB, nodeD, nodeE ]]; + return [ASStackLayoutSpec stackLayoutSpecWithDirection:ASStackLayoutDirectionHorizontal spacing:0 justifyContent:ASStackLayoutJustifyContentSpaceBetween alignItems:ASStackLayoutAlignItemsStart children:@[ self->nodeB, self->nodeD, self->nodeE ]]; }; [fixture.layoutSpecBlocks setObject:specBlockA forKey:nodeA]; return fixture; @@ -576,7 +576,7 @@ [fixture withSizeRangesForAllNodesUsingBlock:^(ASLayoutTestNode * _Nonnull node, ASSizeRange sizeRange) { OCMExpect([node.mock calculateLayoutThatFits:sizeRange]).onMainThread(); - if (!stubbedCalculatedLayoutDidChange) { + if (!self->stubbedCalculatedLayoutDidChange) { OCMExpect([node.mock calculatedLayoutDidChange]).onMainThread(); } }]; diff --git a/Tests/ASLayoutSpecUtilitiesTests.mm b/Tests/ASLayoutSpecUtilitiesTests.mm new file mode 100644 index 00000000..fb099fa8 --- /dev/null +++ b/Tests/ASLayoutSpecUtilitiesTests.mm @@ -0,0 +1,244 @@ +// +// ASLayoutSpecUtilitiesTests.m +// AsyncDisplayKitTests +// +// Copyright (c) Pinterest, Inc. All rights reserved. +// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0 +// + +#import +#import "ASLayoutSpecUtilities.h" + +@interface ASLayoutSpecUtilitiesTests : XCTestCase + +@end + +@implementation ASLayoutSpecUtilitiesTests + +- (void)testMapVectorPrimitive +{ + std::vector a = {3, 1, 4}; + std::vector b = AS::map(a, ^int(int i) { + return i * 2; + }); + std::vector c = {6, 2, 8}; + XCTAssertEqual(b, c); +} + +- (void)testMapVectorNSObject +{ + std::vector a = {@"2.16", @"3.14"}; + std::vector b = AS::map(a, ^float(NSString *str) { + return str.floatValue; + }); + std::vector c = {2.16, 3.14}; + XCTAssertEqual(b, c); +} + +- (void)testMapVectorStruct +{ + struct TestStruct + { + NSString *value; + + bool operator==(const TestStruct& rhs) const + { + return [value isEqualToString:rhs.value]; + } + }; + + std::vector a = { + {.value = @"2"}, + {.value = @"1"}, + {.value = @"6"} + }; + std::vector b = AS::map(a, ^NSInteger(TestStruct s) { + return s.value.integerValue; + }); + std::vector c = {2, 1, 6}; + XCTAssertEqual(b, c); +} + +- (void)testMapVectorClass +{ + class TestClass { + private: + NSString *_value; + + public: + TestClass (NSString *value) + { + _value = value; + } + + NSString *getValue() const noexcept + { + return _value; + } + + void setValue(NSString *value) noexcept + { + _value = value; + } + + bool operator==(const TestClass& rhs) const noexcept + { + return [getValue() isEqualToString:rhs.getValue()]; + } + }; + + std::vector a = { + TestClass(@"2"), + TestClass(@"1"), + TestClass(@"6") + }; + std::vector b = AS::map(a, ^NSInteger(TestClass c) { + return c.getValue().integerValue; + }); + std::vector c = {2, 1, 6}; + XCTAssertEqual(b, c); +} + +- (void)testMapVectorEmpty +{ + std::vector a = {}; + std::vector b = AS::map(a, ^int(NSString *str) { + return str.intValue; + }); + std::vector c = {}; + XCTAssertEqual(b, c); +} + +- (void)testMapNSFastEnumeration +{ + struct TestStruct { + NSString *value; + + bool operator==(const TestStruct& rhs) const + { + return [value isEqualToString:rhs.value]; + } + }; + + NSArray *a = @[@1, @2, @3]; + std::vector b = AS::map(a, ^TestStruct(NSNumber *num) { + return {.value = num.stringValue}; + }); + std::vector c = { + {.value = @"1"}, + {.value = @"2"}, + {.value = @"3"} + }; + XCTAssertEqual(b, c); +} + +- (void)testMapNSFastEnumerationEmpty +{ + NSArray *a = @[]; + std::vector b = AS::map(a, ^int(NSNumber *num) { + return num.intValue; + }); + std::vector c = {}; + XCTAssertEqual(b, c); +} + +- (void)testFilterVectorPrimitive +{ + std::vector a = {1, 2, 3, 4}; + std::vector b = AS::filter(a, ^BOOL(int num) { + return num < 3; + }); + std::vector c = {1, 2}; + XCTAssertEqual(b, c); +} + +- (void)testFilterVectorNSObject +{ + std::vector a = {@"9", @"2", @"6"}; + std::vector b = AS::filter(a, ^BOOL(NSString *str) { + return str.integerValue % 2 == 0; + }); + std::vector c = {@"2", @"6"}; + XCTAssertEqual(b, c); +} + +- (void)testFilterVectorStruct +{ + struct TestStruct { + NSString *value; + + bool operator==(const TestStruct& rhs) const + { + return [value isEqualToString:rhs.value]; + } + }; + + std::vector a = { + {.value = @"6"}, + {.value = @"8"}, + {.value = @"3"}, + {.value = @"9"} + }; + std::vector b = AS::filter(a, ^BOOL(TestStruct s) { + return s.value.integerValue == 3; + }); + std::vector c = { + {.value = @"3"} + }; + XCTAssertEqual(b, c); +} + +- (void)testFilterVectorClass +{ + class TestClass { + private: + NSString *_value; + + public: + TestClass (NSString *value) + { + _value = value; + } + + NSString *getValue() const noexcept + { + return _value; + } + + void setValue(NSString *value) noexcept + { + _value = value; + } + + bool operator==(const TestClass& rhs) const noexcept + { + return [getValue() isEqualToString:rhs.getValue()]; + } + }; + + std::vector a = { + TestClass(@"2"), + TestClass(@"1"), + TestClass(@"6") + }; + std::vector b = AS::filter(a, ^BOOL(TestClass c) { + return c.getValue().integerValue > 1; + }); + std::vector c = { + TestClass(@"2"), + TestClass(@"6") + }; + XCTAssertEqual(b, c); +} + +- (void)testFilterVectorEmpty +{ + std::vector a = {}; + std::vector b = AS::filter(a, ^BOOL(int num) { + return num < 2; + }); + std::vector c = {}; + XCTAssertEqual(b, c); +} + +@end diff --git a/Tests/ASMultiplexImageNodeTests.mm b/Tests/ASMultiplexImageNodeTests.mm index 53d1c67f..8ebd77c4 100644 --- a/Tests/ASMultiplexImageNodeTests.mm +++ b/Tests/ASMultiplexImageNodeTests.mm @@ -112,7 +112,7 @@ OCMExpect([mockCache cachedImageWithURL:[self _testImageURL] callbackQueue:OCMOCK_ANY completion:[OCMArg isNotNil]]) .andDo(^(NSInvocation *inv) { ASImageCacherCompletion completionBlock = [inv as_argumentAtIndexAsObject:4]; - completionBlock([self _testImage]); + completionBlock([self _testImage], ASImageCacheTypeAsynchronous); }); imageNode.imageIdentifiers = @[imageIdentifier]; @@ -217,7 +217,7 @@ OCMExpect([mockCache cachedImageWithURL:[self _testImageURL] callbackQueue:OCMOCK_ANY completion:[OCMArg isNotNil]]) .andDo(^(NSInvocation *inv){ ASImageCacherCompletion completion = [inv as_argumentAtIndexAsObject:4]; - completion(nil); + completion(nil, ASImageCacheTypeAsynchronous); }); // Mock a 50%-progress URL download. diff --git a/Tests/ASNetworkImageNodeTests.mm b/Tests/ASNetworkImageNodeTests.mm index f794ba9e..d0853c1c 100644 --- a/Tests/ASNetworkImageNodeTests.mm +++ b/Tests/ASNetworkImageNodeTests.mm @@ -109,7 +109,7 @@ - (void)cachedImageWithURL:(NSURL *)URL callbackQueue:(dispatch_queue_t)callbackQueue completion:(ASImageCacherCompletion)completion { - completion(nil); + completion(nil, ASImageCacheTypeAsynchronous); } @end diff --git a/Tests/ASRecursiveUnfairLockTests.mm b/Tests/ASRecursiveUnfairLockTests.mm index 3916b319..c76adb65 100644 --- a/Tests/ASRecursiveUnfairLockTests.mm +++ b/Tests/ASRecursiveUnfairLockTests.mm @@ -62,7 +62,7 @@ ASRecursiveUnfairLockLock(&lock); XCTestExpectation *e1 = [self expectationWithDescription:@"Other thread tried lock."]; [NSThread detachNewThreadWithBlock:^{ - XCTAssertThrows(ASRecursiveUnfairLockUnlock(&lock)); + XCTAssertThrows(ASRecursiveUnfairLockUnlock(&self->lock)); [e1 fulfill]; }]; [self waitForExpectationsWithTimeout:10 handler:nil]; @@ -93,7 +93,7 @@ dispatch_group_wait(g, DISPATCH_TIME_FOREVER); { __block int value = 0; [self measureBlock:^{ - CHAOS_TEST_BODY(YES, ASRecursiveUnfairLockLock(&lock), {}, ASRecursiveUnfairLockUnlock(&lock)); + CHAOS_TEST_BODY(YES, ASRecursiveUnfairLockLock(&self->lock), {}, ASRecursiveUnfairLockUnlock(&self->lock)); }]; XCTAssertEqual(value, 0); } @@ -102,7 +102,7 @@ dispatch_group_wait(g, DISPATCH_TIME_FOREVER); { __block int value = 0; [self measureBlock:^{ - CHAOS_TEST_BODY(NO, ASRecursiveUnfairLockLock(&lock), {}, ASRecursiveUnfairLockUnlock(&lock)); + CHAOS_TEST_BODY(NO, ASRecursiveUnfairLockLock(&self->lock), {}, ASRecursiveUnfairLockUnlock(&self->lock)); }]; XCTAssertEqual(value, 0); } diff --git a/Tests/ASRunLoopQueueTests.mm b/Tests/ASRunLoopQueueTests.mm index 2881e301..1396f904 100644 --- a/Tests/ASRunLoopQueueTests.mm +++ b/Tests/ASRunLoopQueueTests.mm @@ -12,7 +12,7 @@ #import "ASDisplayNodeTestsHelper.h" -static NSTimeInterval const kRunLoopRunTime = 0.001; // Allow the RunLoop to run for one millisecond each time. +static NSTimeInterval const kRunLoopRunTime = 0.01; // Allow the RunLoop to run for 1/100 second each time. @interface QueueObject : NSObject @property (nonatomic) BOOL queueObjectProcessed; diff --git a/Tests/ASScrollNodeTests.mm b/Tests/ASScrollNodeTests.mm index f9dbd515..1f7e8c17 100644 --- a/Tests/ASScrollNodeTests.mm +++ b/Tests/ASScrollNodeTests.mm @@ -170,6 +170,10 @@ - (void)testASScrollNodeAccessibility { ASDisplayNode *scrollNode = [[ASDisplayNode alloc] init]; + UIWindow *window = [[UIWindow alloc] initWithFrame:CGRectMake(0, 0, 320, 560)]; + [window addSubnode:scrollNode]; + [window makeKeyAndVisible]; + ASDisplayNode *node = [[ASDisplayNode alloc] init]; node.isAccessibilityContainer = YES; node.accessibilityLabel = @"node"; diff --git a/Tests/ASSnapshotTestCase.mm b/Tests/ASSnapshotTestCase.mm index b6530b05..ce50b7cb 100644 --- a/Tests/ASSnapshotTestCase.mm +++ b/Tests/ASSnapshotTestCase.mm @@ -16,13 +16,6 @@ NSOrderedSet *ASSnapshotTestCaseDefaultSuffixes(void) { NSMutableOrderedSet *suffixesSet = [[NSMutableOrderedSet alloc] init]; - // In some rare cases, slightly different rendering may occur on iOS 10 (text rasterization). - // If the test folders find any image that exactly matches, they pass; - // if an image is not present at all, or it fails, it moves on to check the others. - // This means the order doesn't matter besides reducing logging / performance. - if (AS_AT_LEAST_IOS10) { - [suffixesSet addObject:@"_iOS_10"]; - } [suffixesSet addObject:@"_64"]; return [suffixesSet copy]; } diff --git a/Tests/ASTableViewTests.mm b/Tests/ASTableViewTests.mm index f5e98c27..29bb72c8 100644 --- a/Tests/ASTableViewTests.mm +++ b/Tests/ASTableViewTests.mm @@ -8,10 +8,6 @@ // #import -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdocumentation" -#import -#pragma clang diagnostic pop #import #import @@ -42,13 +38,6 @@ @end -@interface UITableView (Testing) -// This will start recording all editing calls to UITableView -// into the provided array. -// Make sure to call [UITableView deswizzleInstanceMethods] to reset this. -+ (void)as_recordEditingCallsIntoArray:(NSMutableArray *)selectors; -@end - @interface ASTestTableView : ASTableView @property (nonatomic) void (^willDeallocBlock)(ASTableView *tableView); @end @@ -83,20 +72,29 @@ @implementation ASTableViewTestDelegate +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-implementations" - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return 0; } +#pragma clang diagnostic pop +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-implementations" - (ASCellNode *)tableView:(ASTableView *)tableView nodeForRowAtIndexPath:(NSIndexPath *)indexPath { return nil; } +#pragma clang diagnostic pop +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-implementations" - (ASCellNodeBlock)tableView:(ASTableView *)tableView nodeBlockForRowAtIndexPath:(NSIndexPath *)indexPath { return nil; } +#pragma clang diagnostic pop - (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section { @@ -162,16 +160,24 @@ } } +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-implementations" - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return _numberOfSections; } +#pragma clang diagnostic pop +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-implementations" - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return _rowsPerSection; } +#pragma clang diagnostic pop +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-implementations" - (ASCellNode *)tableView:(ASTableView *)tableView nodeForRowAtIndexPath:(NSIndexPath *)indexPath { ASTestTextCellNode *textCellNode = [ASTestTextCellNode new]; @@ -179,7 +185,10 @@ return textCellNode; } +#pragma clang diagnostic pop +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-implementations" - (ASCellNodeBlock)tableView:(ASTableView *)tableView nodeBlockForRowAtIndexPath:(NSIndexPath *)indexPath { if (_nodeBlockForItem) { @@ -190,9 +199,11 @@ ASTestTextCellNode *textCellNode = [ASTestTextCellNode new]; textCellNode.text = [NSString stringWithFormat:@"{%d, %d}", (int)indexPath.section, (int)indexPath.row]; textCellNode.backgroundColor = [UIColor whiteColor]; + textCellNode.tintColor = [UIColor yellowColor]; return textCellNode; }; } +#pragma clang diagnostic pop - (nullable NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView { @@ -211,10 +222,13 @@ @implementation ASTableViewFilledDelegate +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-implementations" - (ASSizeRange)tableView:(ASTableView *)tableView constrainedSizeForRowAtIndexPath:(NSIndexPath *)indexPath { return ASSizeRangeMake(CGSizeMake(10, 42)); } +#pragma clang diagnostic pop @end @@ -607,7 +621,6 @@ - (void)testThatInitialDataLoadHappensInOneShot { - NSMutableArray *selectors = [NSMutableArray array]; ASTableNode *node = [[ASTableNode alloc] initWithStyle:UITableViewStylePlain]; ASTableViewFilledDataSource *dataSource = [ASTableViewFilledDataSource new]; @@ -616,23 +629,25 @@ node.dataSource = dataSource; node.delegate = dataSource; - [UITableView as_recordEditingCallsIntoArray:selectors]; + __block NSUInteger reloadCallCount = 0; + __block IMP originalIMP = ASReplaceMethodWithBlock(UITableView.class, @selector(reloadData), ^(UITableView *_tableView) { + reloadCallCount += 1; + ((void (*)(id,SEL))originalIMP)(_tableView, @selector(reloadData)); + }); + XCTAssertGreaterThan(node.numberOfSections, 0); [node waitUntilAllUpdatesAreProcessed]; XCTAssertGreaterThan(node.view.numberOfSections, 0); // The first reloadData call helps prevent UITableView from calling it multiple times while ASDataController is working. // The second reloadData call is the real one. - NSArray *expectedSelectors = @[ NSStringFromSelector(@selector(reloadData)), - NSStringFromSelector(@selector(reloadData)) ]; - XCTAssertEqualObjects(selectors, expectedSelectors); + XCTAssertEqual(reloadCallCount, 2); - [UITableView deswizzleAllInstanceMethods]; + method_setImplementation(class_getInstanceMethod(UITableView.class, @selector(reloadData)), (IMP)originalIMP); } - (void)testThatReloadDataHappensInOneShot { - NSMutableArray *selectors = [NSMutableArray array]; ASTableNode *node = [[ASTableNode alloc] initWithStyle:UITableViewStylePlain]; ASTableViewFilledDataSource *dataSource = [ASTableViewFilledDataSource new]; @@ -647,16 +662,19 @@ XCTAssertGreaterThan(node.view.numberOfSections, 0); // Reload data. - [UITableView as_recordEditingCallsIntoArray:selectors]; + __block NSUInteger reloadCallCount = 0; + __block IMP originalIMP = ASReplaceMethodWithBlock(UITableView.class, @selector(reloadData), ^(UITableView *_tableView) { + reloadCallCount += 1; + ((void (*)(id,SEL))originalIMP)(_tableView, @selector(reloadData)); + }); [node reloadData]; [node waitUntilAllUpdatesAreProcessed]; // Assert that the beginning of the call pattern is correct. // There is currently noise that comes after that we will allow for this test. - NSArray *expectedSelectors = @[ NSStringFromSelector(@selector(reloadData)) ]; - XCTAssertEqualObjects(selectors, expectedSelectors); + XCTAssertEqual(reloadCallCount, 1); - [UITableView deswizzleAllInstanceMethods]; + method_setImplementation(class_getInstanceMethod(UITableView.class, @selector(reloadData)), (IMP)originalIMP); } /** @@ -886,54 +904,24 @@ XCTAssertEqual([node.view numberOfRowsInSection:0], 2); } -@end -@implementation UITableView (Testing) - -+ (void)as_recordEditingCallsIntoArray:(NSMutableArray *)selectors +- (void)testTintColorIsPropagatedToTableViewCell { - [UITableView swizzleInstanceMethod:@selector(reloadData) withReplacement:JGMethodReplacementProviderBlock { - return JGMethodReplacement(void, UITableView *) { - JGOriginalImplementation(void); - [selectors addObject:NSStringFromSelector(_cmd)]; - }; - }]; - [UITableView swizzleInstanceMethod:@selector(beginUpdates) withReplacement:JGMethodReplacementProviderBlock { - return JGMethodReplacement(void, UITableView *) { - JGOriginalImplementation(void); - [selectors addObject:NSStringFromSelector(_cmd)]; - }; - }]; - [UITableView swizzleInstanceMethod:@selector(endUpdates) withReplacement:JGMethodReplacementProviderBlock { - return JGMethodReplacement(void, UITableView *) { - JGOriginalImplementation(void); - [selectors addObject:NSStringFromSelector(_cmd)]; - }; - }]; - [UITableView swizzleInstanceMethod:@selector(insertRowsAtIndexPaths:withRowAnimation:) withReplacement:JGMethodReplacementProviderBlock { - return JGMethodReplacement(void, UITableView *, NSArray *indexPaths, UITableViewRowAnimation anim) { - JGOriginalImplementation(void, indexPaths, anim); - [selectors addObject:NSStringFromSelector(_cmd)]; - }; - }]; - [UITableView swizzleInstanceMethod:@selector(deleteRowsAtIndexPaths:withRowAnimation:) withReplacement:JGMethodReplacementProviderBlock { - return JGMethodReplacement(void, UITableView *, NSArray *indexPaths, UITableViewRowAnimation anim) { - JGOriginalImplementation(void, indexPaths, anim); - [selectors addObject:NSStringFromSelector(_cmd)]; - }; - }]; - [UITableView swizzleInstanceMethod:@selector(insertSections:withRowAnimation:) withReplacement:JGMethodReplacementProviderBlock { - return JGMethodReplacement(void, UITableView *, NSIndexSet *indexes, UITableViewRowAnimation anim) { - JGOriginalImplementation(void, indexes, anim); - [selectors addObject:NSStringFromSelector(_cmd)]; - }; - }]; - [UITableView swizzleInstanceMethod:@selector(deleteSections:withRowAnimation:) withReplacement:JGMethodReplacementProviderBlock { - return JGMethodReplacement(void, UITableView *, NSIndexSet *indexes, UITableViewRowAnimation anim) { - JGOriginalImplementation(void, indexes, anim); - [selectors addObject:NSStringFromSelector(_cmd)]; - }; - }]; + // If a tint color is explicitly defined on an ASCellNode, we should + CGSize tableViewSize = CGSizeMake(100, 500); + ASTestTableView *tableView = [[ASTestTableView alloc] initWithFrame:CGRectMake(0, 0, tableViewSize.width, tableViewSize.height) + style:UITableViewStylePlain]; + ASTableViewFilledDataSource *dataSource = [ASTableViewFilledDataSource new]; + + tableView.asyncDelegate = dataSource; + tableView.asyncDataSource = dataSource; + + [tableView reloadData]; + [tableView waitUntilAllUpdatesAreCommitted]; + NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0]; + UITableViewCell *uikitCell = [tableView cellForRowAtIndexPath:indexPath]; + BOOL areColorsEqual = CGColorEqualToColor(uikitCell.tintColor.CGColor, UIColor.yellowColor.CGColor); + XCTAssertTrue(areColorsEqual); } @end diff --git a/Tests/ASTextKitTests.mm b/Tests/ASTextKitTests.mm index efd93cf8..0f1a3ec7 100644 --- a/Tests/ASTextKitTests.mm +++ b/Tests/ASTextKitTests.mm @@ -91,7 +91,7 @@ static BOOL checkAttributes(const ASTextKitAttributes &attributes, const CGSize FBSnapshotTestController *controller = [[FBSnapshotTestController alloc] init]; UIImage *labelImage = UITextViewImageWithAttributes(attributes, constrainedSize, linkTextAttributes); UIImage *textKitImage = ASTextKitImageWithAttributes(attributes, constrainedSize); - return [controller compareReferenceImage:labelImage toImage:textKitImage tolerance:0.0 error:nil]; + return [controller compareReferenceImage:labelImage toImage:textKitImage overallTolerance:0.0 error:nil]; } @implementation ASTextKitTests diff --git a/Tests/ASTextNode2SnapshotTests.mm b/Tests/ASTextNode2SnapshotTests.mm index af3313fe..0cda2ce4 100644 --- a/Tests/ASTextNode2SnapshotTests.mm +++ b/Tests/ASTextNode2SnapshotTests.mm @@ -331,4 +331,27 @@ ASSnapshotVerifyNode(textNode, nil); } + +- (void)testTintColorHierarchyChange +{ + ASDisplayNode *containerNode = [[ASDisplayNode alloc] init]; + containerNode.tintColor = [UIColor greenColor]; + + ASTextNode *node = [[ASTextNode alloc] init]; + [containerNode addSubnode:node]; + [node setLayerBacked:YES]; + node.textColorFollowsTintColor = YES; + node.attributedText = [[NSAttributedString alloc] initWithString:@"Hello" attributes:@{}]; + ASDisplayNodeSizeToFitSizeRange(node, ASSizeRangeMake(CGSizeZero, CGSizeMake(INFINITY, INFINITY))); + containerNode.style.preferredSize = node.bounds.size; + ASSnapshotVerifyNode(node, @"green_tint_from_parent"); + + ASDisplayNode *containerNode2 = [[ASDisplayNode alloc] init]; + containerNode2.tintColor = [UIColor redColor]; + [containerNode2 addSubnode:node]; + containerNode2.style.preferredSize = node.bounds.size; + ASSnapshotVerifyNode(node, @"red_tint_from_parent"); +} + + @end diff --git a/Tests/ASTextNodeSnapshotTests.mm b/Tests/ASTextNodeSnapshotTests.mm index f6033bc3..74118a6e 100644 --- a/Tests/ASTextNodeSnapshotTests.mm +++ b/Tests/ASTextNodeSnapshotTests.mm @@ -162,6 +162,28 @@ ASSnapshotVerifyNode(textNode, nil); } +- (void)testTintColorHierarchyChange +{ + ASDisplayNode *containerNode = [[ASDisplayNode alloc] init]; + containerNode.tintColor = [UIColor greenColor]; + + ASTextNode *node = [[ASTextNode alloc] init]; + [containerNode addSubnode:node]; + [node setLayerBacked:YES]; + node.textColorFollowsTintColor = YES; + node.attributedText = [[NSAttributedString alloc] initWithString:@"Hello" attributes:@{}]; + ASDisplayNodeSizeToFitSizeRange(node, ASSizeRangeMake(CGSizeZero, CGSizeMake(INFINITY, INFINITY))); + containerNode.style.preferredSize = node.bounds.size; + ASSnapshotVerifyNode(node, @"green_tint_from_parent"); + + + ASDisplayNode *containerNode2 = [[ASDisplayNode alloc] init]; + containerNode2.tintColor = [UIColor redColor]; + [containerNode2 addSubnode:node]; + containerNode2.style.preferredSize = node.bounds.size; + ASSnapshotVerifyNode(node, @"red_tint_from_parent"); +} + #if AS_AT_LEAST_IOS13 - (void)testUserInterfaceStyleSnapshotTesting @@ -248,6 +270,9 @@ } } + + + #endif // #if AS_AT_LEAST_IOS13 @end diff --git a/Tests/ASThrashUtility.m b/Tests/ASThrashUtility.m index c555d3f7..ac2da531 100644 --- a/Tests/ASThrashUtility.m +++ b/Tests/ASThrashUtility.m @@ -236,16 +236,21 @@ static atomic_uint ASThrashTestSectionNextID = 1; _data = data; } +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-implementations" - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return self.data[section].items.count; } +#pragma clang diagnostic pop - +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-implementations" - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return self.data.count; } +#pragma clang diagnostic pop - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section { @@ -297,6 +302,8 @@ static atomic_uint ASThrashTestSectionNextID = 1; return node; } +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-implementations" - (ASCellNode *)tableView:(ASTableView *)tableView nodeForRowAtIndexPath:(NSIndexPath *)indexPath { ASThrashTestNode *node = [[ASThrashTestNode alloc] init]; @@ -304,6 +311,7 @@ static atomic_uint ASThrashTestSectionNextID = 1; [self.allNodes addObject:node]; return node; } +#pragma clang diagnostic pop #endif diff --git a/Tests/ASViewControllerTests.mm b/Tests/ASViewControllerTests.mm index f6b26e97..929ee67b 100644 --- a/Tests/ASViewControllerTests.mm +++ b/Tests/ASViewControllerTests.mm @@ -24,6 +24,8 @@ - (void)testThatAutomaticSubnodeManagementScrollViewInsetsAreApplied { UIWindow *window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; + [window makeKeyAndVisible]; + ASDisplayNode *node = [[ASDisplayNode alloc] init]; node.automaticallyManagesSubnodes = YES; ASScrollNode *scrollNode = [[ASScrollNode alloc] init]; @@ -34,13 +36,16 @@ window.rootViewController = [[UINavigationController alloc] initWithRootViewController:vc]; [window makeKeyAndVisible]; [window layoutIfNeeded]; + XCTAssertEqualObjects(NSStringFromCGRect(window.bounds), NSStringFromCGRect(node.frame)); - XCTAssertNotEqual(scrollNode.view.contentInset.top, 0); + XCTAssertEqual(scrollNode.view.contentInset.top, 0); } - (void)testThatViewControllerFrameIsRightAfterCustomTransitionWithNonextendedEdges { UIWindow *window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; + [window makeKeyAndVisible]; + ASDisplayNode *node = [[ASDisplayNode alloc] init]; ASViewController *vc = [[ASViewController alloc] initWithNode:node]; @@ -72,8 +77,9 @@ nav.delegate = navDelegate; window.rootViewController = nav; [window makeKeyAndVisible]; - [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate date]]; + [[NSRunLoop mainRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:2]]; [nav pushViewController:vc animated:YES]; + [[NSRunLoop mainRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:2]]; [self waitForExpectationsWithTimeout:2 handler:nil]; diff --git a/Tests/ReferenceImages_64/ASButtonNodeSnapshotTests/testChangingTintColor@2x.png b/Tests/ReferenceImages_64/ASButtonNodeSnapshotTests/testChangingTintColor@2x.png new file mode 100644 index 00000000..97434578 Binary files /dev/null and b/Tests/ReferenceImages_64/ASButtonNodeSnapshotTests/testChangingTintColor@2x.png differ diff --git a/Tests/ReferenceImages_iOS_10/ASButtonNodeSnapshotTests/testTintColorWithForegroundColorSet@2x.png b/Tests/ReferenceImages_64/ASButtonNodeSnapshotTests/testChangingTintColor_modified_tint@2x.png similarity index 57% rename from Tests/ReferenceImages_iOS_10/ASButtonNodeSnapshotTests/testTintColorWithForegroundColorSet@2x.png rename to Tests/ReferenceImages_64/ASButtonNodeSnapshotTests/testChangingTintColor_modified_tint@2x.png index e6dfeed9..697a92cf 100644 Binary files a/Tests/ReferenceImages_iOS_10/ASButtonNodeSnapshotTests/testTintColorWithForegroundColorSet@2x.png and b/Tests/ReferenceImages_64/ASButtonNodeSnapshotTests/testChangingTintColor_modified_tint@2x.png differ diff --git a/Tests/ReferenceImages_iOS_10/ASButtonNodeSnapshotTests/testTintColor@2x.png b/Tests/ReferenceImages_64/ASButtonNodeSnapshotTests/testTintColor@2x.png similarity index 57% rename from Tests/ReferenceImages_iOS_10/ASButtonNodeSnapshotTests/testTintColor@2x.png rename to Tests/ReferenceImages_64/ASButtonNodeSnapshotTests/testTintColor@2x.png index 5c8a8a57..97434578 100644 Binary files a/Tests/ReferenceImages_iOS_10/ASButtonNodeSnapshotTests/testTintColor@2x.png and b/Tests/ReferenceImages_64/ASButtonNodeSnapshotTests/testTintColor@2x.png differ diff --git a/Tests/ReferenceImages_iOS_10/ASButtonNodeSnapshotTests/testChangingTintColor@2x.png b/Tests/ReferenceImages_64/ASButtonNodeSnapshotTests/testTintColorWithForegroundColorSet@2x.png similarity index 57% rename from Tests/ReferenceImages_iOS_10/ASButtonNodeSnapshotTests/testChangingTintColor@2x.png rename to Tests/ReferenceImages_64/ASButtonNodeSnapshotTests/testTintColorWithForegroundColorSet@2x.png index 5c8a8a57..452a8e10 100644 Binary files a/Tests/ReferenceImages_iOS_10/ASButtonNodeSnapshotTests/testChangingTintColor@2x.png and b/Tests/ReferenceImages_64/ASButtonNodeSnapshotTests/testTintColorWithForegroundColorSet@2x.png differ diff --git a/Tests/ReferenceImages_iOS_10/ASButtonNodeSnapshotTests/testChangingTintColor_modified_tint@2x.png b/Tests/ReferenceImages_64/ASButtonNodeSnapshotTests/testTintColorWithInheritedTintColor_green_inherited_tint@2x.png similarity index 58% rename from Tests/ReferenceImages_iOS_10/ASButtonNodeSnapshotTests/testChangingTintColor_modified_tint@2x.png rename to Tests/ReferenceImages_64/ASButtonNodeSnapshotTests/testTintColorWithInheritedTintColor_green_inherited_tint@2x.png index 89a8b63c..4cb86e74 100644 Binary files a/Tests/ReferenceImages_iOS_10/ASButtonNodeSnapshotTests/testChangingTintColor_modified_tint@2x.png and b/Tests/ReferenceImages_64/ASButtonNodeSnapshotTests/testTintColorWithInheritedTintColor_green_inherited_tint@2x.png differ diff --git a/Tests/ReferenceImages_64/ASButtonNodeSnapshotTests/testTintColorWithInheritedTintColor_red_inherited_tint@2x.png b/Tests/ReferenceImages_64/ASButtonNodeSnapshotTests/testTintColorWithInheritedTintColor_red_inherited_tint@2x.png new file mode 100644 index 00000000..97434578 Binary files /dev/null and b/Tests/ReferenceImages_64/ASButtonNodeSnapshotTests/testTintColorWithInheritedTintColor_red_inherited_tint@2x.png differ diff --git a/Tests/ReferenceImages_iOS_10/ASButtonNodeSnapshotTests/testUserInterfaceStyleSnapshotTesting_user_interface_style_dark@2x.png b/Tests/ReferenceImages_64/ASButtonNodeSnapshotTests/testUserInterfaceStyleSnapshotTesting_user_interface_style_dark@2x.png similarity index 100% rename from Tests/ReferenceImages_iOS_10/ASButtonNodeSnapshotTests/testUserInterfaceStyleSnapshotTesting_user_interface_style_dark@2x.png rename to Tests/ReferenceImages_64/ASButtonNodeSnapshotTests/testUserInterfaceStyleSnapshotTesting_user_interface_style_dark@2x.png diff --git a/Tests/ReferenceImages_iOS_10/ASButtonNodeSnapshotTests/testUserInterfaceStyleSnapshotTesting_user_interface_style_light@2x.png b/Tests/ReferenceImages_64/ASButtonNodeSnapshotTests/testUserInterfaceStyleSnapshotTesting_user_interface_style_light@2x.png similarity index 100% rename from Tests/ReferenceImages_iOS_10/ASButtonNodeSnapshotTests/testUserInterfaceStyleSnapshotTesting_user_interface_style_light@2x.png rename to Tests/ReferenceImages_64/ASButtonNodeSnapshotTests/testUserInterfaceStyleSnapshotTesting_user_interface_style_light@2x.png diff --git a/Tests/ReferenceImages_iOS_10/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocationsWithInnerOffset_bottomLeft_inner_childSize@2x.png b/Tests/ReferenceImages_64/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocationsWithInnerOffset_bottomLeft_inner_childSize@2x.png similarity index 100% rename from Tests/ReferenceImages_iOS_10/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocationsWithInnerOffset_bottomLeft_inner_childSize@2x.png rename to Tests/ReferenceImages_64/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocationsWithInnerOffset_bottomLeft_inner_childSize@2x.png diff --git a/Tests/ReferenceImages_iOS_10/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocationsWithInnerOffset_bottomLeft_inner_fullSize@2x.png b/Tests/ReferenceImages_64/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocationsWithInnerOffset_bottomLeft_inner_fullSize@2x.png similarity index 100% rename from Tests/ReferenceImages_iOS_10/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocationsWithInnerOffset_bottomLeft_inner_fullSize@2x.png rename to Tests/ReferenceImages_64/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocationsWithInnerOffset_bottomLeft_inner_fullSize@2x.png diff --git a/Tests/ReferenceImages_iOS_10/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocationsWithInnerOffset_bottomRight_inner_childSize@2x.png b/Tests/ReferenceImages_64/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocationsWithInnerOffset_bottomRight_inner_childSize@2x.png similarity index 100% rename from Tests/ReferenceImages_iOS_10/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocationsWithInnerOffset_bottomRight_inner_childSize@2x.png rename to Tests/ReferenceImages_64/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocationsWithInnerOffset_bottomRight_inner_childSize@2x.png diff --git a/Tests/ReferenceImages_iOS_10/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocationsWithInnerOffset_bottomRight_inner_fullSize@2x.png b/Tests/ReferenceImages_64/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocationsWithInnerOffset_bottomRight_inner_fullSize@2x.png similarity index 100% rename from Tests/ReferenceImages_iOS_10/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocationsWithInnerOffset_bottomRight_inner_fullSize@2x.png rename to Tests/ReferenceImages_64/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocationsWithInnerOffset_bottomRight_inner_fullSize@2x.png diff --git a/Tests/ReferenceImages_iOS_10/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocationsWithInnerOffset_topLeft_inner_childSize@2x.png b/Tests/ReferenceImages_64/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocationsWithInnerOffset_topLeft_inner_childSize@2x.png similarity index 100% rename from Tests/ReferenceImages_iOS_10/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocationsWithInnerOffset_topLeft_inner_childSize@2x.png rename to Tests/ReferenceImages_64/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocationsWithInnerOffset_topLeft_inner_childSize@2x.png diff --git a/Tests/ReferenceImages_iOS_10/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocationsWithInnerOffset_topLeft_inner_fullSize@2x.png b/Tests/ReferenceImages_64/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocationsWithInnerOffset_topLeft_inner_fullSize@2x.png similarity index 100% rename from Tests/ReferenceImages_iOS_10/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocationsWithInnerOffset_topLeft_inner_fullSize@2x.png rename to Tests/ReferenceImages_64/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocationsWithInnerOffset_topLeft_inner_fullSize@2x.png diff --git a/Tests/ReferenceImages_iOS_10/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocationsWithInnerOffset_topRight_inner_childSize@2x.png b/Tests/ReferenceImages_64/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocationsWithInnerOffset_topRight_inner_childSize@2x.png similarity index 100% rename from Tests/ReferenceImages_iOS_10/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocationsWithInnerOffset_topRight_inner_childSize@2x.png rename to Tests/ReferenceImages_64/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocationsWithInnerOffset_topRight_inner_childSize@2x.png diff --git a/Tests/ReferenceImages_iOS_10/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocationsWithInnerOffset_topRight_inner_fullSize@2x.png b/Tests/ReferenceImages_64/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocationsWithInnerOffset_topRight_inner_fullSize@2x.png similarity index 100% rename from Tests/ReferenceImages_iOS_10/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocationsWithInnerOffset_topRight_inner_fullSize@2x.png rename to Tests/ReferenceImages_64/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocationsWithInnerOffset_topRight_inner_fullSize@2x.png diff --git a/Tests/ReferenceImages_iOS_10/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocationsWithOuterOffset_bottomLeft_outer_childSize@2x.png b/Tests/ReferenceImages_64/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocationsWithOuterOffset_bottomLeft_outer_childSize@2x.png similarity index 100% rename from Tests/ReferenceImages_iOS_10/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocationsWithOuterOffset_bottomLeft_outer_childSize@2x.png rename to Tests/ReferenceImages_64/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocationsWithOuterOffset_bottomLeft_outer_childSize@2x.png diff --git a/Tests/ReferenceImages_iOS_10/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocationsWithOuterOffset_bottomLeft_outer_fullSize@2x.png b/Tests/ReferenceImages_64/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocationsWithOuterOffset_bottomLeft_outer_fullSize@2x.png similarity index 100% rename from Tests/ReferenceImages_iOS_10/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocationsWithOuterOffset_bottomLeft_outer_fullSize@2x.png rename to Tests/ReferenceImages_64/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocationsWithOuterOffset_bottomLeft_outer_fullSize@2x.png diff --git a/Tests/ReferenceImages_iOS_10/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocationsWithOuterOffset_bottomRight_outer_childSize@2x.png b/Tests/ReferenceImages_64/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocationsWithOuterOffset_bottomRight_outer_childSize@2x.png similarity index 100% rename from Tests/ReferenceImages_iOS_10/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocationsWithOuterOffset_bottomRight_outer_childSize@2x.png rename to Tests/ReferenceImages_64/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocationsWithOuterOffset_bottomRight_outer_childSize@2x.png diff --git a/Tests/ReferenceImages_iOS_10/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocationsWithOuterOffset_bottomRight_outer_fullSize@2x.png b/Tests/ReferenceImages_64/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocationsWithOuterOffset_bottomRight_outer_fullSize@2x.png similarity index 100% rename from Tests/ReferenceImages_iOS_10/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocationsWithOuterOffset_bottomRight_outer_fullSize@2x.png rename to Tests/ReferenceImages_64/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocationsWithOuterOffset_bottomRight_outer_fullSize@2x.png diff --git a/Tests/ReferenceImages_iOS_10/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocationsWithOuterOffset_topLeft_outer_childSize@2x.png b/Tests/ReferenceImages_64/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocationsWithOuterOffset_topLeft_outer_childSize@2x.png similarity index 100% rename from Tests/ReferenceImages_iOS_10/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocationsWithOuterOffset_topLeft_outer_childSize@2x.png rename to Tests/ReferenceImages_64/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocationsWithOuterOffset_topLeft_outer_childSize@2x.png diff --git a/Tests/ReferenceImages_iOS_10/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocationsWithOuterOffset_topLeft_outer_fullSize@2x.png b/Tests/ReferenceImages_64/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocationsWithOuterOffset_topLeft_outer_fullSize@2x.png similarity index 100% rename from Tests/ReferenceImages_iOS_10/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocationsWithOuterOffset_topLeft_outer_fullSize@2x.png rename to Tests/ReferenceImages_64/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocationsWithOuterOffset_topLeft_outer_fullSize@2x.png diff --git a/Tests/ReferenceImages_iOS_10/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocationsWithOuterOffset_topRight_outer_childSize@2x.png b/Tests/ReferenceImages_64/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocationsWithOuterOffset_topRight_outer_childSize@2x.png similarity index 100% rename from Tests/ReferenceImages_iOS_10/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocationsWithOuterOffset_topRight_outer_childSize@2x.png rename to Tests/ReferenceImages_64/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocationsWithOuterOffset_topRight_outer_childSize@2x.png diff --git a/Tests/ReferenceImages_iOS_10/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocationsWithOuterOffset_topRight_outer_fullSize@2x.png b/Tests/ReferenceImages_64/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocationsWithOuterOffset_topRight_outer_fullSize@2x.png similarity index 100% rename from Tests/ReferenceImages_iOS_10/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocationsWithOuterOffset_topRight_outer_fullSize@2x.png rename to Tests/ReferenceImages_64/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocationsWithOuterOffset_topRight_outer_fullSize@2x.png diff --git a/Tests/ReferenceImages_iOS_10/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocations_bottomLeft_center_childSize@2x.png b/Tests/ReferenceImages_64/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocations_bottomLeft_center_childSize@2x.png similarity index 100% rename from Tests/ReferenceImages_iOS_10/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocations_bottomLeft_center_childSize@2x.png rename to Tests/ReferenceImages_64/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocations_bottomLeft_center_childSize@2x.png diff --git a/Tests/ReferenceImages_iOS_10/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocations_bottomLeft_center_fullSize@2x.png b/Tests/ReferenceImages_64/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocations_bottomLeft_center_fullSize@2x.png similarity index 100% rename from Tests/ReferenceImages_iOS_10/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocations_bottomLeft_center_fullSize@2x.png rename to Tests/ReferenceImages_64/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocations_bottomLeft_center_fullSize@2x.png diff --git a/Tests/ReferenceImages_iOS_10/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocations_bottomRight_center_childSize@2x.png b/Tests/ReferenceImages_64/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocations_bottomRight_center_childSize@2x.png similarity index 100% rename from Tests/ReferenceImages_iOS_10/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocations_bottomRight_center_childSize@2x.png rename to Tests/ReferenceImages_64/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocations_bottomRight_center_childSize@2x.png diff --git a/Tests/ReferenceImages_iOS_10/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocations_bottomRight_center_fullSize@2x.png b/Tests/ReferenceImages_64/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocations_bottomRight_center_fullSize@2x.png similarity index 100% rename from Tests/ReferenceImages_iOS_10/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocations_bottomRight_center_fullSize@2x.png rename to Tests/ReferenceImages_64/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocations_bottomRight_center_fullSize@2x.png diff --git a/Tests/ReferenceImages_iOS_10/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocations_topLeft_center_childSize@2x.png b/Tests/ReferenceImages_64/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocations_topLeft_center_childSize@2x.png similarity index 100% rename from Tests/ReferenceImages_iOS_10/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocations_topLeft_center_childSize@2x.png rename to Tests/ReferenceImages_64/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocations_topLeft_center_childSize@2x.png diff --git a/Tests/ReferenceImages_iOS_10/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocations_topLeft_center_fullSize@2x.png b/Tests/ReferenceImages_64/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocations_topLeft_center_fullSize@2x.png similarity index 100% rename from Tests/ReferenceImages_iOS_10/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocations_topLeft_center_fullSize@2x.png rename to Tests/ReferenceImages_64/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocations_topLeft_center_fullSize@2x.png diff --git a/Tests/ReferenceImages_iOS_10/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocations_topRight_center_childSize@2x.png b/Tests/ReferenceImages_64/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocations_topRight_center_childSize@2x.png similarity index 100% rename from Tests/ReferenceImages_iOS_10/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocations_topRight_center_childSize@2x.png rename to Tests/ReferenceImages_64/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocations_topRight_center_childSize@2x.png diff --git a/Tests/ReferenceImages_iOS_10/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocations_topRight_center_fullSize@2x.png b/Tests/ReferenceImages_64/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocations_topRight_center_fullSize@2x.png similarity index 100% rename from Tests/ReferenceImages_iOS_10/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocations_topRight_center_fullSize@2x.png rename to Tests/ReferenceImages_64/ASCornerLayoutSpecSnapshotTests/testCornerSpecForAllLocations_topRight_center_fullSize@2x.png diff --git a/Tests/ReferenceImages_64/ASDisplayNodeSnapshotTests/testBackgroundDynamicColorLayerBacked_dark@2x.png b/Tests/ReferenceImages_64/ASDisplayNodeSnapshotTests/testBackgroundDynamicColorLayerBacked_dark@2x.png new file mode 100644 index 00000000..2516cc86 Binary files /dev/null and b/Tests/ReferenceImages_64/ASDisplayNodeSnapshotTests/testBackgroundDynamicColorLayerBacked_dark@2x.png differ diff --git a/Tests/ReferenceImages_64/ASDisplayNodeSnapshotTests/testBackgroundDynamicColorLayerBacked_light@2x.png b/Tests/ReferenceImages_64/ASDisplayNodeSnapshotTests/testBackgroundDynamicColorLayerBacked_light@2x.png new file mode 100644 index 00000000..ca7d38e4 Binary files /dev/null and b/Tests/ReferenceImages_64/ASDisplayNodeSnapshotTests/testBackgroundDynamicColorLayerBacked_light@2x.png differ diff --git a/Tests/ReferenceImages_64/ASDisplayNodeSnapshotTests/testBackgroundDynamicColor_dark@2x.png b/Tests/ReferenceImages_64/ASDisplayNodeSnapshotTests/testBackgroundDynamicColor_dark@2x.png new file mode 100644 index 00000000..2516cc86 Binary files /dev/null and b/Tests/ReferenceImages_64/ASDisplayNodeSnapshotTests/testBackgroundDynamicColor_dark@2x.png differ diff --git a/Tests/ReferenceImages_64/ASDisplayNodeSnapshotTests/testBackgroundDynamicColor_light@2x.png b/Tests/ReferenceImages_64/ASDisplayNodeSnapshotTests/testBackgroundDynamicColor_light@2x.png new file mode 100644 index 00000000..ca7d38e4 Binary files /dev/null and b/Tests/ReferenceImages_64/ASDisplayNodeSnapshotTests/testBackgroundDynamicColor_light@2x.png differ diff --git a/Tests/ReferenceImages_iOS_10/ASDisplayNodeSnapshotTests/testClippingCornerRounding@2x.png b/Tests/ReferenceImages_64/ASDisplayNodeSnapshotTests/testClippingCornerRounding@2x.png similarity index 100% rename from Tests/ReferenceImages_iOS_10/ASDisplayNodeSnapshotTests/testClippingCornerRounding@2x.png rename to Tests/ReferenceImages_64/ASDisplayNodeSnapshotTests/testClippingCornerRounding@2x.png diff --git a/Tests/ReferenceImages_iOS_10/ASDisplayNodeSnapshotTests/testClippingCornerRounding_15@2x.png b/Tests/ReferenceImages_64/ASDisplayNodeSnapshotTests/testClippingCornerRounding_15@2x.png similarity index 100% rename from Tests/ReferenceImages_iOS_10/ASDisplayNodeSnapshotTests/testClippingCornerRounding_15@2x.png rename to Tests/ReferenceImages_64/ASDisplayNodeSnapshotTests/testClippingCornerRounding_15@2x.png diff --git a/Tests/ReferenceImages_64/ASDisplayNodeSnapshotTests/testClippingCornerRounding_15_dark@2x.png b/Tests/ReferenceImages_64/ASDisplayNodeSnapshotTests/testClippingCornerRounding_15_dark@2x.png new file mode 100644 index 00000000..3939eff5 Binary files /dev/null and b/Tests/ReferenceImages_64/ASDisplayNodeSnapshotTests/testClippingCornerRounding_15_dark@2x.png differ diff --git a/Tests/ReferenceImages_64/ASDisplayNodeSnapshotTests/testClippingCornerRounding_15_light@2x.png b/Tests/ReferenceImages_64/ASDisplayNodeSnapshotTests/testClippingCornerRounding_15_light@2x.png new file mode 100644 index 00000000..156f9762 Binary files /dev/null and b/Tests/ReferenceImages_64/ASDisplayNodeSnapshotTests/testClippingCornerRounding_15_light@2x.png differ diff --git a/Tests/ReferenceImages_iOS_10/ASDisplayNodeSnapshotTests/testClippingCornerRounding_1@2x.png b/Tests/ReferenceImages_64/ASDisplayNodeSnapshotTests/testClippingCornerRounding_1@2x.png similarity index 100% rename from Tests/ReferenceImages_iOS_10/ASDisplayNodeSnapshotTests/testClippingCornerRounding_1@2x.png rename to Tests/ReferenceImages_64/ASDisplayNodeSnapshotTests/testClippingCornerRounding_1@2x.png diff --git a/Tests/ReferenceImages_64/ASDisplayNodeSnapshotTests/testClippingCornerRounding_1_dark@2x.png b/Tests/ReferenceImages_64/ASDisplayNodeSnapshotTests/testClippingCornerRounding_1_dark@2x.png new file mode 100644 index 00000000..1c3b01ba Binary files /dev/null and b/Tests/ReferenceImages_64/ASDisplayNodeSnapshotTests/testClippingCornerRounding_1_dark@2x.png differ diff --git a/Tests/ReferenceImages_64/ASDisplayNodeSnapshotTests/testClippingCornerRounding_1_light@2x.png b/Tests/ReferenceImages_64/ASDisplayNodeSnapshotTests/testClippingCornerRounding_1_light@2x.png new file mode 100644 index 00000000..7afab053 Binary files /dev/null and b/Tests/ReferenceImages_64/ASDisplayNodeSnapshotTests/testClippingCornerRounding_1_light@2x.png differ diff --git a/Tests/ReferenceImages_iOS_10/ASDisplayNodeSnapshotTests/testClippingCornerRounding_3@2x.png b/Tests/ReferenceImages_64/ASDisplayNodeSnapshotTests/testClippingCornerRounding_3@2x.png similarity index 100% rename from Tests/ReferenceImages_iOS_10/ASDisplayNodeSnapshotTests/testClippingCornerRounding_3@2x.png rename to Tests/ReferenceImages_64/ASDisplayNodeSnapshotTests/testClippingCornerRounding_3@2x.png diff --git a/Tests/ReferenceImages_64/ASDisplayNodeSnapshotTests/testClippingCornerRounding_3_dark@2x.png b/Tests/ReferenceImages_64/ASDisplayNodeSnapshotTests/testClippingCornerRounding_3_dark@2x.png new file mode 100644 index 00000000..ecbd0689 Binary files /dev/null and b/Tests/ReferenceImages_64/ASDisplayNodeSnapshotTests/testClippingCornerRounding_3_dark@2x.png differ diff --git a/Tests/ReferenceImages_64/ASDisplayNodeSnapshotTests/testClippingCornerRounding_3_light@2x.png b/Tests/ReferenceImages_64/ASDisplayNodeSnapshotTests/testClippingCornerRounding_3_light@2x.png new file mode 100644 index 00000000..b75ac65b Binary files /dev/null and b/Tests/ReferenceImages_64/ASDisplayNodeSnapshotTests/testClippingCornerRounding_3_light@2x.png differ diff --git a/Tests/ReferenceImages_iOS_10/ASDisplayNodeSnapshotTests/testClippingCornerRounding_7@2x.png b/Tests/ReferenceImages_64/ASDisplayNodeSnapshotTests/testClippingCornerRounding_7@2x.png similarity index 100% rename from Tests/ReferenceImages_iOS_10/ASDisplayNodeSnapshotTests/testClippingCornerRounding_7@2x.png rename to Tests/ReferenceImages_64/ASDisplayNodeSnapshotTests/testClippingCornerRounding_7@2x.png diff --git a/Tests/ReferenceImages_64/ASDisplayNodeSnapshotTests/testClippingCornerRounding_7_dark@2x.png b/Tests/ReferenceImages_64/ASDisplayNodeSnapshotTests/testClippingCornerRounding_7_dark@2x.png new file mode 100644 index 00000000..b41f6ebc Binary files /dev/null and b/Tests/ReferenceImages_64/ASDisplayNodeSnapshotTests/testClippingCornerRounding_7_dark@2x.png differ diff --git a/Tests/ReferenceImages_64/ASDisplayNodeSnapshotTests/testClippingCornerRounding_7_light@2x.png b/Tests/ReferenceImages_64/ASDisplayNodeSnapshotTests/testClippingCornerRounding_7_light@2x.png new file mode 100644 index 00000000..753c3604 Binary files /dev/null and b/Tests/ReferenceImages_64/ASDisplayNodeSnapshotTests/testClippingCornerRounding_7_light@2x.png differ diff --git a/Tests/ReferenceImages_iOS_10/ASDisplayNodeSnapshotTests/testPrecompositedCornerRounding@2x.png b/Tests/ReferenceImages_64/ASDisplayNodeSnapshotTests/testPrecompositedCornerRounding@2x.png similarity index 100% rename from Tests/ReferenceImages_iOS_10/ASDisplayNodeSnapshotTests/testPrecompositedCornerRounding@2x.png rename to Tests/ReferenceImages_64/ASDisplayNodeSnapshotTests/testPrecompositedCornerRounding@2x.png diff --git a/Tests/ReferenceImages_64/ASDisplayNodeSnapshotTests/testPrecompositedCornerRounding_15@2x.png b/Tests/ReferenceImages_64/ASDisplayNodeSnapshotTests/testPrecompositedCornerRounding_15@2x.png new file mode 100644 index 00000000..a5993c48 Binary files /dev/null and b/Tests/ReferenceImages_64/ASDisplayNodeSnapshotTests/testPrecompositedCornerRounding_15@2x.png differ diff --git a/Tests/ReferenceImages_64/ASDisplayNodeSnapshotTests/testPrecompositedCornerRounding_1@2x.png b/Tests/ReferenceImages_64/ASDisplayNodeSnapshotTests/testPrecompositedCornerRounding_1@2x.png new file mode 100644 index 00000000..581279f1 Binary files /dev/null and b/Tests/ReferenceImages_64/ASDisplayNodeSnapshotTests/testPrecompositedCornerRounding_1@2x.png differ diff --git a/Tests/ReferenceImages_64/ASDisplayNodeSnapshotTests/testPrecompositedCornerRounding_3@2x.png b/Tests/ReferenceImages_64/ASDisplayNodeSnapshotTests/testPrecompositedCornerRounding_3@2x.png new file mode 100644 index 00000000..51143093 Binary files /dev/null and b/Tests/ReferenceImages_64/ASDisplayNodeSnapshotTests/testPrecompositedCornerRounding_3@2x.png differ diff --git a/Tests/ReferenceImages_64/ASDisplayNodeSnapshotTests/testPrecompositedCornerRounding_7@2x.png b/Tests/ReferenceImages_64/ASDisplayNodeSnapshotTests/testPrecompositedCornerRounding_7@2x.png new file mode 100644 index 00000000..b95e87c3 Binary files /dev/null and b/Tests/ReferenceImages_64/ASDisplayNodeSnapshotTests/testPrecompositedCornerRounding_7@2x.png differ diff --git a/Tests/ReferenceImages_iOS_10/ASDisplayNodeSnapshotTests/testUserInterfaceStyleSnapshotTesting_user_interface_style_dark@2x.png b/Tests/ReferenceImages_64/ASDisplayNodeSnapshotTests/testUserInterfaceStyleSnapshotTesting_user_interface_style_dark@2x.png similarity index 100% rename from Tests/ReferenceImages_iOS_10/ASDisplayNodeSnapshotTests/testUserInterfaceStyleSnapshotTesting_user_interface_style_dark@2x.png rename to Tests/ReferenceImages_64/ASDisplayNodeSnapshotTests/testUserInterfaceStyleSnapshotTesting_user_interface_style_dark@2x.png diff --git a/Tests/ReferenceImages_iOS_10/ASDisplayNodeSnapshotTests/testUserInterfaceStyleSnapshotTesting_user_interface_style_light@2x.png b/Tests/ReferenceImages_64/ASDisplayNodeSnapshotTests/testUserInterfaceStyleSnapshotTesting_user_interface_style_light@2x.png similarity index 100% rename from Tests/ReferenceImages_iOS_10/ASDisplayNodeSnapshotTests/testUserInterfaceStyleSnapshotTesting_user_interface_style_light@2x.png rename to Tests/ReferenceImages_64/ASDisplayNodeSnapshotTests/testUserInterfaceStyleSnapshotTesting_user_interface_style_light@2x.png diff --git a/Tests/ReferenceImages_iOS_10/ASImageNodeSnapshotTests/testDynamicAssetImage_user_interface_style_dark@2x.png b/Tests/ReferenceImages_64/ASImageNodeSnapshotTests/testDynamicAssetImage_user_interface_style_dark@2x.png similarity index 100% rename from Tests/ReferenceImages_iOS_10/ASImageNodeSnapshotTests/testDynamicAssetImage_user_interface_style_dark@2x.png rename to Tests/ReferenceImages_64/ASImageNodeSnapshotTests/testDynamicAssetImage_user_interface_style_dark@2x.png diff --git a/Tests/ReferenceImages_iOS_10/ASImageNodeSnapshotTests/testDynamicAssetImage_user_interface_style_light@2x.png b/Tests/ReferenceImages_64/ASImageNodeSnapshotTests/testDynamicAssetImage_user_interface_style_light@2x.png similarity index 100% rename from Tests/ReferenceImages_iOS_10/ASImageNodeSnapshotTests/testDynamicAssetImage_user_interface_style_light@2x.png rename to Tests/ReferenceImages_64/ASImageNodeSnapshotTests/testDynamicAssetImage_user_interface_style_light@2x.png diff --git a/Tests/ReferenceImages_64/ASImageNodeSnapshotTests/testDynamicTintColor_user_interface_style_dark@2x.png b/Tests/ReferenceImages_64/ASImageNodeSnapshotTests/testDynamicTintColor_user_interface_style_dark@2x.png new file mode 100644 index 00000000..183c55b6 Binary files /dev/null and b/Tests/ReferenceImages_64/ASImageNodeSnapshotTests/testDynamicTintColor_user_interface_style_dark@2x.png differ diff --git a/Tests/ReferenceImages_64/ASImageNodeSnapshotTests/testDynamicTintColor_user_interface_style_light@2x.png b/Tests/ReferenceImages_64/ASImageNodeSnapshotTests/testDynamicTintColor_user_interface_style_light@2x.png new file mode 100644 index 00000000..fa575565 Binary files /dev/null and b/Tests/ReferenceImages_64/ASImageNodeSnapshotTests/testDynamicTintColor_user_interface_style_light@2x.png differ diff --git a/Tests/ReferenceImages_64/ASImageNodeSnapshotTests/testForcedScaling_first@2x.png b/Tests/ReferenceImages_64/ASImageNodeSnapshotTests/testForcedScaling_first@2x.png index 896dc7ab..d593e113 100644 Binary files a/Tests/ReferenceImages_64/ASImageNodeSnapshotTests/testForcedScaling_first@2x.png and b/Tests/ReferenceImages_64/ASImageNodeSnapshotTests/testForcedScaling_first@2x.png differ diff --git a/Tests/ReferenceImages_64/ASImageNodeSnapshotTests/testForcedScaling_second@2x.png b/Tests/ReferenceImages_64/ASImageNodeSnapshotTests/testForcedScaling_second@2x.png index 79d4c747..f85d1a9f 100644 Binary files a/Tests/ReferenceImages_64/ASImageNodeSnapshotTests/testForcedScaling_second@2x.png and b/Tests/ReferenceImages_64/ASImageNodeSnapshotTests/testForcedScaling_second@2x.png differ diff --git a/Tests/ReferenceImages_64/ASImageNodeSnapshotTests/testRenderLogoSquare@2x.png b/Tests/ReferenceImages_64/ASImageNodeSnapshotTests/testRenderLogoSquare@2x.png index 896dc7ab..d593e113 100644 Binary files a/Tests/ReferenceImages_64/ASImageNodeSnapshotTests/testRenderLogoSquare@2x.png and b/Tests/ReferenceImages_64/ASImageNodeSnapshotTests/testRenderLogoSquare@2x.png differ diff --git a/Tests/ReferenceImages_64/ASImageNodeSnapshotTests/testTintColorBlock@2x.png b/Tests/ReferenceImages_64/ASImageNodeSnapshotTests/testTintColorBlock@2x.png index 0cc74697..77cf9afb 100644 Binary files a/Tests/ReferenceImages_64/ASImageNodeSnapshotTests/testTintColorBlock@2x.png and b/Tests/ReferenceImages_64/ASImageNodeSnapshotTests/testTintColorBlock@2x.png differ diff --git a/Tests/ReferenceImages_iOS_10/ASImageNodeSnapshotTests/testTintColorInheritsFromSupernodeLayerBacked@2x.png b/Tests/ReferenceImages_64/ASImageNodeSnapshotTests/testTintColorInheritsFromSupernodeLayerBacked@2x.png similarity index 100% rename from Tests/ReferenceImages_iOS_10/ASImageNodeSnapshotTests/testTintColorInheritsFromSupernodeLayerBacked@2x.png rename to Tests/ReferenceImages_64/ASImageNodeSnapshotTests/testTintColorInheritsFromSupernodeLayerBacked@2x.png diff --git a/Tests/ReferenceImages_iOS_10/ASImageNodeSnapshotTests/testTintColorInheritsFromSupernodeViewBacked@2x.png b/Tests/ReferenceImages_64/ASImageNodeSnapshotTests/testTintColorInheritsFromSupernodeViewBacked@2x.png similarity index 100% rename from Tests/ReferenceImages_iOS_10/ASImageNodeSnapshotTests/testTintColorInheritsFromSupernodeViewBacked@2x.png rename to Tests/ReferenceImages_64/ASImageNodeSnapshotTests/testTintColorInheritsFromSupernodeViewBacked@2x.png diff --git a/Tests/ReferenceImages_iOS_10/ASImageNodeSnapshotTests/testTintColorOnGrayscaleNodePropertyAlwaysTemplate_blue_tint@2x.png b/Tests/ReferenceImages_64/ASImageNodeSnapshotTests/testTintColorOnGrayscaleNodePropertyAlwaysTemplate_blue_tint@2x.png similarity index 100% rename from Tests/ReferenceImages_iOS_10/ASImageNodeSnapshotTests/testTintColorOnGrayscaleNodePropertyAlwaysTemplate_blue_tint@2x.png rename to Tests/ReferenceImages_64/ASImageNodeSnapshotTests/testTintColorOnGrayscaleNodePropertyAlwaysTemplate_blue_tint@2x.png diff --git a/Tests/ReferenceImages_iOS_10/ASImageNodeSnapshotTests/testTintColorOnGrayscaleNodePropertyAlwaysTemplate_red_tint@2x.png b/Tests/ReferenceImages_64/ASImageNodeSnapshotTests/testTintColorOnGrayscaleNodePropertyAlwaysTemplate_red_tint@2x.png similarity index 100% rename from Tests/ReferenceImages_iOS_10/ASImageNodeSnapshotTests/testTintColorOnGrayscaleNodePropertyAlwaysTemplate_red_tint@2x.png rename to Tests/ReferenceImages_64/ASImageNodeSnapshotTests/testTintColorOnGrayscaleNodePropertyAlwaysTemplate_red_tint@2x.png diff --git a/Tests/ReferenceImages_iOS_10/ASImageNodeSnapshotTests/testTintColorOnNodePropertyAlwaysOriginal@2x.png b/Tests/ReferenceImages_64/ASImageNodeSnapshotTests/testTintColorOnNodePropertyAlwaysOriginal@2x.png similarity index 100% rename from Tests/ReferenceImages_iOS_10/ASImageNodeSnapshotTests/testTintColorOnNodePropertyAlwaysOriginal@2x.png rename to Tests/ReferenceImages_64/ASImageNodeSnapshotTests/testTintColorOnNodePropertyAlwaysOriginal@2x.png diff --git a/Tests/ReferenceImages_iOS_10/ASImageNodeSnapshotTests/testTintColorOnNodePropertyAlwaysTemplateLayerBackedNode@2x.png b/Tests/ReferenceImages_64/ASImageNodeSnapshotTests/testTintColorOnNodePropertyAlwaysTemplateLayerBackedNode@2x.png similarity index 100% rename from Tests/ReferenceImages_iOS_10/ASImageNodeSnapshotTests/testTintColorOnNodePropertyAlwaysTemplateLayerBackedNode@2x.png rename to Tests/ReferenceImages_64/ASImageNodeSnapshotTests/testTintColorOnNodePropertyAlwaysTemplateLayerBackedNode@2x.png diff --git a/Tests/ReferenceImages_iOS_10/ASImageNodeSnapshotTests/testTintColorOnNodePropertyAlwaysTemplate_blue_tint@2x.png b/Tests/ReferenceImages_64/ASImageNodeSnapshotTests/testTintColorOnNodePropertyAlwaysTemplate_blue_tint@2x.png similarity index 100% rename from Tests/ReferenceImages_iOS_10/ASImageNodeSnapshotTests/testTintColorOnNodePropertyAlwaysTemplate_blue_tint@2x.png rename to Tests/ReferenceImages_64/ASImageNodeSnapshotTests/testTintColorOnNodePropertyAlwaysTemplate_blue_tint@2x.png diff --git a/Tests/ReferenceImages_iOS_10/ASImageNodeSnapshotTests/testTintColorOnNodePropertyAlwaysTemplate_red_tint@2x.png b/Tests/ReferenceImages_64/ASImageNodeSnapshotTests/testTintColorOnNodePropertyAlwaysTemplate_red_tint@2x.png similarity index 100% rename from Tests/ReferenceImages_iOS_10/ASImageNodeSnapshotTests/testTintColorOnNodePropertyAlwaysTemplate_red_tint@2x.png rename to Tests/ReferenceImages_64/ASImageNodeSnapshotTests/testTintColorOnNodePropertyAlwaysTemplate_red_tint@2x.png diff --git a/Tests/ReferenceImages_iOS_10/ASImageNodeSnapshotTests/testTintColorOnNodePropertyAutomatic@2x.png b/Tests/ReferenceImages_64/ASImageNodeSnapshotTests/testTintColorOnNodePropertyAutomatic@2x.png similarity index 100% rename from Tests/ReferenceImages_iOS_10/ASImageNodeSnapshotTests/testTintColorOnNodePropertyAutomatic@2x.png rename to Tests/ReferenceImages_64/ASImageNodeSnapshotTests/testTintColorOnNodePropertyAutomatic@2x.png diff --git a/Tests/ReferenceImages_64/ASImageNodeSnapshotTests/testUIGraphicsRendererDrawingExperiment@2x.png b/Tests/ReferenceImages_64/ASImageNodeSnapshotTests/testUIGraphicsRendererDrawingExperiment@2x.png new file mode 100644 index 00000000..d593e113 Binary files /dev/null and b/Tests/ReferenceImages_64/ASImageNodeSnapshotTests/testUIGraphicsRendererDrawingExperiment@2x.png differ diff --git a/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithFixedSize_10-10-10-10@2x.png b/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithFixedSize_10_10_10_10@2x.png similarity index 100% rename from Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithFixedSize_10-10-10-10@2x.png rename to Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithFixedSize_10_10_10_10@2x.png diff --git a/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithFixedSize_10-10-10-inf@2x.png b/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithFixedSize_10_10_10_inf@2x.png similarity index 100% rename from Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithFixedSize_10-10-10-inf@2x.png rename to Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithFixedSize_10_10_10_inf@2x.png diff --git a/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithFixedSize_10-10-inf-10@2x.png b/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithFixedSize_10_10_inf_10@2x.png similarity index 100% rename from Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithFixedSize_10-10-inf-10@2x.png rename to Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithFixedSize_10_10_inf_10@2x.png diff --git a/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithFixedSize_10-10-inf-inf@2x.png b/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithFixedSize_10_10_inf_inf@2x.png similarity index 100% rename from Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithFixedSize_10-10-inf-inf@2x.png rename to Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithFixedSize_10_10_inf_inf@2x.png diff --git a/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithFixedSize_10-inf-10-10@2x.png b/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithFixedSize_10_inf_10_10@2x.png similarity index 100% rename from Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithFixedSize_10-inf-10-10@2x.png rename to Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithFixedSize_10_inf_10_10@2x.png diff --git a/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithFixedSize_10-inf-10-inf@2x.png b/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithFixedSize_10_inf_10_inf@2x.png similarity index 100% rename from Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithFixedSize_10-inf-10-inf@2x.png rename to Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithFixedSize_10_inf_10_inf@2x.png diff --git a/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithFixedSize_10-inf-inf-10@2x.png b/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithFixedSize_10_inf_inf_10@2x.png similarity index 100% rename from Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithFixedSize_10-inf-inf-10@2x.png rename to Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithFixedSize_10_inf_inf_10@2x.png diff --git a/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithFixedSize_10-inf-inf-inf@2x.png b/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithFixedSize_10_inf_inf_inf@2x.png similarity index 100% rename from Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithFixedSize_10-inf-inf-inf@2x.png rename to Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithFixedSize_10_inf_inf_inf@2x.png diff --git a/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithFixedSize_inf-10-10-10@2x.png b/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithFixedSize_inf_10_10_10@2x.png similarity index 100% rename from Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithFixedSize_inf-10-10-10@2x.png rename to Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithFixedSize_inf_10_10_10@2x.png diff --git a/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithFixedSize_inf-10-10-inf@2x.png b/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithFixedSize_inf_10_10_inf@2x.png similarity index 100% rename from Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithFixedSize_inf-10-10-inf@2x.png rename to Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithFixedSize_inf_10_10_inf@2x.png diff --git a/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithFixedSize_inf-10-inf-10@2x.png b/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithFixedSize_inf_10_inf_10@2x.png similarity index 100% rename from Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithFixedSize_inf-10-inf-10@2x.png rename to Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithFixedSize_inf_10_inf_10@2x.png diff --git a/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithFixedSize_inf-10-inf-inf@2x.png b/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithFixedSize_inf_10_inf_inf@2x.png similarity index 100% rename from Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithFixedSize_inf-10-inf-inf@2x.png rename to Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithFixedSize_inf_10_inf_inf@2x.png diff --git a/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithFixedSize_inf-inf-10-10@2x.png b/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithFixedSize_inf_inf_10_10@2x.png similarity index 100% rename from Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithFixedSize_inf-inf-10-10@2x.png rename to Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithFixedSize_inf_inf_10_10@2x.png diff --git a/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithFixedSize_inf-inf-10-inf@2x.png b/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithFixedSize_inf_inf_10_inf@2x.png similarity index 100% rename from Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithFixedSize_inf-inf-10-inf@2x.png rename to Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithFixedSize_inf_inf_10_inf@2x.png diff --git a/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithFixedSize_inf-inf-inf-10@2x.png b/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithFixedSize_inf_inf_inf_10@2x.png similarity index 100% rename from Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithFixedSize_inf-inf-inf-10@2x.png rename to Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithFixedSize_inf_inf_inf_10@2x.png diff --git a/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithFixedSize_inf-inf-inf-inf@2x.png b/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithFixedSize_inf_inf_inf_inf@2x.png similarity index 100% rename from Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithFixedSize_inf-inf-inf-inf@2x.png rename to Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithFixedSize_inf_inf_inf_inf@2x.png diff --git a/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithInfinityAndZeroInsetValue_0-0-0-0@2x.png b/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithInfinityAndZeroInsetValue_0_0_0_0@2x.png similarity index 100% rename from Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithInfinityAndZeroInsetValue_0-0-0-0@2x.png rename to Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithInfinityAndZeroInsetValue_0_0_0_0@2x.png diff --git a/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithInfinityAndZeroInsetValue_0-0-0-inf@2x.png b/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithInfinityAndZeroInsetValue_0_0_0_inf@2x.png similarity index 100% rename from Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithInfinityAndZeroInsetValue_0-0-0-inf@2x.png rename to Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithInfinityAndZeroInsetValue_0_0_0_inf@2x.png diff --git a/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithInfinityAndZeroInsetValue_0-0-inf-0@2x.png b/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithInfinityAndZeroInsetValue_0_0_inf_0@2x.png similarity index 100% rename from Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithInfinityAndZeroInsetValue_0-0-inf-0@2x.png rename to Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithInfinityAndZeroInsetValue_0_0_inf_0@2x.png diff --git a/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithInfinityAndZeroInsetValue_0-0-inf-inf@2x.png b/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithInfinityAndZeroInsetValue_0_0_inf_inf@2x.png similarity index 100% rename from Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithInfinityAndZeroInsetValue_0-0-inf-inf@2x.png rename to Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithInfinityAndZeroInsetValue_0_0_inf_inf@2x.png diff --git a/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithInfinityAndZeroInsetValue_0-inf-0-0@2x.png b/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithInfinityAndZeroInsetValue_0_inf_0_0@2x.png similarity index 100% rename from Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithInfinityAndZeroInsetValue_0-inf-0-0@2x.png rename to Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithInfinityAndZeroInsetValue_0_inf_0_0@2x.png diff --git a/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithInfinityAndZeroInsetValue_0-inf-0-inf@2x.png b/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithInfinityAndZeroInsetValue_0_inf_0_inf@2x.png similarity index 100% rename from Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithInfinityAndZeroInsetValue_0-inf-0-inf@2x.png rename to Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithInfinityAndZeroInsetValue_0_inf_0_inf@2x.png diff --git a/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithInfinityAndZeroInsetValue_0-inf-inf-0@2x.png b/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithInfinityAndZeroInsetValue_0_inf_inf_0@2x.png similarity index 100% rename from Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithInfinityAndZeroInsetValue_0-inf-inf-0@2x.png rename to Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithInfinityAndZeroInsetValue_0_inf_inf_0@2x.png diff --git a/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithInfinityAndZeroInsetValue_0-inf-inf-inf@2x.png b/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithInfinityAndZeroInsetValue_0_inf_inf_inf@2x.png similarity index 100% rename from Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithInfinityAndZeroInsetValue_0-inf-inf-inf@2x.png rename to Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithInfinityAndZeroInsetValue_0_inf_inf_inf@2x.png diff --git a/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithInfinityAndZeroInsetValue_inf-0-0-0@2x.png b/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithInfinityAndZeroInsetValue_inf_0_0_0@2x.png similarity index 100% rename from Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithInfinityAndZeroInsetValue_inf-0-0-0@2x.png rename to Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithInfinityAndZeroInsetValue_inf_0_0_0@2x.png diff --git a/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithInfinityAndZeroInsetValue_inf-0-0-inf@2x.png b/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithInfinityAndZeroInsetValue_inf_0_0_inf@2x.png similarity index 100% rename from Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithInfinityAndZeroInsetValue_inf-0-0-inf@2x.png rename to Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithInfinityAndZeroInsetValue_inf_0_0_inf@2x.png diff --git a/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithInfinityAndZeroInsetValue_inf-0-inf-0@2x.png b/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithInfinityAndZeroInsetValue_inf_0_inf_0@2x.png similarity index 100% rename from Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithInfinityAndZeroInsetValue_inf-0-inf-0@2x.png rename to Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithInfinityAndZeroInsetValue_inf_0_inf_0@2x.png diff --git a/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithInfinityAndZeroInsetValue_inf-0-inf-inf@2x.png b/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithInfinityAndZeroInsetValue_inf_0_inf_inf@2x.png similarity index 100% rename from Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithInfinityAndZeroInsetValue_inf-0-inf-inf@2x.png rename to Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithInfinityAndZeroInsetValue_inf_0_inf_inf@2x.png diff --git a/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithInfinityAndZeroInsetValue_inf-inf-0-0@2x.png b/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithInfinityAndZeroInsetValue_inf_inf_0_0@2x.png similarity index 100% rename from Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithInfinityAndZeroInsetValue_inf-inf-0-0@2x.png rename to Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithInfinityAndZeroInsetValue_inf_inf_0_0@2x.png diff --git a/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithInfinityAndZeroInsetValue_inf-inf-0-inf@2x.png b/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithInfinityAndZeroInsetValue_inf_inf_0_inf@2x.png similarity index 100% rename from Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithInfinityAndZeroInsetValue_inf-inf-0-inf@2x.png rename to Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithInfinityAndZeroInsetValue_inf_inf_0_inf@2x.png diff --git a/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithInfinityAndZeroInsetValue_inf-inf-inf-0@2x.png b/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithInfinityAndZeroInsetValue_inf_inf_inf_0@2x.png similarity index 100% rename from Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithInfinityAndZeroInsetValue_inf-inf-inf-0@2x.png rename to Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithInfinityAndZeroInsetValue_inf_inf_inf_0@2x.png diff --git a/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithInfinityAndZeroInsetValue_inf-inf-inf-inf@2x.png b/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithInfinityAndZeroInsetValue_inf_inf_inf_inf@2x.png similarity index 100% rename from Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithInfinityAndZeroInsetValue_inf-inf-inf-inf@2x.png rename to Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithInfinityAndZeroInsetValue_inf_inf_inf_inf@2x.png diff --git a/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithVariableSize_10-10-10-10@2x.png b/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithVariableSize_10_10_10_10@2x.png similarity index 100% rename from Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithVariableSize_10-10-10-10@2x.png rename to Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithVariableSize_10_10_10_10@2x.png diff --git a/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithVariableSize_10-10-10-inf@2x.png b/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithVariableSize_10_10_10_inf@2x.png similarity index 100% rename from Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithVariableSize_10-10-10-inf@2x.png rename to Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithVariableSize_10_10_10_inf@2x.png diff --git a/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithVariableSize_10-10-inf-10@2x.png b/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithVariableSize_10_10_inf_10@2x.png similarity index 100% rename from Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithVariableSize_10-10-inf-10@2x.png rename to Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithVariableSize_10_10_inf_10@2x.png diff --git a/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithVariableSize_10-10-inf-inf@2x.png b/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithVariableSize_10_10_inf_inf@2x.png similarity index 100% rename from Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithVariableSize_10-10-inf-inf@2x.png rename to Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithVariableSize_10_10_inf_inf@2x.png diff --git a/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithVariableSize_10-inf-10-10@2x.png b/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithVariableSize_10_inf_10_10@2x.png similarity index 100% rename from Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithVariableSize_10-inf-10-10@2x.png rename to Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithVariableSize_10_inf_10_10@2x.png diff --git a/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithVariableSize_10-inf-10-inf@2x.png b/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithVariableSize_10_inf_10_inf@2x.png similarity index 100% rename from Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithVariableSize_10-inf-10-inf@2x.png rename to Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithVariableSize_10_inf_10_inf@2x.png diff --git a/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithVariableSize_10-inf-inf-10@2x.png b/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithVariableSize_10_inf_inf_10@2x.png similarity index 100% rename from Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithVariableSize_10-inf-inf-10@2x.png rename to Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithVariableSize_10_inf_inf_10@2x.png diff --git a/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithVariableSize_10-inf-inf-inf@2x.png b/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithVariableSize_10_inf_inf_inf@2x.png similarity index 100% rename from Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithVariableSize_10-inf-inf-inf@2x.png rename to Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithVariableSize_10_inf_inf_inf@2x.png diff --git a/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithVariableSize_inf-10-10-10@2x.png b/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithVariableSize_inf_10_10_10@2x.png similarity index 100% rename from Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithVariableSize_inf-10-10-10@2x.png rename to Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithVariableSize_inf_10_10_10@2x.png diff --git a/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithVariableSize_inf-10-10-inf@2x.png b/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithVariableSize_inf_10_10_inf@2x.png similarity index 100% rename from Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithVariableSize_inf-10-10-inf@2x.png rename to Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithVariableSize_inf_10_10_inf@2x.png diff --git a/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithVariableSize_inf-10-inf-10@2x.png b/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithVariableSize_inf_10_inf_10@2x.png similarity index 100% rename from Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithVariableSize_inf-10-inf-10@2x.png rename to Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithVariableSize_inf_10_inf_10@2x.png diff --git a/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithVariableSize_inf-10-inf-inf@2x.png b/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithVariableSize_inf_10_inf_inf@2x.png similarity index 100% rename from Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithVariableSize_inf-10-inf-inf@2x.png rename to Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithVariableSize_inf_10_inf_inf@2x.png diff --git a/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithVariableSize_inf-inf-10-10@2x.png b/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithVariableSize_inf_inf_10_10@2x.png similarity index 100% rename from Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithVariableSize_inf-inf-10-10@2x.png rename to Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithVariableSize_inf_inf_10_10@2x.png diff --git a/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithVariableSize_inf-inf-10-inf@2x.png b/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithVariableSize_inf_inf_10_inf@2x.png similarity index 100% rename from Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithVariableSize_inf-inf-10-inf@2x.png rename to Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithVariableSize_inf_inf_10_inf@2x.png diff --git a/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithVariableSize_inf-inf-inf-10@2x.png b/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithVariableSize_inf_inf_inf_10@2x.png similarity index 100% rename from Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithVariableSize_inf-inf-inf-10@2x.png rename to Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithVariableSize_inf_inf_inf_10@2x.png diff --git a/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithVariableSize_inf-inf-inf-inf@2x.png b/Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithVariableSize_inf_inf_inf_inf@2x.png similarity index 100% rename from Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithVariableSize_inf-inf-inf-inf@2x.png rename to Tests/ReferenceImages_64/ASInsetLayoutSpecSnapshotTests/testInsetsWithVariableSize_inf_inf_inf_inf@2x.png diff --git a/Tests/ReferenceImages_64/ASStackLayoutSpecSnapshotTests/testBaselineAlignmentWithSpaceBetween@2x.png b/Tests/ReferenceImages_64/ASStackLayoutSpecSnapshotTests/testBaselineAlignmentWithSpaceBetween@2x.png index 5174b92e..ce400667 100644 Binary files a/Tests/ReferenceImages_64/ASStackLayoutSpecSnapshotTests/testBaselineAlignmentWithSpaceBetween@2x.png and b/Tests/ReferenceImages_64/ASStackLayoutSpecSnapshotTests/testBaselineAlignmentWithSpaceBetween@2x.png differ diff --git a/Tests/ReferenceImages_64/ASStackLayoutSpecSnapshotTests/testBaselineAlignmentWithStretchedItem@2x.png b/Tests/ReferenceImages_64/ASStackLayoutSpecSnapshotTests/testBaselineAlignmentWithStretchedItem@2x.png index f3e20dbe..0d638be5 100644 Binary files a/Tests/ReferenceImages_64/ASStackLayoutSpecSnapshotTests/testBaselineAlignmentWithStretchedItem@2x.png and b/Tests/ReferenceImages_64/ASStackLayoutSpecSnapshotTests/testBaselineAlignmentWithStretchedItem@2x.png differ diff --git a/Tests/ReferenceImages_64/ASStackLayoutSpecSnapshotTests/testBaselineAlignment_baselineFirst@2x.png b/Tests/ReferenceImages_64/ASStackLayoutSpecSnapshotTests/testBaselineAlignment_baselineFirst@2x.png index e45ab35c..b2faf101 100644 Binary files a/Tests/ReferenceImages_64/ASStackLayoutSpecSnapshotTests/testBaselineAlignment_baselineFirst@2x.png and b/Tests/ReferenceImages_64/ASStackLayoutSpecSnapshotTests/testBaselineAlignment_baselineFirst@2x.png differ diff --git a/Tests/ReferenceImages_64/ASStackLayoutSpecSnapshotTests/testBaselineAlignment_baselineLast@2x.png b/Tests/ReferenceImages_64/ASStackLayoutSpecSnapshotTests/testBaselineAlignment_baselineLast@2x.png index 6cd49099..0db8e01c 100644 Binary files a/Tests/ReferenceImages_64/ASStackLayoutSpecSnapshotTests/testBaselineAlignment_baselineLast@2x.png and b/Tests/ReferenceImages_64/ASStackLayoutSpecSnapshotTests/testBaselineAlignment_baselineLast@2x.png differ diff --git a/Tests/ReferenceImages_64/ASStackLayoutSpecSnapshotTests/testNestedBaselineAlignments@2x.png b/Tests/ReferenceImages_64/ASStackLayoutSpecSnapshotTests/testNestedBaselineAlignments@2x.png index 67f32cb4..28e13ab8 100644 Binary files a/Tests/ReferenceImages_64/ASStackLayoutSpecSnapshotTests/testNestedBaselineAlignments@2x.png and b/Tests/ReferenceImages_64/ASStackLayoutSpecSnapshotTests/testNestedBaselineAlignments@2x.png differ diff --git a/Tests/ReferenceImages_iOS_10/ASTextNode2SnapshotTests/testShadowing_ASTextNode2@2x.png b/Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testShadowing_ASTextNode2@2x.png similarity index 100% rename from Tests/ReferenceImages_iOS_10/ASTextNode2SnapshotTests/testShadowing_ASTextNode2@2x.png rename to Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testShadowing_ASTextNode2@2x.png diff --git a/Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testTextContainerInsetHighlight_ASTextNode2@2x.png b/Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testTextContainerInsetHighlight_ASTextNode2@2x.png new file mode 100644 index 00000000..b29a5244 Binary files /dev/null and b/Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testTextContainerInsetHighlight_ASTextNode2@2x.png differ diff --git a/Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testTextContainerInsetIsIncludedWithSmallerConstrainedSize_ASTextNode2@2x.png b/Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testTextContainerInsetIsIncludedWithSmallerConstrainedSize_ASTextNode2@2x.png new file mode 100644 index 00000000..84ef8a2f Binary files /dev/null and b/Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testTextContainerInsetIsIncludedWithSmallerConstrainedSize_ASTextNode2@2x.png differ diff --git a/Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testTextContainerInset_ASTextNode2@2x.png b/Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testTextContainerInset_ASTextNode2@2x.png new file mode 100644 index 00000000..b19aa0dc Binary files /dev/null and b/Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testTextContainerInset_ASTextNode2@2x.png differ diff --git a/Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testTextTintColor_ASTextNode2@2x.png b/Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testTextTintColor_ASTextNode2@2x.png new file mode 100644 index 00000000..a733837d Binary files /dev/null and b/Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testTextTintColor_ASTextNode2@2x.png differ diff --git a/Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByCharWrapping_0Lines@2x.png b/Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByCharWrapping_0Lines@2x.png new file mode 100644 index 00000000..05cf0e97 Binary files /dev/null and b/Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByCharWrapping_0Lines@2x.png differ diff --git a/Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByCharWrapping_1Lines@2x.png b/Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByCharWrapping_1Lines@2x.png new file mode 100644 index 00000000..5ffec19d Binary files /dev/null and b/Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByCharWrapping_1Lines@2x.png differ diff --git a/Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByCharWrapping_2Lines@2x.png b/Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByCharWrapping_2Lines@2x.png new file mode 100644 index 00000000..147cb5b0 Binary files /dev/null and b/Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByCharWrapping_2Lines@2x.png differ diff --git a/Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByCharWrapping_3Lines@2x.png b/Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByCharWrapping_3Lines@2x.png new file mode 100644 index 00000000..f170241b Binary files /dev/null and b/Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByCharWrapping_3Lines@2x.png differ diff --git a/Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByTruncatingHead_0Lines@2x.png b/Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByTruncatingHead_0Lines@2x.png new file mode 100644 index 00000000..14705437 Binary files /dev/null and b/Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByTruncatingHead_0Lines@2x.png differ diff --git a/Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByTruncatingHead_1Lines@2x.png b/Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByTruncatingHead_1Lines@2x.png new file mode 100644 index 00000000..23601867 Binary files /dev/null and b/Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByTruncatingHead_1Lines@2x.png differ diff --git a/Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByTruncatingHead_2Lines@2x.png b/Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByTruncatingHead_2Lines@2x.png new file mode 100644 index 00000000..49be83e0 Binary files /dev/null and b/Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByTruncatingHead_2Lines@2x.png differ diff --git a/Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByTruncatingHead_3Lines@2x.png b/Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByTruncatingHead_3Lines@2x.png new file mode 100644 index 00000000..dc5689e9 Binary files /dev/null and b/Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByTruncatingHead_3Lines@2x.png differ diff --git a/Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByTruncatingMiddle_0Lines@2x.png b/Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByTruncatingMiddle_0Lines@2x.png new file mode 100644 index 00000000..2d0b073f Binary files /dev/null and b/Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByTruncatingMiddle_0Lines@2x.png differ diff --git a/Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByTruncatingMiddle_1Lines@2x.png b/Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByTruncatingMiddle_1Lines@2x.png new file mode 100644 index 00000000..5e90df20 Binary files /dev/null and b/Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByTruncatingMiddle_1Lines@2x.png differ diff --git a/Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByTruncatingMiddle_2Lines@2x.png b/Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByTruncatingMiddle_2Lines@2x.png new file mode 100644 index 00000000..90dca77b Binary files /dev/null and b/Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByTruncatingMiddle_2Lines@2x.png differ diff --git a/Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByTruncatingMiddle_3Lines@2x.png b/Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByTruncatingMiddle_3Lines@2x.png new file mode 100644 index 00000000..c3cdbe6d Binary files /dev/null and b/Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByTruncatingMiddle_3Lines@2x.png differ diff --git a/Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByTruncatingTail_0Lines@2x.png b/Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByTruncatingTail_0Lines@2x.png new file mode 100644 index 00000000..53937d1a Binary files /dev/null and b/Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByTruncatingTail_0Lines@2x.png differ diff --git a/Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByTruncatingTail_1Lines@2x.png b/Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByTruncatingTail_1Lines@2x.png new file mode 100644 index 00000000..93dfe04b Binary files /dev/null and b/Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByTruncatingTail_1Lines@2x.png differ diff --git a/Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByTruncatingTail_2Lines@2x.png b/Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByTruncatingTail_2Lines@2x.png new file mode 100644 index 00000000..1de1f4bc Binary files /dev/null and b/Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByTruncatingTail_2Lines@2x.png differ diff --git a/Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByTruncatingTail_3Lines@2x.png b/Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByTruncatingTail_3Lines@2x.png new file mode 100644 index 00000000..0b0624b0 Binary files /dev/null and b/Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByTruncatingTail_3Lines@2x.png differ diff --git a/Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByWordWrapping_0Lines@2x.png b/Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByWordWrapping_0Lines@2x.png new file mode 100644 index 00000000..beeeedb3 Binary files /dev/null and b/Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByWordWrapping_0Lines@2x.png differ diff --git a/Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByWordWrapping_1Lines@2x.png b/Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByWordWrapping_1Lines@2x.png new file mode 100644 index 00000000..137f9409 Binary files /dev/null and b/Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByWordWrapping_1Lines@2x.png differ diff --git a/Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByWordWrapping_2Lines@2x.png b/Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByWordWrapping_2Lines@2x.png new file mode 100644 index 00000000..4ce3efe6 Binary files /dev/null and b/Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByWordWrapping_2Lines@2x.png differ diff --git a/Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByWordWrapping_3Lines@2x.png b/Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByWordWrapping_3Lines@2x.png new file mode 100644 index 00000000..b1257ce4 Binary files /dev/null and b/Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByWordWrapping_3Lines@2x.png differ diff --git a/Tests/ReferenceImages_iOS_10/ASTextNode2SnapshotTests/testThatDefaultTruncationTokenAttributesAreInheritedFromTextWhenTruncated_ASTextNode2@2x.png b/Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testThatDefaultTruncationTokenAttributesAreInheritedFromTextWhenTruncated_ASTextNode2@2x.png similarity index 100% rename from Tests/ReferenceImages_iOS_10/ASTextNode2SnapshotTests/testThatDefaultTruncationTokenAttributesAreInheritedFromTextWhenTruncated_ASTextNode2@2x.png rename to Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testThatDefaultTruncationTokenAttributesAreInheritedFromTextWhenTruncated_ASTextNode2@2x.png diff --git a/Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testThatSlowPathTruncationWorks_ASTextNode2@2x.png b/Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testThatSlowPathTruncationWorks_ASTextNode2@2x.png new file mode 100644 index 00000000..12f4eade Binary files /dev/null and b/Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testThatSlowPathTruncationWorks_ASTextNode2@2x.png differ diff --git a/Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testTintColorHierarchyChange_green_tint_from_parent@2x.png b/Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testTintColorHierarchyChange_green_tint_from_parent@2x.png new file mode 100644 index 00000000..966591c5 Binary files /dev/null and b/Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testTintColorHierarchyChange_green_tint_from_parent@2x.png differ diff --git a/Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testTintColorHierarchyChange_red_tint_from_parent@2x.png b/Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testTintColorHierarchyChange_red_tint_from_parent@2x.png new file mode 100644 index 00000000..0d7f5ab4 Binary files /dev/null and b/Tests/ReferenceImages_64/ASTextNode2SnapshotTests/testTintColorHierarchyChange_red_tint_from_parent@2x.png differ diff --git a/Tests/ReferenceImages_iOS_10/ASTextNodeSnapshotTests/testTextContainerInset2@2x.png b/Tests/ReferenceImages_64/ASTextNodeSnapshotTests/testTextContainerInset2@2x.png similarity index 100% rename from Tests/ReferenceImages_iOS_10/ASTextNodeSnapshotTests/testTextContainerInset2@2x.png rename to Tests/ReferenceImages_64/ASTextNodeSnapshotTests/testTextContainerInset2@2x.png diff --git a/Tests/ReferenceImages_64/ASTextNodeSnapshotTests/testTextContainerInset@2x.png b/Tests/ReferenceImages_64/ASTextNodeSnapshotTests/testTextContainerInset@2x.png index 7e6cac14..3ef2b4b1 100644 Binary files a/Tests/ReferenceImages_64/ASTextNodeSnapshotTests/testTextContainerInset@2x.png and b/Tests/ReferenceImages_64/ASTextNodeSnapshotTests/testTextContainerInset@2x.png differ diff --git a/Tests/ReferenceImages_64/ASTextNodeSnapshotTests/testTextContainerInsetHighlight@2x.png b/Tests/ReferenceImages_64/ASTextNodeSnapshotTests/testTextContainerInsetHighlight@2x.png index 4a2fa334..8fcf950b 100644 Binary files a/Tests/ReferenceImages_64/ASTextNodeSnapshotTests/testTextContainerInsetHighlight@2x.png and b/Tests/ReferenceImages_64/ASTextNodeSnapshotTests/testTextContainerInsetHighlight@2x.png differ diff --git a/Tests/ReferenceImages_64/ASTextNodeSnapshotTests/testTextContainerInsetIsIncludedWithSmallerConstrainedSize@2x.png b/Tests/ReferenceImages_64/ASTextNodeSnapshotTests/testTextContainerInsetIsIncludedWithSmallerConstrainedSize@2x.png index 5e2062b8..fc14d5c5 100644 Binary files a/Tests/ReferenceImages_64/ASTextNodeSnapshotTests/testTextContainerInsetIsIncludedWithSmallerConstrainedSize@2x.png and b/Tests/ReferenceImages_64/ASTextNodeSnapshotTests/testTextContainerInsetIsIncludedWithSmallerConstrainedSize@2x.png differ diff --git a/Tests/ReferenceImages_64/ASTextNodeSnapshotTests/testThatFastPathTruncationWorks@2x.png b/Tests/ReferenceImages_64/ASTextNodeSnapshotTests/testThatFastPathTruncationWorks@2x.png index d9f01fce..37b5444e 100644 Binary files a/Tests/ReferenceImages_64/ASTextNodeSnapshotTests/testThatFastPathTruncationWorks@2x.png and b/Tests/ReferenceImages_64/ASTextNodeSnapshotTests/testThatFastPathTruncationWorks@2x.png differ diff --git a/Tests/ReferenceImages_64/ASTextNodeSnapshotTests/testThatSlowPathTruncationWorks@2x.png b/Tests/ReferenceImages_64/ASTextNodeSnapshotTests/testThatSlowPathTruncationWorks@2x.png index 4d68f598..062724a0 100644 Binary files a/Tests/ReferenceImages_64/ASTextNodeSnapshotTests/testThatSlowPathTruncationWorks@2x.png and b/Tests/ReferenceImages_64/ASTextNodeSnapshotTests/testThatSlowPathTruncationWorks@2x.png differ diff --git a/Tests/ReferenceImages_iOS_10/ASTextNodeSnapshotTests/testThatTruncationTokenAttributesPrecedeThoseInheritedFromTextWhenTruncateTailMode@2x.png b/Tests/ReferenceImages_64/ASTextNodeSnapshotTests/testThatTruncationTokenAttributesPrecedeThoseInheritedFromTextWhenTruncateTailMode@2x.png similarity index 100% rename from Tests/ReferenceImages_iOS_10/ASTextNodeSnapshotTests/testThatTruncationTokenAttributesPrecedeThoseInheritedFromTextWhenTruncateTailMode@2x.png rename to Tests/ReferenceImages_64/ASTextNodeSnapshotTests/testThatTruncationTokenAttributesPrecedeThoseInheritedFromTextWhenTruncateTailMode@2x.png diff --git a/Tests/ReferenceImages_64/ASTextNodeSnapshotTests/testTintColorHierarchyChange_green_tint_from_parent@2x.png b/Tests/ReferenceImages_64/ASTextNodeSnapshotTests/testTintColorHierarchyChange_green_tint_from_parent@2x.png new file mode 100644 index 00000000..cecd2aea Binary files /dev/null and b/Tests/ReferenceImages_64/ASTextNodeSnapshotTests/testTintColorHierarchyChange_green_tint_from_parent@2x.png differ diff --git a/Tests/ReferenceImages_64/ASTextNodeSnapshotTests/testTintColorHierarchyChange_red_tint_from_parent@2x.png b/Tests/ReferenceImages_64/ASTextNodeSnapshotTests/testTintColorHierarchyChange_red_tint_from_parent@2x.png new file mode 100644 index 00000000..34239d98 Binary files /dev/null and b/Tests/ReferenceImages_64/ASTextNodeSnapshotTests/testTintColorHierarchyChange_red_tint_from_parent@2x.png differ diff --git a/Tests/ReferenceImages_64/ASTextNodeSnapshotTests/testUIGraphicsRendererDrawingExperiment@2x.png b/Tests/ReferenceImages_64/ASTextNodeSnapshotTests/testUIGraphicsRendererDrawingExperiment@2x.png new file mode 100644 index 00000000..3ef2b4b1 Binary files /dev/null and b/Tests/ReferenceImages_64/ASTextNodeSnapshotTests/testUIGraphicsRendererDrawingExperiment@2x.png differ diff --git a/Tests/ReferenceImages_iOS_10/ASTextNodeSnapshotTests/testUserInterfaceStyleSnapshotTestingTintColor_user_interface_style_dark@2x.png b/Tests/ReferenceImages_64/ASTextNodeSnapshotTests/testUserInterfaceStyleSnapshotTestingTintColor_user_interface_style_dark@2x.png similarity index 100% rename from Tests/ReferenceImages_iOS_10/ASTextNodeSnapshotTests/testUserInterfaceStyleSnapshotTestingTintColor_user_interface_style_dark@2x.png rename to Tests/ReferenceImages_64/ASTextNodeSnapshotTests/testUserInterfaceStyleSnapshotTestingTintColor_user_interface_style_dark@2x.png diff --git a/Tests/ReferenceImages_iOS_10/ASTextNodeSnapshotTests/testUserInterfaceStyleSnapshotTestingTintColor_user_interface_style_dark@3x.png b/Tests/ReferenceImages_64/ASTextNodeSnapshotTests/testUserInterfaceStyleSnapshotTestingTintColor_user_interface_style_dark@3x.png similarity index 100% rename from Tests/ReferenceImages_iOS_10/ASTextNodeSnapshotTests/testUserInterfaceStyleSnapshotTestingTintColor_user_interface_style_dark@3x.png rename to Tests/ReferenceImages_64/ASTextNodeSnapshotTests/testUserInterfaceStyleSnapshotTestingTintColor_user_interface_style_dark@3x.png diff --git a/Tests/ReferenceImages_iOS_10/ASTextNodeSnapshotTests/testUserInterfaceStyleSnapshotTestingTintColor_user_interface_style_light@2x.png b/Tests/ReferenceImages_64/ASTextNodeSnapshotTests/testUserInterfaceStyleSnapshotTestingTintColor_user_interface_style_light@2x.png similarity index 100% rename from Tests/ReferenceImages_iOS_10/ASTextNodeSnapshotTests/testUserInterfaceStyleSnapshotTestingTintColor_user_interface_style_light@2x.png rename to Tests/ReferenceImages_64/ASTextNodeSnapshotTests/testUserInterfaceStyleSnapshotTestingTintColor_user_interface_style_light@2x.png diff --git a/Tests/ReferenceImages_iOS_10/ASTextNodeSnapshotTests/testUserInterfaceStyleSnapshotTestingTintColor_user_interface_style_light@3x.png b/Tests/ReferenceImages_64/ASTextNodeSnapshotTests/testUserInterfaceStyleSnapshotTestingTintColor_user_interface_style_light@3x.png similarity index 100% rename from Tests/ReferenceImages_iOS_10/ASTextNodeSnapshotTests/testUserInterfaceStyleSnapshotTestingTintColor_user_interface_style_light@3x.png rename to Tests/ReferenceImages_64/ASTextNodeSnapshotTests/testUserInterfaceStyleSnapshotTestingTintColor_user_interface_style_light@3x.png diff --git a/Tests/ReferenceImages_iOS_10/ASTextNodeSnapshotTests/testUserInterfaceStyleSnapshotTesting_user_interface_style_dark@2x.png b/Tests/ReferenceImages_64/ASTextNodeSnapshotTests/testUserInterfaceStyleSnapshotTesting_user_interface_style_dark@2x.png similarity index 100% rename from Tests/ReferenceImages_iOS_10/ASTextNodeSnapshotTests/testUserInterfaceStyleSnapshotTesting_user_interface_style_dark@2x.png rename to Tests/ReferenceImages_64/ASTextNodeSnapshotTests/testUserInterfaceStyleSnapshotTesting_user_interface_style_dark@2x.png diff --git a/Tests/ReferenceImages_iOS_10/ASTextNodeSnapshotTests/testUserInterfaceStyleSnapshotTesting_user_interface_style_dark@3x.png b/Tests/ReferenceImages_64/ASTextNodeSnapshotTests/testUserInterfaceStyleSnapshotTesting_user_interface_style_dark@3x.png similarity index 100% rename from Tests/ReferenceImages_iOS_10/ASTextNodeSnapshotTests/testUserInterfaceStyleSnapshotTesting_user_interface_style_dark@3x.png rename to Tests/ReferenceImages_64/ASTextNodeSnapshotTests/testUserInterfaceStyleSnapshotTesting_user_interface_style_dark@3x.png diff --git a/Tests/ReferenceImages_iOS_10/ASTextNodeSnapshotTests/testUserInterfaceStyleSnapshotTesting_user_interface_style_light@2x.png b/Tests/ReferenceImages_64/ASTextNodeSnapshotTests/testUserInterfaceStyleSnapshotTesting_user_interface_style_light@2x.png similarity index 100% rename from Tests/ReferenceImages_iOS_10/ASTextNodeSnapshotTests/testUserInterfaceStyleSnapshotTesting_user_interface_style_light@2x.png rename to Tests/ReferenceImages_64/ASTextNodeSnapshotTests/testUserInterfaceStyleSnapshotTesting_user_interface_style_light@2x.png diff --git a/Tests/ReferenceImages_iOS_10/ASTextNodeSnapshotTests/testUserInterfaceStyleSnapshotTesting_user_interface_style_light@3x.png b/Tests/ReferenceImages_64/ASTextNodeSnapshotTests/testUserInterfaceStyleSnapshotTesting_user_interface_style_light@3x.png similarity index 100% rename from Tests/ReferenceImages_iOS_10/ASTextNodeSnapshotTests/testUserInterfaceStyleSnapshotTesting_user_interface_style_light@3x.png rename to Tests/ReferenceImages_64/ASTextNodeSnapshotTests/testUserInterfaceStyleSnapshotTesting_user_interface_style_light@3x.png diff --git a/Tests/ReferenceImages_64/UIImage_ASConvenienceTests/testRoundedAllCorners@2x.png b/Tests/ReferenceImages_64/UIImage_ASConvenienceTests/testRoundedAllCorners@2x.png new file mode 100644 index 00000000..54bb3fda Binary files /dev/null and b/Tests/ReferenceImages_64/UIImage_ASConvenienceTests/testRoundedAllCorners@2x.png differ diff --git a/Tests/ReferenceImages_64/UIImage_ASConvenienceTests/testRoundedBorderless@2x.png b/Tests/ReferenceImages_64/UIImage_ASConvenienceTests/testRoundedBorderless@2x.png new file mode 100644 index 00000000..bda0688f Binary files /dev/null and b/Tests/ReferenceImages_64/UIImage_ASConvenienceTests/testRoundedBorderless@2x.png differ diff --git a/Tests/ReferenceImages_64/UIImage_ASConvenienceTests/testRoundedPartial@2x.png b/Tests/ReferenceImages_64/UIImage_ASConvenienceTests/testRoundedPartial@2x.png new file mode 100644 index 00000000..d728ffea Binary files /dev/null and b/Tests/ReferenceImages_64/UIImage_ASConvenienceTests/testRoundedPartial@2x.png differ diff --git a/Tests/ReferenceImages_iOS_10/ASDisplayNodeSnapshotTests/testPrecompositedCornerRounding_15@2x.png b/Tests/ReferenceImages_iOS_10/ASDisplayNodeSnapshotTests/testPrecompositedCornerRounding_15@2x.png deleted file mode 100644 index ba850b21..00000000 Binary files a/Tests/ReferenceImages_iOS_10/ASDisplayNodeSnapshotTests/testPrecompositedCornerRounding_15@2x.png and /dev/null differ diff --git a/Tests/ReferenceImages_iOS_10/ASDisplayNodeSnapshotTests/testPrecompositedCornerRounding_1@2x.png b/Tests/ReferenceImages_iOS_10/ASDisplayNodeSnapshotTests/testPrecompositedCornerRounding_1@2x.png deleted file mode 100644 index 0b4a6b42..00000000 Binary files a/Tests/ReferenceImages_iOS_10/ASDisplayNodeSnapshotTests/testPrecompositedCornerRounding_1@2x.png and /dev/null differ diff --git a/Tests/ReferenceImages_iOS_10/ASDisplayNodeSnapshotTests/testPrecompositedCornerRounding_3@2x.png b/Tests/ReferenceImages_iOS_10/ASDisplayNodeSnapshotTests/testPrecompositedCornerRounding_3@2x.png deleted file mode 100644 index 4282e29d..00000000 Binary files a/Tests/ReferenceImages_iOS_10/ASDisplayNodeSnapshotTests/testPrecompositedCornerRounding_3@2x.png and /dev/null differ diff --git a/Tests/ReferenceImages_iOS_10/ASDisplayNodeSnapshotTests/testPrecompositedCornerRounding_7@2x.png b/Tests/ReferenceImages_iOS_10/ASDisplayNodeSnapshotTests/testPrecompositedCornerRounding_7@2x.png deleted file mode 100644 index 46ae9327..00000000 Binary files a/Tests/ReferenceImages_iOS_10/ASDisplayNodeSnapshotTests/testPrecompositedCornerRounding_7@2x.png and /dev/null differ diff --git a/Tests/ReferenceImages_iOS_10/ASImageNodeSnapshotTests/testForcedScaling_first@2x.png b/Tests/ReferenceImages_iOS_10/ASImageNodeSnapshotTests/testForcedScaling_first@2x.png deleted file mode 100644 index 03963aea..00000000 Binary files a/Tests/ReferenceImages_iOS_10/ASImageNodeSnapshotTests/testForcedScaling_first@2x.png and /dev/null differ diff --git a/Tests/ReferenceImages_iOS_10/ASImageNodeSnapshotTests/testForcedScaling_second@2x.png b/Tests/ReferenceImages_iOS_10/ASImageNodeSnapshotTests/testForcedScaling_second@2x.png deleted file mode 100644 index 3e2f7232..00000000 Binary files a/Tests/ReferenceImages_iOS_10/ASImageNodeSnapshotTests/testForcedScaling_second@2x.png and /dev/null differ diff --git a/Tests/ReferenceImages_iOS_10/ASImageNodeSnapshotTests/testRenderLogoSquare@2x.png b/Tests/ReferenceImages_iOS_10/ASImageNodeSnapshotTests/testRenderLogoSquare@2x.png deleted file mode 100644 index 03963aea..00000000 Binary files a/Tests/ReferenceImages_iOS_10/ASImageNodeSnapshotTests/testRenderLogoSquare@2x.png and /dev/null differ diff --git a/Tests/ReferenceImages_iOS_10/ASImageNodeSnapshotTests/testRoundedCornerBlock@2x.png b/Tests/ReferenceImages_iOS_10/ASImageNodeSnapshotTests/testRoundedCornerBlock@2x.png deleted file mode 100644 index bccba69c..00000000 Binary files a/Tests/ReferenceImages_iOS_10/ASImageNodeSnapshotTests/testRoundedCornerBlock@2x.png and /dev/null differ diff --git a/Tests/ReferenceImages_iOS_10/ASImageNodeSnapshotTests/testUIGraphicsRendererDrawingExperiment@2x.png b/Tests/ReferenceImages_iOS_10/ASImageNodeSnapshotTests/testUIGraphicsRendererDrawingExperiment@2x.png deleted file mode 100644 index 896dc7ab..00000000 Binary files a/Tests/ReferenceImages_iOS_10/ASImageNodeSnapshotTests/testUIGraphicsRendererDrawingExperiment@2x.png and /dev/null differ diff --git a/Tests/ReferenceImages_iOS_10/ASStackLayoutSpecSnapshotTests/testBaselineAlignmentWithSpaceBetween@2x.png b/Tests/ReferenceImages_iOS_10/ASStackLayoutSpecSnapshotTests/testBaselineAlignmentWithSpaceBetween@2x.png deleted file mode 100644 index 259778c6..00000000 Binary files a/Tests/ReferenceImages_iOS_10/ASStackLayoutSpecSnapshotTests/testBaselineAlignmentWithSpaceBetween@2x.png and /dev/null differ diff --git a/Tests/ReferenceImages_iOS_10/ASStackLayoutSpecSnapshotTests/testBaselineAlignmentWithStretchedItem@2x.png b/Tests/ReferenceImages_iOS_10/ASStackLayoutSpecSnapshotTests/testBaselineAlignmentWithStretchedItem@2x.png deleted file mode 100644 index 9e8286a8..00000000 Binary files a/Tests/ReferenceImages_iOS_10/ASStackLayoutSpecSnapshotTests/testBaselineAlignmentWithStretchedItem@2x.png and /dev/null differ diff --git a/Tests/ReferenceImages_iOS_10/ASStackLayoutSpecSnapshotTests/testBaselineAlignment_baselineFirst@2x.png b/Tests/ReferenceImages_iOS_10/ASStackLayoutSpecSnapshotTests/testBaselineAlignment_baselineFirst@2x.png deleted file mode 100644 index 7f4045ee..00000000 Binary files a/Tests/ReferenceImages_iOS_10/ASStackLayoutSpecSnapshotTests/testBaselineAlignment_baselineFirst@2x.png and /dev/null differ diff --git a/Tests/ReferenceImages_iOS_10/ASStackLayoutSpecSnapshotTests/testBaselineAlignment_baselineLast@2x.png b/Tests/ReferenceImages_iOS_10/ASStackLayoutSpecSnapshotTests/testBaselineAlignment_baselineLast@2x.png deleted file mode 100644 index c81f3e9c..00000000 Binary files a/Tests/ReferenceImages_iOS_10/ASStackLayoutSpecSnapshotTests/testBaselineAlignment_baselineLast@2x.png and /dev/null differ diff --git a/Tests/ReferenceImages_iOS_10/ASStackLayoutSpecSnapshotTests/testNestedBaselineAlignments@2x.png b/Tests/ReferenceImages_iOS_10/ASStackLayoutSpecSnapshotTests/testNestedBaselineAlignments@2x.png deleted file mode 100644 index 679b98a5..00000000 Binary files a/Tests/ReferenceImages_iOS_10/ASStackLayoutSpecSnapshotTests/testNestedBaselineAlignments@2x.png and /dev/null differ diff --git a/Tests/ReferenceImages_iOS_10/ASTextNode2SnapshotTests/testTextContainerInsetHighlight_ASTextNode2@2x.png b/Tests/ReferenceImages_iOS_10/ASTextNode2SnapshotTests/testTextContainerInsetHighlight_ASTextNode2@2x.png deleted file mode 100644 index 1bbdbbfd..00000000 Binary files a/Tests/ReferenceImages_iOS_10/ASTextNode2SnapshotTests/testTextContainerInsetHighlight_ASTextNode2@2x.png and /dev/null differ diff --git a/Tests/ReferenceImages_iOS_10/ASTextNode2SnapshotTests/testTextContainerInsetIsIncludedWithSmallerConstrainedSize_ASTextNode2@2x.png b/Tests/ReferenceImages_iOS_10/ASTextNode2SnapshotTests/testTextContainerInsetIsIncludedWithSmallerConstrainedSize_ASTextNode2@2x.png deleted file mode 100644 index dd3b0ccf..00000000 Binary files a/Tests/ReferenceImages_iOS_10/ASTextNode2SnapshotTests/testTextContainerInsetIsIncludedWithSmallerConstrainedSize_ASTextNode2@2x.png and /dev/null differ diff --git a/Tests/ReferenceImages_iOS_10/ASTextNode2SnapshotTests/testTextContainerInset_ASTextNode2@2x.png b/Tests/ReferenceImages_iOS_10/ASTextNode2SnapshotTests/testTextContainerInset_ASTextNode2@2x.png deleted file mode 100644 index d66bb3bc..00000000 Binary files a/Tests/ReferenceImages_iOS_10/ASTextNode2SnapshotTests/testTextContainerInset_ASTextNode2@2x.png and /dev/null differ diff --git a/Tests/ReferenceImages_iOS_10/ASTextNode2SnapshotTests/testTextTintColor_ASTextNode2@2x.png b/Tests/ReferenceImages_iOS_10/ASTextNode2SnapshotTests/testTextTintColor_ASTextNode2@2x.png deleted file mode 100644 index fc3bb798..00000000 Binary files a/Tests/ReferenceImages_iOS_10/ASTextNode2SnapshotTests/testTextTintColor_ASTextNode2@2x.png and /dev/null differ diff --git a/Tests/ReferenceImages_iOS_10/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByCharWrapping_0Lines@2x.png b/Tests/ReferenceImages_iOS_10/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByCharWrapping_0Lines@2x.png deleted file mode 100644 index e080782f..00000000 Binary files a/Tests/ReferenceImages_iOS_10/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByCharWrapping_0Lines@2x.png and /dev/null differ diff --git a/Tests/ReferenceImages_iOS_10/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByCharWrapping_1Lines@2x.png b/Tests/ReferenceImages_iOS_10/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByCharWrapping_1Lines@2x.png deleted file mode 100644 index 7139ae65..00000000 Binary files a/Tests/ReferenceImages_iOS_10/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByCharWrapping_1Lines@2x.png and /dev/null differ diff --git a/Tests/ReferenceImages_iOS_10/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByCharWrapping_2Lines@2x.png b/Tests/ReferenceImages_iOS_10/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByCharWrapping_2Lines@2x.png deleted file mode 100644 index 7cab68aa..00000000 Binary files a/Tests/ReferenceImages_iOS_10/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByCharWrapping_2Lines@2x.png and /dev/null differ diff --git a/Tests/ReferenceImages_iOS_10/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByCharWrapping_3Lines@2x.png b/Tests/ReferenceImages_iOS_10/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByCharWrapping_3Lines@2x.png deleted file mode 100644 index 79c7db1e..00000000 Binary files a/Tests/ReferenceImages_iOS_10/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByCharWrapping_3Lines@2x.png and /dev/null differ diff --git a/Tests/ReferenceImages_iOS_10/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByTruncatingHead_0Lines@2x.png b/Tests/ReferenceImages_iOS_10/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByTruncatingHead_0Lines@2x.png deleted file mode 100644 index 4293eb9d..00000000 Binary files a/Tests/ReferenceImages_iOS_10/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByTruncatingHead_0Lines@2x.png and /dev/null differ diff --git a/Tests/ReferenceImages_iOS_10/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByTruncatingHead_1Lines@2x.png b/Tests/ReferenceImages_iOS_10/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByTruncatingHead_1Lines@2x.png deleted file mode 100644 index 1422cb5b..00000000 Binary files a/Tests/ReferenceImages_iOS_10/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByTruncatingHead_1Lines@2x.png and /dev/null differ diff --git a/Tests/ReferenceImages_iOS_10/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByTruncatingHead_2Lines@2x.png b/Tests/ReferenceImages_iOS_10/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByTruncatingHead_2Lines@2x.png deleted file mode 100644 index e9472fc1..00000000 Binary files a/Tests/ReferenceImages_iOS_10/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByTruncatingHead_2Lines@2x.png and /dev/null differ diff --git a/Tests/ReferenceImages_iOS_10/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByTruncatingHead_3Lines@2x.png b/Tests/ReferenceImages_iOS_10/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByTruncatingHead_3Lines@2x.png deleted file mode 100644 index 85f8b968..00000000 Binary files a/Tests/ReferenceImages_iOS_10/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByTruncatingHead_3Lines@2x.png and /dev/null differ diff --git a/Tests/ReferenceImages_iOS_10/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByTruncatingMiddle_0Lines@2x.png b/Tests/ReferenceImages_iOS_10/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByTruncatingMiddle_0Lines@2x.png deleted file mode 100644 index c1a4f2b4..00000000 Binary files a/Tests/ReferenceImages_iOS_10/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByTruncatingMiddle_0Lines@2x.png and /dev/null differ diff --git a/Tests/ReferenceImages_iOS_10/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByTruncatingMiddle_1Lines@2x.png b/Tests/ReferenceImages_iOS_10/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByTruncatingMiddle_1Lines@2x.png deleted file mode 100644 index d534022d..00000000 Binary files a/Tests/ReferenceImages_iOS_10/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByTruncatingMiddle_1Lines@2x.png and /dev/null differ diff --git a/Tests/ReferenceImages_iOS_10/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByTruncatingMiddle_2Lines@2x.png b/Tests/ReferenceImages_iOS_10/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByTruncatingMiddle_2Lines@2x.png deleted file mode 100644 index c52a7e6d..00000000 Binary files a/Tests/ReferenceImages_iOS_10/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByTruncatingMiddle_2Lines@2x.png and /dev/null differ diff --git a/Tests/ReferenceImages_iOS_10/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByTruncatingMiddle_3Lines@2x.png b/Tests/ReferenceImages_iOS_10/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByTruncatingMiddle_3Lines@2x.png deleted file mode 100644 index e5cde0ab..00000000 Binary files a/Tests/ReferenceImages_iOS_10/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByTruncatingMiddle_3Lines@2x.png and /dev/null differ diff --git a/Tests/ReferenceImages_iOS_10/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByTruncatingTail_0Lines@2x.png b/Tests/ReferenceImages_iOS_10/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByTruncatingTail_0Lines@2x.png deleted file mode 100644 index 387d0b8d..00000000 Binary files a/Tests/ReferenceImages_iOS_10/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByTruncatingTail_0Lines@2x.png and /dev/null differ diff --git a/Tests/ReferenceImages_iOS_10/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByTruncatingTail_1Lines@2x.png b/Tests/ReferenceImages_iOS_10/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByTruncatingTail_1Lines@2x.png deleted file mode 100644 index fd36b638..00000000 Binary files a/Tests/ReferenceImages_iOS_10/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByTruncatingTail_1Lines@2x.png and /dev/null differ diff --git a/Tests/ReferenceImages_iOS_10/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByTruncatingTail_2Lines@2x.png b/Tests/ReferenceImages_iOS_10/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByTruncatingTail_2Lines@2x.png deleted file mode 100644 index ebfd1091..00000000 Binary files a/Tests/ReferenceImages_iOS_10/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByTruncatingTail_2Lines@2x.png and /dev/null differ diff --git a/Tests/ReferenceImages_iOS_10/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByTruncatingTail_3Lines@2x.png b/Tests/ReferenceImages_iOS_10/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByTruncatingTail_3Lines@2x.png deleted file mode 100644 index 29e13b8d..00000000 Binary files a/Tests/ReferenceImages_iOS_10/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByTruncatingTail_3Lines@2x.png and /dev/null differ diff --git a/Tests/ReferenceImages_iOS_10/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByWordWrapping_0Lines@2x.png b/Tests/ReferenceImages_iOS_10/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByWordWrapping_0Lines@2x.png deleted file mode 100644 index 6202ed98..00000000 Binary files a/Tests/ReferenceImages_iOS_10/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByWordWrapping_0Lines@2x.png and /dev/null differ diff --git a/Tests/ReferenceImages_iOS_10/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByWordWrapping_1Lines@2x.png b/Tests/ReferenceImages_iOS_10/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByWordWrapping_1Lines@2x.png deleted file mode 100644 index 6316fb81..00000000 Binary files a/Tests/ReferenceImages_iOS_10/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByWordWrapping_1Lines@2x.png and /dev/null differ diff --git a/Tests/ReferenceImages_iOS_10/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByWordWrapping_2Lines@2x.png b/Tests/ReferenceImages_iOS_10/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByWordWrapping_2Lines@2x.png deleted file mode 100644 index ffe6f9c3..00000000 Binary files a/Tests/ReferenceImages_iOS_10/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByWordWrapping_2Lines@2x.png and /dev/null differ diff --git a/Tests/ReferenceImages_iOS_10/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByWordWrapping_3Lines@2x.png b/Tests/ReferenceImages_iOS_10/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByWordWrapping_3Lines@2x.png deleted file mode 100644 index f9248c2e..00000000 Binary files a/Tests/ReferenceImages_iOS_10/ASTextNode2SnapshotTests/testTextTruncationModes_ASTextNode2_NSLineBreakByWordWrapping_3Lines@2x.png and /dev/null differ diff --git a/Tests/ReferenceImages_iOS_10/ASTextNode2SnapshotTests/testThatSlowPathTruncationWorks_ASTextNode2@2x.png b/Tests/ReferenceImages_iOS_10/ASTextNode2SnapshotTests/testThatSlowPathTruncationWorks_ASTextNode2@2x.png deleted file mode 100644 index b8123efd..00000000 Binary files a/Tests/ReferenceImages_iOS_10/ASTextNode2SnapshotTests/testThatSlowPathTruncationWorks_ASTextNode2@2x.png and /dev/null differ diff --git a/Tests/ReferenceImages_iOS_10/ASTextNodeSnapshotTests/testFontPointSizeScaling@2x.png b/Tests/ReferenceImages_iOS_10/ASTextNodeSnapshotTests/testFontPointSizeScaling@2x.png deleted file mode 100644 index 111bd500..00000000 Binary files a/Tests/ReferenceImages_iOS_10/ASTextNodeSnapshotTests/testFontPointSizeScaling@2x.png and /dev/null differ diff --git a/Tests/ReferenceImages_iOS_10/ASTextNodeSnapshotTests/testShadowing@2x.png b/Tests/ReferenceImages_iOS_10/ASTextNodeSnapshotTests/testShadowing@2x.png deleted file mode 100644 index edb68c14..00000000 Binary files a/Tests/ReferenceImages_iOS_10/ASTextNodeSnapshotTests/testShadowing@2x.png and /dev/null differ diff --git a/Tests/ReferenceImages_iOS_10/ASTextNodeSnapshotTests/testTextContainerInset@2x.png b/Tests/ReferenceImages_iOS_10/ASTextNodeSnapshotTests/testTextContainerInset@2x.png deleted file mode 100644 index d66bb3bc..00000000 Binary files a/Tests/ReferenceImages_iOS_10/ASTextNodeSnapshotTests/testTextContainerInset@2x.png and /dev/null differ diff --git a/Tests/ReferenceImages_iOS_10/ASTextNodeSnapshotTests/testTextContainerInsetHighlight@2x.png b/Tests/ReferenceImages_iOS_10/ASTextNodeSnapshotTests/testTextContainerInsetHighlight@2x.png deleted file mode 100644 index 01234cff..00000000 Binary files a/Tests/ReferenceImages_iOS_10/ASTextNodeSnapshotTests/testTextContainerInsetHighlight@2x.png and /dev/null differ diff --git a/Tests/ReferenceImages_iOS_10/ASTextNodeSnapshotTests/testTextContainerInsetIsIncludedWithSmallerConstrainedSize@2x.png b/Tests/ReferenceImages_iOS_10/ASTextNodeSnapshotTests/testTextContainerInsetIsIncludedWithSmallerConstrainedSize@2x.png deleted file mode 100644 index 65c801d4..00000000 Binary files a/Tests/ReferenceImages_iOS_10/ASTextNodeSnapshotTests/testTextContainerInsetIsIncludedWithSmallerConstrainedSize@2x.png and /dev/null differ diff --git a/Tests/ReferenceImages_iOS_10/ASTextNodeSnapshotTests/testThatFastPathTruncationWorks@2x.png b/Tests/ReferenceImages_iOS_10/ASTextNodeSnapshotTests/testThatFastPathTruncationWorks@2x.png deleted file mode 100644 index 37b5444e..00000000 Binary files a/Tests/ReferenceImages_iOS_10/ASTextNodeSnapshotTests/testThatFastPathTruncationWorks@2x.png and /dev/null differ diff --git a/Tests/ReferenceImages_iOS_10/ASTextNodeSnapshotTests/testThatSlowPathTruncationWorks@2x.png b/Tests/ReferenceImages_iOS_10/ASTextNodeSnapshotTests/testThatSlowPathTruncationWorks@2x.png deleted file mode 100644 index 18de8b27..00000000 Binary files a/Tests/ReferenceImages_iOS_10/ASTextNodeSnapshotTests/testThatSlowPathTruncationWorks@2x.png and /dev/null differ diff --git a/Tests/ReferenceImages_iOS_10/ASTextNodeSnapshotTests/testUIGraphicsRendererDrawingExperiment@2x.png b/Tests/ReferenceImages_iOS_10/ASTextNodeSnapshotTests/testUIGraphicsRendererDrawingExperiment@2x.png deleted file mode 100644 index d66bb3bc..00000000 Binary files a/Tests/ReferenceImages_iOS_10/ASTextNodeSnapshotTests/testUIGraphicsRendererDrawingExperiment@2x.png and /dev/null differ diff --git a/Tests/UIImage+ASConvenienceTests.mm b/Tests/UIImage+ASConvenienceTests.mm new file mode 100644 index 00000000..3289a280 --- /dev/null +++ b/Tests/UIImage+ASConvenienceTests.mm @@ -0,0 +1,68 @@ +// +// UIImage+ASConvenienceTests.m +// AsyncDisplayKitTests +// +// Created by Vladimir Solomenchuk on 5/22/20. +// Copyright © 2020 Pinterest. All rights reserved. +// + +#import +#import +#import "ASSnapshotTestCase.h" + +@interface UIImage_ASConvenienceTests : ASSnapshotTestCase + +@end + +@implementation UIImage_ASConvenienceTests +- (UIImage*) imageWithColor:(UIColor *)color { + UIGraphicsBeginImageContext(CGSizeMake(100, 100)); + [color setFill]; + UIRectFill(CGRectMake(0, 0, 100, 100)); + UIImage *result = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + return result; +} + +- (void)testRoundedPartial { + ASImageNode *node = [[ASImageNode alloc] init]; + UIImage *image = [UIImage as_resizableRoundedImageWithCornerRadius:50.0 + cornerColor:UIColor.redColor + fillColor:UIColor.greenColor + borderColor:UIColor.blueColor + borderWidth:4.0 + roundedCorners:UIRectCornerTopLeft | UIRectCornerBottomRight + scale:2.0 + traitCollection:ASPrimitiveTraitCollectionMakeDefault()]; + + node.image = image; + ASDisplayNodeSizeToFitSize(node, CGSizeMake(1000, 1000)); + ASSnapshotVerifyNode(node, nil); +} + +- (void)testRoundedAllCorners { + ASImageNode *node = [[ASImageNode alloc] init]; + UIImage *image = [UIImage as_resizableRoundedImageWithCornerRadius:50.0 + cornerColor:UIColor.redColor + fillColor:UIColor.greenColor + borderColor:UIColor.blueColor + borderWidth:4.0 + traitCollection:ASPrimitiveTraitCollectionMakeDefault()]; + + node.image = image; + ASDisplayNodeSizeToFitSize(node, CGSizeMake(1000, 1000)); + ASSnapshotVerifyNode(node, nil); +} + +- (void)testRoundedBorderless { + ASImageNode *node = [[ASImageNode alloc] init]; + UIImage *image = [UIImage as_resizableRoundedImageWithCornerRadius:50.0 + cornerColor:UIColor.redColor + fillColor:UIColor.greenColor + traitCollection:ASPrimitiveTraitCollectionMakeDefault()]; + + node.image = image; + ASDisplayNodeSizeToFitSize(node, CGSizeMake(1000, 1000)); + ASSnapshotVerifyNode(node, nil); +} +@end diff --git a/Texture.podspec b/Texture.podspec index 8f4de927..0ce226af 100644 --- a/Texture.podspec +++ b/Texture.podspec @@ -39,13 +39,14 @@ Pod::Spec.new do |spec| end spec.subspec 'PINRemoteImage' do |pin| - pin.dependency 'PINRemoteImage/iOS', '= 3.0.0-beta.14' + pin.dependency 'PINRemoteImage/iOS', '~> 3.0.0' pin.dependency 'PINRemoteImage/PINCache' pin.dependency 'Texture/Core' end spec.subspec 'IGListKit' do |igl| - igl.dependency 'IGListKit', '~> 3.0' + igl.dependency 'IGListKit', '~> 4.0' + igl.dependency 'IGListDiffKit', '~> 4.0' igl.dependency 'Texture/Core' end diff --git a/build.sh b/build.sh index a58fc11f..b2115aa5 100755 --- a/build.sh +++ b/build.sh @@ -1,7 +1,15 @@ #!/bin/bash +# echo ************* diagnostics +# echo available devices +# instruments -s devices +# echo available sdk +# xcodebuild -showsdks +# echo available Xcode +# ls -ld /Applications/Xcode* +# echo ************* diagnostics end -PLATFORM="${TEXTURE_BUILD_PLATFORM:-platform=iOS Simulator,OS=10.2,name=iPhone 7}" -SDK="${TEXTURE_BUILD_SDK:-iphonesimulator12.2}" +PLATFORM="${TEXTURE_BUILD_PLATFORM:-platform=iOS Simulator,OS=13.4.1,name=iPhone 8}" +SDK="${TEXTURE_BUILD_SDK:-iphonesimulator13.4}" DERIVED_DATA_PATH="~/ASDKDerivedData" # It is pitch black. @@ -24,13 +32,9 @@ function build_example { example="$1" clean_derived_data - + if [ -f "${example}/Podfile" ]; then echo "Using CocoaPods" - if [ -f "${example}/Podfile.lock" ]; then - rm "$example/Podfile.lock" - fi - rm -rf "$example/Pods" pod install --project-directory=$example set -o pipefail && xcodebuild \ @@ -39,7 +43,7 @@ function build_example { -sdk "$SDK" \ -destination "$PLATFORM" \ -derivedDataPath "$DERIVED_DATA_PATH" \ - build | xcpretty $FORMATTER + build elif [ -f "${example}/Cartfile" ]; then echo "Using Carthage" local_repo=`pwd` @@ -54,21 +58,29 @@ function build_example { -scheme Sample \ -sdk "$SDK" \ -destination "$PLATFORM" \ - build | xcpretty $FORMATTER + build cd ../.. fi } +# Lint subspec +function lint_subspec { + set -o pipefail && pod env && pod lib lint --allow-warnings --subspec="$1" +} + +function cleanup { + # remove all Pods directories + find . -name Pods -type d -exec rm -rf {} + + find . -name Podfile.lock -type f -delete +} + MODE="$1" -if type xcpretty-travis-formatter &> /dev/null; then - FORMATTER="-f $(xcpretty-travis-formatter)" - else - FORMATTER="-s" -fi +cleanup -if [ "$MODE" = "tests" -o "$MODE" = "all" ]; then +case "$MODE" in +tests|all) echo "Building & testing AsyncDisplayKit." pod install set -o pipefail && xcodebuild \ @@ -76,11 +88,11 @@ if [ "$MODE" = "tests" -o "$MODE" = "all" ]; then -scheme AsyncDisplayKit \ -sdk "$SDK" \ -destination "$PLATFORM" \ - build-for-testing test | xcpretty $FORMATTER + build-for-testing test success="1" -fi + ;; -if [ "$MODE" = "tests_listkit" ]; then +tests_listkit) echo "Building & testing AsyncDisplayKit+IGListKit." pod install --project-directory=SubspecWorkspaces/ASDKListKit set -o pipefail && xcodebuild \ @@ -88,125 +100,98 @@ if [ "$MODE" = "tests_listkit" ]; then -scheme ASDKListKitTests \ -sdk "$SDK" \ -destination "$PLATFORM" \ - build-for-testing test | xcpretty $FORMATTER + build-for-testing test success="1" -fi + ;; -if [ "$MODE" = "examples" -o "$MODE" = "all" ]; then +examples|all) echo "Verifying that all AsyncDisplayKit examples compile." - #Update cocoapods repo - pod repo update master - for example in examples/*/; do echo "Building (examples) $example." build_example $example done success="1" -fi + ;; -if [ "$MODE" = "examples-pt1" ]; then +examples-pt1) echo "Verifying that all AsyncDisplayKit examples compile." - #Update cocoapods repo - pod repo update master - for example in $((find ./examples -type d -maxdepth 1 \( ! -iname ".*" \)) | head -6); do echo "Building (examples-pt1) $example" build_example $example done success="1" -fi + ;; -if [ "$MODE" = "examples-pt2" ]; then +examples-pt2) echo "Verifying that all AsyncDisplayKit examples compile." - #Update cocoapods repo - pod repo update master - for example in $((find ./examples -type d -maxdepth 1 \( ! -iname ".*" \)) | head -11 | tail -5); do echo "Building (examples-pt2) $example" build_example $example done success="1" -fi + ;; -if [ "$MODE" = "examples-pt3" ]; then +examples-pt3) echo "Verifying that all AsyncDisplayKit examples compile." - #Update cocoapods repo - pod repo update master - for example in $((find ./examples -type d -maxdepth 1 \( ! -iname ".*" \)) | head -16 | tail -5); do echo "Building (examples-pt3) $example" build_example $example done success="1" -fi + ;; -if [ "$MODE" = "examples-pt4" ]; then +examples-pt4) echo "Verifying that all AsyncDisplayKit examples compile." - #Update cocoapods repo - pod repo update master - for example in $((find ./examples -type d -maxdepth 1 \( ! -iname ".*" \)) | tail -n +17); do echo "Building (examples-pt4) $example" build_example $example done success="1" -fi + ;; -if [ "$MODE" = "examples-extra-pt1" ]; then +examples-extra-pt1) echo "Verifying that all AsyncDisplayKit examples compile." - #Update cocoapods repo - pod repo update master - for example in $((find ./examples_extra -type d -maxdepth 1 \( ! -iname ".*" \)) | head -6); do echo "Building (examples-extra-pt1) $example" build_example $example done success="1" -fi + ;; -if [ "$MODE" = "examples-extra-pt2" ]; then +examples-extra-pt2) echo "Verifying that all AsyncDisplayKit examples compile." - #Update cocoapods repo - pod repo update master - for example in $((find ./examples_extra -type d -maxdepth 1 \( ! -iname ".*" \)) | head -11 | tail -5); do echo "Building (examples-extra-pt2) $example" build_example $example done success="1" -fi + ;; -if [ "$MODE" = "examples-extra-pt3" ]; then +examples-extra-pt3) echo "Verifying that all AsyncDisplayKit examples compile." - #Update cocoapods repo - pod repo update master - for example in $((find ./examples_extra -type d -maxdepth 1 \( ! -iname ".*" \)) | tail -n +12); do echo "Building (examples-extra-pt3) $example" build_example $example done success="1" -fi + ;; -# Support building a specific example: sh build.sh example examples/ASDKLayoutTransition -if [ "$MODE" = "example" ]; then +example) + # Support building a specific example: sh build.sh example examples/ASDKLayoutTransition echo "Verifying $2 compiles." - #Update cocoapods repo - pod repo update master - build_example $2 success="1" -fi + ;; -if [ "$MODE" = "life-without-cocoapods" -o "$MODE" = "all" ]; then +life-without-cocoapods|all) echo "Verifying that AsyncDisplayKit functions as a static library." set -o pipefail && xcodebuild \ @@ -214,11 +199,11 @@ if [ "$MODE" = "life-without-cocoapods" -o "$MODE" = "all" ]; then -scheme "Life Without CocoaPods" \ -sdk "$SDK" \ -destination "$PLATFORM" \ - build | xcpretty $FORMATTER + build success="1" -fi + ;; -if [ "$MODE" = "framework" -o "$MODE" = "all" ]; then +framework|all) echo "Verifying that AsyncDisplayKit functions as a dynamic framework (for Swift/Carthage users)." set -o pipefail && xcodebuild \ @@ -226,27 +211,52 @@ if [ "$MODE" = "framework" -o "$MODE" = "all" ]; then -scheme Sample \ -sdk "$SDK" \ -destination "$PLATFORM" \ - build | xcpretty $FORMATTER + build success="1" -fi + ;; -if [ "$MODE" = "cocoapods-lint" -o "$MODE" = "all" ]; then +cocoapods-lint|all) echo "Verifying that podspec lints." set -o pipefail && pod env && pod lib lint --allow-warnings success="1" -fi + ;; -if [ "$MODE" = "carthage" -o "$MODE" = "all" ]; then +cocoapods-lint-default-subspecs) + echo "Verifying that default subspecs lint." + + for subspec in 'Core' 'PINRemoteImage' 'Video' 'MapKit' 'AssetsLibrary' 'Photos'; do + echo "Verifying that $subspec subspec lints." + + lint_subspec $subspec + done + success="1" + ;; + +cocoapods-lint-other-subspecs) + echo "Verifying that other subspecs lint." + + for subspec in 'IGListKit' 'Yoga' 'TextNode2'; do + echo "Verifying that $subspec subspec lints." + + lint_subspec $subspec + done + success="1" + ;; + +carthage|all) echo "Verifying carthage works." - + set -o pipefail && carthage update && carthage build --no-skip-current success="1" -fi + ;; -if [ "$success" = "1" ]; then +*) + echo "Unrecognized mode '$MODE'." + ;; +esac + +if [ "$success" = "1" ]; then trap - EXIT exit 0 fi - -echo "Unrecognised mode '$MODE'." diff --git a/dangerfile.js b/dangerfile.js deleted file mode 100644 index b191420c..00000000 --- a/dangerfile.js +++ /dev/null @@ -1,89 +0,0 @@ -const { danger, fail, warn, schedule } = require('danger'); -const { readFileSync } = require('fs'); - -const source_pattern = /(\.m|\.mm|\.h)$/; -const modified_source_files = danger.git.modified_files.filter(f => source_pattern.test(f)); -const has_modified_source_files = (Array.isArray(modified_source_files) && modified_source_files.length > 0); -const added_source_files = danger.git.created_files.filter(f => source_pattern.test(f)); -const has_added_source_files = (Array.isArray(added_source_files) && added_source_files.length > 0); - -// Make it more obvious that a PR is a work in progress and shouldn't be merged yet -if (danger.github.pr.title.includes("[WIP]")) { - const msg = "PR is classed as Work in Progress"; - console.error("FAIL: " + msg); - fail(msg); -} - -// Warn when there is a big PR -if (danger.github.pr.additions + danger.github.pr.deletions > 500) { - const msg = "This is a big PR, please consider splitting it up to ease code review."; - console.error("WARN: "+ msg); - warn(msg); -} - -// Modifying the changelog will probably get overwritten. -if (danger.git.modified_files.includes("CHANGELOG.md")) { - if (danger.github.pr.title.includes("#changelog")) { - const msg = "PR modifies CHANGELOG.md, which is a generated file. #changelog added to the title to suppress this warning."; - console.error("WARN: "+ msg); - warn(msg); - } else { - const msg = "PR modifies CHANGELOG.md, which is a generated file. Add #changelog to the title to suppress this failure."; - console.error("FAIL: " + msg); - fail(msg); - } -} - -// Reference: http://a32.me/2014/03/heredoc-multiline-variable-with-javascript/ -function hereDoc(f) { - return f.toString(). - replace(/^[^\/]+\/\*!?/, ''). - replace(/\*\/[^\/]+$/, ''); -} - -function full_license(partial_license, filename) { - var license_header = hereDoc(function() {/*! -// -*/}); - license_header += "// " + filename; - license_header += hereDoc(function() {/*! -// Texture -//*/}); - license_header += partial_license; - return license_header; -} - -function check_file_header(files_to_check, license) { - for (let file of files_to_check) { - const filename = file.replace(/^.*[\\\/]/, ''); // Reference: https://stackoverflow.com/a/423385 - schedule(async () => { - const content = await danger.github.utils.fileContents(file); - if (!content.includes("Pinterest, Inc.")) { - const msg = "Please ensure license is correct for " + filename +":\n```" + full_license(license, filename) + "\n```"; - console.error("FAIL: " + msg); - fail(msg); - } - }); - } -} - -const new_source_license_header = hereDoc(function() {/*! -// Copyright (c) Pinterest, Inc. All rights reserved. -// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0 -//*/}); - -const modified_source_license_header = hereDoc(function() {/*! -// Copyright (c) Facebook, Inc. and its affiliates. All rights reserved. -// Changes after 4/13/2017 are: Copyright (c) Pinterest, Inc. All rights reserved. -// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0 -//*/}); - -// Ensure new files have proper header -if (has_added_source_files) { - check_file_header(added_source_files, new_source_license_header); -} - -// Ensure modified files have proper header -if (has_modified_source_files) { - check_file_header(modified_source_files, modified_source_license_header); -} diff --git a/docs/_docs/automatic-layout-examples-2.md b/docs/_docs/automatic-layout-examples-2.md index 07da8df1..71dd04cb 100755 --- a/docs/_docs/automatic-layout-examples-2.md +++ b/docs/_docs/automatic-layout-examples-2.md @@ -130,7 +130,7 @@ override func layoutSpecThatFits(_ constrainedSize: ASSizeRange) -> ASLayoutSpec To create this layout, we will use a: -- `ASAbsoluteLayoutSpec` to place the photo and icon which have been individually sized and positioned using their `ASLayoutable` properties +- `ASCornerLayoutSpec` to position the icon in corner of the photo
@@ -141,30 +141,18 @@ To create this layout, we will use a:
 - (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize
 {
-  _iconNode.style.preferredSize = CGSizeMake(40, 40);
-  _iconNode.style.layoutPosition = CGPointMake(150, 0);
-  
+  _iconNode.style.preferredSize = CGSizeMake(40, 40);  
   _photoNode.style.preferredSize = CGSizeMake(150, 150);
-  _photoNode.style.layoutPosition = CGPointMake(40 / 2.0, 40 / 2.0);
-  
-  return [ASAbsoluteLayoutSpec absoluteLayoutSpecWithSizing:ASAbsoluteLayoutSpecSizingSizeToFit
-                                                   children:@[_photoNode, _iconNode]];
+
+  return [ASCornerLayoutSpec cornerLayoutSpecWithChild:_photoNode corner:_iconNode location:ASCornerLayoutLocationTopRight];
 }
   
diff --git a/docs/_docs/corner-rounding.md b/docs/_docs/corner-rounding.md index 5dfdbb9f..8081bc7e 100755 --- a/docs/_docs/corner-rounding.md +++ b/docs/_docs/corner-rounding.md @@ -183,7 +183,8 @@ _photoImageNode.willDisplayNodeContentWithRenderingContext = ^(CGContextRef cont CGFloat radius = cornerRadius * screenScale; UIImage *overlay = [UIImage as_resizableRoundedImageWithCornerRadius:radius cornerColor:[UIColor clearColor] - fillColor:[UIColor clearColor]]; + fillColor:[UIColor clearColor] + traitCollection:self.primitiveTraitCollection]; [overlay drawInRect:bounds]; [[UIBezierPath bezierPathWithRoundedRect:bounds cornerRadius:radius] addClip]; }; diff --git a/docs/_docs/development/layout-specs.md b/docs/_docs/development/layout-specs.md index 826774c2..771d4ca0 100644 --- a/docs/_docs/development/layout-specs.md +++ b/docs/_docs/development/layout-specs.md @@ -28,7 +28,7 @@ Here is an example from the project `LayoutSpecExamples` where an `ASDisplayNode _iconNode = [[ASNetworkImageNode alloc] init]; _iconNode.URL = [NSURL URLWithString:@"http://texturegroup.org/static/images/layout-examples-photo-with-outset-icon-overlay-icon.png"]; - [_iconNode setImageModificationBlock:^UIImage *(UIImage *image) { // FIXME: in framework autocomplete for setImageModificationBlock line seems broken + [_iconNode setImageModificationBlock:^UIImage *(UIImage *image, ASPrimitiveTraitCollection traitCollection) { // FIXME: in framework autocomplete for setImageModificationBlock line seems broken CGSize profileImageSize = CGSizeMake(60, 60); return [image makeCircularImageWithSize:profileImageSize withBorderWidth:10]; }]; diff --git a/docs/_docs/image-modification-block.md b/docs/_docs/image-modification-block.md index 1e2e2716..d676ae14 100755 --- a/docs/_docs/image-modification-block.md +++ b/docs/_docs/image-modification-block.md @@ -59,7 +59,7 @@ In the following example we assume we have an avatar node that will be setup in - (instancetype)init { // ... - _userAvatarImageNode.imageModificationBlock = ^UIImage *(UIImage *image) { + _userAvatarImageNode.imageModificationBlock = ^UIImage *(UIImage *image, ASPrimitiveTraitCollection traitCollection) { CGSize profileImageSize = CGSizeMake(USER_IMAGE_HEIGHT, USER_IMAGE_HEIGHT); return [image makeCircularImageWithSize:profileImageSize]; }; diff --git a/docs/_docs/layout2-layoutspec-types.md b/docs/_docs/layout2-layoutspec-types.md index a5ab39b1..f907343a 100755 --- a/docs/_docs/layout2-layoutspec-types.md +++ b/docs/_docs/layout2-layoutspec-types.md @@ -48,7 +48,7 @@ You may also subclass `ASLa { _subnode.style.preferredSize = CGSizeMake(constrainedSize.max.width, constrainedSize.max.height / 2.0); - return [ASWrapperLayoutSpec wrapperWithLayoutElement:subnode]; + return [ASWrapperLayoutSpec wrapperWithLayoutElement:_subnode]; } diff --git a/docs/_docs/layout2-quickstart.md b/docs/_docs/layout2-quickstart.md index 49c5b666..2edbfda9 100755 --- a/docs/_docs/layout2-quickstart.md +++ b/docs/_docs/layout2-quickstart.md @@ -32,7 +32,7 @@ Texture's layout system is centered around two basic concepts: A layout spec, short for "layout specification", has no physical presence. Instead, layout specs act as containers for other layout elements by understanding how these children layout elements relate to each other. -Texture provides several subclasses of `ASLayoutSpec`, from a simple layout specification that insets a single child, to a more complex layout specification that arranges multiple children in varying stack configurations. +Texture provides several subclasses of `ASLayoutSpec`, from a simple layout specification that insets a single child, to a more complex layout specification that arranges multiple children in varying stack configurations. ### Layout Elements @@ -56,7 +56,7 @@ The play button on top of the `ASVideoNode` (top image) is placed using an `ASCe -Some elements have an "intrinsic size" based on their immediately available content. For example, ASTextNode can calculate its size based on its attributed string. Other nodes that have an intrinsic size include +Some elements have an "intrinsic size" based on their immediately available content. For example, ASTextNode can calculate its size based on its attributed string. Nodes that have an intrinsic size include - `ASImageNode` - `ASTextNode` diff --git a/docs/_docs/uicollectionviewinterop.md b/docs/_docs/uicollectionviewinterop.md index a918a0cf..d1f9fb66 100755 --- a/docs/_docs/uicollectionviewinterop.md +++ b/docs/_docs/uicollectionviewinterop.md @@ -71,7 +71,14 @@ For this example, the data source method `collectionNode:nodeBlockForItemAtIndex diff --git a/examples/ASDKTube/Sample/Nodes/VideoContentCell.m b/examples/ASDKTube/Sample/Nodes/VideoContentCell.m index fac4e389..034513f1 100644 --- a/examples/ASDKTube/Sample/Nodes/VideoContentCell.m +++ b/examples/ASDKTube/Sample/Nodes/VideoContentCell.m @@ -45,7 +45,7 @@ _avatarNode = [[ASNetworkImageNode alloc] init]; _avatarNode.URL = _videoModel.avatarUrl; - [_avatarNode setImageModificationBlock:^UIImage *(UIImage *image) { + [_avatarNode setImageModificationBlock:^UIImage *(UIImage *image, ASPrimitiveTraitCollection traitCollection) { CGSize profileImageSize = CGSizeMake(AVATAR_IMAGE_HEIGHT, AVATAR_IMAGE_HEIGHT); return [image makeCircularImageWithSize:profileImageSize]; }]; diff --git a/examples/ASDKgram/Sample/PhotoCellNode.m b/examples/ASDKgram/Sample/PhotoCellNode.m index 5353da65..f6663635 100644 --- a/examples/ASDKgram/Sample/PhotoCellNode.m +++ b/examples/ASDKgram/Sample/PhotoCellNode.m @@ -58,7 +58,7 @@ _userAvatarImageNode.URL = photo.ownerUserProfile.userPicURL; // FIXME: make round // FIXME: autocomplete for this line seems broken - [_userAvatarImageNode setImageModificationBlock:^UIImage *(UIImage *image) { + [_userAvatarImageNode setImageModificationBlock:^UIImage *(UIImage *image, ASPrimitiveTraitCollection traitCollection) { CGSize profileImageSize = CGSizeMake(USER_IMAGE_HEIGHT, USER_IMAGE_HEIGHT); return [image makeCircularImageWithSize:profileImageSize backgroundColor:nil]; }]; diff --git a/examples/ASMapNode/Sample/MapHandlerNode.m b/examples/ASMapNode/Sample/MapHandlerNode.m index 9226253a..da08daef 100644 --- a/examples/ASMapNode/Sample/MapHandlerNode.m +++ b/examples/ASMapNode/Sample/MapHandlerNode.m @@ -49,13 +49,15 @@ UIImage *backgroundImage = [UIImage as_resizableRoundedImageWithCornerRadius:5 cornerColor:[UIColor whiteColor] - fillColor:[UIColor lightGrayColor]]; + fillColor:[UIColor lightGrayColor] + traitCollection:self.primitiveTraitCollection]; UIImage *backgroundHiglightedImage = [UIImage as_resizableRoundedImageWithCornerRadius:5 cornerColor:[UIColor whiteColor] fillColor:[[UIColor lightGrayColor] colorWithAlphaComponent:0.4] borderColor:[UIColor lightGrayColor] - borderWidth:2.0]; + borderWidth:2.0 + traitCollection:self.primitiveTraitCollection]; [_updateRegionButton setBackgroundImage:backgroundImage forState:UIControlStateNormal]; [_updateRegionButton setBackgroundImage:backgroundHiglightedImage forState:UIControlStateHighlighted]; diff --git a/examples/CustomCollectionView-Swift/Sample/ViewController.swift b/examples/CustomCollectionView-Swift/Sample/ViewController.swift index 3af62907..1e33a06f 100644 --- a/examples/CustomCollectionView-Swift/Sample/ViewController.swift +++ b/examples/CustomCollectionView-Swift/Sample/ViewController.swift @@ -17,7 +17,7 @@ class ViewController: ASViewController, MosaicCollectionViewLa let _layoutInspector = MosaicCollectionViewLayoutInspector() let kNumberOfImages: UInt = 14 - init() { + override init() { let layout = MosaicCollectionViewLayout() layout.numberOfColumns = 3; layout.headerHeight = 44; diff --git a/examples/LayoutSpecExamples-Swift/Sample/LayoutExampleNode.swift b/examples/LayoutSpecExamples-Swift/Sample/LayoutExampleNode.swift index c113e07d..c2231d7d 100644 --- a/examples/LayoutSpecExamples-Swift/Sample/LayoutExampleNode.swift +++ b/examples/LayoutSpecExamples-Swift/Sample/LayoutExampleNode.swift @@ -97,7 +97,7 @@ class PhotoWithOutsetIconOverlay : LayoutExampleNode { iconNode.url = URL(string: "http://texturegroup.org/static/images/layout-examples-photo-with-outset-icon-overlay-icon.png") - iconNode.imageModificationBlock = { image in + iconNode.imageModificationBlock = { (image, traitCollection) -> UIImage in let profileImageSize = CGSize(width: 60, height: 60) return image.makeCircularImage(size: profileImageSize, borderWidth: 10) } diff --git a/examples/LayoutSpecExamples-Swift/Sample/OverviewViewController.swift b/examples/LayoutSpecExamples-Swift/Sample/OverviewViewController.swift index f306a12f..0c9110a3 100644 --- a/examples/LayoutSpecExamples-Swift/Sample/OverviewViewController.swift +++ b/examples/LayoutSpecExamples-Swift/Sample/OverviewViewController.swift @@ -13,7 +13,7 @@ class OverviewViewController: ASViewController { let tableNode = ASTableNode() let layoutExamples: [LayoutExampleNode.Type] - init() { + override init() { layoutExamples = [ HeaderWithRightAndLeftItems.self, PhotoWithInsetTextOverlay.self, diff --git a/examples/LayoutSpecExamples/Sample/LayoutExampleNodes.m b/examples/LayoutSpecExamples/Sample/LayoutExampleNodes.m index 5d9d6366..1c0bcc26 100644 --- a/examples/LayoutSpecExamples/Sample/LayoutExampleNodes.m +++ b/examples/LayoutSpecExamples/Sample/LayoutExampleNodes.m @@ -172,7 +172,7 @@ _iconNode = [[ASNetworkImageNode alloc] init]; _iconNode.URL = [NSURL URLWithString:@"http://texturegroup.org/static/images/layout-examples-photo-with-outset-icon-overlay-icon.png"]; - [_iconNode setImageModificationBlock:^UIImage *(UIImage *image) { // FIXME: in framework autocomplete for setImageModificationBlock line seems broken + [_iconNode setImageModificationBlock:^UIImage *(UIImage *image, ASPrimitiveTraitCollection traitCollection) { // FIXME: in framework autocomplete for setImageModificationBlock line seems broken CGSize profileImageSize = CGSizeMake(60, 60); return [image makeCircularImageWithSize:profileImageSize withBorderWidth:10]; }]; @@ -222,7 +222,10 @@ self.backgroundColor = [UIColor whiteColor]; _topSeparator = [[ASImageNode alloc] init]; - _topSeparator.image = [UIImage as_resizableRoundedImageWithCornerRadius:1.0 cornerColor:[UIColor blackColor] fillColor:[UIColor blackColor]]; + _topSeparator.image = [UIImage as_resizableRoundedImageWithCornerRadius:1.0 + cornerColor:[UIColor blackColor] + fillColor:[UIColor blackColor] + traitCollection:self.primitiveTraitCollection]; _textNode = [[ASTextNode alloc] init]; _textNode.attributedText = [NSAttributedString attributedStringWithString:@"this is a long text node" @@ -230,7 +233,10 @@ color:[UIColor blackColor]]; _bottomSeparator = [[ASImageNode alloc] init]; - _bottomSeparator.image = [UIImage as_resizableRoundedImageWithCornerRadius:1.0 cornerColor:[UIColor blackColor] fillColor:[UIColor blackColor]]; + _bottomSeparator.image = [UIImage as_resizableRoundedImageWithCornerRadius:1.0 + cornerColor:[UIColor blackColor] + fillColor:[UIColor blackColor] + traitCollection:self.primitiveTraitCollection]; } return self; @@ -297,7 +303,8 @@ static CGFloat const kSampleBadgeCornerRadius = 12; _badgeImageNode = [ASImageNode new]; _badgeImageNode.image = [UIImage as_resizableRoundedImageWithCornerRadius:kSampleBadgeCornerRadius cornerColor:UIColor.clearColor - fillColor:UIColor.redColor]; + fillColor:UIColor.redColor + traitCollection:self.primitiveTraitCollection]; _photoNode2 = [ASImageNode new]; _photoNode2.image = avatarImage; diff --git a/examples/README.md b/examples/README.md index 76c71a75..39fac1c1 100644 --- a/examples/README.md +++ b/examples/README.md @@ -83,7 +83,7 @@ Featuring: ### CustomCollectionView [ObjC+Swift] -![CustomCollectionView Example App gif](https://github.com/AsyncDisplayKit/Documentation/raw/master/docs/static/images/example-app-screenshots/CustomCollectionView.git) +![CustomCollectionView Example App gif](https://github.com/AsyncDisplayKit/Documentation/raw/master/docs/static/images/example-app-screenshots/CustomCollectionView.gif) Featuring: - custom collection view layout diff --git a/examples/SocialAppLayout-Inverted/Sample/PostNode.m b/examples/SocialAppLayout-Inverted/Sample/PostNode.m index defafc00..a0711d78 100644 --- a/examples/SocialAppLayout-Inverted/Sample/PostNode.m +++ b/examples/SocialAppLayout-Inverted/Sample/PostNode.m @@ -108,7 +108,7 @@ _mediaNode.cornerRadius = 4.0; _mediaNode.URL = [NSURL URLWithString:_post.media]; _mediaNode.delegate = self; - _mediaNode.imageModificationBlock = ^UIImage *(UIImage *image) { + _mediaNode.imageModificationBlock = ^UIImage *(UIImage *image, ASPrimitiveTraitCollection traitCollection) { UIImage *modifiedImage; CGRect rect = CGRectMake(0, 0, image.size.width, image.size.height); @@ -134,7 +134,7 @@ _avatarNode.style.height = ASDimensionMakeWithPoints(44); _avatarNode.cornerRadius = 22.0; _avatarNode.URL = [NSURL URLWithString:_post.photo]; - _avatarNode.imageModificationBlock = ^UIImage *(UIImage *image) { + _avatarNode.imageModificationBlock = ^UIImage *(UIImage *image, ASPrimitiveTraitCollection traitCollection) { UIImage *modifiedImage; CGRect rect = CGRectMake(0, 0, image.size.width, image.size.height); diff --git a/examples/SocialAppLayout/Sample/PostNode.m b/examples/SocialAppLayout/Sample/PostNode.m index defafc00..a0711d78 100644 --- a/examples/SocialAppLayout/Sample/PostNode.m +++ b/examples/SocialAppLayout/Sample/PostNode.m @@ -108,7 +108,7 @@ _mediaNode.cornerRadius = 4.0; _mediaNode.URL = [NSURL URLWithString:_post.media]; _mediaNode.delegate = self; - _mediaNode.imageModificationBlock = ^UIImage *(UIImage *image) { + _mediaNode.imageModificationBlock = ^UIImage *(UIImage *image, ASPrimitiveTraitCollection traitCollection) { UIImage *modifiedImage; CGRect rect = CGRectMake(0, 0, image.size.width, image.size.height); @@ -134,7 +134,7 @@ _avatarNode.style.height = ASDimensionMakeWithPoints(44); _avatarNode.cornerRadius = 22.0; _avatarNode.URL = [NSURL URLWithString:_post.photo]; - _avatarNode.imageModificationBlock = ^UIImage *(UIImage *image) { + _avatarNode.imageModificationBlock = ^UIImage *(UIImage *image, ASPrimitiveTraitCollection traitCollection) { UIImage *modifiedImage; CGRect rect = CGRectMake(0, 0, image.size.width, image.size.height); diff --git a/examples/Swift/Sample/ViewController.swift b/examples/Swift/Sample/ViewController.swift index 0c94d86a..8384906c 100644 --- a/examples/Swift/Sample/ViewController.swift +++ b/examples/Swift/Sample/ViewController.swift @@ -29,7 +29,7 @@ final class ViewController: ASViewController, ASTableDataSource, fileprivate(set) var state: State = .empty - init() { + override init() { super.init(node: ASTableNode()) tableNode.delegate = self tableNode.dataSource = self diff --git a/examples_extra/Shop/Shop.xcodeproj/project.pbxproj b/examples_extra/Shop/Shop.xcodeproj/project.pbxproj index 5c9cc401..3f45385f 100644 --- a/examples_extra/Shop/Shop.xcodeproj/project.pbxproj +++ b/examples_extra/Shop/Shop.xcodeproj/project.pbxproj @@ -228,8 +228,6 @@ 278BFA1A1DD4A7B80065BACA /* Sources */, 278BFA1B1DD4A7B80065BACA /* Frameworks */, 278BFA1C1DD4A7B80065BACA /* Resources */, - 7A9094E163FF7B834F7D5B76 /* [CP] Embed Pods Frameworks */, - 89C7C85237928A7AA1AFD80E /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -248,8 +246,6 @@ 278BFA2E1DD4A7B80065BACA /* Sources */, 278BFA2F1DD4A7B80065BACA /* Frameworks */, 278BFA301DD4A7B80065BACA /* Resources */, - 4E2E9451B168505B69D5EA0F /* [CP] Embed Pods Frameworks */, - D97894A2A1E9AC5B6FFB9271 /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -268,7 +264,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0810; - LastUpgradeCheck = 0910; + LastUpgradeCheck = 1110; ORGANIZATIONNAME = Dimitri; TargetAttributes = { 278BFA1D1DD4A7B80065BACA = { @@ -287,7 +283,7 @@ }; buildConfigurationList = 278BFA191DD4A7B80065BACA /* Build configuration list for PBXProject "Shop" */; compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; + developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( en, @@ -342,21 +338,6 @@ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; - 4E2E9451B168505B69D5EA0F /* [CP] Embed Pods Frameworks */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "[CP] Embed Pods Frameworks"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-ShopTests/Pods-ShopTests-frameworks.sh\"\n"; - showEnvVarsInLog = 0; - }; 53B8D1D4907B5E11F1FB4D84 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -375,51 +356,6 @@ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; - 7A9094E163FF7B834F7D5B76 /* [CP] Embed Pods Frameworks */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "[CP] Embed Pods Frameworks"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Shop/Pods-Shop-frameworks.sh\"\n"; - showEnvVarsInLog = 0; - }; - 89C7C85237928A7AA1AFD80E /* [CP] Copy Pods Resources */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "[CP] Copy Pods Resources"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Shop/Pods-Shop-resources.sh\"\n"; - showEnvVarsInLog = 0; - }; - D97894A2A1E9AC5B6FFB9271 /* [CP] Copy Pods Resources */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "[CP] Copy Pods Resources"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-ShopTests/Pods-ShopTests-resources.sh\"\n"; - showEnvVarsInLog = 0; - }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -480,6 +416,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; @@ -489,6 +426,7 @@ CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; @@ -496,6 +434,7 @@ CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; @@ -536,6 +475,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; @@ -545,6 +485,7 @@ CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; @@ -552,6 +493,7 @@ CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; @@ -594,7 +536,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Shop/Shop-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 4.2; }; name = Debug; }; @@ -610,7 +552,7 @@ PRODUCT_BUNDLE_IDENTIFIER = org.sample.Shop; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Shop/Shop-Bridging-Header.h"; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 4.2; }; name = Release; }; diff --git a/examples_extra/Shop/Shop.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/examples_extra/Shop/Shop.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/examples_extra/Shop/Shop.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/examples_extra/Shop/Shop/AppDelegate.swift b/examples_extra/Shop/Shop/AppDelegate.swift index ebae7efc..03251861 100644 --- a/examples_extra/Shop/Shop/AppDelegate.swift +++ b/examples_extra/Shop/Shop/AppDelegate.swift @@ -10,46 +10,46 @@ import UIKit @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { - + var window: UIWindow? - - func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { + + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // Override point for customization after application launch. UINavigationBar.appearance().tintColor = UIColor.white - UINavigationBar.appearance().titleTextAttributes = [NSForegroundColorAttributeName : UIColor.white] + UINavigationBar.appearance().titleTextAttributes = [NSAttributedString.Key.foregroundColor : UIColor.white] UINavigationBar.appearance().barTintColor = UIColor.primaryBarTintColor() - + self.window = UIWindow(frame: UIScreen.main.bounds) self.window?.backgroundColor = UIColor.white self.window?.rootViewController = UINavigationController(rootViewController: ShopViewController()) self.window?.makeKeyAndVisible() - + return true } - + func applicationWillResignActive(_ application: UIApplication) { // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. } - + func applicationDidEnterBackground(_ application: UIApplication) { // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. } - + func applicationWillEnterForeground(_ application: UIApplication) { // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. } - + func applicationDidBecomeActive(_ application: UIApplication) { // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. } - + func applicationWillTerminate(_ application: UIApplication) { // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. } - - + + } diff --git a/examples_extra/Shop/Shop/Models/DummyGenerator.swift b/examples_extra/Shop/Shop/Models/DummyGenerator.swift index d68e4375..753e1429 100644 --- a/examples_extra/Shop/Shop/Models/DummyGenerator.swift +++ b/examples_extra/Shop/Shop/Models/DummyGenerator.swift @@ -154,7 +154,7 @@ private extension Array { private extension String { var stringWithCapitalizedFirstLetter: String { let firstLetterRange = startIndex.. ASLayoutSpec { - let insets = UIEdgeInsetsMake(2, 2, 2, 2) + let insets = UIEdgeInsets(top: 2, left: 2, bottom: 2, right: 2) return ASInsetLayoutSpec(insets: insets, child: self.containerNode) } @@ -47,11 +47,11 @@ class ProductContentNode: ASDisplayNode { imageNode.url = URL(string: product.imageURL) titleNode = ASTextNode() - let title = NSAttributedString(string: product.title, attributes: [NSForegroundColorAttributeName: UIColor.white, NSFontAttributeName: UIFont.boldSystemFont(ofSize: 17)]) + let title = NSAttributedString(string: product.title, attributes: [NSAttributedString.Key.foregroundColor: UIColor.white, NSAttributedString.Key.font: UIFont.boldSystemFont(ofSize: 17)]) titleNode.attributedText = title subtitleNode = ASTextNode() - let subtitle = NSAttributedString(string: product.currency + " \(product.price)", attributes: [NSForegroundColorAttributeName: UIColor.white, NSFontAttributeName: UIFont.boldSystemFont(ofSize: 15)]) + let subtitle = NSAttributedString(string: product.currency + " \(product.price)", attributes: [NSAttributedString.Key.foregroundColor: UIColor.white, NSAttributedString.Key.font: UIFont.boldSystemFont(ofSize: 15)]) subtitleNode.attributedText = subtitle super.init() @@ -65,7 +65,7 @@ class ProductContentNode: ASDisplayNode { override func layoutSpecThatFits(_ constrainedSize: ASSizeRange) -> ASLayoutSpec { let textNodesStack = ASStackLayoutSpec(direction: .vertical, spacing: 5, justifyContent: .end, alignItems: .stretch, children: [self.titleNode, self.subtitleNode]) - let insetStack = ASInsetLayoutSpec(insets: UIEdgeInsetsMake(CGFloat.infinity, 10, 10, 10), child: textNodesStack) + let insetStack = ASInsetLayoutSpec(insets: UIEdgeInsets(top: CGFloat.infinity, left: 10, bottom: 10, right: 10), child: textNodesStack) return ASOverlayLayoutSpec(child: self.imageNode, overlay: insetStack) } diff --git a/examples_extra/Shop/Shop/Scenes/Products/ProductTableNode.swift b/examples_extra/Shop/Shop/Scenes/Products/ProductTableNode.swift index 816d405d..cbbae144 100644 --- a/examples_extra/Shop/Shop/Scenes/Products/ProductTableNode.swift +++ b/examples_extra/Shop/Shop/Scenes/Products/ProductTableNode.swift @@ -9,7 +9,7 @@ import UIKit class ProductTableNode: ASCellNode { - + // MARK: - Variables private lazy var imageSize: CGSize = { @@ -64,7 +64,7 @@ class ProductTableNode: ASCellNode { } private var titleTextAttributes = { - return [NSForegroundColorAttributeName: UIColor.black, NSFontAttributeName: UIFont.boldSystemFont(ofSize: 16)] + return [NSAttributedString.Key.foregroundColor: UIColor.black, NSAttributedString.Key.font: UIFont.boldSystemFont(ofSize: 16)] } private func setupSubtitleNode() { @@ -74,7 +74,7 @@ class ProductTableNode: ASCellNode { } private var subtitleTextAttributes = { - return [NSForegroundColorAttributeName: UIColor.darkGray, NSFontAttributeName: UIFont.systemFont(ofSize: 14)] + return [NSAttributedString.Key.foregroundColor: UIColor.darkGray, NSAttributedString.Key.font: UIFont.systemFont(ofSize: 14)] } private func setupPriceNode() { @@ -82,7 +82,7 @@ class ProductTableNode: ASCellNode { } private var priceTextAttributes = { - return [NSForegroundColorAttributeName: UIColor.red, NSFontAttributeName: UIFont.boldSystemFont(ofSize: 15)] + return [NSAttributedString.Key.foregroundColor: UIColor.red, NSAttributedString.Key.font: UIFont.boldSystemFont(ofSize: 15)] } private func setupSeparatorNode() { @@ -117,7 +117,7 @@ class ProductTableNode: ASCellNode { let contentSpec = ASStackLayoutSpec(direction: .vertical, spacing: 4.0, justifyContent: .start, alignItems: .stretch, children: [titlePriceSpec, self.subtitleNode, self.starRatingNode]) contentSpec.style.flexShrink = 1 let finalSpec = ASStackLayoutSpec(direction: .horizontal, spacing: 10.0, justifyContent: .start, alignItems: .start, children: [self.imageNode, contentSpec]) - return ASInsetLayoutSpec(insets: UIEdgeInsetsMake(10.0, 10.0, 10.0, 10.0), child: finalSpec) + return ASInsetLayoutSpec(insets: UIEdgeInsets(top: 10.0, left: 10.0, bottom: 10.0, right: 10.0), child: finalSpec) } } diff --git a/examples_extra/Shop/Shop/Scenes/Shop/ShopCellNode.swift b/examples_extra/Shop/Shop/Scenes/Shop/ShopCellNode.swift index 5e713282..06acc9c6 100644 --- a/examples_extra/Shop/Shop/Scenes/Shop/ShopCellNode.swift +++ b/examples_extra/Shop/Shop/Scenes/Shop/ShopCellNode.swift @@ -28,7 +28,7 @@ class ShopCellNode: ASCellNode { // MARK: - Layout override func layoutSpecThatFits(_ constrainedSize: ASSizeRange) -> ASLayoutSpec { - return ASInsetLayoutSpec(insets: UIEdgeInsetsMake(5, 10, 5, 10), child: self.containerNode) + return ASInsetLayoutSpec(insets: UIEdgeInsets(top: 5, left: 10, bottom: 5, right: 10), child: self.containerNode) } } @@ -60,7 +60,7 @@ class ContainerNode: ASDisplayNode { // MARK: - Layout override func layoutSpecThatFits(_ constrainedSize: ASSizeRange) -> ASLayoutSpec { - return ASInsetLayoutSpec(insets: UIEdgeInsetsMake(8, 8, 8, 8), child: self.contentNode) + return ASInsetLayoutSpec(insets: UIEdgeInsets(top: 8, left: 8, bottom: 8, right: 8), child: self.contentNode) } } @@ -80,11 +80,11 @@ class CategoryNode: ASDisplayNode { imageNode.url = URL(string: category.imageURL) titleNode = ASTextNode() - let title = NSAttributedString(string: category.title, attributes: [NSForegroundColorAttributeName: UIColor.white, NSFontAttributeName: UIFont.boldSystemFont(ofSize: 17)]) + let title = NSAttributedString(string: category.title, attributes: [NSAttributedString.Key.foregroundColor: UIColor.white, NSAttributedString.Key.font: UIFont.boldSystemFont(ofSize: 17)]) titleNode.attributedText = title subtitleNode = ASTextNode() - let subtitle = NSAttributedString(string: "\(category.numberOfProducts) products", attributes: [NSForegroundColorAttributeName: UIColor.white, NSFontAttributeName: UIFont.boldSystemFont(ofSize: 15)]) + let subtitle = NSAttributedString(string: "\(category.numberOfProducts) products", attributes: [NSAttributedString.Key.foregroundColor: UIColor.white, NSAttributedString.Key.font: UIFont.boldSystemFont(ofSize: 15)]) subtitleNode.attributedText = subtitle super.init() @@ -98,7 +98,7 @@ class CategoryNode: ASDisplayNode { override func layoutSpecThatFits(_ constrainedSize: ASSizeRange) -> ASLayoutSpec { let textNodesStack = ASStackLayoutSpec(direction: .vertical, spacing: 5, justifyContent: .end, alignItems: .stretch, children: [self.titleNode, self.subtitleNode]) - let insetStack = ASInsetLayoutSpec(insets: UIEdgeInsetsMake(CGFloat.infinity, 10, 10, 10), child: textNodesStack) + let insetStack = ASInsetLayoutSpec(insets: UIEdgeInsets(top: CGFloat.infinity, left: 10, bottom: 10, right: 10), child: textNodesStack) return ASOverlayLayoutSpec(child: self.imageNode, overlay: insetStack) }