2014-10-29 08:01:22 -07:00
|
|
|
/**
|
2016-07-25 06:31:32 -07:00
|
|
|
* Copyright (c) 2014-present, Facebook, Inc.
|
2014-10-29 08:01:22 -07:00
|
|
|
* 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.
|
|
|
|
*/
|
2016-07-25 06:31:32 -07:00
|
|
|
|
2014-09-18 15:15:21 -07:00
|
|
|
package com.facebook.csslayout;
|
|
|
|
|
2014-12-05 14:11:14 +00:00
|
|
|
import javax.annotation.Nullable;
|
|
|
|
|
2014-09-18 15:15:21 -07:00
|
|
|
import java.util.ArrayList;
|
|
|
|
|
2015-01-19 12:37:30 +00:00
|
|
|
import com.facebook.infer.annotation.Assertions;
|
|
|
|
|
2015-09-04 13:50:28 +01:00
|
|
|
import static com.facebook.csslayout.CSSLayout.DIMENSION_HEIGHT;
|
|
|
|
import static com.facebook.csslayout.CSSLayout.DIMENSION_WIDTH;
|
|
|
|
import static com.facebook.csslayout.CSSLayout.POSITION_LEFT;
|
|
|
|
import static com.facebook.csslayout.CSSLayout.POSITION_TOP;
|
2016-07-28 14:43:40 -07:00
|
|
|
import static com.facebook.csslayout.Spacing.BOTTOM;
|
|
|
|
import static com.facebook.csslayout.Spacing.LEFT;
|
|
|
|
import static com.facebook.csslayout.Spacing.RIGHT;
|
|
|
|
import static com.facebook.csslayout.Spacing.TOP;
|
2015-09-04 13:50:28 +01:00
|
|
|
|
2014-09-18 15:15:21 -07:00
|
|
|
/**
|
|
|
|
* A CSS Node. It has a style object you can manipulate at {@link #style}. After calling
|
|
|
|
* {@link #calculateLayout()}, {@link #layout} will be filled with the results of the layout.
|
|
|
|
*/
|
|
|
|
public class CSSNode {
|
|
|
|
|
|
|
|
private static enum LayoutState {
|
|
|
|
/**
|
|
|
|
* Some property of this node or its children has changes and the current values in
|
|
|
|
* {@link #layout} are not valid.
|
|
|
|
*/
|
|
|
|
DIRTY,
|
|
|
|
|
|
|
|
/**
|
2014-10-08 15:42:51 -07:00
|
|
|
* This node has a new layout relative to the last time {@link #markLayoutSeen()} was called.
|
2014-09-18 15:15:21 -07:00
|
|
|
*/
|
|
|
|
HAS_NEW_LAYOUT,
|
|
|
|
|
|
|
|
/**
|
|
|
|
* {@link #layout} is valid for the node's properties and this layout has been marked as
|
2014-10-08 15:42:51 -07:00
|
|
|
* having been seen.
|
2014-09-18 15:15:21 -07:00
|
|
|
*/
|
|
|
|
UP_TO_DATE,
|
|
|
|
}
|
|
|
|
|
|
|
|
public static interface MeasureFunction {
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Should measure the given node and put the result in the given MeasureOutput.
|
|
|
|
*
|
|
|
|
* NB: measure is NOT guaranteed to be threadsafe/re-entrant safe!
|
|
|
|
*/
|
2016-01-06 16:56:56 +00:00
|
|
|
public void measure(CSSNode node, float width, CSSMeasureMode widthMode, float height, CSSMeasureMode heightMode, MeasureOutput measureOutput);
|
2014-09-18 15:15:21 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// VisibleForTesting
|
|
|
|
/*package*/ final CSSStyle style = new CSSStyle();
|
|
|
|
/*package*/ final CSSLayout layout = new CSSLayout();
|
|
|
|
/*package*/ final CachedCSSLayout lastLayout = new CachedCSSLayout();
|
|
|
|
|
2015-05-06 15:14:57 +08:00
|
|
|
public int lineIndex = 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
|
|
|
/*package*/ CSSNode nextChild;
|
2016-06-03 22:19:03 +01:00
|
|
|
|
2015-07-29 11:39:25 +01:00
|
|
|
private @Nullable ArrayList<CSSNode> mChildren;
|
2015-01-19 12:37:30 +00:00
|
|
|
private @Nullable CSSNode mParent;
|
|
|
|
private @Nullable MeasureFunction mMeasureFunction = null;
|
2014-09-18 15:15:21 -07:00
|
|
|
private LayoutState mLayoutState = LayoutState.DIRTY;
|
2016-06-03 15:38:08 +01:00
|
|
|
private boolean mIsTextNode = false;
|
2014-09-18 15:15:21 -07:00
|
|
|
|
|
|
|
public int getChildCount() {
|
2015-07-29 11:39:25 +01:00
|
|
|
return mChildren == null ? 0 : mChildren.size();
|
2014-09-18 15:15:21 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
public CSSNode getChildAt(int i) {
|
2015-07-29 11:39:25 +01:00
|
|
|
Assertions.assertNotNull(mChildren);
|
2014-09-18 15:15:21 -07:00
|
|
|
return mChildren.get(i);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void addChildAt(CSSNode child, int i) {
|
|
|
|
if (child.mParent != null) {
|
|
|
|
throw new IllegalStateException("Child already has a parent, it must be removed first.");
|
|
|
|
}
|
2015-07-29 11:39:25 +01:00
|
|
|
if (mChildren == null) {
|
|
|
|
// 4 is kinda arbitrary, but the default of 10 seems really high for an average View.
|
|
|
|
mChildren = new ArrayList<>(4);
|
|
|
|
}
|
2014-09-18 15:15:21 -07:00
|
|
|
|
|
|
|
mChildren.add(i, child);
|
|
|
|
child.mParent = this;
|
|
|
|
dirty();
|
|
|
|
}
|
|
|
|
|
2015-07-29 11:39:25 +01:00
|
|
|
public CSSNode removeChildAt(int i) {
|
|
|
|
Assertions.assertNotNull(mChildren);
|
|
|
|
CSSNode removed = mChildren.remove(i);
|
|
|
|
removed.mParent = null;
|
2014-09-18 15:15:21 -07:00
|
|
|
dirty();
|
2015-07-29 11:39:25 +01:00
|
|
|
return removed;
|
2014-09-18 15:15:21 -07:00
|
|
|
}
|
|
|
|
|
2015-01-19 12:37:30 +00:00
|
|
|
public @Nullable CSSNode getParent() {
|
2014-09-18 15:15:21 -07:00
|
|
|
return mParent;
|
|
|
|
}
|
|
|
|
|
2015-01-19 12:37:30 +00:00
|
|
|
/**
|
|
|
|
* @return the index of the given child, or -1 if the child doesn't exist in this node.
|
|
|
|
*/
|
|
|
|
public int indexOf(CSSNode child) {
|
2015-07-29 11:39:25 +01:00
|
|
|
Assertions.assertNotNull(mChildren);
|
2015-01-19 12:37:30 +00:00
|
|
|
return mChildren.indexOf(child);
|
|
|
|
}
|
|
|
|
|
2014-09-18 15:15:21 -07:00
|
|
|
public void setMeasureFunction(MeasureFunction measureFunction) {
|
2015-10-05 17:07:23 +01:00
|
|
|
if (mMeasureFunction != measureFunction) {
|
2014-10-08 15:42:51 -07:00
|
|
|
mMeasureFunction = measureFunction;
|
|
|
|
dirty();
|
|
|
|
}
|
2014-09-18 15:15:21 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
public boolean isMeasureDefined() {
|
|
|
|
return mMeasureFunction != null;
|
|
|
|
}
|
|
|
|
|
2016-06-03 15:38:08 +01:00
|
|
|
public void setIsTextNode(boolean isTextNode) {
|
|
|
|
mIsTextNode = isTextNode;
|
|
|
|
}
|
|
|
|
|
|
|
|
public boolean isTextNode() {
|
|
|
|
return mIsTextNode;
|
|
|
|
}
|
|
|
|
|
2016-01-06 16:56:56 +00:00
|
|
|
/*package*/ MeasureOutput measure(MeasureOutput measureOutput, float width, CSSMeasureMode widthMode, float height, CSSMeasureMode heightMode) {
|
2014-09-18 15:15:21 -07:00
|
|
|
if (!isMeasureDefined()) {
|
|
|
|
throw new RuntimeException("Measure function isn't defined!");
|
|
|
|
}
|
2015-03-23 17:49:47 +00:00
|
|
|
measureOutput.height = CSSConstants.UNDEFINED;
|
|
|
|
measureOutput.width = CSSConstants.UNDEFINED;
|
2016-01-06 16:56:56 +00:00
|
|
|
Assertions.assertNotNull(mMeasureFunction).measure(this, width, widthMode, height, heightMode, measureOutput);
|
2015-03-23 17:49:47 +00:00
|
|
|
return measureOutput;
|
2014-09-18 15:15:21 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Performs the actual layout and saves the results in {@link #layout}
|
|
|
|
*/
|
2015-03-23 17:49:47 +00:00
|
|
|
public void calculateLayout(CSSLayoutContext layoutContext) {
|
2015-11-17 18:50:42 +00:00
|
|
|
LayoutEngine.layoutNode(layoutContext, this, CSSConstants.UNDEFINED, CSSConstants.UNDEFINED, null);
|
2014-09-18 15:15:21 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* See {@link LayoutState#DIRTY}.
|
|
|
|
*/
|
2015-05-21 17:35:46 +01:00
|
|
|
protected boolean isDirty() {
|
2014-09-18 15:15:21 -07:00
|
|
|
return mLayoutState == LayoutState.DIRTY;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* See {@link LayoutState#HAS_NEW_LAYOUT}.
|
|
|
|
*/
|
|
|
|
public boolean hasNewLayout() {
|
|
|
|
return mLayoutState == LayoutState.HAS_NEW_LAYOUT;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected void dirty() {
|
|
|
|
if (mLayoutState == LayoutState.DIRTY) {
|
|
|
|
return;
|
|
|
|
} else if (mLayoutState == LayoutState.HAS_NEW_LAYOUT) {
|
2014-10-08 15:42:51 -07:00
|
|
|
throw new IllegalStateException("Previous layout was ignored! markLayoutSeen() never called");
|
2014-09-18 15:15:21 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
mLayoutState = LayoutState.DIRTY;
|
|
|
|
|
|
|
|
if (mParent != null) {
|
|
|
|
mParent.dirty();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*package*/ void markHasNewLayout() {
|
|
|
|
mLayoutState = LayoutState.HAS_NEW_LAYOUT;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2014-10-08 15:42:51 -07:00
|
|
|
* Tells the node that the current values in {@link #layout} have been seen. Subsequent calls
|
2014-09-18 15:15:21 -07:00
|
|
|
* to {@link #hasNewLayout()} will return false until this node is laid out with new parameters.
|
|
|
|
* You must call this each time the layout is generated if the node has a new layout.
|
|
|
|
*/
|
2014-10-08 15:42:51 -07:00
|
|
|
public void markLayoutSeen() {
|
2014-09-18 15:15:21 -07:00
|
|
|
if (!hasNewLayout()) {
|
2014-10-08 15:42:51 -07:00
|
|
|
throw new IllegalStateException("Expected node to have a new layout to be seen!");
|
2014-09-18 15:15:21 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
mLayoutState = LayoutState.UP_TO_DATE;
|
|
|
|
}
|
|
|
|
|
2014-12-02 18:52:57 +00:00
|
|
|
private void toStringWithIndentation(StringBuilder result, int level) {
|
|
|
|
// Spaces and tabs are dropped by IntelliJ logcat integration, so rely on __ instead.
|
|
|
|
StringBuilder indentation = new StringBuilder();
|
|
|
|
for (int i = 0; i < level; ++i) {
|
|
|
|
indentation.append("__");
|
|
|
|
}
|
|
|
|
|
|
|
|
result.append(indentation.toString());
|
|
|
|
result.append(layout.toString());
|
2014-09-18 15:15:21 -07:00
|
|
|
|
|
|
|
if (getChildCount() == 0) {
|
2014-12-02 18:52:57 +00:00
|
|
|
return;
|
2014-09-18 15:15:21 -07:00
|
|
|
}
|
|
|
|
|
2014-12-02 18:52:57 +00:00
|
|
|
result.append(", children: [\n");
|
2014-09-18 15:15:21 -07:00
|
|
|
for (int i = 0; i < getChildCount(); i++) {
|
2014-12-02 18:52:57 +00:00
|
|
|
getChildAt(i).toStringWithIndentation(result, level + 1);
|
|
|
|
result.append("\n");
|
2014-09-18 15:15:21 -07:00
|
|
|
}
|
2014-12-02 18:52:57 +00:00
|
|
|
result.append(indentation + "]");
|
2014-09-18 15:15:21 -07:00
|
|
|
}
|
|
|
|
|
2014-12-02 18:52:57 +00:00
|
|
|
@Override
|
|
|
|
public String toString() {
|
|
|
|
StringBuilder sb = new StringBuilder();
|
|
|
|
this.toStringWithIndentation(sb, 0);
|
|
|
|
return sb.toString();
|
2014-09-18 15:15:21 -07:00
|
|
|
}
|
|
|
|
|
2014-10-08 15:42:51 -07:00
|
|
|
protected boolean valuesEqual(float f1, float f2) {
|
|
|
|
return FloatUtil.floatsEqual(f1, f2);
|
2014-09-18 15:15:21 -07:00
|
|
|
}
|
|
|
|
|
2015-10-21 10:45:33 +01:00
|
|
|
/**
|
|
|
|
* Get this node's direction, as defined in the style.
|
|
|
|
*/
|
|
|
|
public CSSDirection getStyleDirection() {
|
|
|
|
return style.direction;
|
|
|
|
}
|
|
|
|
|
2015-05-20 11:12:24 +01:00
|
|
|
public void setDirection(CSSDirection direction) {
|
2015-10-05 17:07:23 +01:00
|
|
|
if (style.direction != direction) {
|
2015-05-20 11:12:24 +01:00
|
|
|
style.direction = direction;
|
|
|
|
dirty();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-21 10:37:09 +01:00
|
|
|
/**
|
|
|
|
* Get this node's flex direction, as defined by style.
|
|
|
|
*/
|
|
|
|
public CSSFlexDirection getFlexDirection() {
|
|
|
|
return style.flexDirection;
|
|
|
|
}
|
|
|
|
|
2014-10-08 15:42:51 -07:00
|
|
|
public void setFlexDirection(CSSFlexDirection flexDirection) {
|
2015-10-05 17:07:23 +01:00
|
|
|
if (style.flexDirection != flexDirection) {
|
2014-10-08 15:42:51 -07:00
|
|
|
style.flexDirection = flexDirection;
|
2014-09-18 15:15:21 -07:00
|
|
|
dirty();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-21 10:37:09 +01:00
|
|
|
/**
|
|
|
|
* Get this node's justify content, as defined by style.
|
|
|
|
*/
|
|
|
|
public CSSJustify getJustifyContent() {
|
|
|
|
return style.justifyContent;
|
|
|
|
}
|
|
|
|
|
2014-09-18 15:15:21 -07:00
|
|
|
public void setJustifyContent(CSSJustify justifyContent) {
|
2015-10-05 17:07:23 +01:00
|
|
|
if (style.justifyContent != justifyContent) {
|
2014-10-08 15:42:51 -07:00
|
|
|
style.justifyContent = justifyContent;
|
|
|
|
dirty();
|
|
|
|
}
|
2014-09-18 15:15:21 -07:00
|
|
|
}
|
|
|
|
|
2015-10-21 10:37:09 +01:00
|
|
|
/**
|
|
|
|
* Get this node's align items, as defined by style.
|
|
|
|
*/
|
|
|
|
public CSSAlign getAlignItems() {
|
|
|
|
return style.alignItems;
|
|
|
|
}
|
|
|
|
|
2014-09-18 15:15:21 -07:00
|
|
|
public void setAlignItems(CSSAlign alignItems) {
|
2015-10-05 17:07:23 +01:00
|
|
|
if (style.alignItems != alignItems) {
|
2014-10-08 15:42:51 -07:00
|
|
|
style.alignItems = alignItems;
|
|
|
|
dirty();
|
|
|
|
}
|
2014-09-18 15:15:21 -07:00
|
|
|
}
|
|
|
|
|
2015-10-21 10:37:09 +01:00
|
|
|
/**
|
|
|
|
* Get this node's align items, as defined by style.
|
|
|
|
*/
|
|
|
|
public CSSAlign getAlignSelf() {
|
|
|
|
return style.alignSelf;
|
|
|
|
}
|
|
|
|
|
2014-09-18 15:15:21 -07:00
|
|
|
public void setAlignSelf(CSSAlign alignSelf) {
|
2015-10-05 17:07:23 +01:00
|
|
|
if (style.alignSelf != alignSelf) {
|
2014-10-08 15:42:51 -07:00
|
|
|
style.alignSelf = alignSelf;
|
|
|
|
dirty();
|
|
|
|
}
|
2014-09-18 15:15:21 -07:00
|
|
|
}
|
|
|
|
|
2015-10-21 10:37:09 +01:00
|
|
|
/**
|
|
|
|
* Get this node's position type, as defined by style.
|
|
|
|
*/
|
|
|
|
public CSSPositionType getPositionType() {
|
|
|
|
return style.positionType;
|
|
|
|
}
|
|
|
|
|
2014-09-18 15:15:21 -07:00
|
|
|
public void setPositionType(CSSPositionType positionType) {
|
2015-10-05 17:07:23 +01:00
|
|
|
if (style.positionType != positionType) {
|
2014-10-08 15:42:51 -07:00
|
|
|
style.positionType = positionType;
|
|
|
|
dirty();
|
|
|
|
}
|
2014-09-18 15:15:21 -07:00
|
|
|
}
|
|
|
|
|
2014-12-12 12:03:31 +00:00
|
|
|
public void setWrap(CSSWrap flexWrap) {
|
2015-10-05 17:07:23 +01:00
|
|
|
if (style.flexWrap != flexWrap) {
|
2014-12-12 12:03:31 +00:00
|
|
|
style.flexWrap = flexWrap;
|
|
|
|
dirty();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-21 10:37:09 +01:00
|
|
|
/**
|
|
|
|
* Get this node's flex, as defined by style.
|
|
|
|
*/
|
|
|
|
public float getFlex() {
|
|
|
|
return style.flex;
|
|
|
|
}
|
|
|
|
|
2014-09-18 15:15:21 -07:00
|
|
|
public void setFlex(float flex) {
|
2014-10-08 15:42:51 -07:00
|
|
|
if (!valuesEqual(style.flex, flex)) {
|
|
|
|
style.flex = flex;
|
|
|
|
dirty();
|
|
|
|
}
|
2014-09-18 15:15:21 -07:00
|
|
|
}
|
|
|
|
|
2015-10-21 10:37:09 +01:00
|
|
|
/**
|
|
|
|
* Get this node's margin, as defined by style + default margin.
|
|
|
|
*/
|
|
|
|
public Spacing getMargin() {
|
|
|
|
return style.margin;
|
|
|
|
}
|
|
|
|
|
2014-11-20 17:28:54 +00:00
|
|
|
public void setMargin(int spacingType, float margin) {
|
2015-05-14 13:59:13 +01:00
|
|
|
if (style.margin.set(spacingType, margin)) {
|
|
|
|
dirty();
|
|
|
|
}
|
2014-11-20 17:28:54 +00:00
|
|
|
}
|
|
|
|
|
2015-10-21 10:45:33 +01:00
|
|
|
/**
|
|
|
|
* Get this node's padding, as defined by style + default padding.
|
|
|
|
*/
|
|
|
|
public Spacing getPadding() {
|
|
|
|
return style.padding;
|
|
|
|
}
|
|
|
|
|
2014-11-20 17:59:40 +00:00
|
|
|
public void setPadding(int spacingType, float padding) {
|
2015-05-14 13:59:13 +01:00
|
|
|
if (style.padding.set(spacingType, padding)) {
|
|
|
|
dirty();
|
|
|
|
}
|
2014-11-20 17:59:40 +00:00
|
|
|
}
|
|
|
|
|
2015-10-21 10:37:09 +01:00
|
|
|
/**
|
|
|
|
* Get this node's border, as defined by style.
|
|
|
|
*/
|
|
|
|
public Spacing getBorder() {
|
|
|
|
return style.border;
|
|
|
|
}
|
|
|
|
|
2014-11-20 17:59:40 +00:00
|
|
|
public void setBorder(int spacingType, float border) {
|
2015-05-14 13:59:13 +01:00
|
|
|
if (style.border.set(spacingType, border)) {
|
2014-10-08 15:42:51 -07:00
|
|
|
dirty();
|
|
|
|
}
|
2014-09-18 15:15:21 -07:00
|
|
|
}
|
|
|
|
|
2016-07-28 14:43:40 -07:00
|
|
|
/**
|
|
|
|
* Get this node's position, as defined by style.
|
|
|
|
*/
|
2016-07-29 10:30:34 -07:00
|
|
|
public Spacing getPositionValue() {
|
2016-07-28 14:43:40 -07:00
|
|
|
return style.position;
|
|
|
|
}
|
|
|
|
|
2016-07-29 10:30:34 -07:00
|
|
|
public void setPositionValue(int spacingType, float position) {
|
2016-07-28 14:43:40 -07:00
|
|
|
if (style.position.set(spacingType, position)) {
|
|
|
|
dirty();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-21 10:37:09 +01:00
|
|
|
/**
|
|
|
|
* Get this node's position top, as defined by style.
|
|
|
|
*/
|
|
|
|
public float getPositionTop() {
|
2016-07-28 14:43:40 -07:00
|
|
|
return style.position.get(TOP);
|
2015-10-21 10:37:09 +01:00
|
|
|
}
|
|
|
|
|
2014-09-18 15:15:21 -07:00
|
|
|
public void setPositionTop(float positionTop) {
|
2016-07-29 10:30:34 -07:00
|
|
|
setPositionValue(TOP, positionTop);
|
2014-09-18 15:15:21 -07:00
|
|
|
}
|
|
|
|
|
2015-10-21 10:37:09 +01:00
|
|
|
/**
|
|
|
|
* Get this node's position bottom, as defined by style.
|
|
|
|
*/
|
|
|
|
public float getPositionBottom() {
|
2016-07-28 14:43:40 -07:00
|
|
|
return style.position.get(BOTTOM);
|
2015-10-21 10:37:09 +01:00
|
|
|
}
|
|
|
|
|
2014-09-18 15:15:21 -07:00
|
|
|
public void setPositionBottom(float positionBottom) {
|
2016-07-29 10:30:34 -07:00
|
|
|
setPositionValue(BOTTOM, positionBottom);
|
2014-09-18 15:15:21 -07:00
|
|
|
}
|
|
|
|
|
2015-10-21 10:37:09 +01:00
|
|
|
/**
|
|
|
|
* Get this node's position left, as defined by style.
|
|
|
|
*/
|
|
|
|
public float getPositionLeft() {
|
2016-07-28 14:43:40 -07:00
|
|
|
return style.position.get(LEFT);
|
2015-10-21 10:37:09 +01:00
|
|
|
}
|
|
|
|
|
2014-09-18 15:15:21 -07:00
|
|
|
public void setPositionLeft(float positionLeft) {
|
2016-07-29 10:30:34 -07:00
|
|
|
setPositionValue(LEFT, positionLeft);
|
2014-09-18 15:15:21 -07:00
|
|
|
}
|
|
|
|
|
2015-10-21 10:37:09 +01:00
|
|
|
/**
|
|
|
|
* Get this node's position right, as defined by style.
|
|
|
|
*/
|
|
|
|
public float getPositionRight() {
|
2016-07-28 14:43:40 -07:00
|
|
|
return style.position.get(RIGHT);
|
2015-10-21 10:37:09 +01:00
|
|
|
}
|
|
|
|
|
2014-09-18 15:15:21 -07:00
|
|
|
public void setPositionRight(float positionRight) {
|
2016-07-29 10:30:34 -07:00
|
|
|
setPositionValue(RIGHT, positionRight);
|
2014-09-18 15:15:21 -07:00
|
|
|
}
|
|
|
|
|
2015-10-21 10:45:33 +01:00
|
|
|
/**
|
|
|
|
* Get this node's width, as defined in the style.
|
|
|
|
*/
|
|
|
|
public float getStyleWidth() {
|
|
|
|
return style.dimensions[DIMENSION_WIDTH];
|
|
|
|
}
|
|
|
|
|
2014-09-18 15:15:21 -07:00
|
|
|
public void setStyleWidth(float width) {
|
2015-09-04 13:50:28 +01:00
|
|
|
if (!valuesEqual(style.dimensions[DIMENSION_WIDTH], width)) {
|
|
|
|
style.dimensions[DIMENSION_WIDTH] = width;
|
2014-10-08 15:42:51 -07:00
|
|
|
dirty();
|
|
|
|
}
|
2014-09-18 15:15:21 -07:00
|
|
|
}
|
|
|
|
|
2015-10-21 10:45:33 +01:00
|
|
|
/**
|
|
|
|
* Get this node's height, as defined in the style.
|
|
|
|
*/
|
|
|
|
public float getStyleHeight() {
|
|
|
|
return style.dimensions[DIMENSION_HEIGHT];
|
|
|
|
}
|
|
|
|
|
2014-09-18 15:15:21 -07:00
|
|
|
public void setStyleHeight(float height) {
|
2015-09-04 13:50:28 +01:00
|
|
|
if (!valuesEqual(style.dimensions[DIMENSION_HEIGHT], height)) {
|
|
|
|
style.dimensions[DIMENSION_HEIGHT] = height;
|
2014-10-08 15:42:51 -07:00
|
|
|
dirty();
|
|
|
|
}
|
2014-09-18 15:15:21 -07:00
|
|
|
}
|
|
|
|
|
2016-06-01 12:48:51 -07:00
|
|
|
/**
|
|
|
|
* Get this node's max width, as defined in the style
|
|
|
|
*/
|
|
|
|
public float getStyleMaxWidth() {
|
|
|
|
return style.maxWidth;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setStyleMaxWidth(float maxWidth) {
|
|
|
|
if (!valuesEqual(style.maxWidth, maxWidth)) {
|
|
|
|
style.maxWidth = maxWidth;
|
|
|
|
dirty();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get this node's min width, as defined in the style
|
|
|
|
*/
|
|
|
|
public float getStyleMinWidth() {
|
|
|
|
return style.minWidth;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setStyleMinWidth(float minWidth) {
|
|
|
|
if (!valuesEqual(style.minWidth, minWidth)) {
|
|
|
|
style.minWidth = minWidth;
|
|
|
|
dirty();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get this node's max height, as defined in the style
|
|
|
|
*/
|
|
|
|
public float getStyleMaxHeight() {
|
|
|
|
return style.maxHeight;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setStyleMaxHeight(float maxHeight) {
|
|
|
|
if (!valuesEqual(style.maxHeight, maxHeight)) {
|
|
|
|
style.maxHeight = maxHeight;
|
|
|
|
dirty();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get this node's min height, as defined in the style
|
|
|
|
*/
|
|
|
|
public float getStyleMinHeight() {
|
|
|
|
return style.minHeight;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setStyleMinHeight(float minHeight) {
|
|
|
|
if (!valuesEqual(style.minHeight, minHeight)) {
|
|
|
|
style.minHeight = minHeight;
|
|
|
|
dirty();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-18 15:15:21 -07:00
|
|
|
public float getLayoutX() {
|
2015-09-04 13:50:28 +01:00
|
|
|
return layout.position[POSITION_LEFT];
|
2014-09-18 15:15:21 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
public float getLayoutY() {
|
2015-09-04 13:50:28 +01:00
|
|
|
return layout.position[POSITION_TOP];
|
2014-09-18 15:15:21 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
public float getLayoutWidth() {
|
2015-09-04 13:50:28 +01:00
|
|
|
return layout.dimensions[DIMENSION_WIDTH];
|
2014-09-18 15:15:21 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
public float getLayoutHeight() {
|
2015-09-04 13:50:28 +01:00
|
|
|
return layout.dimensions[DIMENSION_HEIGHT];
|
2014-09-18 15:15:21 -07:00
|
|
|
}
|
2015-05-14 13:59:13 +01:00
|
|
|
|
2015-05-20 11:12:24 +01:00
|
|
|
public CSSDirection getLayoutDirection() {
|
|
|
|
return layout.direction;
|
|
|
|
}
|
|
|
|
|
2015-05-14 13:59:13 +01:00
|
|
|
/**
|
|
|
|
* Set a default padding (left/top/right/bottom) for this node.
|
|
|
|
*/
|
|
|
|
public void setDefaultPadding(int spacingType, float padding) {
|
|
|
|
if (style.padding.setDefault(spacingType, padding)) {
|
|
|
|
dirty();
|
|
|
|
}
|
|
|
|
}
|
2015-10-05 16:26:59 +01:00
|
|
|
|
2016-06-01 12:48:51 -07:00
|
|
|
/**
|
|
|
|
* Get this node's overflow property, as defined in the style
|
|
|
|
*/
|
|
|
|
public CSSOverflow getOverflow() {
|
|
|
|
return style.overflow;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setOverflow(CSSOverflow overflow) {
|
|
|
|
if (style.overflow != overflow) {
|
|
|
|
style.overflow = overflow;
|
|
|
|
dirty();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-05 16:26:59 +01:00
|
|
|
/**
|
|
|
|
* Resets this instance to its default state. This method is meant to be used when
|
|
|
|
* recycling {@link CSSNode} instances.
|
|
|
|
*/
|
|
|
|
public void reset() {
|
|
|
|
if (mParent != null || (mChildren != null && mChildren.size() > 0)) {
|
|
|
|
throw new IllegalStateException("You should not reset an attached CSSNode");
|
|
|
|
}
|
|
|
|
|
|
|
|
style.reset();
|
|
|
|
layout.resetResult();
|
|
|
|
lineIndex = 0;
|
|
|
|
mLayoutState = LayoutState.DIRTY;
|
|
|
|
}
|
2014-09-18 15:15:21 -07:00
|
|
|
}
|