Add support for measure mode

This commit is contained in:
Emil Sjolander
2016-01-06 16:56:56 +00:00
parent 68e0b0cc58
commit 7bd6b2b7dd
26 changed files with 237 additions and 45 deletions

9
TestResult.xml Normal file
View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<!--This file represents the results of running a test suite-->
<test-results name="src/csharp/Facebook.CSSLayout.Tests/bin/Release/Facebook.CSSLayout.Tests.dll" total="0" failures="0" not-run="0" date="2016-04-01" time="11:01:04">
<environment nunit-version="2.4.8.0" clr-version="4.0.30319.17020" os-version="Unix 15.4.0.0" platform="Unix" cwd="/Users/emilsj/css-layout" machine-name="emilsj-pro" user="emilsj" user-domain="emilsj-pro" />
<culture-info current-culture="en-US" current-uiculture="en-US" />
<test-suite name="src/csharp/Facebook.CSSLayout.Tests/bin/Release/Facebook.CSSLayout.Tests.dll" success="True" time="0.001" asserts="0">
<results />
</test-suite>
</test-results>

30
dist/css-layout.h vendored
View File

@@ -80,6 +80,12 @@ typedef enum {
CSS_POSITION_COUNT
} css_position_t;
typedef enum {
CSS_MEASURE_MODE_UNDEFINED = 0,
CSS_MEASURE_MODE_EXACTLY,
CSS_MEASURE_MODE_AT_MOST
} css_measure_mode_t;
typedef enum {
CSS_WIDTH = 0,
CSS_HEIGHT
@@ -144,7 +150,7 @@ struct css_node {
css_node_t *next_absolute_child;
css_node_t *next_flex_child;
css_dim_t (*measure)(void *context, float width, float height);
css_dim_t (*measure)(void *context, float width, css_measure_mode_t widthMode, float height, css_measure_mode_t heightMode);
void (*print)(void *context);
struct css_node* (*get_child)(void *context, int i);
bool (*is_dirty)(void *context);
@@ -734,26 +740,40 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth, float parentM
bool isResolvedRowDimDefined = isLayoutDimDefined(node, resolvedRowAxis);
float width = CSS_UNDEFINED;
css_measure_mode_t widthMode = CSS_MEASURE_MODE_UNDEFINED;
if (isStyleDimDefined(node, resolvedRowAxis)) {
width = node->style.dimensions[CSS_WIDTH];
widthMode = CSS_MEASURE_MODE_EXACTLY;
} else if (isResolvedRowDimDefined) {
width = node->layout.dimensions[dim[resolvedRowAxis]];
widthMode = CSS_MEASURE_MODE_EXACTLY;
} else {
width = parentMaxWidth -
getMarginAxis(node, resolvedRowAxis);
widthMode = CSS_MEASURE_MODE_AT_MOST;
}
width -= paddingAndBorderAxisResolvedRow;
if (isUndefined(width)) {
widthMode = CSS_MEASURE_MODE_UNDEFINED;
}
float height = CSS_UNDEFINED;
css_measure_mode_t heightMode = CSS_MEASURE_MODE_UNDEFINED;
if (isStyleDimDefined(node, CSS_FLEX_DIRECTION_COLUMN)) {
height = node->style.dimensions[CSS_HEIGHT];
heightMode = CSS_MEASURE_MODE_EXACTLY;
} else if (isLayoutDimDefined(node, CSS_FLEX_DIRECTION_COLUMN)) {
height = node->layout.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]];
heightMode = CSS_MEASURE_MODE_EXACTLY;
} else {
height = parentMaxHeight -
getMarginAxis(node, resolvedRowAxis);
heightMode = CSS_MEASURE_MODE_AT_MOST;
}
height -= getPaddingAndBorderAxis(node, CSS_FLEX_DIRECTION_COLUMN);
if (isUndefined(height)) {
heightMode = CSS_MEASURE_MODE_UNDEFINED;
}
// We only need to give a dimension for the text if we haven't got any
// for it computed yet. It can either be from the style attribute or because
@@ -768,7 +788,9 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth, float parentM
node->context,
width,
height
widthMode,
height,
heightMode
);
if (isRowUndefined) {
node->layout.dimensions[CSS_WIDTH] = measureDim.dimensions[CSS_WIDTH] +
@@ -1447,8 +1469,8 @@ void layoutNode(css_node_t *node, float parentMaxWidth, float parentMaxHeight, c
!node->is_dirty(node->context) &&
eq(layout->last_requested_dimensions[CSS_WIDTH], layout->dimensions[CSS_WIDTH]) &&
eq(layout->last_requested_dimensions[CSS_HEIGHT], layout->dimensions[CSS_HEIGHT]) &&
eq(layout->last_parent_max_width, parentMaxWidth);
eq(layout->last_parent_max_height, parentMaxHeight);
eq(layout->last_parent_max_width, parentMaxWidth) &&
eq(layout->last_parent_max_height, parentMaxHeight) &&
eq(layout->last_direction, direction);
if (skipLayout) {

BIN
dist/css-layout.jar vendored

Binary file not shown.

24
dist/css-layout.js vendored
View File

@@ -53,6 +53,10 @@ var computeLayout = (function() {
var CSS_POSITION_RELATIVE = 'relative';
var CSS_POSITION_ABSOLUTE = 'absolute';
var CSS_MEASURE_MODE_UNDEFINED = 'undefined';
var CSS_MEASURE_MODE_EXACTLY = 'exactly';
var CSS_MEASURE_MODE_AT_MOST = 'at-most';
var leading = {
'row': 'left',
'row-reverse': 'right',
@@ -110,7 +114,7 @@ var computeLayout = (function() {
}
function isUndefined(value) {
return value === undefined;
return value === undefined || isNaN(value);
}
function isRowDirection(flexDirection) {
@@ -501,26 +505,40 @@ var computeLayout = (function() {
var/*bool*/ isResolvedRowDimDefined = isLayoutDimDefined(node, resolvedRowAxis);
var/*float*/ width = CSS_UNDEFINED;
var/*css_measure_mode_t*/ widthMode = CSS_MEASURE_MODE_UNDEFINED;
if (isStyleDimDefined(node, resolvedRowAxis)) {
width = node.style.width;
widthMode = CSS_MEASURE_MODE_EXACTLY;
} else if (isResolvedRowDimDefined) {
width = node.layout[dim[resolvedRowAxis]];
widthMode = CSS_MEASURE_MODE_EXACTLY;
} else {
width = parentMaxWidth -
getMarginAxis(node, resolvedRowAxis);
widthMode = CSS_MEASURE_MODE_AT_MOST;
}
width -= paddingAndBorderAxisResolvedRow;
if (isUndefined(width)) {
widthMode = CSS_MEASURE_MODE_UNDEFINED;
}
var/*float*/ height = CSS_UNDEFINED;
var/*css_measure_mode_t*/ heightMode = CSS_MEASURE_MODE_UNDEFINED;
if (isStyleDimDefined(node, CSS_FLEX_DIRECTION_COLUMN)) {
height = node.style.height;
heightMode = CSS_MEASURE_MODE_EXACTLY;
} else if (isLayoutDimDefined(node, CSS_FLEX_DIRECTION_COLUMN)) {
height = node.layout[dim[CSS_FLEX_DIRECTION_COLUMN]];
heightMode = CSS_MEASURE_MODE_EXACTLY;
} else {
height = parentMaxHeight -
getMarginAxis(node, resolvedRowAxis);
heightMode = CSS_MEASURE_MODE_AT_MOST;
}
height -= getPaddingAndBorderAxis(node, CSS_FLEX_DIRECTION_COLUMN);
if (isUndefined(height)) {
heightMode = CSS_MEASURE_MODE_UNDEFINED;
}
// We only need to give a dimension for the text if we haven't got any
// for it computed yet. It can either be from the style attribute or because
@@ -535,7 +553,9 @@ var computeLayout = (function() {
/*(c)!node->context,*/
/*(java)!layoutContext.measureOutput,*/
width,
height
widthMode,
height,
heightMode
);
if (isRowUndefined) {
node.layout.width = measureDim.width +

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -11,12 +11,14 @@ function __transpileToCSharpCommon(code) {
return code
.replace(/CSS_UNDEFINED/g, 'CSSConstants.UNDEFINED')
.replace(/CSS_JUSTIFY_/g, 'CSSJustify.')
.replace(/CSS_MEASURE_MODE_/g, 'CSSMeasureMode.')
.replace(/CSS_ALIGN_/g, 'CSSAlign.')
.replace(/CSS_POSITION_/g, 'CSSPositionType.')
.replace(/css_flex_direction_t/g, 'CSSFlexDirection')
.replace(/css_direction_t/g, 'CSSDirection')
.replace(/css_align_t/g, 'CSSAlign')
.replace(/css_justify_t/g, 'CSSJustify')
.replace(/css_measure_mode_t/g, 'CSSMeasureMode')
.replace(/css_dim_t/g, 'MeasureOutput')
.replace(/bool/g, 'boolean')
.replace(/style\[dim/g, 'style.dimensions[dim')
@@ -56,7 +58,7 @@ function __transpileToCSharpCommon(code) {
// additional case conversions
.replace(/(CSSConstants|CSSWrap|CSSJustify|CSSAlign|CSSPositionType)\.([_A-Z]+)/g,
.replace(/(CSSConstants|CSSWrap|CSSJustify|CSSMeasureMode|CSSAlign|CSSPositionType)\.([_A-Z]+)/g,
function(str, match1, match2) {
return match1 + '.' + constantToPascalCase(match2);
});

View File

@@ -11,12 +11,14 @@ function __transpileToJavaCommon(code) {
return code
.replace(/CSS_UNDEFINED/g, 'CSSConstants.UNDEFINED')
.replace(/CSS_JUSTIFY_/g, 'CSSJustify.')
.replace(/CSS_MEASURE_MODE_/g, 'CSSMeasureMode.')
.replace(/CSS_ALIGN_/g, 'CSSAlign.')
.replace(/CSS_POSITION_/g, 'CSSPositionType.')
.replace(/css_flex_direction_t/g, 'CSSFlexDirection')
.replace(/css_direction_t/g, 'CSSDirection')
.replace(/css_align_t/g, 'CSSAlign')
.replace(/css_justify_t/g, 'CSSJustify')
.replace(/css_measure_mode_t/g, 'CSSMeasureMode')
.replace(/css_dim_t/g, 'MeasureOutput')
.replace(/bool/g, 'boolean')
.replace(/style\[dim/g, 'style.dimensions[dim')

View File

@@ -82,11 +82,11 @@ static bool are_layout_equal(css_node_t *a, css_node_t *b) {
return true;
}
css_dim_t measure(void *context, float width, float height) {
css_dim_t measure(void *context, float width, css_measure_mode_t widthMode, float height, css_measure_mode_t heightMode) {
const char *text = (const char *)context;
css_dim_t dim;
if (strcmp(text, SMALL_TEXT) == 0) {
if (width != width) {
if (widthMode == CSS_MEASURE_MODE_UNDEFINED) {
width = 1000000;
}
dim.dimensions[CSS_WIDTH] = fminf(SMALL_WIDTH, width);
@@ -94,7 +94,7 @@ css_dim_t measure(void *context, float width, float height) {
return dim;
}
if (strcmp(text, LONG_TEXT) == 0) {
if (width != width) {
if (widthMode == CSS_MEASURE_MODE_UNDEFINED) {
width = 1000000;
}
dim.dimensions[CSS_WIDTH] = width >= BIG_WIDTH ? BIG_WIDTH : fmaxf(BIG_MIN_WIDTH, width);
@@ -103,10 +103,10 @@ css_dim_t measure(void *context, float width, float height) {
}
if (strcmp(text, MEASURE_WITH_RATIO_2) == 0) {
if (width > 0) {
if (widthMode != CSS_MEASURE_MODE_UNDEFINED) {
dim.dimensions[CSS_WIDTH] = width;
dim.dimensions[CSS_HEIGHT] = width * 2;
} else if (height > 0) {
} else if (heightMode != CSS_MEASURE_MODE_UNDEFINED) {
dim.dimensions[CSS_WIDTH] = height * 2;
dim.dimensions[CSS_HEIGHT] = height;
} else {
@@ -117,6 +117,12 @@ css_dim_t measure(void *context, float width, float height) {
}
if (strcmp(text, MEASURE_WITH_MATCH_PARENT) == 0) {
if (widthMode == CSS_MEASURE_MODE_UNDEFINED) {
width = 99999;
}
if (heightMode == CSS_MEASURE_MODE_UNDEFINED) {
height = 99999;
}
dim.dimensions[CSS_WIDTH] = width;
dim.dimensions[CSS_HEIGHT] = height;
return dim;

View File

@@ -13,6 +13,6 @@
void test(const char *name, css_node_t *style, css_node_t *expected_layout);
int tests_finished(void);
css_dim_t measure(void *context, float width, float height);
css_dim_t measure(void *context, float width, css_measure_mode_t widthMode, float height, css_measure_mode_t heightMode);
void init_css_node_children(css_node_t *node, int children_count);
css_node_t *new_test_css_node(void);

View File

@@ -494,8 +494,8 @@ var layoutTestUtils = (function() {
computeDOMLayout: computeDOMLayout,
reduceTest: reduceTest,
text: function(text) {
var fn = function(width, height) {
if (width === undefined || isNaN(width)) {
var fn = function(width, widthMode, height, heightMode) {
if (widthMode === 'undefined') {
width = Infinity;
}
@@ -522,10 +522,10 @@ var layoutTestUtils = (function() {
return fn;
},
measureWithRatio2: function() {
var fn = function(width, height) {
if (width > 0) {
var fn = function(width, widthMode, height, heightMode) {
if (widthMode !== 'undefined') {
height = width * 2;
} else if (height > 0) {
} else if (heightMode !== 'undefined') {
width = height * 2;
} else {
// This should be Infinity, but it would be pain to transpile,
@@ -540,7 +540,13 @@ var layoutTestUtils = (function() {
return fn;
},
measureWithMatchParent: function() {
var fn = function(width, height) {
var fn = function(width, widthMode, height, heightMode) {
if (widthMode === 'undefined') {
width = 99999;
}
if (heightMode === 'undefined') {
height = 99999;
}
return {width: width, height: height};
};
// This is necessary for transpiled tests, see previous comment

View File

@@ -557,26 +557,40 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth, float parentM
bool isResolvedRowDimDefined = isLayoutDimDefined(node, resolvedRowAxis);
float width = CSS_UNDEFINED;
css_measure_mode_t widthMode = CSS_MEASURE_MODE_UNDEFINED;
if (isStyleDimDefined(node, resolvedRowAxis)) {
width = node->style.dimensions[CSS_WIDTH];
widthMode = CSS_MEASURE_MODE_EXACTLY;
} else if (isResolvedRowDimDefined) {
width = node->layout.dimensions[dim[resolvedRowAxis]];
widthMode = CSS_MEASURE_MODE_EXACTLY;
} else {
width = parentMaxWidth -
getMarginAxis(node, resolvedRowAxis);
widthMode = CSS_MEASURE_MODE_AT_MOST;
}
width -= paddingAndBorderAxisResolvedRow;
if (isUndefined(width)) {
widthMode = CSS_MEASURE_MODE_UNDEFINED;
}
float height = CSS_UNDEFINED;
css_measure_mode_t heightMode = CSS_MEASURE_MODE_UNDEFINED;
if (isStyleDimDefined(node, CSS_FLEX_DIRECTION_COLUMN)) {
height = node->style.dimensions[CSS_HEIGHT];
heightMode = CSS_MEASURE_MODE_EXACTLY;
} else if (isLayoutDimDefined(node, CSS_FLEX_DIRECTION_COLUMN)) {
height = node->layout.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]];
heightMode = CSS_MEASURE_MODE_EXACTLY;
} else {
height = parentMaxHeight -
getMarginAxis(node, resolvedRowAxis);
heightMode = CSS_MEASURE_MODE_AT_MOST;
}
height -= getPaddingAndBorderAxis(node, CSS_FLEX_DIRECTION_COLUMN);
if (isUndefined(height)) {
heightMode = CSS_MEASURE_MODE_UNDEFINED;
}
// We only need to give a dimension for the text if we haven't got any
// for it computed yet. It can either be from the style attribute or because
@@ -591,7 +605,9 @@ static void layoutNodeImpl(css_node_t *node, float parentMaxWidth, float parentM
node->context,
width,
height
widthMode,
height,
heightMode
);
if (isRowUndefined) {
node->layout.dimensions[CSS_WIDTH] = measureDim.dimensions[CSS_WIDTH] +

View File

@@ -76,6 +76,12 @@ typedef enum {
CSS_POSITION_COUNT
} css_position_t;
typedef enum {
CSS_MEASURE_MODE_UNDEFINED = 0,
CSS_MEASURE_MODE_EXACTLY,
CSS_MEASURE_MODE_AT_MOST
} css_measure_mode_t;
typedef enum {
CSS_WIDTH = 0,
CSS_HEIGHT
@@ -140,7 +146,7 @@ struct css_node {
css_node_t *next_absolute_child;
css_node_t *next_flex_child;
css_dim_t (*measure)(void *context, float width, float height);
css_dim_t (*measure)(void *context, float width, css_measure_mode_t widthMode, float height, css_measure_mode_t heightMode);
void (*print)(void *context);
struct css_node* (*get_child)(void *context, int i);
bool (*is_dirty)(void *context);

View File

@@ -34,6 +34,10 @@ var computeLayout = (function() {
var CSS_POSITION_RELATIVE = 'relative';
var CSS_POSITION_ABSOLUTE = 'absolute';
var CSS_MEASURE_MODE_UNDEFINED = 'undefined';
var CSS_MEASURE_MODE_EXACTLY = 'exactly';
var CSS_MEASURE_MODE_AT_MOST = 'at-most';
var leading = {
'row': 'left',
'row-reverse': 'right',
@@ -91,7 +95,7 @@ var computeLayout = (function() {
}
function isUndefined(value) {
return value === undefined;
return value === undefined || isNaN(value);
}
function isRowDirection(flexDirection) {
@@ -482,26 +486,40 @@ var computeLayout = (function() {
var/*bool*/ isResolvedRowDimDefined = isLayoutDimDefined(node, resolvedRowAxis);
var/*float*/ width = CSS_UNDEFINED;
var/*css_measure_mode_t*/ widthMode = CSS_MEASURE_MODE_UNDEFINED;
if (isStyleDimDefined(node, resolvedRowAxis)) {
width = node.style.width;
widthMode = CSS_MEASURE_MODE_EXACTLY;
} else if (isResolvedRowDimDefined) {
width = node.layout[dim[resolvedRowAxis]];
widthMode = CSS_MEASURE_MODE_EXACTLY;
} else {
width = parentMaxWidth -
getMarginAxis(node, resolvedRowAxis);
widthMode = CSS_MEASURE_MODE_AT_MOST;
}
width -= paddingAndBorderAxisResolvedRow;
if (isUndefined(width)) {
widthMode = CSS_MEASURE_MODE_UNDEFINED;
}
var/*float*/ height = CSS_UNDEFINED;
var/*css_measure_mode_t*/ heightMode = CSS_MEASURE_MODE_UNDEFINED;
if (isStyleDimDefined(node, CSS_FLEX_DIRECTION_COLUMN)) {
height = node.style.height;
heightMode = CSS_MEASURE_MODE_EXACTLY;
} else if (isLayoutDimDefined(node, CSS_FLEX_DIRECTION_COLUMN)) {
height = node.layout[dim[CSS_FLEX_DIRECTION_COLUMN]];
heightMode = CSS_MEASURE_MODE_EXACTLY;
} else {
height = parentMaxHeight -
getMarginAxis(node, resolvedRowAxis);
heightMode = CSS_MEASURE_MODE_AT_MOST;
}
height -= getPaddingAndBorderAxis(node, CSS_FLEX_DIRECTION_COLUMN);
if (isUndefined(height)) {
heightMode = CSS_MEASURE_MODE_UNDEFINED;
}
// We only need to give a dimension for the text if we haven't got any
// for it computed yet. It can either be from the style attribute or because
@@ -516,7 +534,9 @@ var computeLayout = (function() {
/*(c)!node->context,*/
/*(java)!layoutContext.measureOutput,*/
width,
height
widthMode,
height,
heightMode
);
if (isRowUndefined) {
node.layout.width = measureDim.width +

View File

@@ -226,7 +226,7 @@ namespace Facebook.CSSLayout.Tests
root.calculateLayout();
markLayoutAppliedForTree(root);
c1.setMeasureFunction((node, width, height) => new MeasureOutput(100, 20));
c1.setMeasureFunction((node, width, widthMode, height, heightMode) => new MeasureOutput(100, 20));
root.calculateLayout();

View File

@@ -25,11 +25,11 @@ public class LayoutEngineTest
const int DIMENSION_HEIGHT = CSSLayout.DIMENSION_HEIGHT;
const int DIMENSION_WIDTH = CSSLayout.DIMENSION_WIDTH;
static readonly MeasureFunction sTestMeasureFunction = (node, width, height) =>
static readonly MeasureFunction sTestMeasureFunction = (node, width, widthMode, height, heightMode) =>
{
TestCSSNode testNode = (TestCSSNode) node;
if (testNode.context.Equals(TestConstants.SMALL_TEXT)) {
if (CSSConstants.IsUndefined(width)) {
if (widthMode == CSSMeasureMode.Undefined) {
width = 10000000;
}
return new MeasureOutput(
@@ -46,14 +46,20 @@ public class LayoutEngineTest
? TestConstants.SMALL_HEIGHT
: TestConstants.BIG_HEIGHT);
} else if (testNode.context.Equals(TestConstants.MEASURE_WITH_RATIO_2)) {
if (width > 0) {
if (widthMode != CSSMeasureMode.Undefined) {
return new MeasureOutput(width, width * 2);
} else if (height > 0) {
} else if (heightMode != CSSMeasureMode.Undefined) {
return new MeasureOutput(height * 2, height);
} else {
return new MeasureOutput(99999, 99999);
}
} else if (testNode.context.Equals(TestConstants.MEASURE_WITH_MATCH_PARENT)) {
if (widthMode == CSSMeasureMode.Undefined) {
width = 99999;
}
if (heightMode == CSSMeasureMode.Undefined) {
height = 99999;
}
return new MeasureOutput(width, height);
} else {
throw new Exception("Got unknown test: " + testNode.context);

View File

@@ -0,0 +1,18 @@
/**
* Copyright (c) 2014, 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.
*/
namespace Facebook.CSSLayout
{
public enum CSSMeasureMode
{
Undefined,
Exactly,
AtMost,
}
}

View File

@@ -17,7 +17,7 @@ namespace Facebook.CSSLayout
* Should measure the given node and put the result in the given MeasureOutput.
*/
public delegate MeasureOutput MeasureFunction(CSSNode node, float width, float height);
public delegate MeasureOutput MeasureFunction(CSSNode node, float width, CSSMeasureMode widthMode, float height, CSSMeasureMode heightMode);
/**
* A CSS Node. It has a style object you can manipulate at {@link #style}. After calling
@@ -140,13 +140,13 @@ namespace Facebook.CSSLayout
get { return mMeasureFunction != null; }
}
internal MeasureOutput measure(MeasureOutput measureOutput, float width, float height)
internal MeasureOutput measure(MeasureOutput measureOutput, float width, CSSMeasureMode widthMode, float height, CSSMeasureMode heightMode)
{
if (!IsMeasureDefined)
{
throw new Exception("Measure function isn't defined!");
}
return Assertions.assertNotNull(mMeasureFunction)(this, width, height);
return Assertions.assertNotNull(mMeasureFunction)(this, width, widthMode, height, heightMode);
}
/**

View File

@@ -45,6 +45,7 @@
<Compile Include="CSSDirection.cs" />
<Compile Include="CSSFlexDirection.cs" />
<Compile Include="CSSJustify.cs" />
<Compile Include="CSSMeasureMode.cs" />
<Compile Include="CSSLayout.cs" />
<Compile Include="CSSLayoutContext.cs" />
<Compile Include="CSSNode.cs" />
@@ -67,4 +68,4 @@
<Target Name="AfterBuild">
</Target>
-->
</Project>
</Project>

View File

@@ -282,26 +282,40 @@ namespace Facebook.CSSLayout
boolean isResolvedRowDimDefined = (!float.IsNaN(node.layout.dimensions[dim[resolvedRowAxis]]) && node.layout.dimensions[dim[resolvedRowAxis]] >= 0.0);
float width = CSSConstants.Undefined;
CSSMeasureMode widthMode = CSSMeasureMode.Undefined;
if ((!float.IsNaN(node.style.dimensions[dim[resolvedRowAxis]]) && node.style.dimensions[dim[resolvedRowAxis]] >= 0.0)) {
width = node.style.dimensions[DIMENSION_WIDTH];
widthMode = CSSMeasureMode.Exactly;
} else if (isResolvedRowDimDefined) {
width = node.layout.dimensions[dim[resolvedRowAxis]];
widthMode = CSSMeasureMode.Exactly;
} else {
width = parentMaxWidth -
(node.style.margin.getWithFallback(leadingSpacing[resolvedRowAxis], leading[resolvedRowAxis]) + node.style.margin.getWithFallback(trailingSpacing[resolvedRowAxis], trailing[resolvedRowAxis]));
widthMode = CSSMeasureMode.AtMost;
}
width -= paddingAndBorderAxisResolvedRow;
if (float.IsNaN(width)) {
widthMode = CSSMeasureMode.Undefined;
}
float height = CSSConstants.Undefined;
CSSMeasureMode heightMode = CSSMeasureMode.Undefined;
if ((!float.IsNaN(node.style.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]]) && node.style.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]] >= 0.0)) {
height = node.style.dimensions[DIMENSION_HEIGHT];
heightMode = CSSMeasureMode.Exactly;
} else if ((!float.IsNaN(node.layout.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]]) && node.layout.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]] >= 0.0)) {
height = node.layout.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]];
heightMode = CSSMeasureMode.Exactly;
} else {
height = parentMaxHeight -
(node.style.margin.getWithFallback(leadingSpacing[resolvedRowAxis], leading[resolvedRowAxis]) + node.style.margin.getWithFallback(trailingSpacing[resolvedRowAxis], trailing[resolvedRowAxis]));
heightMode = CSSMeasureMode.AtMost;
}
height -= ((node.style.padding.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_COLUMN], leading[CSS_FLEX_DIRECTION_COLUMN]) + node.style.border.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_COLUMN], leading[CSS_FLEX_DIRECTION_COLUMN])) + (node.style.padding.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_COLUMN], trailing[CSS_FLEX_DIRECTION_COLUMN]) + node.style.border.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_COLUMN], trailing[CSS_FLEX_DIRECTION_COLUMN])));
if (float.IsNaN(height)) {
heightMode = CSSMeasureMode.Undefined;
}
// We only need to give a dimension for the text if we haven't got any
// for it computed yet. It can either be from the style attribute or because
@@ -316,7 +330,9 @@ namespace Facebook.CSSLayout
layoutContext.measureOutput,
width,
height
widthMode,
height,
heightMode
);
if (isRowUndefined) {
node.layout.dimensions[DIMENSION_WIDTH] = measureDim.width +

View File

@@ -0,0 +1,15 @@
/**
* Copyright (c) 2014, 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.
*/
package com.facebook.csslayout;
public enum CSSMeasureMode {
UNDEFINED,
EXACTLY,
AT_MOST,
}

View File

@@ -53,7 +53,7 @@ public class CSSNode {
*
* NB: measure is NOT guaranteed to be threadsafe/re-entrant safe!
*/
public void measure(CSSNode node, float width, float height, MeasureOutput measureOutput);
public void measure(CSSNode node, float width, CSSMeasureMode widthMode, float height, CSSMeasureMode heightMode, MeasureOutput measureOutput);
}
// VisibleForTesting
@@ -125,13 +125,13 @@ public class CSSNode {
return mMeasureFunction != null;
}
/*package*/ MeasureOutput measure(MeasureOutput measureOutput, float width, float height) {
/*package*/ MeasureOutput measure(MeasureOutput measureOutput, float width, CSSMeasureMode widthMode, float height, CSSMeasureMode heightMode) {
if (!isMeasureDefined()) {
throw new RuntimeException("Measure function isn't defined!");
}
measureOutput.height = CSSConstants.UNDEFINED;
measureOutput.width = CSSConstants.UNDEFINED;
Assertions.assertNotNull(mMeasureFunction).measure(this, width, height, measureOutput);
Assertions.assertNotNull(mMeasureFunction).measure(this, width, widthMode, height, heightMode, measureOutput);
return measureOutput;
}

View File

@@ -258,26 +258,40 @@ public class LayoutEngine {
boolean isResolvedRowDimDefined = (!Float.isNaN(node.layout.dimensions[dim[resolvedRowAxis]]) && node.layout.dimensions[dim[resolvedRowAxis]] >= 0.0);
float width = CSSConstants.UNDEFINED;
CSSMeasureMode widthMode = CSSMeasureMode.UNDEFINED;
if ((!Float.isNaN(node.style.dimensions[dim[resolvedRowAxis]]) && node.style.dimensions[dim[resolvedRowAxis]] >= 0.0)) {
width = node.style.dimensions[DIMENSION_WIDTH];
widthMode = CSSMeasureMode.EXACTLY;
} else if (isResolvedRowDimDefined) {
width = node.layout.dimensions[dim[resolvedRowAxis]];
widthMode = CSSMeasureMode.EXACTLY;
} else {
width = parentMaxWidth -
(node.style.margin.getWithFallback(leadingSpacing[resolvedRowAxis], leading[resolvedRowAxis]) + node.style.margin.getWithFallback(trailingSpacing[resolvedRowAxis], trailing[resolvedRowAxis]));
widthMode = CSSMeasureMode.AT_MOST;
}
width -= paddingAndBorderAxisResolvedRow;
if (Float.isNaN(width)) {
widthMode = CSSMeasureMode.UNDEFINED;
}
float height = CSSConstants.UNDEFINED;
CSSMeasureMode heightMode = CSSMeasureMode.UNDEFINED;
if ((!Float.isNaN(node.style.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]]) && node.style.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]] >= 0.0)) {
height = node.style.dimensions[DIMENSION_HEIGHT];
heightMode = CSSMeasureMode.EXACTLY;
} else if ((!Float.isNaN(node.layout.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]]) && node.layout.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]] >= 0.0)) {
height = node.layout.dimensions[dim[CSS_FLEX_DIRECTION_COLUMN]];
heightMode = CSSMeasureMode.EXACTLY;
} else {
height = parentMaxHeight -
(node.style.margin.getWithFallback(leadingSpacing[resolvedRowAxis], leading[resolvedRowAxis]) + node.style.margin.getWithFallback(trailingSpacing[resolvedRowAxis], trailing[resolvedRowAxis]));
heightMode = CSSMeasureMode.AT_MOST;
}
height -= ((node.style.padding.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_COLUMN], leading[CSS_FLEX_DIRECTION_COLUMN]) + node.style.border.getWithFallback(leadingSpacing[CSS_FLEX_DIRECTION_COLUMN], leading[CSS_FLEX_DIRECTION_COLUMN])) + (node.style.padding.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_COLUMN], trailing[CSS_FLEX_DIRECTION_COLUMN]) + node.style.border.getWithFallback(trailingSpacing[CSS_FLEX_DIRECTION_COLUMN], trailing[CSS_FLEX_DIRECTION_COLUMN])));
if (Float.isNaN(height)) {
heightMode = CSSMeasureMode.UNDEFINED;
}
// We only need to give a dimension for the text if we haven't got any
// for it computed yet. It can either be from the style attribute or because
@@ -292,7 +306,9 @@ public class LayoutEngine {
layoutContext.measureOutput,
width,
height
widthMode,
height,
heightMode
);
if (isRowUndefined) {
node.layout.dimensions[DIMENSION_WIDTH] = measureDim.width +

View File

@@ -223,7 +223,7 @@ public class LayoutCachingTest {
c1.setMeasureFunction(new CSSNode.MeasureFunction() {
@Override
public void measure(CSSNode node, float width, float height, MeasureOutput measureOutput) {
public void measure(CSSNode node, float width, CSSMeasureMode widthMode, float height, CSSMeasureMode heightMode, MeasureOutput measureOutput) {
measureOutput.width = 100;
measureOutput.height = 20;
}

View File

@@ -27,16 +27,16 @@ public class LayoutEngineTest {
new CSSNode.MeasureFunction() {
@Override
public void measure(CSSNode node, float width, float height, MeasureOutput measureOutput) {
public void measure(CSSNode node, float width, CSSMeasureMode widthMode, float height, CSSMeasureMode heightMode, MeasureOutput measureOutput) {
TestCSSNode testNode = (TestCSSNode) node;
if (testNode.context.equals(TestConstants.SMALL_TEXT)) {
if (CSSConstants.isUndefined(width)) {
if (widthMode == CSSMeasureMode.UNDEFINED) {
width = 10000000;
}
measureOutput.width = Math.min(width, TestConstants.SMALL_WIDTH);
measureOutput.height = TestConstants.SMALL_HEIGHT;
} else if (testNode.context.equals(TestConstants.LONG_TEXT)) {
if (CSSConstants.isUndefined(width)) {
if (widthMode == CSSMeasureMode.UNDEFINED) {
width = 10000000;
}
measureOutput.width = width >= TestConstants.BIG_WIDTH ?
@@ -44,10 +44,10 @@ public class LayoutEngineTest {
measureOutput.height = width >= TestConstants.BIG_WIDTH ?
TestConstants.SMALL_HEIGHT : TestConstants.BIG_HEIGHT;
} else if (testNode.context.equals(TestConstants.MEASURE_WITH_RATIO_2)) {
if (width > 0) {
if (widthMode != CSSMeasureMode.UNDEFINED) {
measureOutput.width = width;
measureOutput.height = width * 2;
} else if (height > 0) {
} else if (heightMode != CSSMeasureMode.UNDEFINED) {
measureOutput.width = height * 2;
measureOutput.height = height;
} else {
@@ -55,6 +55,12 @@ public class LayoutEngineTest {
measureOutput.height = 99999;
}
} else if (testNode.context.equals(TestConstants.MEASURE_WITH_MATCH_PARENT)) {
if (widthMode == CSSMeasureMode.UNDEFINED) {
width = 99999;
}
if (heightMode == CSSMeasureMode.UNDEFINED) {
height = 99999;
}
measureOutput.width = width;
measureOutput.height = height;
} else {

View File

@@ -170,6 +170,11 @@ function printLayout(test) {
'nowrap': 'CSS_NOWRAP',
'wrap': 'CSS_WRAP'
});
addEnum(node, 'measureMode', 'measure_mode', {
'undefined': 'CSS_MEASURE_MODE_UNDEFINED',
'exactly': 'CSS_MEASURE_MODE_EXACTLY',
'at-most': 'CSS_MEASURE_MODE_AT_MOST'
});
addFloat(node, 'flex', 'flex');
addFloat(node, 'width', 'dimensions[CSS_WIDTH]');
addFloat(node, 'height', 'dimensions[CSS_HEIGHT]');