1 /*
2  * Copyright (c) 2021 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 "frameworks/bridge/common/dom/dom_div.h"
17 
18 #include "base/log/event_report.h"
19 #include "core/components/focus_collaboration/focus_collaboration_component.h"
20 #include "frameworks/bridge/common/dom/dom_reflect_map.h"
21 #include "frameworks/bridge/common/utils/utils.h"
22 
23 namespace OHOS::Ace::Framework {
24 namespace {
25 
26 const Alignment ALIGN_ARRAY[3][3] = { { Alignment::TOP_LEFT, Alignment::TOP_CENTER, Alignment::TOP_RIGHT },
27     { Alignment::CENTER_LEFT, Alignment::CENTER, Alignment::CENTER_RIGHT },
28     { Alignment::BOTTOM_LEFT, Alignment::BOTTOM_CENTER, Alignment::BOTTOM_RIGHT } };
29 
30 } // namespace
31 
DOMDiv(NodeId nodeId,const std::string & nodeName)32 DOMDiv::DOMDiv(NodeId nodeId, const std::string& nodeName) : DOMNode(nodeId, nodeName) {}
33 
OnChildNodeAdded(const RefPtr<DOMNode> & child,int32_t slot)34 void DOMDiv::OnChildNodeAdded(const RefPtr<DOMNode>& child, int32_t slot)
35 {
36     ACE_DCHECK(child);
37     if (GetDisplay() == DisplayType::GRID) {
38         if (!grid_) {
39             return;
40         }
41         grid_->InsertChild(slot, child->GetRootComponent());
42     } else {
43         if (isFlexWrap_) {
44             if (!wrapChild_) {
45                 return;
46             }
47             wrapChild_->InsertChild(slot, child->GetRootComponent());
48         } else {
49             if (!flexChild_) {
50                 return;
51             }
52             flexChild_->InsertChild(slot, child->GetRootComponent());
53         }
54     }
55 }
56 
OnChildNodeRemoved(const RefPtr<DOMNode> & child)57 void DOMDiv::OnChildNodeRemoved(const RefPtr<DOMNode>& child)
58 {
59     if (GetDisplay() == DisplayType::GRID) {
60         if (!grid_) {
61             return;
62         }
63         grid_->RemoveChild(child->GetRootComponent());
64     } else {
65         if (isFlexWrap_) {
66             if (!wrapChild_) {
67                 return;
68             }
69             wrapChild_->RemoveChild(child->GetRootComponent());
70         } else {
71             if (!flexChild_) {
72                 return;
73             }
74             flexChild_->RemoveChild(child->GetRootComponent());
75         }
76     }
77 }
78 
ComputeFlexAlign(FlexAlign flexMainAlign,FlexAlign flexCrossAlign,bool isColumn,bool isRtl)79 Alignment DOMDiv::ComputeFlexAlign(FlexAlign flexMainAlign, FlexAlign flexCrossAlign, bool isColumn, bool isRtl)
80 {
81     AxisAlign mainAlign;
82     if (flexMainAlign == FlexAlign::FLEX_END) {
83         mainAlign = AxisAlign::END;
84     } else if (flexMainAlign == FlexAlign::CENTER || flexMainAlign == FlexAlign::SPACE_AROUND) {
85         mainAlign = AxisAlign::CENTER;
86     } else {
87         mainAlign = AxisAlign::START;
88     }
89 
90     AxisAlign crossAlign;
91     if (flexCrossAlign == FlexAlign::FLEX_END) {
92         crossAlign = isRtl && isColumn ? AxisAlign::START : AxisAlign::END;
93     } else if (flexCrossAlign == FlexAlign::CENTER) {
94         crossAlign = AxisAlign::CENTER;
95     } else {
96         crossAlign = isRtl && isColumn ? AxisAlign::END : AxisAlign::START;
97     }
98 
99     return isColumn ? ALIGN_ARRAY[static_cast<int32_t>(mainAlign)][static_cast<int32_t>(crossAlign)]
100                     : ALIGN_ARRAY[static_cast<int32_t>(crossAlign)][static_cast<int32_t>(mainAlign)];
101 }
102 
CreateOrUpdateGrid()103 void DOMDiv::CreateOrUpdateGrid()
104 {
105     if (!grid_) {
106         grid_ = AceType::MakeRefPtr<GridLayoutComponent>(std::list<RefPtr<Component>>());
107     }
108     if (boxWrap_) {
109         if (direction_ == DOM_FLEX_ROW || direction_ == DOM_FLEX_ROW_REVERSE) {
110             grid_->SetDirection(FlexDirection::COLUMN);
111         } else {
112             grid_->SetDirection(FlexDirection::ROW);
113         }
114     } else {
115         if (direction_ == DOM_FLEX_COLUMN_REVERSE) {
116             grid_->SetDirection(FlexDirection::COLUMN_REVERSE);
117         } else if (direction_ == DOM_FLEX_ROW) {
118             grid_->SetDirection(FlexDirection::ROW);
119         } else if (direction_ == DOM_FLEX_ROW_REVERSE) {
120             grid_->SetDirection(FlexDirection::ROW_REVERSE);
121         } else {
122             grid_->SetDirection(FlexDirection::COLUMN);
123         }
124     }
125     grid_->SetColumnsArgs(columnsArgs_);
126     grid_->SetRowsArgs(rowsArgs_);
127     grid_->SetUseScroll(false);
128     grid_->SetColumnGap(columnGap_);
129     grid_->SetRowGap(rowGap_);
130     grid_->SetRightToLeft(IsRightToLeft());
131 }
132 
CreateOrUpdateGridItem()133 void DOMDiv::CreateOrUpdateGridItem()
134 {
135     if (!gridItem_) {
136         gridItem_ = AceType::MakeRefPtr<GridLayoutItemComponent>(RefPtr<Component>());
137     }
138     gridItem_->SetRowIndex(rowStart_);
139     gridItem_->SetColumnIndex(columnStart_);
140     gridItem_->SetRowSpan(rowEnd_ - rowStart_ + 1);
141     gridItem_->SetColumnSpan(columnEnd_ - columnStart_ + 1);
142 }
143 
CreateOrUpdateFlex()144 void DOMDiv::CreateOrUpdateFlex()
145 {
146     auto direction = FlexDirectionMap.find(direction_);
147     if (direction != FlexDirectionMap.end()) {
148         flexDirection_ = direction->second;
149     }
150     auto flexMainAlign = FlexAlign::FLEX_START;
151     auto justifyContent = FlexJustifyContentMap.find(justifyContent_);
152     if (justifyContent != FlexJustifyContentMap.end()) {
153         flexMainAlign = justifyContent->second;
154     }
155 
156     auto flexCrossAlign = FlexAlign::STRETCH;
157     auto alignItems = FlexAlignItemsMap.find(alignItems_);
158     if (alignItems != FlexAlignItemsMap.end()) {
159         flexCrossAlign = alignItems->second;
160     }
161     if (!flexChild_) {
162         flexChild_ = AceType::MakeRefPtr<FlexComponent>(
163             flexDirection_, flexMainAlign, flexCrossAlign, std::list<RefPtr<Component>>());
164     } else {
165         flexChild_->SetDirection(flexDirection_);
166         flexChild_->SetMainAxisAlign(flexMainAlign);
167         flexChild_->SetCrossAxisAlign(flexCrossAlign);
168     }
169     if (IsRightToLeft()) {
170         textDirection_ = TextDirection::RTL;
171     } else {
172         textDirection_ = TextDirection::LTR;
173     }
174     flexChild_->SetTextDirection(textDirection_);
175     flexChild_->SetMainAxisAlign(flexMainAlign);
176     flexChild_->SetCrossAxisAlign(flexCrossAlign);
177     if (boxWrap_) {
178         flexChild_->SetMainAxisSize(MainAxisSize::MIN);
179     }
180     bool isColumn = flexDirection_ == FlexDirection::COLUMN;
181     boxComponent_->SetAlignment(ComputeFlexAlign(flexMainAlign, flexCrossAlign, isColumn, IsRightToLeft()));
182     SetRootBoxHeight();
183     if (!boxWrap_) {
184         SetFlexHeight(flexMainAlign);
185     }
186     if (((flexDirection_ == FlexDirection::ROW || flexDirection_ == FlexDirection::ROW_REVERSE) &&
187             boxComponent_->GetWidthDimension().IsValid()) ||
188         ((flexDirection_ == FlexDirection::COLUMN || flexDirection_ == FlexDirection::COLUMN_REVERSE) &&
189             boxComponent_->GetHeightDimension().IsValid())) {
190         flexChild_->SetMainAxisSize(MainAxisSize::MAX);
191     }
192     // When cross size is determined by developers, the flex cross size should be as large as the box.
193     // Otherwise, flex cross size is as large as the max child's size.
194     if (((flexDirection_ == FlexDirection::ROW || flexDirection_ == FlexDirection::ROW_REVERSE) &&
195             boxComponent_->GetHeightDimension().IsValid()) ||
196         ((flexDirection_ == FlexDirection::COLUMN || flexDirection_ == FlexDirection::COLUMN_REVERSE) &&
197             boxComponent_->GetWidthDimension().IsValid())) {
198         flexChild_->SetStretchToParent(!boxWrap_);
199         flexChild_->SetCrossAxisSize(CrossAxisSize::MAX);
200     }
201     SetSpecializedOverflow();
202 }
203 
CreateOrUpdateWrap()204 void DOMDiv::CreateOrUpdateWrap()
205 {
206     if (!wrapChild_) {
207         wrapChild_ = AceType::MakeRefPtr<WrapComponent>(spacing_, contentSpacing_, std::list<RefPtr<Component>>());
208     }
209 
210     auto wrapDirection = WrapDirection::HORIZONTAL;
211     auto direction = WrapDirectionMap.find(direction_);
212     if (direction != WrapDirectionMap.end()) {
213         wrapDirection = direction->second;
214     }
215     wrapChild_->SetDirection(wrapDirection);
216     SetBoxWidthFlex(wrapDirection == WrapDirection::HORIZONTAL);
217 
218     auto wrapMainAlign = WrapAlignment::START;
219     auto justifyContent = WrapJustifyContentMap.find(justifyContent_);
220     if (justifyContent != WrapJustifyContentMap.end()) {
221         wrapMainAlign = justifyContent->second;
222     }
223     wrapChild_->SetMainAlignment(wrapMainAlign);
224 
225     auto wrapCrossAlign = WrapAlignment::STRETCH;
226     auto alignItems = WrapAlignItemsMap.find(alignItems_);
227     if (alignItems != WrapAlignItemsMap.end()) {
228         wrapCrossAlign = alignItems->second;
229     }
230     wrapChild_->SetCrossAlignment(wrapCrossAlign);
231     auto wrapAlignContent = WrapAlignment::START;
232     auto alignContent = WrapAlignContentMap.find(alignContent_);
233     if (alignContent != WrapAlignContentMap.end()) {
234         wrapAlignContent = alignContent->second;
235     }
236     wrapChild_->SetAlignment(wrapAlignContent);
237 
238     if (IsRightToLeft()) {
239         textDirection_ = TextDirection::RTL;
240     } else {
241         textDirection_ = TextDirection::LTR;
242     }
243     wrapChild_->SetTextDirection(textDirection_);
244 
245     // final set box default alignment.
246     boxComponent_->SetAlignment(IsRightToLeft() ? Alignment::TOP_RIGHT : Alignment::TOP_LEFT);
247 }
248 
249 // If not set div width, Div width should fill the row width
SetBoxWidthFlex(bool isHorizontal) const250 void DOMDiv::SetBoxWidthFlex(bool isHorizontal) const
251 {
252     // There is no custom width and the orientation is horizontal.
253     if (boxComponent_->GetWidthDimension().Value() < 0.0 && isHorizontal) {
254         boxComponent_->SetFlex(BoxFlex::FLEX_X);
255     }
256 }
257 
SetSpecializedOverflow()258 void DOMDiv::SetSpecializedOverflow()
259 {
260     auto& overflowStyle = static_cast<CommonOverflowStyle&>(declaration_->GetStyle(StyleTag::COMMON_OVERFLOW_STYLE));
261     if (overflowStyle.IsValid() && flexChild_) {
262         flexChild_->SetOverflow(overflowStyle.overflow);
263     }
264 }
265 
266 // If not set div height, The root node(id=0) should be fill the column height
SetRootBoxHeight() const267 void DOMDiv::SetRootBoxHeight() const
268 {
269     // not the root node 0 or Height != 0
270     if (boxWrap_ || (!isRootNode_) || GreatOrEqual(boxComponent_->GetHeightDimension().Value(), 0.0)) {
271         return;
272     }
273     if (boxComponent_->GetWidthDimension().IsValid()) {
274         boxComponent_->SetFlex(BoxFlex::FLEX_Y);
275         return;
276     }
277     auto context = GetPipelineContext().Upgrade();
278     if (context && (context->GetWindowModal() == WindowModal::SEMI_MODAL ||
279                        context->GetWindowModal() == WindowModal::DIALOG_MODAL)) {
280         boxComponent_->SetFlex(BoxFlex::FLEX_X);
281     } else {
282         boxComponent_->SetFlex(BoxFlex::FLEX_XY);
283         flexChild_->SetCrossAxisSize(CrossAxisSize::MAX);
284     }
285 }
286 
287 // If div and div parent direction is column,Set div height filed by his children
SetFlexHeight(FlexAlign flexMainAlign)288 void DOMDiv::SetFlexHeight(FlexAlign flexMainAlign)
289 {
290     auto parent = AceType::DynamicCast<DOMDiv>(parentNode_.Upgrade());
291     if (!parent) {
292         return;
293     }
294     flexChild_->SetMainAxisSize(MainAxisSize::MAX);
295     if (flexMainAlign == FlexAlign::SPACE_BETWEEN || flexMainAlign == FlexAlign::SPACE_AROUND ||
296         flexMainAlign == FlexAlign::SPACE_EVENLY) {
297         return;
298     }
299     // When parent and child are all column, child should be wrap-content to fit frontend standard.
300     // In this case, the alignment is calculated by boxComponent_.
301     if (parent->flexDirection_ == flexDirection_) {
302         flexChild_->SetMainAxisSize(MainAxisSize::MIN);
303         flexChild_->SetStretchToParent(flexDirection_ == FlexDirection::COLUMN);
304     }
305 }
306 
OnMounted(const RefPtr<DOMNode> & parentNode)307 void DOMDiv::OnMounted(const RefPtr<DOMNode>& parentNode)
308 {
309     if (!declaration_) {
310         return;
311     }
312     auto& overflowStyle = static_cast<CommonOverflowStyle&>(declaration_->GetStyle(StyleTag::COMMON_OVERFLOW_STYLE));
313 
314     // overflowFlag means that default tabcontent, dialog and panel support scroll.
315     auto overflowFlag = !parentNode->HasOverflowStyle() && !declaration_->HasOverflowStyle();
316     if (parentNode->GetTag() == DOM_NODE_TAG_TAB_CONTENT && direction_ == DOM_FLEX_COLUMN && overflowFlag) {
317         auto child = boxComponent_->GetChild();
318         scroll_ = AceType::MakeRefPtr<ScrollComponent>(child);
319         scroll_->SetOnReachStart(onReachStart_);
320         scroll_->SetOnReachEnd(onReachEnd_);
321         scroll_->SetOnReachTop(onReachTop_);
322         scroll_->SetOnReachBottom(onReachBottom_);
323         if (overflowStyle.IsValid()) {
324             scroll_->InitScrollBar(GetTheme<ScrollBarTheme>(), overflowStyle.scrollBarColor,
325                 overflowStyle.scrollBarWidth, overflowStyle.edgeEffect);
326         }
327         boxComponent_->SetChild(scroll_);
328         if (flexChild_) {
329             flexChild_->SetUseViewPortFlag(true);
330         }
331         rootComponent_->MarkNeedUpdate();
332     }
333 
334     if (parentNode->GetTag() == DOM_NODE_TAG_REFRESH && flexDirection_ == FlexDirection::COLUMN) {
335         if (flexChild_) {
336             flexChild_->SetStretchToParent(flexDirection_ == FlexDirection::COLUMN);
337         }
338     }
339 
340     if (parentNode->GetTag() == DOM_NODE_TAG_DIALOG && direction_ == DOM_FLEX_COLUMN && overflowFlag) {
341         if (flexChild_) {
342             flexChild_->SetMainAxisSize(MainAxisSize::MIN);
343         }
344         boxComponent_->SetFlex(BoxFlex::FLEX_X);
345         // dialog child should be scrollable
346         auto child = rootComponent_->GetChild();
347         scroll_ = AceType::MakeRefPtr<ScrollComponent>(child);
348         if (overflowStyle.IsValid()) {
349             scroll_->InitScrollBar(GetTheme<ScrollBarTheme>(), overflowStyle.scrollBarColor,
350                 overflowStyle.scrollBarWidth, overflowStyle.edgeEffect);
351         }
352         // use takeBoundary to expand the size of dialog
353         scroll_->SetTakeBoundary(false);
354         rootComponent_->SetChild(scroll_);
355     }
356 
357     if (parentNode->GetTag() == DOM_NODE_TAG_PANEL && direction_ == DOM_FLEX_COLUMN && overflowFlag) {
358         auto child = rootComponent_->GetChild();
359         scroll_ = AceType::MakeRefPtr<ScrollComponent>(child);
360         if (overflowStyle.IsValid()) {
361             scroll_->InitScrollBar(GetTheme<ScrollBarTheme>(), overflowStyle.scrollBarColor,
362                 overflowStyle.scrollBarWidth, overflowStyle.edgeEffect);
363         }
364         rootComponent_->SetChild(scroll_);
365     }
366 }
367 
SetSpecializedStyle(const std::pair<std::string,std::string> & style)368 bool DOMDiv::SetSpecializedStyle(const std::pair<std::string, std::string>& style)
369 {
370     static const LinearMapNode<void (*)(const std::string&, DOMDiv&)> styleSetters[] {
371         { DOM_ALIGN_CONTENT, [](const std::string& value, DOMDiv& div) { div.alignContent_ = value; } },
372         { DOM_ALIGN_ITEMS, [](const std::string& value, DOMDiv& div) { div.alignItems_ = value; } },
373         { DOM_FLEX_DIRECTION, [](const std::string& value, DOMDiv& div) { div.direction_ = value; } },
374         { DOM_FLEX_WRAP, [](const std::string& value, DOMDiv& div) { div.isFlexWrap_ = value == DOM_WRAP; } },
375         { DOM_GRID_AUTO_FLOW, [](const std::string& value, DOMDiv& div) { div.direction_ = value; } },
376         { DOM_GRID_COLUMN_END, [](const std::string& value, DOMDiv& div) { div.columnEnd_ = StringToInt(value); } },
377         { DOM_GRID_COLUMN_START, [](const std::string& value, DOMDiv& div) { div.columnStart_ = StringToInt(value); } },
378         { DOM_GRID_COLUMN_GAP,
379             [](const std::string& value, DOMDiv& div) { div.columnGap_ = StringToDimension(value); } },
380         { DOM_GRID_ROW_END, [](const std::string& value, DOMDiv& div) { div.rowEnd_ = StringToInt(value); } },
381         { DOM_GRID_ROW_START, [](const std::string& value, DOMDiv& div) { div.rowStart_ = StringToInt(value); } },
382         { DOM_GRID_ROW_GAP, [](const std::string& value, DOMDiv& div) { div.rowGap_ = StringToDimension(value); } },
383         { DOM_GRID_TEMPLATE_COLUMNS, [](const std::string& value, DOMDiv& div) { div.columnsArgs_ = value; } },
384         { DOM_GRID_TEMPLATE_ROWS, [](const std::string& value, DOMDiv& div) { div.rowsArgs_ = value; } },
385         { DOM_JUSTIFY_CONTENT, [](const std::string& value, DOMDiv& div) { div.justifyContent_ = value; } },
386     };
387     auto operatorIter = BinarySearchFindIndex(styleSetters, ArraySize(styleSetters), style.first.c_str());
388     if (operatorIter != -1) {
389         styleSetters[operatorIter].value(style.second, *this);
390         return true;
391     }
392     return false;
393 }
394 
SetSpecializedAttr(const std::pair<std::string,std::string> & attr)395 bool DOMDiv::SetSpecializedAttr(const std::pair<std::string, std::string>& attr)
396 {
397     if (attr.first == DOM_DIV_CARD_TYPE) {
398         isCard_ = StringToBool(attr.second);
399         return true;
400     }
401     if (attr.first == DOM_DIV_CARD_BLUR) {
402         isCardBlur_ = StringToBool(attr.second);
403         return true;
404     }
405     return false;
406 }
407 
AddSpecializedEvent(int32_t pageId,const std::string & event)408 bool DOMDiv::AddSpecializedEvent(int32_t pageId, const std::string& event)
409 {
410     // static linear map must be sorted by key.
411     static const LinearMapNode<void (*)(int32_t, DOMDiv&)> eventOperators[] = {
412         {
413             DOM_DIV_EVENT_REACH_BOTTOM,
414             [](int32_t pageId, DOMDiv& div) {
415                 div.onReachBottom_ = EventMarker(div.GetNodeIdForEvent(), DOM_DIV_EVENT_REACH_BOTTOM, pageId);
416             },
417         },
418         {
419             DOM_DIV_EVENT_REACH_END,
420             [](int32_t pageId, DOMDiv& div) {
421                 div.onReachEnd_ = EventMarker(div.GetNodeIdForEvent(), DOM_DIV_EVENT_REACH_END, pageId);
422             },
423         },
424         {
425             DOM_DIV_EVENT_REACH_START,
426             [](int32_t pageId, DOMDiv& div) {
427                 div.onReachStart_ = EventMarker(div.GetNodeIdForEvent(), DOM_DIV_EVENT_REACH_START, pageId);
428             },
429         },
430         {
431             DOM_DIV_EVENT_REACH_TOP,
432             [](int32_t pageId, DOMDiv& div) {
433                 div.onReachTop_ = EventMarker(div.GetNodeIdForEvent(), DOM_DIV_EVENT_REACH_TOP, pageId);
434             },
435         },
436     };
437     auto iter = BinarySearchFindIndex(eventOperators, ArraySize(eventOperators), event.c_str());
438     if (iter != -1) {
439         eventOperators[iter].value(pageId, *this);
440         return true;
441     }
442     return false;
443 }
444 
SetCardThemeAttrs()445 void DOMDiv::SetCardThemeAttrs()
446 {
447     cardTheme_ = GetTheme<CardTheme>();
448     if (!cardTheme_) {
449         EventReport::SendComponentException(ComponentExcepType::GET_THEME_ERR);
450         return;
451     }
452     if (boxComponent_) {
453         if (isCard_) {
454             RefPtr<Decoration> backDecoration = boxComponent_->GetBackDecoration();
455             if (!backDecoration) {
456                 RefPtr<Decoration> decoration = AceType::MakeRefPtr<Decoration>();
457                 decoration->SetBackgroundColor(cardTheme_->GetBackgroundColor());
458                 decoration->SetBorderRadius(Radius(cardTheme_->GetBorderRadius()));
459                 boxComponent_->SetBackDecoration(decoration);
460             }
461             if (backDecoration && !backDecoration->GetBorder().HasRadius()) {
462                 backDecoration->SetBorderRadius(Radius(cardTheme_->GetBorderRadius()));
463             }
464             if (backDecoration && (backDecoration->GetBackgroundColor() == Color::TRANSPARENT)) {
465                 backDecoration->SetBackgroundColor(cardTheme_->GetBackgroundColor());
466             }
467             RefPtr<Decoration> frontDecoration = boxComponent_->GetFrontDecoration();
468             if (isCardBlur_) {
469                 if (!frontDecoration) {
470                     frontDecoration = AceType::MakeRefPtr<Decoration>();
471                     frontDecoration->SetBlurRadius(cardTheme_->GetBlurRadius());
472                     boxComponent_->SetFrontDecoration(frontDecoration);
473                 }
474                 if (frontDecoration && !frontDecoration->GetBlurRadius().IsValid()) {
475                     frontDecoration->SetBlurRadius(cardTheme_->GetBlurRadius());
476                 }
477             } else {
478                 if (frontDecoration && frontDecoration->GetBlurRadius().IsValid()) {
479                     frontDecoration->SetBlurRadius(Dimension());
480                 }
481             }
482         }
483     }
484 }
485 
GetSpecializedComponent()486 RefPtr<Component> DOMDiv::GetSpecializedComponent()
487 {
488     SetCardThemeAttrs();
489     auto parentNode = GetParentNode();
490     if (parentNode && parentNode->GetDisplay() == DisplayType::GRID) {
491         return gridItem_;
492     } else {
493         if (isFlexWrap_) {
494             return wrapChild_;
495         } else {
496             return flexChild_;
497         }
498     }
499 }
500 
PrepareSpecializedComponent()501 void DOMDiv::PrepareSpecializedComponent()
502 {
503     RefPtr<ComponentGroup> layoutChild;
504     if (isFlexWrap_) {
505         CreateOrUpdateWrap();
506         layoutChild = wrapChild_;
507     } else {
508         CreateOrUpdateFlex();
509         layoutChild = flexChild_;
510     }
511 
512     if (GetDisplay() == DisplayType::GRID) {
513         // Self is grid, node: flex/wrap -> grid
514         CreateOrUpdateGrid();
515         layoutChild->ClearChildren();
516         layoutChild->AppendChild(grid_);
517     }
518     if (GetParentNode() && GetParentNode()->GetDisplay() == DisplayType::GRID) {
519         // Parent is grid, node: gridItem -> flex/wrap.
520         CreateOrUpdateGridItem();
521         gridItem_->SetChild(flexChild_);
522     }
523 }
524 
CompositeComponents()525 void DOMDiv::CompositeComponents()
526 {
527     DOMNode::CompositeComponents();
528 
529     if (!declaration_) {
530         return;
531     }
532     auto& overflowStyle = static_cast<CommonOverflowStyle&>(declaration_->GetStyle(StyleTag::COMMON_OVERFLOW_STYLE));
533     if (!overflowStyle.IsValid()) {
534         return;
535     }
536 
537     scroll_.Reset();
538     // root div is scrollable
539     bool isRootScroll =
540         isRootNode_ && (!declaration_->HasOverflowStyle() || overflowStyle.overflow == Overflow::SCROLL);
541     if (isRootScroll) {
542         auto child = rootComponent_->GetChild();
543         auto focusCollaboration = AceType::MakeRefPtr<FocusCollaborationComponent>();
544         focusCollaboration->InsertChild(0, child);
545         bool isCard = AceApplicationInfo::GetInstance().GetIsCardType();
546         if (isCard) {
547             rootComponent_->SetChild(focusCollaboration);
548         } else if (direction_ == DOM_FLEX_COLUMN) {
549             scroll_ = AceType::MakeRefPtr<ScrollComponent>(focusCollaboration);
550             scroll_->SetAxisDirection(Axis::VERTICAL);
551             scroll_->InitScrollBar(GetTheme<ScrollBarTheme>(), overflowStyle.scrollBarColor,
552                 overflowStyle.scrollBarWidth, overflowStyle.edgeEffect);
553             rootComponent_->SetChild(scroll_);
554         } else if (direction_ == DOM_FLEX_ROW) {
555             scroll_ = AceType::MakeRefPtr<ScrollComponent>(focusCollaboration);
556             scroll_->SetAxisDirection(Axis::HORIZONTAL);
557             scroll_->SetEnable(false);
558             scroll_->InitScrollBar(GetTheme<ScrollBarTheme>(), overflowStyle.scrollBarColor,
559                 overflowStyle.scrollBarWidth, overflowStyle.edgeEffect);
560             rootComponent_->SetChild(scroll_);
561         } else {
562             rootComponent_->SetChild(focusCollaboration);
563         }
564 
565         if (flexChild_) {
566             flexChild_->SetUseViewPortFlag(true);
567             if ((flexDirection_ == FlexDirection::ROW && boxComponent_->GetWidthDimension().IsValid()) ||
568                 (flexDirection_ == FlexDirection::COLUMN && boxComponent_->GetHeightDimension().IsValid())) {
569                 flexChild_->SetMainAxisSize(MainAxisSize::MAX);
570             } else {
571                 flexChild_->SetMainAxisSize(MainAxisSize::MIN);
572             }
573         }
574     } else if (isRootNode_) {
575         auto child = rootComponent_->GetChild();
576         auto focusCollaboration = AceType::MakeRefPtr<FocusCollaborationComponent>();
577         focusCollaboration->InsertChild(0, child);
578         rootComponent_->SetChild(focusCollaboration);
579     }
580     if (!isRootNode_ && overflowStyle.overflow == Overflow::SCROLL) {
581         auto child = boxComponent_->GetChild();
582         scroll_ = AceType::MakeRefPtr<ScrollComponent>(child);
583         scroll_->SetAxisDirection(direction_ == DOM_FLEX_COLUMN ? Axis::VERTICAL : Axis::HORIZONTAL);
584         scroll_->InitScrollBar(GetTheme<ScrollBarTheme>(), overflowStyle.scrollBarColor, overflowStyle.scrollBarWidth,
585             overflowStyle.edgeEffect);
586         boxComponent_->SetChild(scroll_);
587     }
588     if (scroll_ != nullptr) {
589         scroll_->SetOnReachStart(onReachStart_);
590         scroll_->SetOnReachEnd(onReachEnd_);
591         scroll_->SetOnReachTop(onReachTop_);
592         scroll_->SetOnReachBottom(onReachBottom_);
593     }
594 }
595 
AdjustSpecialParamInLiteMode()596 void DOMDiv::AdjustSpecialParamInLiteMode()
597 {
598     if (alignItems_ == DOM_ALIGN_ITEMS_STRETCH) {
599         alignItems_ = DOM_ALIGN_ITEMS_START;
600     }
601 }
602 
603 } // namespace OHOS::Ace::Framework
604