Skip to content

Commit

Permalink
Simplify Layout Transition State #trivial (TextureGroup#269)
Browse files Browse the repository at this point in the history
* Port the changes to the latest master

* Remove extra s
  • Loading branch information
Adlai-Holler authored and bernieperez committed Apr 25, 2018
1 parent a1b6fd2 commit bd742e6
Show file tree
Hide file tree
Showing 4 changed files with 27 additions and 67 deletions.
75 changes: 21 additions & 54 deletions Source/ASDisplayNode+Layout.mm
Original file line number Diff line number Diff line change
Expand Up @@ -454,12 +454,6 @@ - (void)setAutomaticallyManagesSubnodes:(BOOL)automaticallyManagesSubnodes

@implementation ASDisplayNode (ASLayoutTransition)

- (BOOL)_isTransitionInProgress
{
ASDN::MutexLocker l(__instanceLock__);
return _transitionInProgress;
}

- (BOOL)_isLayoutTransitionInvalid
{
ASDN::MutexLocker l(__instanceLock__);
Expand All @@ -475,40 +469,17 @@ - (BOOL)_isLayoutTransitionInvalid
/// Starts a new transition and returns the transition id
- (int32_t)_startNewTransition
{
ASDN::MutexLocker l(__instanceLock__);
_transitionInProgress = YES;
_transitionID = OSAtomicAdd32(1, &_transitionID);
return _transitionID;
}

- (void)_finishOrCancelTransition
{
ASDN::MutexLocker l(__instanceLock__);
_transitionInProgress = NO;
static std::atomic<int32_t> gNextTransitionID;
int32_t newTransitionID = gNextTransitionID.fetch_add(1) + 1;
_transitionID = newTransitionID;
return newTransitionID;
}

- (void)setPendingTransitionID:(int32_t)pendingTransitionID
{
ASDN::MutexLocker l(__instanceLock__);
ASDisplayNodeAssertTrue(_pendingTransitionID < pendingTransitionID);
_pendingTransitionID = pendingTransitionID;
}

- (int32_t)pendingTransitionID
/// Returns NO if there was no transition to cancel/finish.
- (BOOL)_finishOrCancelTransition
{
ASDN::MutexLocker l(__instanceLock__);
return _pendingTransitionID;
}

- (BOOL)_shouldAbortTransitionWithID:(int32_t)transitionID
{
ASDN::MutexLocker l(__instanceLock__);
return [self _locked_shouldAbortTransitionWithID:transitionID];
}

- (BOOL)_locked_shouldAbortTransitionWithID:(int32_t)transitionID
{
return (!_transitionInProgress || _transitionID != transitionID);
int32_t oldValue = _transitionID.exchange(ASLayoutElementContextInvalidTransitionID);
return oldValue != ASLayoutElementContextInvalidTransitionID;
}

#pragma mark Layout Transition
Expand Down Expand Up @@ -554,17 +525,21 @@ - (void)transitionLayoutWithSizeRange:(ASSizeRange)constrainedSize

// Every new layout transition has a transition id associated to check in subsequent transitions for cancelling
int32_t transitionID = [self _startNewTransition];

// NOTE: This block captures self. It's cheaper than hitting the weak table.
asdisplaynode_iscancelled_block_t isCancelled = ^{
return (BOOL)(_transitionID != transitionID);
};

// Move all subnodes in layout pending state for this transition
ASDisplayNodePerformBlockOnEverySubnode(self, NO, ^(ASDisplayNode * _Nonnull node) {
ASDisplayNodeAssert([node _isTransitionInProgress] == NO, @"Can't start a transition when one of the subnodes is performing one.");
ASDisplayNodeAssert(node->_transitionID == ASLayoutElementContextInvalidTransitionID, @"Can't start a transition when one of the subnodes is performing one.");
node.hierarchyState |= ASHierarchyStateLayoutPending;
node.pendingTransitionID = transitionID;
node->_pendingTransitionID = transitionID;
});

// Transition block that executes the layout transition
void (^transitionBlock)(void) = ^{
if ([self _shouldAbortTransitionWithID:transitionID]) {
if (isCancelled()) {
return;
}

Expand All @@ -587,22 +562,21 @@ - (void)transitionLayoutWithSizeRange:(ASSizeRange)constrainedSize
ASLayoutElementClearCurrentContext();
}

if ([self _shouldAbortTransitionWithID:transitionID]) {
if (isCancelled()) {
return;
}

ASPerformBlockOnMainThread(^{
if (isCancelled()) {
return;
}
ASLayoutTransition *pendingLayoutTransition;
_ASTransitionContext *pendingLayoutTransitionContext;
{
// Grab __instanceLock__ here to make sure this transition isn't invalidated
// right after it passed the validation test and before it proceeds
ASDN::MutexLocker l(__instanceLock__);

if ([self _locked_shouldAbortTransitionWithID:transitionID]) {
return;
}

// Update calculated layout
auto previousLayout = _calculatedDisplayNodeLayout;
auto pendingLayout = std::make_shared<ASDisplayNodeLayout>(newLayout,
Expand Down Expand Up @@ -654,14 +628,7 @@ - (void)transitionLayoutWithSizeRange:(ASSizeRange)constrainedSize

- (void)cancelLayoutTransition
{
__instanceLock__.lock();
BOOL transitionInProgress = _transitionInProgress;
__instanceLock__.unlock();

if (transitionInProgress) {
// Cancel transition in progress
[self _finishOrCancelTransition];

if ([self _finishOrCancelTransition]) {
// Tell subnodes to exit layout pending state and clear related properties
ASDisplayNodePerformBlockOnEverySubnode(self, NO, ^(ASDisplayNode * _Nonnull node) {
node.hierarchyState &= (~ASHierarchyStateLayoutPending);
Expand Down
7 changes: 3 additions & 4 deletions Source/ASDisplayNode.mm
Original file line number Diff line number Diff line change
Expand Up @@ -916,7 +916,7 @@ - (void)__layout

// If a current layout transition is in progress there is no need to do a measurement and layout pass in here as
// this is supposed to happen within the layout transition process
if (_transitionInProgress) {
if (_transitionID != ASLayoutElementContextInvalidTransitionID) {
return;
}

Expand Down Expand Up @@ -1807,15 +1807,14 @@ - (void)_setSupernode:(ASDisplayNode *)newSupernode
// This is especially important as with automatic subnode management, adding subnodes can happen while a transition
// is in fly
if (ASHierarchyStateIncludesLayoutPending(stateToEnterOrExit)) {
int32_t pendingTransitionId = newSupernode.pendingTransitionID;
int32_t pendingTransitionId = newSupernode->_pendingTransitionID;
if (pendingTransitionId != ASLayoutElementContextInvalidTransitionID) {
{
ASDN::MutexLocker l(__instanceLock__);
_pendingTransitionID = pendingTransitionId;

// Propagate down the new pending transition id
ASDisplayNodePerformBlockOnEverySubnode(self, NO, ^(ASDisplayNode * _Nonnull node) {
node.pendingTransitionID = pendingTransitionId;
node->_pendingTransitionID = pendingTransitionId;
});
}
}
Expand Down
7 changes: 1 addition & 6 deletions Source/Private/ASDisplayNode+FrameworkPrivate.h
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ __unused static NSString * _Nonnull NSStringFromASHierarchyState(ASHierarchyStat
@end


@interface ASDisplayNode (ASsLayoutInternal)
@interface ASDisplayNode (ASLayoutInternal)

/**
* @abstract Informs the root node that the intrinsic size of the receiver is no longer valid.
Expand Down Expand Up @@ -260,11 +260,6 @@ __unused static NSString * _Nonnull NSStringFromASHierarchyState(ASHierarchyStat

@interface ASDisplayNode (ASLayoutTransitionInternal)

/**
* Sentinel of the current layout transition
*/
@property (atomic, assign) int32_t pendingTransitionID;

/**
* If one or multiple layout transitions are in flight this methods returns if the current layout transition that
* happens in in this particular thread was invalidated through another thread is starting a transition for this node
Expand Down
5 changes: 2 additions & 3 deletions Source/Private/ASDisplayNodeInternal.h
Original file line number Diff line number Diff line change
Expand Up @@ -150,10 +150,9 @@ FOUNDATION_EXPORT NSString * const ASRenderingEngineDidDisplayNodesScheduledBefo

ASLayoutSpecBlock _layoutSpecBlock;

int32_t _transitionID;
BOOL _transitionInProgress;
std::atomic<int32_t> _transitionID;

int32_t _pendingTransitionID;
std::atomic<int32_t> _pendingTransitionID;
ASLayoutTransition *_pendingLayoutTransition;
std::shared_ptr<ASDisplayNodeLayout> _calculatedDisplayNodeLayout;
std::shared_ptr<ASDisplayNodeLayout> _pendingDisplayNodeLayout;
Expand Down

0 comments on commit bd742e6

Please sign in to comment.