http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b77b4259/ios/sdk/WeexSDK/Sources/Layout/WXCoreLayout.cpp ---------------------------------------------------------------------- diff --git a/ios/sdk/WeexSDK/Sources/Layout/WXCoreLayout.cpp b/ios/sdk/WeexSDK/Sources/Layout/WXCoreLayout.cpp new file mode 100644 index 0000000..7d34d83 --- /dev/null +++ b/ios/sdk/WeexSDK/Sources/Layout/WXCoreLayout.cpp @@ -0,0 +1,1038 @@ +#include "WXCoreLayout.h" + +using namespace WeexCore; + +namespace WeexCore { + + /** + * Entry function to calculate layout + */ + void WXCoreLayoutNode::calculateLayout(const std::pair<float,float> &renderPageSize) { + BFCs.clear(); + initFormatingContext(BFCs); + auto bfcDimension = calculateBFCDimension(renderPageSize); + if (std::get<0>(bfcDimension) || isDirty()) { + mChildrenFrozen.assign(getChildCount(kNonBFC), false); + measure(std::get<1>(bfcDimension), std::get<2>(bfcDimension), true); + checkSizeConstraints(this, false); + } + layout(mCssStyle->mMargin.getMargin(kMarginLeft), + mCssStyle->mMargin.getMargin(kMarginTop), + mCssStyle->mMargin.getMargin(kMarginLeft) + getLayoutWidth(), + mCssStyle->mMargin.getMargin(kMarginTop) + getLayoutHeight(), + false, &renderPageSize); + for (Index i = 0; i < getChildCount(kBFC); ++i) { + WXCoreLayoutNode *child = getChildAt(kBFC, i); + child->calculateLayout(renderPageSize); + } + } + + void WXCoreLayoutNode::initFormatingContext(std::vector<WXCoreLayoutNode *> &BFCs) { + NonBFCs.clear(); + for(auto it = ChildListIterBegin(); it != ChildListIterEnd(); it++) { + WXCoreLayoutNode* child = *it; + if (child != nullptr) { + if (isBFC(child)) { + BFCs.push_back(child); + } else { + NonBFCs.push_back(child); + child->initFormatingContext(BFCs); + } + } + } + reset(); + } + + std::tuple<bool, float, float> WXCoreLayoutNode::calculateBFCDimension(const std::pair<float,float>& renderPageSize) { + bool sizeChanged = false; + float width = mCssStyle->mStyleWidth, height = mCssStyle->mStyleHeight; + std::pair<bool,float> ret; + if (isBFC(this)) { + ret = calculateBFCWidth(width, renderPageSize.first); + sizeChanged |=ret.first; + width = ret.second; + + ret = calculateBFCHeight(height,renderPageSize.second); + sizeChanged |=ret.first; + height = ret.second; + } + return std::make_tuple(sizeChanged, width, height); + } + + std::pair<bool,float> WXCoreLayoutNode::calculateBFCWidth(float width, const float renderPageWidth){ + bool sizeChanged = false; + if (isnan(width) && + mParent != nullptr && + !isnan(mCssStyle->mStylePosition.getPosition(kPositionEdgeLeft)) && + !isnan(mCssStyle->mStylePosition.getPosition(kPositionEdgeRight))) { + float containingBlockWidth = NAN; + switch (mCssStyle->mPositionType) { + case kAbsolute: + containingBlockWidth = mParent->mLayoutResult->mLayoutSize.width; + break; + case kFixed: + if (!isnan(renderPageWidth)) { + containingBlockWidth = renderPageWidth; + } + break; + default: + break; + } + if (!isnan(containingBlockWidth)) { + width = containingBlockWidth - + mCssStyle->mStylePosition.getPosition(kPositionEdgeLeft) - + mCssStyle->mStylePosition.getPosition(kPositionEdgeRight); + setWidthMeasureMode(kExactly); + sizeChanged = true; + } + } + return std::make_pair(sizeChanged, width); + } + + + std::pair<bool,float> WXCoreLayoutNode::calculateBFCHeight(float height, const float renderPageHeight){ + bool sizeChanged = false; + if (isnan(mCssStyle->mStyleHeight) && + mParent != nullptr && + !isnan(mCssStyle->mStylePosition.getPosition(kPositionEdgeTop)) && + !isnan(mCssStyle->mStylePosition.getPosition(kPositionEdgeBottom))) { + float containingBlockHeight = NAN; + switch (mCssStyle->mPositionType) { + case kAbsolute: + containingBlockHeight = mParent->mLayoutResult->mLayoutSize.height; + break; + case kFixed: + if (!isnan(renderPageHeight)) { + containingBlockHeight = renderPageHeight; + } + break; + default: + break; + } + if (!isnan(containingBlockHeight)) { + height = containingBlockHeight - + mCssStyle->mStylePosition.getPosition(kPositionEdgeTop) - + mCssStyle->mStylePosition.getPosition(kPositionEdgeBottom); + setHeightMeasureMode(kExactly); + sizeChanged = true; + } + } + return std::make_pair(sizeChanged, height); + } + + void WXCoreLayoutNode::measure(const float width, const float height, const bool hypotheticalMeasurment){ + if(hypotheticalMeasurment){ + //Only BFC will enter this case. + hypotheticalMeasure(width, height); + } + + if(getChildCount(kNonBFC) > 0){ + if((isMainAxisHorizontal(this) && widthDirty) || (!isMainAxisHorizontal(this) && heightDirty)){ + measureInternalNode(width, height, false, false); + } + determineMainSize(width, height); + determineCrossSize(width, height, true); + measureInternalNode(width, height, true, false); + determineCrossSize(width, height, false); + } + else { + if (widthDirty || heightDirty) { + measureLeafNode(width, height, hypotheticalMeasurment, false); + } + } + clearDirty(); + } + + void WXCoreLayoutNode::hypotheticalMeasure(const float width, const float height, const bool stretch){ + if (getChildCount(kNonBFC) > 0) { + measureInternalNode(width, height, true, true); + } else { + measureLeafNode(width, height, true, stretch); + } + + widthDirty = false; + heightDirty = false; + mLayoutResult->mLayoutSize.hypotheticalWidth = mLayoutResult->mLayoutSize.width; + mLayoutResult->mLayoutSize.hypotheticalHeight = mLayoutResult->mLayoutSize.height; + } + + void WXCoreLayoutNode::measureLeafNode(float width, float height, const bool hypothetical, const bool stretch) { + if ((measureFunc != nullptr) && + (widthMeasureMode == kUnspecified + || heightMeasureMode == kUnspecified)) { + float constrainsWidth = width; + if(widthMeasureMode == kExactly && !isnan(width)){ + constrainsWidth -= sumPaddingBorderAlongAxis(this, true); + } + WXCoreSize dimension = measureFunc(this, constrainsWidth, + (stretch && !isnan(width)) ? kExactly:widthMeasureMode, + height, heightMeasureMode); + if (widthMeasureMode == kUnspecified) { + float actualWidth = dimension.width + sumPaddingBorderAlongAxis(this, true); + if (isnan(width)) { + width = actualWidth; + } else if (!stretch) { + width = std::min(width, actualWidth); + } + } + if (heightMeasureMode == kUnspecified) { + float actualHeight = dimension.height + sumPaddingBorderAlongAxis(this, false); + if (isnan(height)) { + height = actualHeight; + } else if (!stretch) { + height = std::min(height, actualHeight); + } + } + } else { + width = widthMeasureMode == kUnspecified ? sumPaddingBorderAlongAxis(this, true) + : width; + height = heightMeasureMode == kUnspecified ? sumPaddingBorderAlongAxis(this, false) + : height; + } + setMeasuredDimension(width, height); + } + + + /** + * Determine the main size by expanding the individual flexGrow attribute. + */ + void WXCoreLayoutNode::determineMainSize(const float width, const float height) { + bool horizontal = isMainAxisHorizontal(this); + if((horizontal && widthMeasureMode == kExactly) || (!horizontal && heightMeasureMode == kExactly)) { + //The measureMode along main axis is exactly + float maxMainSize = horizontal ? width: height; + maxMainSize -= sumPaddingBorderAlongAxis(this, isMainAxisHorizontal(this)); + Index childIndex = 0; + for (WXCoreFlexLine *flexLine : mFlexLines) { + childIndex = expandItemsInFlexLine(flexLine, maxMainSize, childIndex); + } + } + } + + + /** + * @param flexDirection the flex direction attribute + * @param width stylewidth by this node + * @param height styleheight by this node + * @param paddingAlongCrossAxis the padding value for this node along the cross axis + */ + void WXCoreLayoutNode::determineCrossSize(const float width, const float height, const bool stretch) { + if (mFlexLines.size() == 1 && isCrossExactly()) { + bool horizontal = isMainAxisHorizontal(this); + float size = mFlexLines[0]->mCrossSize; + float paddingAlongCrossAxis = sumPaddingBorderAlongAxis(this, !horizontal); + if (horizontal) { + if (heightMeasureMode == kExactly) { + size = height - paddingAlongCrossAxis; + } + } else { + if (widthMeasureMode == kExactly) { + size = width - paddingAlongCrossAxis; + } + } + mFlexLines[0]->mCrossSize = size; + } + if (stretch) { + stretchViewCrossSize(); + } + } + + + void WXCoreLayoutNode::measureInternalNode(const float width, const float height, const bool needMeasure, + const bool hypotheticalMeasurment) { + for (WXCoreFlexLine *flexLine : mFlexLines) { + if(flexLine!= nullptr) { + delete flexLine; + } + flexLine = nullptr; + } + mFlexLines.clear(); + Index childCount = getChildCount(kNonBFC); + WXCoreFlexLine *flexLine = new WXCoreFlexLine(); + + for (Index i = 0; i < childCount; i++) { + WXCoreLayoutNode *child = getChildAt(kNonBFC, i); + if (child->mCssStyle->mAlignSelf == kAlignSelfStretch) { + flexLine->mIndicesAlignSelfStretch.push_back(i); + } + measureChild(child, flexLine->mMainSize, width, height, needMeasure, hypotheticalMeasurment); + checkSizeConstraints(child, hypotheticalMeasurment); + + if (isWrapRequired(width, height, flexLine->mMainSize, + calcItemSizeAlongAxis(child, isMainAxisHorizontal(this)))) { + if (flexLine->mItemCount > 0) { + mFlexLines.push_back(flexLine); + } + flexLine = new WXCoreFlexLine(); + flexLine->mItemCount = 1; + } else { + flexLine->mItemCount++; + } + updateCurrentFlexline(childCount, flexLine, i, child, hypotheticalMeasurment || (!hypotheticalMeasurment && !needMeasure)); + } + setMeasuredDimensionForFlex(width, widthMeasureMode, height, heightMeasureMode); + } + + void WXCoreLayoutNode::updateCurrentFlexline(const Index childCount, WXCoreFlexLine* const flexLine, const Index i, + const WXCoreLayoutNode* const child, const bool useHypotheticalSize){ + flexLine->mMainSize += calcItemSizeAlongAxis(child, isMainAxisHorizontal(this), useHypotheticalSize); + sumFlexGrow(child, flexLine, i); + flexLine->mCrossSize = + std::max(flexLine->mCrossSize, calcItemSizeAlongAxis(child, !isMainAxisHorizontal(this), useHypotheticalSize)); + if (i == childCount - 1 && flexLine->mItemCount != 0) { + mFlexLines.push_back(flexLine); + } + } + + void WXCoreLayoutNode::measureChild(WXCoreLayoutNode* const child, const float currentMainSize, + const float parentWidth, const float parentHeight, + const bool needMeasure, const bool hypotheticalMeasurment) { + if (needMeasure && child->isDirty()) { + if (hypotheticalMeasurment) { + float childWidth = child->mCssStyle->mStyleWidth; + float childHeight = child->mCssStyle->mStyleHeight; + bool stretch = !isMainAxisHorizontal(this) && + child->measureFunc != nullptr && + widthMeasureMode == kExactly && + isSingleFlexLine(parentHeight) && + ((child->mCssStyle->mAlignSelf == kAlignSelfStretch) || + (mCssStyle->mAlignItems == kAlignItemsStretch + && child->mCssStyle->mAlignSelf == kAlignSelfAuto)); + + adjustChildSize(child, currentMainSize, parentWidth, + parentHeight, childWidth, childHeight); + child->hypotheticalMeasure(childWidth, childHeight, stretch); + } else { + if(isSingleFlexLine(isMainAxisHorizontal(this) ? parentWidth : parentHeight) + && !isMainAxisHorizontal(this) && child->widthMeasureMode == kUnspecified){ + child->setLayoutWidth(parentWidth - sumPaddingBorderAlongAxis(this, true) + -child->mCssStyle->sumMarginOfDirection(true)); + if(child->heightMeasureMode == kUnspecified && child->widthDirty) { + child->mLayoutResult->mLayoutSize.height = NAN; + } + } + child->measure(child->mLayoutResult->mLayoutSize.width, + child->mLayoutResult->mLayoutSize.height, hypotheticalMeasurment); + } + } + } + + void WXCoreLayoutNode::adjustChildSize(const WXCoreLayoutNode *child, + const float currentMainSize, + const float parentWidth, + const float parentHeight, + float &childWidth, + float &childHeight) const { + if(child->measureFunc == nullptr) { + if(!isnan(childWidth)){ + childWidth = std::max(childWidth, child->sumPaddingBorderAlongAxis(child, true)); + } + if(!isnan(childHeight)){ + childHeight = std::max(childHeight, child->sumPaddingBorderAlongAxis(child, false)); + } + } + + if (isSingleFlexLine(isMainAxisHorizontal(this) ? parentWidth : parentHeight)) { + if (isMainAxisHorizontal(this)) { + if (!isnan(parentHeight) && isnan(child->mCssStyle->mStyleHeight) + && child->mCssStyle->mAlignSelf == kAlignSelfAuto + && mCssStyle->mAlignItems == kAlignItemsStretch) { + childHeight = parentHeight - sumPaddingBorderAlongAxis(this, false) - + child->mCssStyle->sumMarginOfDirection(false); + } + } else { + if (!isnan(parentWidth) && isnan(child->mCssStyle->mStyleWidth)) { + childWidth = parentWidth - sumPaddingBorderAlongAxis(this, true) - + child->mCssStyle->sumMarginOfDirection(true); + } + } + } + } + + void WXCoreLayoutNode::checkSizeConstraints(WXCoreLayoutNode* const node, const bool hypotheticalMeasurment) { + bool widthRemeasure = false, heightRemeasure = false; + float nodeWidth,nodeHeight; + nodeWidth = node->mLayoutResult->mLayoutSize.width; + nodeHeight = node->mLayoutResult->mLayoutSize.height; + + if (!isnan(node->mCssStyle->mMinWidth) && + nodeWidth < node->mCssStyle->mMinWidth) { + widthRemeasure = true; + nodeWidth = node->mCssStyle->mMinWidth; + } else if (!isnan(node->mCssStyle->mMaxWidth) + && nodeWidth > node->mCssStyle->mMaxWidth) { + widthRemeasure = true; + nodeWidth = node->mCssStyle->mMaxWidth; + } + + if (!isnan(node->mCssStyle->mMinHeight) && + nodeHeight < node->mCssStyle->mMinHeight) { + heightRemeasure = true; + nodeHeight = node->mCssStyle->mMinHeight; + } else if (!isnan(node->mCssStyle->mMaxHeight) && + nodeHeight > node->mCssStyle->mMaxHeight) { + heightRemeasure = true; + nodeHeight = node->mCssStyle->mMaxHeight; + } + + node->setWidthMeasureMode(widthRemeasure ? kExactly : node->widthMeasureMode); + node->setHeightMeasureMode(heightRemeasure ? kExactly : node->heightMeasureMode); + + if (hypotheticalMeasurment) { + if (widthRemeasure) { + node->setLayoutWidth(nodeWidth); + node->mLayoutResult->mLayoutSize.hypotheticalWidth = nodeWidth; + } + if (heightRemeasure) { + node->setLayoutHeight(nodeHeight); + node->mLayoutResult->mLayoutSize.hypotheticalHeight = nodeHeight; + } + } else { + if (widthRemeasure || heightRemeasure) { + node->measure(nodeWidth, nodeHeight, hypotheticalMeasurment); + } + } + } + + Index WXCoreLayoutNode::expandItemsInFlexLine(WXCoreFlexLine* const flexLine, + const float maxMainSize, + const Index startIndex) { + Index childIndex = startIndex; + if (flexLine->mTotalFlexGrow <= 0) { + childIndex += flexLine->mItemCount; + } else { + bool needsReexpand = false; + const float unitSpace = (maxMainSize - flexLine->mMainSize + flexLine->mTotalFlexibleSize) / + (flexLine->mTotalFlexGrow > 1 ? flexLine->mTotalFlexGrow : 1); + float sizeBeforeExpand = flexLine->mMainSize; + flexLine->mMainSize = 0; + + for (Index i = 0; i < flexLine->mItemCount; i++) { + WXCoreLayoutNode *child = getChildAt(kNonBFC, childIndex); + if (!mChildrenFrozen[childIndex]) { + float childSizeAlongMainAxis = unitSpace * child->mCssStyle->mFlexGrow; + std::pair<bool, float> limitSize = limitChildMainSize(flexLine, child, + childSizeAlongMainAxis, childIndex); + needsReexpand = limitSize.first; + adjustChildSize(child, limitSize.second); + } + flexLine->mMainSize += calcItemSizeAlongAxis(child, isMainAxisHorizontal(this)); + childIndex++; + } + + if (needsReexpand && sizeBeforeExpand != flexLine->mMainSize) { + // Re-invoke the method with the same startIndex to distribute the positive free space + // that wasn't fully distributed (because of maximum/minimum length constraint) + expandItemsInFlexLine(flexLine, maxMainSize, startIndex); + } + } + return childIndex; + } + + void WXCoreLayoutNode::adjustChildSize(WXCoreLayoutNode* const child, const float childMainSize) { + if (isMainAxisHorizontal(this)) { + child->setWidthMeasureMode(kExactly); + child->setLayoutWidth(childMainSize); + } else { + child->setHeightMeasureMode(kExactly); + child->setLayoutHeight(childMainSize); + } + } + + void WXCoreLayoutNode::stretchViewCrossSize(){ + if (mCssStyle->mAlignItems == kAlignItemsStretch) { + Index viewIndex = 0; + for (Index i = 0; i< mFlexLines.size(); i++ ) { + WXCoreFlexLine *flexLine = mFlexLines.at(i); + for (Index j = 0; j < flexLine->mItemCount; j++, viewIndex++) { + WXCoreLayoutNode* child = getChildAt(kNonBFC, viewIndex); + if (child->mCssStyle->mAlignSelf == kAlignSelfAuto || + child->mCssStyle->mAlignSelf == kAlignSelfStretch) { + stretchViewCrossSize(child, flexLine->mCrossSize); + } + } + } + } else { + for (WXCoreFlexLine *flexLine : mFlexLines) { + for (auto index : flexLine->mIndicesAlignSelfStretch) { + stretchViewCrossSize(getChildAt(kNonBFC, index), flexLine->mCrossSize); + } + } + } + } + + void WXCoreLayoutNode::stretchViewCrossSize(WXCoreLayoutNode* const child, float crossSize){ + if (isMainAxisHorizontal(this)) { + if (child->heightMeasureMode != kExactly) { + crossSize -= + child->mCssStyle->mMargin.getMargin(kMarginTop) + + child->mCssStyle->mMargin.getMargin(kMarginBottom); + child->setHeightMeasureMode(kExactly); + child->setLayoutHeight(std::max(0.f, crossSize)); + } + } else { + if (child->widthMeasureMode != kExactly) { + crossSize -= + child->mCssStyle->mMargin.getMargin(kMarginLeft) + + child->mCssStyle->mMargin.getMargin(kMarginRight); + child->setWidthMeasureMode(kExactly); + child->setLayoutWidth(std::max(0.f, crossSize)); + } + } + } + + void WXCoreLayoutNode::setFrame(const float l, const float t, const float r, const float b) { + if (mLayoutResult->mLayoutPosition.getPosition(kPositionEdgeLeft) != l + || mLayoutResult->mLayoutPosition.getPosition(kPositionEdgeTop) != t + || mLayoutResult->mLayoutPosition.getPosition(kPositionEdgeRight) != r + || mLayoutResult->mLayoutPosition.getPosition(kPositionEdgeBottom) != b) { + setHasNewLayout(true); + setFrame(&mLayoutResult->mLayoutPosition, l, t, r, b); + } + } + + void WXCoreLayoutNode::setFrame(WXCorePosition* position,const float l, const float t, const float r, const float b){ + position->setPosition(kPositionEdgeLeft, l); + position->setPosition(kPositionEdgeTop, t); + position->setPosition(kPositionEdgeRight, r); + position->setPosition(kPositionEdgeBottom, b); + } + + void WXCoreLayoutNode::layout(float left, float top, float right, float bottom, const bool absoluteFlexItem, const std::pair<float,float>* const renderPageSize) { + if(absoluteFlexItem) { + absoultePositon = new WXCorePosition(); + setFrame(absoultePositon, left, top, right, bottom); + } + else{ + switch (mCssStyle->mPositionType) { + case kFixed: + case kAbsolute: + calcAbsoluteOffset(left, top, right, bottom, renderPageSize); + break; + default: + case kRelative: + calcRelativeOffset(left, top, right, bottom); + break; + } + setFrame(left, top, right, bottom); + onLayout(left, top, right, bottom); + } + } + + void WXCoreLayoutNode::calcRelativeOffset(float &left, float &top, float &right, float &bottom) const { + if (!isnan(mCssStyle->mStylePosition.getPosition(kPositionEdgeLeft))) { + left += mCssStyle->mStylePosition.getPosition(kPositionEdgeLeft); + right += mCssStyle->mStylePosition.getPosition(kPositionEdgeLeft); + } else if (!isnan(mCssStyle->mStylePosition.getPosition(kPositionEdgeRight))) { + left -= mCssStyle->mStylePosition.getPosition(kPositionEdgeRight); + right -= mCssStyle->mStylePosition.getPosition(kPositionEdgeRight); + } + + if (!isnan(mCssStyle->mStylePosition.getPosition(kPositionEdgeTop))) { + top += mCssStyle->mStylePosition.getPosition(kPositionEdgeTop); + bottom += mCssStyle->mStylePosition.getPosition(kPositionEdgeTop); + } else if (!isnan(mCssStyle->mStylePosition.getPosition(kPositionEdgeBottom))) { + top -= mCssStyle->mStylePosition.getPosition(kPositionEdgeBottom); + bottom -= mCssStyle->mStylePosition.getPosition(kPositionEdgeBottom); + } + } + + void WXCoreLayoutNode::calcAbsoluteOffset(float &left, float &top, float &right, float &bottom, const std::pair<float,float>* const renderPageSize){ + WXCorePadding parentPadding; + WXCoreBorderWidth parentBorder; + WXCoreSize parentSize; + if (mCssStyle->mPositionType == kAbsolute && mParent != nullptr) { + parentPadding = mParent->mCssStyle->mPadding; + parentBorder = mParent->mCssStyle->mBorderWidth; + parentSize = mParent->mLayoutResult->mLayoutSize; + positionAbsoluteFlexItem(left, top, right, bottom); + } else if(mCssStyle->mPositionType == kFixed && renderPageSize!= nullptr){ + parentSize.width = renderPageSize->first; + parentSize.height = renderPageSize->second; + } + updateLeftRightForAbsolute(left, right, parentPadding, parentBorder, parentSize); + updateTopBottomForAbsolute(top, bottom, parentPadding, parentBorder, parentSize); + } + + void WXCoreLayoutNode::positionAbsoluteFlexItem(float &left, float &top, float &right, float &bottom){ + if ((isnan(getStylePositionLeft()) && isnan(getStylePositionRight())) || + (isnan(getStylePositionTop()) && isnan(getStylePositionBottom()))) { + WXCoreFlexLine tempLine; + mParent->updateFlexLineForAbsoluteItem(this, &tempLine); + mParent->onLayout(mParent->getLayoutPositionLeft(), + mParent->getLayoutPositionTop(), + mParent->getLayoutPositionRight(), + mParent->getLayoutPositionBottom(), + this, &tempLine); + if(absoultePositon != nullptr) { + if (isnan(getStylePositionLeft()) && isnan(getStylePositionRight())) { + left = absoultePositon->getPosition(kPositionEdgeLeft); + right = absoultePositon->getPosition(kPositionEdgeRight); + } + if (isnan(getStylePositionTop()) && isnan(getStylePositionBottom())) { + top = absoultePositon->getPosition(kPositionEdgeTop); + bottom = absoultePositon->getPosition(kPositionEdgeBottom); + } + delete absoultePositon; + absoultePositon = nullptr; + } + } + } + + void WXCoreLayoutNode::updateFlexLineForAbsoluteItem(WXCoreLayoutNode *const absoluteFlexItem, WXCoreFlexLine *const flexLine){ + flexLine->mMainSize = isMainAxisHorizontal(this) ? + absoluteFlexItem->getLayoutWidth() + absoluteFlexItem->getMarginLeft() + + absoluteFlexItem->getMarginRight() : + absoluteFlexItem->getLayoutHeight() + absoluteFlexItem->getMarginTop() + + absoluteFlexItem->getMarginBottom(); + flexLine->mCrossSize = isMainAxisHorizontal(this) ? + absoluteFlexItem->getLayoutHeight() + absoluteFlexItem->getMarginTop() + + absoluteFlexItem->getMarginBottom() : + absoluteFlexItem->getLayoutWidth() + absoluteFlexItem->getMarginLeft() + + absoluteFlexItem->getMarginRight(); + flexLine->mItemCount = 1; + } + + void WXCoreLayoutNode::onLayout(const float left, const float top, const float right, const float bottom, + WXCoreLayoutNode *const absoulteItem, WXCoreFlexLine *const flexLine) { + switch (mCssStyle->mFlexDirection) { + case kFlexDirectionRow: + layoutHorizontal(false, left, top, right, bottom, absoulteItem, flexLine); + break; + case kFlexDirectionRowReverse: + layoutHorizontal(true, left, top, right, bottom, absoulteItem, flexLine); + break; + case kFlexDirectionColumnReverse: + layoutVertical(mCssStyle->mFlexWrap == kWrapReverse, true, left, top, right, bottom, absoulteItem, flexLine); + break; + case kFlexDirectionColumn: + default: + layoutVertical(mCssStyle->mFlexWrap == kWrapReverse, false, left, top, right, bottom, absoulteItem, flexLine); + break; + } + } + + /** + * Sub method for {@link WXCoreLayoutNode #onLayout(int, int, int, int)} when the + * {@link #mFlexDirection} is either {@link WXCoreFlexDirection #WXCore_Flex_Direction_Row} or + * {@link WXCoreFlexDirection #WXCore_Flex_Direction_Row_REVERSE}. + * + * @param isRtl {@code true} if the horizontal layout direction is mStyleRight to mStyleLeft, {@code + * false} otherwise. + * @param left the mStyleLeft position of this View + * @param top the mStyleTop position of this View + * @param right the mStyleRight position of this View + * @param bottom the mStyleBottom position of this View + */ + void WXCoreLayoutNode::layoutHorizontal(const bool isRtl, + const float left, const float top, + const float right, const float bottom, + WXCoreLayoutNode *const absoulteItem, + WXCoreFlexLine *const flexLine) { + Index currentViewIndex = 0; + float height = bottom - top; + float width = right - left; + + // childBottom is used if the mFlexWrap is FLEX_WRAP_WRAP_REVERSE otherwise + // childTop is used to align the vertical position of the children views. + float childBottom = height - getPaddingBottom() - getBorderWidthBottom(); + float childTop = getPaddingTop() + getBorderWidthTop(); + + // Used only for RTL layout + // Use float to reduce the round error that may happen in when justifyContent == + // SPACE_BETWEEN or SPACE_AROUND + float childLeft, childRight; + const std::vector<WXCoreFlexLine*> &lines = (flexLine == nullptr? mFlexLines: std::vector<WXCoreFlexLine*>{flexLine}); + + for (WXCoreFlexLine *flexLine: lines) { + float spaceBetweenItem = 0.f; + layoutFlexlineHorizontal(width, flexLine, childLeft, childRight, spaceBetweenItem); + spaceBetweenItem = std::max(spaceBetweenItem, 0.f); + + if(absoulteItem == nullptr) { + for (Index j = 0; j < flexLine->mItemCount; j++) { + WXCoreLayoutNode *child = getChildAt(kNonBFC, currentViewIndex); + if (child == nullptr) { + continue; + } + layoutSingleChildHorizontal(isRtl, false, childBottom, childTop, + flexLine, child, childLeft, childRight); + childLeft += child->mLayoutResult->mLayoutSize.width + spaceBetweenItem + child->getMarginRight(); + childRight -= child->mLayoutResult->mLayoutSize.width + spaceBetweenItem + child->getMarginLeft(); + currentViewIndex++; + } + childTop += flexLine->mCrossSize; + childBottom -= flexLine->mCrossSize; + } + else{ + layoutSingleChildHorizontal(isRtl, true, childBottom, childTop, + flexLine, absoulteItem, childLeft, childRight); + } + } + } + + void WXCoreLayoutNode::layoutFlexlineHorizontal(const float width, + const WXCoreFlexLine *const flexLine, + float &childLeft, + float &childRight, + float &spaceBetweenItem) const { + Index visibleCount, visibleItem; + float denominator; + switch (mCssStyle->mJustifyContent) { + case kJustifyFlexEnd: + childLeft = width - flexLine->mMainSize - getPaddingRight() - getBorderWidthRight(); + childRight = width - getPaddingLeft() - getBorderWidthLeft(); + break; + case kJustifyCenter: + childLeft = (width - flexLine->mMainSize - mCssStyle->sumPaddingBorderOfEdge(kRight) + + mCssStyle->sumPaddingBorderOfEdge(kLeft)) / 2; + childRight = childLeft + flexLine->mMainSize; + break; + case kJustifySpaceAround: + visibleCount = flexLine->mItemCount; + if (visibleCount != 0) { + spaceBetweenItem = + (width - flexLine->mMainSize - sumPaddingBorderAlongAxis(this, true)) / visibleCount; + } + childLeft = getPaddingLeft() + getBorderWidthLeft() + spaceBetweenItem / 2.f; + childRight = width - getPaddingRight() - getBorderWidthRight() - spaceBetweenItem / 2.f; + break; + case kJustifySpaceBetween: + childLeft = getPaddingLeft() + getBorderWidthLeft(); + visibleItem = flexLine->mItemCount; + denominator = visibleItem != 1 ? visibleItem - 1 : 1.f; + spaceBetweenItem = + (width - flexLine->mMainSize - sumPaddingBorderAlongAxis(this, true)) / denominator; + childRight = width - getPaddingRight() - getBorderWidthRight(); + break; + case kJustifyFlexStart: + default: + childLeft = getPaddingLeft() + getBorderWidthLeft(); + childRight = width - getPaddingRight() - getBorderWidthRight(); + break; + } + } + + void WXCoreLayoutNode::layoutSingleChildHorizontal(const bool isRtl, const bool absoulteItem, + float childBottom, float childTop, + WXCoreFlexLine *const flexLine, + WXCoreLayoutNode *const child, + float &childLeft, float &childRight) { + childLeft += child->getMarginLeft(); + childRight -= child->getMarginRight(); + if (mCssStyle->mFlexWrap == kWrapReverse) { + if (isRtl) { + layoutSingleChildHorizontal(child, + flexLine, + mCssStyle->mFlexWrap, + mCssStyle->mAlignItems, + childRight - child->mLayoutResult->mLayoutSize.width, + childBottom - child->mLayoutResult->mLayoutSize.height, + childRight, + childBottom, + absoulteItem); + } else { + layoutSingleChildHorizontal(child, + flexLine, + mCssStyle->mFlexWrap, + mCssStyle->mAlignItems, + childLeft, + childBottom - child->mLayoutResult->mLayoutSize.height, + childLeft + child->mLayoutResult->mLayoutSize.width, + childBottom, + absoulteItem); + } + } else { + if (isRtl) { + layoutSingleChildHorizontal(child, flexLine, mCssStyle->mFlexWrap, mCssStyle->mAlignItems, + childRight - child->mLayoutResult->mLayoutSize.width, childTop, + childRight, childTop + child->mLayoutResult->mLayoutSize.height, + absoulteItem); + } else { + layoutSingleChildHorizontal(child, flexLine, mCssStyle->mFlexWrap, mCssStyle->mAlignItems, + childLeft, childTop, + childLeft + child->mLayoutResult->mLayoutSize.width, + childTop + child->mLayoutResult->mLayoutSize.height, + absoulteItem); + } + } + } + + /** + * Place a single View when the layout direction is horizontal ({@link #mFlexDirection} is + * either {@link WXCoreFlexDirection #WXCore_Flex_Direction_Row} or + * {@link WXCoreFlexDirection #WXCore_Flex_Direction_Row_REVERSE}). + * + * @param node the View to be placed + * @param flexLine the {@link WXCoreFlexLine} where the View belongs to + * @param flexWrap the flex wrap attribute of this BasicLayoutNode + * @param alignItems the align items attribute of this BasicLayoutNode + * @param left the mStyleLeft position of the View, which the View's margin is already taken + * into account + * @param top the mStyleTop position of the flex line where the View belongs to. The actual + * View's mStyleTop position is shifted depending on the flexWrap and alignItems + * attributes + * @param right the mStyleRight position of the View, which the View's margin is already taken + * into account + * @param bottom the mStyleBottom position of the flex line where the View belongs to. The actual + * View's mStyleBottom position is shifted depending on the flexWrap and alignItems + * attributes + */ + void WXCoreLayoutNode::layoutSingleChildHorizontal(WXCoreLayoutNode *const node, WXCoreFlexLine* const flexLine, + const WXCoreFlexWrap flexWrap, WXCoreAlignItems alignItems, + const float left, const float top, const float right, const float bottom, const bool absoluteFlexItem) { + if (node->mCssStyle->mAlignSelf != kAlignSelfAuto) { + // Expecting the values for alignItems and alignSelf match except for ALIGN_SELF_AUTO. + // Assigning the alignSelf value as alignItems should work. + alignItems = static_cast<WXCoreAlignItems>(node->mCssStyle->mAlignSelf); + } + + float crossSize = flexLine->mCrossSize; + + switch (alignItems) { + case kAlignItemsFlexStart: + case kAlignItemsStretch: + if (flexWrap != kWrapReverse) { + node->layout(left, top + node->getMarginTop(), right, bottom + node->getMarginTop(), absoluteFlexItem); + } else { + node->layout(left, top - node->getMarginBottom(), right, bottom - node->getMarginBottom(), absoluteFlexItem); + } + break; + case kAlignItemsFlexEnd: + if (flexWrap != kWrapReverse) { + node->layout(left, + top + crossSize - node->mLayoutResult->mLayoutSize.height - node->getMarginBottom(), + right, top + crossSize - node->getMarginBottom(), absoluteFlexItem); + } else { + // If the flexWrap == FLEX_WRAP_WRAP_REVERSE, the direction of the + // flexEnd is flipped (from mStyleTop to mStyleBottom). + node->layout(left, top - crossSize + node->mLayoutResult->mLayoutSize.height + node->getMarginTop(), + right, bottom - crossSize + node->mLayoutResult->mLayoutSize.height + node->getMarginTop(), absoluteFlexItem); + } + break; + case kAlignItemsCenter: + float topFromCrossAxis = (crossSize - node->mLayoutResult->mLayoutSize.height + + node->getMarginTop() - node->getMarginBottom()) / 2; + if (flexWrap != kWrapReverse) { + node->layout(left, top + topFromCrossAxis, + right, top + topFromCrossAxis + node->mLayoutResult->mLayoutSize.height, absoluteFlexItem); + } else { + node->layout(left, top - topFromCrossAxis, + right, top - topFromCrossAxis + node->mLayoutResult->mLayoutSize.height, absoluteFlexItem); + } + break; + } + } + + /** + * Sub method for {@link WXCoreLayoutNode #onLayout(int, int, int, int)} when the + * {@link #mFlexDirection} is either {@link WXCoreFlexDirection #WXCore_Flex_Direction_Column} or + * {@link WXCoreFlexDirection #WXCore_Flex_Direction_Column_Reverse}. + * + * @param isRtl {@code true} if the horizontal layout direction is mStyleRight to mStyleLeft, + * {@code false} + * otherwise + * @param fromBottomToTop {@code true} if the layout direction is mStyleBottom to mStyleTop, {@code false} + * otherwise + * @param left the mStyleLeft position of this View + * @param top the mStyleTop position of this View + * @param right the mStyleRight position of this View + * @param bottom the mStyleBottom position of this View + */ + void + WXCoreLayoutNode::layoutVertical(const bool isRtl, + const bool fromBottomToTop, + const float left, const float top, + const float right, const float bottom, + WXCoreLayoutNode *const absoulteItem, + WXCoreFlexLine *const flexLine) { + float childLeft = getPaddingLeft() + getBorderWidthLeft(); + Index currentViewIndex = 0; + float width = right - left; + float height = bottom - top; + + // childRight is used if the mFlexWrap is FLEX_WRAP_WRAP_REVERSE otherwise + // childLeft is used to align the horizontal position of the children views. + float childRight = width - getPaddingRight() - getBorderWidthRight(); + + // Use float to reduce the round error that may happen in when justifyContent == + // SPACE_BETWEEN or SPACE_AROUND + float childTop, childBottom; + const std::vector<WXCoreFlexLine*> &lines = (flexLine == nullptr? mFlexLines: std::vector<WXCoreFlexLine*>{flexLine}); + + for (WXCoreFlexLine *flexLine : lines) { + float spaceBetweenItem = 0.f; + layoutFlexlineVertical(height, flexLine, childTop, childBottom, spaceBetweenItem); + spaceBetweenItem = std::max(spaceBetweenItem, 0.f); + if(absoulteItem == nullptr) { + for (Index j = 0; j < flexLine->mItemCount; j++) { + WXCoreLayoutNode *child = getChildAt(kNonBFC, currentViewIndex); + if (child == nullptr) { + continue; + } + layoutSingleChildVertical(isRtl, fromBottomToTop, false, + childLeft, childRight, flexLine, + child, childTop, childBottom); + childTop += child->mLayoutResult->mLayoutSize.height + spaceBetweenItem + child->getMarginBottom(); + childBottom -= child->mLayoutResult->mLayoutSize.height + spaceBetweenItem + child->getMarginTop(); + currentViewIndex++; + } + childLeft += flexLine->mCrossSize; + childRight -= flexLine->mCrossSize; + } + else{ + layoutSingleChildVertical(isRtl, fromBottomToTop, true, + childLeft, childRight, flexLine, + absoulteItem, childTop, childBottom); + } + } + } + + void WXCoreLayoutNode::layoutFlexlineVertical(const float height, + const WXCoreFlexLine *const flexLine, + float &childTop, + float &childBottom, + float &spaceBetweenItem) const { + Index visibleCount, visibleItem; + float denominator; + switch (mCssStyle->mJustifyContent) { + case kJustifyFlexEnd: + childTop = height - flexLine->mMainSize - getPaddingBottom() - getBorderWidthBottom(); + childBottom = height - getPaddingTop() - getBorderWidthTop(); + break; + case kJustifyCenter: + childTop = (height - flexLine->mMainSize - mCssStyle->sumPaddingBorderOfEdge(kBottom) + + mCssStyle->sumPaddingBorderOfEdge(kTop)) / 2; + childBottom = childTop + flexLine->mMainSize; + break; + case kJustifySpaceAround: + visibleCount = flexLine->mItemCount; + if (visibleCount != 0) { + spaceBetweenItem = (height - flexLine->mMainSize - sumPaddingBorderAlongAxis(this, false)) + / visibleCount; + } + childTop = getPaddingTop() + getBorderWidthTop() + spaceBetweenItem / 2; + childBottom = height - getPaddingBottom() - getBorderWidthBottom() - spaceBetweenItem / 2; + break; + case kJustifySpaceBetween: + childTop = getPaddingTop() + getBorderWidthTop(); + visibleItem = flexLine->mItemCount; + denominator = visibleItem != 1 ? visibleItem - 1 : 1.f; + spaceBetweenItem = + (height - flexLine->mMainSize - sumPaddingBorderAlongAxis(this, false)) / denominator; + childBottom = height - getPaddingBottom() - getBorderWidthBottom(); + break; + case kJustifyFlexStart: + default: + childTop = getPaddingTop() + getBorderWidthTop(); + childBottom = height - getPaddingBottom() - getBorderWidthBottom(); + break; + } + } + + void WXCoreLayoutNode::layoutSingleChildVertical(const bool isRtl, const bool fromBottomToTop, + const bool absoluteFlexItem, + const float childLeft, const float childRight, + WXCoreFlexLine *const flexLine, + WXCoreLayoutNode *const child, + float &childTop, float &childBottom) { + childTop += child->getMarginTop(); + childBottom -= child->getMarginBottom(); + if (isRtl) { + if (fromBottomToTop) { + layoutSingleChildVertical(child, flexLine, true, + mCssStyle->mAlignItems, + childRight - child->mLayoutResult->mLayoutSize.width, + childBottom - child->mLayoutResult->mLayoutSize.height, + childRight, childBottom, absoluteFlexItem); + } else { + layoutSingleChildVertical(child, flexLine, true, mCssStyle->mAlignItems, + childRight - child->mLayoutResult->mLayoutSize.width, childTop, + childRight, childTop + child->mLayoutResult->mLayoutSize.height, + absoluteFlexItem); + } + } else { + if (fromBottomToTop) { + layoutSingleChildVertical(child, flexLine, false, mCssStyle->mAlignItems, + childLeft, childBottom - child->mLayoutResult->mLayoutSize.height, + childLeft + child->mLayoutResult->mLayoutSize.width, childBottom, + absoluteFlexItem); + } else { + layoutSingleChildVertical(child, flexLine, false, mCssStyle->mAlignItems, + childLeft, childTop, + childLeft + child->mLayoutResult->mLayoutSize.width, + childTop + child->mLayoutResult->mLayoutSize.height, + absoluteFlexItem); + } + } + } + + /** + * Place a single View when the layout direction is vertical ({@link #mFlexDirection} is + * either {@link WXCoreFlexDirection #WXCore_Flex_Direction_Column} or + * {@link WXCoreFlexDirection #WXCore_Flex_Direction_Column_Reverse}). + * + * @param node the View to be placed + * @param flexLine the {@link FlexLine} where the View belongs to + * @param isRtl {@code true} if the layout direction is mStyleRight to mStyleLeft, {@code false} + * otherwise + * @param alignItems the align items attribute of this BasicLayoutNode + * @param left the mStyleLeft position of the flex line where the View belongs to. The actual + * View's mStyleLeft position is shifted depending on the isRtl and alignItems + * attributes + * @param top the mStyleTop position of the View, which the View's margin is already taken + * into account + * @param right the mStyleRight position of the flex line where the View belongs to. The actual + * View's mStyleRight position is shifted depending on the isRtl and alignItems + * attributes + * @param bottom the mStyleBottom position of the View, which the View's margin is already taken + * into account + */ + void WXCoreLayoutNode::layoutSingleChildVertical(WXCoreLayoutNode* const node, WXCoreFlexLine* const flexLine, const bool isRtl, + WXCoreAlignItems alignItems, const float left, const float top, const float right, + const float bottom, const bool absoluteFlexItem) { + if (node->mCssStyle->mAlignSelf != kAlignSelfAuto) { + // Expecting the values for alignItems and alignSelf match except for ALIGN_SELF_AUTO. + // Assigning the alignSelf value as alignItems should work. + alignItems = static_cast<WXCoreAlignItems>(node->mCssStyle->mAlignSelf); + } + + float crossSize = flexLine->mCrossSize; + + switch (alignItems) { + case kAlignItemsFlexStart: + case kAlignItemsStretch: + if (!isRtl) { + node->layout(left + node->getMarginLeft(), top, right + node->getMarginLeft(), bottom, absoluteFlexItem); + } else { + node->layout(left - node->getMarginRight(), top, right - node->getMarginRight(), bottom, absoluteFlexItem); + } + break; + case kAlignItemsFlexEnd: + if (!isRtl) { + node->layout(left + crossSize - node->mLayoutResult->mLayoutSize.width - node->getMarginRight(), + top, right + crossSize - node->mLayoutResult->mLayoutSize.width - node->getMarginRight(), + bottom, absoluteFlexItem); + } else { + // If the flexWrap == FLEX_WRAP_WRAP_REVERSE, the direction of the + // flexEnd is flipped (from mStyleLeft to mStyleRight). + node->layout(left - crossSize + node->mLayoutResult->mLayoutSize.width + node->getMarginLeft(), top, + right - crossSize + node->mLayoutResult->mLayoutSize.width + node->getMarginLeft(), + bottom, absoluteFlexItem); + } + break; + case kAlignItemsCenter: + float leftFromCrossAxis = (crossSize - node->mLayoutResult->mLayoutSize.width + + node->getMarginLeft() + - node->getMarginRight()) / 2.f; + if (!isRtl) { + node->layout(left + leftFromCrossAxis, top, right + leftFromCrossAxis, bottom, absoluteFlexItem); + } else { + node->layout(left - leftFromCrossAxis, top, right - leftFromCrossAxis, bottom, absoluteFlexItem); + } + break; + } + } +} + +
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b77b4259/ios/sdk/WeexSDK/Sources/Layout/WXCoreLayout.h ---------------------------------------------------------------------- diff --git a/ios/sdk/WeexSDK/Sources/Layout/WXCoreLayout.h b/ios/sdk/WeexSDK/Sources/Layout/WXCoreLayout.h new file mode 100644 index 0000000..498c243 --- /dev/null +++ b/ios/sdk/WeexSDK/Sources/Layout/WXCoreLayout.h @@ -0,0 +1,1073 @@ +#ifdef __cplusplus + +#ifndef WEEXCORE_FLEXLAYOUT_WXCORELAYOUTNODE_H +#define WEEXCORE_FLEXLAYOUT_WXCORELAYOUTNODE_H + +#include "WXCoreStyle.h" +#include "WXCoreFlexEnum.h" +#include <vector> +#include <iostream> +#include <string> +#include <algorithm> + +namespace WeexCore { + + class WXCoreLayoutNode; + + class WXCoreFlexLine; + + enum FormattingContext { + kBFC, + kNonBFC, + } ; + + enum MeasureMode { + kUnspecified, + 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(); + } + + + ~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; + + WXCoreMeasureFunc measureFunc = nullptr; + + void *context; + + /** ================================ 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 WXCoreMeasureFunc getMeasureFunc() const { + return measureFunc; + } + + inline bool haveMeasureFunc() const { + return measureFunc != nullptr; + } + + /** ================================ 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(); + } + } + + inline void copyMeasureFunc(WXCoreLayoutNode *srcNode) { + if (memcmp(&measureFunc, &srcNode->measureFunc, sizeof(WXCoreMeasureFunc)) != 0) { + memcpy(&measureFunc, &srcNode->measureFunc, sizeof(WXCoreMeasureFunc)); + markDirty(); + } + } + + 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 = calcFreeSpaceAlongMainAxis(width, height, currentLength); + return !isSingleFlexLine(freeMainSize) && freeMainSize < childLength; + } + + //If width/height is NAN, ret is NAN, which property we use on purpose. + virtual float calcFreeSpaceAlongMainAxis(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 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 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 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 getStypePositionType() 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 setFlex(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(); + } + } + } + + 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)); + } + }; +} +#endif //WEEXCORE_FLEXLAYOUT_WXCORELAYOUTNODE_H +#endif
