Import new C source of truth css-layout
fbshipit-source-id: e866918d6c62fc1cf3a04c269f782b94db9b875a
This commit is contained in:
18
java/com/facebook/csslayout/CSSAlign.java
Normal file
18
java/com/facebook/csslayout/CSSAlign.java
Normal file
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* Copyright (c) 2014-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
package com.facebook.csslayout;
|
||||
|
||||
public enum CSSAlign {
|
||||
AUTO,
|
||||
FLEX_START,
|
||||
CENTER,
|
||||
FLEX_END,
|
||||
STRETCH,
|
||||
}
|
20
java/com/facebook/csslayout/CSSCachedMeasurement.java
Normal file
20
java/com/facebook/csslayout/CSSCachedMeasurement.java
Normal file
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* Copyright (c) 2014-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
package com.facebook.csslayout;
|
||||
|
||||
public class CSSCachedMeasurement {
|
||||
public float availableWidth;
|
||||
public float availableHeight;
|
||||
public CSSMeasureMode widthMeasureMode = null;
|
||||
public CSSMeasureMode heightMeasureMode = null;
|
||||
|
||||
public float computedWidth;
|
||||
public float computedHeight;
|
||||
}
|
19
java/com/facebook/csslayout/CSSConstants.java
Normal file
19
java/com/facebook/csslayout/CSSConstants.java
Normal file
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* Copyright (c) 2014-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
package com.facebook.csslayout;
|
||||
|
||||
public class CSSConstants {
|
||||
|
||||
public static final float UNDEFINED = Float.NaN;
|
||||
|
||||
public static boolean isUndefined(float value) {
|
||||
return Float.compare(value, UNDEFINED) == 0;
|
||||
}
|
||||
}
|
16
java/com/facebook/csslayout/CSSDirection.java
Normal file
16
java/com/facebook/csslayout/CSSDirection.java
Normal file
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* Copyright (c) 2014-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
package com.facebook.csslayout;
|
||||
|
||||
public enum CSSDirection {
|
||||
INHERIT,
|
||||
LTR,
|
||||
RTL,
|
||||
}
|
17
java/com/facebook/csslayout/CSSFlexDirection.java
Normal file
17
java/com/facebook/csslayout/CSSFlexDirection.java
Normal file
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* Copyright (c) 2014-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
package com.facebook.csslayout;
|
||||
|
||||
public enum CSSFlexDirection {
|
||||
COLUMN,
|
||||
COLUMN_REVERSE,
|
||||
ROW,
|
||||
ROW_REVERSE
|
||||
}
|
18
java/com/facebook/csslayout/CSSJustify.java
Normal file
18
java/com/facebook/csslayout/CSSJustify.java
Normal file
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* Copyright (c) 2014-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
package com.facebook.csslayout;
|
||||
|
||||
public enum CSSJustify {
|
||||
FLEX_START,
|
||||
CENTER,
|
||||
FLEX_END,
|
||||
SPACE_BETWEEN,
|
||||
SPACE_AROUND,
|
||||
}
|
77
java/com/facebook/csslayout/CSSLayout.java
Normal file
77
java/com/facebook/csslayout/CSSLayout.java
Normal file
@@ -0,0 +1,77 @@
|
||||
/**
|
||||
* Copyright (c) 2014-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
package com.facebook.csslayout;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Where the output of {@link LayoutEngine#layoutNode(CSSNode, float)} will go in the CSSNode.
|
||||
*/
|
||||
public class CSSLayout {
|
||||
// This value was chosen based on empiracle data. Even the most complicated
|
||||
// layouts should not require more than 16 entries to fit within the cache.
|
||||
public static final int MAX_CACHED_RESULT_COUNT = 16;
|
||||
|
||||
public static final int POSITION_LEFT = 0;
|
||||
public static final int POSITION_TOP = 1;
|
||||
public static final int POSITION_RIGHT = 2;
|
||||
public static final int POSITION_BOTTOM = 3;
|
||||
|
||||
public static final int DIMENSION_WIDTH = 0;
|
||||
public static final int DIMENSION_HEIGHT = 1;
|
||||
|
||||
public float[] position = new float[4];
|
||||
public float[] dimensions = new float[2];
|
||||
public CSSDirection direction = CSSDirection.LTR;
|
||||
|
||||
public float flexBasis;
|
||||
|
||||
public int generationCount;
|
||||
public CSSDirection lastParentDirection;
|
||||
|
||||
public int nextCachedMeasurementsIndex;
|
||||
public CSSCachedMeasurement[] cachedMeasurements = new CSSCachedMeasurement[MAX_CACHED_RESULT_COUNT];
|
||||
public float[] measuredDimensions = new float[2];
|
||||
|
||||
public CSSCachedMeasurement cachedLayout = new CSSCachedMeasurement();
|
||||
|
||||
CSSLayout() {
|
||||
resetResult();
|
||||
}
|
||||
|
||||
public void resetResult() {
|
||||
Arrays.fill(position, 0);
|
||||
Arrays.fill(dimensions, CSSConstants.UNDEFINED);
|
||||
direction = CSSDirection.LTR;
|
||||
|
||||
flexBasis = 0;
|
||||
|
||||
generationCount = 0;
|
||||
lastParentDirection = null;
|
||||
|
||||
nextCachedMeasurementsIndex = 0;
|
||||
measuredDimensions[DIMENSION_WIDTH] = CSSConstants.UNDEFINED;
|
||||
measuredDimensions[DIMENSION_HEIGHT] = CSSConstants.UNDEFINED;
|
||||
|
||||
cachedLayout.widthMeasureMode = null;
|
||||
cachedLayout.heightMeasureMode = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "layout: {" +
|
||||
"left: " + position[POSITION_LEFT] + ", " +
|
||||
"top: " + position[POSITION_TOP] + ", " +
|
||||
"width: " + dimensions[DIMENSION_WIDTH] + ", " +
|
||||
"height: " + dimensions[DIMENSION_HEIGHT] + ", " +
|
||||
"direction: " + direction +
|
||||
"}";
|
||||
}
|
||||
}
|
22
java/com/facebook/csslayout/CSSLayoutContext.java
Normal file
22
java/com/facebook/csslayout/CSSLayoutContext.java
Normal file
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* Copyright (c) 2014-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
package com.facebook.csslayout;
|
||||
|
||||
/**
|
||||
* A context for holding values local to a given instance of layout computation.
|
||||
*
|
||||
* This is necessary for making layout thread-safe. A separate instance should
|
||||
* be used when {@link CSSNode#calculateLayout} is called concurrently on
|
||||
* different node hierarchies.
|
||||
*/
|
||||
public class CSSLayoutContext {
|
||||
/*package*/ final MeasureOutput measureOutput = new MeasureOutput();
|
||||
int currentGenerationCount;
|
||||
}
|
16
java/com/facebook/csslayout/CSSMeasureMode.java
Normal file
16
java/com/facebook/csslayout/CSSMeasureMode.java
Normal file
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* Copyright (c) 2014-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
package com.facebook.csslayout;
|
||||
|
||||
public enum CSSMeasureMode {
|
||||
UNDEFINED,
|
||||
EXACTLY,
|
||||
AT_MOST,
|
||||
}
|
573
java/com/facebook/csslayout/CSSNode.java
Normal file
573
java/com/facebook/csslayout/CSSNode.java
Normal file
@@ -0,0 +1,573 @@
|
||||
/**
|
||||
* Copyright (c) 2014-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
package com.facebook.csslayout;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import com.facebook.infer.annotation.Assertions;
|
||||
|
||||
import static com.facebook.csslayout.CSSLayout.DIMENSION_HEIGHT;
|
||||
import static com.facebook.csslayout.CSSLayout.DIMENSION_WIDTH;
|
||||
import static com.facebook.csslayout.CSSLayout.POSITION_BOTTOM;
|
||||
import static com.facebook.csslayout.CSSLayout.POSITION_LEFT;
|
||||
import static com.facebook.csslayout.CSSLayout.POSITION_RIGHT;
|
||||
import static com.facebook.csslayout.CSSLayout.POSITION_TOP;
|
||||
|
||||
/**
|
||||
* 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,
|
||||
|
||||
/**
|
||||
* This node has a new layout relative to the last time {@link #markLayoutSeen()} was called.
|
||||
*/
|
||||
HAS_NEW_LAYOUT,
|
||||
|
||||
/**
|
||||
* {@link #layout} is valid for the node's properties and this layout has been marked as
|
||||
* having been seen.
|
||||
*/
|
||||
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!
|
||||
*/
|
||||
public void measure(CSSNode node, float width, CSSMeasureMode widthMode, float height, CSSMeasureMode heightMode, MeasureOutput measureOutput);
|
||||
}
|
||||
|
||||
// VisibleForTesting
|
||||
/*package*/ final CSSStyle style = new CSSStyle();
|
||||
/*package*/ final CSSLayout layout = new CSSLayout();
|
||||
/*package*/ final CachedCSSLayout lastLayout = new CachedCSSLayout();
|
||||
|
||||
public int lineIndex = 0;
|
||||
|
||||
/*package*/ CSSNode nextChild;
|
||||
|
||||
private @Nullable ArrayList<CSSNode> mChildren;
|
||||
private @Nullable CSSNode mParent;
|
||||
private @Nullable MeasureFunction mMeasureFunction = null;
|
||||
private LayoutState mLayoutState = LayoutState.DIRTY;
|
||||
private boolean mIsTextNode = false;
|
||||
|
||||
public int getChildCount() {
|
||||
return mChildren == null ? 0 : mChildren.size();
|
||||
}
|
||||
|
||||
public CSSNode getChildAt(int i) {
|
||||
Assertions.assertNotNull(mChildren);
|
||||
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.");
|
||||
}
|
||||
if (mChildren == null) {
|
||||
// 4 is kinda arbitrary, but the default of 10 seems really high for an average View.
|
||||
mChildren = new ArrayList<>(4);
|
||||
}
|
||||
|
||||
mChildren.add(i, child);
|
||||
child.mParent = this;
|
||||
dirty();
|
||||
}
|
||||
|
||||
public CSSNode removeChildAt(int i) {
|
||||
Assertions.assertNotNull(mChildren);
|
||||
CSSNode removed = mChildren.remove(i);
|
||||
removed.mParent = null;
|
||||
dirty();
|
||||
return removed;
|
||||
}
|
||||
|
||||
public @Nullable CSSNode getParent() {
|
||||
return mParent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the index of the given child, or -1 if the child doesn't exist in this node.
|
||||
*/
|
||||
public int indexOf(CSSNode child) {
|
||||
Assertions.assertNotNull(mChildren);
|
||||
return mChildren.indexOf(child);
|
||||
}
|
||||
|
||||
public void setMeasureFunction(MeasureFunction measureFunction) {
|
||||
if (mMeasureFunction != measureFunction) {
|
||||
mMeasureFunction = measureFunction;
|
||||
dirty();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isMeasureDefined() {
|
||||
return mMeasureFunction != null;
|
||||
}
|
||||
|
||||
public void setIsTextNode(boolean isTextNode) {
|
||||
mIsTextNode = isTextNode;
|
||||
}
|
||||
|
||||
public boolean isTextNode() {
|
||||
return mIsTextNode;
|
||||
}
|
||||
|
||||
/*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, widthMode, height, heightMode, measureOutput);
|
||||
return measureOutput;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the actual layout and saves the results in {@link #layout}
|
||||
*/
|
||||
public void calculateLayout(CSSLayoutContext layoutContext) {
|
||||
LayoutEngine.layoutNode(layoutContext, this, CSSConstants.UNDEFINED, CSSConstants.UNDEFINED, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* See {@link LayoutState#DIRTY}.
|
||||
*/
|
||||
protected boolean isDirty() {
|
||||
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) {
|
||||
throw new IllegalStateException("Previous layout was ignored! markLayoutSeen() never called");
|
||||
}
|
||||
|
||||
mLayoutState = LayoutState.DIRTY;
|
||||
|
||||
if (mParent != null) {
|
||||
mParent.dirty();
|
||||
}
|
||||
}
|
||||
|
||||
/*package*/ void markHasNewLayout() {
|
||||
mLayoutState = LayoutState.HAS_NEW_LAYOUT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells the node that the current values in {@link #layout} have been seen. Subsequent calls
|
||||
* 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.
|
||||
*/
|
||||
public void markLayoutSeen() {
|
||||
if (!hasNewLayout()) {
|
||||
throw new IllegalStateException("Expected node to have a new layout to be seen!");
|
||||
}
|
||||
|
||||
mLayoutState = LayoutState.UP_TO_DATE;
|
||||
}
|
||||
|
||||
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());
|
||||
|
||||
if (getChildCount() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
result.append(", children: [\n");
|
||||
for (int i = 0; i < getChildCount(); i++) {
|
||||
getChildAt(i).toStringWithIndentation(result, level + 1);
|
||||
result.append("\n");
|
||||
}
|
||||
result.append(indentation + "]");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
this.toStringWithIndentation(sb, 0);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
protected boolean valuesEqual(float f1, float f2) {
|
||||
return FloatUtil.floatsEqual(f1, f2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get this node's direction, as defined in the style.
|
||||
*/
|
||||
public CSSDirection getStyleDirection() {
|
||||
return style.direction;
|
||||
}
|
||||
|
||||
public void setDirection(CSSDirection direction) {
|
||||
if (style.direction != direction) {
|
||||
style.direction = direction;
|
||||
dirty();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get this node's flex direction, as defined by style.
|
||||
*/
|
||||
public CSSFlexDirection getFlexDirection() {
|
||||
return style.flexDirection;
|
||||
}
|
||||
|
||||
public void setFlexDirection(CSSFlexDirection flexDirection) {
|
||||
if (style.flexDirection != flexDirection) {
|
||||
style.flexDirection = flexDirection;
|
||||
dirty();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get this node's justify content, as defined by style.
|
||||
*/
|
||||
public CSSJustify getJustifyContent() {
|
||||
return style.justifyContent;
|
||||
}
|
||||
|
||||
public void setJustifyContent(CSSJustify justifyContent) {
|
||||
if (style.justifyContent != justifyContent) {
|
||||
style.justifyContent = justifyContent;
|
||||
dirty();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get this node's align items, as defined by style.
|
||||
*/
|
||||
public CSSAlign getAlignItems() {
|
||||
return style.alignItems;
|
||||
}
|
||||
|
||||
public void setAlignItems(CSSAlign alignItems) {
|
||||
if (style.alignItems != alignItems) {
|
||||
style.alignItems = alignItems;
|
||||
dirty();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get this node's align items, as defined by style.
|
||||
*/
|
||||
public CSSAlign getAlignSelf() {
|
||||
return style.alignSelf;
|
||||
}
|
||||
|
||||
public void setAlignSelf(CSSAlign alignSelf) {
|
||||
if (style.alignSelf != alignSelf) {
|
||||
style.alignSelf = alignSelf;
|
||||
dirty();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get this node's position type, as defined by style.
|
||||
*/
|
||||
public CSSPositionType getPositionType() {
|
||||
return style.positionType;
|
||||
}
|
||||
|
||||
public void setPositionType(CSSPositionType positionType) {
|
||||
if (style.positionType != positionType) {
|
||||
style.positionType = positionType;
|
||||
dirty();
|
||||
}
|
||||
}
|
||||
|
||||
public void setWrap(CSSWrap flexWrap) {
|
||||
if (style.flexWrap != flexWrap) {
|
||||
style.flexWrap = flexWrap;
|
||||
dirty();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get this node's flex, as defined by style.
|
||||
*/
|
||||
public float getFlex() {
|
||||
return style.flex;
|
||||
}
|
||||
|
||||
public void setFlex(float flex) {
|
||||
if (!valuesEqual(style.flex, flex)) {
|
||||
style.flex = flex;
|
||||
dirty();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get this node's margin, as defined by style + default margin.
|
||||
*/
|
||||
public Spacing getMargin() {
|
||||
return style.margin;
|
||||
}
|
||||
|
||||
public void setMargin(int spacingType, float margin) {
|
||||
if (style.margin.set(spacingType, margin)) {
|
||||
dirty();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get this node's padding, as defined by style + default padding.
|
||||
*/
|
||||
public Spacing getPadding() {
|
||||
return style.padding;
|
||||
}
|
||||
|
||||
public void setPadding(int spacingType, float padding) {
|
||||
if (style.padding.set(spacingType, padding)) {
|
||||
dirty();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get this node's border, as defined by style.
|
||||
*/
|
||||
public Spacing getBorder() {
|
||||
return style.border;
|
||||
}
|
||||
|
||||
public void setBorder(int spacingType, float border) {
|
||||
if (style.border.set(spacingType, border)) {
|
||||
dirty();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get this node's position top, as defined by style.
|
||||
*/
|
||||
public float getPositionTop() {
|
||||
return style.position[POSITION_TOP];
|
||||
}
|
||||
|
||||
public void setPositionTop(float positionTop) {
|
||||
if (!valuesEqual(style.position[POSITION_TOP], positionTop)) {
|
||||
style.position[POSITION_TOP] = positionTop;
|
||||
dirty();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get this node's position bottom, as defined by style.
|
||||
*/
|
||||
public float getPositionBottom() {
|
||||
return style.position[POSITION_BOTTOM];
|
||||
}
|
||||
|
||||
public void setPositionBottom(float positionBottom) {
|
||||
if (!valuesEqual(style.position[POSITION_BOTTOM], positionBottom)) {
|
||||
style.position[POSITION_BOTTOM] = positionBottom;
|
||||
dirty();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get this node's position left, as defined by style.
|
||||
*/
|
||||
public float getPositionLeft() {
|
||||
return style.position[POSITION_LEFT];
|
||||
}
|
||||
|
||||
public void setPositionLeft(float positionLeft) {
|
||||
if (!valuesEqual(style.position[POSITION_LEFT], positionLeft)) {
|
||||
style.position[POSITION_LEFT] = positionLeft;
|
||||
dirty();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get this node's position right, as defined by style.
|
||||
*/
|
||||
public float getPositionRight() {
|
||||
return style.position[POSITION_RIGHT];
|
||||
}
|
||||
|
||||
public void setPositionRight(float positionRight) {
|
||||
if (!valuesEqual(style.position[POSITION_RIGHT], positionRight)) {
|
||||
style.position[POSITION_RIGHT] = positionRight;
|
||||
dirty();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get this node's width, as defined in the style.
|
||||
*/
|
||||
public float getStyleWidth() {
|
||||
return style.dimensions[DIMENSION_WIDTH];
|
||||
}
|
||||
|
||||
public void setStyleWidth(float width) {
|
||||
if (!valuesEqual(style.dimensions[DIMENSION_WIDTH], width)) {
|
||||
style.dimensions[DIMENSION_WIDTH] = width;
|
||||
dirty();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get this node's height, as defined in the style.
|
||||
*/
|
||||
public float getStyleHeight() {
|
||||
return style.dimensions[DIMENSION_HEIGHT];
|
||||
}
|
||||
|
||||
public void setStyleHeight(float height) {
|
||||
if (!valuesEqual(style.dimensions[DIMENSION_HEIGHT], height)) {
|
||||
style.dimensions[DIMENSION_HEIGHT] = height;
|
||||
dirty();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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();
|
||||
}
|
||||
}
|
||||
|
||||
public float getLayoutX() {
|
||||
return layout.position[POSITION_LEFT];
|
||||
}
|
||||
|
||||
public float getLayoutY() {
|
||||
return layout.position[POSITION_TOP];
|
||||
}
|
||||
|
||||
public float getLayoutWidth() {
|
||||
return layout.dimensions[DIMENSION_WIDTH];
|
||||
}
|
||||
|
||||
public float getLayoutHeight() {
|
||||
return layout.dimensions[DIMENSION_HEIGHT];
|
||||
}
|
||||
|
||||
public CSSDirection getLayoutDirection() {
|
||||
return layout.direction;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
15
java/com/facebook/csslayout/CSSOverflow.java
Normal file
15
java/com/facebook/csslayout/CSSOverflow.java
Normal file
@@ -0,0 +1,15 @@
|
||||
/**
|
||||
* Copyright (c) 2014-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
package com.facebook.csslayout;
|
||||
|
||||
public enum CSSOverflow {
|
||||
VISIBLE,
|
||||
HIDDEN,
|
||||
}
|
15
java/com/facebook/csslayout/CSSPositionType.java
Normal file
15
java/com/facebook/csslayout/CSSPositionType.java
Normal file
@@ -0,0 +1,15 @@
|
||||
/**
|
||||
* Copyright (c) 2014-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
package com.facebook.csslayout;
|
||||
|
||||
public enum CSSPositionType {
|
||||
RELATIVE,
|
||||
ABSOLUTE,
|
||||
}
|
72
java/com/facebook/csslayout/CSSStyle.java
Normal file
72
java/com/facebook/csslayout/CSSStyle.java
Normal file
@@ -0,0 +1,72 @@
|
||||
/**
|
||||
* Copyright (c) 2014-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
package com.facebook.csslayout;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* The CSS style definition for a {@link CSSNode}.
|
||||
*/
|
||||
public class CSSStyle {
|
||||
|
||||
public CSSDirection direction;
|
||||
public CSSFlexDirection flexDirection;
|
||||
public CSSJustify justifyContent;
|
||||
public CSSAlign alignContent;
|
||||
public CSSAlign alignItems;
|
||||
public CSSAlign alignSelf;
|
||||
public CSSPositionType positionType;
|
||||
public CSSWrap flexWrap;
|
||||
public CSSOverflow overflow;
|
||||
public float flex;
|
||||
|
||||
public Spacing margin = new Spacing();
|
||||
public Spacing padding = new Spacing();
|
||||
public Spacing border = new Spacing();
|
||||
|
||||
public float[] position = new float[4];
|
||||
public float[] dimensions = new float[2];
|
||||
|
||||
public float minWidth = CSSConstants.UNDEFINED;
|
||||
public float minHeight = CSSConstants.UNDEFINED;
|
||||
|
||||
public float maxWidth = CSSConstants.UNDEFINED;
|
||||
public float maxHeight = CSSConstants.UNDEFINED;
|
||||
|
||||
CSSStyle() {
|
||||
reset();
|
||||
}
|
||||
|
||||
void reset() {
|
||||
direction = CSSDirection.INHERIT;
|
||||
flexDirection = CSSFlexDirection.COLUMN;
|
||||
justifyContent = CSSJustify.FLEX_START;
|
||||
alignContent = CSSAlign.FLEX_START;
|
||||
alignItems = CSSAlign.STRETCH;
|
||||
alignSelf = CSSAlign.AUTO;
|
||||
positionType = CSSPositionType.RELATIVE;
|
||||
flexWrap = CSSWrap.NOWRAP;
|
||||
overflow = CSSOverflow.VISIBLE;
|
||||
flex = 0f;
|
||||
|
||||
margin.reset();;
|
||||
padding.reset();
|
||||
border.reset();
|
||||
|
||||
Arrays.fill(position, CSSConstants.UNDEFINED);
|
||||
Arrays.fill(dimensions, CSSConstants.UNDEFINED);
|
||||
|
||||
minWidth = CSSConstants.UNDEFINED;
|
||||
minHeight = CSSConstants.UNDEFINED;
|
||||
|
||||
maxWidth = CSSConstants.UNDEFINED;
|
||||
maxHeight = CSSConstants.UNDEFINED;
|
||||
}
|
||||
}
|
15
java/com/facebook/csslayout/CSSWrap.java
Normal file
15
java/com/facebook/csslayout/CSSWrap.java
Normal file
@@ -0,0 +1,15 @@
|
||||
/**
|
||||
* Copyright (c) 2014-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
package com.facebook.csslayout;
|
||||
|
||||
public enum CSSWrap {
|
||||
NOWRAP,
|
||||
WRAP,
|
||||
}
|
23
java/com/facebook/csslayout/CachedCSSLayout.java
Normal file
23
java/com/facebook/csslayout/CachedCSSLayout.java
Normal file
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* Copyright (c) 2014-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
package com.facebook.csslayout;
|
||||
|
||||
/**
|
||||
* CSSLayout with additional information about the conditions under which it was generated.
|
||||
* {@link #requestedWidth} and {@link #requestedHeight} are the width and height the parent set on
|
||||
* this node before calling layout visited us.
|
||||
*/
|
||||
public class CachedCSSLayout extends CSSLayout {
|
||||
|
||||
public float requestedWidth = CSSConstants.UNDEFINED;
|
||||
public float requestedHeight = CSSConstants.UNDEFINED;
|
||||
public float parentMaxWidth = CSSConstants.UNDEFINED;
|
||||
public float parentMaxHeight = CSSConstants.UNDEFINED;
|
||||
}
|
22
java/com/facebook/csslayout/FloatUtil.java
Normal file
22
java/com/facebook/csslayout/FloatUtil.java
Normal file
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* Copyright (c) 2014-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
package com.facebook.csslayout;
|
||||
|
||||
public class FloatUtil {
|
||||
|
||||
private static final float EPSILON = .00001f;
|
||||
|
||||
public static boolean floatsEqual(float f1, float f2) {
|
||||
if (Float.isNaN(f1) || Float.isNaN(f2)) {
|
||||
return Float.isNaN(f1) && Float.isNaN(f2);
|
||||
}
|
||||
return Math.abs(f2 - f1) < EPSILON;
|
||||
}
|
||||
}
|
1411
java/com/facebook/csslayout/LayoutEngine.java
Normal file
1411
java/com/facebook/csslayout/LayoutEngine.java
Normal file
File diff suppressed because it is too large
Load Diff
19
java/com/facebook/csslayout/MeasureOutput.java
Normal file
19
java/com/facebook/csslayout/MeasureOutput.java
Normal file
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* Copyright (c) 2014-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
package com.facebook.csslayout;
|
||||
|
||||
/**
|
||||
* POJO to hold the output of the measure function.
|
||||
*/
|
||||
public class MeasureOutput {
|
||||
|
||||
public float width;
|
||||
public float height;
|
||||
}
|
221
java/com/facebook/csslayout/Spacing.java
Normal file
221
java/com/facebook/csslayout/Spacing.java
Normal file
@@ -0,0 +1,221 @@
|
||||
/**
|
||||
* Copyright (c) 2014-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
package com.facebook.csslayout;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Class representing CSS spacing (padding, margin, and borders). This is mostly necessary to
|
||||
* properly implement interactions and updates for properties like margin, marginLeft, and
|
||||
* marginHorizontal.
|
||||
*/
|
||||
public class Spacing {
|
||||
|
||||
/**
|
||||
* Spacing type that represents the left direction. E.g. {@code marginLeft}.
|
||||
*/
|
||||
public static final int LEFT = 0;
|
||||
/**
|
||||
* Spacing type that represents the top direction. E.g. {@code marginTop}.
|
||||
*/
|
||||
public static final int TOP = 1;
|
||||
/**
|
||||
* Spacing type that represents the right direction. E.g. {@code marginRight}.
|
||||
*/
|
||||
public static final int RIGHT = 2;
|
||||
/**
|
||||
* Spacing type that represents the bottom direction. E.g. {@code marginBottom}.
|
||||
*/
|
||||
public static final int BOTTOM = 3;
|
||||
/**
|
||||
* Spacing type that represents vertical direction (top and bottom). E.g. {@code marginVertical}.
|
||||
*/
|
||||
public static final int VERTICAL = 4;
|
||||
/**
|
||||
* Spacing type that represents horizontal direction (left and right). E.g.
|
||||
* {@code marginHorizontal}.
|
||||
*/
|
||||
public static final int HORIZONTAL = 5;
|
||||
/**
|
||||
* Spacing type that represents start direction e.g. left in left-to-right, right in right-to-left.
|
||||
*/
|
||||
public static final int START = 6;
|
||||
/**
|
||||
* Spacing type that represents end direction e.g. right in left-to-right, left in right-to-left.
|
||||
*/
|
||||
public static final int END = 7;
|
||||
/**
|
||||
* Spacing type that represents all directions (left, top, right, bottom). E.g. {@code margin}.
|
||||
*/
|
||||
public static final int ALL = 8;
|
||||
|
||||
private static final int[] sFlagsMap = {
|
||||
1, /*LEFT*/
|
||||
2, /*TOP*/
|
||||
4, /*RIGHT*/
|
||||
8, /*BOTTOM*/
|
||||
16, /*VERTICAL*/
|
||||
32, /*HORIZONTAL*/
|
||||
64, /*START*/
|
||||
128, /*END*/
|
||||
256, /*ALL*/
|
||||
};
|
||||
|
||||
private final float[] mSpacing = newFullSpacingArray();
|
||||
@Nullable private float[] mDefaultSpacing = null;
|
||||
private int mValueFlags = 0;
|
||||
private boolean mHasAliasesSet;
|
||||
|
||||
/**
|
||||
* Set a spacing value.
|
||||
*
|
||||
* @param spacingType one of {@link #LEFT}, {@link #TOP}, {@link #RIGHT}, {@link #BOTTOM},
|
||||
* {@link #VERTICAL}, {@link #HORIZONTAL}, {@link #ALL}
|
||||
* @param value the value for this direction
|
||||
* @return {@code true} if the spacing has changed, or {@code false} if the same value was already
|
||||
* set
|
||||
*/
|
||||
public boolean set(int spacingType, float value) {
|
||||
if (!FloatUtil.floatsEqual(mSpacing[spacingType], value)) {
|
||||
mSpacing[spacingType] = value;
|
||||
|
||||
if (CSSConstants.isUndefined(value)) {
|
||||
mValueFlags &= ~sFlagsMap[spacingType];
|
||||
} else {
|
||||
mValueFlags |= sFlagsMap[spacingType];
|
||||
}
|
||||
|
||||
mHasAliasesSet =
|
||||
(mValueFlags & sFlagsMap[ALL]) != 0 ||
|
||||
(mValueFlags & sFlagsMap[VERTICAL]) != 0 ||
|
||||
(mValueFlags & sFlagsMap[HORIZONTAL]) != 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a default spacing value. This is used as a fallback when no spacing has been set for a
|
||||
* particular direction.
|
||||
*
|
||||
* @param spacingType one of {@link #LEFT}, {@link #TOP}, {@link #RIGHT}, {@link #BOTTOM}
|
||||
* @param value the default value for this direction
|
||||
* @return
|
||||
*/
|
||||
public boolean setDefault(int spacingType, float value) {
|
||||
if (mDefaultSpacing == null) {
|
||||
mDefaultSpacing = newSpacingResultArray();
|
||||
}
|
||||
if (!FloatUtil.floatsEqual(mDefaultSpacing[spacingType], value)) {
|
||||
mDefaultSpacing[spacingType] = value;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the spacing for a direction. This takes into account any default values that have been set.
|
||||
*
|
||||
* @param spacingType one of {@link #LEFT}, {@link #TOP}, {@link #RIGHT}, {@link #BOTTOM}
|
||||
*/
|
||||
public float get(int spacingType) {
|
||||
float defaultValue = (mDefaultSpacing != null)
|
||||
? mDefaultSpacing[spacingType]
|
||||
: (spacingType == START || spacingType == END ? CSSConstants.UNDEFINED : 0);
|
||||
|
||||
if (mValueFlags == 0) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
if ((mValueFlags & sFlagsMap[spacingType]) != 0) {
|
||||
return mSpacing[spacingType];
|
||||
}
|
||||
|
||||
if (mHasAliasesSet) {
|
||||
int secondType = spacingType == TOP || spacingType == BOTTOM ? VERTICAL : HORIZONTAL;
|
||||
if ((mValueFlags & sFlagsMap[secondType]) != 0) {
|
||||
return mSpacing[secondType];
|
||||
} else if ((mValueFlags & sFlagsMap[ALL]) != 0) {
|
||||
return mSpacing[ALL];
|
||||
}
|
||||
}
|
||||
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the raw value (that was set using {@link #set(int, float)}), without taking into account
|
||||
* any default values.
|
||||
*
|
||||
* @param spacingType one of {@link #LEFT}, {@link #TOP}, {@link #RIGHT}, {@link #BOTTOM},
|
||||
* {@link #VERTICAL}, {@link #HORIZONTAL}, {@link #ALL}
|
||||
*/
|
||||
public float getRaw(int spacingType) {
|
||||
return mSpacing[spacingType];
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the spacing instance to its default state. This method is meant to be used when
|
||||
* recycling {@link Spacing} instances.
|
||||
*/
|
||||
void reset() {
|
||||
Arrays.fill(mSpacing, CSSConstants.UNDEFINED);
|
||||
mDefaultSpacing = null;
|
||||
mHasAliasesSet = false;
|
||||
mValueFlags = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to get start value and fallback to given type if not defined. This is used privately
|
||||
* by the layout engine as a more efficient way to fetch direction-aware values by
|
||||
* avoid extra method invocations.
|
||||
*/
|
||||
float getWithFallback(int spacingType, int fallbackType) {
|
||||
return
|
||||
(mValueFlags & sFlagsMap[spacingType]) != 0
|
||||
? mSpacing[spacingType]
|
||||
: get(fallbackType);
|
||||
}
|
||||
|
||||
private static float[] newFullSpacingArray() {
|
||||
return new float[] {
|
||||
CSSConstants.UNDEFINED,
|
||||
CSSConstants.UNDEFINED,
|
||||
CSSConstants.UNDEFINED,
|
||||
CSSConstants.UNDEFINED,
|
||||
CSSConstants.UNDEFINED,
|
||||
CSSConstants.UNDEFINED,
|
||||
CSSConstants.UNDEFINED,
|
||||
CSSConstants.UNDEFINED,
|
||||
CSSConstants.UNDEFINED,
|
||||
};
|
||||
}
|
||||
|
||||
private static float[] newSpacingResultArray() {
|
||||
return newSpacingResultArray(0);
|
||||
}
|
||||
|
||||
private static float[] newSpacingResultArray(float defaultValue) {
|
||||
return new float[] {
|
||||
defaultValue,
|
||||
defaultValue,
|
||||
defaultValue,
|
||||
defaultValue,
|
||||
defaultValue,
|
||||
defaultValue,
|
||||
CSSConstants.UNDEFINED,
|
||||
CSSConstants.UNDEFINED,
|
||||
defaultValue,
|
||||
};
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user