// // 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 //#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 object, void(^block)(id node)) { if (!object) { return; } std::queue> queue; queue.push(object); while (!queue.empty()) { id object = queue.front(); queue.pop(); block(object); for (id child in [object children]) { queue.push(child); } } } void ASEnvironmentPerformBlockOnObjectAndParents(id object, void(^block)(id node)) { while (object) { block(object); object = [object parent]; } } #pragma mark - Set and get extensible values from state structs void _ASEnvironmentLayoutOptionsExtensionSetBoolAtIndex(id 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 object, int idx) { NSCAssert(idx < kMaxEnvironmentStateBoolExtensions, @"Accessing index outside of max bool extensions space"); return object.environmentState.layoutOptionsState._extensions.boolExtensions[idx]; } void _ASEnvironmentLayoutOptionsExtensionSetIntegerAtIndex(id 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 object, int idx) { NSCAssert(idx < kMaxEnvironmentStateIntegerExtensions, @"Accessing index outside of max integer extensions space"); return object.environmentState.layoutOptionsState._extensions.integerExtensions[idx]; } void _ASEnvironmentLayoutOptionsExtensionSetEdgeInsetsAtIndex(id 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 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.containerSize = parentTraitCollection.containerSize; childEnvironmentState.environmentTraitCollection = childTraitCollection; } return childEnvironmentState; }