From 96df35e41a1574a5b3d93f81499137401f5d1285 Mon Sep 17 00:00:00 2001 From: Michael Schneider Date: Tue, 29 Mar 2016 11:22:45 -0700 Subject: [PATCH 1/6] Initial commit for ASEnvironment --- AsyncDisplayKit.xcodeproj/project.pbxproj | 108 +++---- AsyncDisplayKit/ASDisplayNode.mm | 35 ++- AsyncDisplayKit/AsyncDisplayKit.h | 2 +- AsyncDisplayKit/Details/ASEnvironment.h | 92 ++++++ AsyncDisplayKit/Details/ASEnvironment.m | 41 +++ AsyncDisplayKit/Layout/ASLayoutOptions.h | 91 ------ AsyncDisplayKit/Layout/ASLayoutOptions.mm | 263 ------------------ .../Layout/ASLayoutOptionsPrivate.mm | 143 ---------- AsyncDisplayKit/Layout/ASLayoutSpec.mm | 40 ++- AsyncDisplayKit/Layout/ASLayoutable.h | 3 +- AsyncDisplayKit/Layout/ASLayoutable.mm | 183 ++++++++++++ AsyncDisplayKit/Layout/ASLayoutablePrivate.h | 8 +- AsyncDisplayKit/Layout/ASStackLayoutSpec.mm | 9 + AsyncDisplayKit/Layout/ASStaticLayoutSpec.mm | 10 +- .../Private/ASDisplayNode+FrameworkPrivate.h | 1 - .../Private/ASDisplayNodeInternal.h | 3 +- .../Private/ASEnvironmentInternal.h | 56 ++++ .../Private/ASEnvironmentInternal.mm | 100 +++++++ .../Private/ASLayoutOptionsPrivate.h | 33 --- .../ASStackBaselinePositionedLayout.mm | 1 - .../Private/ASStackPositionedLayout.mm | 1 - .../Private/ASStackUnpositionedLayout.mm | 4 +- .../ASCenterLayoutSpecSnapshotTests.mm | 1 - .../ASRelativeLayoutSpecSnapshotTests.mm | 1 - .../ASStackLayoutSpecSnapshotTests.mm | 1 - 25 files changed, 620 insertions(+), 610 deletions(-) create mode 100644 AsyncDisplayKit/Details/ASEnvironment.h create mode 100644 AsyncDisplayKit/Details/ASEnvironment.m delete mode 100644 AsyncDisplayKit/Layout/ASLayoutOptions.h delete mode 100644 AsyncDisplayKit/Layout/ASLayoutOptions.mm delete mode 100644 AsyncDisplayKit/Layout/ASLayoutOptionsPrivate.mm create mode 100644 AsyncDisplayKit/Private/ASEnvironmentInternal.h create mode 100644 AsyncDisplayKit/Private/ASEnvironmentInternal.mm delete mode 100644 AsyncDisplayKit/Private/ASLayoutOptionsPrivate.h diff --git a/AsyncDisplayKit.xcodeproj/project.pbxproj b/AsyncDisplayKit.xcodeproj/project.pbxproj index cdabc84113..ac41e847c5 100644 --- a/AsyncDisplayKit.xcodeproj/project.pbxproj +++ b/AsyncDisplayKit.xcodeproj/project.pbxproj @@ -258,6 +258,14 @@ 68EE0DBE1C1B4ED300BA1B99 /* ASMainSerialQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 68EE0DBB1C1B4ED300BA1B99 /* ASMainSerialQueue.h */; }; 68EE0DBF1C1B4ED300BA1B99 /* ASMainSerialQueue.mm in Sources */ = {isa = PBXBuildFile; fileRef = 68EE0DBC1C1B4ED300BA1B99 /* ASMainSerialQueue.mm */; }; 68EE0DC01C1B4ED300BA1B99 /* ASMainSerialQueue.mm in Sources */ = {isa = PBXBuildFile; fileRef = 68EE0DBC1C1B4ED300BA1B99 /* ASMainSerialQueue.mm */; }; + 698548631CA9E025008A345F /* ASEnvironment.h in Headers */ = {isa = PBXBuildFile; fileRef = 698548611CA9E025008A345F /* ASEnvironment.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 698548641CA9E025008A345F /* ASEnvironment.h in Headers */ = {isa = PBXBuildFile; fileRef = 698548611CA9E025008A345F /* ASEnvironment.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 698548651CA9E025008A345F /* ASEnvironment.m in Sources */ = {isa = PBXBuildFile; fileRef = 698548621CA9E025008A345F /* ASEnvironment.m */; }; + 698548661CA9E025008A345F /* ASEnvironment.m in Sources */ = {isa = PBXBuildFile; fileRef = 698548621CA9E025008A345F /* ASEnvironment.m */; }; + 69E1006D1CA89CB600D88C1B /* ASEnvironmentInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 69E100691CA89CB600D88C1B /* ASEnvironmentInternal.h */; }; + 69E1006E1CA89CB600D88C1B /* ASEnvironmentInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 69E100691CA89CB600D88C1B /* ASEnvironmentInternal.h */; }; + 69E1006F1CA89CB600D88C1B /* ASEnvironmentInternal.mm in Sources */ = {isa = PBXBuildFile; fileRef = 69E1006A1CA89CB600D88C1B /* ASEnvironmentInternal.mm */; }; + 69E100701CA89CB600D88C1B /* ASEnvironmentInternal.mm in Sources */ = {isa = PBXBuildFile; fileRef = 69E1006A1CA89CB600D88C1B /* ASEnvironmentInternal.mm */; }; 69F10C861C84C35D0026140C /* ASRangeControllerUpdateRangeProtocol+Beta.h in Headers */ = {isa = PBXBuildFile; fileRef = 69F10C851C84C35D0026140C /* ASRangeControllerUpdateRangeProtocol+Beta.h */; settings = {ATTRIBUTES = (Public, ); }; }; 69F10C871C84C35D0026140C /* ASRangeControllerUpdateRangeProtocol+Beta.h in Headers */ = {isa = PBXBuildFile; fileRef = 69F10C851C84C35D0026140C /* ASRangeControllerUpdateRangeProtocol+Beta.h */; settings = {ATTRIBUTES = (Public, ); }; }; 6BDC61F61979037800E50D21 /* AsyncDisplayKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 6BDC61F51978FEA400E50D21 /* AsyncDisplayKit.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -288,14 +296,6 @@ 9C55866A1BD549CB00B50E3A /* ASAsciiArtBoxCreator.m in Sources */ = {isa = PBXBuildFile; fileRef = 9C5586681BD549CB00B50E3A /* ASAsciiArtBoxCreator.m */; }; 9C55866B1BD54A1900B50E3A /* ASAsciiArtBoxCreator.m in Sources */ = {isa = PBXBuildFile; fileRef = 9C5586681BD549CB00B50E3A /* ASAsciiArtBoxCreator.m */; }; 9C55866C1BD54A3000B50E3A /* ASAsciiArtBoxCreator.h in Headers */ = {isa = PBXBuildFile; fileRef = 9C5586671BD549CB00B50E3A /* ASAsciiArtBoxCreator.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 9C5FA3511B8F6ADF00A62714 /* ASLayoutOptions.h in Headers */ = {isa = PBXBuildFile; fileRef = 9C5FA34F1B8F6ADF00A62714 /* ASLayoutOptions.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 9C5FA3521B8F6ADF00A62714 /* ASLayoutOptions.h in Headers */ = {isa = PBXBuildFile; fileRef = 9C5FA34F1B8F6ADF00A62714 /* ASLayoutOptions.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 9C5FA3531B8F6ADF00A62714 /* ASLayoutOptions.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9C5FA3501B8F6ADF00A62714 /* ASLayoutOptions.mm */; }; - 9C5FA3541B8F6ADF00A62714 /* ASLayoutOptions.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9C5FA3501B8F6ADF00A62714 /* ASLayoutOptions.mm */; }; - 9C5FA35F1B90C9A500A62714 /* ASLayoutOptionsPrivate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9C5FA35C1B90C9A500A62714 /* ASLayoutOptionsPrivate.mm */; }; - 9C5FA3601B90C9A500A62714 /* ASLayoutOptionsPrivate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9C5FA35C1B90C9A500A62714 /* ASLayoutOptionsPrivate.mm */; }; - 9C65A72A1BA8EA4D0084DA91 /* ASLayoutOptionsPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 9C65A7291BA8EA4D0084DA91 /* ASLayoutOptionsPrivate.h */; }; - 9C65A72B1BA8EA4D0084DA91 /* ASLayoutOptionsPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 9C65A7291BA8EA4D0084DA91 /* ASLayoutOptionsPrivate.h */; }; 9C6BB3B21B8CC9C200F13F52 /* ASStaticLayoutable.h in Headers */ = {isa = PBXBuildFile; fileRef = 9C6BB3B01B8CC9C200F13F52 /* ASStaticLayoutable.h */; settings = {ATTRIBUTES = (Public, ); }; }; 9C6BB3B31B8CC9C200F13F52 /* ASStaticLayoutable.h in Headers */ = {isa = PBXBuildFile; fileRef = 9C6BB3B01B8CC9C200F13F52 /* ASStaticLayoutable.h */; settings = {ATTRIBUTES = (Public, ); }; }; 9C8221951BA237B80037F19A /* ASStackBaselinePositionedLayout.h in Headers */ = {isa = PBXBuildFile; fileRef = 9C8221931BA237B80037F19A /* ASStackBaselinePositionedLayout.h */; }; @@ -740,6 +740,10 @@ 68B027791C1A79CC0041016B /* ASDisplayNode+Beta.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ASDisplayNode+Beta.h"; sourceTree = ""; }; 68EE0DBB1C1B4ED300BA1B99 /* ASMainSerialQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASMainSerialQueue.h; sourceTree = ""; }; 68EE0DBC1C1B4ED300BA1B99 /* ASMainSerialQueue.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASMainSerialQueue.mm; sourceTree = ""; }; + 698548611CA9E025008A345F /* ASEnvironment.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASEnvironment.h; sourceTree = ""; }; + 698548621CA9E025008A345F /* ASEnvironment.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASEnvironment.m; sourceTree = ""; }; + 69E100691CA89CB600D88C1B /* ASEnvironmentInternal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASEnvironmentInternal.h; sourceTree = ""; }; + 69E1006A1CA89CB600D88C1B /* ASEnvironmentInternal.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASEnvironmentInternal.mm; sourceTree = ""; }; 69F10C851C84C35D0026140C /* ASRangeControllerUpdateRangeProtocol+Beta.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ASRangeControllerUpdateRangeProtocol+Beta.h"; sourceTree = ""; }; 6BDC61F51978FEA400E50D21 /* AsyncDisplayKit.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; path = AsyncDisplayKit.h; sourceTree = ""; }; 764D83D21C8EA515009B4FB8 /* AsyncDisplayKit+Debug.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "AsyncDisplayKit+Debug.h"; sourceTree = ""; }; @@ -755,10 +759,6 @@ 9C49C36E1B853957000B0DD5 /* ASStackLayoutable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASStackLayoutable.h; path = AsyncDisplayKit/Layout/ASStackLayoutable.h; sourceTree = ""; }; 9C5586671BD549CB00B50E3A /* ASAsciiArtBoxCreator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASAsciiArtBoxCreator.h; path = AsyncDisplayKit/Layout/ASAsciiArtBoxCreator.h; sourceTree = ""; }; 9C5586681BD549CB00B50E3A /* ASAsciiArtBoxCreator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ASAsciiArtBoxCreator.m; path = AsyncDisplayKit/Layout/ASAsciiArtBoxCreator.m; sourceTree = ""; }; - 9C5FA34F1B8F6ADF00A62714 /* ASLayoutOptions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASLayoutOptions.h; path = AsyncDisplayKit/Layout/ASLayoutOptions.h; sourceTree = ""; }; - 9C5FA3501B8F6ADF00A62714 /* ASLayoutOptions.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = ASLayoutOptions.mm; path = AsyncDisplayKit/Layout/ASLayoutOptions.mm; sourceTree = ""; }; - 9C5FA35C1B90C9A500A62714 /* ASLayoutOptionsPrivate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = ASLayoutOptionsPrivate.mm; path = AsyncDisplayKit/Layout/ASLayoutOptionsPrivate.mm; sourceTree = ""; }; - 9C65A7291BA8EA4D0084DA91 /* ASLayoutOptionsPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASLayoutOptionsPrivate.h; sourceTree = ""; }; 9C6BB3B01B8CC9C200F13F52 /* ASStaticLayoutable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASStaticLayoutable.h; path = AsyncDisplayKit/Layout/ASStaticLayoutable.h; sourceTree = ""; }; 9C8221931BA237B80037F19A /* ASStackBaselinePositionedLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASStackBaselinePositionedLayout.h; sourceTree = ""; }; 9C8221941BA237B80037F19A /* ASStackBaselinePositionedLayout.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASStackBaselinePositionedLayout.mm; sourceTree = ""; }; @@ -802,7 +802,7 @@ ACF6ED161B17843500DA7C62 /* ASStackLayoutSpec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASStackLayoutSpec.h; path = AsyncDisplayKit/Layout/ASStackLayoutSpec.h; sourceTree = ""; }; ACF6ED171B17843500DA7C62 /* ASStackLayoutSpec.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = ASStackLayoutSpec.mm; path = AsyncDisplayKit/Layout/ASStackLayoutSpec.mm; sourceTree = ""; }; ACF6ED181B17843500DA7C62 /* ASStaticLayoutSpec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASStaticLayoutSpec.h; path = AsyncDisplayKit/Layout/ASStaticLayoutSpec.h; sourceTree = ""; }; - ACF6ED191B17843500DA7C62 /* ASStaticLayoutSpec.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; name = ASStaticLayoutSpec.mm; path = AsyncDisplayKit/Layout/ASStaticLayoutSpec.mm; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; + ACF6ED191B17843500DA7C62 /* ASStaticLayoutSpec.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; name = ASStaticLayoutSpec.mm; path = AsyncDisplayKit/Layout/ASStaticLayoutSpec.mm; sourceTree = ""; }; ACF6ED431B17847A00DA7C62 /* ASInternalHelpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASInternalHelpers.h; sourceTree = ""; }; ACF6ED441B17847A00DA7C62 /* ASInternalHelpers.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASInternalHelpers.mm; sourceTree = ""; }; ACF6ED451B17847A00DA7C62 /* ASLayoutSpecUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASLayoutSpecUtilities.h; sourceTree = ""; }; @@ -1116,14 +1116,6 @@ 058D09E1195D050800B7D73C /* Details */ = { isa = PBXGroup; children = ( - 25B171EA1C12242700508A7A /* Data Controller */, - 81EE384D1C8E94F000456208 /* ASRunLoopQueue.h */, - 81EE384E1C8E94F000456208 /* ASRunLoopQueue.mm */, - CC7FD9DC1BB5E962005CCB2B /* ASPhotosFrameworkImageRequest.h */, - CC7FD9DD1BB5E962005CCB2B /* ASPhotosFrameworkImageRequest.m */, - 251B8EF41BBB3D690087C538 /* ASCollectionViewFlowLayoutInspector.h */, - 251B8EF51BBB3D690087C538 /* ASCollectionViewFlowLayoutInspector.m */, - 251B8EF61BBB3D690087C538 /* ASDataController+Subclasses.h */, 058D09E2195D050800B7D73C /* _ASDisplayLayer.h */, 058D09E3195D050800B7D73C /* _ASDisplayLayer.mm */, 058D09E4195D050800B7D73C /* _ASDisplayView.h */, @@ -1134,31 +1126,41 @@ 054963481A1EA066000F8E56 /* ASBasicImageDownloader.mm */, 299DA1A71A828D2900162D41 /* ASBatchContext.h */, 299DA1A81A828D2900162D41 /* ASBatchContext.mm */, + 251B8EF41BBB3D690087C538 /* ASCollectionViewFlowLayoutInspector.h */, + 251B8EF51BBB3D690087C538 /* ASCollectionViewFlowLayoutInspector.m */, 205F0E1B1B373A2C007741D0 /* ASCollectionViewLayoutController.h */, 205F0E1C1B373A2C007741D0 /* ASCollectionViewLayoutController.mm */, + 251B8EF61BBB3D690087C538 /* ASDataController+Subclasses.h */, 05A6D05819D0EB64002DD95E /* ASDealloc2MainObject.h */, 05A6D05919D0EB64002DD95E /* ASDealloc2MainObject.m */, + 698548611CA9E025008A345F /* ASEnvironment.h */, + 698548621CA9E025008A345F /* ASEnvironment.m */, 4640521B1A3F83C40061C0BA /* ASFlowLayoutController.h */, 4640521C1A3F83C40061C0BA /* ASFlowLayoutController.mm */, 058D09E6195D050800B7D73C /* ASHighlightOverlayLayer.h */, 058D09E7195D050800B7D73C /* ASHighlightOverlayLayer.mm */, + 05F20AA31A15733C00DCA68A /* ASImageProtocols.h */, 430E7C8D1B4C23F100697A4C /* ASIndexPath.h */, 430E7C8E1B4C23F100697A4C /* ASIndexPath.m */, - 05F20AA31A15733C00DCA68A /* ASImageProtocols.h */, 4640521D1A3F83C40061C0BA /* ASLayoutController.h */, 292C59991A956527007E5DD6 /* ASLayoutRangeType.h */, 68EE0DBB1C1B4ED300BA1B99 /* ASMainSerialQueue.h */, 68EE0DBC1C1B4ED300BA1B99 /* ASMainSerialQueue.mm */, 058D09E8195D050800B7D73C /* ASMutableAttributedStringBuilder.h */, 058D09E9195D050800B7D73C /* ASMutableAttributedStringBuilder.m */, + CC7FD9DC1BB5E962005CCB2B /* ASPhotosFrameworkImageRequest.h */, + CC7FD9DD1BB5E962005CCB2B /* ASPhotosFrameworkImageRequest.m */, 055F1A3619ABD413004DAFF1 /* ASRangeController.h */, 055F1A3719ABD413004DAFF1 /* ASRangeController.mm */, 69F10C851C84C35D0026140C /* ASRangeControllerUpdateRangeProtocol+Beta.h */, + 81EE384D1C8E94F000456208 /* ASRunLoopQueue.h */, + 81EE384E1C8E94F000456208 /* ASRunLoopQueue.mm */, 296A0A311A951715005ACEAA /* ASScrollDirection.h */, 205F0E111B371BD7007741D0 /* ASScrollDirection.m */, 058D0A12195D050800B7D73C /* ASThread.h */, 205F0E1F1B376416007741D0 /* CGRect+ASConvenience.h */, 205F0E201B376416007741D0 /* CGRect+ASConvenience.m */, + 25B171EA1C12242700508A7A /* Data Controller */, 058D09F5195D050800B7D73C /* NSMutableAttributedString+TextKitAdditions.h */, 058D09F6195D050800B7D73C /* NSMutableAttributedString+TextKitAdditions.m */, 058D09F7195D050800B7D73C /* Transactions */, @@ -1186,50 +1188,51 @@ 058D0A01195D050800B7D73C /* Private */ = { isa = PBXGroup; children = ( - DB55C25F1C6408D6004EDCF5 /* _ASTransitionContext.h */, - DB55C2601C6408D6004EDCF5 /* _ASTransitionContext.m */, - CC3B20811C3F76D600798563 /* ASPendingStateController.h */, - CC3B20821C3F76D600798563 /* ASPendingStateController.mm */, - CC3B20871C3F7A5400798563 /* ASWeakSet.h */, - CC3B20881C3F7A5400798563 /* ASWeakSet.m */, - AC026B6D1BD57DBF00BBC17E /* _ASHierarchyChangeSet.h */, - AC026B6E1BD57DBF00BBC17E /* _ASHierarchyChangeSet.m */, - 9C65A7291BA8EA4D0084DA91 /* ASLayoutOptionsPrivate.h */, - 9C8221931BA237B80037F19A /* ASStackBaselinePositionedLayout.h */, - 9C8221941BA237B80037F19A /* ASStackBaselinePositionedLayout.mm */, - 2967F9E11AB0A4CF0072E4AB /* ASBasicImageDownloaderInternal.h */, 058D0A02195D050800B7D73C /* _AS-objc-internal.h */, 058D0A03195D050800B7D73C /* _ASCoreAnimationExtras.h */, 058D0A04195D050800B7D73C /* _ASCoreAnimationExtras.mm */, + AC026B6D1BD57DBF00BBC17E /* _ASHierarchyChangeSet.h */, + AC026B6E1BD57DBF00BBC17E /* _ASHierarchyChangeSet.m */, 058D0A05195D050800B7D73C /* _ASPendingState.h */, 058D0A06195D050800B7D73C /* _ASPendingState.mm */, 058D0A07195D050800B7D73C /* _ASScopeTimer.h */, - 058D0A08195D050800B7D73C /* ASDisplayNode+AsyncDisplay.mm */, + DB55C25F1C6408D6004EDCF5 /* _ASTransitionContext.h */, + DB55C2601C6408D6004EDCF5 /* _ASTransitionContext.m */, + 2967F9E11AB0A4CF0072E4AB /* ASBasicImageDownloaderInternal.h */, 044285051BAA63FE00D16268 /* ASBatchFetching.h */, 044285061BAA63FE00D16268 /* ASBatchFetching.m */, + AEB7B0181C5962EA00662EF4 /* ASDefaultPlayButton.h */, + AEB7B0191C5962EA00662EF4 /* ASDefaultPlayButton.m */, + 058D0A08195D050800B7D73C /* ASDisplayNode+AsyncDisplay.mm */, 058D0A09195D050800B7D73C /* ASDisplayNode+DebugTiming.h */, 058D0A0A195D050800B7D73C /* ASDisplayNode+DebugTiming.mm */, - 058D0A0B195D050800B7D73C /* ASDisplayNode+UIViewBridge.mm */, DE6EA3211C14000600183B10 /* ASDisplayNode+FrameworkPrivate.h */, + 058D0A0B195D050800B7D73C /* ASDisplayNode+UIViewBridge.mm */, + 058D0A0C195D050800B7D73C /* ASDisplayNodeInternal.h */, E52405B41C8FEF16004DC8E7 /* ASDisplayNodeLayoutContext.h */, E52405B21C8FEF03004DC8E7 /* ASDisplayNodeLayoutContext.mm */, - 058D0A0C195D050800B7D73C /* ASDisplayNodeInternal.h */, + 69E100691CA89CB600D88C1B /* ASEnvironmentInternal.h */, + 69E1006A1CA89CB600D88C1B /* ASEnvironmentInternal.mm */, 058D0A0D195D050800B7D73C /* ASImageNode+CGExtras.h */, 058D0A0E195D050800B7D73C /* ASImageNode+CGExtras.m */, - 058D0A10195D050800B7D73C /* ASSentinel.h */, - 058D0A11195D050800B7D73C /* ASSentinel.m */, ACF6ED431B17847A00DA7C62 /* ASInternalHelpers.h */, ACF6ED441B17847A00DA7C62 /* ASInternalHelpers.mm */, ACF6ED451B17847A00DA7C62 /* ASLayoutSpecUtilities.h */, + 0442850B1BAA64EC00D16268 /* ASMultidimensionalArrayUtils.h */, + 0442850C1BAA64EC00D16268 /* ASMultidimensionalArrayUtils.mm */, + CC3B20811C3F76D600798563 /* ASPendingStateController.h */, + CC3B20821C3F76D600798563 /* ASPendingStateController.mm */, + 058D0A10195D050800B7D73C /* ASSentinel.h */, + 058D0A11195D050800B7D73C /* ASSentinel.m */, + 9C8221931BA237B80037F19A /* ASStackBaselinePositionedLayout.h */, + 9C8221941BA237B80037F19A /* ASStackBaselinePositionedLayout.mm */, ACF6ED461B17847A00DA7C62 /* ASStackLayoutSpecUtilities.h */, ACF6ED471B17847A00DA7C62 /* ASStackPositionedLayout.h */, ACF6ED481B17847A00DA7C62 /* ASStackPositionedLayout.mm */, ACF6ED491B17847A00DA7C62 /* ASStackUnpositionedLayout.h */, ACF6ED4A1B17847A00DA7C62 /* ASStackUnpositionedLayout.mm */, - 0442850B1BAA64EC00D16268 /* ASMultidimensionalArrayUtils.h */, - 0442850C1BAA64EC00D16268 /* ASMultidimensionalArrayUtils.mm */, - AEB7B0181C5962EA00662EF4 /* ASDefaultPlayButton.h */, - AEB7B0191C5962EA00662EF4 /* ASDefaultPlayButton.m */, + CC3B20871C3F7A5400798563 /* ASWeakSet.h */, + CC3B20881C3F7A5400798563 /* ASWeakSet.m */, DBC452D91C5BF64600B16017 /* NSArray+Diffing.h */, DBC452DA1C5BF64600B16017 /* NSArray+Diffing.m */, ); @@ -1338,9 +1341,6 @@ 9C6BB3B01B8CC9C200F13F52 /* ASStaticLayoutable.h */, ACF6ED181B17843500DA7C62 /* ASStaticLayoutSpec.h */, ACF6ED191B17843500DA7C62 /* ASStaticLayoutSpec.mm */, - 9C5FA34F1B8F6ADF00A62714 /* ASLayoutOptions.h */, - 9C5FA3501B8F6ADF00A62714 /* ASLayoutOptions.mm */, - 9C5FA35C1B90C9A500A62714 /* ASLayoutOptionsPrivate.mm */, ); name = Layout; path = ..; @@ -1379,6 +1379,7 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( + 698548631CA9E025008A345F /* ASEnvironment.h in Headers */, E5711A2B1C840C81009619D4 /* ASIndexedNodeContext.h in Headers */, 257754C21BEE458E00737CA5 /* ASTextKitCoreTextAdditions.h in Headers */, A373200F1C571B730011FC94 /* ASTextNode+Beta.h in Headers */, @@ -1462,8 +1463,6 @@ 9CDC18CC1B910E12004965E2 /* ASLayoutablePrivate.h in Headers */, B0F8805A1BEAEC7500D17647 /* ASTableNode.h in Headers */, 464052241A3F83C40061C0BA /* ASLayoutController.h in Headers */, - 9C5FA3511B8F6ADF00A62714 /* ASLayoutOptions.h in Headers */, - 9C65A72A1BA8EA4D0084DA91 /* ASLayoutOptionsPrivate.h in Headers */, 292C599F1A956527007E5DD6 /* ASLayoutRangeType.h in Headers */, 257754B61BEE44CD00737CA5 /* ASEqualityHashHelpers.h in Headers */, ACF6ED261B17843500DA7C62 /* ASLayoutSpec.h in Headers */, @@ -1487,6 +1486,7 @@ 9C8221951BA237B80037F19A /* ASStackBaselinePositionedLayout.h in Headers */, 257754C31BEE458E00737CA5 /* ASTextNodeTypes.h in Headers */, 9C49C36F1B853957000B0DD5 /* ASStackLayoutable.h in Headers */, + 69E1006D1CA89CB600D88C1B /* ASEnvironmentInternal.h in Headers */, AC21EC101B3D0BF600C8B19A /* ASStackLayoutDefines.h in Headers */, CC7FD9DE1BB5E962005CCB2B /* ASPhotosFrameworkImageRequest.h in Headers */, ACF6ED2F1B17843500DA7C62 /* ASStackLayoutSpec.h in Headers */, @@ -1522,6 +1522,7 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( + 698548641CA9E025008A345F /* ASEnvironment.h in Headers */, AC026B6A1BD57D6F00BBC17E /* ASChangeSetDataController.h in Headers */, B35062481B010EFD0018CF92 /* _AS-objc-internal.h in Headers */, 69F10C871C84C35D0026140C /* ASRangeControllerUpdateRangeProtocol+Beta.h in Headers */, @@ -1598,8 +1599,6 @@ 34EFC7691B701CE100AD841F /* ASLayoutable.h in Headers */, 9CDC18CD1B910E12004965E2 /* ASLayoutablePrivate.h in Headers */, B35062201B010EFD0018CF92 /* ASLayoutController.h in Headers */, - 9C5FA3521B8F6ADF00A62714 /* ASLayoutOptions.h in Headers */, - 9C65A72B1BA8EA4D0084DA91 /* ASLayoutOptionsPrivate.h in Headers */, B35062211B010EFD0018CF92 /* ASLayoutRangeType.h in Headers */, 34EFC76A1B701CE600AD841F /* ASLayoutSpec.h in Headers */, 34EFC7791B701D3600AD841F /* ASLayoutSpecUtilities.h in Headers */, @@ -1640,6 +1639,7 @@ 92DD2FE81BF4D0A80074C9DD /* ASMapNode.h in Headers */, 044284FE1BAA387800D16268 /* ASStackLayoutSpecUtilities.h in Headers */, 34EFC7751B701D2400AD841F /* ASStackPositionedLayout.h in Headers */, + 69E1006E1CA89CB600D88C1B /* ASEnvironmentInternal.h in Headers */, 34EFC7771B701D2D00AD841F /* ASStackUnpositionedLayout.h in Headers */, 9C6BB3B31B8CC9C200F13F52 /* ASStaticLayoutable.h in Headers */, 34EFC7731B701D0700AD841F /* ASStaticLayoutSpec.h in Headers */, @@ -1872,6 +1872,7 @@ DBDB83961C6E879900D0098C /* ASPagerFlowLayout.m in Sources */, 058D0A26195D050800B7D73C /* _ASCoreAnimationExtras.mm in Sources */, 257754B41BEE44CD00737CA5 /* ASTextKitTailTruncater.mm in Sources */, + 69E1006F1CA89CB600D88C1B /* ASEnvironmentInternal.mm in Sources */, AC026B711BD57DBF00BBC17E /* _ASHierarchyChangeSet.m in Sources */, 257754BF1BEE458E00737CA5 /* ASTextKitCoreTextAdditions.m in Sources */, 058D0A18195D050800B7D73C /* _ASDisplayLayer.mm in Sources */, @@ -1915,10 +1916,9 @@ 430E7C911B4C23F100697A4C /* ASIndexPath.m in Sources */, ACF6ED231B17843500DA7C62 /* ASInsetLayoutSpec.mm in Sources */, ACF6ED4C1B17847A00DA7C62 /* ASInternalHelpers.mm in Sources */, + 698548651CA9E025008A345F /* ASEnvironment.m in Sources */, ACF6ED251B17843500DA7C62 /* ASLayout.mm in Sources */, DB55C2631C6408D6004EDCF5 /* _ASTransitionContext.m in Sources */, - 9C5FA3531B8F6ADF00A62714 /* ASLayoutOptions.mm in Sources */, - 9C5FA35F1B90C9A500A62714 /* ASLayoutOptionsPrivate.mm in Sources */, 251B8EFA1BBB3D690087C538 /* ASCollectionViewFlowLayoutInspector.m in Sources */, ACF6ED271B17843500DA7C62 /* ASLayoutSpec.mm in Sources */, 257754B01BEE44CD00737CA5 /* ASTextKitRenderer+TextChecking.mm in Sources */, @@ -2026,6 +2026,7 @@ B35062421B010EFD0018CF92 /* _ASAsyncTransactionGroup.m in Sources */, B350624A1B010EFD0018CF92 /* _ASCoreAnimationExtras.mm in Sources */, 68EE0DC01C1B4ED300BA1B99 /* ASMainSerialQueue.mm in Sources */, + 698548661CA9E025008A345F /* ASEnvironment.m in Sources */, 2767E9421BB19BD600EA9B77 /* ASViewController.m in Sources */, B35062101B010EFD0018CF92 /* _ASDisplayLayer.mm in Sources */, 9C55866B1BD54A1900B50E3A /* ASAsciiArtBoxCreator.m in Sources */, @@ -2055,6 +2056,7 @@ 636EA1A41C7FF4EC00EE152F /* NSArray+Diffing.m in Sources */, B35062501B010EFD0018CF92 /* ASDisplayNode+DebugTiming.mm in Sources */, DEC146B91C37A16A004A0EE7 /* ASCollectionInternal.m in Sources */, + 69E100701CA89CB600D88C1B /* ASEnvironmentInternal.mm in Sources */, 254C6B891BF94F8A003EC431 /* ASTextKitRenderer+Positioning.mm in Sources */, E5711A301C840C96009619D4 /* ASIndexedNodeContext.m in Sources */, B35062511B010EFD0018CF92 /* ASDisplayNode+UIViewBridge.mm in Sources */, @@ -2072,8 +2074,6 @@ 34EFC7601B701C8B00AD841F /* ASInsetLayoutSpec.mm in Sources */, 34EFC75E1B701BF000AD841F /* ASInternalHelpers.mm in Sources */, 34EFC7681B701CDE00AD841F /* ASLayout.mm in Sources */, - 9C5FA3541B8F6ADF00A62714 /* ASLayoutOptions.mm in Sources */, - 9C5FA3601B90C9A500A62714 /* ASLayoutOptionsPrivate.mm in Sources */, DECBD6EA1BE56E1900CF4905 /* ASButtonNode.mm in Sources */, 254C6B841BF94F8A003EC431 /* ASTextNodeWordKerner.m in Sources */, 34EFC76B1B701CEB00AD841F /* ASLayoutSpec.mm in Sources */, diff --git a/AsyncDisplayKit/ASDisplayNode.mm b/AsyncDisplayKit/ASDisplayNode.mm index b08e64a2f9..febf735ff0 100644 --- a/AsyncDisplayKit/ASDisplayNode.mm +++ b/AsyncDisplayKit/ASDisplayNode.mm @@ -10,7 +10,6 @@ #import "ASDisplayNode+Subclasses.h" #import "ASDisplayNode+FrameworkPrivate.h" #import "ASDisplayNode+Beta.h" -#import "ASLayoutOptionsPrivate.h" #import #import @@ -25,6 +24,7 @@ #import "ASDisplayNodeExtras.h" #import "ASEqualityHelpers.h" #import "ASRunLoopQueue.h" +#import "ASEnvironment.h" #import "ASInternalHelpers.h" #import "ASLayout.h" @@ -60,7 +60,7 @@ NSString * const ASRenderingEngineDidDisplayNodesScheduledBeforeTimestamp = @"AS @implementation ASDisplayNode // these dynamic properties all defined in ASLayoutOptionsPrivate.m -@dynamic spacingAfter, spacingBefore, flexGrow, flexShrink, flexBasis, alignSelf, ascender, descender, sizeRange, layoutPosition, layoutOptions; +@dynamic spacingAfter, spacingBefore, flexGrow, flexShrink, flexBasis, alignSelf, ascender, descender, sizeRange, layoutPosition; @synthesize name = _name; @synthesize preferredFrameSize = _preferredFrameSize; @synthesize isFinalLayoutable = _isFinalLayoutable; @@ -252,6 +252,9 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c) _contentsScaleForDisplay = ASScreenScale(); _displaySentinel = [[ASSentinel alloc] init]; _preferredFrameSize = CGSizeZero; + + _environmentCollection = ASEnvironmentCollectionCreate(); + ASLayoutableSetValuesForLayoutable(self); } - (id)init @@ -1855,6 +1858,7 @@ void recursivelyTriggerDisplayForLayer(CALayer *layer, BOOL shouldBlock) if (_methodOverrides & ASDisplayNodeMethodOverrideLayoutSpecThatFits) { ASLayoutSpec *layoutSpec = [self layoutSpecThatFits:constrainedSize]; layoutSpec.isMutable = NO; + layoutSpec.parent = self; ASLayout *layout = [layoutSpec measureWithSizeRange:constrainedSize]; // Make sure layoutableObject of the root layout is `self`, so that the flattened layout will be structurally correct. if (layout.layoutableObject != self) { @@ -2666,6 +2670,33 @@ static const char *ASDisplayNodeDrawingPriorityKey = "ASDrawingPriority"; return self; } +#pragma mark - ASEnvironment + +- (ASEnvironmentCollection *)environmentCollection +{ + return &_environmentCollection; +} + +- (ASDisplayNode *)parent +{ + return self.supernode; +} + +- (void)setParent:(ASDisplayNode *)parent +{ + [self __setSupernode:parent]; +} + +- (NSArray *)children +{ + return self.subnodes; +} + +- (BOOL)supportsMultipleChildren +{ + return NO; +} + #if TARGET_OS_TV #pragma mark - UIFocusEnvironment Protocol (tvOS) diff --git a/AsyncDisplayKit/AsyncDisplayKit.h b/AsyncDisplayKit/AsyncDisplayKit.h index 1c94faffbf..6e11c23a55 100644 --- a/AsyncDisplayKit/AsyncDisplayKit.h +++ b/AsyncDisplayKit/AsyncDisplayKit.h @@ -41,6 +41,7 @@ #import #import +#import #import #import #import @@ -68,7 +69,6 @@ #import #import #import -#import #import #import #import diff --git a/AsyncDisplayKit/Details/ASEnvironment.h b/AsyncDisplayKit/Details/ASEnvironment.h new file mode 100644 index 0000000000..7229a166ea --- /dev/null +++ b/AsyncDisplayKit/Details/ASEnvironment.h @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2014-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + +#import + +#import "ASDimension.h" +#import "ASStackLayoutDefines.h" +#import "ASRelativeSize.h" + + +ASDISPLAYNODE_EXTERN_C_BEGIN +NS_ASSUME_NONNULL_BEGIN + + +#pragma mark ASEnvironmentLayoutOptionsState + +typedef struct ASEnvironmentLayoutOptionsState { + CGFloat spacingBefore;// = 0; + CGFloat spacingAfter;// = 0; + BOOL flexGrow;// = NO; + BOOL flexShrink;// = NO; + ASRelativeDimension flexBasis;// = ASRelativeDimensionUnconstrained; + ASStackLayoutAlignSelf alignSelf;// = ASStackLayoutAlignSelfAuto; + CGFloat ascender;// = 0; + CGFloat descender;// = 0; + + ASRelativeSizeRange sizeRange;// = ASRelativeSizeRangeMake(ASRelativeSizeMakeWithCGSize(CGSizeZero), ASRelativeSizeMakeWithCGSize(CGSizeZero));; + CGPoint layoutPosition;// = CGPointZero; + + // TODO: ASEnvironment: find a good way to expand the options state + // id otherOptions; +} ASEnvironmentLayoutOptionsState; +extern ASEnvironmentLayoutOptionsState ASEnvironmentLayoutOptionsStateCreate(); + + +#pragma mark ASEnvironmentHierarchyState + +typedef struct ASEnvironmentHierarchyState { + unsigned rasterized:1; // = NO + unsigned rangeManaged:1; // = NO + unsigned transitioningSupernodes:1; // = NO + unsigned layoutPending:1; // = NO +} ASEnvironmentHierarchyState; +extern ASEnvironmentHierarchyState ASEnvironmentHierarchyStateCreate(); + + +#pragma mark ASEnvironmentCollection + +typedef struct ASEnvironmentCollection { + struct ASEnvironmentHierarchyState hierarchyState; + struct ASEnvironmentLayoutOptionsState layoutOptionsState; +} ASEnvironmentCollection; +extern ASEnvironmentCollection ASEnvironmentCollectionCreate(); + +ASDISPLAYNODE_EXTERN_C_END + + +#pragma mark - ASEnvironment + +/** + * ASEnvironment allows objects that conform to the ASEnvironment protocol to be able to propagate specific States + * defined in an ASEnvironmentCollection up and down the ASEnvironment tree. To be able to define how merges of + * States should happen, specific merge functions can be provided + */ +@protocol ASEnvironment + +/// The environment collection of an object which class conforms to the ASEnvironment protocol +- (ASEnvironmentCollection *)environmentCollection; + +/// Returns the parent of an object which class conforms to the ASEnvironment protocol +- (id)parent; + +/// Set the parent of an object which class conforms to the ASEnvironment protocol +- (void)setParent:(id)parent; + +/// Returns all children of an object which class conforms to the ASEnvironment protocol +- (NSArray> *)children; + +// TODO: ASEnvironment: Find a better name. As in ASDisplayNode this returns NO which in theory is wrong as as +// it supports multiple subnodes +- (BOOL)supportsMultipleChildren; + +@end + +NS_ASSUME_NONNULL_END \ No newline at end of file diff --git a/AsyncDisplayKit/Details/ASEnvironment.m b/AsyncDisplayKit/Details/ASEnvironment.m new file mode 100644 index 0000000000..e08795a7b3 --- /dev/null +++ b/AsyncDisplayKit/Details/ASEnvironment.m @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2014-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + +#import "ASEnvironment.h" + +ASEnvironmentLayoutOptionsState ASEnvironmentLayoutOptionsStateCreate() +{ + return (ASEnvironmentLayoutOptionsState) { + .spacingBefore = 0, + .flexBasis = ASRelativeDimensionUnconstrained, + .alignSelf = ASStackLayoutAlignSelfAuto, + + .sizeRange = ASRelativeSizeRangeMake(ASRelativeSizeMakeWithCGSize(CGSizeZero), ASRelativeSizeMakeWithCGSize(CGSizeZero)), + .layoutPosition = CGPointZero + }; +} + +ASEnvironmentHierarchyState ASEnvironmentHierarchyStateCreate() +{ + return (ASEnvironmentHierarchyState) { + .rasterized = NO, + .rangeManaged = NO, + .transitioningSupernodes = NO, + .layoutPending = NO + }; +} + +ASEnvironmentCollection ASEnvironmentCollectionCreate() +{ + return (ASEnvironmentCollection) { + .hierarchyState = ASEnvironmentHierarchyStateCreate(), + .layoutOptionsState = ASEnvironmentLayoutOptionsStateCreate() + }; +} \ No newline at end of file diff --git a/AsyncDisplayKit/Layout/ASLayoutOptions.h b/AsyncDisplayKit/Layout/ASLayoutOptions.h deleted file mode 100644 index fbc50bf8e3..0000000000 --- a/AsyncDisplayKit/Layout/ASLayoutOptions.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (c) 2014-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - */ - -#import -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -@protocol ASLayoutable; - -/** - * A store for all of the options defined by ASLayoutSpec subclasses. All implementors of ASLayoutable own a - * ASLayoutOptions. When certain layoutSpecs need option values, they are read from this class. - * - * Unless you wish to create a custom layout spec, ASLayoutOptions can largely be ignored. Instead you can access - * the layout option properties exposed in ASLayoutable directly, which will set the values in ASLayoutOptions - * behind the scenes. - */ -@interface ASLayoutOptions : NSObject - -/** - * Sets the class name for the ASLayoutOptions subclasses that will be created when a node or layoutSpec's options - * are first accessed. - * - * If you create a custom layoutSpec that includes new options, you will want to subclass ASLayoutOptions to add - * the new layout options for your layoutSpec(s). In order to make sure your subclass is created instead of an - * instance of ASLayoutOptions, call setDefaultLayoutOptionsClass: early in app launch (applicationDidFinishLaunching:) - * with your subclass's class. - * - * @param defaultLayoutOptionsClass The class of ASLayoutOptions that will be lazily created for a node or layout spec. - */ -+ (void)setDefaultLayoutOptionsClass:(Class)defaultLayoutOptionsClass; - -/** - * @return the Class of ASLayoutOptions that will be created for a node or layoutspec. Defaults to [ASLayoutOptions class]; - */ -+ (Class)defaultLayoutOptionsClass; - -#pragma mark - Subclasses should implement these! -/** - * Initializes a new ASLayoutOptions using the given layoutable to assign any intrinsic option values. - * This init function sets a sensible default value for each layout option. If you create a subclass of - * ASLayoutOptions, your subclass should do the same. - * - * @param layoutable The layoutable that will own these options. The layoutable will be used to set any intrinsic - * layoutOptions. For example, if the layoutable is an ASTextNode the ascender/descender values will get set. - * - * @return a new instance of ASLayoutOptions - */ -- (instancetype)initWithLayoutable:(id)layoutable; - -/** - * Copies the values of layoutOptions into self. This is useful when placing a layoutable inside of another. Consider - * an ASTextNode that you want to align to the baseline by putting it in an ASStackLayoutSpec. Before that, you want - * to inset the ASTextNode by placing it in an ASInsetLayoutSpec. An ASInsetLayoutSpec will not have any information - * about the ASTextNode's ascender/descender unless we copy over the layout options from ASTextNode to ASInsetLayoutSpec. - * This is done automatically and should not need to be called directly. It is listed here to make sure that any - * ASLayoutOptions subclass implements the method. - * - * @param layoutOptions The layoutOptions to copy from - */ -- (void)copyFromOptions:(ASLayoutOptions *)layoutOptions; - -#pragma mark - ASStackLayoutable - -@property (nonatomic, readwrite) CGFloat spacingBefore; -@property (nonatomic, readwrite) CGFloat spacingAfter; -@property (nonatomic, readwrite) BOOL flexGrow; -@property (nonatomic, readwrite) BOOL flexShrink; -@property (nonatomic, readwrite) ASRelativeDimension flexBasis; -@property (nonatomic, readwrite) ASStackLayoutAlignSelf alignSelf; -@property (nonatomic, readwrite) CGFloat ascender; -@property (nonatomic, readwrite) CGFloat descender; - -#pragma mark - ASStaticLayoutable - -@property (nonatomic, readwrite) ASRelativeSizeRange sizeRange; -@property (nonatomic, readwrite) CGPoint layoutPosition; - -@end - -NS_ASSUME_NONNULL_END - diff --git a/AsyncDisplayKit/Layout/ASLayoutOptions.mm b/AsyncDisplayKit/Layout/ASLayoutOptions.mm deleted file mode 100644 index ad503014bf..0000000000 --- a/AsyncDisplayKit/Layout/ASLayoutOptions.mm +++ /dev/null @@ -1,263 +0,0 @@ -/* - * Copyright (c) 2014-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - */ - -#import "ASLayoutOptions.h" - -#import -#import -#import -#import "ASInternalHelpers.h" - -@interface ASLayoutOptions() -{ - ASDN::RecursiveMutex _propertyLock; -} -@end - -@implementation ASLayoutOptions - -@synthesize spacingBefore = _spacingBefore; -@synthesize spacingAfter = _spacingAfter; -@synthesize flexGrow = _flexGrow; -@synthesize flexShrink = _flexShrink; -@synthesize flexBasis = _flexBasis; -@synthesize alignSelf = _alignSelf; - -@synthesize ascender = _ascender; -@synthesize descender = _descender; - -@synthesize sizeRange = _sizeRange; -@synthesize layoutPosition = _layoutPosition; - -static Class gDefaultLayoutOptionsClass = nil; -+ (void)setDefaultLayoutOptionsClass:(Class)defaultLayoutOptionsClass -{ - gDefaultLayoutOptionsClass = defaultLayoutOptionsClass; -} - -+ (Class)defaultLayoutOptionsClass -{ - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - if (gDefaultLayoutOptionsClass == nil) { - // If someone is asking for this and it hasn't been customized yet, use the default. - gDefaultLayoutOptionsClass = [ASLayoutOptions class]; - } - }); - return gDefaultLayoutOptionsClass; -} - -- (instancetype)init -{ - return nil; -} - -- (instancetype)initWithLayoutable:(id)layoutable -{ - self = [super init]; - if (self) { - - self.flexBasis = ASRelativeDimensionUnconstrained; - self.sizeRange = ASRelativeSizeRangeMake(ASRelativeSizeMakeWithCGSize(CGSizeZero), ASRelativeSizeMakeWithCGSize(CGSizeZero)); - self.layoutPosition = CGPointZero; - - // The following properties use a default value of 0 which we do not need to assign. - // self.spacingBefore = 0; - // self.spacingAfter = 0; - // self.flexGrow = NO; - // self.flexShrink = NO; - // self.alignSelf = ASStackLayoutAlignSelfAuto; - // self.ascender = 0; - // self.descender = 0; - - [self setValuesFromLayoutable:layoutable]; - } - return self; -} - -#pragma mark - NSCopying -- (id)copyWithZone:(NSZone *)zone -{ - ASLayoutOptions *copy = [[[self class] alloc] init]; - [copy copyFromOptions:self]; - return copy; -} - -- (void)copyFromOptions:(ASLayoutOptions *)layoutOptions -{ - ASDN::MutexLocker l(_propertyLock); - self.flexBasis = layoutOptions.flexBasis; - self.spacingAfter = layoutOptions.spacingAfter; - self.spacingBefore = layoutOptions.spacingBefore; - self.flexGrow = layoutOptions.flexGrow; - self.flexShrink = layoutOptions.flexShrink; - self.alignSelf = layoutOptions.alignSelf; - - self.ascender = layoutOptions.ascender; - self.descender = layoutOptions.descender; - - self.sizeRange = layoutOptions.sizeRange; - self.layoutPosition = layoutOptions.layoutPosition; -} - -/** - * Given an id, set up layout options that are intrinsically defined by the layoutable. - * - * While this could be done in the layoutable object itself, moving the logic into the ASLayoutOptions class - * allows a custom spec to set up defaults without needing to alter the layoutable itself. For example, - * image you were creating a custom baseline spec that needed ascender/descender. To assign values automatically - * when a text node's attribute string is set, you would need to subclass ASTextNode and assign the values in the - * override of setAttributeString. However, assigning the defaults in an ASLayoutOptions subclass's - * setValuesFromLayoutable allows you to create a custom spec without the need to create a - * subclass of ASTextNode. - * - * @param layoutable The layoutable object to inspect for default intrinsic layout option values - */ -- (void)setValuesFromLayoutable:(id)layoutable -{ - ASDN::MutexLocker l(_propertyLock); - if ([layoutable isKindOfClass:[ASDisplayNode class]]) { - ASDisplayNode *displayNode = (ASDisplayNode *)layoutable; - self.sizeRange = ASRelativeSizeRangeMake(ASRelativeSizeMakeWithCGSize(displayNode.preferredFrameSize), ASRelativeSizeMakeWithCGSize(displayNode.preferredFrameSize)); - - if ([layoutable isKindOfClass:[ASTextNode class]]) { - ASTextNode *textNode = (ASTextNode *)layoutable; - NSAttributedString *attributedString = textNode.attributedString; - if (attributedString.length > 0) { - CGFloat screenScale = ASScreenScale(); - self.ascender = round([[attributedString attribute:NSFontAttributeName atIndex:0 effectiveRange:NULL] ascender] * screenScale)/screenScale; - self.descender = round([[attributedString attribute:NSFontAttributeName atIndex:attributedString.length - 1 effectiveRange:NULL] descender] * screenScale)/screenScale; - } - } - - } -} - -- (CGFloat)spacingAfter -{ - ASDN::MutexLocker l(_propertyLock); - return _spacingAfter; -} - -- (void)setSpacingAfter:(CGFloat)spacingAfter -{ - ASDN::MutexLocker l(_propertyLock); - _spacingAfter = spacingAfter; -} - -- (CGFloat)spacingBefore -{ - ASDN::MutexLocker l(_propertyLock); - return _spacingBefore; -} - -- (void)setSpacingBefore:(CGFloat)spacingBefore -{ - ASDN::MutexLocker l(_propertyLock); - _spacingBefore = spacingBefore; -} - -- (BOOL)flexGrow -{ - ASDN::MutexLocker l(_propertyLock); - return _flexGrow; -} - -- (void)setFlexGrow:(BOOL)flexGrow -{ - ASDN::MutexLocker l(_propertyLock); - _flexGrow = flexGrow; -} - -- (BOOL)flexShrink -{ - ASDN::MutexLocker l(_propertyLock); - return _flexShrink; -} - -- (void)setFlexShrink:(BOOL)flexShrink -{ - ASDN::MutexLocker l(_propertyLock); - _flexShrink = flexShrink; -} - -- (ASRelativeDimension)flexBasis -{ - ASDN::MutexLocker l(_propertyLock); - return _flexBasis; -} - -- (void)setFlexBasis:(ASRelativeDimension)flexBasis -{ - ASDN::MutexLocker l(_propertyLock); - _flexBasis = flexBasis; -} - -- (ASStackLayoutAlignSelf)alignSelf -{ - ASDN::MutexLocker l(_propertyLock); - return _alignSelf; -} - -- (void)setAlignSelf:(ASStackLayoutAlignSelf)alignSelf -{ - ASDN::MutexLocker l(_propertyLock); - _alignSelf = alignSelf; -} - -- (CGFloat)ascender -{ - ASDN::MutexLocker l(_propertyLock); - return _ascender; -} - -- (void)setAscender:(CGFloat)ascender -{ - ASDN::MutexLocker l(_propertyLock); - _ascender = ascender; -} - -- (CGFloat)descender -{ - ASDN::MutexLocker l(_propertyLock); - return _descender; -} - -- (void)setDescender:(CGFloat)descender -{ - ASDN::MutexLocker l(_propertyLock); - _descender = descender; -} - -- (ASRelativeSizeRange)sizeRange -{ - ASDN::MutexLocker l(_propertyLock); - return _sizeRange; -} - -- (void)setSizeRange:(ASRelativeSizeRange)sizeRange -{ - ASDN::MutexLocker l(_propertyLock); - _sizeRange = sizeRange; -} - -- (CGPoint)layoutPosition -{ - ASDN::MutexLocker l(_propertyLock); - return _layoutPosition; -} - -- (void)setLayoutPosition:(CGPoint)layoutPosition -{ - ASDN::MutexLocker l(_propertyLock); - _layoutPosition = layoutPosition; -} - -@end diff --git a/AsyncDisplayKit/Layout/ASLayoutOptionsPrivate.mm b/AsyncDisplayKit/Layout/ASLayoutOptionsPrivate.mm deleted file mode 100644 index 334f42f1a5..0000000000 --- a/AsyncDisplayKit/Layout/ASLayoutOptionsPrivate.mm +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright (c) 2014-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - */ - -#import "ASLayoutOptionsPrivate.h" -#import - - -/** - * Both an ASDisplayNode and an ASLayoutSpec conform to ASLayoutable. There are several properties - * in ASLayoutable that are used as layoutOptions when a node or spec is used in a layout spec. - * These properties are provided for convenience, as they are forwards to the node or spec's - * ASLayoutOptions class. Instead of duplicating the property forwarding in both classes, we - * create a define that allows us to easily implement the forwards in one place. - * - * If you create a custom layout spec, we recommend this stragety if you decide to extend - * ASDisplayNode and ASLayoutSpec to provide convenience properties for any options that your - * layoutSpec may require. - */ -#define ASLayoutOptionsForwarding \ -- (ASLayoutOptions *)layoutOptions\ -{\ -ASDN::MutexLocker l(_layoutOptionsLock);\ -if (_layoutOptions == nil) {\ -_layoutOptions = [[[ASLayoutOptions defaultLayoutOptionsClass] alloc] initWithLayoutable:self];\ -}\ -return _layoutOptions;\ -}\ -\ -- (CGFloat)spacingBefore\ -{\ -return self.layoutOptions.spacingBefore;\ -}\ -\ -- (void)setSpacingBefore:(CGFloat)spacingBefore\ -{\ -self.layoutOptions.spacingBefore = spacingBefore;\ -}\ -\ -- (CGFloat)spacingAfter\ -{\ -return self.layoutOptions.spacingAfter;\ -}\ -\ -- (void)setSpacingAfter:(CGFloat)spacingAfter\ -{\ -self.layoutOptions.spacingAfter = spacingAfter;\ -}\ -\ -- (BOOL)flexGrow\ -{\ -return self.layoutOptions.flexGrow;\ -}\ -\ -- (void)setFlexGrow:(BOOL)flexGrow\ -{\ -self.layoutOptions.flexGrow = flexGrow;\ -}\ -\ -- (BOOL)flexShrink\ -{\ -return self.layoutOptions.flexShrink;\ -}\ -\ -- (void)setFlexShrink:(BOOL)flexShrink\ -{\ -self.layoutOptions.flexShrink = flexShrink;\ -}\ -\ -- (ASRelativeDimension)flexBasis\ -{\ -return self.layoutOptions.flexBasis;\ -}\ -\ -- (void)setFlexBasis:(ASRelativeDimension)flexBasis\ -{\ -self.layoutOptions.flexBasis = flexBasis;\ -}\ -\ -- (ASStackLayoutAlignSelf)alignSelf\ -{\ -return self.layoutOptions.alignSelf;\ -}\ -\ -- (void)setAlignSelf:(ASStackLayoutAlignSelf)alignSelf\ -{\ - self.layoutOptions.alignSelf = alignSelf;\ -}\ -\ -- (CGFloat)ascender\ -{\ - return self.layoutOptions.ascender;\ -}\ -\ -- (void)setAscender:(CGFloat)ascender\ -{\ - self.layoutOptions.ascender = ascender;\ -}\ -\ -- (CGFloat)descender\ -{\ - return self.layoutOptions.descender;\ -}\ -\ -- (void)setDescender:(CGFloat)descender\ -{\ - self.layoutOptions.descender = descender;\ -}\ -\ -- (ASRelativeSizeRange)sizeRange\ -{\ - return self.layoutOptions.sizeRange;\ -}\ -\ -- (void)setSizeRange:(ASRelativeSizeRange)sizeRange\ -{\ - self.layoutOptions.sizeRange = sizeRange;\ -}\ -\ -- (CGPoint)layoutPosition\ -{\ - return self.layoutOptions.layoutPosition;\ -}\ -\ -- (void)setLayoutPosition:(CGPoint)position\ -{\ - self.layoutOptions.layoutPosition = position;\ -}\ - - -@implementation ASDisplayNode(ASLayoutOptions) -ASLayoutOptionsForwarding -@end - -@implementation ASLayoutSpec(ASLayoutOptions) -ASLayoutOptionsForwarding -@end diff --git a/AsyncDisplayKit/Layout/ASLayoutSpec.mm b/AsyncDisplayKit/Layout/ASLayoutSpec.mm index abb428ebd1..d0b1b7ba48 100644 --- a/AsyncDisplayKit/Layout/ASLayoutSpec.mm +++ b/AsyncDisplayKit/Layout/ASLayoutSpec.mm @@ -8,29 +8,33 @@ * */ -#import "ASLayoutOptionsPrivate.h" +#import "ASLayoutSpec.h" #import "ASAssert.h" #import "ASBaseDefines.h" +#import "ASEnvironmentInternal.h" #import "ASInternalHelpers.h" #import "ASLayout.h" -#import "ASLayoutOptions.h" #import "ASThread.h" + #import static NSString * const kDefaultChildKey = @"kDefaultChildKey"; static NSString * const kDefaultChildrenKey = @"kDefaultChildrenKey"; -@interface ASLayoutSpec() +@interface ASLayoutSpec() { + ASEnvironmentCollection _environmentCollection; +} +@property (nonatomic, weak) id parent; @property (nonatomic, strong) NSMutableDictionary *layoutChildren; @end @implementation ASLayoutSpec // these dynamic properties all defined in ASLayoutOptionsPrivate.m -@dynamic spacingAfter, spacingBefore, flexGrow, flexShrink, flexBasis, alignSelf, ascender, descender, sizeRange, layoutPosition, layoutOptions; +@dynamic spacingAfter, spacingBefore, flexGrow, flexShrink, flexBasis, alignSelf, ascender, descender, sizeRange, layoutPosition; @synthesize layoutChildren = _layoutChildren; @synthesize isFinalLayoutable = _isFinalLayoutable; @@ -40,6 +44,9 @@ static NSString * const kDefaultChildrenKey = @"kDefaultChildrenKey"; return nil; } _isMutable = YES; + _environmentCollection = ASEnvironmentCollectionCreate(); + ASLayoutableSetValuesForLayoutable(self); + return self; } @@ -75,7 +82,8 @@ static NSString * const kDefaultChildrenKey = @"kDefaultChildrenKey"; id finalLayoutable = [child finalLayoutable]; if (finalLayoutable != child) { - [finalLayoutable.layoutOptions copyFromOptions:child.layoutOptions]; + // Copy layout options + finalLayoutable.environmentCollection->layoutOptionsState = child.environmentCollection->layoutOptionsState; return finalLayoutable; } } @@ -90,6 +98,15 @@ static NSString * const kDefaultChildrenKey = @"kDefaultChildrenKey"; return _layoutChildren; } +- (void)setParent:(id)parent +{ + _parent = parent; + + if (![parent supportsMultipleChildren]) { + ASEnvironmentStatePropagateUp(parent, self.environmentCollection->layoutOptionsState); + } +} + - (void)setChild:(id)child; { [self setChild:child forIdentifier:kDefaultChildKey]; @@ -128,6 +145,19 @@ static NSString * const kDefaultChildrenKey = @"kDefaultChildrenKey"; return self.layoutChildren[kDefaultChildrenKey]; } + +#pragma mark - ASEnvironment + +- (ASEnvironmentCollection *)environmentCollection +{ + return &_environmentCollection; +} + +- (BOOL)supportsMultipleChildren +{ + return NO; +} + @end @implementation ASLayoutSpec (Debugging) diff --git a/AsyncDisplayKit/Layout/ASLayoutable.h b/AsyncDisplayKit/Layout/ASLayoutable.h index 121477b1f6..11553674f4 100644 --- a/AsyncDisplayKit/Layout/ASLayoutable.h +++ b/AsyncDisplayKit/Layout/ASLayoutable.h @@ -15,6 +15,7 @@ #import #import +#import @class ASLayout; @class ASLayoutSpec; @@ -37,7 +38,7 @@ NS_ASSUME_NONNULL_BEGIN * access to the options via convenience properties. If you are creating custom layout spec, then you can * extend the backing layout options class to accommodate any new layout options. */ -@protocol ASLayoutable +@protocol ASLayoutable /** * @abstract Calculate a layout based on given size range. diff --git a/AsyncDisplayKit/Layout/ASLayoutable.mm b/AsyncDisplayKit/Layout/ASLayoutable.mm index 78aeb9bc12..6bdfdbe758 100644 --- a/AsyncDisplayKit/Layout/ASLayoutable.mm +++ b/AsyncDisplayKit/Layout/ASLayoutable.mm @@ -7,6 +7,12 @@ // #import "ASLayoutablePrivate.h" +#import "ASInternalHelpers.h" +#import "ASEnvironmentInternal.h" +#import "ASDisplayNodeInternal.h" +#import "ASTextNode.h" +#import "ASLayoutSpec.h" + #import "pthread.h" #import #import @@ -75,3 +81,180 @@ void ASLayoutableClearCurrentContext() ASDN::StaticMutexLocker l(_layoutableContextLock); layoutableContextMap.erase(key); } + +/** + * Given an id, set up layout options that are intrinsically defined by the layoutable. + * + * While this could be done in the layoutable object itself, moving the logic into this helper function + * allows a custom spec to set up defaults without needing to alter the layoutable itself. For example, + * image you were creating a custom baseline spec that needed ascender/descender. To assign values automatically + * when a text node's attribute string is set, you would need to subclass ASTextNode and assign the values in the + * override of setAttributeString. However, assigning the defaults via this function allows you to create a + * custom spec without the need to create a subclass of ASTextNode. + * + * @param layoutable The layoutable object to inspect for default intrinsic layout option values + */ +void ASLayoutableSetValuesForLayoutable(id layoutable) +{ + //ASDN::MutexLocker l(_propertyLock); + if ([layoutable isKindOfClass:[ASDisplayNode class]]) { + ASDisplayNode *displayNode = (ASDisplayNode *)layoutable; + displayNode.sizeRange = ASRelativeSizeRangeMake(ASRelativeSizeMakeWithCGSize(displayNode.preferredFrameSize), ASRelativeSizeMakeWithCGSize(displayNode.preferredFrameSize)); + + if ([layoutable isKindOfClass:[ASTextNode class]]) { + ASTextNode *textNode = (ASTextNode *)layoutable; + NSAttributedString *attributedString = textNode.attributedString; + if (attributedString.length > 0) { + CGFloat screenScale = ASScreenScale(); + textNode.ascender = round([[attributedString attribute:NSFontAttributeName atIndex:0 effectiveRange:NULL] ascender] * screenScale)/screenScale; + textNode.descender = round([[attributedString attribute:NSFontAttributeName atIndex:attributedString.length - 1 effectiveRange:NULL] descender] * screenScale)/screenScale; + } + } + + } +} + +/** + * Both an ASDisplayNode and an ASLayoutSpec conform to ASLayoutable. There are several properties + * in ASLayoutable that are used when a node or spec is used in a layout spec. + * These properties are provided for convenience, as they are forwards to the node or spec's + * properties. Instead of duplicating the property forwarding in both classes, we + * create a define that allows us to easily implement the forwards in one place. + * + * If you create a custom layout spec, we recommend this stragety if you decide to extend + * ASDisplayNode and ASLayoutSpec to provide convenience properties for any options that your + * layoutSpec may require. + */ + +#define ASEnvironmentLayoutOptionsForwarding \ +- (ASEnvironmentLayoutOptionsState *)layoutOptionsState\ +{\ + return &(self.environmentCollection->layoutOptionsState);\ +}\ +- (void)propagateUpLayoutOptionsState\ +{\ + id parent = [self parent];\ + if (![parent supportsMultipleChildren]) {\ + ASEnvironmentStatePropagateUp(parent, self.environmentCollection->layoutOptionsState);\ + }\ +}\ +\ +- (CGFloat)spacingAfter\ +{\ + return self.layoutOptionsState->spacingAfter;\ +}\ +\ +- (void)setSpacingAfter:(CGFloat)spacingAfter\ +{\ + self.layoutOptionsState->spacingAfter = spacingAfter;\ + [self propagateUpLayoutOptionsState];\ +}\ +\ +- (CGFloat)spacingBefore\ +{\ + return self.layoutOptionsState->spacingBefore;\ +}\ +\ +- (void)setSpacingBefore:(CGFloat)spacingBefore\ +{\ + self.layoutOptionsState->spacingBefore = spacingBefore;\ + [self propagateUpLayoutOptionsState];\ +}\ +\ +- (BOOL)flexGrow\ +{\ + return self.layoutOptionsState->flexGrow;\ +}\ +\ +- (void)setFlexGrow:(BOOL)flexGrow\ +{\ + self.layoutOptionsState->flexGrow = flexGrow;\ + [self propagateUpLayoutOptionsState];\ +}\ +\ +- (BOOL)flexShrink\ +{\ + return self.layoutOptionsState->flexShrink;\ +}\ +\ +- (void)setFlexShrink:(BOOL)flexShrink\ +{\ + self.layoutOptionsState->flexShrink = flexShrink;\ + [self propagateUpLayoutOptionsState];\ +}\ +\ +- (ASRelativeDimension)flexBasis\ +{\ + return self.layoutOptionsState->flexBasis;\ +}\ +\ +- (void)setFlexBasis:(ASRelativeDimension)flexBasis\ +{\ + self.layoutOptionsState->flexBasis = flexBasis;\ + [self propagateUpLayoutOptionsState];\ +}\ +\ +- (ASStackLayoutAlignSelf)alignSelf\ +{\ + return self.layoutOptionsState->alignSelf;\ +}\ +\ +- (void)setAlignSelf:(ASStackLayoutAlignSelf)alignSelf\ +{\ + self.layoutOptionsState->alignSelf = alignSelf;\ + [self propagateUpLayoutOptionsState];\ +}\ +\ +- (CGFloat)ascender\ +{\ + return self.layoutOptionsState->ascender;\ +}\ +\ +- (void)setAscender:(CGFloat)ascender\ +{\ + self.layoutOptionsState->ascender = ascender;\ + [self propagateUpLayoutOptionsState];\ +}\ +\ +- (CGFloat)descender\ +{\ + return self.layoutOptionsState->descender;\ +}\ +\ +- (void)setDescender:(CGFloat)descender\ +{\ + self.layoutOptionsState->descender = descender;\ + [self propagateUpLayoutOptionsState];\ +}\ +\ +- (ASRelativeSizeRange)sizeRange\ +{\ + return self.layoutOptionsState->sizeRange;\ +}\ +\ +- (void)setSizeRange:(ASRelativeSizeRange)sizeRange\ +{\ + self.layoutOptionsState->sizeRange = sizeRange;\ + [self propagateUpLayoutOptionsState];\ +}\ +\ +- (CGPoint)layoutPosition\ +{\ + return self.layoutOptionsState->layoutPosition;\ +}\ +\ +- (void)setLayoutPosition:(CGPoint)layoutPosition\ +{\ + self.layoutOptionsState->layoutPosition = layoutPosition;\ + [self propagateUpLayoutOptionsState];\ +}\ + + +@implementation ASDisplayNode(ASLayoutOptions) +ASEnvironmentLayoutOptionsForwarding +@end + +@implementation ASLayoutSpec(ASLayoutOptions) +ASEnvironmentLayoutOptionsForwarding +@end + diff --git a/AsyncDisplayKit/Layout/ASLayoutablePrivate.h b/AsyncDisplayKit/Layout/ASLayoutablePrivate.h index 2ae509b621..e4aa37e8db 100644 --- a/AsyncDisplayKit/Layout/ASLayoutablePrivate.h +++ b/AsyncDisplayKit/Layout/ASLayoutablePrivate.h @@ -11,7 +11,6 @@ #import @class ASLayoutSpec; -@class ASLayoutOptions; @protocol ASLayoutable; struct ASLayoutableContext { @@ -35,6 +34,8 @@ extern struct ASLayoutableContext ASLayoutableGetCurrentContext(); extern void ASLayoutableClearCurrentContext(); +extern void ASLayoutableSetValuesForLayoutable(id layoutable); + /** * The base protocol for ASLayoutable. Generally the methods/properties in this class do not need to be * called by the end user and are only called internally. However, there may be a case where the methods are useful. @@ -60,9 +61,4 @@ extern void ASLayoutableClearCurrentContext(); */ @property (nonatomic, assign) BOOL isFinalLayoutable; - -/** - * The class that holds all of the layoutOptions set on an ASLayoutable. - */ -@property (nonatomic, strong, readonly) ASLayoutOptions *layoutOptions; @end diff --git a/AsyncDisplayKit/Layout/ASStackLayoutSpec.mm b/AsyncDisplayKit/Layout/ASStackLayoutSpec.mm index 76539bf57a..6af951ec86 100644 --- a/AsyncDisplayKit/Layout/ASStackLayoutSpec.mm +++ b/AsyncDisplayKit/Layout/ASStackLayoutSpec.mm @@ -198,6 +198,15 @@ @end +@implementation ASStackLayoutSpec (ASEnvironment) + +- (BOOL)supportsMultipleChildren +{ + return YES; +} + +@end + @implementation ASStackLayoutSpec (Debugging) #pragma mark - ASLayoutableAsciiArtProtocol diff --git a/AsyncDisplayKit/Layout/ASStaticLayoutSpec.mm b/AsyncDisplayKit/Layout/ASStaticLayoutSpec.mm index 2d0edba4cd..388b06aa02 100644 --- a/AsyncDisplayKit/Layout/ASStaticLayoutSpec.mm +++ b/AsyncDisplayKit/Layout/ASStaticLayoutSpec.mm @@ -11,7 +11,6 @@ #import "ASStaticLayoutSpec.h" #import "ASLayoutSpecUtilities.h" -#import "ASLayoutOptions.h" #import "ASInternalHelpers.h" #import "ASLayout.h" @@ -86,6 +85,15 @@ @end +@implementation ASStaticLayoutSpec (ASEnvironment) + +- (BOOL)supportsMultipleChildren +{ + return YES; +} + +@end + @implementation ASStaticLayoutSpec (Debugging) #pragma mark - ASLayoutableAsciiArtProtocol diff --git a/AsyncDisplayKit/Private/ASDisplayNode+FrameworkPrivate.h b/AsyncDisplayKit/Private/ASDisplayNode+FrameworkPrivate.h index 996ec2a7d0..07cb3440b8 100644 --- a/AsyncDisplayKit/Private/ASDisplayNode+FrameworkPrivate.h +++ b/AsyncDisplayKit/Private/ASDisplayNode+FrameworkPrivate.h @@ -16,7 +16,6 @@ #import "ASDisplayNode.h" #import "ASSentinel.h" #import "ASThread.h" -#import "ASLayoutOptions.h" #import "_ASDisplayLayer.h" NS_ASSUME_NONNULL_BEGIN diff --git a/AsyncDisplayKit/Private/ASDisplayNodeInternal.h b/AsyncDisplayKit/Private/ASDisplayNodeInternal.h index bd00cd9417..f632f64ae0 100644 --- a/AsyncDisplayKit/Private/ASDisplayNodeInternal.h +++ b/AsyncDisplayKit/Private/ASDisplayNodeInternal.h @@ -16,9 +16,9 @@ #import "ASDisplayNode.h" #import "ASSentinel.h" #import "ASThread.h" -#import "ASLayoutOptions.h" #import "_ASTransitionContext.h" #import "ASDisplayNodeLayoutContext.h" +#import "ASEnvironment.h" #include @@ -97,6 +97,7 @@ FOUNDATION_EXPORT NSString * const ASRenderingEngineDidDisplayNodesScheduledBefo // This is the desired contentsScale, not the scale at which the layer's contents should be displayed CGFloat _contentsScaleForDisplay; + ASEnvironmentCollection _environmentCollection; ASLayout *_layout; ASSizeRange _constrainedSize; diff --git a/AsyncDisplayKit/Private/ASEnvironmentInternal.h b/AsyncDisplayKit/Private/ASEnvironmentInternal.h new file mode 100644 index 0000000000..cf77e36cfa --- /dev/null +++ b/AsyncDisplayKit/Private/ASEnvironmentInternal.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2014-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + +#import "ASEnvironment.h" + +#pragma once + +enum ASEnvironmentStatePropagation { DOWN, UP }; + +#pragma mark - Traversing an ASEnvironment Tree + +void ASEnvironmentPerformBlockOnObjectAndChildren(id object, void(^block)(id object)); +void ASEnvironmentPerformBlockOnObjectAndParents(id object, void(^block)(id object)); + + +#pragma mark - Merging + +static const struct ASEnvironmentLayoutOptionsState ASEnvironmentDefaultLayoutOptionsState = {}; +void ASEnvironmentMergeObjectAndState(id object, ASEnvironmentLayoutOptionsState& state, ASEnvironmentStatePropagation propagation); + + +static const struct ASEnvironmentHierarchyState ASEnvironmentDefaultHierarchyState = {}; +void ASEnvironmentMergeObjectAndState(id object, ASEnvironmentHierarchyState& state, ASEnvironmentStatePropagation propagation); + + +#pragma mark - Propagation + +template +void ASEnvironmentStatePropagateDown(id object, ASEnvironmentStateType& state) { + ASEnvironmentPerformBlockOnObjectAndChildren(object, ^(id node) { + ASEnvironmentMergeObjectAndState(object, state, DOWN); + }); +} + +template +void ASEnvironmentStatePropagateUp(id object, ASEnvironmentStateType& state) { + ASEnvironmentPerformBlockOnObjectAndParents(object, ^(id node) { + ASEnvironmentMergeObjectAndState(object, state, UP); + }); +} + +template +void ASEnvironmentStateApply(id object, ASEnvironmentStateType& state, ASEnvironmentStatePropagation propagate) { + if (propagate == DOWN) { + ASEnvironmentStatePropagateUp(object, state); + } else if (propagate == UP) { + ASEnvironmentStatePropagateDown(object, state); + } +} diff --git a/AsyncDisplayKit/Private/ASEnvironmentInternal.mm b/AsyncDisplayKit/Private/ASEnvironmentInternal.mm new file mode 100644 index 0000000000..b4e217a1ec --- /dev/null +++ b/AsyncDisplayKit/Private/ASEnvironmentInternal.mm @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2014-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + +#import "ASEnvironmentInternal.h" +#import + +//#define LOG(...) NSLog(__VA_ARGS__) +#define LOG(...) + +#pragma mark - Traversing an ASEnvironment Tree + +void ASEnvironmentPerformBlockOnObjectAndChildren(id object, void(^block)(id node)) +{ + if (!object) { + return; + } + + std::queue> queue; + queue.push(object); + + while (!queue.empty()) { + id object = queue.front(); queue.pop(); + + block(object); + + for (id child in [object children]) { + queue.push(child); + } + } +} + +void ASEnvironmentPerformBlockOnObjectAndParents(id object, void(^block)(id node)) +{ + while (object) { + block(object); + object = [object parent]; + } +} + + +#pragma mark - Merging functions for states + +void ASEnvironmentMergeObjectAndState(id object, ASEnvironmentHierarchyState& state, ASEnvironmentStatePropagation propagation) { + // Merge object and hierarchy state + LOG(@"Merge object and state: %@ - ASEnvironmentHierarchyState", object); +} + +void ASEnvironmentMergeObjectAndState(id object, ASEnvironmentLayoutOptionsState& state, ASEnvironmentStatePropagation propagation) { + // Merge object and layout options state + LOG(@"Merge object and state: %@ - ASEnvironmentLayoutOptionsState", object); + + // Support propagate up + if (propagation == UP) { + + // Object is the parent and the state is the state of the child + const ASEnvironmentLayoutOptionsState defaultState = ASEnvironmentDefaultLayoutOptionsState; + ASEnvironmentLayoutOptionsState parentState = object.environmentCollection->layoutOptionsState; + + // For every field check if the parent value is equal to the default than propegate up the child value to + // the parent + if (parentState.spacingBefore != defaultState.spacingBefore) { + parentState.spacingBefore = state.spacingBefore; + } + if (parentState.spacingAfter != defaultState.spacingAfter) { + parentState.spacingAfter = state.spacingAfter; + } + if (parentState.alignSelf != defaultState.alignSelf) { + parentState.alignSelf = defaultState.alignSelf; + } + if (parentState.flexGrow != defaultState.flexGrow) { + parentState.flexGrow = defaultState.flexGrow; + } + if (!ASRelativeDimensionEqualToRelativeDimension(parentState.flexBasis, defaultState.flexBasis)) { + parentState.flexBasis = defaultState.flexBasis; + } + if (parentState.alignSelf != defaultState.alignSelf) { + parentState.alignSelf = defaultState.alignSelf; + } + if (parentState.ascender != defaultState.ascender) { + parentState.ascender = defaultState.ascender; + } + + if (!ASRelativeSizeRangeEqualToRelativeSizeRange(parentState.sizeRange, defaultState.sizeRange)) { + parentState.sizeRange = defaultState.sizeRange; + } + if (CGPointEqualToPoint(parentState.layoutPosition, defaultState.layoutPosition)) { + parentState.layoutPosition = defaultState.layoutPosition; + } + + object.environmentCollection->layoutOptionsState = parentState; + } + +} diff --git a/AsyncDisplayKit/Private/ASLayoutOptionsPrivate.h b/AsyncDisplayKit/Private/ASLayoutOptionsPrivate.h deleted file mode 100644 index 34a26da4f2..0000000000 --- a/AsyncDisplayKit/Private/ASLayoutOptionsPrivate.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2014-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - */ - -#import -#import -#import - -@interface ASDisplayNode(ASLayoutOptions) -@end - -@interface ASDisplayNode() -{ - ASLayoutOptions *_layoutOptions; - ASDN::RecursiveMutex _layoutOptionsLock; -} -@end - -@interface ASLayoutSpec(ASLayoutOptions) -@end - -@interface ASLayoutSpec() -{ - ASLayoutOptions *_layoutOptions; - ASDN::RecursiveMutex _layoutOptionsLock; -} -@end diff --git a/AsyncDisplayKit/Private/ASStackBaselinePositionedLayout.mm b/AsyncDisplayKit/Private/ASStackBaselinePositionedLayout.mm index ed6b622162..46df924adf 100644 --- a/AsyncDisplayKit/Private/ASStackBaselinePositionedLayout.mm +++ b/AsyncDisplayKit/Private/ASStackBaselinePositionedLayout.mm @@ -12,7 +12,6 @@ #import "ASLayoutSpecUtilities.h" #import "ASStackLayoutSpecUtilities.h" -#import "ASLayoutOptions.h" static CGFloat baselineForItem(const ASStackLayoutSpecStyle &style, const ASLayout *layout) { diff --git a/AsyncDisplayKit/Private/ASStackPositionedLayout.mm b/AsyncDisplayKit/Private/ASStackPositionedLayout.mm index 428319d317..cd18dd2157 100644 --- a/AsyncDisplayKit/Private/ASStackPositionedLayout.mm +++ b/AsyncDisplayKit/Private/ASStackPositionedLayout.mm @@ -14,7 +14,6 @@ #import "ASLayoutSpecUtilities.h" #import "ASStackLayoutSpecUtilities.h" #import "ASLayoutable.h" -#import "ASLayoutOptions.h" #import "ASAssert.h" static CGFloat crossOffset(const ASStackLayoutSpecStyle &style, diff --git a/AsyncDisplayKit/Private/ASStackUnpositionedLayout.mm b/AsyncDisplayKit/Private/ASStackUnpositionedLayout.mm index a19ae298ba..57902a6b4e 100644 --- a/AsyncDisplayKit/Private/ASStackUnpositionedLayout.mm +++ b/AsyncDisplayKit/Private/ASStackUnpositionedLayout.mm @@ -14,7 +14,6 @@ #import "ASLayoutSpecUtilities.h" #import "ASStackLayoutSpecUtilities.h" -#import "ASLayoutOptions.h" /** Sizes the child given the parameters specified, and returns the computed layout. @@ -116,8 +115,7 @@ static CGFloat computeStackDimensionSum(const std::vector child = l.child; - const ASLayoutOptions *layoutOptions = child.layoutOptions; - return x + layoutOptions.spacingBefore + layoutOptions.spacingAfter; + return x + child.spacingBefore + child.spacingAfter; }); // Sum up the childrens' dimensions (including spacing) in the stack direction. diff --git a/AsyncDisplayKitTests/ASCenterLayoutSpecSnapshotTests.mm b/AsyncDisplayKitTests/ASCenterLayoutSpecSnapshotTests.mm index f6ba9da1e5..bb38be0d18 100644 --- a/AsyncDisplayKitTests/ASCenterLayoutSpecSnapshotTests.mm +++ b/AsyncDisplayKitTests/ASCenterLayoutSpecSnapshotTests.mm @@ -13,7 +13,6 @@ #import "ASBackgroundLayoutSpec.h" #import "ASCenterLayoutSpec.h" #import "ASStackLayoutSpec.h" -#import "ASLayoutOptions.h" static const ASSizeRange kSize = {{100, 120}, {320, 160}}; diff --git a/AsyncDisplayKitTests/ASRelativeLayoutSpecSnapshotTests.mm b/AsyncDisplayKitTests/ASRelativeLayoutSpecSnapshotTests.mm index 468b515a05..213045ea68 100644 --- a/AsyncDisplayKitTests/ASRelativeLayoutSpecSnapshotTests.mm +++ b/AsyncDisplayKitTests/ASRelativeLayoutSpecSnapshotTests.mm @@ -13,7 +13,6 @@ #import "ASBackgroundLayoutSpec.h" #import "ASRelativeLayoutSpec.h" #import "ASStackLayoutSpec.h" -#import "ASLayoutOptions.h" static const ASSizeRange kSize = {{100, 120}, {320, 160}}; diff --git a/AsyncDisplayKitTests/ASStackLayoutSpecSnapshotTests.mm b/AsyncDisplayKitTests/ASStackLayoutSpecSnapshotTests.mm index 20989a71d3..d5ca9074aa 100644 --- a/AsyncDisplayKitTests/ASStackLayoutSpecSnapshotTests.mm +++ b/AsyncDisplayKitTests/ASStackLayoutSpecSnapshotTests.mm @@ -15,7 +15,6 @@ #import "ASBackgroundLayoutSpec.h" #import "ASRatioLayoutSpec.h" #import "ASInsetLayoutSpec.h" -#import "ASLayoutOptions.h" @interface ASStackLayoutSpecSnapshotTests : ASLayoutSpecSnapshotTestCase @end From 65b4961802b5e3239e858224ec0ecd342d2fd254 Mon Sep 17 00:00:00 2001 From: Michael Schneider Date: Tue, 29 Mar 2016 19:59:17 -0700 Subject: [PATCH 2/6] Add extensibility support for ASEnvironmentLayoutOptionsState --- AsyncDisplayKit.xcodeproj/project.pbxproj | 10 +++- AsyncDisplayKit/ASDisplayNode.mm | 36 +++++++++++++- AsyncDisplayKit/Details/ASEnvironment.h | 21 ++++++-- AsyncDisplayKit/Layout/ASLayoutSpec.mm | 33 +++++++++++++ AsyncDisplayKit/Layout/ASLayoutable.h | 3 +- AsyncDisplayKit/Layout/ASLayoutable.mm | 7 ++- .../Layout/ASLayoutableExtensibility.h | 25 ++++++++++ .../Private/ASEnvironmentInternal.h | 13 +++++ .../Private/ASEnvironmentInternal.mm | 49 +++++++++++++++++++ 9 files changed, 186 insertions(+), 11 deletions(-) create mode 100644 AsyncDisplayKit/Layout/ASLayoutableExtensibility.h diff --git a/AsyncDisplayKit.xcodeproj/project.pbxproj b/AsyncDisplayKit.xcodeproj/project.pbxproj index ac41e847c5..e159eae52b 100644 --- a/AsyncDisplayKit.xcodeproj/project.pbxproj +++ b/AsyncDisplayKit.xcodeproj/project.pbxproj @@ -262,6 +262,8 @@ 698548641CA9E025008A345F /* ASEnvironment.h in Headers */ = {isa = PBXBuildFile; fileRef = 698548611CA9E025008A345F /* ASEnvironment.h */; settings = {ATTRIBUTES = (Public, ); }; }; 698548651CA9E025008A345F /* ASEnvironment.m in Sources */ = {isa = PBXBuildFile; fileRef = 698548621CA9E025008A345F /* ASEnvironment.m */; }; 698548661CA9E025008A345F /* ASEnvironment.m in Sources */ = {isa = PBXBuildFile; fileRef = 698548621CA9E025008A345F /* ASEnvironment.m */; }; + 698C8B611CAB49FC0052DC3F /* ASLayoutableExtensibility.h in Headers */ = {isa = PBXBuildFile; fileRef = 698C8B601CAB49FC0052DC3F /* ASLayoutableExtensibility.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 698C8B621CAB49FC0052DC3F /* ASLayoutableExtensibility.h in Headers */ = {isa = PBXBuildFile; fileRef = 698C8B601CAB49FC0052DC3F /* ASLayoutableExtensibility.h */; settings = {ATTRIBUTES = (Public, ); }; }; 69E1006D1CA89CB600D88C1B /* ASEnvironmentInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 69E100691CA89CB600D88C1B /* ASEnvironmentInternal.h */; }; 69E1006E1CA89CB600D88C1B /* ASEnvironmentInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 69E100691CA89CB600D88C1B /* ASEnvironmentInternal.h */; }; 69E1006F1CA89CB600D88C1B /* ASEnvironmentInternal.mm in Sources */ = {isa = PBXBuildFile; fileRef = 69E1006A1CA89CB600D88C1B /* ASEnvironmentInternal.mm */; }; @@ -742,6 +744,7 @@ 68EE0DBC1C1B4ED300BA1B99 /* ASMainSerialQueue.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASMainSerialQueue.mm; sourceTree = ""; }; 698548611CA9E025008A345F /* ASEnvironment.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASEnvironment.h; sourceTree = ""; }; 698548621CA9E025008A345F /* ASEnvironment.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASEnvironment.m; sourceTree = ""; }; + 698C8B601CAB49FC0052DC3F /* ASLayoutableExtensibility.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASLayoutableExtensibility.h; path = AsyncDisplayKit/Layout/ASLayoutableExtensibility.h; sourceTree = ""; }; 69E100691CA89CB600D88C1B /* ASEnvironmentInternal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASEnvironmentInternal.h; sourceTree = ""; }; 69E1006A1CA89CB600D88C1B /* ASEnvironmentInternal.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASEnvironmentInternal.mm; sourceTree = ""; }; 69F10C851C84C35D0026140C /* ASRangeControllerUpdateRangeProtocol+Beta.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ASRangeControllerUpdateRangeProtocol+Beta.h"; sourceTree = ""; }; @@ -1317,14 +1320,13 @@ ACF6ED041B17843500DA7C62 /* ASCenterLayoutSpec.mm */, ACF6ED071B17843500DA7C62 /* ASDimension.h */, ACF6ED081B17843500DA7C62 /* ASDimension.mm */, - AC47D9431B3BB41900AAEE9D /* ASRelativeSize.h */, - AC47D9441B3BB41900AAEE9D /* ASRelativeSize.mm */, ACF6ED091B17843500DA7C62 /* ASInsetLayoutSpec.h */, ACF6ED0A1B17843500DA7C62 /* ASInsetLayoutSpec.mm */, ACF6ED0B1B17843500DA7C62 /* ASLayout.h */, ACF6ED0C1B17843500DA7C62 /* ASLayout.mm */, ACF6ED111B17843500DA7C62 /* ASLayoutable.h */, E55D86311CA8A14000A0C26F /* ASLayoutable.mm */, + 698C8B601CAB49FC0052DC3F /* ASLayoutableExtensibility.h */, 9CDC18CB1B910E12004965E2 /* ASLayoutablePrivate.h */, ACF6ED0D1B17843500DA7C62 /* ASLayoutSpec.h */, ACF6ED0E1B17843500DA7C62 /* ASLayoutSpec.mm */, @@ -1334,6 +1336,8 @@ ACF6ED151B17843500DA7C62 /* ASRatioLayoutSpec.mm */, 7A06A7391C35F08800FE8DAA /* ASRelativeLayoutSpec.h */, 7A06A7381C35F08800FE8DAA /* ASRelativeLayoutSpec.mm */, + AC47D9431B3BB41900AAEE9D /* ASRelativeSize.h */, + AC47D9441B3BB41900AAEE9D /* ASRelativeSize.mm */, 9C49C36E1B853957000B0DD5 /* ASStackLayoutable.h */, AC21EC0F1B3D0BF600C8B19A /* ASStackLayoutDefines.h */, ACF6ED161B17843500DA7C62 /* ASStackLayoutSpec.h */, @@ -1379,6 +1383,7 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( + 698C8B611CAB49FC0052DC3F /* ASLayoutableExtensibility.h in Headers */, 698548631CA9E025008A345F /* ASEnvironment.h in Headers */, E5711A2B1C840C81009619D4 /* ASIndexedNodeContext.h in Headers */, 257754C21BEE458E00737CA5 /* ASTextKitCoreTextAdditions.h in Headers */, @@ -1522,6 +1527,7 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( + 698C8B621CAB49FC0052DC3F /* ASLayoutableExtensibility.h in Headers */, 698548641CA9E025008A345F /* ASEnvironment.h in Headers */, AC026B6A1BD57D6F00BBC17E /* ASChangeSetDataController.h in Headers */, B35062481B010EFD0018CF92 /* _AS-objc-internal.h in Headers */, diff --git a/AsyncDisplayKit/ASDisplayNode.mm b/AsyncDisplayKit/ASDisplayNode.mm index febf735ff0..d6fc281d17 100644 --- a/AsyncDisplayKit/ASDisplayNode.mm +++ b/AsyncDisplayKit/ASDisplayNode.mm @@ -24,7 +24,7 @@ #import "ASDisplayNodeExtras.h" #import "ASEqualityHelpers.h" #import "ASRunLoopQueue.h" -#import "ASEnvironment.h" +#import "ASEnvironmentInternal.h" #import "ASInternalHelpers.h" #import "ASLayout.h" @@ -2697,6 +2697,40 @@ static const char *ASDisplayNodeDrawingPriorityKey = "ASDrawingPriority"; return NO; } + +#pragma mark - ASLayoutableExtensibility + +- (void)setLayoutOptionExtensionBool:(BOOL)value atIndex:(int)idx +{ + _ASEnvironmentLayoutOptionsExtensionSetBoolAtIndex(self, idx, value); +} + +- (BOOL)layoutOptionExtensionBoolAtIndex:(int)idx +{ + return _ASEnvironmentLayoutOptionsExtensionGetBoolAtIndex(self, idx); +} + +- (void)setLayoutOptionExtensionInteger:(NSInteger)value atIndex:(int)idx +{ + _ASEnvironmentLayoutOptionsExtensionSetIntegerAtIndex(self, idx, value); +} + +- (NSInteger)layoutOptionExtensionIntegerAtIndex:(int)idx +{ + return _ASEnvironmentLayoutOptionsExtensionGetIntegerAtIndex(self, idx); +} + +- (void)setLayoutOptionExtensionEdgeInsets:(UIEdgeInsets)value atIndex:(int)idx +{ + _ASEnvironmentLayoutOptionsExtensionSetEdgeInsetsAtIndex(self, idx, value); +} + +- (UIEdgeInsets)layoutOptionExtensionEdgeInsetsAtIndex:(int)idx +{ + return _ASEnvironmentLayoutOptionsExtensionGetEdgeInsetsAtIndex(self, idx); +} + + #if TARGET_OS_TV #pragma mark - UIFocusEnvironment Protocol (tvOS) diff --git a/AsyncDisplayKit/Details/ASEnvironment.h b/AsyncDisplayKit/Details/ASEnvironment.h index 7229a166ea..7f1f0f8863 100644 --- a/AsyncDisplayKit/Details/ASEnvironment.h +++ b/AsyncDisplayKit/Details/ASEnvironment.h @@ -18,8 +18,20 @@ ASDISPLAYNODE_EXTERN_C_BEGIN NS_ASSUME_NONNULL_BEGIN +static const int kMaxEnvironmentStateBoolExtensions = 1; +static const int kMaxEnvironmentStateIntegerExtensions = 4; +static const int kMaxEnvironmentStateEdgeInsetExtensions = 1; -#pragma mark ASEnvironmentLayoutOptionsState +#pragma mark - + +typedef struct ASEnvironmentStateExtensions { + // Values to store extensions + BOOL boolExtensions[kMaxEnvironmentStateBoolExtensions]; + NSInteger integerExtensions[kMaxEnvironmentStateIntegerExtensions]; + UIEdgeInsets edgeInsetsExtensions[kMaxEnvironmentStateEdgeInsetExtensions]; +} ASEnvironmentStateExtensions; + +#pragma mark - ASEnvironmentLayoutOptionsState typedef struct ASEnvironmentLayoutOptionsState { CGFloat spacingBefore;// = 0; @@ -34,13 +46,12 @@ typedef struct ASEnvironmentLayoutOptionsState { ASRelativeSizeRange sizeRange;// = ASRelativeSizeRangeMake(ASRelativeSizeMakeWithCGSize(CGSizeZero), ASRelativeSizeMakeWithCGSize(CGSizeZero));; CGPoint layoutPosition;// = CGPointZero; - // TODO: ASEnvironment: find a good way to expand the options state - // id otherOptions; + ASEnvironmentStateExtensions _extensions; } ASEnvironmentLayoutOptionsState; extern ASEnvironmentLayoutOptionsState ASEnvironmentLayoutOptionsStateCreate(); -#pragma mark ASEnvironmentHierarchyState +#pragma mark - ASEnvironmentHierarchyState typedef struct ASEnvironmentHierarchyState { unsigned rasterized:1; // = NO @@ -51,7 +62,7 @@ typedef struct ASEnvironmentHierarchyState { extern ASEnvironmentHierarchyState ASEnvironmentHierarchyStateCreate(); -#pragma mark ASEnvironmentCollection +#pragma mark - ASEnvironmentCollection typedef struct ASEnvironmentCollection { struct ASEnvironmentHierarchyState hierarchyState; diff --git a/AsyncDisplayKit/Layout/ASLayoutSpec.mm b/AsyncDisplayKit/Layout/ASLayoutSpec.mm index d0b1b7ba48..77abc59671 100644 --- a/AsyncDisplayKit/Layout/ASLayoutSpec.mm +++ b/AsyncDisplayKit/Layout/ASLayoutSpec.mm @@ -158,6 +158,39 @@ static NSString * const kDefaultChildrenKey = @"kDefaultChildrenKey"; return NO; } + +#pragma mark - ASLayoutableExtensibility + +- (void)setLayoutOptionExtensionBool:(BOOL)value atIndex:(int)idx +{ + _ASEnvironmentLayoutOptionsExtensionSetBoolAtIndex(self, idx, value); +} + +- (BOOL)layoutOptionExtensionBoolAtIndex:(int)idx +{ + return _ASEnvironmentLayoutOptionsExtensionGetBoolAtIndex(self, idx); +} + +- (void)setLayoutOptionExtensionInteger:(NSInteger)value atIndex:(int)idx +{ + _ASEnvironmentLayoutOptionsExtensionSetIntegerAtIndex(self, idx, value); +} + +- (NSInteger)layoutOptionExtensionIntegerAtIndex:(int)idx +{ + return _ASEnvironmentLayoutOptionsExtensionGetIntegerAtIndex(self, idx); +} + +- (void)setLayoutOptionExtensionEdgeInsets:(UIEdgeInsets)value atIndex:(int)idx +{ + _ASEnvironmentLayoutOptionsExtensionSetEdgeInsetsAtIndex(self, idx, value); +} + +- (UIEdgeInsets)layoutOptionExtensionEdgeInsetsAtIndex:(int)idx +{ + return _ASEnvironmentLayoutOptionsExtensionGetEdgeInsetsAtIndex(self, idx); +} + @end @implementation ASLayoutSpec (Debugging) diff --git a/AsyncDisplayKit/Layout/ASLayoutable.h b/AsyncDisplayKit/Layout/ASLayoutable.h index 11553674f4..325a81535c 100644 --- a/AsyncDisplayKit/Layout/ASLayoutable.h +++ b/AsyncDisplayKit/Layout/ASLayoutable.h @@ -16,6 +16,7 @@ #import #import +#import @class ASLayout; @class ASLayoutSpec; @@ -38,7 +39,7 @@ NS_ASSUME_NONNULL_BEGIN * access to the options via convenience properties. If you are creating custom layout spec, then you can * extend the backing layout options class to accommodate any new layout options. */ -@protocol ASLayoutable +@protocol ASLayoutable /** * @abstract Calculate a layout based on given size range. diff --git a/AsyncDisplayKit/Layout/ASLayoutable.mm b/AsyncDisplayKit/Layout/ASLayoutable.mm index 6bdfdbe758..c38586ff5a 100644 --- a/AsyncDisplayKit/Layout/ASLayoutable.mm +++ b/AsyncDisplayKit/Layout/ASLayoutable.mm @@ -114,6 +114,9 @@ void ASLayoutableSetValuesForLayoutable(id layoutable) } } + +#pragma mark - ASLayoutOptionsForwarding + /** * Both an ASDisplayNode and an ASLayoutSpec conform to ASLayoutable. There are several properties * in ASLayoutable that are used when a node or spec is used in a layout spec. @@ -250,11 +253,11 @@ void ASLayoutableSetValuesForLayoutable(id layoutable) }\ -@implementation ASDisplayNode(ASLayoutOptions) +@implementation ASDisplayNode(ASLayoutOptionsForwarding) ASEnvironmentLayoutOptionsForwarding @end -@implementation ASLayoutSpec(ASLayoutOptions) +@implementation ASLayoutSpec(ASLayoutOptionsForwarding) ASEnvironmentLayoutOptionsForwarding @end diff --git a/AsyncDisplayKit/Layout/ASLayoutableExtensibility.h b/AsyncDisplayKit/Layout/ASLayoutableExtensibility.h new file mode 100644 index 0000000000..1451368d27 --- /dev/null +++ b/AsyncDisplayKit/Layout/ASLayoutableExtensibility.h @@ -0,0 +1,25 @@ +// +// ASLayoutableExtensibility.h +// AsyncDisplayKit +// +// Created by Michael Schneider on 3/29/16. +// Copyright © 2016 Facebook. All rights reserved. +// + +#import + +@protocol ASLayoutableExtensibility + +/// Currently up to 4 BOOL values +- (void)setLayoutOptionExtensionBool:(BOOL)value atIndex:(int)idx; +- (BOOL)layoutOptionExtensionBoolAtIndex:(int)idx; + +/// Currently up to 1 NSInteger value +- (void)setLayoutOptionExtensionInteger:(NSInteger)value atIndex:(int)idx; +- (NSInteger)layoutOptionExtensionIntegerAtIndex:(int)idx; + +/// Currently up to 1 UIEdgeInsets value +- (void)setLayoutOptionExtensionEdgeInsets:(UIEdgeInsets)value atIndex:(int)idx; +- (UIEdgeInsets)layoutOptionExtensionEdgeInsetsAtIndex:(int)idx; + +@end diff --git a/AsyncDisplayKit/Private/ASEnvironmentInternal.h b/AsyncDisplayKit/Private/ASEnvironmentInternal.h index cf77e36cfa..877508330a 100644 --- a/AsyncDisplayKit/Private/ASEnvironmentInternal.h +++ b/AsyncDisplayKit/Private/ASEnvironmentInternal.h @@ -14,6 +14,19 @@ enum ASEnvironmentStatePropagation { DOWN, UP }; + +#pragma mark - Set and get extensible values for layout options + +void _ASEnvironmentLayoutOptionsExtensionSetBoolAtIndex(id object, int idx, BOOL value); +BOOL _ASEnvironmentLayoutOptionsExtensionGetBoolAtIndex(id object, int idx); + +void _ASEnvironmentLayoutOptionsExtensionSetIntegerAtIndex(id object, int idx, NSInteger value); +NSInteger _ASEnvironmentLayoutOptionsExtensionGetIntegerAtIndex(id object, int idx); + +void _ASEnvironmentLayoutOptionsExtensionSetEdgeInsetsAtIndex(id object, int idx, UIEdgeInsets value); +UIEdgeInsets _ASEnvironmentLayoutOptionsExtensionGetEdgeInsetsAtIndex(id object, int idx); + + #pragma mark - Traversing an ASEnvironment Tree void ASEnvironmentPerformBlockOnObjectAndChildren(id object, void(^block)(id object)); diff --git a/AsyncDisplayKit/Private/ASEnvironmentInternal.mm b/AsyncDisplayKit/Private/ASEnvironmentInternal.mm index b4e217a1ec..2ab5ed21a0 100644 --- a/AsyncDisplayKit/Private/ASEnvironmentInternal.mm +++ b/AsyncDisplayKit/Private/ASEnvironmentInternal.mm @@ -9,6 +9,7 @@ */ #import "ASEnvironmentInternal.h" + #import //#define LOG(...) NSLog(__VA_ARGS__) @@ -45,6 +46,54 @@ void ASEnvironmentPerformBlockOnObjectAndParents(id object, void( } +#pragma mark - Set and get extensible values from state structs + +void _ASEnvironmentLayoutOptionsExtensionSetBoolAtIndex(id object, int idx, BOOL value) +{ + NSCAssert(idx < kMaxEnvironmentStateBoolExtensions, @"Setting index outside of max bool extensions space"); + + ASEnvironmentStateExtensions extension = object.environmentCollection->layoutOptionsState._extensions; + extension.boolExtensions[idx] = value; + object.environmentCollection->layoutOptionsState._extensions = extension; +} + +BOOL _ASEnvironmentLayoutOptionsExtensionGetBoolAtIndex(id object, int idx) +{ + NSCAssert(idx < kMaxEnvironmentStateBoolExtensions, @"Accessing index outside of max bool extensions space"); + return object.environmentCollection->layoutOptionsState._extensions.boolExtensions[idx]; +} + +void _ASEnvironmentLayoutOptionsExtensionSetIntegerAtIndex(id object, int idx, NSInteger value) +{ + NSCAssert(idx < kMaxEnvironmentStateIntegerExtensions, @"Setting index outside of max integer extensions space"); + + ASEnvironmentStateExtensions extension = object.environmentCollection->layoutOptionsState._extensions; + extension.integerExtensions[idx] = value; + object.environmentCollection->layoutOptionsState._extensions = extension; +} + +NSInteger _ASEnvironmentLayoutOptionsExtensionGetIntegerAtIndex(id object, int idx) +{ + NSCAssert(idx < kMaxEnvironmentStateIntegerExtensions, @"Accessing index outside of max integer extensions space"); + return object.environmentCollection->layoutOptionsState._extensions.integerExtensions[idx]; +} + +void _ASEnvironmentLayoutOptionsExtensionSetEdgeInsetsAtIndex(id object, int idx, UIEdgeInsets value) +{ + NSCAssert(idx < kMaxEnvironmentStateEdgeInsetExtensions, @"Setting index outside of max edge insets extensions space"); + + ASEnvironmentStateExtensions extension = object.environmentCollection->layoutOptionsState._extensions; + extension.edgeInsetsExtensions[idx] = value; + object.environmentCollection->layoutOptionsState._extensions = extension; +} + +UIEdgeInsets _ASEnvironmentLayoutOptionsExtensionGetEdgeInsetsAtIndex(id object, int idx) +{ + NSCAssert(idx < kMaxEnvironmentStateEdgeInsetExtensions, @"Accessing index outside of max edge insets extensions space"); + return object.environmentCollection->layoutOptionsState._extensions.edgeInsetsExtensions[idx]; +} + + #pragma mark - Merging functions for states void ASEnvironmentMergeObjectAndState(id object, ASEnvironmentHierarchyState& state, ASEnvironmentStatePropagation propagation) { From 4e757f0969ff057207edca8ce5e9835508e0657a Mon Sep 17 00:00:00 2001 From: Michael Schneider Date: Wed, 30 Mar 2016 22:02:17 -0700 Subject: [PATCH 3/6] General improvements - Refactor naming of ASEnvironmentCollection to ASEnvironmentState - Remove struct pointers - Move ASEnvironmentStatePropagation to a enum class - Move merge functions to pure functions - Move ASLayoutOptionsForwarding and ASLayoutableExtensibility into ASLayoutSpec and ASDisplayNode - Remove ASLayoutableSetValuesForLayoutable and move into explicit classes (ASDisplayNode, ASTextNode) --- AsyncDisplayKit/ASDisplayNode.mm | 62 ++---- AsyncDisplayKit/ASTextNode.mm | 6 + AsyncDisplayKit/Details/ASEnvironment.h | 22 +- AsyncDisplayKit/Details/ASEnvironment.m | 4 +- AsyncDisplayKit/Layout/ASLayoutSpec.h | 2 + AsyncDisplayKit/Layout/ASLayoutSpec.mm | 56 ++--- AsyncDisplayKit/Layout/ASLayoutable.mm | 180 ---------------- AsyncDisplayKit/Layout/ASLayoutablePrivate.h | 200 +++++++++++++++++- AsyncDisplayKit/Layout/ASStackLayoutSpec.mm | 4 +- AsyncDisplayKit/Layout/ASStaticLayoutSpec.mm | 4 +- .../Private/ASDisplayNodeInternal.h | 2 +- .../Private/ASEnvironmentInternal.h | 18 +- .../Private/ASEnvironmentInternal.mm | 30 +-- 13 files changed, 281 insertions(+), 309 deletions(-) diff --git a/AsyncDisplayKit/ASDisplayNode.mm b/AsyncDisplayKit/ASDisplayNode.mm index d6fc281d17..3bfe80760c 100644 --- a/AsyncDisplayKit/ASDisplayNode.mm +++ b/AsyncDisplayKit/ASDisplayNode.mm @@ -253,8 +253,7 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c) _displaySentinel = [[ASSentinel alloc] init]; _preferredFrameSize = CGSizeZero; - _environmentCollection = ASEnvironmentCollectionCreate(); - ASLayoutableSetValuesForLayoutable(self); + _environmentState = ASEnvironmentStateCreate(); } - (id)init @@ -1703,6 +1702,10 @@ static NSInteger incrementIfFound(NSInteger i) { [self exitHierarchyState:stateToEnterOrExit]; } } + + if ([newSupernode supportsUpwardPropagation]) { + ASEnvironmentStatePropagateUp(newSupernode, self.environmentState.layoutOptionsState); + } } // Track that a node will be displayed as part of the current node hierarchy. @@ -1857,8 +1860,8 @@ void recursivelyTriggerDisplayForLayer(CALayer *layer, BOOL shouldBlock) ASDN::MutexLocker l(_propertyLock); if (_methodOverrides & ASDisplayNodeMethodOverrideLayoutSpecThatFits) { ASLayoutSpec *layoutSpec = [self layoutSpecThatFits:constrainedSize]; - layoutSpec.isMutable = NO; layoutSpec.parent = self; + layoutSpec.isMutable = NO; ASLayout *layout = [layoutSpec measureWithSizeRange:constrainedSize]; // Make sure layoutableObject of the root layout is `self`, so that the flattened layout will be structurally correct. if (layout.layoutableObject != self) { @@ -1922,6 +1925,7 @@ void recursivelyTriggerDisplayForLayer(CALayer *layer, BOOL shouldBlock) ASDN::MutexLocker l(_propertyLock); if (! CGSizeEqualToSize(_preferredFrameSize, preferredFrameSize)) { _preferredFrameSize = preferredFrameSize; + self.sizeRange = ASRelativeSizeRangeMake(ASRelativeSizeMakeWithCGSize(_preferredFrameSize), ASRelativeSizeMakeWithCGSize(_preferredFrameSize)); [self invalidateCalculatedLayout]; } } @@ -2672,9 +2676,14 @@ static const char *ASDisplayNodeDrawingPriorityKey = "ASDrawingPriority"; #pragma mark - ASEnvironment -- (ASEnvironmentCollection *)environmentCollection +- (ASEnvironmentState)environmentState { - return &_environmentCollection; + return _environmentState; +} + +- (void)setEnvironmentState:(ASEnvironmentState)environmentState +{ + _environmentState = environmentState; } - (ASDisplayNode *)parent @@ -2682,53 +2691,18 @@ static const char *ASDisplayNodeDrawingPriorityKey = "ASDrawingPriority"; return self.supernode; } -- (void)setParent:(ASDisplayNode *)parent -{ - [self __setSupernode:parent]; -} - - (NSArray *)children { return self.subnodes; } -- (BOOL)supportsMultipleChildren +- (BOOL)supportsUpwardPropagation { - return NO; + return YES; } - -#pragma mark - ASLayoutableExtensibility - -- (void)setLayoutOptionExtensionBool:(BOOL)value atIndex:(int)idx -{ - _ASEnvironmentLayoutOptionsExtensionSetBoolAtIndex(self, idx, value); -} - -- (BOOL)layoutOptionExtensionBoolAtIndex:(int)idx -{ - return _ASEnvironmentLayoutOptionsExtensionGetBoolAtIndex(self, idx); -} - -- (void)setLayoutOptionExtensionInteger:(NSInteger)value atIndex:(int)idx -{ - _ASEnvironmentLayoutOptionsExtensionSetIntegerAtIndex(self, idx, value); -} - -- (NSInteger)layoutOptionExtensionIntegerAtIndex:(int)idx -{ - return _ASEnvironmentLayoutOptionsExtensionGetIntegerAtIndex(self, idx); -} - -- (void)setLayoutOptionExtensionEdgeInsets:(UIEdgeInsets)value atIndex:(int)idx -{ - _ASEnvironmentLayoutOptionsExtensionSetEdgeInsetsAtIndex(self, idx, value); -} - -- (UIEdgeInsets)layoutOptionExtensionEdgeInsetsAtIndex:(int)idx -{ - return _ASEnvironmentLayoutOptionsExtensionGetEdgeInsetsAtIndex(self, idx); -} +ASEnvironmentLayoutOptionsForwarding +ASEnvironmentLayoutExtensibilityForwarding #if TARGET_OS_TV diff --git a/AsyncDisplayKit/ASTextNode.mm b/AsyncDisplayKit/ASTextNode.mm index 8c59739588..504b3fae98 100644 --- a/AsyncDisplayKit/ASTextNode.mm +++ b/AsyncDisplayKit/ASTextNode.mm @@ -364,6 +364,12 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ]; } _attributedString = ASCleanseAttributedStringOfCoreTextAttributes(attributedString); + + if (_attributedString.length > 0) { + CGFloat screenScale = ASScreenScale(); + self.ascender = round([[_attributedString attribute:NSFontAttributeName atIndex:0 effectiveRange:NULL] ascender] * screenScale)/screenScale; + self.descender = round([[_attributedString attribute:NSFontAttributeName atIndex:_attributedString.length - 1 effectiveRange:NULL] descender] * screenScale)/screenScale; + } // Sync the truncation string with attributes from the updated _attributedString // Without this, the size calculation of the text with truncation applied will diff --git a/AsyncDisplayKit/Details/ASEnvironment.h b/AsyncDisplayKit/Details/ASEnvironment.h index 7f1f0f8863..43e21bda09 100644 --- a/AsyncDisplayKit/Details/ASEnvironment.h +++ b/AsyncDisplayKit/Details/ASEnvironment.h @@ -62,13 +62,13 @@ typedef struct ASEnvironmentHierarchyState { extern ASEnvironmentHierarchyState ASEnvironmentHierarchyStateCreate(); -#pragma mark - ASEnvironmentCollection +#pragma mark - ASEnvironmentState -typedef struct ASEnvironmentCollection { +typedef struct ASEnvironmentState { struct ASEnvironmentHierarchyState hierarchyState; struct ASEnvironmentLayoutOptionsState layoutOptionsState; -} ASEnvironmentCollection; -extern ASEnvironmentCollection ASEnvironmentCollectionCreate(); +} ASEnvironmentState; +extern ASEnvironmentState ASEnvironmentStateCreate(); ASDISPLAYNODE_EXTERN_C_END @@ -77,26 +77,22 @@ ASDISPLAYNODE_EXTERN_C_END /** * ASEnvironment allows objects that conform to the ASEnvironment protocol to be able to propagate specific States - * defined in an ASEnvironmentCollection up and down the ASEnvironment tree. To be able to define how merges of + * defined in an ASEnvironmentState up and down the ASEnvironment tree. To be able to define how merges of * States should happen, specific merge functions can be provided */ @protocol ASEnvironment /// The environment collection of an object which class conforms to the ASEnvironment protocol -- (ASEnvironmentCollection *)environmentCollection; +- (ASEnvironmentState)environmentState; +- (void)setEnvironmentState:(ASEnvironmentState)environmentState; /// Returns the parent of an object which class conforms to the ASEnvironment protocol -- (id)parent; - -/// Set the parent of an object which class conforms to the ASEnvironment protocol -- (void)setParent:(id)parent; +- (id _Nullable)parent; /// Returns all children of an object which class conforms to the ASEnvironment protocol - (NSArray> *)children; -// TODO: ASEnvironment: Find a better name. As in ASDisplayNode this returns NO which in theory is wrong as as -// it supports multiple subnodes -- (BOOL)supportsMultipleChildren; +- (BOOL)supportsUpwardPropagation; @end diff --git a/AsyncDisplayKit/Details/ASEnvironment.m b/AsyncDisplayKit/Details/ASEnvironment.m index e08795a7b3..5cbe4d95c1 100644 --- a/AsyncDisplayKit/Details/ASEnvironment.m +++ b/AsyncDisplayKit/Details/ASEnvironment.m @@ -32,9 +32,9 @@ ASEnvironmentHierarchyState ASEnvironmentHierarchyStateCreate() }; } -ASEnvironmentCollection ASEnvironmentCollectionCreate() +ASEnvironmentState ASEnvironmentStateCreate() { - return (ASEnvironmentCollection) { + return (ASEnvironmentState) { .hierarchyState = ASEnvironmentHierarchyStateCreate(), .layoutOptionsState = ASEnvironmentLayoutOptionsStateCreate() }; diff --git a/AsyncDisplayKit/Layout/ASLayoutSpec.h b/AsyncDisplayKit/Layout/ASLayoutSpec.h index 991c4224a7..dcb9b33246 100644 --- a/AsyncDisplayKit/Layout/ASLayoutSpec.h +++ b/AsyncDisplayKit/Layout/ASLayoutSpec.h @@ -25,6 +25,8 @@ NS_ASSUME_NONNULL_BEGIN - (instancetype)init; +@property (nullable, nonatomic, weak) id parent; + /** * Adds a child to this layout spec using a default identifier. * diff --git a/AsyncDisplayKit/Layout/ASLayoutSpec.mm b/AsyncDisplayKit/Layout/ASLayoutSpec.mm index 77abc59671..7c7598b90a 100644 --- a/AsyncDisplayKit/Layout/ASLayoutSpec.mm +++ b/AsyncDisplayKit/Layout/ASLayoutSpec.mm @@ -25,9 +25,9 @@ static NSString * const kDefaultChildKey = @"kDefaultChildKey"; static NSString * const kDefaultChildrenKey = @"kDefaultChildrenKey"; @interface ASLayoutSpec() { - ASEnvironmentCollection _environmentCollection; + ASEnvironmentState _environmentState; + ASDN::RecursiveMutex _propertyLock; } -@property (nonatomic, weak) id parent; @property (nonatomic, strong) NSMutableDictionary *layoutChildren; @end @@ -44,8 +44,7 @@ static NSString * const kDefaultChildrenKey = @"kDefaultChildrenKey"; return nil; } _isMutable = YES; - _environmentCollection = ASEnvironmentCollectionCreate(); - ASLayoutableSetValuesForLayoutable(self); + _environmentState = ASEnvironmentStateCreate(); return self; } @@ -83,7 +82,9 @@ static NSString * const kDefaultChildrenKey = @"kDefaultChildrenKey"; id finalLayoutable = [child finalLayoutable]; if (finalLayoutable != child) { // Copy layout options - finalLayoutable.environmentCollection->layoutOptionsState = child.environmentCollection->layoutOptionsState; + ASEnvironmentState environmentState = finalLayoutable.environmentState; + environmentState.layoutOptionsState = child.environmentState.layoutOptionsState; + finalLayoutable.environmentState = environmentState; return finalLayoutable; } } @@ -102,8 +103,8 @@ static NSString * const kDefaultChildrenKey = @"kDefaultChildrenKey"; { _parent = parent; - if (![parent supportsMultipleChildren]) { - ASEnvironmentStatePropagateUp(parent, self.environmentCollection->layoutOptionsState); + if ([parent supportsUpwardPropagation]) { + ASEnvironmentStatePropagateUp(parent, _environmentState.layoutOptionsState); } } @@ -148,48 +149,23 @@ static NSString * const kDefaultChildrenKey = @"kDefaultChildrenKey"; #pragma mark - ASEnvironment -- (ASEnvironmentCollection *)environmentCollection +- (ASEnvironmentState)environmentState { - return &_environmentCollection; + return _environmentState; } -- (BOOL)supportsMultipleChildren +- (void)setEnvironmentState:(ASEnvironmentState)environmentState { - return NO; + _environmentState = environmentState; } - -#pragma mark - ASLayoutableExtensibility - -- (void)setLayoutOptionExtensionBool:(BOOL)value atIndex:(int)idx +- (BOOL)supportsUpwardPropagation { - _ASEnvironmentLayoutOptionsExtensionSetBoolAtIndex(self, idx, value); + return YES; } -- (BOOL)layoutOptionExtensionBoolAtIndex:(int)idx -{ - return _ASEnvironmentLayoutOptionsExtensionGetBoolAtIndex(self, idx); -} - -- (void)setLayoutOptionExtensionInteger:(NSInteger)value atIndex:(int)idx -{ - _ASEnvironmentLayoutOptionsExtensionSetIntegerAtIndex(self, idx, value); -} - -- (NSInteger)layoutOptionExtensionIntegerAtIndex:(int)idx -{ - return _ASEnvironmentLayoutOptionsExtensionGetIntegerAtIndex(self, idx); -} - -- (void)setLayoutOptionExtensionEdgeInsets:(UIEdgeInsets)value atIndex:(int)idx -{ - _ASEnvironmentLayoutOptionsExtensionSetEdgeInsetsAtIndex(self, idx, value); -} - -- (UIEdgeInsets)layoutOptionExtensionEdgeInsetsAtIndex:(int)idx -{ - return _ASEnvironmentLayoutOptionsExtensionGetEdgeInsetsAtIndex(self, idx); -} +ASEnvironmentLayoutOptionsForwarding +ASEnvironmentLayoutExtensibilityForwarding @end diff --git a/AsyncDisplayKit/Layout/ASLayoutable.mm b/AsyncDisplayKit/Layout/ASLayoutable.mm index c38586ff5a..23fd59e9ff 100644 --- a/AsyncDisplayKit/Layout/ASLayoutable.mm +++ b/AsyncDisplayKit/Layout/ASLayoutable.mm @@ -81,183 +81,3 @@ void ASLayoutableClearCurrentContext() ASDN::StaticMutexLocker l(_layoutableContextLock); layoutableContextMap.erase(key); } - -/** - * Given an id, set up layout options that are intrinsically defined by the layoutable. - * - * While this could be done in the layoutable object itself, moving the logic into this helper function - * allows a custom spec to set up defaults without needing to alter the layoutable itself. For example, - * image you were creating a custom baseline spec that needed ascender/descender. To assign values automatically - * when a text node's attribute string is set, you would need to subclass ASTextNode and assign the values in the - * override of setAttributeString. However, assigning the defaults via this function allows you to create a - * custom spec without the need to create a subclass of ASTextNode. - * - * @param layoutable The layoutable object to inspect for default intrinsic layout option values - */ -void ASLayoutableSetValuesForLayoutable(id layoutable) -{ - //ASDN::MutexLocker l(_propertyLock); - if ([layoutable isKindOfClass:[ASDisplayNode class]]) { - ASDisplayNode *displayNode = (ASDisplayNode *)layoutable; - displayNode.sizeRange = ASRelativeSizeRangeMake(ASRelativeSizeMakeWithCGSize(displayNode.preferredFrameSize), ASRelativeSizeMakeWithCGSize(displayNode.preferredFrameSize)); - - if ([layoutable isKindOfClass:[ASTextNode class]]) { - ASTextNode *textNode = (ASTextNode *)layoutable; - NSAttributedString *attributedString = textNode.attributedString; - if (attributedString.length > 0) { - CGFloat screenScale = ASScreenScale(); - textNode.ascender = round([[attributedString attribute:NSFontAttributeName atIndex:0 effectiveRange:NULL] ascender] * screenScale)/screenScale; - textNode.descender = round([[attributedString attribute:NSFontAttributeName atIndex:attributedString.length - 1 effectiveRange:NULL] descender] * screenScale)/screenScale; - } - } - - } -} - - -#pragma mark - ASLayoutOptionsForwarding - -/** - * Both an ASDisplayNode and an ASLayoutSpec conform to ASLayoutable. There are several properties - * in ASLayoutable that are used when a node or spec is used in a layout spec. - * These properties are provided for convenience, as they are forwards to the node or spec's - * properties. Instead of duplicating the property forwarding in both classes, we - * create a define that allows us to easily implement the forwards in one place. - * - * If you create a custom layout spec, we recommend this stragety if you decide to extend - * ASDisplayNode and ASLayoutSpec to provide convenience properties for any options that your - * layoutSpec may require. - */ - -#define ASEnvironmentLayoutOptionsForwarding \ -- (ASEnvironmentLayoutOptionsState *)layoutOptionsState\ -{\ - return &(self.environmentCollection->layoutOptionsState);\ -}\ -- (void)propagateUpLayoutOptionsState\ -{\ - id parent = [self parent];\ - if (![parent supportsMultipleChildren]) {\ - ASEnvironmentStatePropagateUp(parent, self.environmentCollection->layoutOptionsState);\ - }\ -}\ -\ -- (CGFloat)spacingAfter\ -{\ - return self.layoutOptionsState->spacingAfter;\ -}\ -\ -- (void)setSpacingAfter:(CGFloat)spacingAfter\ -{\ - self.layoutOptionsState->spacingAfter = spacingAfter;\ - [self propagateUpLayoutOptionsState];\ -}\ -\ -- (CGFloat)spacingBefore\ -{\ - return self.layoutOptionsState->spacingBefore;\ -}\ -\ -- (void)setSpacingBefore:(CGFloat)spacingBefore\ -{\ - self.layoutOptionsState->spacingBefore = spacingBefore;\ - [self propagateUpLayoutOptionsState];\ -}\ -\ -- (BOOL)flexGrow\ -{\ - return self.layoutOptionsState->flexGrow;\ -}\ -\ -- (void)setFlexGrow:(BOOL)flexGrow\ -{\ - self.layoutOptionsState->flexGrow = flexGrow;\ - [self propagateUpLayoutOptionsState];\ -}\ -\ -- (BOOL)flexShrink\ -{\ - return self.layoutOptionsState->flexShrink;\ -}\ -\ -- (void)setFlexShrink:(BOOL)flexShrink\ -{\ - self.layoutOptionsState->flexShrink = flexShrink;\ - [self propagateUpLayoutOptionsState];\ -}\ -\ -- (ASRelativeDimension)flexBasis\ -{\ - return self.layoutOptionsState->flexBasis;\ -}\ -\ -- (void)setFlexBasis:(ASRelativeDimension)flexBasis\ -{\ - self.layoutOptionsState->flexBasis = flexBasis;\ - [self propagateUpLayoutOptionsState];\ -}\ -\ -- (ASStackLayoutAlignSelf)alignSelf\ -{\ - return self.layoutOptionsState->alignSelf;\ -}\ -\ -- (void)setAlignSelf:(ASStackLayoutAlignSelf)alignSelf\ -{\ - self.layoutOptionsState->alignSelf = alignSelf;\ - [self propagateUpLayoutOptionsState];\ -}\ -\ -- (CGFloat)ascender\ -{\ - return self.layoutOptionsState->ascender;\ -}\ -\ -- (void)setAscender:(CGFloat)ascender\ -{\ - self.layoutOptionsState->ascender = ascender;\ - [self propagateUpLayoutOptionsState];\ -}\ -\ -- (CGFloat)descender\ -{\ - return self.layoutOptionsState->descender;\ -}\ -\ -- (void)setDescender:(CGFloat)descender\ -{\ - self.layoutOptionsState->descender = descender;\ - [self propagateUpLayoutOptionsState];\ -}\ -\ -- (ASRelativeSizeRange)sizeRange\ -{\ - return self.layoutOptionsState->sizeRange;\ -}\ -\ -- (void)setSizeRange:(ASRelativeSizeRange)sizeRange\ -{\ - self.layoutOptionsState->sizeRange = sizeRange;\ - [self propagateUpLayoutOptionsState];\ -}\ -\ -- (CGPoint)layoutPosition\ -{\ - return self.layoutOptionsState->layoutPosition;\ -}\ -\ -- (void)setLayoutPosition:(CGPoint)layoutPosition\ -{\ - self.layoutOptionsState->layoutPosition = layoutPosition;\ - [self propagateUpLayoutOptionsState];\ -}\ - - -@implementation ASDisplayNode(ASLayoutOptionsForwarding) -ASEnvironmentLayoutOptionsForwarding -@end - -@implementation ASLayoutSpec(ASLayoutOptionsForwarding) -ASEnvironmentLayoutOptionsForwarding -@end - diff --git a/AsyncDisplayKit/Layout/ASLayoutablePrivate.h b/AsyncDisplayKit/Layout/ASLayoutablePrivate.h index e4aa37e8db..d18d0b7419 100644 --- a/AsyncDisplayKit/Layout/ASLayoutablePrivate.h +++ b/AsyncDisplayKit/Layout/ASLayoutablePrivate.h @@ -34,8 +34,6 @@ extern struct ASLayoutableContext ASLayoutableGetCurrentContext(); extern void ASLayoutableClearCurrentContext(); -extern void ASLayoutableSetValuesForLayoutable(id layoutable); - /** * The base protocol for ASLayoutable. Generally the methods/properties in this class do not need to be * called by the end user and are only called internally. However, there may be a case where the methods are useful. @@ -62,3 +60,201 @@ extern void ASLayoutableSetValuesForLayoutable(id layoutable); @property (nonatomic, assign) BOOL isFinalLayoutable; @end + + +#pragma mark - ASLayoutOptionsForwarding + +/** + * Both an ASDisplayNode and an ASLayoutSpec conform to ASLayoutable. There are several properties + * in ASLayoutable that are used when a node or spec is used in a layout spec. + * These properties are provided for convenience, as they are forwards to the node or spec's + * properties. Instead of duplicating the property forwarding in both classes, we + * create a define that allows us to easily implement the forwards in one place. + * + * If you create a custom layout spec, we recommend this stragety if you decide to extend + * ASDisplayNode and ASLayoutSpec to provide convenience properties for any options that your + * layoutSpec may require. + */ + +#define ASEnvironmentLayoutOptionsForwarding \ +- (void)propagateUpLayoutOptionsState\ +{\ + id parent = [self parent];\ + if ([parent supportsUpwardPropagation]) {\ + ASEnvironmentStatePropagateUp(parent, _environmentState.layoutOptionsState);\ + }\ +}\ +\ +- (CGFloat)spacingAfter\ +{\ + ASDN::MutexLocker l(_propertyLock);\ + return _environmentState.layoutOptionsState.spacingAfter;\ +}\ +\ +- (void)setSpacingAfter:(CGFloat)spacingAfter\ +{\ + _propertyLock.lock();\ + _environmentState.layoutOptionsState.spacingAfter = spacingAfter;\ + [self propagateUpLayoutOptionsState];\ + _propertyLock.unlock();\ +}\ +\ +- (CGFloat)spacingBefore\ +{\ + ASDN::MutexLocker l(_propertyLock);\ + return _environmentState.layoutOptionsState.spacingBefore;\ +}\ +\ +- (void)setSpacingBefore:(CGFloat)spacingBefore\ +{\ + _propertyLock.lock();\ + _environmentState.layoutOptionsState.spacingBefore = spacingBefore;\ + [self propagateUpLayoutOptionsState];\ + _propertyLock.unlock();\ +}\ +\ +- (BOOL)flexGrow\ +{\ + ASDN::MutexLocker l(_propertyLock);\ + return _environmentState.layoutOptionsState.flexGrow;\ +}\ +\ +- (void)setFlexGrow:(BOOL)flexGrow\ +{\ + _propertyLock.lock();\ + _environmentState.layoutOptionsState.flexGrow = flexGrow;\ + [self propagateUpLayoutOptionsState];\ + _propertyLock.unlock();\ +}\ +\ +- (BOOL)flexShrink\ +{\ + ASDN::MutexLocker l(_propertyLock);\ + return _environmentState.layoutOptionsState.flexShrink;\ +}\ +\ +- (void)setFlexShrink:(BOOL)flexShrink\ +{\ + _propertyLock.lock();\ + _environmentState.layoutOptionsState.flexShrink = flexShrink;\ + [self propagateUpLayoutOptionsState];\ + _propertyLock.unlock();\ +}\ +\ +- (ASRelativeDimension)flexBasis\ +{\ + ASDN::MutexLocker l(_propertyLock);\ + return _environmentState.layoutOptionsState.flexBasis;\ +}\ +\ +- (void)setFlexBasis:(ASRelativeDimension)flexBasis\ +{\ + _propertyLock.lock();\ + _environmentState.layoutOptionsState.flexBasis = flexBasis;\ + [self propagateUpLayoutOptionsState];\ + _propertyLock.unlock();\ +}\ +\ +- (ASStackLayoutAlignSelf)alignSelf\ +{\ + ASDN::MutexLocker l(_propertyLock);\ + return _environmentState.layoutOptionsState.alignSelf;\ +}\ +\ +- (void)setAlignSelf:(ASStackLayoutAlignSelf)alignSelf\ +{\ + _propertyLock.lock();\ + _environmentState.layoutOptionsState.alignSelf = alignSelf;\ + [self propagateUpLayoutOptionsState];\ + _propertyLock.unlock();\ +}\ +\ +- (CGFloat)ascender\ +{\ + ASDN::MutexLocker l(_propertyLock);\ + return _environmentState.layoutOptionsState.ascender;\ +}\ +\ +- (void)setAscender:(CGFloat)ascender\ +{\ + _propertyLock.lock();\ + _environmentState.layoutOptionsState.ascender = ascender;\ + [self propagateUpLayoutOptionsState];\ + _propertyLock.unlock();\ +}\ +\ +- (CGFloat)descender\ +{\ + ASDN::MutexLocker l(_propertyLock);\ + return _environmentState.layoutOptionsState.descender;\ +}\ +\ +- (void)setDescender:(CGFloat)descender\ +{\ + _propertyLock.lock();\ + _environmentState.layoutOptionsState.descender = descender;\ + [self propagateUpLayoutOptionsState];\ + _propertyLock.unlock();\ +}\ +\ +- (ASRelativeSizeRange)sizeRange\ +{\ + ASDN::MutexLocker l(_propertyLock);\ + return _environmentState.layoutOptionsState.sizeRange;\ +}\ +\ +- (void)setSizeRange:(ASRelativeSizeRange)sizeRange\ +{\ + _propertyLock.lock();\ + _environmentState.layoutOptionsState.sizeRange = sizeRange;\ + [self propagateUpLayoutOptionsState];\ + _propertyLock.unlock();\ +}\ +\ +- (CGPoint)layoutPosition\ +{\ + ASDN::MutexLocker l(_propertyLock);\ + return _environmentState.layoutOptionsState.layoutPosition;\ +}\ +\ +- (void)setLayoutPosition:(CGPoint)layoutPosition\ +{\ + _propertyLock.lock();\ + _environmentState.layoutOptionsState.layoutPosition = layoutPosition;\ + [self propagateUpLayoutOptionsState];\ + _propertyLock.unlock();\ +}\ + + +#pragma mark - ASLayoutableExtensibility + +#define ASEnvironmentLayoutExtensibilityForwarding \ +- (void)setLayoutOptionExtensionBool:(BOOL)value atIndex:(int)idx\ +{\ + _ASEnvironmentLayoutOptionsExtensionSetBoolAtIndex(self, idx, value);\ +}\ +\ +- (BOOL)layoutOptionExtensionBoolAtIndex:(int)idx\ +{\ + return _ASEnvironmentLayoutOptionsExtensionGetBoolAtIndex(self, idx);\ +}\ +\ +- (void)setLayoutOptionExtensionInteger:(NSInteger)value atIndex:(int)idx\ +{\ + _ASEnvironmentLayoutOptionsExtensionSetIntegerAtIndex(self, idx, value);\ +}\ +\ +- (NSInteger)layoutOptionExtensionIntegerAtIndex:(int)idx\ +{\ + return _ASEnvironmentLayoutOptionsExtensionGetIntegerAtIndex(self, idx);\ +}\ +\ +- (void)setLayoutOptionExtensionEdgeInsets:(UIEdgeInsets)value atIndex:(int)idx\ +{\ + _ASEnvironmentLayoutOptionsExtensionSetEdgeInsetsAtIndex(self, idx, value);\ +}\ +\ +- (UIEdgeInsets)layoutOptionExtensionEdgeInsetsAtIndex:(int)idx\ +{\ + return _ASEnvironmentLayoutOptionsExtensionGetEdgeInsetsAtIndex(self, idx);\ +}\ diff --git a/AsyncDisplayKit/Layout/ASStackLayoutSpec.mm b/AsyncDisplayKit/Layout/ASStackLayoutSpec.mm index 6af951ec86..26b6d449c7 100644 --- a/AsyncDisplayKit/Layout/ASStackLayoutSpec.mm +++ b/AsyncDisplayKit/Layout/ASStackLayoutSpec.mm @@ -200,9 +200,9 @@ @implementation ASStackLayoutSpec (ASEnvironment) -- (BOOL)supportsMultipleChildren +- (BOOL)supportsUpwardPropagation { - return YES; + return NO; } @end diff --git a/AsyncDisplayKit/Layout/ASStaticLayoutSpec.mm b/AsyncDisplayKit/Layout/ASStaticLayoutSpec.mm index 388b06aa02..a727376a57 100644 --- a/AsyncDisplayKit/Layout/ASStaticLayoutSpec.mm +++ b/AsyncDisplayKit/Layout/ASStaticLayoutSpec.mm @@ -87,9 +87,9 @@ @implementation ASStaticLayoutSpec (ASEnvironment) -- (BOOL)supportsMultipleChildren +- (BOOL)supportsUpwardPropagation { - return YES; + return NO; } @end diff --git a/AsyncDisplayKit/Private/ASDisplayNodeInternal.h b/AsyncDisplayKit/Private/ASDisplayNodeInternal.h index f632f64ae0..e8930b9865 100644 --- a/AsyncDisplayKit/Private/ASDisplayNodeInternal.h +++ b/AsyncDisplayKit/Private/ASDisplayNodeInternal.h @@ -97,7 +97,7 @@ FOUNDATION_EXPORT NSString * const ASRenderingEngineDidDisplayNodesScheduledBefo // This is the desired contentsScale, not the scale at which the layer's contents should be displayed CGFloat _contentsScaleForDisplay; - ASEnvironmentCollection _environmentCollection; + ASEnvironmentState _environmentState; ASLayout *_layout; ASSizeRange _constrainedSize; diff --git a/AsyncDisplayKit/Private/ASEnvironmentInternal.h b/AsyncDisplayKit/Private/ASEnvironmentInternal.h index 877508330a..9cf9a11e55 100644 --- a/AsyncDisplayKit/Private/ASEnvironmentInternal.h +++ b/AsyncDisplayKit/Private/ASEnvironmentInternal.h @@ -12,7 +12,7 @@ #pragma once -enum ASEnvironmentStatePropagation { DOWN, UP }; +enum class ASEnvironmentStatePropagation { DOWN, UP }; #pragma mark - Set and get extensible values for layout options @@ -36,34 +36,34 @@ void ASEnvironmentPerformBlockOnObjectAndParents(id object, void( #pragma mark - Merging static const struct ASEnvironmentLayoutOptionsState ASEnvironmentDefaultLayoutOptionsState = {}; -void ASEnvironmentMergeObjectAndState(id object, ASEnvironmentLayoutOptionsState& state, ASEnvironmentStatePropagation propagation); +ASEnvironmentState ASEnvironmentMergeObjectAndState(ASEnvironmentState environmentState, ASEnvironmentLayoutOptionsState state, ASEnvironmentStatePropagation propagation); static const struct ASEnvironmentHierarchyState ASEnvironmentDefaultHierarchyState = {}; -void ASEnvironmentMergeObjectAndState(id object, ASEnvironmentHierarchyState& state, ASEnvironmentStatePropagation propagation); +ASEnvironmentState ASEnvironmentMergeObjectAndState(ASEnvironmentState environmentState, ASEnvironmentHierarchyState state, ASEnvironmentStatePropagation propagation); #pragma mark - Propagation template -void ASEnvironmentStatePropagateDown(id object, ASEnvironmentStateType& state) { +void ASEnvironmentStatePropagateDown(id object, ASEnvironmentStateType state) { ASEnvironmentPerformBlockOnObjectAndChildren(object, ^(id node) { - ASEnvironmentMergeObjectAndState(object, state, DOWN); + object.environmentState = ASEnvironmentMergeObjectAndState(object.environmentState, state, ASEnvironmentStatePropagation::DOWN); }); } template -void ASEnvironmentStatePropagateUp(id object, ASEnvironmentStateType& state) { +void ASEnvironmentStatePropagateUp(id object, ASEnvironmentStateType state) { ASEnvironmentPerformBlockOnObjectAndParents(object, ^(id node) { - ASEnvironmentMergeObjectAndState(object, state, UP); + object.environmentState = ASEnvironmentMergeObjectAndState(object.environmentState, state, ASEnvironmentStatePropagation::UP); }); } template void ASEnvironmentStateApply(id object, ASEnvironmentStateType& state, ASEnvironmentStatePropagation propagate) { - if (propagate == DOWN) { + if (propagate == ASEnvironmentStatePropagation::DOWN) { ASEnvironmentStatePropagateUp(object, state); - } else if (propagate == UP) { + } else if (propagate == ASEnvironmentStatePropagation::UP) { ASEnvironmentStatePropagateDown(object, state); } } diff --git a/AsyncDisplayKit/Private/ASEnvironmentInternal.mm b/AsyncDisplayKit/Private/ASEnvironmentInternal.mm index 2ab5ed21a0..4bec0df268 100644 --- a/AsyncDisplayKit/Private/ASEnvironmentInternal.mm +++ b/AsyncDisplayKit/Private/ASEnvironmentInternal.mm @@ -52,65 +52,66 @@ void _ASEnvironmentLayoutOptionsExtensionSetBoolAtIndex(id object { NSCAssert(idx < kMaxEnvironmentStateBoolExtensions, @"Setting index outside of max bool extensions space"); - ASEnvironmentStateExtensions extension = object.environmentCollection->layoutOptionsState._extensions; + ASEnvironmentStateExtensions extension = object.environmentState.layoutOptionsState._extensions; extension.boolExtensions[idx] = value; - object.environmentCollection->layoutOptionsState._extensions = extension; + object.environmentState.layoutOptionsState._extensions = extension; } BOOL _ASEnvironmentLayoutOptionsExtensionGetBoolAtIndex(id object, int idx) { NSCAssert(idx < kMaxEnvironmentStateBoolExtensions, @"Accessing index outside of max bool extensions space"); - return object.environmentCollection->layoutOptionsState._extensions.boolExtensions[idx]; + return object.environmentState.layoutOptionsState._extensions.boolExtensions[idx]; } void _ASEnvironmentLayoutOptionsExtensionSetIntegerAtIndex(id object, int idx, NSInteger value) { NSCAssert(idx < kMaxEnvironmentStateIntegerExtensions, @"Setting index outside of max integer extensions space"); - ASEnvironmentStateExtensions extension = object.environmentCollection->layoutOptionsState._extensions; + ASEnvironmentStateExtensions extension = object.environmentState.layoutOptionsState._extensions; extension.integerExtensions[idx] = value; - object.environmentCollection->layoutOptionsState._extensions = extension; + object.environmentState.layoutOptionsState._extensions = extension; } NSInteger _ASEnvironmentLayoutOptionsExtensionGetIntegerAtIndex(id object, int idx) { NSCAssert(idx < kMaxEnvironmentStateIntegerExtensions, @"Accessing index outside of max integer extensions space"); - return object.environmentCollection->layoutOptionsState._extensions.integerExtensions[idx]; + return object.environmentState.layoutOptionsState._extensions.integerExtensions[idx]; } void _ASEnvironmentLayoutOptionsExtensionSetEdgeInsetsAtIndex(id object, int idx, UIEdgeInsets value) { NSCAssert(idx < kMaxEnvironmentStateEdgeInsetExtensions, @"Setting index outside of max edge insets extensions space"); - ASEnvironmentStateExtensions extension = object.environmentCollection->layoutOptionsState._extensions; + ASEnvironmentStateExtensions extension = object.environmentState.layoutOptionsState._extensions; extension.edgeInsetsExtensions[idx] = value; - object.environmentCollection->layoutOptionsState._extensions = extension; + object.environmentState.layoutOptionsState._extensions = extension; } UIEdgeInsets _ASEnvironmentLayoutOptionsExtensionGetEdgeInsetsAtIndex(id object, int idx) { NSCAssert(idx < kMaxEnvironmentStateEdgeInsetExtensions, @"Accessing index outside of max edge insets extensions space"); - return object.environmentCollection->layoutOptionsState._extensions.edgeInsetsExtensions[idx]; + return object.environmentState.layoutOptionsState._extensions.edgeInsetsExtensions[idx]; } #pragma mark - Merging functions for states -void ASEnvironmentMergeObjectAndState(id object, ASEnvironmentHierarchyState& state, ASEnvironmentStatePropagation propagation) { +ASEnvironmentState ASEnvironmentMergeObjectAndState(ASEnvironmentState environmentState, ASEnvironmentHierarchyState state, ASEnvironmentStatePropagation propagation) { // Merge object and hierarchy state LOG(@"Merge object and state: %@ - ASEnvironmentHierarchyState", object); + return environmentState; } -void ASEnvironmentMergeObjectAndState(id object, ASEnvironmentLayoutOptionsState& state, ASEnvironmentStatePropagation propagation) { +ASEnvironmentState ASEnvironmentMergeObjectAndState(ASEnvironmentState environmentState, ASEnvironmentLayoutOptionsState state, ASEnvironmentStatePropagation propagation) { // Merge object and layout options state LOG(@"Merge object and state: %@ - ASEnvironmentLayoutOptionsState", object); // Support propagate up - if (propagation == UP) { + if (propagation == ASEnvironmentStatePropagation::UP) { // Object is the parent and the state is the state of the child const ASEnvironmentLayoutOptionsState defaultState = ASEnvironmentDefaultLayoutOptionsState; - ASEnvironmentLayoutOptionsState parentState = object.environmentCollection->layoutOptionsState; + ASEnvironmentLayoutOptionsState parentState = environmentState.layoutOptionsState; // For every field check if the parent value is equal to the default than propegate up the child value to // the parent @@ -143,7 +144,8 @@ void ASEnvironmentMergeObjectAndState(id object, ASEnvironmentLay parentState.layoutPosition = defaultState.layoutPosition; } - object.environmentCollection->layoutOptionsState = parentState; + environmentState.layoutOptionsState = parentState; } + return environmentState; } From f46f5640ff24914e15be6b0bd72590e20b2070a4 Mon Sep 17 00:00:00 2001 From: Michael Schneider Date: Thu, 31 Mar 2016 10:30:43 -0700 Subject: [PATCH 4/6] Add improvements - Remove defaults for ASEnvironmentLayoutOptionsState and ASEnvironmentHierarchyState - Add locking for ASEnvironmentLayoutExtensibilityForwarding - Other smaller improvements --- AsyncDisplayKit/ASDisplayNode.mm | 2 +- AsyncDisplayKit/Details/ASEnvironment.h | 3 +-- AsyncDisplayKit/Details/ASEnvironment.m | 20 ++++++------------- AsyncDisplayKit/Layout/ASLayoutSpec.mm | 9 +++++---- .../Layout/ASLayoutableExtensibility.h | 2 +- AsyncDisplayKit/Layout/ASLayoutablePrivate.h | 9 +++++++++ 6 files changed, 23 insertions(+), 22 deletions(-) diff --git a/AsyncDisplayKit/ASDisplayNode.mm b/AsyncDisplayKit/ASDisplayNode.mm index 3bfe80760c..850d0a46aa 100644 --- a/AsyncDisplayKit/ASDisplayNode.mm +++ b/AsyncDisplayKit/ASDisplayNode.mm @@ -1704,7 +1704,7 @@ static NSInteger incrementIfFound(NSInteger i) { } if ([newSupernode supportsUpwardPropagation]) { - ASEnvironmentStatePropagateUp(newSupernode, self.environmentState.layoutOptionsState); + ASEnvironmentStatePropagateUp(newSupernode, _environmentState.layoutOptionsState); } } diff --git a/AsyncDisplayKit/Details/ASEnvironment.h b/AsyncDisplayKit/Details/ASEnvironment.h index 43e21bda09..62e352fb52 100644 --- a/AsyncDisplayKit/Details/ASEnvironment.h +++ b/AsyncDisplayKit/Details/ASEnvironment.h @@ -48,7 +48,6 @@ typedef struct ASEnvironmentLayoutOptionsState { ASEnvironmentStateExtensions _extensions; } ASEnvironmentLayoutOptionsState; -extern ASEnvironmentLayoutOptionsState ASEnvironmentLayoutOptionsStateCreate(); #pragma mark - ASEnvironmentHierarchyState @@ -59,7 +58,6 @@ typedef struct ASEnvironmentHierarchyState { unsigned transitioningSupernodes:1; // = NO unsigned layoutPending:1; // = NO } ASEnvironmentHierarchyState; -extern ASEnvironmentHierarchyState ASEnvironmentHierarchyStateCreate(); #pragma mark - ASEnvironmentState @@ -92,6 +90,7 @@ ASDISPLAYNODE_EXTERN_C_END /// Returns all children of an object which class conforms to the ASEnvironment protocol - (NSArray> *)children; +/// Classes should implement this method and return YES / NO dependent if upward propagation is enabled or not - (BOOL)supportsUpwardPropagation; @end diff --git a/AsyncDisplayKit/Details/ASEnvironment.m b/AsyncDisplayKit/Details/ASEnvironment.m index 5cbe4d95c1..01006405d4 100644 --- a/AsyncDisplayKit/Details/ASEnvironment.m +++ b/AsyncDisplayKit/Details/ASEnvironment.m @@ -10,32 +10,24 @@ #import "ASEnvironment.h" -ASEnvironmentLayoutOptionsState ASEnvironmentLayoutOptionsStateCreate() +ASEnvironmentLayoutOptionsState _ASEnvironmentLayoutOptionsStateCreate() { return (ASEnvironmentLayoutOptionsState) { - .spacingBefore = 0, - .flexBasis = ASRelativeDimensionUnconstrained, - .alignSelf = ASStackLayoutAlignSelfAuto, - - .sizeRange = ASRelativeSizeRangeMake(ASRelativeSizeMakeWithCGSize(CGSizeZero), ASRelativeSizeMakeWithCGSize(CGSizeZero)), - .layoutPosition = CGPointZero + // Default values can be defined in here }; } -ASEnvironmentHierarchyState ASEnvironmentHierarchyStateCreate() +ASEnvironmentHierarchyState _ASEnvironmentHierarchyStateCreate() { return (ASEnvironmentHierarchyState) { - .rasterized = NO, - .rangeManaged = NO, - .transitioningSupernodes = NO, - .layoutPending = NO + // Default values can be defined in here }; } ASEnvironmentState ASEnvironmentStateCreate() { return (ASEnvironmentState) { - .hierarchyState = ASEnvironmentHierarchyStateCreate(), - .layoutOptionsState = ASEnvironmentLayoutOptionsStateCreate() + .layoutOptionsState = _ASEnvironmentLayoutOptionsStateCreate(), + .hierarchyState = _ASEnvironmentHierarchyStateCreate() }; } \ No newline at end of file diff --git a/AsyncDisplayKit/Layout/ASLayoutSpec.mm b/AsyncDisplayKit/Layout/ASLayoutSpec.mm index 7c7598b90a..94e7e0a1a9 100644 --- a/AsyncDisplayKit/Layout/ASLayoutSpec.mm +++ b/AsyncDisplayKit/Layout/ASLayoutSpec.mm @@ -81,10 +81,8 @@ static NSString * const kDefaultChildrenKey = @"kDefaultChildrenKey"; id finalLayoutable = [child finalLayoutable]; if (finalLayoutable != child) { - // Copy layout options - ASEnvironmentState environmentState = finalLayoutable.environmentState; - environmentState.layoutOptionsState = child.environmentState.layoutOptionsState; - finalLayoutable.environmentState = environmentState; + // Layout options state of child needs to be copied to final layoutable + finalLayoutable.environmentState.layoutOptionsState = child.environmentState.layoutOptionsState; return finalLayoutable; } } @@ -159,6 +157,9 @@ static NSString * const kDefaultChildrenKey = @"kDefaultChildrenKey"; _environmentState = environmentState; } +// Subclasses can override this method to return NO, because upward propagation is not enabled if a layout +// specification has more than one child. Currently ASStackLayoutSpec and ASStaticLayoutSpec are currently +// the specifications that are known to have more than one. - (BOOL)supportsUpwardPropagation { return YES; diff --git a/AsyncDisplayKit/Layout/ASLayoutableExtensibility.h b/AsyncDisplayKit/Layout/ASLayoutableExtensibility.h index 1451368d27..c35d04f046 100644 --- a/AsyncDisplayKit/Layout/ASLayoutableExtensibility.h +++ b/AsyncDisplayKit/Layout/ASLayoutableExtensibility.h @@ -6,7 +6,7 @@ // Copyright © 2016 Facebook. All rights reserved. // -#import +#import @protocol ASLayoutableExtensibility diff --git a/AsyncDisplayKit/Layout/ASLayoutablePrivate.h b/AsyncDisplayKit/Layout/ASLayoutablePrivate.h index d18d0b7419..ce2de20f6d 100644 --- a/AsyncDisplayKit/Layout/ASLayoutablePrivate.h +++ b/AsyncDisplayKit/Layout/ASLayoutablePrivate.h @@ -231,30 +231,39 @@ extern void ASLayoutableClearCurrentContext(); #define ASEnvironmentLayoutExtensibilityForwarding \ - (void)setLayoutOptionExtensionBool:(BOOL)value atIndex:(int)idx\ {\ + _propertyLock.lock();\ _ASEnvironmentLayoutOptionsExtensionSetBoolAtIndex(self, idx, value);\ + _propertyLock.unlock();\ }\ \ - (BOOL)layoutOptionExtensionBoolAtIndex:(int)idx\ {\ + ASDN::MutexLocker l(_propertyLock);\ return _ASEnvironmentLayoutOptionsExtensionGetBoolAtIndex(self, idx);\ }\ \ - (void)setLayoutOptionExtensionInteger:(NSInteger)value atIndex:(int)idx\ {\ + _propertyLock.lock();\ _ASEnvironmentLayoutOptionsExtensionSetIntegerAtIndex(self, idx, value);\ + _propertyLock.unlock();\ }\ \ - (NSInteger)layoutOptionExtensionIntegerAtIndex:(int)idx\ {\ + ASDN::MutexLocker l(_propertyLock);\ return _ASEnvironmentLayoutOptionsExtensionGetIntegerAtIndex(self, idx);\ }\ \ - (void)setLayoutOptionExtensionEdgeInsets:(UIEdgeInsets)value atIndex:(int)idx\ {\ + _propertyLock.lock();\ _ASEnvironmentLayoutOptionsExtensionSetEdgeInsetsAtIndex(self, idx, value);\ + _propertyLock.unlock();\ }\ \ - (UIEdgeInsets)layoutOptionExtensionEdgeInsetsAtIndex:(int)idx\ {\ + ASDN::MutexLocker l(_propertyLock);\ return _ASEnvironmentLayoutOptionsExtensionGetEdgeInsetsAtIndex(self, idx);\ }\ From 5baab95506f24d167f7b979fa1c83e0ea51677d2 Mon Sep 17 00:00:00 2001 From: Michael Schneider Date: Thu, 31 Mar 2016 11:24:54 -0700 Subject: [PATCH 5/6] Add up propagation of ASEnvironmentLayoutOptionsState in ASLayoutSpec while setting a child --- AsyncDisplayKit/Layout/ASLayoutSpec.mm | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/AsyncDisplayKit/Layout/ASLayoutSpec.mm b/AsyncDisplayKit/Layout/ASLayoutSpec.mm index 94e7e0a1a9..72904044ff 100644 --- a/AsyncDisplayKit/Layout/ASLayoutSpec.mm +++ b/AsyncDisplayKit/Layout/ASLayoutSpec.mm @@ -114,7 +114,14 @@ static NSString * const kDefaultChildrenKey = @"kDefaultChildrenKey"; - (void)setChild:(id)child forIdentifier:(NSString *)identifier { ASDisplayNodeAssert(self.isMutable, @"Cannot set properties when layout spec is not mutable"); - self.layoutChildren[identifier] = [self layoutableToAddFromLayoutable:child];; + id finalLayoutable = [self layoutableToAddFromLayoutable:child]; + BOOL needsToPropagateLayoutOptionsState = (child != finalLayoutable); + self.layoutChildren[identifier] = finalLayoutable; + if (needsToPropagateLayoutOptionsState) { + // We only need to propagate up layout options in setChild: as up propagation is currently only supported for + // layout specification has with one child + [self propagateUpLayoutOptionsState]; + } } - (void)setChildren:(NSArray *)children From 20ee9bca8d0bb11e206ae05de9571e7587de75a8 Mon Sep 17 00:00:00 2001 From: Michael Schneider Date: Thu, 31 Mar 2016 20:42:22 -0700 Subject: [PATCH 6/6] Rename ASEnvironmentStateCreate to ASEnvironmentStateMakeDefault --- AsyncDisplayKit/ASDisplayNode.mm | 2 +- AsyncDisplayKit/Details/ASEnvironment.h | 2 +- AsyncDisplayKit/Details/ASEnvironment.m | 10 +++++----- AsyncDisplayKit/Layout/ASLayoutSpec.mm | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/AsyncDisplayKit/ASDisplayNode.mm b/AsyncDisplayKit/ASDisplayNode.mm index 850d0a46aa..0d0b362b85 100644 --- a/AsyncDisplayKit/ASDisplayNode.mm +++ b/AsyncDisplayKit/ASDisplayNode.mm @@ -253,7 +253,7 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c) _displaySentinel = [[ASSentinel alloc] init]; _preferredFrameSize = CGSizeZero; - _environmentState = ASEnvironmentStateCreate(); + _environmentState = ASEnvironmentStateMakeDefault(); } - (id)init diff --git a/AsyncDisplayKit/Details/ASEnvironment.h b/AsyncDisplayKit/Details/ASEnvironment.h index 62e352fb52..20837d4aa4 100644 --- a/AsyncDisplayKit/Details/ASEnvironment.h +++ b/AsyncDisplayKit/Details/ASEnvironment.h @@ -66,7 +66,7 @@ typedef struct ASEnvironmentState { struct ASEnvironmentHierarchyState hierarchyState; struct ASEnvironmentLayoutOptionsState layoutOptionsState; } ASEnvironmentState; -extern ASEnvironmentState ASEnvironmentStateCreate(); +extern ASEnvironmentState ASEnvironmentStateMakeDefault(); ASDISPLAYNODE_EXTERN_C_END diff --git a/AsyncDisplayKit/Details/ASEnvironment.m b/AsyncDisplayKit/Details/ASEnvironment.m index 01006405d4..f3b2039f8f 100644 --- a/AsyncDisplayKit/Details/ASEnvironment.m +++ b/AsyncDisplayKit/Details/ASEnvironment.m @@ -10,24 +10,24 @@ #import "ASEnvironment.h" -ASEnvironmentLayoutOptionsState _ASEnvironmentLayoutOptionsStateCreate() +ASEnvironmentLayoutOptionsState _ASEnvironmentLayoutOptionsStateMakeDefault() { return (ASEnvironmentLayoutOptionsState) { // Default values can be defined in here }; } -ASEnvironmentHierarchyState _ASEnvironmentHierarchyStateCreate() +ASEnvironmentHierarchyState _ASEnvironmentHierarchyStateMakeDefault() { return (ASEnvironmentHierarchyState) { // Default values can be defined in here }; } -ASEnvironmentState ASEnvironmentStateCreate() +ASEnvironmentState ASEnvironmentStateMakeDefault() { return (ASEnvironmentState) { - .layoutOptionsState = _ASEnvironmentLayoutOptionsStateCreate(), - .hierarchyState = _ASEnvironmentHierarchyStateCreate() + .layoutOptionsState = _ASEnvironmentLayoutOptionsStateMakeDefault(), + .hierarchyState = _ASEnvironmentHierarchyStateMakeDefault() }; } \ No newline at end of file diff --git a/AsyncDisplayKit/Layout/ASLayoutSpec.mm b/AsyncDisplayKit/Layout/ASLayoutSpec.mm index 72904044ff..c61e7a966f 100644 --- a/AsyncDisplayKit/Layout/ASLayoutSpec.mm +++ b/AsyncDisplayKit/Layout/ASLayoutSpec.mm @@ -44,7 +44,7 @@ static NSString * const kDefaultChildrenKey = @"kDefaultChildrenKey"; return nil; } _isMutable = YES; - _environmentState = ASEnvironmentStateCreate(); + _environmentState = ASEnvironmentStateMakeDefault(); return self; }