/** * Copyright (c) 2015-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.react.uimanager; import com.facebook.yoga.YogaConstants; 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 start direction e.g. left in left-to-right, right in right-to-left. */ public static final int START = 4; /** * Spacing type that represents end direction e.g. right in left-to-right, left in right-to-left. */ public static final int END = 5; /** * Spacing type that represents horizontal direction (left and right). E.g. * {@code marginHorizontal}. */ public static final int HORIZONTAL = 6; /** * Spacing type that represents vertical direction (top and bottom). E.g. {@code marginVertical}. */ public static final int VERTICAL = 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, /*START*/ 32, /*END*/ 64, /*HORIZONTAL*/ 128, /*VERTICAL*/ 256, /*ALL*/ }; private final float[] mSpacing = newFullSpacingArray(); private int mValueFlags = 0; private float mDefaultValue; private boolean mHasAliasesSet; public Spacing() { this(0); } public Spacing(float defaultValue) { mDefaultValue = defaultValue; } /** * 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 (YogaConstants.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; } /** * 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 = (spacingType == START || spacingType == END ? YogaConstants.UNDEFINED : mDefaultValue); 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. */ public void reset() { Arrays.fill(mSpacing, YogaConstants.UNDEFINED); 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[] { YogaConstants.UNDEFINED, YogaConstants.UNDEFINED, YogaConstants.UNDEFINED, YogaConstants.UNDEFINED, YogaConstants.UNDEFINED, YogaConstants.UNDEFINED, YogaConstants.UNDEFINED, YogaConstants.UNDEFINED, YogaConstants.UNDEFINED, }; } }