1 /* 2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 #include "core/components/flex/render_flex.h" 17 18 #include "base/log/dump_log.h" 19 #include "core/components/flex/flex_component.h" 20 #include "core/components/scroll/render_single_child_scroll.h" 21 #include "core/pipeline/base/position_layout_utils.h" 22 23 namespace OHOS::Ace { 24 namespace { 25 26 const static int32_t PLATFORM_VERSION_FIVE = 5; 27 FlipAxis(FlexDirection direction)28 inline FlexDirection FlipAxis(FlexDirection direction) 29 { 30 if (direction == FlexDirection::ROW || direction == FlexDirection::ROW_REVERSE) { 31 return FlexDirection::COLUMN; 32 } else { 33 return FlexDirection::ROW; 34 } 35 } 36 GetMainAxisValue(const Size & size,FlexDirection direction)37 double GetMainAxisValue(const Size& size, FlexDirection direction) 38 { 39 return direction == FlexDirection::ROW || direction == FlexDirection::ROW_REVERSE ? size.Width() : size.Height(); 40 } 41 IsNonRelativePosition(PositionType pos)42 inline bool IsNonRelativePosition(PositionType pos) 43 { 44 return ( 45 (pos != PositionType::PTRELATIVE) && (pos != PositionType::PTSEMI_RELATIVE) && (pos != PositionType::PTOFFSET)); 46 } 47 48 } // namespace 49 Create()50 RefPtr<RenderNode> RenderFlex::Create() 51 { 52 return AceType::MakeRefPtr<RenderFlex>(); 53 } 54 Update(const RefPtr<Component> & component)55 void RenderFlex::Update(const RefPtr<Component>& component) 56 { 57 const RefPtr<FlexComponent> flex = AceType::DynamicCast<FlexComponent>(component); 58 if (!flex) { 59 return; 60 } 61 isTabs_ = flex->GetTabsFlag(); 62 isTabContent_ = flex->GetTabContentFlag(); 63 64 direction_ = flex->GetDirection(); 65 mainAxisAlign_ = flex->GetMainAxisAlign(); 66 crossAxisAlign_ = flex->GetCrossAxisAlign(); 67 mainAxisSize_ = flex->GetMainAxisSize(); 68 crossAxisSize_ = flex->GetCrossAxisSize(); 69 stretchToParent_ = flex->IsStretchToParent(); 70 useViewPort_ = flex->GetUseViewPortFlag(); 71 containsNavigation_ = flex->ContainsNavigation(); 72 overflow_ = flex->GetOverflow(); 73 SetTextDirection(flex->GetTextDirection()); 74 alignPtr_ = flex->GetAlignDeclarationPtr(); 75 76 auto context = GetContext().Upgrade(); 77 if (context) { 78 space_ = context->NormalizeToPx(flex->GetSpace()); 79 inspectorSpace_ = flex->GetSpace(); 80 useOldLayoutVersion_ = context->GetMinPlatformVersion() <= PLATFORM_VERSION_FIVE; 81 isDeclarative_ = context->GetIsDeclarative(); 82 } 83 UpdateAccessibilityAttr(); 84 MarkNeedLayout(); 85 } 86 UpdateAccessibilityAttr()87 void RenderFlex::UpdateAccessibilityAttr() 88 { 89 auto refPtr = accessibilityNode_.Upgrade(); 90 if (!refPtr) { 91 return; 92 } 93 RefPtr<RenderSingleChildScroll> scroll; 94 auto parent = GetParent().Upgrade(); 95 while (parent) { 96 scroll = AceType::DynamicCast<RenderSingleChildScroll>(parent); 97 if (scroll) { 98 break; 99 } 100 parent = parent->GetParent().Upgrade(); 101 } 102 if (!scroll || !scroll->GetAccessibilityNode().Upgrade()) { 103 return; 104 } 105 if (scroll->GetAccessibilityNode().Upgrade()->GetNodeId() != refPtr->GetNodeId()) { 106 return; 107 } 108 109 refPtr->SetScrollableState(true); 110 refPtr->SetActionScrollForward([weakScroll = AceType::WeakClaim(RawPtr(scroll))]() { 111 auto scroll = weakScroll.Upgrade(); 112 if (scroll) { 113 scroll->ScrollPage(false, true); 114 return true; 115 } 116 return false; 117 }); 118 refPtr->SetActionScrollBackward([weakScroll = AceType::WeakClaim(RawPtr(scroll))]() { 119 auto scroll = weakScroll.Upgrade(); 120 if (scroll) { 121 scroll->ScrollPage(true, true); 122 return true; 123 } 124 return false; 125 }); 126 refPtr->AddSupportAction(AceAction::ACTION_SCROLL_FORWARD); 127 refPtr->AddSupportAction(AceAction::ACTION_SCROLL_BACKWARD); 128 scrollNode = scroll; 129 } 130 OnPaintFinish()131 void RenderFlex::OnPaintFinish() 132 { 133 auto refPtr = accessibilityNode_.Upgrade(); 134 if (!refPtr || !scrollNode) { 135 return; 136 } 137 auto collectionInfo = refPtr->GetCollectionInfo(); 138 collectionInfo.rows = static_cast<int32_t>(GetChildren().size()); 139 collectionInfo.columns = 1; 140 refPtr->SetCollectionInfo(collectionInfo); 141 Rect itemRect; 142 Rect viewPortRect(scrollNode->GetGlobalOffset(), scrollNode->GetChildViewPort()); 143 for (const auto& item : GetChildren()) { 144 auto node = item->GetAccessibilityNode().Upgrade(); 145 if (!node) { 146 continue; 147 } 148 bool visible = GetVisible(); 149 if (visible) { 150 itemRect.SetSize(item->GetLayoutSize()); 151 itemRect.SetOffset(item->GetGlobalOffset()); 152 visible = itemRect.IsIntersectWith(viewPortRect); 153 } 154 item->SetAccessibilityVisible(visible); 155 if (visible) { 156 Rect clampRect = itemRect.Constrain(viewPortRect); 157 if (clampRect != itemRect) { 158 item->SetAccessibilityRect(clampRect); 159 } 160 } else { 161 item->NotifyPaintFinish(); 162 } 163 } 164 } 165 MakeStretchInnerLayoutParam(const RefPtr<RenderNode> & item) const166 LayoutParam RenderFlex::MakeStretchInnerLayoutParam(const RefPtr<RenderNode>& item) const 167 { 168 // must be called in the second time layout, so that crossSize_ is determined. 169 LayoutParam innerLayout; 170 double crossAxisLimit = GetStretchCrossLimit(); 171 if (direction_ == FlexDirection::ROW || direction_ == FlexDirection::ROW_REVERSE) { 172 innerLayout.SetFixedSize(Size(GetMainSize(item), crossAxisLimit)); 173 } else { 174 innerLayout.SetFixedSize(Size(crossAxisLimit, GetMainSize(item))); 175 } 176 return innerLayout; 177 } 178 MakeLayoutParamWithLimit(double minMainLimit,double maxMainLimit,bool isStretch) const179 LayoutParam RenderFlex::MakeLayoutParamWithLimit(double minMainLimit, double maxMainLimit, bool isStretch) const 180 { 181 LayoutParam innerLayout; 182 double minCrossLimit = 0.0; 183 double maxCrossLimit = (direction_ == FlexDirection::ROW || direction_ == FlexDirection::ROW_REVERSE) 184 ? GetLayoutParam().GetMaxSize().Height() 185 : GetLayoutParam().GetMaxSize().Width(); 186 if (isStretch) { 187 minCrossLimit = GetStretchCrossLimit(); 188 maxCrossLimit = minCrossLimit; 189 } 190 if (direction_ == FlexDirection::ROW || direction_ == FlexDirection::ROW_REVERSE) { 191 innerLayout.SetMinSize(Size(minMainLimit, minCrossLimit)); 192 innerLayout.SetMaxSize(Size(maxMainLimit, maxCrossLimit)); 193 } else { 194 innerLayout.SetMinSize(Size(minCrossLimit, minMainLimit)); 195 innerLayout.SetMaxSize(Size(maxCrossLimit, maxMainLimit)); 196 } 197 return innerLayout; 198 } 199 MakeConstrainedLayoutParam(double mainFlexExtent,const LayoutParam & constraints,bool isStretch,bool supportZero) const200 LayoutParam RenderFlex::MakeConstrainedLayoutParam( 201 double mainFlexExtent, const LayoutParam& constraints, bool isStretch, bool supportZero) const 202 { 203 LayoutParam innerLayout; 204 if (LessNotEqual(mainFlexExtent, 0.0)) { 205 innerLayout.SetMaxSize(GetLayoutParam().GetMaxSize()); 206 } else if (GreatNotEqual(mainFlexExtent, 0.0)) { 207 innerLayout = MakeLayoutParamWithLimit(mainFlexExtent, mainFlexExtent, isStretch); 208 } else { 209 if (supportZero) { 210 innerLayout = MakeLayoutParamWithLimit(mainFlexExtent, mainFlexExtent, isStretch); 211 } else { 212 innerLayout.SetMaxSize(GetLayoutParam().GetMaxSize()); 213 } 214 } 215 innerLayout.SetMaxSize(constraints.Constrain(innerLayout.GetMaxSize())); 216 innerLayout.SetMinSize(constraints.Constrain(innerLayout.GetMinSize())); 217 // SetHasUsedPercentFlag is to tell box not to use constraints 218 innerLayout.SetHasUsedConstraints(true); 219 return innerLayout; 220 } 221 GetStretchCrossLimit() const222 double RenderFlex::GetStretchCrossLimit() const 223 { 224 Size maxLayoutParam = GetLayoutParam().GetMaxSize(); 225 double crossAxisLimit = 0.0; 226 if (!stretchToParent_) { 227 crossAxisLimit = crossSize_; 228 } else if (!isCrossInfinite_ || !useViewPort_) { 229 crossAxisLimit = (direction_ == FlexDirection::ROW || direction_ == FlexDirection::ROW_REVERSE) 230 ? maxLayoutParam.Height() 231 : maxLayoutParam.Width(); 232 } else { 233 crossAxisLimit = (direction_ == FlexDirection::ROW || direction_ == FlexDirection::ROW_REVERSE) 234 ? viewPort_.Height() 235 : viewPort_.Width(); 236 } 237 return crossAxisLimit; 238 } 239 PerformLayout()240 void RenderFlex::PerformLayout() 241 { 242 if (GetChildren().empty()) { 243 SetLayoutSize(Size()); 244 return; 245 } 246 247 auto context = GetContext().Upgrade(); 248 if (!context) { 249 return; 250 } 251 if (alignPtr_ != nullptr) { 252 context->AddAlignDeclarationNode(AceType::Claim(this)); 253 } 254 255 // init properties. 256 InitFlexProperties(); 257 if (layoutMode_ == FlexLayoutMode::FLEX_WEIGHT_MODE) { 258 PerformLayoutInWeightMode(); 259 } else if (maxDisplayIndex_ > 1) { 260 PerformLayoutInIndexMode(); 261 } else { 262 PerformLayoutInItemMode(); 263 } 264 ClearChildrenLists(); 265 266 if (alignPtr_ != nullptr) { 267 auto& nodeList = context->GetAlignDeclarationNodeList(); 268 PerformItemAlign(nodeList); 269 } 270 } 271 PerformLayoutInWeightMode()272 void RenderFlex::PerformLayoutInWeightMode() 273 { 274 double maxMainSize = GetMainAxisValue(GetLayoutParam().GetMaxSize(), direction_); 275 if (NearEqual(maxMainSize, Size::INFINITE_SIZE)) { 276 LOGW("not supported infinite size"); 277 return; 278 } 279 if (!relativeNodes_.empty()) { 280 maxMainSize -= GetSpace() * (relativeNodes_.size() - 1); 281 } 282 BaselineProperties baselineProperties; 283 LayoutParam innerLayout; 284 double allocatedSize = allocatedSize_; 285 for (const auto& child : relativeNodes_) { 286 if (LessOrEqual(child->GetFlexWeight(), 0.0)) { 287 child->Layout(GetLayoutParam()); 288 ResizeByItem(child, allocatedSize); 289 CheckSizeValidity(child); 290 CheckBaselineProperties(child, baselineProperties); 291 } 292 } 293 maxMainSize -= allocatedSize_; 294 // if remain size less than zero, adjust it to zero 295 if (!useOldLayoutVersion_ && LessNotEqual(maxMainSize, 0.0)) { 296 maxMainSize = 0.0; 297 } 298 // totalFlexWeight_ is guard in InitFlexProperties() so it won't be zero 299 auto spacePerWeight = maxMainSize / totalFlexWeight_; 300 bool isExceed = false; 301 auto iter = magicNodes_.rbegin(); 302 // Calculate innerLayoutParam for each magic node 303 while (iter != magicNodes_.rend()) { 304 auto& layoutList = (*iter).second; 305 for (auto& node : layoutList) { 306 auto child = node.node; 307 if (LessOrEqual(child->GetFlexWeight(), 0.0)) { 308 continue; 309 } 310 auto childFlexSize = spacePerWeight * child->GetFlexWeight(); 311 auto flexItem = AceType::DynamicCast<RenderFlexItem>(child); 312 if (flexItem) { 313 innerLayout = MakeConstrainedLayoutParam( 314 childFlexSize, flexItem->GetNormalizedConstraints(), false, !useOldLayoutVersion_); 315 } else { 316 innerLayout = MakeLayoutParamWithLimit(childFlexSize, childFlexSize, false); 317 } 318 // If min constraint is larger than flexSize, total size must exceed. 319 isExceed = isExceed || GetMainAxisValue(innerLayout.GetMaxSize(), direction_) > childFlexSize; 320 node.innerLayout = innerLayout; 321 } 322 if (!isExceed) { 323 iter++; 324 } else if (magicNodes_.size() <= 1) { 325 break; 326 } else { 327 // Hide nodes, reset properties and start next loop 328 totalFlexWeight_ -= magicWeightMaps_[(*magicNodes_.begin()).first]; 329 spacePerWeight = maxMainSize / totalFlexWeight_; 330 isExceed = false; 331 magicNodes_.erase(magicNodes_.begin()); 332 iter = magicNodes_.rbegin(); 333 } 334 } 335 // Layout magic nodes 336 LayoutMagicNodes(baselineProperties); 337 if (crossAxisAlign_ == FlexAlign::STRETCH) { 338 RelayoutForStretchMagicNode(); 339 } 340 LayoutAbsoluteChildren(); 341 LayoutHiddenNodes(); 342 Size layoutSize = GetConstrainedSize(GetMainAxisValue(GetLayoutParam().GetMaxSize(), direction_)); 343 SetLayoutSize(layoutSize); 344 mainSize_ = GetMainAxisValue(layoutSize, direction_); 345 crossSize_ = (direction_ == FlexDirection::ROW || direction_ == FlexDirection::ROW_REVERSE) ? layoutSize.Height() 346 : layoutSize.Width(); 347 DetermineItemsPosition(baselineProperties); 348 } 349 LayoutMagicNodes(BaselineProperties & baselineProperties)350 void RenderFlex::LayoutMagicNodes(BaselineProperties& baselineProperties) 351 { 352 double allocatedSize = allocatedSize_; 353 for (const auto& magicNode : magicNodes_) { 354 auto nodeList = magicNode.second; 355 for (const auto& child : nodeList) { 356 if (LessOrEqual(child.node->GetFlexWeight(), 0.0)) { 357 continue; 358 } 359 child.node->Layout(child.innerLayout); 360 child.node->SetVisible(GetVisible()); 361 ResizeByItem(child.node, allocatedSize); 362 CheckSizeValidity(child.node); 363 CheckBaselineProperties(child.node, baselineProperties); 364 } 365 } 366 } 367 RelayoutForStretchMagicNode()368 void RenderFlex::RelayoutForStretchMagicNode() 369 { 370 LayoutParam innerLayout; 371 for (const auto& magicNodeMap : magicNodes_) { 372 auto nodeList = magicNodeMap.second; 373 for (const auto& node : nodeList) { 374 auto child = node.node; 375 auto flexItem = AceType::DynamicCast<RenderFlexItem>(child); 376 if (!flexItem) { 377 innerLayout = MakeLayoutParamWithLimit(GetMainSize(child), GetMainSize(child), true); 378 } else if (flexItem->GetStretchFlag()) { 379 innerLayout = 380 MakeConstrainedLayoutParam(GetMainSize(flexItem), flexItem->GetNormalizedConstraints(), true); 381 } else { 382 // FlexItem cannot be stretched, skip it. 383 continue; 384 } 385 child->Layout(innerLayout); 386 // stretch only need to adjust crossSize 387 crossSize_ = std::max(crossSize_, GetCrossSize(child)); 388 } 389 } 390 } 391 PerformLayoutInIndexMode()392 void RenderFlex::PerformLayoutInIndexMode() 393 { 394 auto maxMainSize = GetMainAxisValue(GetLayoutParam().GetMaxSize(), direction_); 395 LayoutParam innerLayout; 396 innerLayout.SetMaxSize(GetLayoutParam().GetMaxSize()); 397 FlexItemProperties flexItemProperties; 398 for (auto iter = magicNodes_.rbegin(); iter != magicNodes_.rend();) { 399 auto nodeList = (*iter).second; 400 for (const auto& node : nodeList) { 401 auto child = node.node; 402 child->Layout(innerLayout); 403 allocatedSize_ += GetMainSize(child); 404 allocatedSize_ += space_; 405 } 406 if ((allocatedSize_ - space_) > maxMainSize) { 407 for (const auto& node : nodeList) { 408 auto child = node.node; 409 allocatedSize_ -= GetMainSize(child); 410 allocatedSize_ -= space_; 411 } 412 break; 413 } 414 // If not fill all the main size, record the node and continue the loop. 415 for (const auto& node : nodeList) { 416 auto child = node.node; 417 CheckSizeValidity(child); 418 child->SetVisible(GetVisible()); 419 auto flexItem = AceType::DynamicCast<RenderFlexItem>(child); 420 if (flexItem && GreatNotEqual(flexItem->GetFlexGrow(), 0.0)) { 421 flexItemProperties.totalGrow += flexItem->GetFlexGrow(); 422 flexItemProperties.lastGrowChild = flexItem; 423 } 424 crossSize_ = std::max(crossSize_, GetCrossSize(child)); 425 } 426 if (NearEqual(allocatedSize_, maxMainSize)) { 427 break; 428 } 429 iter++; 430 } 431 // Second Layout for grow/stretch 432 if (crossAxisAlign_ == FlexAlign::STRETCH || flexItemProperties.totalGrow > 0) { 433 RelayoutForStretchFlexNode(flexItemProperties); 434 } 435 LayoutHiddenNodes(); 436 LayoutAbsoluteChildren(); 437 allocatedSize_ -= space_; 438 Size layoutSize; 439 if (!isDeclarative_ || mainAxisSize_ == MainAxisSize::MAX) { 440 layoutSize = GetConstrainedSize(maxMainSize); 441 } else { 442 layoutSize = GetConstrainedSize(allocatedSize_); 443 } 444 SetLayoutSize(layoutSize); 445 mainSize_ = GetMainAxisValue(layoutSize, direction_); 446 crossSize_ = (direction_ == FlexDirection::ROW || direction_ == FlexDirection::ROW_REVERSE) ? layoutSize.Height() 447 : layoutSize.Width(); 448 BaselineProperties baselineProperties; 449 DetermineItemsPosition(baselineProperties); 450 } 451 RelayoutForStretchFlexNode(const FlexItemProperties & flexItemProperties)452 void RenderFlex::RelayoutForStretchFlexNode(const FlexItemProperties& flexItemProperties) 453 { 454 auto remainSpace = GetMainAxisValue(GetLayoutParam().GetMaxSize(), direction_) - allocatedSize_; 455 // only grow applied in display index mode. 456 double spacePerFlex = 0.0; 457 if (GreatNotEqual(flexItemProperties.totalGrow, 0.0)) { 458 spacePerFlex = remainSpace / flexItemProperties.totalGrow; 459 } 460 double allocatedFlexSpace = 0.0; 461 BaselineProperties baselineProperties; 462 for (const auto& item : displayNodes_) { 463 auto flexItem = AceType::DynamicCast<RenderFlexItem>(item); 464 if (!flexItem) { 465 if (crossAxisAlign_ == FlexAlign::STRETCH) { 466 item->Layout(MakeStretchInnerLayoutParam(item)); 467 // stretch only need to adjust cross size 468 crossSize_ = std::max(crossSize_, GetCrossSize(item)); 469 } 470 continue; 471 } 472 if (GreatNotEqual(flexItem->GetFlexGrow(), 0.0)) { 473 double flexSize = 0.0; 474 flexSize = flexItem == flexItemProperties.lastGrowChild ? remainSpace - allocatedFlexSpace 475 : spacePerFlex * flexItem->GetFlexGrow(); 476 RedoLayoutFlexItem(flexItem, flexSize, baselineProperties, allocatedFlexSpace); 477 } else if (crossAxisAlign_ == FlexAlign::STRETCH && flexItem->GetStretchFlag()) { 478 flexItem->Layout( 479 MakeConstrainedLayoutParam(GetMainSize(flexItem), flexItem->GetNormalizedConstraints(), true)); 480 crossSize_ = std::max(crossSize_, GetCrossSize(flexItem)); 481 } else { 482 // not stretch or grow, continue. 483 continue; 484 } 485 } 486 } 487 LayoutHiddenNodes()488 void RenderFlex::LayoutHiddenNodes() 489 { 490 LayoutParam innerLayout = LayoutParam(Size(), Size()); 491 for (const auto& child : relativeNodes_) { 492 if (displayNodes_.find(child) != displayNodes_.end()) { 493 continue; 494 } 495 child->SetVisible(false); 496 child->Layout(innerLayout); 497 } 498 } 499 PerformLayoutInItemMode()500 void RenderFlex::PerformLayoutInItemMode() 501 { 502 LayoutParam innerLayout; 503 innerLayout.SetMaxSize(GetLayoutParam().GetMaxSize()); 504 FlexItemProperties flexItemProperties; 505 BaselineProperties baselineProperties; 506 double allocatedSize = allocatedSize_; 507 // first time layout 508 for (const auto& item : relativeNodes_) { 509 auto flexItem = AceType::DynamicCast<RenderFlexItem>(item); 510 if (!flexItem || flexItem->IsHidden()) { 511 item->Layout(innerLayout); 512 } else { 513 LayoutFlexItem(flexItem, flexItemProperties); 514 } 515 if (item == GetChildren().front() && containsNavigation_) { 516 navigationMainSize_ = GetMainAxisValue(item->GetLayoutSize(), direction_); 517 } 518 ResizeByItem(item, allocatedSize); 519 CheckSizeValidity(item); 520 CheckBaselineProperties(item, baselineProperties); 521 } 522 // second time layout 523 double mainViewPort = GetMainAxisValue(viewPort_, direction_); 524 bool useViewPort = useViewPort_ && !viewPort_.IsInfinite() && (allocatedSize_ < mainViewPort); 525 auto mainAxisSize = mainAxisSize_; 526 if (!isMainInfinite_ || useViewPort) { 527 ResizeItems(flexItemProperties, baselineProperties); 528 } else if (!infinityLayoutNodes_.empty()) { 529 if (allocatedSize_ < mainViewPort) { 530 allocatedSize_ = Size::INFINITE_SIZE; 531 } else { 532 double availableMainSize = GetAvailableMainSize(); 533 for (auto& infinityItem : infinityLayoutNodes_) { 534 LayoutInfinityChild(infinityItem, availableMainSize, baselineProperties); 535 } 536 mainAxisSize = MainAxisSize::MIN; 537 } 538 } else if (allocatedSize_ >= mainViewPort && crossAxisAlign_ == FlexAlign::STRETCH) { 539 // Children size larger than viewPort, second layout only do stretch. 540 for (const auto& item : relativeNodes_) { 541 // If Item has set width/height in main axis, not need to stretch. 542 auto flexItem = AceType::DynamicCast<RenderFlexItem>(item); 543 if (flexItem && !flexItem->GetStretchFlag()) { 544 continue; 545 } 546 item->Layout(MakeStretchInnerLayoutParam(item)); 547 } 548 } else { 549 for (const auto& item : stretchNodes_) { 550 item->Layout(MakeStretchInnerLayoutParam(item)); 551 } 552 mainAxisSize = MainAxisSize::MIN; 553 } 554 LayoutAbsoluteChildren(); 555 if (needRelayoutCross_) { 556 crossSize_ = 0.0; 557 for (const auto& item : relativeNodes_) { 558 crossSize_ = std::max(crossSize_, GetCrossSize(item)); 559 } 560 } 561 // get layout size and set positions 562 DetermineSelfSize(mainAxisSize, useViewPort); 563 DetermineItemsPosition(baselineProperties); 564 } 565 ResizeItems(const FlexItemProperties & flexItemProps,BaselineProperties & baselineProps)566 void RenderFlex::ResizeItems(const FlexItemProperties& flexItemProps, BaselineProperties& baselineProps) 567 { 568 double availableMainSize = GetAvailableMainSize(); 569 if (flexItemProps.totalGrow > 0 && availableMainSize > allocatedSize_ && !isDeclarative_) { 570 mainAxisSize_ = MainAxisSize::MAX; 571 } 572 // remainSpace should be (availableMainSize - allocatedSize_), and do not remain space when MainAxisSize::MIN. 573 // Handle infinity children specially, because allocatedSize_ not include infinity child. 574 double remainSpace = 575 (mainAxisSize_ == MainAxisSize::MIN && availableMainSize >= allocatedSize_ && infinityLayoutNodes_.empty()) 576 ? 0.0 577 : availableMainSize - allocatedSize_; 578 double infiniteLayoutSize = availableMainSize; 579 if (!infinityLayoutNodes_.empty()) { 580 if (remainSpace > 0.0) { 581 infiniteLayoutSize = remainSpace / infinityLayoutNodes_.size(); 582 remainSpace = 0.0; 583 } else { 584 remainSpace -= infiniteLayoutSize; 585 } 586 } 587 // reduce layout times in special cases 588 if (relativeNodes_.size() <= 1 && crossAxisAlign_ != FlexAlign::STRETCH && NearZero(remainSpace)) { 589 return; 590 } 591 double spacePerFlex = 0.0; 592 double allocatedFlexSpace = 0.0; 593 double (*getFlex)(const RefPtr<RenderFlexItem>&) = nullptr; 594 RefPtr<RenderFlexItem> lastChild; 595 if (remainSpace > 0) { 596 getFlex = [](const RefPtr<RenderFlexItem>& item) { return item->GetFlexGrow(); }; 597 spacePerFlex = NearZero(flexItemProps.totalGrow) ? 0.0 : remainSpace / flexItemProps.totalGrow; 598 lastChild = flexItemProps.lastGrowChild; 599 } else { 600 getFlex = [](const RefPtr<RenderFlexItem>& item) { return item->GetFlexShrink(); }; 601 spacePerFlex = NearZero(flexItemProps.totalShrink) ? 0.0 : remainSpace / flexItemProps.totalShrink; 602 lastChild = flexItemProps.lastShrinkChild; 603 } 604 if (!NearZero(spacePerFlex)) { 605 needRelayoutCross_ = true; 606 } 607 // In second layout, do not need to check the size validity, they are all checked. 608 for (const auto& item : relativeNodes_) { 609 if (infinityLayoutNodes_.find(item) != infinityLayoutNodes_.end()) { 610 LayoutInfinityChild(item, infiniteLayoutSize, baselineProps); 611 continue; 612 } 613 auto flexItem = AceType::DynamicCast<RenderFlexItem>(item); 614 if (!flexItem || flexItem->IsHidden()) { 615 if (crossAxisAlign_ == FlexAlign::STRETCH) { 616 item->Layout(MakeStretchInnerLayoutParam(item)); 617 } 618 continue; 619 } 620 double itemFlex = getFlex(flexItem); 621 double flexSize = (flexItem == lastChild) ? (remainSpace - allocatedFlexSpace) 622 : ((remainSpace > 0) ? spacePerFlex * itemFlex 623 : spacePerFlex * itemFlex * GetMainSize(item)); 624 RedoLayoutFlexItem(flexItem, flexSize, baselineProps, allocatedFlexSpace); 625 } 626 } 627 DetermineSelfSize(MainAxisSize mainAxisSize,bool useViewPort)628 void RenderFlex::DetermineSelfSize(MainAxisSize mainAxisSize, bool useViewPort) 629 { 630 double maxMainSize = GetMainAxisValue(GetLayoutParam().GetMaxSize(), direction_); 631 double mainViewPort = GetMainAxisValue(viewPort_, direction_); 632 if (NearEqual(maxMainSize, Size::INFINITE_SIZE)) { 633 // If max size of layoutParam is infinity, use children's allocated size as max size. 634 maxMainSize = allocatedSize_; 635 } 636 allocatedSize_ -= space_; 637 // useViewPort means that it is the root flex, should be as large as viewPort. 638 Size layoutSize = (mainAxisSize == MainAxisSize::MIN) ? GetConstrainedSize(allocatedSize_) 639 : useViewPort ? GetConstrainedSize(mainViewPort) 640 : GetConstrainedSize(maxMainSize); 641 if (useViewPort && !absoluteNodes_.empty()) { 642 layoutSize = GetConstrainedSize(mainViewPort); 643 } 644 isChildOverflow_ = allocatedSize_ > GetMainAxisValue(layoutSize, direction_); 645 SetLayoutSize(layoutSize); 646 mainSize_ = GetMainAxisValue(layoutSize, direction_); 647 crossSize_ = (direction_ == FlexDirection::ROW || direction_ == FlexDirection::ROW_REVERSE) ? layoutSize.Height() 648 : layoutSize.Width(); 649 } 650 DetermineItemsPosition(const BaselineProperties & baselineProperties)651 void RenderFlex::DetermineItemsPosition(const BaselineProperties& baselineProperties) 652 { 653 double remainSpace = (mainSize_ - allocatedSize_) > 0.0 ? (mainSize_ - allocatedSize_) : 0.0; 654 double frontSpace = 0.0; 655 double betweenSpace = 0.0; 656 // make use of remain space 657 CalculateSpace(remainSpace, frontSpace, betweenSpace); 658 // position elements 659 PlaceChildren(frontSpace, betweenSpace, baselineProperties); 660 } 661 CalculateSpace(double remainSpace,double & frontSpace,double & betweenSpace) const662 void RenderFlex::CalculateSpace(double remainSpace, double& frontSpace, double& betweenSpace) const 663 { 664 switch (mainAxisAlign_) { 665 case FlexAlign::FLEX_START: 666 frontSpace = 0.0; 667 betweenSpace = space_; 668 break; 669 case FlexAlign::FLEX_END: 670 frontSpace = remainSpace; 671 betweenSpace = space_; 672 break; 673 case FlexAlign::CENTER: 674 frontSpace = remainSpace / 2.0; 675 betweenSpace = space_; 676 break; 677 case FlexAlign::SPACE_BETWEEN: 678 frontSpace = 0.0; 679 betweenSpace = validSizeCount_ > 1 ? remainSpace / (validSizeCount_ - 1) : 0.0; 680 break; 681 case FlexAlign::SPACE_AROUND: 682 betweenSpace = validSizeCount_ > 0 ? remainSpace / validSizeCount_ : 0.0; 683 frontSpace = betweenSpace / 2.0; 684 break; 685 case FlexAlign::SPACE_EVENLY: 686 betweenSpace = validSizeCount_ > 0 ? remainSpace / (validSizeCount_ + 1) : 0.0; 687 frontSpace = betweenSpace; 688 break; 689 default: 690 break; 691 } 692 } 693 PlaceChildren(double frontSpace,double betweenSpace,const BaselineProperties & baselineProperties)694 void RenderFlex::PlaceChildren(double frontSpace, double betweenSpace, const BaselineProperties& baselineProperties) 695 { 696 double childMainPos = IsStartTopLeft(direction_, GetTextDirection()) ? frontSpace : mainSize_ - frontSpace; 697 double childCrossPos = 0.0; 698 for (const auto& item : GetChildren()) { 699 if (item->IsIgnored()) { 700 continue; 701 } 702 auto flexItem = AceType::DynamicCast<RenderFlexItem>(item); 703 if (flexItem && flexItem->IsHidden() && !flexItem->GetLayoutSize().IsValid()) { 704 continue; 705 } 706 if (IsNonRelativePosition(item->GetPositionType())) { 707 Offset absoluteOffset = PositionLayoutUtils::GetAbsoluteOffset(Claim(this), item); 708 item->SetAbsolutePosition(absoluteOffset); 709 continue; 710 } 711 auto alignItem = GetSelfAlign(item); 712 auto textDirection = AdjustTextDirectionByDir(); 713 switch (alignItem) { 714 case FlexAlign::FLEX_START: 715 case FlexAlign::FLEX_END: 716 childCrossPos = 717 (IsStartTopLeft(FlipAxis(direction_), textDirection) == (alignItem == FlexAlign::FLEX_START)) 718 ? 0.0 719 : (crossSize_ - GetCrossSize(item)); 720 break; 721 case FlexAlign::CENTER: 722 childCrossPos = (crossSize_ / 2.0) - (GetCrossSize(item) / 2.0); 723 break; 724 case FlexAlign::STRETCH: 725 childCrossPos = 726 IsStartTopLeft(FlipAxis(direction_), textDirection) ? 0.0 : (crossSize_ - GetCrossSize(item)); 727 break; 728 case FlexAlign::BASELINE: 729 childCrossPos = 0.0; 730 if (direction_ == FlexDirection::ROW || direction_ == FlexDirection::ROW_REVERSE) { 731 double distance = item->GetBaselineDistance(textBaseline_); 732 childCrossPos = baselineProperties.maxBaselineDistance - distance; 733 } 734 break; 735 default: 736 break; 737 } 738 Offset offset; 739 if (direction_ == FlexDirection::ROW || direction_ == FlexDirection::ROW_REVERSE) { 740 if (item->GetPositionType() == PositionType::PTSEMI_RELATIVE) { 741 childMainPos = 0.0; 742 } 743 offset = Offset(childMainPos, childCrossPos); 744 } else { 745 offset = 746 Offset((item->GetPositionType() == PositionType::PTSEMI_RELATIVE) ? 0.0 : childCrossPos, childMainPos); 747 } 748 749 if (!IsStartTopLeft(direction_, GetTextDirection())) { 750 if (direction_ != FlexDirection::COLUMN_REVERSE) { 751 offset.SetX(offset.GetX() - GetMainSize(item)); 752 } else { 753 offset.SetY(offset.GetY() - GetMainSize(item)); 754 } 755 item->SetPosition(offset); 756 childMainPos -= GetMainSize(item) + betweenSpace; 757 } else { 758 item->SetPosition(offset); 759 childMainPos += GetMainSize(item) + betweenSpace; 760 } 761 } 762 } 763 LayoutFlexItem(RefPtr<RenderFlexItem> & flexItem,FlexItemProperties & flexItemProperties)764 void RenderFlex::LayoutFlexItem(RefPtr<RenderFlexItem>& flexItem, FlexItemProperties& flexItemProperties) 765 { 766 double itemShrink = flexItem->GetFlexShrink(); 767 double itemGrow = flexItem->GetFlexGrow(); 768 double itemBasis = flexItem->GetFlexBasisToPx(); 769 if (flexItem->MustStretch()) { 770 stretchNodes_.emplace_back(flexItem); 771 } 772 if (itemGrow > 0) { 773 flexItemProperties.lastGrowChild = flexItem; 774 } 775 if (itemShrink > 0) { 776 flexItemProperties.lastShrinkChild = flexItem; 777 } 778 LayoutParam innerLayout; 779 if (GreatNotEqual(itemBasis, 0.0)) { 780 innerLayout = MakeLayoutParamWithLimit(itemBasis, itemBasis, false); 781 } else { 782 innerLayout.SetMaxSize(GetLayoutParam().GetMaxSize()); 783 } 784 // first time layout flex item 785 flexItem->Layout(innerLayout); 786 flexItemProperties.totalShrink += itemShrink * GetMainSize(flexItem); 787 flexItemProperties.totalGrow += itemGrow; 788 } 789 RedoLayoutFlexItem(const RefPtr<RenderFlexItem> & flexItem,double flexSize,BaselineProperties & baselineProps,double & allocatedFlexSpace)790 void RenderFlex::RedoLayoutFlexItem(const RefPtr<RenderFlexItem>& flexItem, double flexSize, 791 BaselineProperties& baselineProps, double& allocatedFlexSpace) 792 { 793 bool canItemStretch = flexItem->MustStretch() || ((GetSelfAlign(flexItem) == FlexAlign::STRETCH) && 794 (flexItem->GetStretchFlag()) && (relativeNodes_.size() > 1)); 795 // less or equal than api 5 796 if (useOldLayoutVersion_) { 797 canItemStretch = 798 flexItem->MustStretch() || ((GetSelfAlign(flexItem) == FlexAlign::STRETCH) && (flexItem->GetStretchFlag())); 799 } 800 801 if (NearZero(flexSize) && !canItemStretch) { 802 return; 803 } 804 auto mainFlexExtent = flexSize + GetMainSize(flexItem); 805 auto childMainContent = GetMainAxisValue(flexItem->GetContentSize(), direction_); 806 if (childMainContent > mainFlexExtent) { 807 mainFlexExtent = childMainContent; 808 } 809 allocatedSize_ -= GetMainSize(flexItem); 810 auto innerLayout = MakeConstrainedLayoutParam(mainFlexExtent, flexItem->GetNormalizedConstraints(), canItemStretch, 811 flexItem->MustStretch() || !useOldLayoutVersion_); 812 if (flexItem->MustStretch()) { 813 auto crossStretch = crossAxisSize_ == CrossAxisSize::MAX 814 ? GetMainAxisValue(GetLayoutParam().GetMaxSize(), FlipAxis(direction_)) 815 : crossSize_; 816 auto innerMax = innerLayout.GetMaxSize(); 817 if (direction_ == FlexDirection::ROW || direction_ == FlexDirection::ROW_REVERSE) { 818 innerMax.SetHeight(crossStretch); 819 } else { 820 innerMax.SetWidth(crossStretch); 821 } 822 innerLayout.SetMaxSize(innerMax); 823 innerLayout.SetMinSize(innerMax); 824 } 825 flexItem->Layout(innerLayout); 826 allocatedFlexSpace += flexSize; 827 allocatedSize_ -= space_; 828 double allocatedSize = allocatedSize_; 829 ResizeByItem(flexItem, allocatedSize); 830 CheckBaselineProperties(flexItem, baselineProps); 831 } 832 LayoutInfinityChild(const RefPtr<RenderNode> & item,double mainSize,BaselineProperties & baselineProps)833 void RenderFlex::LayoutInfinityChild(const RefPtr<RenderNode>& item, double mainSize, BaselineProperties& baselineProps) 834 { 835 auto flexItem = AceType::DynamicCast<RenderFlexItem>(item); 836 bool isStretch = false; 837 if (flexItem) { 838 isStretch = (crossAxisAlign_ == FlexAlign::STRETCH) && (flexItem->GetStretchFlag()); 839 } else { 840 isStretch = crossAxisAlign_ == FlexAlign::STRETCH; 841 } 842 LayoutParam innerLayout = MakeLayoutParamWithLimit(mainSize, mainSize, isStretch); 843 item->Layout(innerLayout); 844 double allocatedSize = allocatedSize_; 845 ResizeByItem(item, allocatedSize); 846 CheckBaselineProperties(item, baselineProps); 847 } 848 LayoutAbsoluteChildren()849 void RenderFlex::LayoutAbsoluteChildren() 850 { 851 if (absoluteNodes_.empty()) { 852 return; 853 } 854 for (const auto& item : absoluteNodes_) { 855 item->Layout(GetLayoutParam()); 856 } 857 } 858 CheckBaselineProperties(const RefPtr<RenderNode> & item,BaselineProperties & baselineProperties)859 void RenderFlex::CheckBaselineProperties(const RefPtr<RenderNode>& item, BaselineProperties& baselineProperties) 860 { 861 auto flexItem = AceType::DynamicCast<RenderFlexItem>(item); 862 bool isChildBaselineAlign = flexItem ? flexItem->GetAlignSelf() == FlexAlign::BASELINE : false; 863 if (crossAxisAlign_ == FlexAlign::BASELINE || isChildBaselineAlign) { 864 double distance = item->GetBaselineDistance(textBaseline_); 865 baselineProperties.maxBaselineDistance = std::max(baselineProperties.maxBaselineDistance, distance); 866 baselineProperties.maxDistanceAboveBaseline = std::max(baselineProperties.maxDistanceAboveBaseline, distance); 867 baselineProperties.maxDistanceBelowBaseline = 868 std::max(baselineProperties.maxDistanceBelowBaseline, GetCrossSize(item) - distance); 869 if (crossAxisAlign_ == FlexAlign::BASELINE) { 870 crossSize_ = baselineProperties.maxDistanceAboveBaseline + baselineProperties.maxDistanceBelowBaseline; 871 } 872 } 873 } 874 GetBaselineDistance(TextBaseline baseline)875 double RenderFlex::GetBaselineDistance(TextBaseline baseline) 876 { 877 if (direction_ == FlexDirection::ROW || direction_ == FlexDirection::ROW_REVERSE) { 878 // in row, use default children baseline defined in render node. 879 return GetHighestChildBaseline(baseline); 880 } else { 881 // in column, just get the first child baseline 882 return GetFirstChildBaseline(baseline); 883 } 884 } 885 GetChildViewPort()886 Size RenderFlex::GetChildViewPort() 887 { 888 if (containsNavigation_) { 889 double width = viewPort_.Width(); 890 double height = viewPort_.Height(); 891 if (direction_ == FlexDirection::ROW || direction_ == FlexDirection::ROW_REVERSE) { 892 width -= navigationMainSize_; 893 } else { 894 height -= navigationMainSize_; 895 } 896 return Size(width, height); 897 } else { 898 return viewPort_; 899 } 900 } 901 InitFlexProperties()902 void RenderFlex::InitFlexProperties() 903 { 904 mainSize_ = 0.0; 905 crossSize_ = 0.0; 906 allocatedSize_ = 0.0; 907 validSizeCount_ = 0; 908 layoutMode_ = FlexLayoutMode::FLEX_WEIGHT_MODE; 909 totalFlexWeight_ = 0.0; 910 maxDisplayIndex_ = 0; 911 needRelayoutCross_ = false; 912 if (direction_ == FlexDirection::ROW) { 913 isMainInfinite_ = GetLayoutParam().GetMaxSize().IsWidthInfinite(); 914 isCrossInfinite_ = GetLayoutParam().GetMaxSize().IsHeightInfinite(); 915 } else { 916 isMainInfinite_ = GetLayoutParam().GetMaxSize().IsHeightInfinite(); 917 isCrossInfinite_ = GetLayoutParam().GetMaxSize().IsWidthInfinite(); 918 } 919 // determine the flex layout mode 920 TravelChildrenFlexProps(); 921 } 922 TravelChildrenFlexProps()923 void RenderFlex::TravelChildrenFlexProps() 924 { 925 for (const auto& child : GetChildren()) { 926 child->SetVisible(GetVisible()); 927 if (IsNonRelativePosition(child->GetPositionType())) { 928 absoluteNodes_.insert(child); 929 continue; 930 } 931 maxDisplayIndex_ = std::max(child->GetDisplayIndex(), maxDisplayIndex_); 932 relativeNodes_.emplace_back(child); 933 MagicLayoutNode node; 934 node.node = child; 935 auto idx = child->GetDisplayIndex(); 936 if (magicNodes_.find(idx) != magicNodes_.end()) { 937 magicNodes_[idx].emplace_back(node); 938 magicWeightMaps_[idx] += child->GetFlexWeight(); 939 } else { 940 std::list<MagicLayoutNode> nodes; 941 nodes.emplace_back(node); 942 magicNodes_[idx] = nodes; 943 magicWeightMaps_[idx] = child->GetFlexWeight(); 944 } 945 // FLEX_WEIGHT_MODE now active if one child has set flexWeight 946 totalFlexWeight_ += child->GetFlexWeight(); 947 } 948 layoutMode_ = 949 LessOrEqual(totalFlexWeight_, 0.0) ? FlexLayoutMode::FLEX_ITEM_MODE : FlexLayoutMode::FLEX_WEIGHT_MODE; 950 if (relativeNodes_.empty() && !absoluteNodes_.empty()) { 951 layoutMode_ = FlexLayoutMode::FLEX_ITEM_MODE; 952 } 953 } 954 ClearChildrenLists()955 void RenderFlex::ClearChildrenLists() 956 { 957 infinityLayoutNodes_.clear(); 958 absoluteNodes_.clear(); 959 relativeNodes_.clear(); 960 magicNodes_.clear(); 961 magicWeightMaps_.clear(); 962 displayNodes_.clear(); 963 stretchNodes_.clear(); 964 } 965 ResizeByItem(const RefPtr<RenderNode> & item,double & allocatedSize)966 void RenderFlex::ResizeByItem(const RefPtr<RenderNode>& item, double& allocatedSize) 967 { 968 double mainSize = GetMainSize(item); 969 if (NearEqual(mainSize, Size::INFINITE_SIZE)) { 970 mainSize = 0.0; 971 // push infinite nodes 972 infinityLayoutNodes_.insert(item); 973 } 974 if (IsNonRelativePosition(item->GetPositionType())) { 975 return; 976 } 977 978 crossSize_ = std::max(crossSize_, GetCrossSize(item)); 979 // Semi relative and variable allocatedSize is used for grid container. 980 if ((item->GetPositionType() == PositionType::PTSEMI_RELATIVE) && 981 (direction_ == FlexDirection::ROW || direction_ == FlexDirection::ROW_REVERSE)) { 982 allocatedSize_ = std::max(allocatedSize_, mainSize); 983 allocatedSize = mainSize; 984 } else { 985 allocatedSize_ += mainSize; 986 allocatedSize_ += space_; 987 allocatedSize += mainSize; 988 allocatedSize += space_; 989 } 990 } 991 CheckSizeValidity(const RefPtr<RenderNode> & item)992 void RenderFlex::CheckSizeValidity(const RefPtr<RenderNode>& item) 993 { 994 if (item->IsIgnored() || IsNonRelativePosition(item->GetPositionType())) { 995 return; 996 } 997 if (!item->GetLayoutSize().IsValid()) { 998 auto flexItem = AceType::DynamicCast<RenderFlexItem>(item); 999 if (flexItem && flexItem->IsHidden()) { 1000 return; 1001 } 1002 } 1003 ++validSizeCount_; 1004 displayNodes_.insert(item); 1005 } 1006 GetAvailableMainSize()1007 double RenderFlex::GetAvailableMainSize() 1008 { 1009 double maxMainSize = 0.0; 1010 if (!isMainInfinite_ || !useViewPort_) { 1011 maxMainSize = (direction_ == FlexDirection::ROW || direction_ == FlexDirection::ROW_REVERSE) 1012 ? GetLayoutParam().GetMaxSize().Width() 1013 : GetLayoutParam().GetMaxSize().Height(); 1014 } else { 1015 maxMainSize = (direction_ == FlexDirection::ROW || direction_ == FlexDirection::ROW_REVERSE) 1016 ? viewPort_.Width() 1017 : viewPort_.Height(); 1018 } 1019 return maxMainSize; 1020 } 1021 GetMainSize(const RefPtr<RenderNode> & item) const1022 double RenderFlex::GetMainSize(const RefPtr<RenderNode>& item) const 1023 { 1024 double size = 0.0; 1025 if (!item) { 1026 return size; 1027 } 1028 if (direction_ == FlexDirection::ROW || direction_ == FlexDirection::ROW_REVERSE) { 1029 size = item->GetLayoutSize().Width(); 1030 if (item->GetPositionType() == PositionType::PTSEMI_RELATIVE) { 1031 Offset absoluteOffset = PositionLayoutUtils::GetAbsoluteOffset(Claim(const_cast<RenderFlex*>(this)), item); 1032 size += absoluteOffset.GetX(); 1033 } 1034 } else { 1035 size = item->GetLayoutSize().Height(); 1036 } 1037 return size; 1038 } 1039 GetCrossSize(const RefPtr<RenderNode> & item) const1040 double RenderFlex::GetCrossSize(const RefPtr<RenderNode>& item) const 1041 { 1042 double size = 0.0; 1043 if (!item) { 1044 return size; 1045 } 1046 if (direction_ == FlexDirection::ROW || direction_ == FlexDirection::ROW_REVERSE) { 1047 size = item->GetLayoutSize().Height(); 1048 } else { 1049 size = item->GetLayoutSize().Width(); 1050 if (item->GetPositionType() == PositionType::PTSEMI_RELATIVE) { 1051 Offset absoluteOffset = PositionLayoutUtils::GetAbsoluteOffset(Claim(const_cast<RenderFlex*>(this)), item); 1052 size += absoluteOffset.GetX(); 1053 } 1054 } 1055 return size; 1056 } 1057 IsStartTopLeft(FlexDirection direction,TextDirection textDirection) const1058 bool RenderFlex::IsStartTopLeft(FlexDirection direction, TextDirection textDirection) const 1059 { 1060 switch (direction) { 1061 case FlexDirection::ROW: 1062 return textDirection == TextDirection::LTR; 1063 case FlexDirection::ROW_REVERSE: 1064 return textDirection == TextDirection::RTL; 1065 case FlexDirection::COLUMN: 1066 return true; 1067 case FlexDirection::COLUMN_REVERSE: 1068 return false; 1069 default: 1070 return true; 1071 } 1072 } 1073 GetConstrainedSize(double mainSize)1074 Size RenderFlex::GetConstrainedSize(double mainSize) 1075 { 1076 if ((stretchToParent_ && crossAxisAlign_ == FlexAlign::STRETCH) || (crossAxisSize_ == CrossAxisSize::MAX)) { 1077 if (direction_ == FlexDirection::ROW || direction_ == FlexDirection::ROW_REVERSE) { 1078 return GetLayoutParam().Constrain(Size(mainSize, GetLayoutParam().GetMaxSize().Height())); 1079 } else { 1080 return GetLayoutParam().Constrain(Size(GetLayoutParam().GetMaxSize().Width(), mainSize)); 1081 } 1082 } 1083 if (direction_ == FlexDirection::ROW || direction_ == FlexDirection::ROW_REVERSE) { 1084 return GetLayoutParam().Constrain(Size(mainSize, crossSize_)); 1085 } else { 1086 return GetLayoutParam().Constrain(Size(crossSize_, mainSize)); 1087 } 1088 } 1089 GetSelfAlign(const RefPtr<RenderNode> & item) const1090 FlexAlign RenderFlex::GetSelfAlign(const RefPtr<RenderNode>& item) const 1091 { 1092 auto flexItem = AceType::DynamicCast<RenderFlexItem>(item); 1093 if (flexItem) { 1094 auto alignSelf = flexItem->GetAlignSelf(); 1095 return alignSelf == FlexAlign::AUTO ? crossAxisAlign_ : alignSelf; 1096 } 1097 return crossAxisAlign_; 1098 } 1099 AdjustTextDirectionByDir()1100 TextDirection RenderFlex::AdjustTextDirectionByDir() 1101 { 1102 auto textDir = GetTextDirection(); 1103 if (direction_ == FlexDirection::ROW_REVERSE) { 1104 textDir = GetTextDirection() == TextDirection::RTL ? TextDirection::LTR : TextDirection::RTL; 1105 } 1106 return textDir; 1107 } 1108 OnChildRemoved(const RefPtr<RenderNode> & child)1109 void RenderFlex::OnChildRemoved(const RefPtr<RenderNode>& child) 1110 { 1111 if (child) { 1112 child->SetAccessibilityVisible(false); 1113 child->ClearAccessibilityRect(); 1114 } 1115 MarkNeedLayout(); 1116 } 1117 ClearRenderObject()1118 void RenderFlex::ClearRenderObject() 1119 { 1120 RenderNode::ClearRenderObject(); 1121 direction_ = FlexDirection::ROW; 1122 mainAxisAlign_ = FlexAlign::FLEX_START; 1123 crossAxisAlign_ = FlexAlign::FLEX_START; 1124 mainAxisSize_ = MainAxisSize::MAX; 1125 crossAxisSize_ = CrossAxisSize::MIN; 1126 textBaseline_ = TextBaseline::ALPHABETIC; 1127 layoutMode_ = FlexLayoutMode::FLEX_ITEM_MODE; 1128 stretchToParent_ = false; 1129 mainSize_ = 0.0; 1130 crossSize_ = 0.0; 1131 allocatedSize_ = 0.0; 1132 infinityLayoutNodes_.clear(); 1133 absoluteNodes_.clear(); 1134 relativeNodes_.clear(); 1135 magicNodes_.clear(); 1136 magicWeightMaps_.clear(); 1137 displayNodes_.clear(); 1138 stretchNodes_.clear(); 1139 scrollNode = nullptr; 1140 isMainInfinite_ = false; 1141 isCrossInfinite_ = false; 1142 useViewPort_ = false; 1143 containsNavigation_ = false; 1144 navigationMainSize_ = 0.0; 1145 validSizeCount_ = 0; 1146 totalFlexWeight_ = 0.0; 1147 maxDisplayIndex_ = 0; 1148 space_ = 0.0; 1149 alignPtr_ = nullptr; 1150 } 1151 MaybeRelease()1152 bool RenderFlex::MaybeRelease() 1153 { 1154 auto context = GetContext().Upgrade(); 1155 if (context && context->GetRenderFactory() && context->GetRenderFactory()->GetRenderFlexFactory()->Recycle(this)) { 1156 ClearRenderObject(); 1157 return false; 1158 } 1159 return true; 1160 } 1161 GetAlignDeclarationOffset(AlignDeclarationPtr alignDeclarationPtr,Offset & offset) const1162 bool RenderFlex::GetAlignDeclarationOffset(AlignDeclarationPtr alignDeclarationPtr, Offset& offset) const 1163 { 1164 if (alignPtr_ != alignDeclarationPtr) { 1165 return RenderNode::GetAlignDeclarationOffset(alignDeclarationPtr, offset); 1166 } 1167 if (alignDeclarationPtr->GetDeclarationType() == AlignDeclaration::DeclarationType::HORIZONTAL) { 1168 switch (alignDeclarationPtr->GetHorizontalAlign()) { 1169 case HorizontalAlign::START: 1170 break; 1171 case HorizontalAlign::CENTER: { 1172 offset = offset + Offset(GetLayoutSize().Width() / 2, 0); 1173 break; 1174 } 1175 case HorizontalAlign::END: { 1176 offset = offset + Offset(GetLayoutSize().Width(), 0); 1177 break; 1178 } 1179 default: 1180 break; 1181 } 1182 offset.SetY(0.0); 1183 } else { 1184 switch (alignDeclarationPtr->GetVerticalAlign()) { 1185 case VerticalAlign::TOP: 1186 break; 1187 case VerticalAlign::CENTER: { 1188 offset = offset + Offset(0, GetLayoutSize().Height() / 2); 1189 break; 1190 } 1191 case VerticalAlign::BOTTOM: { 1192 offset = offset + Offset(0, GetLayoutSize().Height()); 1193 break; 1194 } 1195 case VerticalAlign::BASELINE: 1196 case VerticalAlign::NONE: 1197 return false; 1198 default: 1199 break; 1200 } 1201 offset.SetX(0.0); 1202 } 1203 return true; 1204 } 1205 PerformItemAlign(std::list<RefPtr<RenderNode>> & nodelist)1206 void RenderFlex::PerformItemAlign(std::list<RefPtr<RenderNode>>& nodelist) 1207 { 1208 auto item = nodelist.begin(); 1209 1210 while (item != nodelist.end()) { 1211 if (*item == AceType::Claim(this)) { 1212 nodelist.erase(item); 1213 return; 1214 } 1215 const RefPtr<RenderBox> box = AceType::DynamicCast<RenderBox>(*item); 1216 if (!box) { 1217 nodelist.clear(); 1218 LOGE("PerformItemAlign error"); 1219 return; 1220 } 1221 if (box->GetAlignDeclarationPtr() != alignPtr_) { 1222 item++; 1223 continue; 1224 } 1225 box->CalculateAlignDeclaration(); 1226 item = nodelist.erase(item); 1227 } 1228 } 1229 Dump()1230 void RenderFlex::Dump() 1231 { 1232 DumpLog::GetInstance().AddDesc(std::string("Direction: ") 1233 .append(std::to_string(static_cast<int32_t>(direction_))) 1234 .append(", Mode: ") 1235 .append(std::to_string(static_cast<int32_t>(layoutMode_))) 1236 .append(", MainAlign: ") 1237 .append(std::to_string(static_cast<int32_t>(mainAxisAlign_))) 1238 .append(", CrossAlign: ") 1239 .append(std::to_string(static_cast<int32_t>(crossAxisAlign_))) 1240 .append(", MainAxisSize: ") 1241 .append(std::to_string(static_cast<int32_t>(mainAxisSize_))) 1242 .append(", CrossAxisSize: ") 1243 .append(std::to_string(static_cast<int32_t>(crossAxisSize_)))); 1244 } 1245 CheckIfNeedLayoutAgain()1246 bool RenderFlex::CheckIfNeedLayoutAgain() 1247 { 1248 if (NeedLayout()) { 1249 return true; 1250 } 1251 return layoutMode_ != FlexLayoutMode::FLEX_WEIGHT_MODE; 1252 } 1253 OnVisibleChanged()1254 void RenderFlex::OnVisibleChanged() 1255 { 1256 auto accessibilityNode = GetAccessibilityNode().Upgrade(); 1257 if (accessibilityNode) { 1258 accessibilityNode->SetVisible(GetVisible()); 1259 } 1260 } 1261 ProvideRestoreInfo()1262 std::string RenderFlex::ProvideRestoreInfo() 1263 { 1264 if (isTabs_) { 1265 auto childNode = GetChildren().front(); 1266 if (!childNode || childNode->GetChildren().empty()) { 1267 return ""; 1268 } 1269 auto childChildNode = childNode->GetChildren().front(); 1270 if (!childChildNode) { 1271 return ""; 1272 } 1273 isTabs_ = false; 1274 return childChildNode->ProvideRestoreInfo(); 1275 } 1276 1277 if (isTabContent_) { 1278 auto childNode = GetChildren().back(); 1279 if (!childNode || childNode->GetChildren().empty()) { 1280 return ""; 1281 } 1282 auto childChildNode = childNode->GetChildren().front(); 1283 if (!childChildNode) { 1284 return ""; 1285 } 1286 isTabContent_ = false; 1287 return childChildNode->ProvideRestoreInfo(); 1288 } 1289 1290 return ""; 1291 } 1292 1293 } // namespace OHOS::Ace 1294