| /** |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| #ifdef __cplusplus |
| |
| #ifndef WEEXCORE_FLEXLAYOUT_WXCORELAYOUTNODE_H |
| #define WEEXCORE_FLEXLAYOUT_WXCORELAYOUTNODE_H |
| |
| #include "style.h" |
| #include "flex_enum.h" |
| #include <vector> |
| #include <iostream> |
| #include <string> |
| #include <algorithm> |
| |
| namespace WeexCore { |
| |
| class WXCoreLayoutNode; |
| |
| class WXCoreFlexLine; |
| |
| enum FormattingContext { |
| kBFC, |
| kNonBFC, |
| } ; |
| |
| enum MeasureMode { |
| kUnspecified = 0, |
| kExactly, |
| } ; |
| |
| struct WXCoreSize { |
| private: |
| float hypotheticalWidth; |
| float hypotheticalHeight; |
| public: |
| friend class WXCoreLayoutNode; |
| float width; |
| float height; |
| |
| WXCoreSize() : hypotheticalWidth(NAN), |
| hypotheticalHeight(NAN), |
| width(0), height(0) {} |
| |
| inline void reset() { |
| hypotheticalWidth = NAN ; |
| hypotheticalHeight = NAN; |
| width = 0; |
| height = 0; |
| } |
| |
| inline bool isNAN() { |
| return isnan(width) || isnan(height); |
| } |
| }; |
| |
| /** |
| * layout-result:layout-height、layout-width、position(left、right、top、bottom) |
| */ |
| struct WXCorelayoutResult { |
| WXCoreSize mLayoutSize; |
| WXCorePosition mLayoutPosition; |
| |
| inline bool isNAN() { |
| return mLayoutSize.isNAN() || mLayoutPosition.isNAN(); |
| } |
| |
| inline void reset() { |
| mLayoutSize.reset(); |
| mLayoutPosition.reset(); |
| } |
| }; |
| |
| typedef WXCoreSize(*WXCoreMeasureFunc)(WXCoreLayoutNode *node, float width, |
| MeasureMode widthMeasureMode, |
| float height, MeasureMode heightMeasureMode); |
| |
| using Index = std::vector<WXCoreLayoutNode *>::size_type; |
| |
| /** |
| * flie line |
| */ |
| class WXCoreFlexLine { |
| public: |
| float mMainSize; |
| |
| float mCrossSize; |
| |
| Index mItemCount; |
| |
| float mTotalFlexGrow; |
| |
| float mTotalFlexibleSize; |
| |
| /** |
| * Store the indices of the children views whose mAlignSelf property is stretch. |
| * The stored indices are the absolute indices including all children in the Flexbox, |
| * not the relative indices in this flex line. |
| */ |
| std::vector<Index> mIndicesAlignSelfStretch; |
| |
| WXCoreFlexLine() : mMainSize(0), |
| mCrossSize(0), |
| mItemCount(0), |
| mTotalFlexGrow(0), |
| mTotalFlexibleSize(0) { |
| } |
| |
| ~WXCoreFlexLine() { |
| mMainSize = 0; |
| mCrossSize = 0; |
| mItemCount = 0; |
| mTotalFlexGrow = 0; |
| mTotalFlexibleSize = 0; |
| mIndicesAlignSelfStretch.clear(); |
| } |
| }; |
| |
| /** |
| * Layout node |
| */ |
| class WXCoreLayoutNode { |
| |
| public: |
| WXCoreLayoutNode() : |
| mParent(nullptr), |
| dirty(true), |
| widthDirty{false}, |
| heightDirty{false}, |
| mHasNewLayout(true), |
| mIsDestroy(false), |
| measureFunc(nullptr) { |
| mCssStyle = new WXCoreCSSStyle(); |
| mLayoutResult = new WXCorelayoutResult(); |
| } |
| |
| |
| virtual ~WXCoreLayoutNode() { |
| mIsDestroy = true; |
| mHasNewLayout = true; |
| dirty = true; |
| measureFunc = nullptr; |
| mParent = nullptr; |
| mChildList.clear(); |
| BFCs.clear(); |
| NonBFCs.clear(); |
| mChildrenFrozen.clear(); |
| |
| for (WXCoreFlexLine *flexLine : mFlexLines) { |
| if (flexLine != nullptr) { |
| delete flexLine; |
| flexLine = nullptr; |
| } |
| } |
| mFlexLines.clear(); |
| |
| if (mCssStyle != nullptr) { |
| delete mCssStyle; |
| mCssStyle = nullptr; |
| } |
| |
| if (mLayoutResult != nullptr) { |
| delete mLayoutResult; |
| mLayoutResult = nullptr; |
| } |
| } |
| |
| private: |
| |
| /** |
| * Holds the 'frozen' state of children during measure. If a view is frozen it will no longer |
| * expand regardless of mFlexGrow. Items are indexed by the child's |
| * reordered index. |
| */ |
| std::vector<bool> mChildrenFrozen; |
| |
| std::vector<WXCoreFlexLine *> mFlexLines; |
| |
| std::vector<WXCoreLayoutNode *> mChildList; |
| |
| std::vector<WXCoreLayoutNode *> BFCs; |
| |
| std::vector<WXCoreLayoutNode *> NonBFCs; |
| |
| WXCoreLayoutNode *mParent = nullptr; |
| |
| WXCoreCSSStyle *mCssStyle = nullptr; |
| |
| MeasureMode widthMeasureMode = kUnspecified; |
| |
| MeasureMode heightMeasureMode = kUnspecified; |
| |
| WXCorelayoutResult *mLayoutResult = nullptr; |
| |
| WXCorePosition *absoultePositon = nullptr; |
| |
| bool mHasNewLayout; |
| |
| bool dirty, widthDirty, heightDirty; |
| |
| bool mIsDestroy = true; |
| |
| bool mNeedsPlatformDependentLayout = false; |
| |
| WXCoreMeasureFunc measureFunc = nullptr; |
| |
| void *context = nullptr; |
| |
| /** ================================ Cache:Last calculate result =================================== **/ |
| |
| public: |
| |
| |
| /** ================================ Engine Entry Function =================================== **/ |
| |
| void calculateLayout(const std::pair<float,float>&); |
| |
| /** ================================ measureFunc =================================== **/ |
| |
| inline void setMeasureFunc(WXCoreMeasureFunc measure) { |
| measureFunc = measure; |
| markDirty(); |
| } |
| |
| inline bool haveMeasureFunc() const { |
| return nullptr != measureFunc; |
| } |
| |
| inline WXCoreMeasureFunc getMeasureFunc() const { |
| return measureFunc; |
| } |
| |
| /** ================================ context =================================== **/ |
| |
| |
| inline void *getContext() const { |
| return context; |
| } |
| |
| inline void setContext(void * const context) { |
| this->context = context; |
| } |
| |
| inline void copyStyle(WXCoreLayoutNode *srcNode) { |
| if (memcmp(mCssStyle, srcNode->mCssStyle, sizeof(WXCoreCSSStyle)) != 0) { |
| memcpy(mCssStyle, srcNode->mCssStyle, sizeof(WXCoreCSSStyle)); |
| markDirty(); |
| } |
| } |
| |
| void copyFrom(WXCoreLayoutNode* srcNode){ |
| memcpy(mCssStyle, srcNode->mCssStyle, sizeof(WXCoreCSSStyle)); |
| } |
| |
| inline void copyMeasureFunc(WXCoreLayoutNode *srcNode) { |
| if (memcmp(&measureFunc, &srcNode->measureFunc, sizeof(WXCoreMeasureFunc)) != 0) { |
| memcpy(&measureFunc, &srcNode->measureFunc, sizeof(WXCoreMeasureFunc)); |
| markDirty(); |
| } |
| } |
| |
| /** ================================ custom =================================== **/ |
| inline bool getNeedsPlatformDependentLayout() const { |
| return mNeedsPlatformDependentLayout; |
| } |
| |
| inline void setNeedsPlatformDependentLayout(bool v) { |
| this->mNeedsPlatformDependentLayout = v; |
| } |
| |
| private: |
| |
| /** ================================ measure =================================== **/ |
| |
| inline void reset() { |
| if (isDirty()) { |
| mLayoutResult->reset(); |
| for (WXCoreFlexLine *flexLine : mFlexLines) { |
| if (flexLine != nullptr) { |
| delete flexLine; |
| flexLine = nullptr; |
| } |
| } |
| mFlexLines.clear(); |
| |
| mChildrenFrozen.assign(getChildCount(kNonBFC), false); |
| } |
| widthMeasureMode = isnan(mCssStyle->mStyleWidth) ? kUnspecified : kExactly; |
| heightMeasureMode = isnan(mCssStyle->mStyleHeight) ? kUnspecified : kExactly; |
| } |
| |
| inline void setLayoutWidth(const float width) { |
| if (mLayoutResult->mLayoutSize.width != width && |
| (!isnan(width) || !isnan(mLayoutResult->mLayoutSize.width))) { |
| mLayoutResult->mLayoutSize.width = width; |
| widthDirty = true; |
| markDirty(false); |
| } |
| } |
| |
| inline void setLayoutHeight(const float height) { |
| if (mLayoutResult->mLayoutSize.height != height && |
| (!isnan(height) || !isnan(mLayoutResult->mLayoutSize.height))) { |
| mLayoutResult->mLayoutSize.height = height; |
| heightDirty = true; |
| markDirty(false); |
| } |
| } |
| |
| inline void setWidthMeasureMode(const MeasureMode measureMode) { |
| if (widthMeasureMode != measureMode) { |
| widthMeasureMode = measureMode; |
| if (getChildCount(kNonBFC) > 0) { |
| widthDirty = true; |
| } |
| } |
| } |
| |
| inline void setHeightMeasureMode(const MeasureMode measureMode) { |
| if (heightMeasureMode != measureMode) { |
| heightMeasureMode = measureMode; |
| if (getChildCount(kNonBFC) > 0) { |
| heightDirty = true; |
| } |
| } |
| } |
| |
| inline float firstLineCrossSize() const { |
| float sum = sumPaddingBorderAlongAxis(this, !isMainAxisHorizontal(this)); |
| if (!mFlexLines.empty()) { |
| sum += mFlexLines[0]->mCrossSize; |
| } |
| return sum; |
| } |
| |
| inline float getSumOfCrossSize() const { |
| float sum = sumPaddingBorderAlongAxis(this, !isMainAxisHorizontal(this)); |
| for (WXCoreFlexLine *flexLine: mFlexLines) { |
| sum += flexLine->mCrossSize; |
| } |
| return sum; |
| } |
| |
| inline bool isMainAxisHorizontal(const WXCoreLayoutNode* const node) const { |
| return node->mCssStyle->mFlexDirection == kFlexDirectionRow || |
| node->mCssStyle->mFlexDirection == kFlexDirectionRowReverse; |
| } |
| |
| inline bool isCrossExactly() const { |
| return isMainAxisHorizontal(this) ? heightMeasureMode == kExactly |
| : widthMeasureMode == kExactly; |
| } |
| |
| inline float sumPaddingBorderAlongAxis(const WXCoreLayoutNode* const node, bool horizontal) const { |
| float paddingBorderAlongAxis; |
| if (horizontal) { |
| paddingBorderAlongAxis = |
| node->mCssStyle->mPadding.getPadding(kPaddingLeft) + |
| node->mCssStyle->mPadding.getPadding(kPaddingRight) + |
| node->mCssStyle->mBorderWidth.getBorderWidth(kBorderWidthLeft) + |
| node->mCssStyle->mBorderWidth.getBorderWidth(kBorderWidthRight); |
| } else { |
| paddingBorderAlongAxis = |
| node->mCssStyle->mPadding.getPadding(kPaddingTop) + |
| node->mCssStyle->mPadding.getPadding(kPaddingBottom) + |
| node->mCssStyle->mBorderWidth.getBorderWidth(kBorderWidthTop) + |
| node->mCssStyle->mBorderWidth.getBorderWidth(kBorderWidthBottom); |
| } |
| return paddingBorderAlongAxis; |
| } |
| |
| inline bool isWrapRequired(const float &width, const float &height, |
| const float ¤tLength, const float &childLength) const { |
| float freeMainSize = CalculateFreeSpaceAlongMainAxis(width, height, currentLength); |
| return !isSingleFlexLine(freeMainSize) && freeMainSize < childLength; |
| } |
| |
| //If width/height is NAN, ret is NAN, which property we use on purpose. |
| virtual float CalculateFreeSpaceAlongMainAxis(const float &width, const float &height, |
| const float ¤tLength) const{ |
| float ret; |
| if(isMainAxisHorizontal(this)){ |
| ret = width - sumPaddingBorderAlongAxis(this, true) - currentLength; |
| } |
| else{ |
| ret = height - sumPaddingBorderAlongAxis(this, false) - currentLength; |
| } |
| return ret; |
| } |
| |
| inline bool isSingleFlexLine(const float &mainSize) const { |
| return mCssStyle->mFlexWrap == kNoWrap || isnan(mainSize); |
| } |
| |
| inline void sumFlexGrow(const WXCoreLayoutNode* const child, WXCoreFlexLine* const flexLine, Index i){ |
| if (child->mCssStyle->mFlexGrow > 0) { |
| flexLine->mTotalFlexGrow += child->mCssStyle->mFlexGrow; |
| mChildrenFrozen[i] = false; |
| if (isMainAxisHorizontal(this)) { |
| if (!isnan(child->mLayoutResult->mLayoutSize.hypotheticalWidth)) { |
| flexLine->mTotalFlexibleSize += child->mLayoutResult->mLayoutSize.hypotheticalWidth; |
| } |
| } else { |
| if (!isnan(child->mLayoutResult->mLayoutSize.hypotheticalHeight)) { |
| flexLine->mTotalFlexibleSize += child->mLayoutResult->mLayoutSize.hypotheticalHeight; |
| } |
| } |
| } else { |
| mChildrenFrozen[i] = true; |
| } |
| } |
| |
| inline void setMeasuredDimensionForFlex( |
| const float width, const MeasureMode widthMeasureMode, |
| const float height, const MeasureMode heightMeasureMode){ |
| float actualWidth, actualHeight; |
| if (isMainAxisHorizontal(this)) { |
| actualWidth = widthMeasureMode == kExactly ? width : getLargestMainSize(); |
| actualHeight = heightMeasureMode == kExactly ? height : getSumOfCrossSize(); |
| } else { |
| actualHeight = heightMeasureMode == kExactly ? height : getLargestMainSize(); |
| actualWidth = widthMeasureMode == kExactly ? width : firstLineCrossSize(); |
| } |
| setMeasuredDimension(actualWidth, actualHeight); |
| } |
| |
| inline float calcItemSizeAlongAxis(const WXCoreLayoutNode* const node, const bool horizontal, const bool useHypotheticalSize = false) const { |
| float ret; |
| if (horizontal) { |
| ret = node->mCssStyle->mMargin.getMargin(kMarginLeft) + |
| node->mCssStyle->mMargin.getMargin(kMarginRight); |
| ret += useHypotheticalSize ? node->mLayoutResult->mLayoutSize.hypotheticalWidth |
| : node->mLayoutResult->mLayoutSize.width; |
| } else { |
| ret = node->mCssStyle->mMargin.getMargin(kMarginTop) + |
| node->mCssStyle->mMargin.getMargin(kMarginBottom); |
| ret += useHypotheticalSize ? node->mLayoutResult->mLayoutSize.hypotheticalHeight |
| : node->mLayoutResult->mLayoutSize.height; |
| } |
| return ret; |
| } |
| |
| inline void limitMainSizeForFlexGrow(WXCoreFlexLine* const flexLine, const Index childIndex, |
| const float flexGrow) { |
| mChildrenFrozen[childIndex] = true; |
| flexLine->mTotalFlexGrow -= flexGrow; |
| } |
| |
| inline void setMeasuredDimension(const float width, const float height) { |
| mLayoutResult->mLayoutSize.width = width; |
| mLayoutResult->mLayoutSize.height = height; |
| } |
| |
| inline std::pair<bool, float> limitChildMainSize(WXCoreFlexLine* const flexLine, const WXCoreLayoutNode* const child, |
| float childSizeAlongMainAxis, const Index childIndex){ |
| bool needsReexpand = false; |
| if (isMainAxisHorizontal(this)) { |
| if (!isnan(child->mCssStyle->mMaxWidth) && |
| childSizeAlongMainAxis > child->mCssStyle->mMaxWidth) { |
| needsReexpand = true; |
| childSizeAlongMainAxis = child->mCssStyle->mMaxWidth; |
| } else if (!isnan(child->mCssStyle->mMinWidth) && |
| childSizeAlongMainAxis < child->mCssStyle->mMinWidth) { |
| needsReexpand = true; |
| childSizeAlongMainAxis = child->mCssStyle->mMinWidth; |
| } |
| } else { |
| if (!isnan(child->mCssStyle->mMaxHeight) && |
| childSizeAlongMainAxis > child->mCssStyle->mMaxHeight) { |
| needsReexpand = true; |
| childSizeAlongMainAxis = child->mCssStyle->mMaxHeight; |
| } else if (!isnan(child->mCssStyle->mMinHeight) && |
| childSizeAlongMainAxis < child->mCssStyle->mMinHeight) { |
| needsReexpand = true; |
| childSizeAlongMainAxis = child->mCssStyle->mMinHeight; |
| } |
| } |
| limitMainSizeForFlexGrow(flexLine, childIndex, child->mCssStyle->mFlexGrow); |
| return std::make_pair(needsReexpand, childSizeAlongMainAxis); |
| } |
| |
| void updateLeftRightForAbsolute(float &left, float &right, |
| const WXCorePadding &parentPadding, |
| const WXCoreBorderWidth &parentBorder, |
| const WXCoreSize &parentSize) const { |
| if (isnan(mCssStyle->mStylePosition.getPosition(kPositionEdgeLeft))) { |
| if (isnan(mCssStyle->mStylePosition.getPosition(kPositionEdgeRight))) { |
| ; |
| } else { |
| right += parentSize.width - |
| (parentBorder.getBorderWidth(kBorderWidthRight) + |
| mCssStyle->mStylePosition.getPosition(kPositionEdgeRight) |
| + mLayoutResult->mLayoutSize.width); |
| left += parentSize.width - |
| (parentBorder.getBorderWidth(kBorderWidthRight) + |
| mCssStyle->mStylePosition.getPosition(kPositionEdgeRight) |
| + mLayoutResult->mLayoutSize.width); |
| } |
| } else { |
| left += parentBorder.getBorderWidth(kBorderWidthLeft) + |
| mCssStyle->mStylePosition.getPosition(kPositionEdgeLeft); |
| right += parentBorder.getBorderWidth(kBorderWidthLeft) + |
| mCssStyle->mStylePosition.getPosition(kPositionEdgeLeft); |
| } |
| } |
| |
| void updateTopBottomForAbsolute(float &top, float &bottom, |
| const WXCorePadding &parentPadding, |
| const WXCoreBorderWidth &parentBorder, |
| const WXCoreSize &parentSize) const { |
| if (isnan(mCssStyle->mStylePosition.getPosition(kPositionEdgeTop))) { |
| if (isnan(mCssStyle->mStylePosition.getPosition(kPositionEdgeBottom))) { |
| ; |
| } else { |
| top += parentSize.height - |
| (parentBorder.getBorderWidth(kBorderWidthBottom) + |
| mCssStyle->mStylePosition.getPosition(kPositionEdgeBottom) |
| + mLayoutResult->mLayoutSize.height); |
| bottom += parentSize.height - |
| (parentBorder.getBorderWidth(kBorderWidthBottom) + |
| mCssStyle->mStylePosition.getPosition(kPositionEdgeBottom) |
| + mLayoutResult->mLayoutSize.height); |
| } |
| } else { |
| top += parentBorder.getBorderWidth(kBorderWidthTop) + |
| mCssStyle->mStylePosition.getPosition(kPositionEdgeTop); |
| bottom += parentBorder.getBorderWidth(kBorderWidthTop) + |
| mCssStyle->mStylePosition.getPosition(kPositionEdgeTop); |
| } |
| } |
| |
| /** ================================ other =================================== **/ |
| |
| inline void clearDirty() { |
| dirty = false; |
| widthDirty = false; |
| heightDirty = false; |
| } |
| |
| void |
| measure(float, float, bool); |
| |
| void hypotheticalMeasure(float, float, bool = false); |
| |
| void measureLeafNode(float, float, bool, bool); |
| |
| void measureInternalNode(float, float, bool, bool); |
| |
| void updateCurrentFlexline(Index, WXCoreFlexLine *, Index, const WXCoreLayoutNode *, bool); |
| |
| void measureChild(WXCoreLayoutNode* , float, float, float, bool, bool); |
| |
| void adjustChildSize(WXCoreLayoutNode *, float); |
| |
| void adjustChildSize(const WXCoreLayoutNode *child, |
| const float currentMainSize, |
| const float parentWidth, |
| const float parentHeight, |
| float &childWidth, |
| float &childHeight) const; |
| |
| void stretchViewCrossSize(); |
| |
| void stretchViewCrossSize(WXCoreLayoutNode *, float); |
| |
| Index expandItemsInFlexLine(WXCoreFlexLine *, float, Index); |
| |
| void checkSizeConstraints(WXCoreLayoutNode *, bool); |
| |
| void |
| determineMainSize(float width, float height); |
| |
| void |
| determineCrossSize(float, float, bool); |
| |
| void |
| determineCrossSize(float, float, WXCoreFlexLine *); |
| |
| void setFrame(float, float, float, float); |
| |
| void setFrame(WXCorePosition*,float, float, float, float); |
| |
| /** ================================ layout =================================== **/ |
| |
| void layout(float left, float top, float right, float bottom, bool, const std::pair<float,float>* = nullptr); |
| |
| void calcRelativeOffset(float &left, float &top, float &right, float &bottom) const ; |
| |
| void calcAbsoluteOffset(float &left, float &top, float &right, float &bottom, const std::pair<float,float>* = nullptr); |
| |
| void positionAbsoluteFlexItem(float &left, float &top, float &right, float &bottom); |
| |
| void onLayout(float left, float top, float right, float bottom, WXCoreLayoutNode* = nullptr, WXCoreFlexLine *const flexLine = nullptr); |
| |
| void layoutHorizontal(bool isRtl, float left, float top, float right, float bottom, |
| WXCoreLayoutNode*, WXCoreFlexLine *const flexLine); |
| |
| void layoutFlexlineHorizontal(const float width, |
| const WXCoreFlexLine *const flexLine, |
| float &childLeft, |
| float &childRight, |
| float &spaceBetweenItem) const; |
| |
| void layoutSingleChildHorizontal(WXCoreLayoutNode *node, WXCoreFlexLine *flexLine, |
| WXCoreFlexWrap flexWrap, WXCoreAlignItems alignItems, |
| float, float, float, float, bool); |
| |
| void layoutSingleChildHorizontal(const bool isRtl, |
| const bool, |
| float childBottom, float childTop, |
| WXCoreFlexLine *const flexLine, |
| WXCoreLayoutNode *const child, |
| float&, float&); |
| |
| void layoutVertical(bool isRtl, bool fromBottomToTop, float left, float top, float right, float bottom, |
| WXCoreLayoutNode*, WXCoreFlexLine *const flexLine); |
| |
| void layoutFlexlineVertical(const float height, |
| const WXCoreFlexLine *const flexLine, |
| float &childTop, |
| float &childBottom, |
| float &spaceBetweenItem) const; |
| void layoutSingleChildVertical(WXCoreLayoutNode *node, WXCoreFlexLine *flexLine, |
| bool isRtl, WXCoreAlignItems alignItems, |
| float, float, float, float, bool); |
| |
| void layoutSingleChildVertical(const bool isRtl, const bool fromBottomToTop, |
| const bool absoluteFlexItem, |
| const float childLeft, const float childRight, |
| WXCoreFlexLine *const flexLine, |
| WXCoreLayoutNode *const child, |
| float& ,float&); |
| |
| void updateFlexLineForAbsoluteItem(WXCoreLayoutNode *const absoluteFlexItem, WXCoreFlexLine *const flexLine); |
| |
| void initFormatingContext(std::vector<WXCoreLayoutNode *> &BFCs); |
| |
| std::pair<bool,float> calculateBFCWidth(float, float); |
| |
| std::pair<bool,float> calculateBFCHeight(float, float); |
| |
| std::tuple<bool, float, float> calculateBFCDimension(const std::pair<float,float>&); |
| |
| virtual void OnLayoutBefore() { |
| |
| } |
| |
| virtual void OnLayoutAfter(float width, float height) { |
| |
| } |
| |
| |
| public: |
| |
| /** ================================ tree =================================== **/ |
| |
| inline Index getChildCount(FormattingContext formattingContext) const { |
| switch (formattingContext) { |
| case kNonBFC: |
| return NonBFCs.size(); |
| case kBFC: |
| return BFCs.size(); |
| default: |
| return mChildList.size(); |
| } |
| } |
| |
| inline Index getChildCount() const { |
| return mChildList.size(); |
| } |
| |
| inline std::vector<WXCoreLayoutNode *>::const_iterator ChildListIterBegin() { |
| return mChildList.cbegin(); |
| } |
| |
| inline std::vector<WXCoreLayoutNode *>::const_iterator ChildListIterEnd() { |
| return mChildList.cend(); |
| } |
| |
| inline bool hasChild(const WXCoreLayoutNode* const child){ |
| if(std::find(mChildList.begin(), mChildList.end(), child) != mChildList.end()){ |
| return true; |
| }else{ |
| return false; |
| } |
| } |
| |
| inline void removeChild(const WXCoreLayoutNode* const child) { |
| for (int index = 0; index < mChildList.size(); index++) { |
| if (child == mChildList[index]) { |
| mChildList.erase(mChildList.begin() + index); |
| break; |
| } |
| } |
| markDirty(); |
| } |
| |
| inline void addChildAt(WXCoreLayoutNode* const child, Index index) { |
| mChildList.insert(mChildList.begin() + index, child); |
| child->mParent = this; |
| markDirty(); |
| } |
| |
| inline WXCoreLayoutNode *getChildAt(const FormattingContext formattingContext, const Index index) const { |
| switch (formattingContext) { |
| case kNonBFC: |
| return NonBFCs[index]; |
| case kBFC: |
| return BFCs[index]; |
| default: |
| return mChildList[index]; |
| } |
| } |
| |
| inline WXCoreLayoutNode *getChildAt(const Index index) const { |
| return mChildList[index]; |
| } |
| |
| inline WXCoreLayoutNode *getParent() const { |
| return mParent; |
| } |
| |
| inline void setParent(WXCoreLayoutNode * const parent, WXCoreLayoutNode * const child) const { |
| child->mParent = parent; |
| } |
| |
| inline bool isBFC(WXCoreLayoutNode* const node) const { |
| return node->mCssStyle->mPositionType == kAbsolute || node->mCssStyle->mPositionType == kFixed; |
| } |
| |
| /** ================================ margin =================================== **/ |
| |
| inline float getMarginTop() const { |
| return mCssStyle->mMargin.getMargin(kMarginTop); |
| } |
| |
| inline float getMarginBottom() const { |
| return mCssStyle->mMargin.getMargin(kMarginBottom); |
| } |
| |
| inline float getMarginLeft() const { |
| return mCssStyle->mMargin.getMargin(kMarginLeft); |
| } |
| |
| inline float getMarginRight() const { |
| return mCssStyle->mMargin.getMargin(kMarginRight); |
| } |
| |
| inline void setMargin(const WXCoreMarginEdge &edge, const float margin) { |
| if (mCssStyle->mMargin.setMargin(edge, margin)) { |
| markDirty(); |
| } |
| } |
| |
| inline const WXCoreMargin &GetMargins() const { |
| return mCssStyle->mMargin; |
| } |
| |
| /** ================================ padding =================================== **/ |
| |
| inline float getPaddingLeft() const { |
| return mCssStyle->mPadding.getPadding(kPaddingLeft); |
| } |
| |
| inline float getPaddingRight() const { |
| return mCssStyle->mPadding.getPadding(kPaddingRight); |
| } |
| |
| inline float getPaddingTop() const { |
| return mCssStyle->mPadding.getPadding(kPaddingTop); |
| } |
| |
| inline float getPaddingBottom() const { |
| return mCssStyle->mPadding.getPadding(kPaddingBottom); |
| } |
| |
| inline void setPadding(const WXCorePaddingEdge edge, const float padding) { |
| if (mCssStyle->mPadding.setPadding(edge, padding)) { |
| markDirty(); |
| } |
| } |
| |
| inline const WXCorePadding &GetPaddings() const { |
| return mCssStyle->mPadding; |
| } |
| |
| /** ================================ border-width =================================== **/ |
| |
| inline float getBorderWidthLeft() const { |
| return mCssStyle->mBorderWidth.getBorderWidth(kBorderWidthLeft); |
| } |
| |
| inline float getBorderWidthRight() const { |
| return mCssStyle->mBorderWidth.getBorderWidth(kBorderWidthRight); |
| } |
| |
| inline float getBorderWidthTop() const { |
| return mCssStyle->mBorderWidth.getBorderWidth(kBorderWidthTop); |
| } |
| |
| inline float getBorderWidthBottom() const { |
| return mCssStyle->mBorderWidth.getBorderWidth(kBorderWidthBottom); |
| } |
| |
| inline void setBorderWidth(const WXCoreBorderWidthEdge edge, const float borderWidth) { |
| if (mCssStyle->mBorderWidth.setBorderWidth(edge, borderWidth)) { |
| markDirty(); |
| } |
| } |
| |
| inline const WXCoreBorderWidth &GetBorders() const { |
| return mCssStyle->mBorderWidth; |
| } |
| |
| /** ================================ position-type =================================== **/ |
| |
| inline void setStylePositionType(const WXCorePositionType positionType) { |
| if (mCssStyle->mPositionType != positionType) { |
| mCssStyle->mPositionType = positionType; |
| markDirty(); |
| } |
| } |
| |
| inline WXCorePositionType getStylePositionType() const { |
| return mCssStyle->mPositionType; |
| } |
| |
| |
| /** ================================ position =================================== **/ |
| |
| inline float getStylePositionTop() const { |
| return mCssStyle->mStylePosition.getPosition(kPositionEdgeTop); |
| } |
| |
| inline float getStylePositionBottom() const { |
| return mCssStyle->mStylePosition.getPosition(kPositionEdgeBottom); |
| } |
| |
| inline float getStylePositionLeft() const { |
| return mCssStyle->mStylePosition.getPosition(kPositionEdgeLeft); |
| } |
| |
| inline float getStylePositionRight() const { |
| return mCssStyle->mStylePosition.getPosition(kPositionEdgeRight); |
| } |
| |
| inline void setStylePosition(const WXCorePositionEdge edge, const float positionRight) { |
| if (mCssStyle->mStylePosition.setPosition(edge, positionRight)) |
| markDirty(); |
| } |
| |
| |
| /** ================================ dimension =================================== **/ |
| |
| inline void setStyleWidthLevel(const DimensionLevel level) const { |
| if (mCssStyle->mStyleWidthLevel != level) { |
| mCssStyle->mStyleWidthLevel = level; |
| } |
| } |
| |
| inline void setStyleHeightLevel(const DimensionLevel level) const { |
| if (mCssStyle->mStyleHeightLevel != level) { |
| mCssStyle->mStyleHeightLevel = level; |
| } |
| } |
| |
| inline DimensionLevel getStyleHeightLevel() const { |
| return mCssStyle->mStyleHeightLevel; |
| } |
| |
| inline DimensionLevel getStyleWidthLevel() const { |
| return mCssStyle->mStyleWidthLevel; |
| } |
| |
| inline void setStyleWidth(const float width, const bool updating) { |
| if (mCssStyle->mStyleWidth != width) { |
| mCssStyle->mStyleWidth = width; |
| markDirty(); |
| if(updating) { |
| markChildrenDirty(true); |
| } |
| } |
| } |
| |
| inline void setStyleWidthToNAN() { |
| if (!isnan(mCssStyle->mStyleWidth)) { |
| mCssStyle->mStyleWidth = NAN; |
| markDirty(); |
| markChildrenDirty(true); |
| } |
| } |
| |
| inline float getStyleWidth() const { |
| return mCssStyle->mStyleWidth; |
| } |
| |
| inline void setStyleHeight(const float height) { |
| if (mCssStyle->mStyleHeight != height) { |
| mCssStyle->mStyleHeight = height; |
| markDirty(); |
| } |
| } |
| |
| inline float getStyleHeight() const { |
| return mCssStyle->mStyleHeight; |
| } |
| |
| inline void setMinWidth(const float minWidth, const bool updating) { |
| if (mCssStyle->mMinWidth != minWidth) { |
| mCssStyle->mMinWidth = minWidth; |
| markDirty(); |
| if(updating) { |
| markChildrenDirty(true); |
| } |
| } |
| } |
| |
| inline float getMinWidth() const { |
| return mCssStyle->mMinWidth; |
| } |
| |
| inline void setMaxWidth(const float maxWidth, const bool updating) { |
| if (mCssStyle->mMaxWidth != maxWidth) { |
| mCssStyle->mMaxWidth = maxWidth; |
| markDirty(); |
| if(updating) { |
| markChildrenDirty(true); |
| } |
| } |
| } |
| |
| inline float getMaxWidth() const { |
| return mCssStyle->mMaxWidth; |
| } |
| |
| inline void setMinHeight(const float minHeight) { |
| if (mCssStyle->mMinHeight != minHeight) { |
| mCssStyle->mMinHeight = minHeight; |
| markDirty(); |
| } |
| } |
| |
| inline float getMinHeight() const { |
| return mCssStyle->mMinHeight; |
| } |
| |
| inline void setMaxHeight(const float maxHeight) { |
| if (mCssStyle->mMaxHeight != maxHeight) { |
| mCssStyle->mMaxHeight = maxHeight; |
| markDirty(); |
| } |
| } |
| |
| inline float getMaxHeight() const { |
| return mCssStyle->mMaxHeight; |
| } |
| |
| |
| /** ================================ flex-style =================================== **/ |
| |
| inline void setFlexDirection(const WXCoreFlexDirection flexDirection, const bool updating) { |
| if (mCssStyle->mFlexDirection != flexDirection) { |
| mCssStyle->mFlexDirection = flexDirection; |
| markDirty(); |
| if (updating) { |
| for (auto it = ChildListIterBegin(); it != ChildListIterEnd(); it++) { |
| (*it)->markDirty(false); |
| } |
| } |
| } |
| } |
| |
| inline WXCoreFlexDirection getFlexDirection() const { |
| return mCssStyle->mFlexDirection; |
| } |
| |
| inline void setFlexWrap(const WXCoreFlexWrap flexWrap) { |
| if (mCssStyle->mFlexWrap != flexWrap) { |
| mCssStyle->mFlexWrap = flexWrap; |
| markDirty(); |
| } |
| } |
| |
| inline WXCoreFlexWrap getFlexWrap() const { |
| return mCssStyle->mFlexWrap; |
| } |
| |
| inline void setJustifyContent(const WXCoreJustifyContent justifyContent) { |
| if (mCssStyle->mJustifyContent != justifyContent) { |
| mCssStyle->mJustifyContent = justifyContent; |
| } |
| } |
| |
| inline WXCoreJustifyContent getJustifyContent() const { |
| return mCssStyle->mJustifyContent; |
| } |
| |
| inline void setAlignItems(const WXCoreAlignItems alignItems) { |
| if (mCssStyle->mAlignItems != alignItems) { |
| mCssStyle->mAlignItems = alignItems; |
| markDirty(); |
| } |
| } |
| |
| inline WXCoreAlignItems getAlignItems() const { |
| return mCssStyle->mAlignItems; |
| } |
| |
| inline void setAlignSelf(const WXCoreAlignSelf alignSelf) { |
| if (mCssStyle->mAlignSelf != alignSelf) { |
| mCssStyle->mAlignSelf = alignSelf; |
| markDirty(); |
| } |
| } |
| |
| inline WXCoreAlignSelf getAlignSelf() const { |
| return mCssStyle->mAlignSelf; |
| } |
| |
| virtual void set_flex(const float flex) { |
| if (mCssStyle->mFlexGrow != flex) { |
| mCssStyle->mFlexGrow = flex; |
| markDirty(); |
| } |
| } |
| |
| inline float getFlex() const { |
| return mCssStyle->mFlexGrow; |
| } |
| |
| /** ================================ layout-result =================================== **/ |
| |
| inline float getLayoutWidth() const { |
| return mLayoutResult->mLayoutSize.width; |
| } |
| |
| inline float getLayoutHeight() const { |
| return mLayoutResult->mLayoutSize.height; |
| } |
| |
| inline float getLayoutPositionTop() const { |
| return mLayoutResult->mLayoutPosition.getPosition(kPositionEdgeTop); |
| } |
| |
| inline float getLayoutPositionBottom() const { |
| return mLayoutResult->mLayoutPosition.getPosition(kPositionEdgeBottom); |
| } |
| |
| inline float getLayoutPositionLeft() const { |
| return mLayoutResult->mLayoutPosition.getPosition(kPositionEdgeLeft); |
| } |
| |
| inline float getLayoutPositionRight() const { |
| return mLayoutResult->mLayoutPosition.getPosition(kPositionEdgeRight); |
| } |
| |
| inline bool hasNewLayout() const { |
| return mHasNewLayout; |
| } |
| |
| inline bool isDirty() const { |
| return dirty; |
| } |
| |
| inline void markDirty(const bool recursion = true) { |
| if (!isDirty()) { |
| dirty = true; |
| if (getParent() != nullptr && recursion) { |
| getParent()->markDirty(); |
| } |
| } |
| } |
| |
| void markAllDirty() { |
| markDirty(false); |
| for (WXCoreLayoutNode* c : mChildList) { |
| c->markAllDirty(); |
| } |
| } |
| |
| bool markChildrenDirty(const bool updatedNode = false) { |
| bool ret = false; |
| if(getChildCount() == 0){ |
| if(measureFunc!= nullptr){ |
| ret = true; |
| } |
| } |
| else { |
| //isnan(mCssStyle->mStyleWidth) XOR updatedNode |
| if(isnan(mCssStyle->mStyleWidth) != updatedNode){ |
| for (auto it = ChildListIterBegin(); it != ChildListIterEnd(); it++) { |
| ret = ((*it)->markChildrenDirty() || ret) ; |
| } |
| } |
| } |
| dirty = ret || dirty; |
| return ret; |
| } |
| |
| inline void setHasNewLayout(const bool hasNewLayout) { |
| this->mHasNewLayout = hasNewLayout; |
| } |
| |
| inline float getLargestMainSize() const { |
| float largestSize = 0; |
| for (WXCoreFlexLine *flexLine : mFlexLines) { |
| largestSize = std::max(largestSize, flexLine->mMainSize); |
| } |
| return largestSize + sumPaddingBorderAlongAxis(this, isMainAxisHorizontal(this)); |
| } |
| |
| inline void rewriteLayoutResult(float left, float top, float width, float height) { |
| if (mLayoutResult != nullptr) { |
| mLayoutResult->mLayoutPosition.setPosition(kPositionEdgeLeft, left); |
| mLayoutResult->mLayoutPosition.setPosition(kPositionEdgeTop, top); |
| mLayoutResult->mLayoutPosition.setPosition(kPositionEdgeRight, left + width); |
| mLayoutResult->mLayoutPosition.setPosition(kPositionEdgeBottom, top + height); |
| mLayoutResult->mLayoutSize.width = width; |
| mLayoutResult->mLayoutSize.height = height; |
| } |
| } |
| }; |
| } |
| #endif //WEEXCORE_FLEXLAYOUT_WXCORELAYOUTNODE_H |
| #endif |