Add 'submodules/AsyncDisplayKit/' from commit '02bedc12816e251ad71777f9d2578329b6d2bef6'

git-subtree-dir: submodules/AsyncDisplayKit
git-subtree-mainline: d06f423e0e
git-subtree-split: 02bedc1281
This commit is contained in:
Peter
2019-06-11 18:42:43 +01:00
2160 changed files with 232035 additions and 0 deletions

View File

@@ -0,0 +1,101 @@
//
// ASAssert.h
// Texture
//
// Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
// Changes after 4/13/2017 are: Copyright (c) Pinterest, Inc. All rights reserved.
// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
//
#pragma once
#import <Foundation/NSException.h>
#import <pthread.h>
#import <AsyncDisplayKit/ASBaseDefines.h>
#if !defined(NS_BLOCK_ASSERTIONS)
#define ASDISPLAYNODE_ASSERTIONS_ENABLED 1
#else
#define ASDISPLAYNODE_ASSERTIONS_ENABLED 0
#endif
/**
* Note: In some cases it would be sufficient to do e.g.:
* ASDisplayNodeAssert(...) NSAssert(__VA_ARGS__)
* but we prefer not to, because we want to match the autocomplete behavior of NSAssert.
* The construction listed above does not show the user what arguments are required and what are optional.
*/
#define ASDisplayNodeAssert(condition, desc, ...) NSAssert(condition, desc, ##__VA_ARGS__)
#define ASDisplayNodeCAssert(condition, desc, ...) NSCAssert(condition, desc, ##__VA_ARGS__)
#define ASDisplayNodeAssertNil(condition, desc, ...) ASDisplayNodeAssert((condition) == nil, desc, ##__VA_ARGS__)
#define ASDisplayNodeCAssertNil(condition, desc, ...) ASDisplayNodeCAssert((condition) == nil, desc, ##__VA_ARGS__)
#define ASDisplayNodeAssertNotNil(condition, desc, ...) ASDisplayNodeAssert((condition) != nil, desc, ##__VA_ARGS__)
#define ASDisplayNodeCAssertNotNil(condition, desc, ...) ASDisplayNodeCAssert((condition) != nil, desc, ##__VA_ARGS__)
#define ASDisplayNodeAssertImplementedBySubclass() ASDisplayNodeAssert(NO, @"This method must be implemented by subclass %@", [self class]);
#define ASDisplayNodeAssertNotInstantiable() ASDisplayNodeAssert(NO, nil, @"This class is not instantiable.");
#define ASDisplayNodeAssertNotSupported() ASDisplayNodeAssert(NO, nil, @"This method is not supported by class %@", [self class]);
#define ASDisplayNodeAssertMainThread() ASDisplayNodeAssert(ASMainThreadAssertionsAreDisabled() || 0 != pthread_main_np(), @"This method must be called on the main thread")
#define ASDisplayNodeCAssertMainThread() ASDisplayNodeCAssert(ASMainThreadAssertionsAreDisabled() || 0 != pthread_main_np(), @"This function must be called on the main thread")
#define ASDisplayNodeAssertNotMainThread() ASDisplayNodeAssert(0 == pthread_main_np(), @"This method must be called off the main thread")
#define ASDisplayNodeCAssertNotMainThread() ASDisplayNodeCAssert(0 == pthread_main_np(), @"This function must be called off the main thread")
#define ASDisplayNodeAssertFlag(X, desc, ...) ASDisplayNodeAssert((1 == __builtin_popcount(X)), desc, ##__VA_ARGS__)
#define ASDisplayNodeCAssertFlag(X, desc, ...) ASDisplayNodeCAssert((1 == __builtin_popcount(X)), desc, ##__VA_ARGS__)
#define ASDisplayNodeAssertTrue(condition) ASDisplayNodeAssert((condition), @"Expected %s to be true.", #condition)
#define ASDisplayNodeCAssertTrue(condition) ASDisplayNodeCAssert((condition), @"Expected %s to be true.", #condition)
#define ASDisplayNodeAssertFalse(condition) ASDisplayNodeAssert(!(condition), @"Expected %s to be false.", #condition)
#define ASDisplayNodeCAssertFalse(condition) ASDisplayNodeCAssert(!(condition), @"Expected %s to be false.", #condition)
#define ASDisplayNodeFailAssert(desc, ...) ASDisplayNodeAssert(NO, desc, ##__VA_ARGS__)
#define ASDisplayNodeCFailAssert(desc, ...) ASDisplayNodeCAssert(NO, desc, ##__VA_ARGS__)
#define ASDisplayNodeConditionalAssert(shouldTestCondition, condition, desc, ...) ASDisplayNodeAssert((!(shouldTestCondition) || (condition)), desc, ##__VA_ARGS__)
#define ASDisplayNodeConditionalCAssert(shouldTestCondition, condition, desc, ...) ASDisplayNodeCAssert((!(shouldTestCondition) || (condition)), desc, ##__VA_ARGS__)
#define ASDisplayNodeCAssertPositiveReal(description, num) ASDisplayNodeCAssert(num >= 0 && num <= CGFLOAT_MAX, @"%@ must be a real positive integer: %f.", description, (CGFloat)num)
#define ASDisplayNodeCAssertInfOrPositiveReal(description, num) ASDisplayNodeCAssert(isinf(num) || (num >= 0 && num <= CGFLOAT_MAX), @"%@ must be infinite or a real positive integer: %f.", description, (CGFloat)num)
#define ASDisplayNodeCAssertPermanent(object) ASDisplayNodeCAssert(CFGetRetainCount((__bridge CFTypeRef)(object)) == CFGetRetainCount(kCFNull), @"Expected %s to be a permanent object.", #object)
#define ASDisplayNodeErrorDomain @"ASDisplayNodeErrorDomain"
#define ASDisplayNodeNonFatalErrorCode 1
/**
* In debug methods, it can be useful to disable main thread assertions to get valuable information,
* even if it means violating threading requirements. These functions are used in -debugDescription and let
* threads decide to suppress/re-enable main thread assertions.
*/
#pragma mark - Main Thread Assertions Disabling
AS_EXTERN BOOL ASMainThreadAssertionsAreDisabled(void);
AS_EXTERN void ASPushMainThreadAssertionsDisabled(void);
AS_EXTERN void ASPopMainThreadAssertionsDisabled(void);
#pragma mark - Non-Fatal Assertions
/// Returns YES if assertion passed, NO otherwise.
#define ASDisplayNodeAssertNonFatal(condition, desc, ...) ({ \
BOOL __evaluated = condition; \
if (__evaluated == NO) { \
ASDisplayNodeFailAssert(desc, ##__VA_ARGS__); \
ASDisplayNodeNonFatalErrorBlock block = [ASDisplayNode nonFatalErrorBlock]; \
if (block != nil) { \
NSDictionary *userInfo = nil; \
if (desc.length > 0) { \
userInfo = @{ NSLocalizedDescriptionKey : desc }; \
} \
NSError *error = [NSError errorWithDomain:ASDisplayNodeErrorDomain code:ASDisplayNodeNonFatalErrorCode userInfo:userInfo]; \
block(error); \
} \
} \
__evaluated; \
}) \

View File

@@ -0,0 +1,72 @@
//
// ASAssert.m
// Texture
//
// Copyright (c) Pinterest, Inc. All rights reserved.
// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
//
#import <AsyncDisplayKit/ASAssert.h>
#import <AsyncDisplayKit/ASAvailability.h>
<<<<<<< HEAD
#ifndef MINIMAL_ASDK
static _Thread_local int tls_mainThreadAssertionsDisabledCount;
#endif
=======
#if AS_TLS_AVAILABLE
>>>>>>> 565da7d4935740d12fc204aa061faf093831da1e
static _Thread_local int tls_mainThreadAssertionsDisabledCount;
BOOL ASMainThreadAssertionsAreDisabled() {
#ifdef MINIMAL_ASDK
return false;
#else
return tls_mainThreadAssertionsDisabledCount > 0;
#endif
}
void ASPushMainThreadAssertionsDisabled() {
#ifndef MINIMAL_ASDK
tls_mainThreadAssertionsDisabledCount += 1;
#endif
}
void ASPopMainThreadAssertionsDisabled() {
#ifndef MINIMAL_ASDK
tls_mainThreadAssertionsDisabledCount -= 1;
ASDisplayNodeCAssert(tls_mainThreadAssertionsDisabledCount >= 0, @"Attempt to pop thread assertion-disabling without corresponding push.");
#endif
}
#else
#import <dispatch/once.h>
static pthread_key_t ASMainThreadAssertionsDisabledKey() {
static pthread_key_t k;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
pthread_key_create(&k, NULL);
});
return k;
}
BOOL ASMainThreadAssertionsAreDisabled() {
return (pthread_getspecific(ASMainThreadAssertionsDisabledKey()) > 0);
}
void ASPushMainThreadAssertionsDisabled() {
let key = ASMainThreadAssertionsDisabledKey();
let oldVal = pthread_getspecific(key);
pthread_setspecific(key, oldVal + 1);
}
void ASPopMainThreadAssertionsDisabled() {
let key = ASMainThreadAssertionsDisabledKey();
let oldVal = pthread_getspecific(key);
pthread_setspecific(key, oldVal - 1);
ASDisplayNodeCAssert(oldVal > 0, @"Attempt to pop thread assertion-disabling without corresponding push.");
}
#endif // AS_TLS_AVAILABLE

View File

@@ -0,0 +1,58 @@
//
// ASAssert.mm
// Texture
//
// Copyright (c) Pinterest, Inc. All rights reserved.
// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
//
#import <AsyncDisplayKit/ASAssert.h>
#import <AsyncDisplayKit/ASAvailability.h>
#if AS_TLS_AVAILABLE
static _Thread_local int tls_mainThreadAssertionsDisabledCount;
BOOL ASMainThreadAssertionsAreDisabled() {
return tls_mainThreadAssertionsDisabledCount > 0;
}
void ASPushMainThreadAssertionsDisabled() {
tls_mainThreadAssertionsDisabledCount += 1;
}
void ASPopMainThreadAssertionsDisabled() {
tls_mainThreadAssertionsDisabledCount -= 1;
ASDisplayNodeCAssert(tls_mainThreadAssertionsDisabledCount >= 0, @"Attempt to pop thread assertion-disabling without corresponding push.");
}
#else
#import <dispatch/once.h>
static pthread_key_t ASMainThreadAssertionsDisabledKey() {
static pthread_key_t k;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
pthread_key_create(&k, NULL);
});
return k;
}
BOOL ASMainThreadAssertionsAreDisabled() {
return (nullptr != pthread_getspecific(ASMainThreadAssertionsDisabledKey()));
}
void ASPushMainThreadAssertionsDisabled() {
const auto key = ASMainThreadAssertionsDisabledKey();
const auto oldVal = (intptr_t)pthread_getspecific(key);
pthread_setspecific(key, (void *)(oldVal + 1));
}
void ASPopMainThreadAssertionsDisabled() {
const auto key = ASMainThreadAssertionsDisabledKey();
const auto oldVal = (intptr_t)pthread_getspecific(key);
pthread_setspecific(key, (void *)(oldVal - 1));
ASDisplayNodeCAssert(oldVal > 0, @"Attempt to pop thread assertion-disabling without corresponding push.");
}
#endif // AS_TLS_AVAILABLE

View File

@@ -0,0 +1,85 @@
//
// ASAvailability.h
// Texture
//
// Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
// Changes after 4/13/2017 are: Copyright (c) Pinterest, Inc. All rights reserved.
// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
//
#import <CoreFoundation/CFBase.h>
#pragma once
#define AS_TLS_AVAILABLE 0
#ifndef AS_ENABLE_TEXTNODE
#define AS_ENABLE_TEXTNODE 1 // Enable old TextNode by default
#endif
// This needs to stay in sync with Weaver
#ifndef AS_USE_VIDEO
#define AS_USE_VIDEO 0
#endif
#ifndef AS_USE_PHOTOS
#define AS_USE_PHOTOS 0
#endif
#ifndef AS_USE_MAPKIT
#define AS_USE_MAPKIT 0
#endif
#ifndef AS_USE_ASSETS_LIBRARY
#define AS_USE_ASSETS_LIBRARY 0
#endif
#ifndef kCFCoreFoundationVersionNumber_iOS_10_0
#define kCFCoreFoundationVersionNumber_iOS_10_0 1348.00
#endif
#ifndef kCFCoreFoundationVersionNumber_iOS_11_0
#define kCFCoreFoundationVersionNumber_iOS_11_0 1438.10
#endif
#ifndef __IPHONE_11_0
#define __IPHONE_11_0 110000
#endif
#define AS_AT_LEAST_IOS10 (kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber_iOS_10_0)
#define AS_AT_LEAST_IOS11 (kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber_iOS_11_0)
// Use __builtin_available if we're on Xcode >= 9, AS_AT_LEAST otherwise.
#if __has_builtin(__builtin_available)
#define AS_AVAILABLE_IOS(ver) __builtin_available(iOS ver, *)
#define AS_AVAILABLE_TVOS(ver) __builtin_available(tvOS ver, *)
#define AS_AVAILABLE_IOS_TVOS(ver1, ver2) __builtin_available(iOS ver1, tvOS ver2, *)
#else
#define AS_AVAILABLE_IOS(ver) (TARGET_OS_IOS && AS_AT_LEAST_IOS##ver)
#define AS_AVAILABLE_TVOS(ver) (TARGET_OS_TV && AS_AT_LEAST_IOS##ver)
#define AS_AVAILABLE_IOS_TVOS(ver1, ver2) (AS_AVAILABLE_IOS(ver1) || AS_AVAILABLE_TVOS(ver2))
#endif
// If Yoga is available, make it available anywhere we use ASAvailability.
// This reduces Yoga-specific code in other files.
// NOTE: Yoga integration is experimental and not fully tested. Use with caution and test layouts carefully.
#ifndef YOGA_HEADER_PATH
#define YOGA_HEADER_PATH <yoga/Yoga.h>
#endif
#ifndef YOGA
#define YOGA __has_include(YOGA_HEADER_PATH)
#endif
#ifdef ASTEXTNODE_EXPERIMENT_GLOBAL_ENABLE
#error "ASTEXTNODE_EXPERIMENT_GLOBAL_ENABLE is unavailable. See ASConfiguration.h."
#endif
#define AS_PIN_REMOTE_IMAGE __has_include(<PINRemoteImage/PINRemoteImage.h>)
#define AS_IG_LIST_KIT __has_include(<IGListKit/IGListKit.h>)
/**
* For IGListKit versions < 3.0, you have to use IGListCollectionView.
* For 3.0 and later, that class is removed and you use UICollectionView.
*/
#define IG_LIST_COLLECTION_VIEW __has_include(<IGListKit/IGListCollectionView.h>)

View File

@@ -0,0 +1,258 @@
//
// ASBaseDefines.h
// Texture
//
// Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
// Changes after 4/13/2017 are: Copyright (c) Pinterest, Inc. All rights reserved.
// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
//
#import <Foundation/Foundation.h>
#define AS_EXTERN FOUNDATION_EXTERN
#define unowned __unsafe_unretained
/**
* Hack to support building for iOS with Xcode 9. UIUserInterfaceStyle was previously tvOS-only,
* and it was added to iOS 12. Xcode 9 (iOS 11 SDK) will flat-out refuse to build anything that
* references this enum targeting iOS, even if it's guarded with the right availability macros,
* because it thinks the entire platform isn't compatible with the enum.
*/
#if TARGET_OS_TV || (defined(__IPHONE_12_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_12_0)
#define AS_BUILD_UIUSERINTERFACESTYLE 1
#else
#define AS_BUILD_UIUSERINTERFACESTYLE 0
#endif
/**
* Decorates methods that clients can implement in categories on our base class. These methods
* will be stubbed with an empty implementation if no implementation is provided.
*/
#define AS_CATEGORY_IMPLEMENTABLE
#ifdef __GNUC__
# define ASDISPLAYNODE_GNUC(major, minor) \
(__GNUC__ > (major) || (__GNUC__ == (major) && __GNUC_MINOR__ >= (minor)))
#else
# define ASDISPLAYNODE_GNUC(major, minor) 0
#endif
#ifndef ASDISPLAYNODE_INLINE
# if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
# define ASDISPLAYNODE_INLINE static inline
# elif defined (__MWERKS__) || defined (__cplusplus)
# define ASDISPLAYNODE_INLINE static inline
# elif ASDISPLAYNODE_GNUC (3, 0)
# define ASDISPLAYNODE_INLINE static __inline__ __attribute__ ((always_inline))
# else
# define ASDISPLAYNODE_INLINE static
# endif
#endif
#ifndef ASDISPLAYNODE_WARN_DEPRECATED
# define ASDISPLAYNODE_WARN_DEPRECATED 1
#endif
#ifndef ASDISPLAYNODE_DEPRECATED
# if ASDISPLAYNODE_GNUC (3, 0) && ASDISPLAYNODE_WARN_DEPRECATED
# define ASDISPLAYNODE_DEPRECATED __attribute__ ((deprecated))
# else
# define ASDISPLAYNODE_DEPRECATED
# endif
#endif
#ifndef ASDISPLAYNODE_DEPRECATED_MSG
# if ASDISPLAYNODE_GNUC (3, 0) && ASDISPLAYNODE_WARN_DEPRECATED
# define ASDISPLAYNODE_DEPRECATED_MSG(msg) __deprecated_msg(msg)
# else
# define ASDISPLAYNODE_DEPRECATED_MSG(msg)
# endif
#endif
#ifndef AS_ENABLE_TIPS
#define AS_ENABLE_TIPS 0
#endif
/**
* The event backtraces take a static 2KB of memory
* and retain all objects present in all the registers
* of the stack frames. The memory consumption impact
* is too significant even to be enabled during general
* development.
*/
#ifndef AS_SAVE_EVENT_BACKTRACES
# define AS_SAVE_EVENT_BACKTRACES 0
#endif
#ifndef __has_feature // Optional.
#define __has_feature(x) 0 // Compatibility with non-clang compilers.
#endif
#ifndef __has_attribute // Optional.
#define __has_attribute(x) 0 // Compatibility with non-clang compilers.
#endif
#ifndef NS_RETURNS_RETAINED
#if __has_feature(attribute_ns_returns_retained)
#define NS_RETURNS_RETAINED __attribute__((ns_returns_retained))
#else
#define NS_RETURNS_RETAINED
#endif
#endif
#ifndef CF_RETURNS_RETAINED
#if __has_feature(attribute_cf_returns_retained)
#define CF_RETURNS_RETAINED __attribute__((cf_returns_retained))
#else
#define CF_RETURNS_RETAINED
#endif
#endif
#ifndef ASDISPLAYNODE_REQUIRES_SUPER
#if __has_attribute(objc_requires_super)
#define ASDISPLAYNODE_REQUIRES_SUPER __attribute__((objc_requires_super))
#else
#define ASDISPLAYNODE_REQUIRES_SUPER
#endif
#endif
#ifndef AS_UNAVAILABLE
#if __has_attribute(unavailable)
#define AS_UNAVAILABLE(message) __attribute__((unavailable(message)))
#else
#define AS_UNAVAILABLE(message)
#endif
#endif
#ifndef AS_WARN_UNUSED_RESULT
#if __has_attribute(warn_unused_result)
#define AS_WARN_UNUSED_RESULT __attribute__((warn_unused_result))
#else
#define AS_WARN_UNUSED_RESULT
#endif
#endif
#define ASOVERLOADABLE __attribute__((overloadable))
#if __has_attribute(noescape)
#define AS_NOESCAPE __attribute__((noescape))
#else
#define AS_NOESCAPE
#endif
#if __has_attribute(objc_subclassing_restricted)
#define AS_SUBCLASSING_RESTRICTED __attribute__((objc_subclassing_restricted))
#else
#define AS_SUBCLASSING_RESTRICTED
#endif
#define AS_ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
#define ASCreateOnce(expr) ({ \
static dispatch_once_t onceToken; \
static __typeof__(expr) staticVar; \
dispatch_once(&onceToken, ^{ \
staticVar = expr; \
}); \
staticVar; \
})
/// Ensure that class is of certain kind
#define ASDynamicCast(x, c) ({ \
id __val = x;\
((c *) ([__val isKindOfClass:[c class]] ? __val : nil));\
})
/// Ensure that class is of certain kind, assuming it is subclass restricted
#define ASDynamicCastStrict(x, c) ({ \
id __val = x;\
((c *) ([__val class] == [c class] ? __val : nil));\
})
// Compare two primitives, assign if different. Returns whether the assignment happened.
#define ASCompareAssign(lvalue, newValue) ({ \
BOOL result = (lvalue != newValue); \
if (result) { lvalue = newValue; } \
result; \
})
#define ASCompareAssignObjects(lvalue, newValue) \
ASCompareAssignCustom(lvalue, newValue, ASObjectIsEqual)
// e.g. ASCompareAssignCustom(_myInsets, insets, UIEdgeInsetsEqualToEdgeInsets)
#define ASCompareAssignCustom(lvalue, newValue, isequal) ({ \
BOOL result = !(isequal(lvalue, newValue)); \
if (result) { lvalue = newValue; } \
result; \
})
#define ASCompareAssignCopy(lvalue, newValue) ({ \
BOOL result = !ASObjectIsEqual(lvalue, newValue); \
if (result) { lvalue = [newValue copyWithZone:NULL]; } \
result; \
})
/**
* Create a new set by mapping `collection` over `work`, ignoring nil.
*/
#define ASSetByFlatMapping(collection, decl, work) ({ \
NSMutableSet *s = [[NSMutableSet alloc] init]; \
for (decl in collection) {\
id result = work; \
if (result != nil) { \
[s addObject:result]; \
} \
} \
s; \
})
/**
* Create a new ObjectPointerPersonality NSHashTable by mapping `collection` over `work`, ignoring nil.
*
* capacity: 0 is taken from +hashTableWithOptions.
*/
#define ASPointerTableByFlatMapping(collection, decl, work) ({ \
NSHashTable *t = [[NSHashTable alloc] initWithOptions:NSHashTableObjectPointerPersonality capacity:0]; \
for (decl in collection) {\
id result = work; \
if (result != nil) { \
[t addObject:result]; \
} \
} \
t; \
})
/**
* Create a new array by mapping `collection` over `work`, ignoring nil.
*/
#define ASArrayByFlatMapping(collectionArg, decl, work) ({ \
id __collection = collectionArg; \
NSArray *__result; \
if (__collection) { \
id __buf[[__collection count]]; \
NSUInteger __i = 0; \
for (decl in __collection) {\
if ((__buf[__i] = work)) { \
__i++; \
} \
} \
__result = [NSArray arrayByTransferring:__buf count:__i]; \
} \
__result; \
})
/**
* Capture-and-clear a strong reference without the intervening retain/release pair.
*
* E.g. const auto localVar = ASTransferStrong(_myIvar);
* Post-condition: localVar has the strong value from _myIvar and _myIvar is nil.
* No retain/release is emitted when the optimizer is on.
*/
#define ASTransferStrong(lvalue) ({ \
CFTypeRef *__rawPtr = (CFTypeRef *)(void *)(&(lvalue)); \
CFTypeRef __cfValue = *__rawPtr; \
*__rawPtr = NULL; \
__typeof(lvalue) __result = (__bridge_transfer __typeof(lvalue))__cfValue; \
__result; \
})

View File

@@ -0,0 +1,55 @@
//
// ASDisplayNode+Ancestry.h
// Texture
//
// Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
// Changes after 4/13/2017 are: Copyright (c) Pinterest, Inc. All rights reserved.
// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
//
#import <Foundation/Foundation.h>
#import <AsyncDisplayKit/ASDisplayNode.h>
NS_ASSUME_NONNULL_BEGIN
@interface ASDisplayNode (Ancestry)
/**
* Returns an object to enumerate the supernode ancestry of this node, starting with its supernode.
*
* For instance, you could write:
* for (ASDisplayNode *node in self.supernodes) {
* if ([node.backgroundColor isEqual:[UIColor blueColor]]) {
* node.hidden = YES;
* }
* }
*
* Note: If this property is read on the main thread, the enumeration will attempt to go up
* the layer hierarchy if it finds a break in the display node hierarchy.
*/
@property (readonly) id<NSFastEnumeration> supernodes;
/**
* Same as `supernodes` but begins the enumeration with self.
*/
@property (readonly) id<NSFastEnumeration> supernodesIncludingSelf;
/**
* Searches the supernodes of this node for one matching the given class.
*
* @param supernodeClass The class of node you're looking for.
* @param includeSelf Whether to include self in the search.
* @return A node of the given class that is an ancestor of this node, or nil.
*
* @note See the documentation on `supernodes` for details about the upward traversal.
*/
- (nullable __kindof ASDisplayNode *)supernodeOfClass:(Class)supernodeClass includingSelf:(BOOL)includeSelf;
/**
* e.g. "(<MYTextNode: 0xFFFF>, <MYTextContainingNode: 0xFFFF>, <MYCellNode: 0xFFFF>)"
*/
@property (copy, readonly) NSString *ancestryDescription;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,90 @@
//
// ASDisplayNode+Ancestry.mm
// Texture
//
// Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
// Changes after 4/13/2017 are: Copyright (c) Pinterest, Inc. All rights reserved.
// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
//
#import "ASDisplayNode+Ancestry.h"
#import <AsyncDisplayKit/ASThread.h>
#import <AsyncDisplayKit/ASDisplayNodeExtras.h>
AS_SUBCLASSING_RESTRICTED
@interface ASNodeAncestryEnumerator : NSEnumerator
@end
@implementation ASNodeAncestryEnumerator {
ASDisplayNode *_lastNode; // This needs to be strong because enumeration will not retain the current batch of objects
BOOL _initialState;
}
- (instancetype)initWithNode:(ASDisplayNode *)node
{
if (self = [super init]) {
_initialState = YES;
_lastNode = node;
}
return self;
}
- (id)nextObject
{
if (_initialState) {
_initialState = NO;
return _lastNode;
}
ASDisplayNode *nextNode = _lastNode.supernode;
if (nextNode == nil && ASDisplayNodeThreadIsMain()) {
CALayer *layer = _lastNode.nodeLoaded ? _lastNode.layer.superlayer : nil;
while (layer != nil) {
nextNode = ASLayerToDisplayNode(layer);
if (nextNode != nil) {
break;
}
layer = layer.superlayer;
}
}
_lastNode = nextNode;
return nextNode;
}
@end
@implementation ASDisplayNode (Ancestry)
- (id<NSFastEnumeration>)supernodes
{
NSEnumerator *result = [[ASNodeAncestryEnumerator alloc] initWithNode:self];
[result nextObject]; // discard first object (self)
return result;
}
- (id<NSFastEnumeration>)supernodesIncludingSelf
{
return [[ASNodeAncestryEnumerator alloc] initWithNode:self];
}
- (nullable __kindof ASDisplayNode *)supernodeOfClass:(Class)supernodeClass includingSelf:(BOOL)includeSelf
{
id<NSFastEnumeration> chain = includeSelf ? self.supernodesIncludingSelf : self.supernodes;
for (ASDisplayNode *ancestor in chain) {
if ([ancestor isKindOfClass:supernodeClass]) {
return ancestor;
}
}
return nil;
}
- (NSString *)ancestryDescription
{
NSMutableArray *strings = [NSMutableArray array];
for (ASDisplayNode *node in self.supernodes) {
[strings addObject:ASObjectDescriptionMakeTiny(node)];
}
return strings.description;
}
@end

View File

@@ -0,0 +1,21 @@
//
// ASEqualityHelpers.h
// Texture
//
// Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
// Changes after 4/13/2017 are: Copyright (c) Pinterest, Inc. All rights reserved.
// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
//
#import <AsyncDisplayKit/ASBaseDefines.h>
/**
@abstract Correctly equates two objects, including cases where both objects are nil. The latter is a case where `isEqual:` fails.
@param obj The first object in the comparison. Can be nil.
@param otherObj The second object in the comparison. Can be nil.
@result YES if the objects are equal, including cases where both object are nil.
*/
ASDISPLAYNODE_INLINE BOOL ASObjectIsEqual(id<NSObject> obj, id<NSObject> otherObj)
{
return obj == otherObj || [obj isEqual:otherObj];
}

View File

@@ -0,0 +1,163 @@
//
// ASLog.h
// Texture
//
// Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
// Changes after 4/13/2017 are: Copyright (c) Pinterest, Inc. All rights reserved.
// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
//
#import <AsyncDisplayKit/ASAvailability.h>
#import <AsyncDisplayKit/ASBaseDefines.h>
#import <Foundation/Foundation.h>
#import <os/log.h>
#import <os/activity.h>
#ifndef ASEnableVerboseLogging
#define ASEnableVerboseLogging 0
#endif
/**
* Disable all logging.
*
* You should only use this function if the default log level is
* annoying during development. By default, logging is run at
* the appropriate system log level (see the os_log_* functions),
* so you do not need to worry generally about the performance
* implications of log messages.
*
* For example, virtually all log messages generated by Texture
* are at the `debug` log level, which the system
* disables in production.
*/
AS_EXTERN void ASDisableLogging(void);
/**
* Restore logging that has been runtime-disabled via ASDisableLogging().
*
* Logging can be disabled at runtime using the ASDisableLogging() function.
* This command restores logging to the level provided in the build
* configuration. This can be used in conjunction with ASDisableLogging()
* to allow logging to be toggled off and back on at runtime.
*/
AS_EXTERN void ASEnableLogging(void);
/// Log for general node events e.g. interfaceState, didLoad.
#define ASNodeLogEnabled 1
AS_EXTERN os_log_t ASNodeLog(void);
/// Log for layout-specific events e.g. calculateLayout.
#define ASLayoutLogEnabled 1
AS_EXTERN os_log_t ASLayoutLog(void);
/// Log for display-specific events e.g. display queue batches.
#define ASDisplayLogEnabled 1
AS_EXTERN os_log_t ASDisplayLog(void);
/// Log for collection events e.g. reloadData, performBatchUpdates.
#define ASCollectionLogEnabled 1
AS_EXTERN os_log_t ASCollectionLog(void);
/// Log for ASNetworkImageNode and ASMultiplexImageNode events.
#define ASImageLoadingLogEnabled 1
AS_EXTERN os_log_t ASImageLoadingLog(void);
/// Specialized log for our main thread deallocation trampoline.
#define ASMainThreadDeallocationLogEnabled 0
AS_EXTERN os_log_t ASMainThreadDeallocationLog(void);
/**
* The activity tracing system changed a lot between iOS 9 and 10.
* In iOS 10, the system was merged with logging and became much more powerful
* and adopted a new API.
*
* The legacy API is visible, but its functionality is extremely limited and the API is so different
* that we don't bother with it. For example, activities described by os_activity_start/end are not
* reflected in the log whereas activities described by the newer
* os_activity_scope are. So unfortunately we must use these iOS 10
* APIs to get meaningful logging data.
*/
#if OS_LOG_TARGET_HAS_10_12_FEATURES
#define OS_ACTIVITY_NULLABLE nullable
#define AS_ACTIVITY_CURRENT OS_ACTIVITY_CURRENT
#define as_activity_scope(activity) os_activity_scope(activity)
#define as_activity_apply(activity, block) os_activity_apply(activity, block)
#define as_activity_create(description, parent_activity, flags) os_activity_create(description, parent_activity, flags)
#define as_activity_scope_enter(activity, statePtr) os_activity_scope_enter(activity, statePtr)
#define as_activity_scope_leave(statePtr) os_activity_scope_leave(statePtr)
#define as_activity_get_identifier(activity, outParentID) os_activity_get_identifier(activity, outParentID)
#else
#define OS_ACTIVITY_NULLABLE
#define AS_ACTIVITY_CURRENT OS_ACTIVITY_NULL
#define as_activity_scope(activity)
#define as_activity_apply(activity, block)
#define as_activity_create(description, parent_activity, flags) OS_ACTIVITY_NULL
#define as_activity_scope_enter(activity, statePtr)
#define as_activity_scope_leave(statePtr)
#define as_activity_get_identifier(activity, outParentID) (os_activity_id_t)0
#endif // OS_LOG_TARGET_HAS_10_12_FEATURES
// Create activities only when verbose enabled. Doesn't materially impact performance, but good if we're cluttering up
// activity scopes and reducing readability.
#if ASEnableVerboseLogging
#define as_activity_scope_verbose(activity) as_activity_scope(activity)
#else
#define as_activity_scope_verbose(activity)
#endif
// Convenience for: as_activity_scope(as_activity_create(description, AS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_DEFAULT))
#define as_activity_create_for_scope(description) \
as_activity_scope(as_activity_create(description, AS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_DEFAULT))
/**
* The logging macros are not guarded by deployment-target checks like the activity macros are, but they are
* only available on iOS >= 9 at runtime, so just make them conditional.
*/
#define as_log_create(subsystem, category) ({ \
os_log_t __val; \
if (AS_AVAILABLE_IOS_TVOS(9, 9)) { \
__val = os_log_create(subsystem, category); \
} else { \
__val = (os_log_t)0; \
} \
__val; \
})
#define as_log_debug(log, format, ...) \
if (AS_AVAILABLE_IOS_TVOS(9, 9)) { \
os_log_debug(log, format, ##__VA_ARGS__); \
} else { \
(void)0; \
} \
#define as_log_info(log, format, ...) \
if (AS_AVAILABLE_IOS_TVOS(9, 9)) { \
os_log_info(log, format, ##__VA_ARGS__); \
} else { \
(void)0; \
} \
#define as_log_error(log, format, ...) \
if (AS_AVAILABLE_IOS_TVOS(9, 9)) { \
os_log_error(log, format, ##__VA_ARGS__); \
} else { \
(void)0; \
} \
#define as_log_fault(log, format, ...) \
if (AS_AVAILABLE_IOS_TVOS(9, 9)) { \
os_log_fault(log, format, ##__VA_ARGS__); \
} else { \
(void)0; \
} \
#if ASEnableVerboseLogging
#define as_log_verbose(log, format, ...) as_log_debug(log, format, ##__VA_ARGS__)
#else
#define as_log_verbose(log, format, ...)
#endif

View File

@@ -0,0 +1,48 @@
//
// ASLog.mm
// Texture
//
// Copyright (c) Pinterest, Inc. All rights reserved.
// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
//
#import <AsyncDisplayKit/ASLog.h>
#import <stdatomic.h>
static atomic_bool __ASLogEnabled = ATOMIC_VAR_INIT(YES);
void ASDisableLogging() {
atomic_store(&__ASLogEnabled, NO);
}
void ASEnableLogging() {
atomic_store(&__ASLogEnabled, YES);
}
ASDISPLAYNODE_INLINE BOOL ASLoggingIsEnabled() {
return atomic_load(&__ASLogEnabled);
}
os_log_t ASNodeLog() {
return (ASNodeLogEnabled && ASLoggingIsEnabled()) ? ASCreateOnce(as_log_create("org.TextureGroup.Texture", "Node")) : OS_LOG_DISABLED;
}
os_log_t ASLayoutLog() {
return (ASLayoutLogEnabled && ASLoggingIsEnabled()) ? ASCreateOnce(as_log_create("org.TextureGroup.Texture", "Layout")) : OS_LOG_DISABLED;
}
os_log_t ASCollectionLog() {
return (ASCollectionLogEnabled && ASLoggingIsEnabled()) ?ASCreateOnce(as_log_create("org.TextureGroup.Texture", "Collection")) : OS_LOG_DISABLED;
}
os_log_t ASDisplayLog() {
return (ASDisplayLogEnabled && ASLoggingIsEnabled()) ?ASCreateOnce(as_log_create("org.TextureGroup.Texture", "Display")) : OS_LOG_DISABLED;
}
os_log_t ASImageLoadingLog() {
return (ASImageLoadingLogEnabled && ASLoggingIsEnabled()) ? ASCreateOnce(as_log_create("org.TextureGroup.Texture", "ImageLoading")) : OS_LOG_DISABLED;
}
os_log_t ASMainThreadDeallocationLog() {
return (ASMainThreadDeallocationLogEnabled && ASLoggingIsEnabled()) ? ASCreateOnce(as_log_create("org.TextureGroup.Texture", "MainDealloc")) : OS_LOG_DISABLED;
}

View File

@@ -0,0 +1,94 @@
//
// ASSignpost.h
// Texture
//
// Copyright (c) Pinterest, Inc. All rights reserved.
// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
//
/// The signposts we use. Signposts are grouped by color. The SystemTrace.tracetemplate file
/// should be kept up-to-date with these values.
typedef NS_ENUM(uint32_t, ASSignpostName) {
// Collection/Table (Blue)
ASSignpostDataControllerBatch = 300, // Alloc/layout nodes before collection update.
ASSignpostRangeControllerUpdate, // Ranges update pass.
ASSignpostCollectionUpdate, // Entire update process, from -endUpdates to [super perform…]
// Rendering (Green)
ASSignpostLayerDisplay = 325, // Client display callout.
ASSignpostRunLoopQueueBatch, // One batch of ASRunLoopQueue.
// Layout (Purple)
ASSignpostCalculateLayout = 350, // Start of calculateLayoutThatFits to end. Max 1 per thread.
// Misc (Orange)
ASSignpostDeallocQueueDrain = 375, // One chunk of dealloc queue work. arg0 is count.
ASSignpostCATransactionLayout, // The CA transaction commit layout phase.
ASSignpostCATransactionCommit // The CA transaction commit post-layout phase.
};
typedef NS_ENUM(uintptr_t, ASSignpostColor) {
ASSignpostColorBlue,
ASSignpostColorGreen,
ASSignpostColorPurple,
ASSignpostColorOrange,
ASSignpostColorRed,
ASSignpostColorDefault
};
static inline ASSignpostColor ASSignpostGetColor(ASSignpostName name, ASSignpostColor colorPref) {
if (colorPref == ASSignpostColorDefault) {
return (ASSignpostColor)((name / 25) % 4);
} else {
return colorPref;
}
}
#if defined(PROFILE) && __has_include(<sys/kdebug_signpost.h>)
#define AS_KDEBUG_ENABLE 1
#else
#define AS_KDEBUG_ENABLE 0
#endif
#if AS_KDEBUG_ENABLE
#import <sys/kdebug_signpost.h>
// These definitions are required to build the backward-compatible kdebug trace
// on the iOS 10 SDK. The kdebug_trace function crashes if run on iOS 9 and earlier.
// It's valuable to support trace signposts on iOS 9, because A5 devices don't support iOS 10.
#ifndef DBG_MACH_CHUD
#define DBG_MACH_CHUD 0x0A
#define DBG_FUNC_NONE 0
#define DBG_FUNC_START 1
#define DBG_FUNC_END 2
#define DBG_APPS 33
#define SYS_kdebug_trace 180
#define KDBG_CODE(Class, SubClass, code) (((Class & 0xff) << 24) | ((SubClass & 0xff) << 16) | ((code & 0x3fff) << 2))
#define APPSDBG_CODE(SubClass,code) KDBG_CODE(DBG_APPS, SubClass, code)
#endif
// Currently we'll reserve arg3.
#define ASSignpost(name, identifier, arg2, color) \
AS_AT_LEAST_IOS10 ? kdebug_signpost(name, (uintptr_t)identifier, (uintptr_t)arg2, 0, ASSignpostGetColor(name, color)) \
: syscall(SYS_kdebug_trace, APPSDBG_CODE(DBG_MACH_CHUD, name) | DBG_FUNC_NONE, (uintptr_t)identifier, (uintptr_t)arg2, 0, ASSignpostGetColor(name, color));
#define ASSignpostStartCustom(name, identifier, arg2) \
AS_AT_LEAST_IOS10 ? kdebug_signpost_start(name, (uintptr_t)identifier, (uintptr_t)arg2, 0, 0) \
: syscall(SYS_kdebug_trace, APPSDBG_CODE(DBG_MACH_CHUD, name) | DBG_FUNC_START, (uintptr_t)identifier, (uintptr_t)arg2, 0, 0);
#define ASSignpostStart(name) ASSignpostStartCustom(name, self, 0)
#define ASSignpostEndCustom(name, identifier, arg2, color) \
AS_AT_LEAST_IOS10 ? kdebug_signpost_end(name, (uintptr_t)identifier, (uintptr_t)arg2, 0, ASSignpostGetColor(name, color)) \
: syscall(SYS_kdebug_trace, APPSDBG_CODE(DBG_MACH_CHUD, name) | DBG_FUNC_END, (uintptr_t)identifier, (uintptr_t)arg2, 0, ASSignpostGetColor(name, color));
#define ASSignpostEnd(name) ASSignpostEndCustom(name, self, 0, ASSignpostColorDefault)
#else
#define ASSignpost(name, identifier, arg2, color)
#define ASSignpostStartCustom(name, identifier, arg2)
#define ASSignpostStart(name)
#define ASSignpostEndCustom(name, identifier, arg2, color)
#define ASSignpostEnd(name)
#endif