2014-10-29 08:01:22 -07:00
|
|
|
/**
|
|
|
|
* 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.
|
|
|
|
*/
|
2015-08-11 16:52:57 +01:00
|
|
|
/* globals document, computeLayout, navigator */
|
2014-04-18 16:35:37 -07:00
|
|
|
|
|
|
|
var layoutTestUtils = (function() {
|
2014-12-11 13:30:46 +00:00
|
|
|
|
2015-05-08 14:51:05 +08:00
|
|
|
//
|
|
|
|
// Sets the test cases precision, by default set to 1.0, aka pixel precision
|
|
|
|
// (assuming the browser does pixel snapping - and that we're ok with being
|
|
|
|
// 'only' pixel perfect).
|
|
|
|
//
|
|
|
|
// Set it to '10' for .1 precision, etc... in theory the browser is doing
|
|
|
|
// 'pixel' snapping so 1.0 should do, the code is left for clarity...
|
|
|
|
//
|
|
|
|
// Set it to undefined to disable and use full precision.
|
|
|
|
//
|
|
|
|
var testMeasurePrecision = 1.0;
|
|
|
|
|
2014-12-11 20:23:53 +00:00
|
|
|
if (typeof jasmine !== 'undefined') {
|
2015-10-07 21:52:22 +01:00
|
|
|
jasmine.matchersUtil.buildFailureMessage = function() {
|
|
|
|
var args = Array.prototype.slice.call(arguments, 0);
|
|
|
|
var matcherName = args[0];
|
|
|
|
var isNot = args[1];
|
|
|
|
var actual = args[2];
|
|
|
|
var expected = args.slice(3);
|
|
|
|
var englishyPredicate = matcherName.replace(/[A-Z]/g, function(s) { return ' ' + s.toLowerCase(); });
|
2014-12-11 20:23:53 +00:00
|
|
|
|
|
|
|
var pp = function(node) {
|
|
|
|
return jasmine.pp(node)
|
|
|
|
.replace(/([\{\[]) /g, '$1')
|
|
|
|
.replace(/ ([\}\]:])/g, '$1');
|
|
|
|
};
|
|
|
|
|
|
|
|
var message = 'Expected ' +
|
|
|
|
pp(actual) +
|
|
|
|
(isNot ? ' not ' : ' ') +
|
|
|
|
'\n' +
|
|
|
|
englishyPredicate;
|
|
|
|
|
|
|
|
if (expected.length > 0) {
|
|
|
|
for (var i = 0; i < expected.length; i++) {
|
|
|
|
if (i > 0) {
|
|
|
|
message += ',';
|
|
|
|
}
|
|
|
|
message += ' ' + pp(expected[i]);
|
2014-12-11 13:30:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-11 20:23:53 +00:00
|
|
|
return message + '.';
|
|
|
|
};
|
|
|
|
}
|
2014-12-11 13:30:46 +00:00
|
|
|
|
2015-02-17 21:12:29 -05:00
|
|
|
var _cachedIframe;
|
|
|
|
|
2015-02-05 17:23:56 +11:00
|
|
|
function renderIframe() {
|
|
|
|
var iframe = document.createElement('iframe');
|
|
|
|
document.body.appendChild(iframe);
|
|
|
|
return iframe;
|
|
|
|
}
|
|
|
|
|
2015-02-17 21:12:29 -05:00
|
|
|
function getIframe(iframe) {
|
|
|
|
if (_cachedIframe) {
|
|
|
|
return _cachedIframe;
|
2014-09-26 16:22:44 -07:00
|
|
|
}
|
2015-02-05 17:23:56 +11:00
|
|
|
|
2014-04-18 16:35:37 -07:00
|
|
|
var doc = iframe.contentDocument;
|
|
|
|
|
2015-02-17 21:12:29 -05:00
|
|
|
if (doc.readyState === 'complete') {
|
2015-02-05 17:23:56 +11:00
|
|
|
var style = document.createElement('style');
|
|
|
|
style.textContent = (function() {/*
|
|
|
|
body, div {
|
|
|
|
box-sizing: border-box;
|
|
|
|
border: 0 solid black;
|
|
|
|
position: relative;
|
2014-12-11 13:44:03 +00:00
|
|
|
|
2015-02-05 17:23:56 +11:00
|
|
|
display: flex;
|
|
|
|
display: -webkit-flex;
|
|
|
|
flex-direction: column;
|
|
|
|
-webkit-flex-direction: column;
|
|
|
|
align-items: stretch;
|
|
|
|
-webkit-align-items: stretch;
|
|
|
|
justify-content: flex-start;
|
|
|
|
-webkit-justify-content: flex-start;
|
|
|
|
flex-shrink: 0;
|
|
|
|
-webkit-flex-shrink: 0;
|
|
|
|
|
|
|
|
margin: 0;
|
|
|
|
padding: 0;
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
min-width: 0;
|
2015-02-05 17:23:56 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
hack to ignore three hundred px width of the body {}
|
|
|
|
body > div {
|
|
|
|
align-self: flex-start;
|
|
|
|
}
|
|
|
|
*/} + '').slice(15, -4);
|
|
|
|
doc.head.appendChild(style);
|
2015-02-17 21:12:29 -05:00
|
|
|
_cachedIframe = iframe;
|
2015-02-05 17:23:56 +11:00
|
|
|
return iframe;
|
|
|
|
} else {
|
2015-03-31 20:27:19 -07:00
|
|
|
setTimeout(getIframe.bind(null, iframe), 0);
|
2015-02-05 17:23:56 +11:00
|
|
|
}
|
2014-09-26 16:22:44 -07:00
|
|
|
}
|
2014-04-18 16:35:37 -07:00
|
|
|
|
2015-02-05 17:23:56 +11:00
|
|
|
if (typeof window !== 'undefined') {
|
|
|
|
var iframe = renderIframe();
|
2015-02-17 21:12:29 -05:00
|
|
|
getIframe(iframe);
|
2015-02-05 17:23:56 +11:00
|
|
|
}
|
2014-04-26 19:02:16 -07:00
|
|
|
|
2015-02-07 00:01:35 -05:00
|
|
|
if (typeof computeLayout === 'object') {
|
|
|
|
var fillNodes = computeLayout.fillNodes;
|
|
|
|
var realComputeLayout = computeLayout.computeLayout;
|
2014-09-26 16:22:44 -07:00
|
|
|
}
|
2014-04-26 12:46:21 -07:00
|
|
|
|
2015-08-13 08:39:28 +01:00
|
|
|
function extractNodes(node) {
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
var keysToCopy = [
|
|
|
|
'width',
|
|
|
|
'height',
|
|
|
|
'left',
|
|
|
|
'top'
|
|
|
|
];
|
|
|
|
var layout = {};
|
|
|
|
keysToCopy.forEach(function(key) {
|
|
|
|
layout[key] = node.layout[key];
|
|
|
|
});
|
|
|
|
|
2015-08-13 08:39:28 +01:00
|
|
|
if (node.children && node.children.length > 0) {
|
|
|
|
layout.children = node.children.map(extractNodes);
|
|
|
|
} else {
|
|
|
|
delete node.children;
|
|
|
|
}
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
|
|
|
|
delete node.layout;
|
2015-08-13 08:39:28 +01:00
|
|
|
|
|
|
|
return layout;
|
|
|
|
}
|
|
|
|
|
2014-12-11 16:31:57 +00:00
|
|
|
function roundLayout(layout) {
|
|
|
|
// Chrome rounds all the numbers with a precision of 1/64
|
|
|
|
// Reproduce the same behavior
|
|
|
|
function round(number) {
|
|
|
|
var floored = Math.floor(number);
|
|
|
|
var decimal = number - floored;
|
|
|
|
if (decimal === 0) {
|
|
|
|
return number;
|
|
|
|
}
|
|
|
|
var minDifference = Infinity;
|
|
|
|
var minDecimal = Infinity;
|
|
|
|
for (var i = 1; i < 64; ++i) {
|
|
|
|
var roundedDecimal = i / 64;
|
|
|
|
var difference = Math.abs(roundedDecimal - decimal);
|
|
|
|
if (difference < minDifference) {
|
|
|
|
minDifference = difference;
|
|
|
|
minDecimal = roundedDecimal;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return floored + minDecimal;
|
|
|
|
}
|
|
|
|
|
|
|
|
function rec(layout) {
|
|
|
|
layout.top = round(layout.top);
|
|
|
|
layout.left = round(layout.left);
|
|
|
|
layout.width = round(layout.width);
|
|
|
|
layout.height = round(layout.height);
|
|
|
|
if (layout.children) {
|
|
|
|
for (var i = 0; i < layout.children.length; ++i) {
|
|
|
|
rec(layout.children[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
rec(layout);
|
|
|
|
return layout;
|
|
|
|
}
|
|
|
|
|
2015-05-11 15:39:02 +01:00
|
|
|
function capitalizeFirst(str) {
|
|
|
|
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
|
|
}
|
|
|
|
|
2014-04-26 12:46:21 -07:00
|
|
|
function computeCSSLayout(rootNode) {
|
|
|
|
fillNodes(rootNode);
|
2014-04-27 12:37:26 -07:00
|
|
|
realComputeLayout(rootNode);
|
2014-12-11 16:31:57 +00:00
|
|
|
return roundLayout(extractNodes(rootNode));
|
2014-04-26 12:46:21 -07:00
|
|
|
}
|
|
|
|
|
2014-04-18 16:35:37 -07:00
|
|
|
function computeDOMLayout(node) {
|
2014-09-26 16:22:44 -07:00
|
|
|
var body = getIframe().contentDocument.body;
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
|
|
|
|
function setStyle(div, name, value) {
|
|
|
|
div.style['-webkit-' + name] = value;
|
|
|
|
div.style['webkit' + capitalizeFirst(name)] = value;
|
|
|
|
div.style[name] = value;
|
|
|
|
}
|
|
|
|
|
2014-04-18 16:35:37 -07:00
|
|
|
function transfer(div, node, name, ext) {
|
|
|
|
if (name in node.style) {
|
2015-05-11 15:39:02 +01:00
|
|
|
var value = node.style[name] + (ext || '');
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
setStyle(div, name, value);
|
2014-04-18 16:35:37 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-04-22 11:31:42 -07:00
|
|
|
function transferSpacing(div, node, type, suffix) {
|
|
|
|
transfer(div, node, type + suffix, 'px');
|
|
|
|
transfer(div, node, type + 'Left' + suffix, 'px');
|
|
|
|
transfer(div, node, type + 'Top' + suffix, 'px');
|
|
|
|
transfer(div, node, type + 'Bottom' + suffix, 'px');
|
|
|
|
transfer(div, node, type + 'Right' + suffix, 'px');
|
2015-05-11 15:39:02 +01:00
|
|
|
transfer(div, node, type + 'Start' + suffix, 'px');
|
|
|
|
transfer(div, node, type + 'End' + suffix, 'px');
|
2014-04-18 16:35:37 -07:00
|
|
|
}
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
|
|
|
|
function transferFlex(div, node) {
|
|
|
|
if ('flex' in node.style) {
|
|
|
|
var flex = node.style.flex;
|
|
|
|
var resolvedFlex = (
|
|
|
|
flex < 0 ? '0 1 auto' :
|
|
|
|
flex > 0 ? (flex + ' 0 0') :
|
|
|
|
'0 0 auto'
|
|
|
|
);
|
|
|
|
setStyle(div, 'flex', resolvedFlex);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-04-18 16:35:37 -07:00
|
|
|
function renderNode(parent, node) {
|
|
|
|
var div = document.createElement('div');
|
|
|
|
transfer(div, node, 'width', 'px');
|
|
|
|
transfer(div, node, 'height', 'px');
|
2015-03-31 17:27:13 +08:00
|
|
|
transfer(div, node, 'minWidth', 'px');
|
|
|
|
transfer(div, node, 'minHeight', 'px');
|
|
|
|
transfer(div, node, 'maxWidth', 'px');
|
|
|
|
transfer(div, node, 'maxHeight', 'px');
|
2014-04-18 16:35:37 -07:00
|
|
|
transfer(div, node, 'top', 'px');
|
|
|
|
transfer(div, node, 'left', 'px');
|
|
|
|
transfer(div, node, 'right', 'px');
|
|
|
|
transfer(div, node, 'bottom', 'px');
|
2014-04-22 11:31:42 -07:00
|
|
|
transferSpacing(div, node, 'margin', '');
|
|
|
|
transferSpacing(div, node, 'padding', '');
|
|
|
|
transferSpacing(div, node, 'border', 'Width');
|
2014-04-18 16:35:37 -07:00
|
|
|
transfer(div, node, 'flexDirection');
|
2015-05-06 21:22:44 +01:00
|
|
|
transfer(div, node, 'direction');
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
transferFlex(div, node);
|
2014-12-11 13:30:46 +00:00
|
|
|
transfer(div, node, 'flexWrap');
|
2014-04-18 16:35:37 -07:00
|
|
|
transfer(div, node, 'justifyContent');
|
|
|
|
transfer(div, node, 'alignSelf');
|
|
|
|
transfer(div, node, 'alignItems');
|
2015-05-08 15:18:38 +08:00
|
|
|
transfer(div, node, 'alignContent');
|
2014-04-18 16:35:37 -07:00
|
|
|
transfer(div, node, 'position');
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
transfer(div, node, 'overflow');
|
2014-04-18 16:35:37 -07:00
|
|
|
parent.appendChild(div);
|
|
|
|
(node.children || []).forEach(function(child) {
|
|
|
|
renderNode(div, child);
|
|
|
|
});
|
2014-04-26 17:11:22 -07:00
|
|
|
if (node.style.measure) {
|
|
|
|
div.innerText = node.style.measure.toString();
|
2014-04-26 12:16:27 -07:00
|
|
|
}
|
2014-04-18 16:35:37 -07:00
|
|
|
return div;
|
|
|
|
}
|
|
|
|
|
|
|
|
var div = renderNode(body, node);
|
|
|
|
|
|
|
|
function buildLayout(absoluteRect, div) {
|
|
|
|
var rect = div.getBoundingClientRect();
|
|
|
|
var result = {
|
2014-09-11 09:23:30 -07:00
|
|
|
width: rect.width,
|
|
|
|
height: rect.height,
|
|
|
|
top: rect.top - absoluteRect.top,
|
|
|
|
left: rect.left - absoluteRect.left
|
2014-04-18 16:35:37 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
var children = [];
|
|
|
|
for (var child = div.firstChild; child; child = child.nextSibling) {
|
2014-04-26 12:16:27 -07:00
|
|
|
if (child.nodeType !== 3 /* textNode */) {
|
|
|
|
children.push(buildLayout(rect, child));
|
|
|
|
}
|
2014-04-18 16:35:37 -07:00
|
|
|
}
|
|
|
|
if (children.length) {
|
|
|
|
result.children = children;
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
var layout = buildLayout({left: 0, top: 0}, div);
|
|
|
|
body.removeChild(div);
|
|
|
|
return layout;
|
|
|
|
}
|
|
|
|
|
2015-05-09 11:46:28 +08:00
|
|
|
function inplaceRoundNumbersInObject(obj) {
|
|
|
|
if (!testMeasurePrecision) {
|
|
|
|
// undefined/0, disables rounding
|
2015-05-08 14:51:05 +08:00
|
|
|
return;
|
2015-05-09 11:46:28 +08:00
|
|
|
}
|
2015-05-08 14:51:05 +08:00
|
|
|
|
2015-05-09 11:46:28 +08:00
|
|
|
for (var key in obj) {
|
|
|
|
if (!obj.hasOwnProperty(key)) {
|
2015-05-08 14:51:05 +08:00
|
|
|
continue;
|
|
|
|
}
|
2015-05-09 11:46:28 +08:00
|
|
|
|
|
|
|
var val = obj[key];
|
|
|
|
if (typeof val === 'number') {
|
2015-05-09 13:03:21 +08:00
|
|
|
obj[key] = Math.floor((val * testMeasurePrecision) + 0.5) / testMeasurePrecision;
|
2015-10-07 21:52:22 +01:00
|
|
|
} else if (typeof val === 'object') {
|
2015-05-09 11:46:28 +08:00
|
|
|
inplaceRoundNumbersInObject(val);
|
2015-05-08 14:51:05 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-04-18 16:35:37 -07:00
|
|
|
function nameLayout(name, layout) {
|
|
|
|
var namedLayout = {name: name};
|
|
|
|
for (var key in layout) {
|
|
|
|
namedLayout[key] = layout[key];
|
|
|
|
}
|
|
|
|
return namedLayout;
|
|
|
|
}
|
|
|
|
|
2015-02-07 00:01:35 -05:00
|
|
|
function testFillNodes(node, filledNode) {
|
|
|
|
expect(fillNodes(node)).toEqual(filledNode);
|
|
|
|
}
|
|
|
|
|
|
|
|
function testExtractNodes(node, extractedNode) {
|
|
|
|
expect(extractNodes(node)).toEqual(extractedNode);
|
|
|
|
}
|
|
|
|
|
2014-04-18 16:35:37 -07:00
|
|
|
function testNamedLayout(name, layoutA, layoutB) {
|
|
|
|
expect(nameLayout(name, layoutA))
|
|
|
|
.toEqual(nameLayout(name, layoutB));
|
|
|
|
}
|
|
|
|
|
2014-04-21 16:52:53 -07:00
|
|
|
function isEqual(a, b) {
|
2014-04-26 12:46:21 -07:00
|
|
|
// computeCSSLayout and computeDOMLayout output a tree with same ordered elements
|
2014-04-21 16:52:53 -07:00
|
|
|
return JSON.stringify(a) === JSON.stringify(b);
|
|
|
|
}
|
|
|
|
|
|
|
|
function reduceTest(node) {
|
|
|
|
function isWorking() {
|
|
|
|
return isEqual(
|
|
|
|
computeDOMLayout(node),
|
2014-04-26 12:46:21 -07:00
|
|
|
computeCSSLayout(node)
|
2014-04-21 16:52:53 -07:00
|
|
|
);
|
|
|
|
}
|
|
|
|
if (isWorking()) {
|
2014-04-22 09:32:49 -07:00
|
|
|
return node;
|
2014-04-21 16:52:53 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
var isModified = true;
|
|
|
|
|
|
|
|
function rec(node) {
|
2015-02-17 21:12:29 -05:00
|
|
|
var key;
|
|
|
|
var value;
|
|
|
|
|
2014-04-21 16:52:53 -07:00
|
|
|
// Style
|
2015-02-17 21:12:29 -05:00
|
|
|
for (key in node.style) {
|
|
|
|
value = node.style[key];
|
2014-04-21 16:52:53 -07:00
|
|
|
delete node.style[key];
|
|
|
|
if (isWorking()) {
|
|
|
|
node.style[key] = value;
|
|
|
|
} else {
|
|
|
|
isModified = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Round values
|
2015-02-17 21:12:29 -05:00
|
|
|
for (key in node.style) {
|
|
|
|
value = node.style[key];
|
2014-04-21 16:52:53 -07:00
|
|
|
if (value > 100) {
|
|
|
|
node.style[key] = Math.round(value / 100) * 100;
|
|
|
|
} else if (value > 10) {
|
|
|
|
node.style[key] = Math.round(value / 10) * 10;
|
2014-04-21 18:50:34 -07:00
|
|
|
} else if (value > 1) {
|
2014-04-21 16:52:53 -07:00
|
|
|
node.style[key] = 5;
|
|
|
|
}
|
|
|
|
if (node.style[key] !== value) {
|
|
|
|
if (isWorking()) {
|
|
|
|
node.style[key] = value;
|
|
|
|
} else {
|
|
|
|
isModified = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Children
|
|
|
|
for (var i = 0; node.children && i < node.children.length; ++i) {
|
2015-02-17 21:12:29 -05:00
|
|
|
value = node.children[i];
|
2014-04-21 16:52:53 -07:00
|
|
|
node.children.splice(i, 1);
|
2014-04-21 17:07:05 -07:00
|
|
|
if (isWorking()) {
|
|
|
|
if (!node.children) {
|
|
|
|
node.children = [];
|
|
|
|
}
|
2014-04-21 16:52:53 -07:00
|
|
|
node.children.splice(i, 0, value);
|
|
|
|
rec(node.children[i]);
|
|
|
|
} else {
|
|
|
|
i--;
|
|
|
|
isModified = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
while (isModified) {
|
|
|
|
isModified = false;
|
|
|
|
rec(node);
|
|
|
|
}
|
|
|
|
|
2014-04-22 09:32:49 -07:00
|
|
|
return node;
|
2014-04-21 16:52:53 -07:00
|
|
|
}
|
|
|
|
|
2014-09-26 16:22:44 -07:00
|
|
|
var iframeText;
|
2014-09-19 18:36:18 -07:00
|
|
|
function measureTextSizes(text, width) {
|
2014-09-26 16:22:44 -07:00
|
|
|
iframeText = iframeText || document.createElement('iframe');
|
|
|
|
document.body.appendChild(iframeText);
|
|
|
|
|
2014-09-19 18:36:18 -07:00
|
|
|
var body = iframeText.contentDocument.body;
|
2015-10-07 21:52:22 +01:00
|
|
|
if (width === undefined || isNaN(width)) {
|
2014-09-19 18:36:18 -07:00
|
|
|
width = Infinity;
|
|
|
|
}
|
|
|
|
|
|
|
|
var div = document.createElement('div');
|
|
|
|
div.style.width = (width === Infinity ? 10000000 : width) + 'px';
|
|
|
|
div.style.display = 'flex';
|
|
|
|
div.style.flexDirection = 'column';
|
|
|
|
div.style.alignItems = 'flex-start';
|
2015-05-09 11:58:02 +08:00
|
|
|
div.style.alignContent = 'flex-start';
|
2014-09-19 18:36:18 -07:00
|
|
|
|
|
|
|
var span = document.createElement('span');
|
|
|
|
span.style.display = 'flex';
|
|
|
|
span.style.flexDirection = 'column';
|
|
|
|
span.style.alignItems = 'flex-start';
|
2015-05-09 11:58:02 +08:00
|
|
|
span.style.alignContent = 'flex-start';
|
2014-09-19 18:36:18 -07:00
|
|
|
span.innerText = text;
|
|
|
|
|
|
|
|
div.appendChild(span);
|
|
|
|
body.appendChild(div);
|
|
|
|
var rect = span.getBoundingClientRect();
|
|
|
|
body.removeChild(div);
|
|
|
|
return {
|
|
|
|
width: rect.width,
|
|
|
|
height: rect.height
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
var texts = {
|
|
|
|
small: 'small',
|
2015-02-17 21:12:29 -05:00
|
|
|
big: 'loooooooooong with space'
|
2014-09-19 18:36:18 -07:00
|
|
|
};
|
|
|
|
|
2014-09-26 20:38:34 -07:00
|
|
|
var preDefinedTextSizes = {
|
|
|
|
smallWidth: 34.671875,
|
2015-04-24 14:00:40 +01:00
|
|
|
smallHeight: 18,
|
2014-09-26 20:38:34 -07:00
|
|
|
bigWidth: 172.421875,
|
2015-08-05 21:57:06 -07:00
|
|
|
bigHeight: 36,
|
2015-04-24 14:00:40 +01:00
|
|
|
bigMinWidth: 100.4375
|
2014-09-26 20:38:34 -07:00
|
|
|
};
|
|
|
|
|
2015-05-09 11:47:27 +08:00
|
|
|
// Note(prenaux): Clearly not what I would like, but it seems to be the only
|
|
|
|
// way :( My guess is that since the font on Windows is
|
|
|
|
// different than on OSX it has a different size.
|
2015-08-11 16:52:57 +01:00
|
|
|
if (typeof navigator !== 'undefined' && navigator.userAgent.indexOf('Windows NT') > -1) {
|
2015-05-09 11:47:27 +08:00
|
|
|
preDefinedTextSizes.bigHeight = 36;
|
|
|
|
}
|
|
|
|
|
2014-09-26 16:22:44 -07:00
|
|
|
var textSizes;
|
|
|
|
if (typeof require === 'function') {
|
2014-09-26 20:38:34 -07:00
|
|
|
textSizes = preDefinedTextSizes;
|
2014-09-26 16:22:44 -07:00
|
|
|
} else {
|
|
|
|
textSizes = {
|
|
|
|
smallWidth: measureTextSizes(texts.small, 0).width,
|
|
|
|
smallHeight: measureTextSizes(texts.small, 0).height,
|
|
|
|
bigWidth: measureTextSizes(texts.big).width,
|
|
|
|
bigHeight: measureTextSizes(texts.big, 0).height,
|
2015-02-17 21:12:29 -05:00
|
|
|
bigMinWidth: measureTextSizes(texts.big, 0).width
|
2014-09-26 16:22:44 -07:00
|
|
|
};
|
|
|
|
}
|
2014-09-19 18:22:09 -07:00
|
|
|
|
2015-05-08 14:51:05 +08:00
|
|
|
// round the text sizes so that we dont have to update it for every browser
|
|
|
|
// update, assumes we're ok with pixel precision
|
|
|
|
inplaceRoundNumbersInObject(preDefinedTextSizes);
|
|
|
|
inplaceRoundNumbersInObject(textSizes);
|
|
|
|
|
2014-04-18 16:35:37 -07:00
|
|
|
return {
|
2014-09-19 18:36:18 -07:00
|
|
|
texts: texts,
|
2014-09-19 18:22:09 -07:00
|
|
|
textSizes: textSizes,
|
2014-09-26 20:38:34 -07:00
|
|
|
preDefinedTextSizes: preDefinedTextSizes,
|
2014-04-18 16:35:37 -07:00
|
|
|
testLayout: function(node, expectedLayout) {
|
2014-04-26 12:46:21 -07:00
|
|
|
var layout = computeCSSLayout(node);
|
2014-04-18 16:35:37 -07:00
|
|
|
var domLayout = computeDOMLayout(node);
|
2015-05-08 15:10:28 +08:00
|
|
|
inplaceRoundNumbersInObject(layout);
|
|
|
|
inplaceRoundNumbersInObject(domLayout);
|
|
|
|
inplaceRoundNumbersInObject(expectedLayout);
|
2014-04-18 16:35:37 -07:00
|
|
|
testNamedLayout('expected-dom', expectedLayout, domLayout);
|
|
|
|
testNamedLayout('layout-dom', layout, domLayout);
|
|
|
|
},
|
2015-08-11 16:52:57 +01:00
|
|
|
testLayoutAgainstDomOnly: function(node) {
|
2015-05-08 14:52:11 +08:00
|
|
|
var layout = computeCSSLayout(node);
|
|
|
|
var domLayout = computeDOMLayout(node);
|
2015-05-08 15:10:28 +08:00
|
|
|
inplaceRoundNumbersInObject(layout);
|
|
|
|
inplaceRoundNumbersInObject(domLayout);
|
2015-05-08 14:52:11 +08:00
|
|
|
testNamedLayout('layout-dom', layout, domLayout);
|
|
|
|
},
|
2015-11-17 18:50:42 +00:00
|
|
|
testLayoutAgainstExpectedOnly: function(node, expectedLayout) {
|
|
|
|
var layout = computeCSSLayout(node);
|
|
|
|
inplaceRoundNumbersInObject(layout);
|
|
|
|
inplaceRoundNumbersInObject(expectedLayout);
|
|
|
|
testNamedLayout('expected-dom', expectedLayout, layout);
|
|
|
|
},
|
2015-02-07 00:01:35 -05:00
|
|
|
testFillNodes: testFillNodes,
|
|
|
|
testExtractNodes: testExtractNodes,
|
2015-02-17 21:12:29 -05:00
|
|
|
testRandomLayout: function(node) {
|
2015-05-08 15:10:28 +08:00
|
|
|
var layout = computeCSSLayout(node);
|
|
|
|
var domLayout = computeDOMLayout(node);
|
|
|
|
inplaceRoundNumbersInObject(layout);
|
|
|
|
inplaceRoundNumbersInObject(domLayout);
|
|
|
|
expect({node: node, layout: layout})
|
|
|
|
.toEqual({node: node, layout: domLayout});
|
2014-04-19 22:08:10 -07:00
|
|
|
},
|
2014-09-25 17:56:02 -07:00
|
|
|
testsFinished: function() {
|
|
|
|
console.log('tests finished!');
|
|
|
|
},
|
2014-04-26 12:46:21 -07:00
|
|
|
computeLayout: computeCSSLayout,
|
2014-04-21 16:52:53 -07:00
|
|
|
computeDOMLayout: computeDOMLayout,
|
2014-04-26 17:11:22 -07:00
|
|
|
reduceTest: reduceTest,
|
|
|
|
text: function(text) {
|
2016-01-06 16:56:56 +00:00
|
|
|
var fn = function(width, widthMode, height, heightMode) {
|
|
|
|
if (widthMode === 'undefined') {
|
2014-06-04 10:51:23 -07:00
|
|
|
width = Infinity;
|
|
|
|
}
|
|
|
|
|
2014-04-28 12:34:04 -07:00
|
|
|
// Constants for testing purposes between C/JS and other platforms
|
|
|
|
// Comment this block of code if you want to use the browser to
|
|
|
|
// generate proper sizes
|
2014-09-19 18:36:18 -07:00
|
|
|
if (text === texts.small) {
|
2014-09-19 18:22:09 -07:00
|
|
|
return {
|
|
|
|
width: Math.min(textSizes.smallWidth, width),
|
|
|
|
height: textSizes.smallHeight
|
|
|
|
};
|
2014-04-28 12:34:04 -07:00
|
|
|
}
|
2014-09-19 18:36:18 -07:00
|
|
|
if (text === texts.big) {
|
2014-06-04 10:51:23 -07:00
|
|
|
var res = {
|
2014-09-19 18:22:09 -07:00
|
|
|
width: width >= textSizes.bigWidth ? textSizes.bigWidth : Math.max(textSizes.bigMinWidth, width),
|
|
|
|
height: width >= textSizes.bigWidth ? textSizes.smallHeight : textSizes.bigHeight
|
2014-06-04 10:51:23 -07:00
|
|
|
};
|
2014-09-19 18:22:09 -07:00
|
|
|
return res;
|
2014-04-28 12:34:04 -07:00
|
|
|
}
|
2014-04-26 17:11:22 -07:00
|
|
|
};
|
2015-11-17 18:50:42 +00:00
|
|
|
// Name of the function is used in DOM tests as a text in the measured node
|
|
|
|
// and as a way to tell different measure functions apart in transpiled tests
|
2014-09-19 18:36:18 -07:00
|
|
|
fn.toString = function() { return text; };
|
2014-04-26 17:11:22 -07:00
|
|
|
return fn;
|
2015-11-17 18:50:42 +00:00
|
|
|
},
|
|
|
|
measureWithRatio2: function() {
|
2016-01-06 16:56:56 +00:00
|
|
|
var fn = function(width, widthMode, height, heightMode) {
|
|
|
|
if (widthMode !== 'undefined') {
|
2015-11-17 18:50:42 +00:00
|
|
|
height = width * 2;
|
2016-01-06 16:56:56 +00:00
|
|
|
} else if (heightMode !== 'undefined') {
|
2015-11-17 18:50:42 +00:00
|
|
|
width = height * 2;
|
|
|
|
} else {
|
|
|
|
// This should be Infinity, but it would be pain to transpile,
|
|
|
|
// so let's just go with big numbers.
|
|
|
|
height = 99999;
|
|
|
|
width = 99999;
|
|
|
|
}
|
|
|
|
return {width: width, height: height};
|
|
|
|
};
|
|
|
|
// This is necessary for transpiled tests, see previous comment
|
|
|
|
fn.toString = function() { return 'measureWithRatio2'; };
|
|
|
|
return fn;
|
2016-01-05 19:33:04 +00:00
|
|
|
},
|
|
|
|
measureWithMatchParent: function() {
|
2016-01-06 16:56:56 +00:00
|
|
|
var fn = function(width, widthMode, height, heightMode) {
|
|
|
|
if (widthMode === 'undefined') {
|
|
|
|
width = 99999;
|
|
|
|
}
|
|
|
|
if (heightMode === 'undefined') {
|
|
|
|
height = 99999;
|
|
|
|
}
|
2016-01-05 19:33:04 +00:00
|
|
|
return {width: width, height: height};
|
|
|
|
};
|
|
|
|
// This is necessary for transpiled tests, see previous comment
|
|
|
|
fn.toString = function() { return 'measureWithMatchParent'; };
|
|
|
|
return fn;
|
2014-04-26 17:11:22 -07:00
|
|
|
}
|
2014-09-26 20:38:34 -07:00
|
|
|
};
|
2014-04-18 16:35:37 -07:00
|
|
|
})();
|
2014-09-26 16:22:44 -07:00
|
|
|
|
|
|
|
if (typeof module !== 'undefined') {
|
|
|
|
module.exports = layoutTestUtils;
|
|
|
|
}
|