/* 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. */ // // The following methods are ONLY for use by _ASDisplayLayer, _ASDisplayView, and ASDisplayNode. // These methods must never be called or overridden by other classes. // #import "_AS-objc-internal.h" #import "ASDisplayNodeExtraIvars.h" #import "ASDisplayNode.h" #import "ASSentinel.h" #import "ASThread.h" #import "ASLayoutOptions.h" #import "_ASTransitionContext.h" #include @protocol _ASDisplayLayerDelegate; @class _ASDisplayLayer; @class _ASPendingState; BOOL ASDisplayNodeSubclassOverridesSelector(Class subclass, SEL selector); /// Get the pending view state for the node, creating one if needed. _ASPendingState *ASDisplayNodeGetPendingState(ASDisplayNode *node); typedef NS_OPTIONS(NSUInteger, ASDisplayNodeMethodOverrides) { ASDisplayNodeMethodOverrideNone = 0, ASDisplayNodeMethodOverrideTouchesBegan = 1 << 0, ASDisplayNodeMethodOverrideTouchesCancelled = 1 << 1, ASDisplayNodeMethodOverrideTouchesEnded = 1 << 2, ASDisplayNodeMethodOverrideTouchesMoved = 1 << 3, ASDisplayNodeMethodOverrideLayoutSpecThatFits = 1 << 4 }; @class _ASDisplayNodePosition; FOUNDATION_EXPORT NSString * const ASRenderingEngineDidDisplayScheduledNodesNotification; FOUNDATION_EXPORT NSString * const ASRenderingEngineDidDisplayNodesScheduledBeforeTimestamp; // Allow 2^n increments of begin disabling hierarchy notifications #define VISIBILITY_NOTIFICATIONS_DISABLED_BITS 4 #define TIME_DISPLAYNODE_OPS 0 // If you're using this information frequently, try: (DEBUG || PROFILE) @interface ASDisplayNode () { @package _ASPendingState *_pendingViewState; // Protects access to _view, _layer, _pendingViewState, _subnodes, _supernode, and other properties which are accessed from multiple threads. ASDN::RecursiveMutex _propertyLock; UIView *_view; CALayer *_layer; struct ASDisplayNodeFlags { // public properties unsigned synchronous:1; unsigned layerBacked:1; unsigned displaysAsynchronously:1; unsigned shouldRasterizeDescendants:1; unsigned shouldBypassEnsureDisplay:1; unsigned displaySuspended:1; unsigned hasCustomDrawingPriority:1; // whether custom drawing is enabled unsigned implementsInstanceDrawRect:1; unsigned implementsDrawRect:1; unsigned implementsInstanceImageDisplay:1; unsigned implementsImageDisplay:1; unsigned implementsDrawParameters:1; // internal state unsigned isMeasured:1; unsigned isEnteringHierarchy:1; unsigned isExitingHierarchy:1; unsigned isInHierarchy:1; unsigned isMovingBetweenNodes:1; unsigned visibilityNotificationsDisabled:VISIBILITY_NOTIFICATIONS_DISABLED_BITS; } _flags; @protected ASDisplayNode * __weak _supernode; ASSentinel *_displaySentinel; ASSentinel *_replaceAsyncSentinel; // This is the desired contentsScale, not the scale at which the layer's contents should be displayed CGFloat _contentsScaleForDisplay; ASLayout *_previousLayout; ASLayout *_layout; ASSizeRange _previousConstrainedSize; ASSizeRange _constrainedSize; UIEdgeInsets _hitTestSlop; NSMutableArray *_subnodes; _ASTransitionContext *_transitionContext; BOOL _usesImplicitHierarchyManagement; NSArray *_insertedSubnodes; NSArray *_removedSubnodes; std::vector _insertedSubnodePositions; std::vector _removedSubnodePositions; ASDisplayNodeViewBlock _viewBlock; ASDisplayNodeLayerBlock _layerBlock; ASDisplayNodeDidLoadBlock _nodeLoadedBlock; Class _viewClass; Class _layerClass; UIImage *_placeholderImage; CALayer *_placeholderLayer; // keeps track of nodes/subnodes that have not finished display, used with placeholders NSMutableSet *_pendingDisplayNodes; ASDisplayNodeExtraIvars _extra; ASDisplayNodeContextModifier _willDisplayNodeContentWithRenderingContext; ASDisplayNodeContextModifier _didDisplayNodeContentWithRenderingContext; #if TIME_DISPLAYNODE_OPS @public NSTimeInterval _debugTimeToCreateView; NSTimeInterval _debugTimeToApplyPendingState; NSTimeInterval _debugTimeToAddSubnodeViews; NSTimeInterval _debugTimeForDidLoad; #endif } + (void)scheduleNodeForRecursiveDisplay:(ASDisplayNode *)node; // The _ASDisplayLayer backing the node, if any. @property (nonatomic, readonly, retain) _ASDisplayLayer *asyncLayer; // Bitmask to check which methods an object overrides. @property (nonatomic, assign, readonly) ASDisplayNodeMethodOverrides methodOverrides; // Swizzle to extend the builtin functionality with custom logic - (BOOL)__shouldLoadViewOrLayer; - (BOOL)__shouldSize; /** Invoked before a call to setNeedsLayout to the underlying view */ - (void)__setNeedsLayout; /** Invoked after a call to setNeedsDisplay to the underlying view */ - (void)__setNeedsDisplay; - (void)__layout; - (void)__setSupernode:(ASDisplayNode *)supernode; // Private API for helper functions / unit tests. Use ASDisplayNodeDisableHierarchyNotifications() to control this. - (BOOL)__visibilityNotificationsDisabled; - (BOOL)__selfOrParentHasVisibilityNotificationsDisabled; - (void)__incrementVisibilityNotificationsDisabled; - (void)__decrementVisibilityNotificationsDisabled; // Helper method to summarize whether or not the node run through the display process - (BOOL)__implementsDisplay; // Display the node's view/layer immediately on the current thread, bypassing the background thread rendering. Will be deprecated. - (void)displayImmediately; // Alternative initialiser for backing with a custom view class. Supports asynchronous display with _ASDisplayView subclasses. - (id)initWithViewClass:(Class)viewClass; // Alternative initialiser for backing with a custom layer class. Supports asynchronous display with _ASDisplayLayer subclasses. - (id)initWithLayerClass:(Class)layerClass; @property (nonatomic, assign) CGFloat contentsScaleForDisplay; - (void)applyPendingViewState; /** * // TODO: NOT YET IMPLEMENTED * * @abstract Prevents interface state changes from affecting the node, until disabled. * * @discussion Useful to avoid flashing after removing a node from the hierarchy and re-adding it. * Removing a node from the hierarchy will cause it to exit the Display state, clearing its contents. * For some animations, it's desirable to be able to remove a node without causing it to re-display. * Once re-enabled, the interface state will be updated to the same value it would have been. * * @see ASInterfaceState */ @property (nonatomic, assign) BOOL interfaceStateSuspended; /** * This method has proven helpful in a few rare scenarios, similar to a category extension on UIView, * but it's considered private API for now and its use should not be encouraged. * @param checkViewHierarchy If YES, and no supernode can be found, method will walk up from `self.view` to find a supernode. * If YES, this method must be called on the main thread and the node must not be layer-backed. */ - (ASDisplayNode *)_supernodeWithClass:(Class)supernodeClass checkViewHierarchy:(BOOL)checkViewHierarchy; @end