mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-08-17 11:00:07 +00:00
629 lines
16 KiB
Plaintext
629 lines
16 KiB
Plaintext
/* 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 "_ASCoreAnimationExtras.h"
|
|
#import "_ASPendingState.h"
|
|
#import "ASAssert.h"
|
|
#import "ASDisplayNode+Subclasses.h"
|
|
#import "ASDisplayNodeInternal.h"
|
|
|
|
/**
|
|
* The following macros are conveniences to help in the common tasks related to the bridging that ASDisplayNode does to UIView and CALayer.
|
|
* In general, a property can either be:
|
|
* - Always sent to the layer or view's layer
|
|
* use _getFromLayer / _setToLayer
|
|
* - Bridged to the view if view-backed or the layer if layer-backed
|
|
* use _getFromViewOrLayer / _setToViewOrLayer / _messageToViewOrLayer
|
|
* - Only applicable if view-backed
|
|
* use _setToViewOnly / _getFromViewOnly
|
|
* - Has differing types on views and layers, or custom ASDisplayNode-specific behavior is desired
|
|
* manually implement
|
|
*
|
|
* _bridge_prologue is defined to either take an appropriate lock or assert thread affinity. Add it at the beginning of any bridged methods.
|
|
*/
|
|
|
|
#define DISPLAYNODE_USE_LOCKS 1
|
|
|
|
#define __loaded (_layer != nil)
|
|
|
|
#if DISPLAYNODE_USE_LOCKS
|
|
#define _bridge_prologue ASDisplayNodeAssertThreadAffinity(self); ASDN::MutexLocker l(_propertyLock)
|
|
#else
|
|
#define _bridge_prologue ASDisplayNodeAssertThreadAffinity(self)
|
|
#endif
|
|
|
|
|
|
#define _getFromViewOrLayer(layerProperty, viewAndPendingViewStateProperty) __loaded ? \
|
|
(_view ? _view.viewAndPendingViewStateProperty : _layer.layerProperty )\
|
|
: self.pendingViewState.viewAndPendingViewStateProperty
|
|
|
|
#define _setToViewOrLayer(layerProperty, layerValueExpr, viewAndPendingViewStateProperty, viewAndPendingViewStateExpr) __loaded ? \
|
|
(_view ? _view.viewAndPendingViewStateProperty = (viewAndPendingViewStateExpr) : _layer.layerProperty = (layerValueExpr))\
|
|
: self.pendingViewState.viewAndPendingViewStateProperty = (viewAndPendingViewStateExpr)
|
|
|
|
#define _setToViewOnly(viewAndPendingViewStateProperty, viewAndPendingViewStateExpr) __loaded ? _view.viewAndPendingViewStateProperty = (viewAndPendingViewStateExpr) : self.pendingViewState.viewAndPendingViewStateProperty = (viewAndPendingViewStateExpr)
|
|
|
|
#define _getFromViewOnly(viewAndPendingViewStateProperty) __loaded ? _view.viewAndPendingViewStateProperty : self.pendingViewState.viewAndPendingViewStateProperty
|
|
|
|
#define _getFromLayer(layerProperty) __loaded ? _layer.layerProperty : self.pendingViewState.layerProperty
|
|
|
|
#define _setToLayer(layerProperty, layerValueExpr) __loaded ? _layer.layerProperty = (layerValueExpr) : self.pendingViewState.layerProperty = (layerValueExpr)
|
|
|
|
#define _messageToViewOrLayer(viewAndLayerSelector) __loaded ? (_view ? [_view viewAndLayerSelector] : [_layer viewAndLayerSelector]) : [self.pendingViewState viewAndLayerSelector]
|
|
|
|
#define _messageToLayer(layerSelector) __loaded ? [_layer layerSelector] : [self.pendingViewState layerSelector]
|
|
|
|
/**
|
|
* This category implements certainly frequently-used properties and methods of UIView and CALayer so that ASDisplayNode clients can just call the view/layer methods on the node,
|
|
* with minimal loss in performance. Unlike UIView and CALayer methods, these can be called from a non-main thread until the view or layer is created.
|
|
* This allows text sizing in -calculateSizeThatFits: (essentially a simplified layout) to happen off the main thread
|
|
* without any CALayer or UIView actually existing while still being able to set and read properties from ASDisplayNode instances.
|
|
*/
|
|
@implementation ASDisplayNode (UIViewBridge)
|
|
|
|
- (CGFloat)alpha
|
|
{
|
|
_bridge_prologue;
|
|
return _getFromViewOrLayer(opacity, alpha);
|
|
}
|
|
|
|
- (void)setAlpha:(CGFloat)newAlpha
|
|
{
|
|
_bridge_prologue;
|
|
_setToViewOrLayer(opacity, newAlpha, alpha, newAlpha);
|
|
}
|
|
|
|
- (CGFloat)contentsScale
|
|
{
|
|
_bridge_prologue;
|
|
return _getFromLayer(contentsScale);
|
|
}
|
|
|
|
- (void)setContentsScale:(CGFloat)newContentsScale
|
|
{
|
|
_bridge_prologue;
|
|
_setToLayer(contentsScale, newContentsScale);
|
|
}
|
|
|
|
- (CGRect)bounds
|
|
{
|
|
_bridge_prologue;
|
|
return _getFromViewOrLayer(bounds, bounds);
|
|
}
|
|
|
|
- (void)setBounds:(CGRect)newBounds
|
|
{
|
|
_bridge_prologue;
|
|
_setToViewOrLayer(bounds, newBounds, bounds, newBounds);
|
|
}
|
|
|
|
- (CGRect)frame
|
|
{
|
|
_bridge_prologue;
|
|
|
|
// Frame is only defined when transform is identity.
|
|
#if DEBUG
|
|
// Checking if the transform is identity is expensive, so disable when unnecessary. We have assertions on in Release, so DEBUG is the only way I know of.
|
|
ASDisplayNodeAssert(CATransform3DIsIdentity(self.transform), @"Must be an identity transform");
|
|
#endif
|
|
|
|
CGPoint position = self.position;
|
|
CGRect bounds = self.bounds;
|
|
CGPoint anchorPoint = self.anchorPoint;
|
|
CGPoint origin = CGPointMake(position.x - bounds.size.width * anchorPoint.x,
|
|
position.y - bounds.size.height * anchorPoint.y);
|
|
return CGRectMake(origin.x, origin.y, bounds.size.width, bounds.size.height);
|
|
}
|
|
|
|
- (void)setFrame:(CGRect)rect
|
|
{
|
|
_bridge_prologue;
|
|
|
|
// Frame is only defined when transform is identity because we explicitly diverge from CALayer behavior and define frame without transform
|
|
#if DEBUG
|
|
// Checking if the transform is identity is expensive, so disable when unnecessary. We have assertions on in Release, so DEBUG is the only way I know of.
|
|
ASDisplayNodeAssert(CATransform3DIsIdentity(self.transform), @"Must be an identity transform");
|
|
#endif
|
|
|
|
if (_layer && ASDisplayNodeThreadIsMain()) {
|
|
CGPoint anchorPoint = _layer.anchorPoint;
|
|
_layer.bounds = CGRectMake(0, 0, rect.size.width, rect.size.height);
|
|
_layer.position = CGPointMake(rect.origin.x + rect.size.width * anchorPoint.x,
|
|
rect.origin.y + rect.size.height * anchorPoint.y);
|
|
} else {
|
|
CGPoint anchorPoint = self.anchorPoint;
|
|
self.bounds = CGRectMake(0, 0, rect.size.width, rect.size.height);
|
|
self.position = CGPointMake(rect.origin.x + rect.size.width * anchorPoint.x,
|
|
rect.origin.y + rect.size.height * anchorPoint.y);
|
|
}
|
|
}
|
|
|
|
- (void)setNeedsDisplay
|
|
{
|
|
ASDisplayNode *rasterizedContainerNode = [self __rasterizedContainerNode];
|
|
if (rasterizedContainerNode) {
|
|
[rasterizedContainerNode setNeedsDisplay];
|
|
} else {
|
|
[_layer setNeedsDisplay];
|
|
}
|
|
}
|
|
|
|
- (void)setNeedsLayout
|
|
{
|
|
_bridge_prologue;
|
|
_messageToViewOrLayer(setNeedsLayout);
|
|
}
|
|
|
|
- (BOOL)isOpaque
|
|
{
|
|
_bridge_prologue;
|
|
return _getFromLayer(opaque);
|
|
}
|
|
|
|
- (void)setOpaque:(BOOL)newOpaque
|
|
{
|
|
_bridge_prologue;
|
|
_setToLayer(opaque, newOpaque);
|
|
}
|
|
|
|
- (BOOL)isUserInteractionEnabled
|
|
{
|
|
_bridge_prologue;
|
|
if (_flags.isLayerBacked) return NO;
|
|
return _getFromViewOnly(userInteractionEnabled);
|
|
}
|
|
|
|
- (void)setUserInteractionEnabled:(BOOL)enabled
|
|
{
|
|
_bridge_prologue;
|
|
_setToViewOnly(userInteractionEnabled, enabled);
|
|
}
|
|
|
|
- (BOOL)isExclusiveTouch
|
|
{
|
|
_bridge_prologue;
|
|
return _getFromViewOnly(exclusiveTouch);
|
|
}
|
|
|
|
- (void)setExclusiveTouch:(BOOL)exclusiveTouch
|
|
{
|
|
_bridge_prologue;
|
|
_setToViewOnly(exclusiveTouch, exclusiveTouch);
|
|
}
|
|
|
|
- (BOOL)clipsToBounds
|
|
{
|
|
_bridge_prologue;
|
|
return _getFromViewOrLayer(masksToBounds, clipsToBounds);
|
|
}
|
|
|
|
- (void)setClipsToBounds:(BOOL)clips
|
|
{
|
|
_bridge_prologue;
|
|
_setToViewOrLayer(masksToBounds, clips, clipsToBounds, clips);
|
|
}
|
|
|
|
- (CGPoint)anchorPoint
|
|
{
|
|
_bridge_prologue;
|
|
return _getFromLayer(anchorPoint);
|
|
}
|
|
|
|
- (void)setAnchorPoint:(CGPoint)newAnchorPoint
|
|
{
|
|
_bridge_prologue;
|
|
_setToLayer(anchorPoint, newAnchorPoint);
|
|
}
|
|
|
|
- (CGPoint)position
|
|
{
|
|
_bridge_prologue;
|
|
return _getFromLayer(position);
|
|
}
|
|
|
|
- (void)setPosition:(CGPoint)newPosition
|
|
{
|
|
_bridge_prologue;
|
|
_setToLayer(position, newPosition);
|
|
}
|
|
|
|
- (CGFloat)zPosition
|
|
{
|
|
_bridge_prologue;
|
|
return _getFromLayer(zPosition);
|
|
}
|
|
|
|
- (void)setZPosition:(CGFloat)newPosition
|
|
{
|
|
_bridge_prologue;
|
|
_setToLayer(zPosition, newPosition);
|
|
}
|
|
|
|
- (CATransform3D)transform
|
|
{
|
|
_bridge_prologue;
|
|
return _getFromLayer(transform);
|
|
}
|
|
|
|
- (void)setTransform:(CATransform3D)newTransform
|
|
{
|
|
_bridge_prologue;
|
|
_setToLayer(transform, newTransform);
|
|
}
|
|
|
|
- (CATransform3D)subnodeTransform
|
|
{
|
|
_bridge_prologue;
|
|
return _getFromLayer(sublayerTransform);
|
|
}
|
|
|
|
- (void)setSubnodeTransform:(CATransform3D)newSubnodeTransform
|
|
{
|
|
_bridge_prologue;
|
|
_setToLayer(sublayerTransform, newSubnodeTransform);
|
|
}
|
|
|
|
- (id)contents
|
|
{
|
|
_bridge_prologue;
|
|
return _getFromLayer(contents);
|
|
}
|
|
|
|
- (void)setContents:(id)newContents
|
|
{
|
|
_bridge_prologue;
|
|
_setToLayer(contents, newContents);
|
|
}
|
|
|
|
- (BOOL)isHidden
|
|
{
|
|
_bridge_prologue;
|
|
return _getFromViewOrLayer(hidden, hidden);
|
|
}
|
|
|
|
- (void)setHidden:(BOOL)flag
|
|
{
|
|
_bridge_prologue;
|
|
_setToViewOrLayer(hidden, flag, hidden, flag);
|
|
}
|
|
|
|
- (BOOL)needsDisplayOnBoundsChange
|
|
{
|
|
_bridge_prologue;
|
|
return _getFromLayer(needsDisplayOnBoundsChange);
|
|
}
|
|
|
|
- (void)setNeedsDisplayOnBoundsChange:(BOOL)flag
|
|
{
|
|
_bridge_prologue;
|
|
_setToLayer(needsDisplayOnBoundsChange, flag);
|
|
}
|
|
|
|
- (BOOL)autoresizesSubviews
|
|
{
|
|
_bridge_prologue;
|
|
ASDisplayNodeAssert(!_flags.isLayerBacked, @"Danger: this property is undefined on layer-backed nodes.");
|
|
return _getFromViewOnly(autoresizesSubviews);
|
|
}
|
|
|
|
- (void)setAutoresizesSubviews:(BOOL)flag
|
|
{
|
|
_bridge_prologue;
|
|
ASDisplayNodeAssert(!_flags.isLayerBacked, @"Danger: this property is undefined on layer-backed nodes.");
|
|
_setToViewOnly(autoresizesSubviews, flag);
|
|
}
|
|
|
|
- (UIViewAutoresizing)autoresizingMask
|
|
{
|
|
_bridge_prologue;
|
|
ASDisplayNodeAssert(!_flags.isLayerBacked, @"Danger: this property is undefined on layer-backed nodes.");
|
|
return _getFromViewOnly(autoresizingMask);
|
|
}
|
|
|
|
- (void)setAutoresizingMask:(UIViewAutoresizing)mask
|
|
{
|
|
_bridge_prologue;
|
|
ASDisplayNodeAssert(!_flags.isLayerBacked, @"Danger: this property is undefined on layer-backed nodes.");
|
|
_setToViewOnly(autoresizingMask, mask);
|
|
}
|
|
|
|
- (UIViewContentMode)contentMode
|
|
{
|
|
_bridge_prologue;
|
|
if (__loaded) {
|
|
return ASDisplayNodeUIContentModeFromCAContentsGravity(_layer.contentsGravity);
|
|
} else {
|
|
return self.pendingViewState.contentMode;
|
|
}
|
|
}
|
|
|
|
- (void)setContentMode:(UIViewContentMode)mode
|
|
{
|
|
_bridge_prologue;
|
|
if (__loaded) {
|
|
_layer.contentsGravity = ASDisplayNodeCAContentsGravityFromUIContentMode(mode);
|
|
} else {
|
|
self.pendingViewState.contentMode = mode;
|
|
}
|
|
}
|
|
|
|
- (UIColor *)backgroundColor
|
|
{
|
|
_bridge_prologue;
|
|
return [UIColor colorWithCGColor:_getFromLayer(backgroundColor)];
|
|
}
|
|
|
|
- (void)setBackgroundColor:(UIColor *)backgroundColor
|
|
{
|
|
_bridge_prologue;
|
|
_setToLayer(backgroundColor, backgroundColor.CGColor);
|
|
}
|
|
|
|
- (CGColorRef)shadowColor
|
|
{
|
|
_bridge_prologue;
|
|
return _getFromLayer(shadowColor);
|
|
}
|
|
|
|
- (void)setShadowColor:(CGColorRef)colorValue
|
|
{
|
|
_bridge_prologue;
|
|
_setToLayer(shadowColor, colorValue);
|
|
}
|
|
|
|
- (CGFloat)shadowOpacity
|
|
{
|
|
_bridge_prologue;
|
|
return _getFromLayer(shadowOpacity);
|
|
}
|
|
|
|
- (void)setShadowOpacity:(CGFloat)opacity
|
|
{
|
|
_bridge_prologue;
|
|
_setToLayer(shadowOpacity, opacity);
|
|
}
|
|
|
|
- (CGSize)shadowOffset
|
|
{
|
|
_bridge_prologue;
|
|
return _getFromLayer(shadowOffset);
|
|
}
|
|
|
|
- (void)setShadowOffset:(CGSize)offset
|
|
{
|
|
_bridge_prologue;
|
|
_setToLayer(shadowOffset, offset);
|
|
}
|
|
|
|
- (CGFloat)shadowRadius
|
|
{
|
|
_bridge_prologue;
|
|
return _getFromLayer(shadowRadius);
|
|
}
|
|
|
|
- (void)setShadowRadius:(CGFloat)radius
|
|
{
|
|
_bridge_prologue;
|
|
_setToLayer(shadowRadius, radius);
|
|
}
|
|
|
|
- (CGFloat)borderWidth
|
|
{
|
|
_bridge_prologue;
|
|
return _getFromLayer(borderWidth);
|
|
}
|
|
|
|
- (void)setBorderWidth:(CGFloat)width
|
|
{
|
|
_bridge_prologue;
|
|
_setToLayer(borderWidth, width);
|
|
}
|
|
|
|
- (CGColorRef)borderColor
|
|
{
|
|
_bridge_prologue;
|
|
return _getFromLayer(borderColor);
|
|
}
|
|
|
|
- (void)setBorderColor:(CGColorRef)colorValue
|
|
{
|
|
_bridge_prologue;
|
|
_setToLayer(borderColor, colorValue);
|
|
}
|
|
|
|
- (BOOL)allowsEdgeAntialiasing
|
|
{
|
|
_bridge_prologue;
|
|
return _getFromLayer(allowsEdgeAntialiasing);
|
|
}
|
|
|
|
- (void)setAllowsEdgeAntialiasing:(BOOL)allowsEdgeAntialiasing
|
|
{
|
|
_bridge_prologue;
|
|
_setToLayer(allowsEdgeAntialiasing, allowsEdgeAntialiasing);
|
|
}
|
|
|
|
- (unsigned int)edgeAntialiasingMask
|
|
{
|
|
_bridge_prologue;
|
|
return _getFromLayer(edgeAntialiasingMask);
|
|
}
|
|
|
|
- (void)setEdgeAntialiasingMask:(unsigned int)edgeAntialiasingMask
|
|
{
|
|
_bridge_prologue;
|
|
_setToLayer(edgeAntialiasingMask, edgeAntialiasingMask);
|
|
}
|
|
|
|
- (NSString *)name
|
|
{
|
|
_bridge_prologue;
|
|
return _getFromLayer(asyncdisplaykit_name);
|
|
}
|
|
|
|
- (void)setName:(NSString *)name
|
|
{
|
|
_bridge_prologue;
|
|
_setToLayer(asyncdisplaykit_name, name);
|
|
}
|
|
|
|
- (BOOL)isAccessibilityElement
|
|
{
|
|
_bridge_prologue;
|
|
return _getFromViewOnly(isAccessibilityElement);
|
|
}
|
|
|
|
- (void)setIsAccessibilityElement:(BOOL)isAccessibilityElement
|
|
{
|
|
_bridge_prologue;
|
|
_setToViewOnly(isAccessibilityElement, isAccessibilityElement);
|
|
}
|
|
|
|
- (NSString *)accessibilityLabel
|
|
{
|
|
_bridge_prologue;
|
|
return _getFromViewOnly(accessibilityLabel);
|
|
}
|
|
|
|
- (void)setAccessibilityLabel:(NSString *)accessibilityLabel
|
|
{
|
|
_bridge_prologue;
|
|
_setToViewOnly(accessibilityLabel, accessibilityLabel);
|
|
}
|
|
|
|
- (NSString *)accessibilityHint
|
|
{
|
|
_bridge_prologue;
|
|
return _getFromViewOnly(accessibilityHint);
|
|
}
|
|
|
|
- (void)setAccessibilityHint:(NSString *)accessibilityHint
|
|
{
|
|
_bridge_prologue;
|
|
_setToViewOnly(accessibilityHint, accessibilityHint);
|
|
}
|
|
|
|
- (NSString *)accessibilityValue
|
|
{
|
|
_bridge_prologue;
|
|
return _getFromViewOnly(accessibilityValue);
|
|
}
|
|
|
|
- (void)setAccessibilityValue:(NSString *)accessibilityValue
|
|
{
|
|
_bridge_prologue;
|
|
_setToViewOnly(accessibilityValue, accessibilityValue);
|
|
}
|
|
|
|
- (UIAccessibilityTraits)accessibilityTraits
|
|
{
|
|
_bridge_prologue;
|
|
return _getFromViewOnly(accessibilityTraits);
|
|
}
|
|
|
|
- (void)setAccessibilityTraits:(UIAccessibilityTraits)accessibilityTraits
|
|
{
|
|
_bridge_prologue;
|
|
_setToViewOnly(accessibilityTraits, accessibilityTraits);
|
|
}
|
|
|
|
- (CGRect)accessibilityFrame
|
|
{
|
|
_bridge_prologue;
|
|
return _getFromViewOnly(accessibilityFrame);
|
|
}
|
|
|
|
- (void)setAccessibilityFrame:(CGRect)accessibilityFrame
|
|
{
|
|
_bridge_prologue;
|
|
_setToViewOnly(accessibilityFrame, accessibilityFrame);
|
|
}
|
|
|
|
- (NSString *)accessibilityLanguage
|
|
{
|
|
_bridge_prologue;
|
|
return _getFromViewOnly(accessibilityLanguage);
|
|
}
|
|
|
|
- (void)setAccessibilityLanguage:(NSString *)accessibilityLanguage
|
|
{
|
|
_bridge_prologue;
|
|
_setToViewOnly(accessibilityLanguage, accessibilityLanguage);
|
|
}
|
|
|
|
- (BOOL)accessibilityElementsHidden
|
|
{
|
|
_bridge_prologue;
|
|
return _getFromViewOnly(accessibilityElementsHidden);
|
|
}
|
|
|
|
- (void)setAccessibilityElementsHidden:(BOOL)accessibilityElementsHidden
|
|
{
|
|
_bridge_prologue;
|
|
_setToViewOnly(accessibilityElementsHidden, accessibilityElementsHidden);
|
|
}
|
|
|
|
- (BOOL)accessibilityViewIsModal
|
|
{
|
|
_bridge_prologue;
|
|
return _getFromViewOnly(accessibilityViewIsModal);
|
|
}
|
|
|
|
- (void)setAccessibilityViewIsModal:(BOOL)accessibilityViewIsModal
|
|
{
|
|
_bridge_prologue;
|
|
_setToViewOnly(accessibilityViewIsModal, accessibilityViewIsModal);
|
|
}
|
|
|
|
- (BOOL)shouldGroupAccessibilityChildren
|
|
{
|
|
_bridge_prologue;
|
|
return _getFromViewOnly(shouldGroupAccessibilityChildren);
|
|
}
|
|
|
|
- (void)setShouldGroupAccessibilityChildren:(BOOL)shouldGroupAccessibilityChildren
|
|
{
|
|
_bridge_prologue;
|
|
_setToViewOnly(shouldGroupAccessibilityChildren, shouldGroupAccessibilityChildren);
|
|
}
|
|
|
|
@end
|
|
|
|
|
|
@implementation ASDisplayNode (ASAsyncTransactionContainer)
|
|
|
|
- (BOOL)asyncdisplaykit_isAsyncTransactionContainer
|
|
{
|
|
_bridge_prologue;
|
|
return _getFromViewOrLayer(asyncdisplaykit_isAsyncTransactionContainer, asyncdisplaykit_isAsyncTransactionContainer);
|
|
}
|
|
|
|
- (void)asyncdisplaykit_setAsyncTransactionContainer:(BOOL)asyncTransactionContainer
|
|
{
|
|
_bridge_prologue;
|
|
_setToViewOrLayer(asyncdisplaykit_asyncTransactionContainer, asyncTransactionContainer, asyncdisplaykit_asyncTransactionContainer, asyncTransactionContainer);
|
|
}
|
|
|
|
- (ASAsyncTransactionContainerState)asyncdisplaykit_asyncTransactionContainerState
|
|
{
|
|
ASDisplayNodeAssertMainThread();
|
|
return [_layer asyncdisplaykit_asyncTransactionContainerState];
|
|
}
|
|
|
|
- (void)asyncdisplaykit_cancelAsyncTransactions
|
|
{
|
|
ASDisplayNodeAssertMainThread();
|
|
[_layer asyncdisplaykit_cancelAsyncTransactions];
|
|
}
|
|
|
|
- (void)asyncdisplaykit_asyncTransactionContainerStateDidChange
|
|
{
|
|
}
|
|
|
|
@end
|