mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2026-01-03 19:54:31 +00:00
Passing around a pointer was leading to crashes as the ASVC was the sole owner of the context. There are cases where the VC would dealloc while its subnodes were laying out. This could lead to the subnodes accessing a garbage pointer.
216 lines
9.1 KiB
Plaintext
216 lines
9.1 KiB
Plaintext
//
|
|
// ASEnvironmentInternal.mm
|
|
// AsyncDisplayKit
|
|
//
|
|
// 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 <queue>
|
|
|
|
//#define LOG(...) NSLog(__VA_ARGS__)
|
|
#define LOG(...)
|
|
|
|
#define AS_SUPPORT_PROPAGATION YES
|
|
#define AS_DOES_NOT_SUPPORT_PROPAGATION NO
|
|
|
|
BOOL ASEnvironmentStatePropagationEnabled()
|
|
{
|
|
return AS_DOES_NOT_SUPPORT_PROPAGATION;
|
|
}
|
|
|
|
BOOL ASEnvironmentStateTraitCollectionPropagationEnabled()
|
|
{
|
|
return AS_SUPPORT_PROPAGATION;
|
|
}
|
|
|
|
#pragma mark - Traversing an ASEnvironment Tree
|
|
|
|
void ASEnvironmentPerformBlockOnObjectAndChildren(id<ASEnvironment> object, void(^block)(id<ASEnvironment> node))
|
|
{
|
|
if (!object) {
|
|
return;
|
|
}
|
|
|
|
std::queue<id<ASEnvironment>> queue;
|
|
queue.push(object);
|
|
|
|
while (!queue.empty()) {
|
|
id<ASEnvironment> object = queue.front(); queue.pop();
|
|
|
|
block(object);
|
|
|
|
for (id<ASEnvironment> child in [object children]) {
|
|
queue.push(child);
|
|
}
|
|
}
|
|
}
|
|
|
|
void ASEnvironmentPerformBlockOnObjectAndParents(id<ASEnvironment> object, void(^block)(id<ASEnvironment> node))
|
|
{
|
|
while (object) {
|
|
block(object);
|
|
object = [object parent];
|
|
}
|
|
}
|
|
|
|
|
|
#pragma mark - Set and get extensible values from state structs
|
|
|
|
void _ASEnvironmentLayoutOptionsExtensionSetBoolAtIndex(id<ASEnvironment> object, int idx, BOOL value)
|
|
{
|
|
NSCAssert(idx < kMaxEnvironmentStateBoolExtensions, @"Setting index outside of max bool extensions space");
|
|
|
|
ASEnvironmentState state = object.environmentState;
|
|
state.layoutOptionsState._extensions.boolExtensions[idx] = value;
|
|
object.environmentState = state;
|
|
}
|
|
|
|
BOOL _ASEnvironmentLayoutOptionsExtensionGetBoolAtIndex(id<ASEnvironment> object, int idx)
|
|
{
|
|
NSCAssert(idx < kMaxEnvironmentStateBoolExtensions, @"Accessing index outside of max bool extensions space");
|
|
return object.environmentState.layoutOptionsState._extensions.boolExtensions[idx];
|
|
}
|
|
|
|
void _ASEnvironmentLayoutOptionsExtensionSetIntegerAtIndex(id<ASEnvironment> object, int idx, NSInteger value)
|
|
{
|
|
NSCAssert(idx < kMaxEnvironmentStateIntegerExtensions, @"Setting index outside of max integer extensions space");
|
|
|
|
ASEnvironmentState state = object.environmentState;
|
|
state.layoutOptionsState._extensions.integerExtensions[idx] = value;
|
|
object.environmentState = state;
|
|
}
|
|
|
|
NSInteger _ASEnvironmentLayoutOptionsExtensionGetIntegerAtIndex(id<ASEnvironment> object, int idx)
|
|
{
|
|
NSCAssert(idx < kMaxEnvironmentStateIntegerExtensions, @"Accessing index outside of max integer extensions space");
|
|
return object.environmentState.layoutOptionsState._extensions.integerExtensions[idx];
|
|
}
|
|
|
|
void _ASEnvironmentLayoutOptionsExtensionSetEdgeInsetsAtIndex(id<ASEnvironment> object, int idx, UIEdgeInsets value)
|
|
{
|
|
NSCAssert(idx < kMaxEnvironmentStateEdgeInsetExtensions, @"Setting index outside of max edge insets extensions space");
|
|
|
|
ASEnvironmentState state = object.environmentState;
|
|
state.layoutOptionsState._extensions.edgeInsetsExtensions[idx] = value;
|
|
object.environmentState = state;
|
|
}
|
|
|
|
UIEdgeInsets _ASEnvironmentLayoutOptionsExtensionGetEdgeInsetsAtIndex(id<ASEnvironment> object, int idx)
|
|
{
|
|
NSCAssert(idx < kMaxEnvironmentStateEdgeInsetExtensions, @"Accessing index outside of max edge insets extensions space");
|
|
return object.environmentState.layoutOptionsState._extensions.edgeInsetsExtensions[idx];
|
|
}
|
|
|
|
|
|
#pragma mark - Merging functions for states
|
|
|
|
ASEnvironmentState ASEnvironmentMergeObjectAndState(ASEnvironmentState environmentState, ASEnvironmentHierarchyState hierarchyState, ASEnvironmentStatePropagation propagation) {
|
|
// Merge object and hierarchy state
|
|
LOG(@"Merge object and state: %@ - ASEnvironmentHierarchyState", hierarchyState);
|
|
return environmentState;
|
|
}
|
|
|
|
ASEnvironmentState ASEnvironmentMergeObjectAndState(ASEnvironmentState environmentState, ASEnvironmentLayoutOptionsState layoutOptionsState, ASEnvironmentStatePropagation propagation) {
|
|
// Merge object and layout options state
|
|
LOG(@"Merge object and state: %@ - ASEnvironmentLayoutOptionsState", layoutOptionsState);
|
|
|
|
if (!ASEnvironmentStatePropagationEnabled() && propagation == ASEnvironmentStatePropagation::UP) {
|
|
return environmentState;
|
|
}
|
|
|
|
// Support propagate up
|
|
if (propagation == ASEnvironmentStatePropagation::UP) {
|
|
|
|
// Object is the parent and the state is the state of the child
|
|
const ASEnvironmentLayoutOptionsState defaultState = ASEnvironmentDefaultLayoutOptionsState;
|
|
ASEnvironmentLayoutOptionsState parentLayoutOptionsState = environmentState.layoutOptionsState;
|
|
|
|
// For every field check if the parent value is equal to the default and if so propegate up the value of the passed
|
|
// in layout options state
|
|
if (parentLayoutOptionsState.spacingBefore == defaultState.spacingBefore) {
|
|
parentLayoutOptionsState.spacingBefore = layoutOptionsState.spacingBefore;
|
|
}
|
|
if (parentLayoutOptionsState.spacingAfter == defaultState.spacingAfter) {
|
|
parentLayoutOptionsState.spacingAfter = layoutOptionsState.spacingAfter;
|
|
}
|
|
if (parentLayoutOptionsState.alignSelf == defaultState.alignSelf) {
|
|
parentLayoutOptionsState.alignSelf = layoutOptionsState.alignSelf;
|
|
}
|
|
if (parentLayoutOptionsState.flexGrow == defaultState.flexGrow) {
|
|
parentLayoutOptionsState.flexGrow = layoutOptionsState.flexGrow;
|
|
}
|
|
if (ASRelativeDimensionEqualToRelativeDimension(parentLayoutOptionsState.flexBasis, defaultState.flexBasis)) {
|
|
parentLayoutOptionsState.flexBasis = layoutOptionsState.flexBasis;
|
|
}
|
|
if (parentLayoutOptionsState.alignSelf == defaultState.alignSelf) {
|
|
parentLayoutOptionsState.alignSelf = layoutOptionsState.alignSelf;
|
|
}
|
|
if (parentLayoutOptionsState.ascender == defaultState.ascender) {
|
|
parentLayoutOptionsState.ascender = layoutOptionsState.ascender;
|
|
}
|
|
|
|
if (ASRelativeSizeRangeEqualToRelativeSizeRange(parentLayoutOptionsState.sizeRange, defaultState.sizeRange)) {
|
|
// For now it is unclear if we should be up-propagating sizeRange or layoutPosition.
|
|
// parentLayoutOptionsState.sizeRange = layoutOptionsState.sizeRange;
|
|
}
|
|
if (CGPointEqualToPoint(parentLayoutOptionsState.layoutPosition, defaultState.layoutPosition)) {
|
|
// For now it is unclear if we should be up-propagating sizeRange or layoutPosition.
|
|
// parentLayoutOptionsState.layoutPosition = layoutOptionsState.layoutPosition;
|
|
}
|
|
|
|
// Merge extended values if necessary
|
|
const ASEnvironmentStateExtensions defaultExtensions = ASEnvironmentDefaultStateExtensions;
|
|
const ASEnvironmentStateExtensions layoutOptionsStateExtensions = layoutOptionsState._extensions;
|
|
ASEnvironmentStateExtensions parentLayoutOptionsExtensions = parentLayoutOptionsState._extensions;
|
|
|
|
for (int i = 0; i < kMaxEnvironmentStateBoolExtensions; i++) {
|
|
if (parentLayoutOptionsExtensions.boolExtensions[i] == defaultExtensions.boolExtensions[i]) {
|
|
parentLayoutOptionsExtensions.boolExtensions[i] = layoutOptionsStateExtensions.boolExtensions[i];
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < kMaxEnvironmentStateIntegerExtensions; i++) {
|
|
if (parentLayoutOptionsExtensions.integerExtensions[i] == defaultExtensions.integerExtensions[i]) {
|
|
parentLayoutOptionsExtensions.integerExtensions[i] = layoutOptionsStateExtensions.integerExtensions[i];
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < kMaxEnvironmentStateEdgeInsetExtensions; i++) {
|
|
if (UIEdgeInsetsEqualToEdgeInsets(parentLayoutOptionsExtensions.edgeInsetsExtensions[i], defaultExtensions.edgeInsetsExtensions[i])) {
|
|
parentLayoutOptionsExtensions.edgeInsetsExtensions[i] = layoutOptionsStateExtensions.edgeInsetsExtensions[i];
|
|
}
|
|
}
|
|
parentLayoutOptionsState._extensions = parentLayoutOptionsExtensions;
|
|
|
|
// Update layout options state
|
|
environmentState.layoutOptionsState = parentLayoutOptionsState;
|
|
}
|
|
|
|
return environmentState;
|
|
}
|
|
|
|
ASEnvironmentState ASEnvironmentMergeObjectAndState(ASEnvironmentState childEnvironmentState, ASEnvironmentTraitCollection parentTraitCollection, ASEnvironmentStatePropagation propagation) {
|
|
if (propagation == ASEnvironmentStatePropagation::DOWN && !ASEnvironmentStateTraitCollectionPropagationEnabled()) {
|
|
return childEnvironmentState;
|
|
}
|
|
|
|
// Support propagate down
|
|
if (propagation == ASEnvironmentStatePropagation::DOWN) {
|
|
ASEnvironmentTraitCollection childTraitCollection = childEnvironmentState.environmentTraitCollection;
|
|
childTraitCollection.horizontalSizeClass = parentTraitCollection.horizontalSizeClass;
|
|
childTraitCollection.verticalSizeClass = parentTraitCollection.verticalSizeClass;
|
|
childTraitCollection.userInterfaceIdiom = parentTraitCollection.userInterfaceIdiom;
|
|
childTraitCollection.forceTouchCapability = parentTraitCollection.forceTouchCapability;
|
|
childTraitCollection.displayScale = parentTraitCollection.displayScale;
|
|
childTraitCollection.containerWindowSize = parentTraitCollection.containerWindowSize;
|
|
childEnvironmentState.environmentTraitCollection = childTraitCollection;
|
|
|
|
}
|
|
return childEnvironmentState;
|
|
}
|