Revamp API

Reviewed By: majak

Differential Revision: D3579423

fbshipit-source-id: 040ecab2f20216aa136ccb8a9e7e15ffa882b313
This commit is contained in:
Emil Sjolander 2016-07-20 08:46:00 -07:00 committed by Facebook Github Bot 6
parent 12ec213c0d
commit 1af9270e45
9 changed files with 510 additions and 288 deletions

View File

@ -28,10 +28,10 @@
{
[super setUp];
self.parentView = [self _shadowViewWithStyle:^(CSSStyle *style) {
style->flexDirection = CSSFlexDirectionColumn;
style->dimensions[0] = 440;
style->dimensions[1] = 440;
self.parentView = [self _shadowViewWithConfig:^(CSSNodeRef node) {
CSSNodeStyleSetFlexDirection(node, CSSFlexDirectionColumn);
CSSNodeStyleSetWidth(node, 440);
CSSNodeStyleSetHeight(node, 440);
}];
self.parentView.reactTag = @1; // must be valid rootView tag
}
@ -50,43 +50,43 @@
//
- (void)testApplyingLayoutRecursivelyToShadowView
{
RCTShadowView *leftView = [self _shadowViewWithStyle:^(CSSStyle *style) {
style->flex = 1;
RCTShadowView *leftView = [self _shadowViewWithConfig:^(CSSNodeRef node) {
CSSNodeStyleSetFlex(node, 1);
}];
RCTShadowView *centerView = [self _shadowViewWithStyle:^(CSSStyle *style) {
style->flex = 2;
style->margin[0] = 10;
style->margin[2] = 10;
RCTShadowView *centerView = [self _shadowViewWithConfig:^(CSSNodeRef node) {
CSSNodeStyleSetFlex(node, 2);
CSSNodeStyleSetMarginLeft(node, 10);
CSSNodeStyleSetMarginRight(node, 10);
}];
RCTShadowView *rightView = [self _shadowViewWithStyle:^(CSSStyle *style) {
style->flex = 1;
RCTShadowView *rightView = [self _shadowViewWithConfig:^(CSSNodeRef node) {
CSSNodeStyleSetFlex(node, 1);
}];
RCTShadowView *mainView = [self _shadowViewWithStyle:^(CSSStyle *style) {
style->flexDirection = CSSFlexDirectionRow;
style->flex = 2;
style->margin[1] = 10;
style->margin[3] = 10;
RCTShadowView *mainView = [self _shadowViewWithConfig:^(CSSNodeRef node) {
CSSNodeStyleSetFlexDirection(node, CSSFlexDirectionRow);
CSSNodeStyleSetFlex(node, 2);
CSSNodeStyleSetMarginTop(node, 10);
CSSNodeStyleSetMarginBottom(node, 10);
}];
[mainView insertReactSubview:leftView atIndex:0];
[mainView insertReactSubview:centerView atIndex:1];
[mainView insertReactSubview:rightView atIndex:2];
RCTShadowView *headerView = [self _shadowViewWithStyle:^(CSSStyle *style) {
style->flex = 1;
RCTShadowView *headerView = [self _shadowViewWithConfig:^(CSSNodeRef node) {
CSSNodeStyleSetFlex(node, 1);
}];
RCTShadowView *footerView = [self _shadowViewWithStyle:^(CSSStyle *style) {
style->flex = 1;
RCTShadowView *footerView = [self _shadowViewWithConfig:^(CSSNodeRef node) {
CSSNodeStyleSetFlex(node, 1);
}];
self.parentView.cssNode->style.padding[0] = 10;
self.parentView.cssNode->style.padding[1] = 10;
self.parentView.cssNode->style.padding[2] = 10;
self.parentView.cssNode->style.padding[3] = 10;
CSSNodeStyleSetPaddingLeft(self.parentView.cssNode, 10);
CSSNodeStyleSetPaddingTop(self.parentView.cssNode, 10);
CSSNodeStyleSetPaddingRight(self.parentView.cssNode, 10);
CSSNodeStyleSetPaddingBottom(self.parentView.cssNode, 10);
[self.parentView insertReactSubview:headerView atIndex:0];
[self.parentView insertReactSubview:mainView atIndex:1];
@ -108,10 +108,10 @@
- (void)testAssignsSuggestedWidthDimension
{
[self _withShadowViewWithStyle:^(CSSStyle *style) {
style->position[CSSPositionLeft] = 0;
style->position[CSSPositionTop] = 0;
style->dimensions[CSSDimensionHeight] = 10;
[self _withShadowViewWithStyle:^(CSSNodeRef node) {
CSSNodeStyleSetPositionLeft(node, 0);
CSSNodeStyleSetPositionTop(node, 0);
CSSNodeStyleSetHeight(node, 10);
}
assertRelativeLayout:CGRectMake(0, 0, 3, 10)
withIntrinsicContentSize:CGSizeMake(3, UIViewNoIntrinsicMetric)];
@ -119,10 +119,10 @@
- (void)testAssignsSuggestedHeightDimension
{
[self _withShadowViewWithStyle:^(CSSStyle *style) {
style->position[CSSPositionLeft] = 0;
style->position[CSSPositionTop] = 0;
style->dimensions[CSSDimensionWidth] = 10;
[self _withShadowViewWithStyle:^(CSSNodeRef node) {
CSSNodeStyleSetPositionLeft(node, 0);
CSSNodeStyleSetPositionTop(node, 0);
CSSNodeStyleSetWidth(node, 10);
}
assertRelativeLayout:CGRectMake(0, 0, 10, 4)
withIntrinsicContentSize:CGSizeMake(UIViewNoIntrinsicMetric, 4)];
@ -130,11 +130,11 @@
- (void)testDoesNotOverrideDimensionStyleWithSuggestedDimensions
{
[self _withShadowViewWithStyle:^(CSSStyle *style) {
style->position[CSSPositionLeft] = 0;
style->position[CSSPositionTop] = 0;
style->dimensions[CSSDimensionWidth] = 10;
style->dimensions[CSSDimensionHeight] = 10;
[self _withShadowViewWithStyle:^(CSSNodeRef node) {
CSSNodeStyleSetPositionLeft(node, 0);
CSSNodeStyleSetPositionTop(node, 0);
CSSNodeStyleSetWidth(node, 10);
CSSNodeStyleSetHeight(node, 10);
}
assertRelativeLayout:CGRectMake(0, 0, 10, 10)
withIntrinsicContentSize:CGSizeMake(3, 4)];
@ -142,20 +142,20 @@
- (void)testDoesNotAssignSuggestedDimensionsWhenStyledWithFlexAttribute
{
float parentWidth = self.parentView.cssNode->style.dimensions[CSSDimensionWidth];
float parentHeight = self.parentView.cssNode->style.dimensions[CSSDimensionHeight];
[self _withShadowViewWithStyle:^(CSSStyle *style) {
style->flex = 1;
float parentWidth = CSSNodeStyleGetWidth(self.parentView.cssNode);
float parentHeight = CSSNodeStyleGetHeight(self.parentView.cssNode);
[self _withShadowViewWithStyle:^(CSSNodeRef node) {
CSSNodeStyleSetFlex(node, 1);
}
assertRelativeLayout:CGRectMake(0, 0, parentWidth, parentHeight)
withIntrinsicContentSize:CGSizeMake(3, 4)];
}
- (void)_withShadowViewWithStyle:(void(^)(CSSStyle *style))styleBlock
- (void)_withShadowViewWithStyle:(void(^)(CSSNodeRef node))configBlock
assertRelativeLayout:(CGRect)expectedRect
withIntrinsicContentSize:(CGSize)contentSize
{
RCTShadowView *view = [self _shadowViewWithStyle:styleBlock];
RCTShadowView *view = [self _shadowViewWithConfig:configBlock];
[self.parentView insertReactSubview:view atIndex:0];
view.intrinsicContentSize = contentSize;
[self.parentView collectViewsWithUpdatedFrames];
@ -166,14 +166,10 @@
NSStringFromCGRect(actualRect));
}
- (RCTRootShadowView *)_shadowViewWithStyle:(void(^)(CSSStyle *style))styleBlock
- (RCTRootShadowView *)_shadowViewWithConfig:(void(^)(CSSNodeRef node))configBlock
{
RCTRootShadowView *shadowView = [RCTRootShadowView new];
CSSStyle style = shadowView.cssNode->style;
styleBlock(&style);
shadowView.cssNode->style = style;
configBlock(shadowView.cssNode);
return shadowView;
}

View File

@ -33,7 +33,7 @@ NSString *const RCTReactTagAttributeName = @"ReactTagAttributeName";
CGFloat _effectiveLetterSpacing;
}
static CSSMeasureResult RCTMeasure(void *context, float width, CSSMeasureMode widthMode, float height, CSSMeasureMode heightMode)
static CSSSize RCTMeasure(void *context, float width, CSSMeasureMode widthMode, float height, CSSMeasureMode heightMode)
{
RCTShadowText *shadowText = (__bridge RCTShadowText *)context;
NSTextStorage *textStorage = [shadowText buildTextStorageForWidth:width widthMode:widthMode];
@ -41,12 +41,12 @@ static CSSMeasureResult RCTMeasure(void *context, float width, CSSMeasureMode wi
NSTextContainer *textContainer = layoutManager.textContainers.firstObject;
CGSize computedSize = [layoutManager usedRectForTextContainer:textContainer].size;
CSSMeasureResult result;
result.dimensions[CSSDimensionWidth] = RCTCeilPixelValue(computedSize.width);
CSSSize result;
result.width = RCTCeilPixelValue(computedSize.width);
if (shadowText->_effectiveLetterSpacing < 0) {
result.dimensions[CSSDimensionWidth] -= shadowText->_effectiveLetterSpacing;
result.width -= shadowText->_effectiveLetterSpacing;
}
result.dimensions[CSSDimensionHeight] = RCTCeilPixelValue(computedSize.height);
result.height = RCTCeilPixelValue(computedSize.height);
return result;
}
@ -61,7 +61,7 @@ static CSSMeasureResult RCTMeasure(void *context, float width, CSSMeasureMode wi
_cachedTextStorageWidth = -1;
_cachedTextStorageWidthMode = -1;
_fontSizeMultiplier = 1.0;
self.cssNode->measure = RCTMeasure;
CSSNodeSetMeasureFunc(self.cssNode, RCTMeasure);
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(contentSizeMultiplierDidChange:)
name:RCTUIManagerWillUpdateViewsDueToContentSizeMultiplierChangeNotification
@ -128,7 +128,7 @@ static CSSMeasureResult RCTMeasure(void *context, float width, CSSMeasureMode wi
return parentProperties;
}
- (void)applyLayoutNode:(CSSNode *)node
- (void)applyLayoutNode:(CSSNodeRef)node
viewsWithNewFrame:(NSMutableSet<RCTShadowView *> *)viewsWithNewFrame
absolutePosition:(CGPoint)absolutePosition
{
@ -136,7 +136,7 @@ static CSSMeasureResult RCTMeasure(void *context, float width, CSSMeasureMode wi
[self dirtyPropagation];
}
- (void)applyLayoutToChildren:(CSSNode *)node
- (void)applyLayoutToChildren:(CSSNodeRef)node
viewsWithNewFrame:(NSMutableSet<RCTShadowView *> *)viewsWithNewFrame
absolutePosition:(CGPoint)absolutePosition
{
@ -148,9 +148,9 @@ static CSSMeasureResult RCTMeasure(void *context, float width, CSSMeasureMode wi
NSRange characterRange = [layoutManager characterRangeForGlyphRange:glyphRange actualGlyphRange:NULL];
[layoutManager.textStorage enumerateAttribute:RCTShadowViewAttributeName inRange:characterRange options:0 usingBlock:^(RCTShadowView *child, NSRange range, BOOL *_) {
if (child) {
CSSNode *childNode = child.cssNode;
float width = childNode->style.dimensions[CSSDimensionWidth];
float height = childNode->style.dimensions[CSSDimensionHeight];
CSSNodeRef childNode = child.cssNode;
float width = CSSNodeStyleGetWidth(childNode);
float height = CSSNodeStyleGetHeight(childNode);
if (isUndefined(width) || isUndefined(height)) {
RCTLogError(@"Views nested within a <Text> must have a width and height");
}
@ -291,8 +291,8 @@ static CSSMeasureResult RCTMeasure(void *context, float width, CSSMeasureMode wi
[attributedString appendAttributedString:[[NSAttributedString alloc] initWithString:shadowRawText.text ?: @""]];
[child setTextComputed];
} else {
float width = child.cssNode->style.dimensions[CSSDimensionWidth];
float height = child.cssNode->style.dimensions[CSSDimensionHeight];
float width = CSSNodeStyleGetWidth(child.cssNode);
float height = CSSNodeStyleGetHeight(child.cssNode);
if (isUndefined(width) || isUndefined(height)) {
RCTLogError(@"Views nested within a <Text> must have a width and height");
}
@ -384,10 +384,10 @@ static CSSMeasureResult RCTMeasure(void *context, float width, CSSMeasureMode wi
// We will climb up to the first node which style has been setted as non-inherit
if (newTextAlign == NSTextAlignmentRight || newTextAlign == NSTextAlignmentLeft) {
RCTShadowView *view = self;
while (view != nil && view.cssNode->style.direction == CSSDirectionInherit) {
while (view != nil && CSSNodeStyleGetDirection(view.cssNode) == CSSDirectionInherit) {
view = [view reactSuperview];
}
if (view != nil && view.cssNode->style.direction == CSSDirectionRTL) {
if (view != nil && CSSNodeStyleGetDirection(view.cssNode) == CSSDirectionRTL) {
if (newTextAlign == NSTextAlignmentRight) {
newTextAlign = NSTextAlignmentLeft;
} else if (newTextAlign == NSTextAlignmentLeft) {

View File

@ -0,0 +1,104 @@
/**
* 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.
*/
#ifndef __CSS_LAYOUT_INTERNAL_H
#define __CSS_LAYOUT_INTERNAL_H
#include <stdio.h>
#include <stdlib.h>
#include "CSSLayout.h"
CSS_EXTERN_C_BEGIN
typedef struct CSSCachedMeasurement {
float availableWidth;
float availableHeight;
CSSMeasureMode widthMeasureMode;
CSSMeasureMode heightMeasureMode;
float computedWidth;
float computedHeight;
} CSSCachedMeasurement;
// This value was chosen based on empiracle data. Even the most complicated
// layouts should not require more than 16 entries to fit within the cache.
enum {
CSS_MAX_CACHED_RESULT_COUNT = 16
};
typedef struct CSSLayout {
float position[4];
float dimensions[2];
CSSDirection direction;
float flexBasis;
// Instead of recomputing the entire layout every single time, we
// cache some information to break early when nothing changed
int generationCount;
CSSDirection lastParentDirection;
int nextCachedMeasurementsIndex;
CSSCachedMeasurement cachedMeasurements[CSS_MAX_CACHED_RESULT_COUNT];
float measuredDimensions[2];
CSSCachedMeasurement cached_layout;
} CSSLayout;
typedef struct CSSStyle {
CSSDirection direction;
CSSFlexDirection flexDirection;
CSSJustify justifyContent;
CSSAlign alignContent;
CSSAlign alignItems;
CSSAlign alignSelf;
CSSPositionType positionType;
CSSWrapType flexWrap;
CSSOverflow overflow;
float flex;
float margin[6];
float position[4];
/**
* You should skip all the rules that contain negative values for the
* following attributes. For example:
* {padding: 10, paddingLeft: -5}
* should output:
* {left: 10 ...}
* the following two are incorrect:
* {left: -5 ...}
* {left: 0 ...}
*/
float padding[6];
float border[6];
float dimensions[2];
float minDimensions[2];
float maxDimensions[2];
} CSSStyle;
typedef struct CSSNode {
CSSStyle style;
CSSLayout layout;
int childCount;
int lineIndex;
bool shouldUpdate;
struct CSSNode* nextChild;
CSSSize (*measure)(void *context, float width, CSSMeasureMode widthMode, float height, CSSMeasureMode heightMode);
struct CSSNode* (*getChild)(void *context, int i);
bool (*isDirty)(void *context);
bool (*isTextNode)(void *context);
void (*print)(void *context);
void *context;
} CSSNode;
CSS_EXTERN_C_END
#endif

View File

@ -13,7 +13,7 @@
#include <stdlib.h>
#include <string.h>
#include "CSSLayout.h"
#include "CSSLayout-internal.h"
#ifdef _MSC_VER
#include <float.h>
@ -29,23 +29,17 @@ __forceinline const float fmaxf(const float a, const float b) {
#define POSITIVE_FLEX_IS_AUTO 0
int gCurrentGenerationCount = 0;
bool layoutNodeInternal(CSSNode* node, float availableWidth, float availableHeight, CSSDirection parentDirection,
CSSMeasureMode widthMeasureMode, CSSMeasureMode heightMeasureMode, bool performLayout, char* reason);
bool isUndefined(float value) {
return isnan(value);
CSSNodeRef CSSNodeNew() {
CSSNode* node = (CSSNode*)calloc(1, sizeof(*node));
CSSNodeInit(node);
return node;
}
static bool eq(float a, float b) {
if (isUndefined(a)) {
return isUndefined(b);
}
return fabs(a - b) < 0.0001;
void CSSNodeFree(CSSNodeRef node) {
free(node);
}
void CSSNodeInit(CSSNode* node) {
void CSSNodeInit(CSSNodeRef node) {
node->style.alignItems = CSSAlignStretch;
node->style.alignContent = CSSAlignFlexStart;
@ -81,7 +75,7 @@ void CSSNodeInit(CSSNode* node) {
// Such that the comparison is always going to be false
node->layout.lastParentDirection = (CSSDirection)-1;
node->layout.shouldUpdate = true;
node->shouldUpdate = true;
node->layout.nextCachedMeasurementsIndex = 0;
node->layout.measuredDimensions[CSSDimensionWidth] = CSSUndefined;
@ -90,14 +84,103 @@ void CSSNodeInit(CSSNode* node) {
node->layout.cached_layout.heightMeasureMode = (CSSMeasureMode)-1;
}
CSSNode* CSSNodeNew() {
CSSNode* node = (CSSNode*)calloc(1, sizeof(*node));
CSSNodeInit(node);
return node;
#define CSS_NODE_PROPERTY_IMPL(type, name, paramName, instanceName) \
void CSSNodeSet##name(CSSNodeRef node, type paramName) { \
node->instanceName = paramName;\
} \
\
type CSSNodeGet##name(CSSNodeRef node) { \
return node->instanceName;\
} \
#define CSS_NODE_STYLE_PROPERTY_IMPL(type, name, paramName, instanceName) \
void CSSNodeStyleSet##name(CSSNodeRef node, type paramName) { \
node->style.instanceName = paramName;\
} \
\
type CSSNodeStyleGet##name(CSSNodeRef node) { \
return node->style.instanceName;\
} \
#define CSS_NODE_LAYOUT_PROPERTY_IMPL(type, name, instanceName) \
type CSSNodeLayoutGet##name(CSSNodeRef node) { \
return node->layout.instanceName;\
} \
CSS_NODE_PROPERTY_IMPL(void*, Context, context, context);
CSS_NODE_PROPERTY_IMPL(int, ChildCount, childCount, childCount);
CSS_NODE_PROPERTY_IMPL(CSSMeasureFunc, MeasureFunc, measureFunc, measure);
CSS_NODE_PROPERTY_IMPL(CSSChildFunc, ChildFunc, childFunc, getChild);
CSS_NODE_PROPERTY_IMPL(CSSIsDirtyFunc, IsDirtyFunc, isDirtyFunc, isDirty);
CSS_NODE_PROPERTY_IMPL(CSSIsTextFunc, IsTextFunc, isTextFunc, isTextNode);
CSS_NODE_PROPERTY_IMPL(CSSPrintFunc, PrintFunc, printFunc, print);
CSS_NODE_PROPERTY_IMPL(bool, ShouldUpdate, shouldUpdate, shouldUpdate);
CSS_NODE_STYLE_PROPERTY_IMPL(CSSDirection, Direction, direction, direction);
CSS_NODE_STYLE_PROPERTY_IMPL(CSSFlexDirection, FlexDirection, flexDirection, flexDirection);
CSS_NODE_STYLE_PROPERTY_IMPL(CSSJustify, JustifyContent, justifyContent, justifyContent);
CSS_NODE_STYLE_PROPERTY_IMPL(CSSAlign, AlignContent, alignContent, alignContent);
CSS_NODE_STYLE_PROPERTY_IMPL(CSSAlign, AlignItems, alignItems, alignItems);
CSS_NODE_STYLE_PROPERTY_IMPL(CSSAlign, AlignSelf, alignSelf, alignSelf);
CSS_NODE_STYLE_PROPERTY_IMPL(CSSPositionType, PositionType, positionType, positionType);
CSS_NODE_STYLE_PROPERTY_IMPL(CSSWrapType, FlexWrap, flexWrap, flexWrap);
CSS_NODE_STYLE_PROPERTY_IMPL(CSSOverflow, Overflow, overflow, overflow);
CSS_NODE_STYLE_PROPERTY_IMPL(float, Flex, flex, flex);
CSS_NODE_STYLE_PROPERTY_IMPL(float, PositionLeft, positionLeft, position[CSSPositionLeft]);
CSS_NODE_STYLE_PROPERTY_IMPL(float, PositionTop, positionTop, position[CSSPositionTop]);
CSS_NODE_STYLE_PROPERTY_IMPL(float, PositionRight, positionRight, position[CSSPositionRight]);
CSS_NODE_STYLE_PROPERTY_IMPL(float, PositionBottom, positionBottom, position[CSSPositionBottom]);
CSS_NODE_STYLE_PROPERTY_IMPL(float, MarginLeft, marginLeft, margin[CSSPositionLeft]);
CSS_NODE_STYLE_PROPERTY_IMPL(float, MarginTop, marginTop, margin[CSSPositionTop]);
CSS_NODE_STYLE_PROPERTY_IMPL(float, MarginRight, marginRight, margin[CSSPositionRight]);
CSS_NODE_STYLE_PROPERTY_IMPL(float, MarginBottom, marginBottom, margin[CSSPositionBottom]);
CSS_NODE_STYLE_PROPERTY_IMPL(float, MarginStart, marginStart, margin[CSSPositionStart]);
CSS_NODE_STYLE_PROPERTY_IMPL(float, MarginEnd, marginEnd, margin[CSSPositionEnd]);
CSS_NODE_STYLE_PROPERTY_IMPL(float, PaddingLeft, paddingLeft, padding[CSSPositionLeft]);
CSS_NODE_STYLE_PROPERTY_IMPL(float, PaddingTop, paddingTop, padding[CSSPositionTop]);
CSS_NODE_STYLE_PROPERTY_IMPL(float, PaddingRight, paddingRight, padding[CSSPositionRight]);
CSS_NODE_STYLE_PROPERTY_IMPL(float, PaddingBottom, paddingBottom, padding[CSSPositionBottom]);
CSS_NODE_STYLE_PROPERTY_IMPL(float, PaddingStart, paddingStart, padding[CSSPositionStart]);
CSS_NODE_STYLE_PROPERTY_IMPL(float, PaddingEnd, paddingEnd, padding[CSSPositionEnd]);
CSS_NODE_STYLE_PROPERTY_IMPL(float, BorderLeft, borderLeft, border[CSSPositionLeft]);
CSS_NODE_STYLE_PROPERTY_IMPL(float, BorderTop, borderTop, border[CSSPositionTop]);
CSS_NODE_STYLE_PROPERTY_IMPL(float, BorderRight, borderRight, border[CSSPositionRight]);
CSS_NODE_STYLE_PROPERTY_IMPL(float, BorderBottom, borderBottom, border[CSSPositionBottom]);
CSS_NODE_STYLE_PROPERTY_IMPL(float, BorderStart, borderStart, border[CSSPositionStart]);
CSS_NODE_STYLE_PROPERTY_IMPL(float, BorderEnd, BorderEnd, border[CSSPositionEnd]);
CSS_NODE_STYLE_PROPERTY_IMPL(float, Width, width, dimensions[CSSDimensionWidth]);
CSS_NODE_STYLE_PROPERTY_IMPL(float, Height, height, dimensions[CSSDimensionHeight]);
CSS_NODE_STYLE_PROPERTY_IMPL(float, MinWidth, minWidth, minDimensions[CSSDimensionWidth]);
CSS_NODE_STYLE_PROPERTY_IMPL(float, MinHeight, minHeight, minDimensions[CSSDimensionHeight]);
CSS_NODE_STYLE_PROPERTY_IMPL(float, MaxWidth, maxWidth, maxDimensions[CSSDimensionWidth]);
CSS_NODE_STYLE_PROPERTY_IMPL(float, MaxHeight, maxHeight, maxDimensions[CSSDimensionHeight]);
CSS_NODE_LAYOUT_PROPERTY_IMPL(float, Left, position[CSSPositionLeft]);
CSS_NODE_LAYOUT_PROPERTY_IMPL(float, Top, position[CSSPositionTop]);
CSS_NODE_LAYOUT_PROPERTY_IMPL(float, Right, position[CSSPositionRight]);
CSS_NODE_LAYOUT_PROPERTY_IMPL(float, Bottom, position[CSSPositionBottom]);
CSS_NODE_LAYOUT_PROPERTY_IMPL(float, Width, dimensions[CSSDimensionWidth]);
CSS_NODE_LAYOUT_PROPERTY_IMPL(float, Height, dimensions[CSSDimensionHeight]);
int gCurrentGenerationCount = 0;
bool layoutNodeInternal(CSSNode* node, float availableWidth, float availableHeight, CSSDirection parentDirection,
CSSMeasureMode widthMeasureMode, CSSMeasureMode heightMeasureMode, bool performLayout, char* reason);
bool isUndefined(float value) {
return isnan(value);
}
void CSSNodeFree(CSSNode* node) {
free(node);
static bool eq(float a, float b) {
if (isUndefined(a)) {
return isUndefined(b);
}
return fabs(a - b) < 0.0001;
}
static void indent(int n) {
@ -682,7 +765,7 @@ static void layoutNodeImpl(CSSNode* node, float availableWidth, float availableH
} else {
// Measure the text under the current constraints.
CSSMeasureResult measureDim = node->measure(
CSSSize measuredSize = node->measure(
node->context,
innerWidth,
@ -693,11 +776,11 @@ static void layoutNodeImpl(CSSNode* node, float availableWidth, float availableH
node->layout.measuredDimensions[CSSDimensionWidth] = boundAxis(node, CSSFlexDirectionRow,
(widthMeasureMode == CSSMeasureModeUndefined || widthMeasureMode == CSSMeasureModeAtMost) ?
measureDim.dimensions[CSSDimensionWidth] + paddingAndBorderAxisRow :
measuredSize.width + paddingAndBorderAxisRow :
availableWidth - marginAxisRow);
node->layout.measuredDimensions[CSSDimensionHeight] = boundAxis(node, CSSFlexDirectionColumn,
(heightMeasureMode == CSSMeasureModeUndefined || heightMeasureMode == CSSMeasureModeAtMost) ?
measureDim.dimensions[CSSDimensionHeight] + paddingAndBorderAxisColumn :
measuredSize.height + paddingAndBorderAxisColumn :
availableHeight - marginAxisColumn);
}
@ -1764,7 +1847,7 @@ bool layoutNodeInternal(CSSNode* node, float availableWidth, float availableHeig
if (performLayout) {
node->layout.dimensions[CSSDimensionWidth] = node->layout.measuredDimensions[CSSDimensionWidth];
node->layout.dimensions[CSSDimensionHeight] = node->layout.measuredDimensions[CSSDimensionHeight];
layout->shouldUpdate = true;
node->shouldUpdate = true;
}
gDepth--;
@ -1772,7 +1855,7 @@ bool layoutNodeInternal(CSSNode* node, float availableWidth, float availableHeig
return (needToVisitNode || cachedResults == NULL);
}
void layoutNode(CSSNode* node, float availableWidth, float availableHeight, CSSDirection parentDirection) {
void CSSNodeCalculateLayout(CSSNode* node, float availableWidth, float availableHeight, CSSDirection parentDirection) {
// Increment the generation count. This will force the recursive routine to visit
// all dirty nodes at least once. Subsequent visits will be skipped if the input
// parameters don't change.

View File

@ -7,8 +7,8 @@
* of patent rights can be found in the PATENTS file in the same directory.
*/
#ifndef __LAYOUT_H
#define __LAYOUT_H
#ifndef __CSS_LAYOUT_H
#define __CSS_LAYOUT_H
#include <math.h>
#ifndef __cplusplus
@ -97,110 +97,110 @@ typedef enum CSSDimension {
CSSDimensionHeight,
} CSSDimension;
typedef struct CSSCachedMeasurement {
float availableWidth;
float availableHeight;
CSSMeasureMode widthMeasureMode;
CSSMeasureMode heightMeasureMode;
float computedWidth;
float computedHeight;
} CSSCachedMeasurement;
// This value was chosen based on empiracle data. Even the most complicated
// layouts should not require more than 16 entries to fit within the cache.
enum {
CSS_MAX_CACHED_RESULT_COUNT = 16
};
typedef struct CSSLayout {
float position[4];
float dimensions[2];
CSSDirection direction;
float flexBasis;
// Instead of recomputing the entire layout every single time, we
// cache some information to break early when nothing changed
bool shouldUpdate;
int generationCount;
CSSDirection lastParentDirection;
int nextCachedMeasurementsIndex;
CSSCachedMeasurement cachedMeasurements[CSS_MAX_CACHED_RESULT_COUNT];
float measuredDimensions[2];
CSSCachedMeasurement cached_layout;
} CSSLayout;
typedef struct CSSMeasureResult {
float dimensions[2];
} CSSMeasureResult;
typedef struct CSSStyle {
CSSDirection direction;
CSSFlexDirection flexDirection;
CSSJustify justifyContent;
CSSAlign alignContent;
CSSAlign alignItems;
CSSAlign alignSelf;
CSSPositionType positionType;
CSSWrapType flexWrap;
CSSOverflow overflow;
float flex;
float margin[6];
float position[4];
/**
* You should skip all the rules that contain negative values for the
* following attributes. For example:
* {padding: 10, paddingLeft: -5}
* should output:
* {left: 10 ...}
* the following two are incorrect:
* {left: -5 ...}
* {left: 0 ...}
*/
float padding[6];
float border[6];
float dimensions[2];
float minDimensions[2];
float maxDimensions[2];
} CSSStyle;
typedef struct CSSNode {
CSSStyle style;
CSSLayout layout;
int childCount;
int lineIndex;
struct CSSNode* nextChild;
CSSMeasureResult (*measure)(void *context, float width, CSSMeasureMode widthMode, float height, CSSMeasureMode heightMode);
void (*print)(void *context);
struct CSSNode* (*getChild)(void *context, int i);
bool (*isDirty)(void *context);
bool (*isTextNode)(void *context);
void *context;
} CSSNode;
// Lifecycle of nodes and children
CSSNode *CSSNodeNew();
void CSSNodeInit(CSSNode *node);
void CSSNodeFree(CSSNode *node);
// Print utilities
typedef enum CSSPrintOptions {
CSSPrintOptionsLayout = 1,
CSSPrintOptionsStyle = 2,
CSSPrintOptionsChildren = 4,
} CSSPrintOptions;
void CSSNodePrint(CSSNode *node, CSSPrintOptions options);
typedef struct CSSSize {
float width;
float height;
} CSSSize;
typedef struct CSSNode * CSSNodeRef;
typedef CSSSize (*CSSMeasureFunc)(void *context, float width, CSSMeasureMode widthMode, float height, CSSMeasureMode heightMode);
typedef CSSNodeRef (*CSSChildFunc)(void *context, int i);
typedef bool (*CSSIsDirtyFunc)(void *context);
typedef bool (*CSSIsTextFunc)(void *context);
typedef void (*CSSPrintFunc)(void *context);
// CSSNode
CSSNodeRef CSSNodeNew();
void CSSNodeInit(CSSNodeRef node);
void CSSNodeFree(CSSNodeRef node);
void CSSNodeCalculateLayout(
CSSNodeRef node,
float availableWidth,
float availableHeight,
CSSDirection parentDirection);
void CSSNodePrint(CSSNodeRef node, CSSPrintOptions options);
// Function that computes the layout!
void layoutNode(CSSNode *node, float availableWidth, float availableHeight, CSSDirection parentDirection);
bool isUndefined(float value);
#define CSS_NODE_PROPERTY(type, name, paramName) \
void CSSNodeSet##name(CSSNodeRef node, type paramName); \
type CSSNodeGet##name(CSSNodeRef node);
#define CSS_NODE_STYLE_PROPERTY(type, name, paramName) \
void CSSNodeStyleSet##name(CSSNodeRef node, type paramName); \
type CSSNodeStyleGet##name(CSSNodeRef node);
#define CSS_NODE_LAYOUT_PROPERTY(type, name) \
type CSSNodeLayoutGet##name(CSSNodeRef node);
CSS_NODE_PROPERTY(void*, Context, context);
CSS_NODE_PROPERTY(int, ChildCount, childCount);
CSS_NODE_PROPERTY(CSSMeasureFunc, MeasureFunc, measureFunc);
CSS_NODE_PROPERTY(CSSChildFunc, ChildFunc, childFunc);
CSS_NODE_PROPERTY(CSSIsDirtyFunc, IsDirtyFunc, isDirtyFunc);
CSS_NODE_PROPERTY(CSSIsTextFunc, IsTextFunc, isTextFunc);
CSS_NODE_PROPERTY(CSSPrintFunc, PrintFunc, printFunc);
CSS_NODE_PROPERTY(bool, ShouldUpdate, shouldUpdate);
CSS_NODE_STYLE_PROPERTY(CSSDirection, Direction, direction);
CSS_NODE_STYLE_PROPERTY(CSSFlexDirection, FlexDirection, flexDirection);
CSS_NODE_STYLE_PROPERTY(CSSJustify, JustifyContent, justifyContent);
CSS_NODE_STYLE_PROPERTY(CSSAlign, AlignContent, alignContent);
CSS_NODE_STYLE_PROPERTY(CSSAlign, AlignItems, alignItems);
CSS_NODE_STYLE_PROPERTY(CSSAlign, AlignSelf, alignSelf);
CSS_NODE_STYLE_PROPERTY(CSSPositionType, PositionType, positionType);
CSS_NODE_STYLE_PROPERTY(CSSWrapType, FlexWrap, flexWrap);
CSS_NODE_STYLE_PROPERTY(CSSOverflow, Overflow, overflow);
CSS_NODE_STYLE_PROPERTY(float, Flex, flex);
CSS_NODE_STYLE_PROPERTY(float, PositionLeft, positionLeft);
CSS_NODE_STYLE_PROPERTY(float, PositionTop, positionTop);
CSS_NODE_STYLE_PROPERTY(float, PositionRight, positionRight);
CSS_NODE_STYLE_PROPERTY(float, PositionBottom, positionBottom);
CSS_NODE_STYLE_PROPERTY(float, MarginLeft, marginLeft);
CSS_NODE_STYLE_PROPERTY(float, MarginTop, marginTop);
CSS_NODE_STYLE_PROPERTY(float, MarginRight, marginRight);
CSS_NODE_STYLE_PROPERTY(float, MarginBottom, marginBottom);
CSS_NODE_STYLE_PROPERTY(float, MarginStart, marginStart);
CSS_NODE_STYLE_PROPERTY(float, MarginEnd, marginEnd);
CSS_NODE_STYLE_PROPERTY(float, PaddingLeft, paddingLeft);
CSS_NODE_STYLE_PROPERTY(float, PaddingTop, paddingTop);
CSS_NODE_STYLE_PROPERTY(float, PaddingRight, paddingRight);
CSS_NODE_STYLE_PROPERTY(float, PaddingBottom, paddingBottom);
CSS_NODE_STYLE_PROPERTY(float, PaddingStart, paddingStart);
CSS_NODE_STYLE_PROPERTY(float, PaddingEnd, paddingEnd);
CSS_NODE_STYLE_PROPERTY(float, BorderLeft, borderLeft);
CSS_NODE_STYLE_PROPERTY(float, BorderTop, borderTop);
CSS_NODE_STYLE_PROPERTY(float, BorderRight, borderRight);
CSS_NODE_STYLE_PROPERTY(float, BorderBottom, borderBottom);
CSS_NODE_STYLE_PROPERTY(float, BorderStart, borderStart);
CSS_NODE_STYLE_PROPERTY(float, BorderEnd, borderEnd);
CSS_NODE_STYLE_PROPERTY(float, Width, width);
CSS_NODE_STYLE_PROPERTY(float, Height, height);
CSS_NODE_STYLE_PROPERTY(float, MinWidth, minWidth);
CSS_NODE_STYLE_PROPERTY(float, MinHeight, minHeight);
CSS_NODE_STYLE_PROPERTY(float, MaxWidth, maxWidth);
CSS_NODE_STYLE_PROPERTY(float, MaxHeight, maxHeight);
CSS_NODE_LAYOUT_PROPERTY(float, Left);
CSS_NODE_LAYOUT_PROPERTY(float, Top);
CSS_NODE_LAYOUT_PROPERTY(float, Right);
CSS_NODE_LAYOUT_PROPERTY(float, Bottom);
CSS_NODE_LAYOUT_PROPERTY(float, Width);
CSS_NODE_LAYOUT_PROPERTY(float, Height);
CSS_EXTERN_C_END
#endif

View File

@ -121,6 +121,7 @@
000E6CEA1AB0E980000CDF4D /* RCTSourceCode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTSourceCode.m; sourceTree = "<group>"; };
008341F41D1DB34400876D9A /* RCTJSStackFrame.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTJSStackFrame.m; sourceTree = "<group>"; };
008341F51D1DB34400876D9A /* RCTJSStackFrame.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTJSStackFrame.h; sourceTree = "<group>"; };
131541CF1D3E4893006A0E08 /* CSSLayout-internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "CSSLayout-internal.h"; sourceTree = "<group>"; };
131B6AF01AF1093D00FFC3E0 /* RCTSegmentedControl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTSegmentedControl.h; sourceTree = "<group>"; };
131B6AF11AF1093D00FFC3E0 /* RCTSegmentedControl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTSegmentedControl.m; sourceTree = "<group>"; };
131B6AF21AF1093D00FFC3E0 /* RCTSegmentedControlManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTSegmentedControlManager.h; sourceTree = "<group>"; };
@ -342,6 +343,7 @@
133683431D37ACA10077D0C3 /* CSSLayout */ = {
isa = PBXGroup;
children = (
131541CF1D3E4893006A0E08 /* CSSLayout-internal.h */,
133683441D37ACA10077D0C3 /* CSSLayout.c */,
133683451D37ACA10077D0C3 /* CSSLayout.h */,
133683481D37ACA10077D0C3 /* CSSMacros.h */,

View File

@ -21,7 +21,7 @@
self = [super init];
if (self) {
if ([[RCTI18nUtil sharedInstance] isRTL]) {
self.cssNode->style.direction = CSSDirectionRTL;
CSSNodeStyleSetDirection(self.cssNode, CSSDirectionRTL);
}
}
return self;
@ -33,14 +33,14 @@
case RCTRootViewSizeFlexibilityNone:
break;
case RCTRootViewSizeFlexibilityWidth:
self.cssNode->style.dimensions[CSSDimensionWidth] = CSSUndefined;
CSSNodeStyleSetWidth(self.cssNode, CSSUndefined);
break;
case RCTRootViewSizeFlexibilityHeight:
self.cssNode->style.dimensions[CSSDimensionHeight] = CSSUndefined;
CSSNodeStyleSetHeight(self.cssNode, CSSUndefined);
break;
case RCTRootViewSizeFlexibilityWidthAndHeight:
self.cssNode->style.dimensions[CSSDimensionWidth] = CSSUndefined;
self.cssNode->style.dimensions[CSSDimensionHeight] = CSSUndefined;
CSSNodeStyleSetWidth(self.cssNode, CSSUndefined);
CSSNodeStyleSetHeight(self.cssNode, CSSUndefined);
break;
}
}
@ -49,7 +49,7 @@
{
[self applySizeConstraints];
layoutNode(self.cssNode, CSSUndefined, CSSUndefined, CSSDirectionInherit);
CSSNodeCalculateLayout(self.cssNode, CSSUndefined, CSSUndefined, CSSDirectionInherit);
NSMutableSet<RCTShadowView *> *viewsWithNewFrame = [NSMutableSet set];
[self applyLayoutNode:self.cssNode viewsWithNewFrame:viewsWithNewFrame absolutePosition:CGPointZero];

View File

@ -44,7 +44,7 @@ typedef void (^RCTApplierBlock)(NSDictionary<NSNumber *, UIView *> *viewRegistry
- (void)removeReactSubview:(RCTShadowView *)subview NS_REQUIRES_SUPER;
@property (nonatomic, weak, readonly) RCTShadowView *superview;
@property (nonatomic, assign, readonly) CSSNode *cssNode;
@property (nonatomic, assign, readonly) CSSNodeRef cssNode;
@property (nonatomic, copy) NSString *viewName;
@property (nonatomic, strong) UIColor *backgroundColor; // Used to propagate to children
@property (nonatomic, assign) RCTUpdateLifecycle layoutLifecycle;
@ -172,14 +172,14 @@ typedef void (^RCTApplierBlock)(NSDictionary<NSNumber *, UIView *> *viewRegistry
* is split into two methods so subclasses can override `applyLayoutToChildren:`
* while using default implementation of `applyLayoutNode:`.
*/
- (void)applyLayoutNode:(CSSNode *)node
- (void)applyLayoutNode:(CSSNodeRef)node
viewsWithNewFrame:(NSMutableSet<RCTShadowView *> *)viewsWithNewFrame
absolutePosition:(CGPoint)absolutePosition NS_REQUIRES_SUPER;
/**
* Enumerate the child nodes and tell them to apply layout.
*/
- (void)applyLayoutToChildren:(CSSNode *)node
- (void)applyLayoutToChildren:(CSSNodeRef)node
viewsWithNewFrame:(NSMutableSet<RCTShadowView *> *)viewsWithNewFrame
absolutePosition:(CGPoint)absolutePosition;

View File

@ -56,7 +56,7 @@ static void RCTPrint(void *context)
printf("%s(%zd), ", shadowView.viewName.UTF8String, shadowView.reactTag.integerValue);
}
static CSSNode *RCTGetChild(void *context, int i)
static CSSNodeRef RCTGetChild(void *context, int i)
{
RCTShadowView *shadowView = (__bridge RCTShadowView *)context;
RCTShadowView *child = [shadowView reactSubviews][i];
@ -70,25 +70,53 @@ static bool RCTIsDirty(void *context)
}
// Enforces precedence rules, e.g. marginLeft > marginHorizontal > margin.
static void RCTProcessMetaProps(const float metaProps[META_PROP_COUNT], float style[CSSPositionCount]) {
style[CSSPositionLeft] = !isUndefined(metaProps[META_PROP_LEFT]) ? metaProps[META_PROP_LEFT]
: !isUndefined(metaProps[META_PROP_HORIZONTAL]) ? metaProps[META_PROP_HORIZONTAL]
: !isUndefined(metaProps[META_PROP_ALL]) ? metaProps[META_PROP_ALL]
: 0;
style[CSSPositionRight] = !isUndefined(metaProps[META_PROP_RIGHT]) ? metaProps[META_PROP_RIGHT]
: !isUndefined(metaProps[META_PROP_HORIZONTAL]) ? metaProps[META_PROP_HORIZONTAL]
: !isUndefined(metaProps[META_PROP_ALL]) ? metaProps[META_PROP_ALL]
: 0;
style[CSSPositionTop] = !isUndefined(metaProps[META_PROP_TOP]) ? metaProps[META_PROP_TOP]
: !isUndefined(metaProps[META_PROP_VERTICAL]) ? metaProps[META_PROP_VERTICAL]
: !isUndefined(metaProps[META_PROP_ALL]) ? metaProps[META_PROP_ALL]
: 0;
style[CSSPositionBottom] = !isUndefined(metaProps[META_PROP_BOTTOM]) ? metaProps[META_PROP_BOTTOM]
: !isUndefined(metaProps[META_PROP_VERTICAL]) ? metaProps[META_PROP_VERTICAL]
: !isUndefined(metaProps[META_PROP_ALL]) ? metaProps[META_PROP_ALL]
: 0;
#define DEFINE_PROCESS_META_PROPS(type) \
static void RCTProcessMetaProps##type(const float metaProps[META_PROP_COUNT], CSSNodeRef node) { \
if (!isUndefined(metaProps[META_PROP_LEFT])) { \
CSSNodeStyleSet##type##Left(node, metaProps[META_PROP_LEFT]); \
} else if (!isUndefined(metaProps[META_PROP_HORIZONTAL])) { \
CSSNodeStyleSet##type##Left(node, metaProps[META_PROP_HORIZONTAL]); \
} else if (!isUndefined(metaProps[META_PROP_ALL])) { \
CSSNodeStyleSet##type##Left(node, metaProps[META_PROP_ALL]); \
} else { \
CSSNodeStyleSet##type##Left(node, 0); \
} \
\
if (!isUndefined(metaProps[META_PROP_RIGHT])) { \
CSSNodeStyleSet##type##Right(node, metaProps[META_PROP_RIGHT]); \
} else if (!isUndefined(metaProps[META_PROP_HORIZONTAL])) { \
CSSNodeStyleSet##type##Right(node, metaProps[META_PROP_HORIZONTAL]); \
} else if (!isUndefined(metaProps[META_PROP_ALL])) { \
CSSNodeStyleSet##type##Right(node, metaProps[META_PROP_ALL]); \
} else { \
CSSNodeStyleSet##type##Right(node, 0); \
} \
\
if (!isUndefined(metaProps[META_PROP_TOP])) { \
CSSNodeStyleSet##type##Top(node, metaProps[META_PROP_TOP]); \
} else if (!isUndefined(metaProps[META_PROP_VERTICAL])) { \
CSSNodeStyleSet##type##Top(node, metaProps[META_PROP_VERTICAL]); \
} else if (!isUndefined(metaProps[META_PROP_ALL])) { \
CSSNodeStyleSet##type##Top(node, metaProps[META_PROP_ALL]); \
} else { \
CSSNodeStyleSet##type##Top(node, 0); \
} \
\
if (!isUndefined(metaProps[META_PROP_BOTTOM])) { \
CSSNodeStyleSet##type##Bottom(node, metaProps[META_PROP_BOTTOM]); \
} else if (!isUndefined(metaProps[META_PROP_VERTICAL])) { \
CSSNodeStyleSet##type##Bottom(node, metaProps[META_PROP_VERTICAL]); \
} else if (!isUndefined(metaProps[META_PROP_ALL])) { \
CSSNodeStyleSet##type##Bottom(node, metaProps[META_PROP_ALL]); \
} else { \
CSSNodeStyleSet##type##Bottom(node, 0); \
} \
}
DEFINE_PROCESS_META_PROPS(Padding);
DEFINE_PROCESS_META_PROPS(Margin);
DEFINE_PROCESS_META_PROPS(Border);
// The absolute stuff is so that we can take into account our absolute position when rounding in order to
// snap to the pixel grid. For example, say you have the following structure:
//
@ -118,29 +146,29 @@ static void RCTProcessMetaProps(const float metaProps[META_PROP_COUNT], float st
// width = 213.5 - 106.5 = 107
// You'll notice that this is the same width we calculated for the parent view because we've taken its position into account.
- (void)applyLayoutNode:(CSSNode *)node
- (void)applyLayoutNode:(CSSNodeRef)node
viewsWithNewFrame:(NSMutableSet<RCTShadowView *> *)viewsWithNewFrame
absolutePosition:(CGPoint)absolutePosition
{
if (!node->layout.shouldUpdate) {
if (!CSSNodeGetShouldUpdate(node)) {
return;
}
node->layout.shouldUpdate = false;
CSSNodeSetShouldUpdate(node, false);
_layoutLifecycle = RCTUpdateLifecycleComputed;
CGPoint absoluteTopLeft = {
absolutePosition.x + node->layout.position[CSSPositionLeft],
absolutePosition.y + node->layout.position[CSSPositionTop]
absolutePosition.x + CSSNodeLayoutGetLeft(node),
absolutePosition.y + CSSNodeLayoutGetTop(node)
};
CGPoint absoluteBottomRight = {
absolutePosition.x + node->layout.position[CSSPositionLeft] + node->layout.dimensions[CSSDimensionWidth],
absolutePosition.y + node->layout.position[CSSPositionTop] + node->layout.dimensions[CSSDimensionHeight]
absolutePosition.x + CSSNodeLayoutGetLeft(node) + CSSNodeLayoutGetWidth(node),
absolutePosition.y + CSSNodeLayoutGetTop(node) + CSSNodeLayoutGetHeight(node)
};
CGRect frame = {{
RCTRoundPixelValue(node->layout.position[CSSPositionLeft]),
RCTRoundPixelValue(node->layout.position[CSSPositionTop]),
RCTRoundPixelValue(CSSNodeLayoutGetLeft(node)),
RCTRoundPixelValue(CSSNodeLayoutGetTop(node)),
}, {
RCTRoundPixelValue(absoluteBottomRight.x - absoluteTopLeft.x),
RCTRoundPixelValue(absoluteBottomRight.y - absoluteTopLeft.y)
@ -151,19 +179,19 @@ static void RCTProcessMetaProps(const float metaProps[META_PROP_COUNT], float st
[viewsWithNewFrame addObject:self];
}
absolutePosition.x += node->layout.position[CSSPositionLeft];
absolutePosition.y += node->layout.position[CSSPositionTop];
absolutePosition.x += CSSNodeLayoutGetLeft(node);
absolutePosition.y += CSSNodeLayoutGetTop(node);
[self applyLayoutToChildren:node viewsWithNewFrame:viewsWithNewFrame absolutePosition:absolutePosition];
}
- (void)applyLayoutToChildren:(CSSNode *)node
- (void)applyLayoutToChildren:(CSSNodeRef)node
viewsWithNewFrame:(NSMutableSet<RCTShadowView *> *)viewsWithNewFrame
absolutePosition:(CGPoint)absolutePosition
{
for (int i = 0; i < node->childCount; ++i) {
for (int i = 0; i < CSSNodeGetChildCount(node); ++i) {
RCTShadowView *child = (RCTShadowView *)_reactSubviews[i];
[child applyLayoutNode:node->getChild(node->context, i)
[child applyLayoutNode:RCTGetChild(CSSNodeGetContext(node), i)
viewsWithNewFrame:viewsWithNewFrame
absolutePosition:absolutePosition];
}
@ -237,18 +265,19 @@ static void RCTProcessMetaProps(const float metaProps[META_PROP_COUNT], float st
}
if (!CGRectEqualToRect(frame, _frame)) {
_cssNode->style.positionType = CSSPositionTypeAbsolute;
_cssNode->style.dimensions[CSSDimensionWidth] = frame.size.width;
_cssNode->style.dimensions[CSSDimensionHeight] = frame.size.height;
_cssNode->style.position[CSSPositionLeft] = frame.origin.x;
_cssNode->style.position[CSSPositionTop] = frame.origin.y;
CSSNodeStyleSetPositionType(_cssNode, CSSPositionTypeAbsolute);
CSSNodeStyleSetWidth(_cssNode, frame.size.width);
CSSNodeStyleSetHeight(_cssNode, frame.size.height);
CSSNodeStyleSetPositionLeft(_cssNode, frame.origin.x);
CSSNodeStyleSetPositionTop(_cssNode, frame.origin.y);
// Our parent has asked us to change our cssNode->styles. Dirty the layout
// so that we can rerun layout on this node. The request came from our parent
// so there's no need to dirty our ancestors by calling dirtyLayout.
_layoutLifecycle = RCTUpdateLifecycleDirtied;
}
layoutNode(_cssNode, frame.size.width, frame.size.height, CSSDirectionInherit);
CSSNodeCalculateLayout(_cssNode, frame.size.width, frame.size.height, CSSDirectionInherit);
[self applyLayoutNode:_cssNode viewsWithNewFrame:viewsWithNewFrame absolutePosition:absolutePosition];
}
@ -289,10 +318,10 @@ static void RCTProcessMetaProps(const float metaProps[META_PROP_COUNT], float st
_reactSubviews = [NSMutableArray array];
_cssNode = CSSNodeNew();
_cssNode->context = (__bridge void *)self;
_cssNode->print = RCTPrint;
_cssNode->getChild = RCTGetChild;
_cssNode->isDirty = RCTIsDirty;
CSSNodeSetContext(_cssNode, (__bridge void *)self);
CSSNodeSetChildFunc(_cssNode, RCTGetChild);
CSSNodeSetPrintFunc(_cssNode, RCTPrint);
CSSNodeSetIsDirtyFunc(_cssNode, RCTIsDirty);
}
return self;
}
@ -359,7 +388,7 @@ static void RCTProcessMetaProps(const float metaProps[META_PROP_COUNT], float st
- (void)insertReactSubview:(RCTShadowView *)subview atIndex:(NSInteger)atIndex
{
[_reactSubviews insertObject:subview atIndex:atIndex];
_cssNode->childCount = [self isCSSLeafNode] ? 0 : (int)_reactSubviews.count;
CSSNodeSetChildCount(_cssNode, [self isCSSLeafNode] ? 0 : (int)_reactSubviews.count);
subview->_superview = self;
_didUpdateSubviews = YES;
[self dirtyText];
@ -375,7 +404,7 @@ static void RCTProcessMetaProps(const float metaProps[META_PROP_COUNT], float st
_didUpdateSubviews = YES;
subview->_superview = nil;
[_reactSubviews removeObject:subview];
_cssNode->childCount = [self isCSSLeafNode] ? 0 : (int)_reactSubviews.count;
CSSNodeSetChildCount(_cssNode, [self isCSSLeafNode] ? 0 : (int)_reactSubviews.count);
}
- (NSArray<RCTShadowView *> *)reactSubviews
@ -475,10 +504,10 @@ RCT_PADDING_PROPERTY(Right, RIGHT)
- (UIEdgeInsets)paddingAsInsets
{
return (UIEdgeInsets){
_cssNode->style.padding[CSSPositionTop],
_cssNode->style.padding[CSSPositionLeft],
_cssNode->style.padding[CSSPositionBottom],
_cssNode->style.padding[CSSPositionRight]
CSSNodeStyleGetPaddingTop(_cssNode),
CSSNodeStyleGetPaddingLeft(_cssNode),
CSSNodeStyleGetPaddingBottom(_cssNode),
CSSNodeStyleGetPaddingRight(_cssNode)
};
}
@ -504,58 +533,66 @@ RCT_BORDER_PROPERTY(Right, RIGHT)
// Dimensions
#define RCT_DIMENSION_PROPERTY(setProp, getProp, cssProp, category) \
#define RCT_DIMENSION_PROPERTY(setProp, getProp, cssProp) \
- (void)set##setProp:(CGFloat)value \
{ \
_cssNode->style.category[CSS##cssProp] = value; \
CSSNodeStyleSet##cssProp(_cssNode, value); \
[self dirtyLayout]; \
[self dirtyText]; \
} \
- (CGFloat)getProp \
{ \
return _cssNode->style.category[CSS##cssProp]; \
return CSSNodeStyleGet##cssProp(_cssNode); \
}
RCT_DIMENSION_PROPERTY(Width, width, DimensionWidth, dimensions)
RCT_DIMENSION_PROPERTY(Height, height, DimensionHeight, dimensions)
RCT_DIMENSION_PROPERTY(MinWidth, minWidth, DimensionWidth, minDimensions)
RCT_DIMENSION_PROPERTY(MaxWidth, maxWidth, DimensionWidth, maxDimensions)
RCT_DIMENSION_PROPERTY(MinHeight, minHeight, DimensionHeight, minDimensions)
RCT_DIMENSION_PROPERTY(MaxHeight, maxHeight, DimensionHeight, maxDimensions)
RCT_DIMENSION_PROPERTY(Width, width, Width)
RCT_DIMENSION_PROPERTY(Height, height, Height)
RCT_DIMENSION_PROPERTY(MinWidth, minWidth, MinWidth)
RCT_DIMENSION_PROPERTY(MinHeight, minHeight, MinHeight)
RCT_DIMENSION_PROPERTY(MaxWidth, maxWidth, MaxWidth)
RCT_DIMENSION_PROPERTY(MaxHeight, maxHeight, MaxHeight)
// Position
#define RCT_POSITION_PROPERTY(setProp, getProp, cssProp) \
RCT_DIMENSION_PROPERTY(setProp, getProp, cssProp, position)
RCT_POSITION_PROPERTY(Top, top, PositionTop)
RCT_POSITION_PROPERTY(Right, right, PositionRight)
RCT_POSITION_PROPERTY(Bottom, bottom, PositionBottom)
RCT_POSITION_PROPERTY(Left, left, PositionLeft)
RCT_DIMENSION_PROPERTY(Top, top, PositionTop)
RCT_DIMENSION_PROPERTY(Right, right, PositionRight)
RCT_DIMENSION_PROPERTY(Bottom, bottom, PositionBottom)
RCT_DIMENSION_PROPERTY(Left, left, PositionLeft)
- (void)setFrame:(CGRect)frame
{
_cssNode->style.position[CSSPositionLeft] = CGRectGetMinX(frame);
_cssNode->style.position[CSSPositionTop] = CGRectGetMinY(frame);
_cssNode->style.dimensions[CSSDimensionWidth] = CGRectGetWidth(frame);
_cssNode->style.dimensions[CSSDimensionHeight] = CGRectGetHeight(frame);
CSSNodeStyleSetPositionLeft(_cssNode, CGRectGetMinX(frame));
CSSNodeStyleSetPositionTop(_cssNode, CGRectGetMinY(frame));
CSSNodeStyleSetWidth(_cssNode, CGRectGetWidth(frame));
CSSNodeStyleSetHeight(_cssNode, CGRectGetHeight(frame));
[self dirtyLayout];
}
static inline BOOL RCTAssignSuggestedDimension(CSSNode *cssNode, int dimension, CGFloat amount)
static inline BOOL RCTAssignSuggestedDimension(CSSNodeRef cssNode, CSSDimension dimension, CGFloat amount)
{
if (amount != UIViewNoIntrinsicMetric
&& isnan(cssNode->style.dimensions[dimension])) {
cssNode->style.dimensions[dimension] = amount;
return YES;
if (amount != UIViewNoIntrinsicMetric) {
switch (dimension) {
case CSSDimensionWidth:
if (isnan(CSSNodeStyleGetWidth(cssNode))) {
CSSNodeStyleSetWidth(cssNode, amount);
return YES;
}
break;
case CSSDimensionHeight:
if (isnan(CSSNodeStyleGetHeight(cssNode))) {
CSSNodeStyleSetHeight(cssNode, amount);
return YES;
}
break;
}
}
return NO;
}
- (void)setIntrinsicContentSize:(CGSize)size
{
if (_cssNode->style.flex == 0) {
if (CSSNodeStyleGetFlex(_cssNode) == 0) {
BOOL dirty = NO;
dirty |= RCTAssignSuggestedDimension(_cssNode, CSSDimensionHeight, size.height);
dirty |= RCTAssignSuggestedDimension(_cssNode, CSSDimensionWidth, size.width);
@ -567,15 +604,15 @@ static inline BOOL RCTAssignSuggestedDimension(CSSNode *cssNode, int dimension,
- (void)setTopLeft:(CGPoint)topLeft
{
_cssNode->style.position[CSSPositionLeft] = topLeft.x;
_cssNode->style.position[CSSPositionTop] = topLeft.y;
CSSNodeStyleSetPositionLeft(_cssNode, topLeft.x);
CSSNodeStyleSetPositionTop(_cssNode, topLeft.y);
[self dirtyLayout];
}
- (void)setSize:(CGSize)size
{
_cssNode->style.dimensions[CSSDimensionWidth] = size.width;
_cssNode->style.dimensions[CSSDimensionHeight] = size.height;
CSSNodeStyleSetWidth(_cssNode, size.width);
CSSNodeStyleSetHeight(_cssNode, size.height);
[self dirtyLayout];
}
@ -584,21 +621,21 @@ static inline BOOL RCTAssignSuggestedDimension(CSSNode *cssNode, int dimension,
#define RCT_STYLE_PROPERTY(setProp, getProp, cssProp, type) \
- (void)set##setProp:(type)value \
{ \
_cssNode->style.cssProp = value; \
CSSNodeStyleSet##cssProp(_cssNode, value); \
[self dirtyLayout]; \
} \
- (type)getProp \
{ \
return _cssNode->style.cssProp; \
return CSSNodeStyleGet##cssProp(_cssNode); \
}
RCT_STYLE_PROPERTY(Flex, flex, flex, CGFloat)
RCT_STYLE_PROPERTY(FlexDirection, flexDirection, flexDirection, CSSFlexDirection)
RCT_STYLE_PROPERTY(JustifyContent, justifyContent, justifyContent, CSSJustify)
RCT_STYLE_PROPERTY(AlignSelf, alignSelf, alignSelf, CSSAlign)
RCT_STYLE_PROPERTY(AlignItems, alignItems, alignItems, CSSAlign)
RCT_STYLE_PROPERTY(Position, position, positionType, CSSPositionType)
RCT_STYLE_PROPERTY(FlexWrap, flexWrap, flexWrap, CSSWrapType)
RCT_STYLE_PROPERTY(Flex, flex, Flex, CGFloat)
RCT_STYLE_PROPERTY(FlexDirection, flexDirection, FlexDirection, CSSFlexDirection)
RCT_STYLE_PROPERTY(JustifyContent, justifyContent, JustifyContent, CSSJustify)
RCT_STYLE_PROPERTY(AlignSelf, alignSelf, AlignSelf, CSSAlign)
RCT_STYLE_PROPERTY(AlignItems, alignItems, AlignItems, CSSAlign)
RCT_STYLE_PROPERTY(Position, position, PositionType, CSSPositionType)
RCT_STYLE_PROPERTY(FlexWrap, flexWrap, FlexWrap, CSSWrapType)
- (void)setBackgroundColor:(UIColor *)color
{
@ -624,13 +661,13 @@ RCT_STYLE_PROPERTY(FlexWrap, flexWrap, flexWrap, CSSWrapType)
- (void)didSetProps:(__unused NSArray<NSString *> *)changedProps
{
if (_recomputePadding) {
RCTProcessMetaProps(_paddingMetaProps, _cssNode->style.padding);
RCTProcessMetaPropsPadding(_paddingMetaProps, _cssNode);
}
if (_recomputeMargin) {
RCTProcessMetaProps(_marginMetaProps, _cssNode->style.margin);
RCTProcessMetaPropsMargin(_marginMetaProps, _cssNode);
}
if (_recomputeBorder) {
RCTProcessMetaProps(_borderMetaProps, _cssNode->style.border);
RCTProcessMetaPropsBorder(_borderMetaProps, _cssNode);
}
if (_recomputePadding || _recomputeMargin || _recomputeBorder) {
[self dirtyLayout];