• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-2023 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_ng/base/frame_node.h"
17 
18 #include "base/geometry/ng/point_t.h"
19 #include "base/log/ace_trace.h"
20 #include "base/log/dump_log.h"
21 #include "base/memory/ace_type.h"
22 #include "base/memory/referenced.h"
23 #include "base/thread/cancelable_callback.h"
24 #include "base/thread/task_executor.h"
25 #include "base/utils/system_properties.h"
26 #include "base/utils/utils.h"
27 #include "core/common/ace_application_info.h"
28 #include "core/components/common/layout/constants.h"
29 #include "core/components_ng/base/ui_node.h"
30 #include "core/components_ng/event/gesture_event_hub.h"
31 #include "core/components_ng/layout/layout_algorithm.h"
32 #include "core/components_ng/layout/layout_wrapper.h"
33 #include "core/components_ng/pattern/pattern.h"
34 #include "core/components_ng/property/measure_property.h"
35 #include "core/components_ng/property/measure_utils.h"
36 #include "core/components_ng/property/property.h"
37 #include "core/components_ng/render/paint_wrapper.h"
38 #include "core/components_v2/inspector/inspector_constants.h"
39 #include "core/pipeline_ng/pipeline_context.h"
40 #include "core/pipeline_ng/ui_task_scheduler.h"
41 
42 namespace {
43 constexpr double VISIBLE_RATIO_MIN = 0.0;
44 constexpr double VISIBLE_RATIO_MAX = 1.0;
45 #if defined(PREVIEW)
46 constexpr int32_t SUBSTR_LENGTH = 3;
47 const char DIMENSION_UNIT_VP[] = "vp";
48 #endif
49 } // namespace
50 namespace OHOS::Ace::NG {
FrameNode(const std::string & tag,int32_t nodeId,const RefPtr<Pattern> & pattern,bool isRoot)51 FrameNode::FrameNode(const std::string& tag, int32_t nodeId, const RefPtr<Pattern>& pattern, bool isRoot)
52     : UINode(tag, nodeId, isRoot), pattern_(pattern)
53 {
54     renderContext_->InitContext(IsRootNode(), pattern_->GetSurfaceNodeName(), pattern_->UseExternalRSNode());
55     paintProperty_ = pattern->CreatePaintProperty();
56     layoutProperty_ = pattern->CreateLayoutProperty();
57     eventHub_ = pattern->CreateEventHub();
58     accessibilityProperty_ = pattern->CreateAccessibilityProperty();
59     // first create make layout property dirty.
60     layoutProperty_->UpdatePropertyChangeFlag(PROPERTY_UPDATE_MEASURE);
61     layoutProperty_->SetHost(WeakClaim(this));
62 }
63 
~FrameNode()64 FrameNode::~FrameNode()
65 {
66     for (const auto& destroyCallback : destroyCallbacks_) {
67         destroyCallback();
68     }
69     pattern_->DetachFromFrameNode(this);
70     if (IsOnMainTree()) {
71         OnDetachFromMainTree();
72     }
73     auto pipeline = PipelineContext::GetCurrentContext();
74     if (pipeline) {
75         pipeline->RemoveOnAreaChangeNode(GetId());
76         auto dragManager = pipeline->GetDragDropManager();
77         dragManager->RemoveDragFrameNode(AceType::WeakClaim(this));
78     }
79 }
80 
CreateFrameNodeWithTree(const std::string & tag,int32_t nodeId,const RefPtr<Pattern> & pattern)81 RefPtr<FrameNode> FrameNode::CreateFrameNodeWithTree(
82     const std::string& tag, int32_t nodeId, const RefPtr<Pattern>& pattern)
83 {
84     auto newChild = CreateFrameNode(tag, nodeId, pattern, true);
85     newChild->SetDepth(1);
86     return newChild;
87 }
88 
GetOrCreateFrameNode(const std::string & tag,int32_t nodeId,const std::function<RefPtr<Pattern> (void)> & patternCreator)89 RefPtr<FrameNode> FrameNode::GetOrCreateFrameNode(
90     const std::string& tag, int32_t nodeId, const std::function<RefPtr<Pattern>(void)>& patternCreator)
91 {
92     auto frameNode = GetFrameNode(tag, nodeId);
93     if (frameNode) {
94         return frameNode;
95     }
96     auto pattern = patternCreator ? patternCreator() : MakeRefPtr<Pattern>();
97     return CreateFrameNode(tag, nodeId, pattern);
98 }
99 
GetFrameNode(const std::string & tag,int32_t nodeId)100 RefPtr<FrameNode> FrameNode::GetFrameNode(const std::string& tag, int32_t nodeId)
101 {
102     auto frameNode = ElementRegister::GetInstance()->GetSpecificItemById<FrameNode>(nodeId);
103     CHECK_NULL_RETURN_NOLOG(frameNode, nullptr);
104     if (frameNode->GetTag() != tag) {
105         LOGE("the tag is changed");
106         ElementRegister::GetInstance()->RemoveItemSilently(nodeId);
107         auto parent = frameNode->GetParent();
108         if (parent) {
109             parent->RemoveChild(frameNode);
110         }
111         return nullptr;
112     }
113     return frameNode;
114 }
115 
CreateFrameNode(const std::string & tag,int32_t nodeId,const RefPtr<Pattern> & pattern,bool isRoot)116 RefPtr<FrameNode> FrameNode::CreateFrameNode(
117     const std::string& tag, int32_t nodeId, const RefPtr<Pattern>& pattern, bool isRoot)
118 {
119     auto frameNode = MakeRefPtr<FrameNode>(tag, nodeId, pattern, isRoot);
120     frameNode->InitializePatternAndContext();
121     ElementRegister::GetInstance()->AddUINode(frameNode);
122     return frameNode;
123 }
124 
InitializePatternAndContext()125 void FrameNode::InitializePatternAndContext()
126 {
127     eventHub_->AttachHost(WeakClaim(this));
128     pattern_->AttachToFrameNode(WeakClaim(this));
129     accessibilityProperty_->SetHost(WeakClaim(this));
130     renderContext_->SetRequestFrame([weak = WeakClaim(this)] {
131         auto frameNode = weak.Upgrade();
132         CHECK_NULL_VOID(frameNode);
133         if (frameNode->IsOnMainTree()) {
134             auto context = frameNode->GetContext();
135             CHECK_NULL_VOID(context);
136             context->RequestFrame();
137             return;
138         }
139         frameNode->hasPendingRequest_ = true;
140     });
141     renderContext_->SetHostNode(WeakClaim(this));
142     // Initialize FocusHub
143     if (pattern_->GetFocusPattern().GetFocusType() != FocusType::DISABLE) {
144         GetOrCreateFocusHub();
145     }
146 }
147 
DumpInfo()148 void FrameNode::DumpInfo()
149 {
150     DumpLog::GetInstance().AddDesc(std::string("FrameRect: ").append(geometryNode_->GetFrameRect().ToString()));
151     DumpLog::GetInstance().AddDesc(
152         std::string("BackgroundColor: ").append(renderContext_->GetBackgroundColor()->ColorToString()));
153     DumpLog::GetInstance().AddDesc(std::string("ParentLayoutConstraint: ")
154                                        .append(geometryNode_->GetParentLayoutConstraint().has_value()
155                                                    ? geometryNode_->GetParentLayoutConstraint().value().ToString()
156                                                    : "NA"));
157     DumpLog::GetInstance().AddDesc(std::string("top: ")
158                                        .append(std::to_string(GetOffsetRelativeToWindow().GetY()))
159                                        .append(" left: ")
160                                        .append(std::to_string(GetOffsetRelativeToWindow().GetX())));
161     DumpLog::GetInstance().AddDesc(std::string("Visible: ")
162                                        .append(std::to_string(static_cast<int32_t>(
163                                            layoutProperty_->GetVisibility().value_or(VisibleType::VISIBLE)))));
164     if (layoutProperty_->GetPaddingProperty()) {
165         DumpLog::GetInstance().AddDesc(
166             std::string("Padding: ").append(layoutProperty_->GetPaddingProperty()->ToString().c_str()));
167     }
168     if (layoutProperty_->GetBorderWidthProperty()) {
169         DumpLog::GetInstance().AddDesc(
170             std::string("Border: ").append(layoutProperty_->GetBorderWidthProperty()->ToString().c_str()));
171     }
172     if (layoutProperty_->GetMarginProperty()) {
173         DumpLog::GetInstance().AddDesc(
174             std::string("Margin: ").append(layoutProperty_->GetMarginProperty()->ToString().c_str()));
175     }
176     DumpLog::GetInstance().AddDesc(std::string("compid: ").append(propInspectorId_.value_or("")));
177     DumpLog::GetInstance().AddDesc(std::string("ContentConstraint: ")
178                                        .append(layoutProperty_->GetContentLayoutConstraint().has_value()
179                                                    ? layoutProperty_->GetContentLayoutConstraint().value().ToString()
180                                                    : "NA"));
181     DumpLog::GetInstance().AddDesc(
182         std::string("PaintRect: ").append(renderContext_->GetPaintRectWithTransform().ToString()));
183     if (pattern_) {
184         pattern_->DumpInfo();
185     }
186     if (renderContext_) {
187         renderContext_->DumpInfo();
188     }
189 }
190 
FocusToJsonValue(std::unique_ptr<JsonValue> & json) const191 void FrameNode::FocusToJsonValue(std::unique_ptr<JsonValue>& json) const
192 {
193     bool enabled = true;
194     bool focusable = false;
195     bool focused = false;
196     bool defaultFocus = false;
197     bool groupDefaultFocus = false;
198     bool focusOnTouch = false;
199     int32_t tabIndex = 0;
200     auto focusHub = GetFocusHub();
201     if (focusHub) {
202         enabled = focusHub->IsEnabled();
203         focusable = focusHub->IsFocusable();
204         focused = focusHub->IsCurrentFocus();
205         defaultFocus = focusHub->IsDefaultFocus();
206         groupDefaultFocus = focusHub->IsDefaultGroupFocus();
207         focusOnTouch = focusHub->IsFocusOnTouch().value_or(false);
208         tabIndex = focusHub->GetTabIndex();
209     }
210     json->Put("enabled", enabled);
211     json->Put("focusable", focusable);
212     json->Put("focused", focused);
213     json->Put("defaultFocus", defaultFocus);
214     json->Put("groupDefaultFocus", groupDefaultFocus);
215     json->Put("focusOnTouch", focusOnTouch);
216     json->Put("tabIndex", tabIndex);
217 }
218 
MouseToJsonValue(std::unique_ptr<JsonValue> & json) const219 void FrameNode::MouseToJsonValue(std::unique_ptr<JsonValue>& json) const
220 {
221     std::string hoverEffect = "HoverEffect.Auto";
222     auto inputEventHub = GetOrCreateInputEventHub();
223     if (inputEventHub) {
224         hoverEffect = inputEventHub->GetHoverEffectStr();
225     }
226     json->Put("hoverEffect", hoverEffect.c_str());
227 }
228 
TouchToJsonValue(std::unique_ptr<JsonValue> & json) const229 void FrameNode::TouchToJsonValue(std::unique_ptr<JsonValue>& json) const
230 {
231     bool touchable = true;
232     std::string hitTestMode = "HitTestMode.Default";
233     auto gestureEventHub = GetOrCreateGestureEventHub();
234     std::vector<DimensionRect> responseRegion;
235     if (gestureEventHub) {
236         touchable = gestureEventHub->GetTouchable();
237         hitTestMode = gestureEventHub->GetHitTestModeStr();
238         responseRegion = gestureEventHub->GetResponseRegion();
239     }
240     json->Put("touchable", touchable);
241     json->Put("hitTestBehavior", hitTestMode.c_str());
242     auto jsArr = JsonUtil::CreateArray(true);
243     for (int32_t i = 0; i < static_cast<int32_t>(responseRegion.size()); ++i) {
244         auto iStr = std::to_string(i);
245         jsArr->Put(iStr.c_str(), responseRegion[i].ToJsonString().c_str());
246     }
247     json->Put("responseRegion", jsArr);
248 }
249 
GeometryNodeToJsonValue(std::unique_ptr<JsonValue> & json) const250 void FrameNode::GeometryNodeToJsonValue(std::unique_ptr<JsonValue>& json) const
251 {
252 #if defined(PREVIEW)
253     bool hasIdealWidth = false;
254     bool hasIdealHeight = false;
255     if (layoutProperty_ && layoutProperty_->GetCalcLayoutConstraint()) {
256         auto selfIdealSize = layoutProperty_->GetCalcLayoutConstraint()->selfIdealSize;
257         hasIdealWidth = selfIdealSize.has_value() && selfIdealSize.value().Width().has_value();
258         hasIdealHeight = selfIdealSize.has_value() && selfIdealSize.value().Height().has_value();
259     }
260 
261     auto jsonSize = json->GetValue("size");
262     if (!hasIdealWidth) {
263         auto idealWidthVpStr = std::to_string(Dimension(geometryNode_->GetFrameSize().Width()).ConvertToVp());
264         auto widthStr =
265             (idealWidthVpStr.substr(0, idealWidthVpStr.find(".") + SUBSTR_LENGTH) + DIMENSION_UNIT_VP).c_str();
266         json->Put("width", widthStr);
267         if (jsonSize) {
268             jsonSize->Put("width", widthStr);
269         }
270     }
271 
272     if (!hasIdealHeight) {
273         auto idealHeightVpStr = std::to_string(Dimension(geometryNode_->GetFrameSize().Height()).ConvertToVp());
274         auto heightStr =
275             (idealHeightVpStr.substr(0, idealHeightVpStr.find(".") + SUBSTR_LENGTH) + DIMENSION_UNIT_VP).c_str();
276         json->Put("height", heightStr);
277         if (jsonSize) {
278             jsonSize->Put("height", heightStr);
279         }
280     }
281 #endif
282 }
283 
ToJsonValue(std::unique_ptr<JsonValue> & json) const284 void FrameNode::ToJsonValue(std::unique_ptr<JsonValue>& json) const
285 {
286     if (renderContext_) {
287         renderContext_->ToJsonValue(json);
288     }
289     // scrollable in AccessibilityProperty
290     ACE_PROPERTY_TO_JSON_VALUE(accessibilityProperty_, AccessibilityProperty);
291     ACE_PROPERTY_TO_JSON_VALUE(layoutProperty_, LayoutProperty);
292     ACE_PROPERTY_TO_JSON_VALUE(paintProperty_, PaintProperty);
293     ACE_PROPERTY_TO_JSON_VALUE(pattern_, Pattern);
294     if (eventHub_) {
295         eventHub_->ToJsonValue(json);
296     }
297     FocusToJsonValue(json);
298     MouseToJsonValue(json);
299     TouchToJsonValue(json);
300     GeometryNodeToJsonValue(json);
301     json->Put("id", propInspectorId_.value_or("").c_str());
302 }
303 
OnAttachToMainTree()304 void FrameNode::OnAttachToMainTree()
305 {
306     UINode::OnAttachToMainTree();
307     eventHub_->FireOnAppear();
308     renderContext_->OnNodeAppear();
309     if (IsResponseRegion() || HasPositionProp()) {
310         auto parent = GetParent();
311         while (parent) {
312             auto frameNode = AceType::DynamicCast<FrameNode>(parent);
313             if (frameNode) {
314                 frameNode->MarkResponseRegion(true);
315             }
316             parent = parent->GetParent();
317         }
318     }
319     if (!hasPendingRequest_) {
320         return;
321     }
322     auto context = GetContext();
323     CHECK_NULL_VOID(context);
324     context->RequestFrame();
325     hasPendingRequest_ = false;
326 }
327 
OnVisibleChange(bool isVisible)328 void FrameNode::OnVisibleChange(bool isVisible)
329 {
330     pattern_->OnVisibleChange(isVisible);
331     for (const auto& child : GetChildren()) {
332         child->OnVisibleChange(isVisible);
333     }
334 }
335 
OnDetachFromMainTree()336 void FrameNode::OnDetachFromMainTree()
337 {
338     eventHub_->FireOnDisappear();
339     renderContext_->OnNodeDisappear();
340 }
341 
SwapDirtyLayoutWrapperOnMainThread(const RefPtr<LayoutWrapper> & dirty)342 void FrameNode::SwapDirtyLayoutWrapperOnMainThread(const RefPtr<LayoutWrapper>& dirty)
343 {
344     ACE_FUNCTION_TRACE();
345     LOGD("SwapDirtyLayoutWrapperOnMainThread, %{public}s", GetTag().c_str());
346     CHECK_NULL_VOID(dirty);
347 
348     // update new layout constrain.
349     layoutProperty_->UpdateLayoutConstraint(dirty->GetLayoutProperty());
350 
351     // active change flag judge.
352     SetActive(dirty->IsActive());
353     if (!isActive_) {
354         LOGD("current node is inactive, don't need to render");
355         return;
356     }
357 
358     // update layout size.
359     bool frameSizeChange = geometryNode_->GetFrameSize() != dirty->GetGeometryNode()->GetFrameSize();
360     bool frameOffsetChange = geometryNode_->GetFrameOffset() != dirty->GetGeometryNode()->GetFrameOffset();
361     bool contentSizeChange = geometryNode_->GetContentSize() != dirty->GetGeometryNode()->GetContentSize();
362     bool contentOffsetChange = geometryNode_->GetContentOffset() != dirty->GetGeometryNode()->GetContentOffset();
363 
364     SetGeometryNode(dirty->GetGeometryNode());
365     if (frameSizeChange || frameOffsetChange || HasPositionProp() ||
366         (pattern_->GetSurfaceNodeName().has_value() && contentSizeChange)) {
367         if (pattern_->NeedOverridePaintRect()) {
368             renderContext_->SyncGeometryProperties(pattern_->GetOverridePaintRect().value_or(RectF()));
369         } else {
370             renderContext_->SyncGeometryProperties(RawPtr(dirty->GetGeometryNode()));
371         }
372     }
373 
374     // clean layout flag.
375     layoutProperty_->CleanDirty();
376     DirtySwapConfig config { frameSizeChange, frameOffsetChange, contentSizeChange, contentOffsetChange };
377     // check if need to paint content.
378     auto layoutAlgorithmWrapper = DynamicCast<LayoutAlgorithmWrapper>(dirty->GetLayoutAlgorithm());
379     CHECK_NULL_VOID(layoutAlgorithmWrapper);
380     config.skipMeasure = layoutAlgorithmWrapper->SkipMeasure() || dirty->SkipMeasureContent();
381     config.skipLayout = layoutAlgorithmWrapper->SkipLayout();
382     auto needRerender = pattern_->OnDirtyLayoutWrapperSwap(dirty, config);
383     // TODO: temp use and need to delete.
384     needRerender = needRerender || pattern_->OnDirtyLayoutWrapperSwap(dirty, config.skipMeasure, config.skipLayout);
385     if (needRerender || CheckNeedRender(paintProperty_->GetPropertyChangeFlag())) {
386         MarkDirtyNode(true, true, PROPERTY_UPDATE_RENDER);
387     }
388 
389     // update border.
390     if (layoutProperty_->GetBorderWidthProperty()) {
391         if (!renderContext_->HasBorderColor()) {
392             BorderColorProperty borderColorProperty;
393             borderColorProperty.SetColor(Color::BLACK);
394             renderContext_->UpdateBorderColor(borderColorProperty);
395         }
396         if (!renderContext_->HasBorderStyle()) {
397             BorderStyleProperty borderStyleProperty;
398             borderStyleProperty.SetBorderStyle(BorderStyle::SOLID);
399             renderContext_->UpdateBorderStyle(borderStyleProperty);
400         }
401         if (layoutProperty_->GetLayoutConstraint().has_value()) {
402             renderContext_->UpdateBorderWidthF(ConvertToBorderWidthPropertyF(layoutProperty_->GetBorderWidthProperty(),
403                 ScaleProperty::CreateScaleProperty(),
404                 layoutProperty_->GetLayoutConstraint()->percentReference.Width()));
405         } else {
406             renderContext_->UpdateBorderWidthF(ConvertToBorderWidthPropertyF(layoutProperty_->GetBorderWidthProperty(),
407                 ScaleProperty::CreateScaleProperty(), PipelineContext::GetCurrentRootWidth()));
408         }
409     }
410 
411     // update focus state
412     auto focusHub = GetFocusHub();
413     if (focusHub && focusHub->IsCurrentFocus()) {
414         focusHub->ClearFocusState();
415         focusHub->PaintFocusState();
416     }
417 
418     // rebuild child render node.
419     RebuildRenderContextTree();
420 }
421 
AdjustGridOffset()422 void FrameNode::AdjustGridOffset()
423 {
424     if (!isActive_) {
425         return;
426     }
427     if (layoutProperty_->UpdateGridOffset(Claim(this))) {
428         renderContext_->UpdateOffset(OffsetT<Dimension>());
429         renderContext_->UpdateAnchor(OffsetT<Dimension>());
430         renderContext_->SyncGeometryProperties(RawPtr(GetGeometryNode()));
431     }
432 }
433 
SetOnAreaChangeCallback(OnAreaChangedFunc && callback)434 void FrameNode::SetOnAreaChangeCallback(OnAreaChangedFunc&& callback)
435 {
436     if (!lastFrameRect_) {
437         lastFrameRect_ = std::make_unique<RectF>();
438     }
439     if (!lastParentOffsetToWindow_) {
440         lastParentOffsetToWindow_ = std::make_unique<OffsetF>();
441     }
442     eventHub_->SetOnAreaChanged(std::move(callback));
443 }
444 
TriggerOnAreaChangeCallback()445 void FrameNode::TriggerOnAreaChangeCallback()
446 {
447     if (eventHub_->HasOnAreaChanged() && lastFrameRect_ && lastParentOffsetToWindow_) {
448         auto currFrameRect = geometryNode_->GetFrameRect();
449         auto currParentOffsetToWindow = GetOffsetRelativeToWindow() - currFrameRect.GetOffset();
450         if (currFrameRect != *lastFrameRect_ || currParentOffsetToWindow != *lastParentOffsetToWindow_) {
451             eventHub_->FireOnAreaChanged(
452                 *lastFrameRect_, *lastParentOffsetToWindow_, currFrameRect, currParentOffsetToWindow);
453             *lastFrameRect_ = currFrameRect;
454             *lastParentOffsetToWindow_ = currParentOffsetToWindow;
455         }
456     }
457     pattern_->OnAreaChangedInner();
458 }
459 
TriggerVisibleAreaChangeCallback(std::list<VisibleCallbackInfo> & callbackInfoList)460 void FrameNode::TriggerVisibleAreaChangeCallback(std::list<VisibleCallbackInfo>& callbackInfoList)
461 {
462     auto context = PipelineContext::GetCurrentContext();
463     CHECK_NULL_VOID(context);
464 
465     bool curFrameIsActive = true;
466     auto parent = GetParent();
467     while (parent) {
468         auto parentFrame = AceType::DynamicCast<FrameNode>(parent);
469         if (!parentFrame) {
470             parent = parent->GetParent();
471             continue;
472         }
473         if (!parentFrame->isActive_) {
474             curFrameIsActive = false;
475             break;
476         }
477         parent = parent->GetParent();
478     }
479 
480     if (!context->GetOnShow() || !IsVisible() || !curFrameIsActive) {
481         if (!NearEqual(lastVisibleRatio_, VISIBLE_RATIO_MIN)) {
482             ProcessAllVisibleCallback(callbackInfoList, VISIBLE_RATIO_MIN);
483             lastVisibleRatio_ = VISIBLE_RATIO_MIN;
484         }
485         return;
486     }
487 
488     auto frameRect = renderContext_->GetPaintRectWithTransform();
489     frameRect.SetOffset(GetOffsetRelativeToWindow());
490     auto visibleRect = frameRect;
491     RectF parentRect;
492     auto parentUi = GetParent();
493     while (parentUi) {
494         auto parentFrame = AceType::DynamicCast<FrameNode>(parentUi);
495         if (!parentFrame) {
496             parentUi = parentUi->GetParent();
497             continue;
498         }
499         parentRect = parentFrame->GetRenderContext()->GetPaintRectWithTransform();
500         parentRect.SetOffset(parentFrame->GetOffsetRelativeToWindow());
501         visibleRect = visibleRect.Constrain(parentRect);
502         parentUi = parentUi->GetParent();
503     }
504 
505     double currentVisibleRatio =
506         std::clamp(CalculateCurrentVisibleRatio(visibleRect, frameRect), VISIBLE_RATIO_MIN, VISIBLE_RATIO_MAX);
507     if (!NearEqual(currentVisibleRatio, lastVisibleRatio_)) {
508         ProcessAllVisibleCallback(callbackInfoList, currentVisibleRatio);
509         lastVisibleRatio_ = currentVisibleRatio;
510     }
511 }
512 
CalculateCurrentVisibleRatio(const RectF & visibleRect,const RectF & renderRect)513 double FrameNode::CalculateCurrentVisibleRatio(const RectF& visibleRect, const RectF& renderRect)
514 {
515     if (!visibleRect.IsValid() || !renderRect.IsValid()) {
516         return 0.0;
517     }
518     return visibleRect.Width() * visibleRect.Height() / (renderRect.Width() * renderRect.Height());
519 }
520 
ProcessAllVisibleCallback(std::list<VisibleCallbackInfo> & callbackInfoList,double currentVisibleRatio)521 void FrameNode::ProcessAllVisibleCallback(std::list<VisibleCallbackInfo>& callbackInfoList, double currentVisibleRatio)
522 {
523     for (auto& nodeCallbackInfo : callbackInfoList) {
524         if (GreatNotEqual(currentVisibleRatio, nodeCallbackInfo.visibleRatio) && !nodeCallbackInfo.isCurrentVisible) {
525             OnVisibleAreaChangeCallback(nodeCallbackInfo, true, currentVisibleRatio);
526             continue;
527         }
528 
529         if (LessNotEqual(currentVisibleRatio, nodeCallbackInfo.visibleRatio) && nodeCallbackInfo.isCurrentVisible) {
530             OnVisibleAreaChangeCallback(nodeCallbackInfo, false, currentVisibleRatio);
531             continue;
532         }
533 
534         if (NearEqual(currentVisibleRatio, nodeCallbackInfo.visibleRatio) &&
535             NearEqual(nodeCallbackInfo.visibleRatio, VISIBLE_RATIO_MIN)) {
536             if (nodeCallbackInfo.isCurrentVisible) {
537                 OnVisibleAreaChangeCallback(nodeCallbackInfo, false, VISIBLE_RATIO_MIN);
538             } else {
539                 OnVisibleAreaChangeCallback(nodeCallbackInfo, true, VISIBLE_RATIO_MIN);
540             }
541         } else if (NearEqual(currentVisibleRatio, nodeCallbackInfo.visibleRatio) &&
542                    NearEqual(nodeCallbackInfo.visibleRatio, VISIBLE_RATIO_MAX)) {
543             if (!nodeCallbackInfo.isCurrentVisible) {
544                 OnVisibleAreaChangeCallback(nodeCallbackInfo, true, VISIBLE_RATIO_MAX);
545             } else {
546                 OnVisibleAreaChangeCallback(nodeCallbackInfo, false, VISIBLE_RATIO_MAX);
547             }
548         }
549     }
550 }
551 
OnVisibleAreaChangeCallback(VisibleCallbackInfo & callbackInfo,bool visibleType,double currentVisibleRatio)552 void FrameNode::OnVisibleAreaChangeCallback(
553     VisibleCallbackInfo& callbackInfo, bool visibleType, double currentVisibleRatio)
554 {
555     callbackInfo.isCurrentVisible = visibleType;
556     if (callbackInfo.callback) {
557         callbackInfo.callback(visibleType, currentVisibleRatio);
558     }
559 }
560 
SetActive(bool active)561 void FrameNode::SetActive(bool active)
562 {
563     bool activeChanged = false;
564     if (active && !isActive_) {
565         pattern_->OnActive();
566         isActive_ = true;
567         activeChanged = true;
568     }
569     if (!active && isActive_) {
570         pattern_->OnInActive();
571         isActive_ = false;
572         activeChanged = true;
573     }
574     if (activeChanged) {
575         auto parent = GetAncestorNodeOfFrame();
576         if (parent) {
577             parent->MarkNeedSyncRenderTree();
578         }
579     }
580 }
581 
SetGeometryNode(const RefPtr<GeometryNode> & node)582 void FrameNode::SetGeometryNode(const RefPtr<GeometryNode>& node)
583 {
584     geometryNode_ = node;
585 }
586 
CreateLayoutTask(bool forceUseMainThread)587 std::optional<UITask> FrameNode::CreateLayoutTask(bool forceUseMainThread)
588 {
589     if (!isLayoutDirtyMarked_) {
590         return std::nullopt;
591     }
592     ACE_SCOPED_TRACE("CreateLayoutTask:PrepareTask");
593     RefPtr<LayoutWrapper> layoutWrapper;
594     UpdateLayoutPropertyFlag();
595     layoutWrapper = CreateLayoutWrapper();
596     CHECK_NULL_RETURN_NOLOG(layoutWrapper, std::nullopt);
597     auto task = [layoutWrapper, layoutConstraint = GetLayoutConstraint(), forceUseMainThread]() {
598         layoutWrapper->SetActive();
599         layoutWrapper->SetRootMeasureNode();
600         {
601             ACE_SCOPED_TRACE("LayoutWrapper::Measure");
602             layoutWrapper->Measure(layoutConstraint);
603         }
604         {
605             ACE_SCOPED_TRACE("LayoutWrapper::Layout");
606             layoutWrapper->Layout();
607         }
608         {
609             ACE_SCOPED_TRACE("LayoutWrapper::MountToHostOnMainThread");
610             if (forceUseMainThread || layoutWrapper->CheckShouldRunOnMain()) {
611                 layoutWrapper->MountToHostOnMainThread();
612                 return;
613             }
614             auto host = layoutWrapper->GetHostNode();
615             CHECK_NULL_VOID(host);
616             host->PostTask([layoutWrapper]() { layoutWrapper->MountToHostOnMainThread(); });
617         }
618     };
619     if (forceUseMainThread || layoutWrapper->CheckShouldRunOnMain()) {
620         return UITask(std::move(task), MAIN_TASK);
621     }
622     return UITask(std::move(task), layoutWrapper->CanRunOnWhichThread());
623 }
624 
CreateRenderTask(bool forceUseMainThread)625 std::optional<UITask> FrameNode::CreateRenderTask(bool forceUseMainThread)
626 {
627     if (!isRenderDirtyMarked_) {
628         return std::nullopt;
629     }
630     ACE_SCOPED_TRACE("CreateRenderTask:PrepareTask");
631     auto wrapper = CreatePaintWrapper();
632     CHECK_NULL_RETURN_NOLOG(wrapper, std::nullopt);
633     auto task = [wrapper, paintProperty = paintProperty_]() {
634         ACE_SCOPED_TRACE("FrameNode::RenderTask");
635         wrapper->FlushRender();
636         paintProperty->CleanDirty();
637     };
638     if (forceUseMainThread || wrapper->CheckShouldRunOnMain()) {
639         return UITask(std::move(task), MAIN_TASK);
640     }
641     return UITask(std::move(task), wrapper->CanRunOnWhichThread());
642 }
643 
GetLayoutConstraint() const644 LayoutConstraintF FrameNode::GetLayoutConstraint() const
645 {
646     if (geometryNode_->GetParentLayoutConstraint().has_value()) {
647         return geometryNode_->GetParentLayoutConstraint().value();
648     }
649     LayoutConstraintF layoutConstraint;
650     layoutConstraint.scaleProperty = ScaleProperty::CreateScaleProperty();
651     auto rootWidth = PipelineContext::GetCurrentRootWidth();
652     auto rootHeight = PipelineContext::GetCurrentRootHeight();
653     layoutConstraint.percentReference.SetWidth(rootWidth);
654     layoutConstraint.percentReference.SetHeight(rootHeight);
655     layoutConstraint.maxSize.SetWidth(rootWidth);
656     layoutConstraint.maxSize.SetHeight(rootHeight);
657     return layoutConstraint;
658 }
659 
GetParentGlobalOffset() const660 OffsetF FrameNode::GetParentGlobalOffset() const
661 {
662     auto parent = GetAncestorNodeOfFrame();
663     if (!parent) {
664         return { 0.0f, 0.0f };
665     }
666     return parent->geometryNode_->GetParentGlobalOffset();
667 }
668 
UpdateLayoutPropertyFlag()669 void FrameNode::UpdateLayoutPropertyFlag()
670 {
671     auto selfFlag = layoutProperty_->GetPropertyChangeFlag();
672     if (!CheckUpdateByChildRequest(selfFlag)) {
673         return;
674     }
675     if (CheckForceParentMeasureFlag(selfFlag)) {
676         return;
677     }
678     auto flag = PROPERTY_UPDATE_NORMAL;
679     const auto& children = GetChildren();
680     for (const auto& child : children) {
681         child->UpdateLayoutPropertyFlag();
682         child->AdjustParentLayoutFlag(flag);
683         if (CheckForceParentMeasureFlag(selfFlag)) {
684             break;
685         }
686     }
687     if (CheckForceParentMeasureFlag(flag)) {
688         layoutProperty_->UpdatePropertyChangeFlag(PROPERTY_UPDATE_MEASURE);
689     }
690 }
691 
AdjustParentLayoutFlag(PropertyChangeFlag & flag)692 void FrameNode::AdjustParentLayoutFlag(PropertyChangeFlag& flag)
693 {
694     flag = flag | layoutProperty_->GetPropertyChangeFlag();
695 }
696 
CreateLayoutWrapper(bool forceMeasure,bool forceLayout)697 RefPtr<LayoutWrapper> FrameNode::CreateLayoutWrapper(bool forceMeasure, bool forceLayout)
698 {
699     CHECK_NULL_RETURN_NOLOG(layoutProperty_, nullptr);
700     CHECK_NULL_RETURN_NOLOG(pattern_, nullptr);
701     if (layoutProperty_->GetVisibility().value_or(VisibleType::VISIBLE) == VisibleType::GONE) {
702         auto layoutWrapper =
703             MakeRefPtr<LayoutWrapper>(WeakClaim(this), MakeRefPtr<GeometryNode>(), layoutProperty_->Clone());
704         layoutWrapper->SetLayoutAlgorithm(MakeRefPtr<LayoutAlgorithmWrapper>(nullptr, true, true));
705         isLayoutDirtyMarked_ = false;
706         return layoutWrapper;
707     }
708 
709     pattern_->BeforeCreateLayoutWrapper();
710     if (!isActive_ || forceMeasure) {
711         layoutProperty_->UpdatePropertyChangeFlag(PROPERTY_UPDATE_MEASURE);
712     }
713     if (forceLayout) {
714         layoutProperty_->UpdatePropertyChangeFlag(PROPERTY_UPDATE_LAYOUT);
715     }
716     auto flag = layoutProperty_->GetPropertyChangeFlag();
717     // It is necessary to copy the layoutProperty property to prevent the layoutProperty property from being modified
718     // during the layout process, resulting in the problem of judging whether the front-end setting value changes the
719     // next time js is executed.
720     auto layoutWrapper = MakeRefPtr<LayoutWrapper>(WeakClaim(this), geometryNode_->Clone(), layoutProperty_->Clone());
721     LOGD("%{public}s create layout wrapper: %{public}x, %{public}d, %{public}d", GetTag().c_str(), flag, forceMeasure,
722         forceLayout);
723     do {
724         if (CheckNeedMeasure(flag) || forceMeasure) {
725             layoutWrapper->SetLayoutAlgorithm(MakeRefPtr<LayoutAlgorithmWrapper>(pattern_->CreateLayoutAlgorithm()));
726             bool forceChildMeasure = CheckMeasureFlag(flag) || CheckMeasureSelfAndChildFlag(flag) || forceMeasure;
727             UpdateChildrenLayoutWrapper(layoutWrapper, forceChildMeasure, false);
728             break;
729         }
730         if (CheckNeedLayout(flag) || forceLayout) {
731             layoutWrapper->SetLayoutAlgorithm(
732                 MakeRefPtr<LayoutAlgorithmWrapper>(pattern_->CreateLayoutAlgorithm(), true, false));
733             UpdateChildrenLayoutWrapper(layoutWrapper, false, false);
734             break;
735         }
736         layoutWrapper->SetLayoutAlgorithm(MakeRefPtr<LayoutAlgorithmWrapper>(nullptr, true, true));
737     } while (false);
738     // check position flag.
739     layoutWrapper->SetOutOfLayout(renderContext_->HasPosition());
740     layoutWrapper->SetActive(isActive_);
741     isLayoutDirtyMarked_ = false;
742     return layoutWrapper;
743 }
744 
UpdateChildrenLayoutWrapper(const RefPtr<LayoutWrapper> & self,bool forceMeasure,bool forceLayout)745 void FrameNode::UpdateChildrenLayoutWrapper(const RefPtr<LayoutWrapper>& self, bool forceMeasure, bool forceLayout)
746 {
747     const auto& children = GetChildren();
748     for (const auto& child : children) {
749         child->AdjustLayoutWrapperTree(self, forceMeasure, forceLayout);
750     }
751 }
752 
AdjustLayoutWrapperTree(const RefPtr<LayoutWrapper> & parent,bool forceMeasure,bool forceLayout)753 void FrameNode::AdjustLayoutWrapperTree(const RefPtr<LayoutWrapper>& parent, bool forceMeasure, bool forceLayout)
754 {
755     ACE_DCHECK(parent);
756     auto layoutWrapper = CreateLayoutWrapper(forceMeasure, forceLayout);
757     parent->AppendChild(layoutWrapper);
758 }
759 
CreatePaintWrapper()760 RefPtr<PaintWrapper> FrameNode::CreatePaintWrapper()
761 {
762     pattern_->BeforeCreatePaintWrapper();
763     isRenderDirtyMarked_ = false;
764     auto paintMethod = pattern_->CreateNodePaintMethod();
765     // It is necessary to copy the layoutProperty property to prevent the paintProperty_ property from being modified
766     // during the paint process, resulting in the problem of judging whether the front-end setting value changes the
767     // next time js is executed.
768     if (paintMethod) {
769         auto paintWrapper = MakeRefPtr<PaintWrapper>(renderContext_, geometryNode_->Clone(), paintProperty_->Clone());
770         paintWrapper->SetNodePaintMethod(paintMethod);
771         return paintWrapper;
772     }
773     if (renderContext_->GetAccessibilityFocus().value_or(false)) {
774         auto paintWrapper = MakeRefPtr<PaintWrapper>(renderContext_, geometryNode_->Clone(), paintProperty_->Clone());
775         paintWrapper->SetNodePaintMethod(MakeRefPtr<NodePaintMethod>());
776         return paintWrapper;
777     }
778     return nullptr;
779 }
780 
PostTask(std::function<void ()> && task,TaskExecutor::TaskType taskType)781 void FrameNode::PostTask(std::function<void()>&& task, TaskExecutor::TaskType taskType)
782 {
783     auto context = GetContext();
784     CHECK_NULL_VOID(context);
785     context->PostAsyncEvent(std::move(task), taskType);
786 }
787 
UpdateLayoutConstraint(const MeasureProperty & calcLayoutConstraint)788 void FrameNode::UpdateLayoutConstraint(const MeasureProperty& calcLayoutConstraint)
789 {
790     layoutProperty_->UpdateCalcLayoutProperty(calcLayoutConstraint);
791 }
792 
RebuildRenderContextTree()793 void FrameNode::RebuildRenderContextTree()
794 {
795     if (!needSyncRenderTree_) {
796         return;
797     }
798     frameChildren_.clear();
799     std::list<RefPtr<FrameNode>> children;
800     GenerateOneDepthVisibleFrame(children);
801     frameChildren_ = { children.begin(), children.end() };
802     renderContext_->RebuildFrame(this, children);
803     pattern_->OnRebuildFrame();
804     needSyncRenderTree_ = false;
805 }
806 
MarkModifyDone()807 void FrameNode::MarkModifyDone()
808 {
809     pattern_->OnModifyDone();
810     eventHub_->MarkModifyDone();
811     if (IsResponseRegion() || HasPositionProp()) {
812         auto parent = GetParent();
813         while (parent) {
814             auto frameNode = AceType::DynamicCast<FrameNode>(parent);
815             if (frameNode) {
816                 frameNode->MarkResponseRegion(true);
817             }
818             parent = parent->GetParent();
819         }
820     }
821     renderContext_->OnModifyDone();
822 }
823 
OnMountToParentDone()824 void FrameNode::OnMountToParentDone()
825 {
826     pattern_->OnMountToParentDone();
827 }
828 
FlushUpdateAndMarkDirty()829 void FrameNode::FlushUpdateAndMarkDirty()
830 {
831     MarkDirtyNode();
832 }
833 
MarkDirtyNode(PropertyChangeFlag extraFlag)834 void FrameNode::MarkDirtyNode(PropertyChangeFlag extraFlag)
835 {
836     MarkDirtyNode(IsMeasureBoundary(), IsRenderBoundary(), extraFlag);
837 }
838 
GetAncestorNodeOfFrame() const839 RefPtr<FrameNode> FrameNode::GetAncestorNodeOfFrame() const
840 {
841     auto parent = GetParent();
842     while (parent) {
843         if (InstanceOf<FrameNode>(parent)) {
844             return DynamicCast<FrameNode>(parent);
845         }
846         parent = parent->GetParent();
847     }
848     return nullptr;
849 }
850 
MarkNeedRenderOnly()851 void FrameNode::MarkNeedRenderOnly()
852 {
853     MarkNeedRender(IsRenderBoundary());
854 }
855 
MarkNeedRender(bool isRenderBoundary)856 void FrameNode::MarkNeedRender(bool isRenderBoundary)
857 {
858     auto context = GetContext();
859     CHECK_NULL_VOID(context);
860     // If it has dirtyLayoutBox, need to mark dirty after layout done.
861     paintProperty_->UpdatePropertyChangeFlag(PROPERTY_UPDATE_RENDER);
862     if (isRenderDirtyMarked_ || isLayoutDirtyMarked_) {
863         LOGD("this node has already mark dirty, %{public}s, %{public}d, %{public}d", GetTag().c_str(),
864             isRenderDirtyMarked_, isLayoutDirtyMarked_);
865         return;
866     }
867     isRenderDirtyMarked_ = true;
868     if (isRenderBoundary) {
869         context->AddDirtyRenderNode(Claim(this));
870         return;
871     }
872     auto parent = GetAncestorNodeOfFrame();
873     if (parent) {
874         parent->MarkDirtyNode(PROPERTY_UPDATE_RENDER_BY_CHILD_REQUEST);
875     }
876 }
877 
MarkDirtyNode(bool isMeasureBoundary,bool isRenderBoundary,PropertyChangeFlag extraFlag)878 void FrameNode::MarkDirtyNode(bool isMeasureBoundary, bool isRenderBoundary, PropertyChangeFlag extraFlag)
879 {
880     if (CheckNeedRender(extraFlag)) {
881         paintProperty_->UpdatePropertyChangeFlag(extraFlag);
882     }
883     layoutProperty_->UpdatePropertyChangeFlag(extraFlag);
884     paintProperty_->UpdatePropertyChangeFlag(extraFlag);
885     auto layoutFlag = layoutProperty_->GetPropertyChangeFlag();
886     auto paintFlag = paintProperty_->GetPropertyChangeFlag();
887     if (CheckNoChanged(layoutFlag | paintFlag)) {
888         LOGD("MarkDirtyNode: flag not changed, node tag: %{public}s", GetTag().c_str());
889         return;
890     }
891     auto context = GetContext();
892     CHECK_NULL_VOID(context);
893 
894     if (CheckNeedRequestMeasureAndLayout(layoutFlag)) {
895         if (!isMeasureBoundary && IsNeedRequestParentMeasure()) {
896             auto parent = GetAncestorNodeOfFrame();
897             if (parent) {
898                 parent->MarkDirtyNode(PROPERTY_UPDATE_BY_CHILD_REQUEST);
899                 return;
900             }
901         }
902         if (isLayoutDirtyMarked_) {
903             LOGD("MarkDirtyNode: isLayoutDirtyMarked is true");
904             return;
905         }
906         isLayoutDirtyMarked_ = true;
907         context->AddDirtyLayoutNode(Claim(this));
908         return;
909     }
910     layoutProperty_->CleanDirty();
911     MarkNeedRender(isRenderBoundary);
912 }
913 
IsNeedRequestParentMeasure() const914 bool FrameNode::IsNeedRequestParentMeasure() const
915 {
916     auto layoutFlag = layoutProperty_->GetPropertyChangeFlag();
917     if (layoutFlag == PROPERTY_UPDATE_BY_CHILD_REQUEST) {
918         const auto& calcLayoutConstraint = layoutProperty_->GetCalcLayoutConstraint();
919         if (calcLayoutConstraint && calcLayoutConstraint->selfIdealSize &&
920             calcLayoutConstraint->selfIdealSize->IsValid()) {
921             LOGD("make self measure boundary");
922             return false;
923         }
924     }
925     return CheckNeedRequestParentMeasure(layoutFlag);
926 }
927 
OnGenerateOneDepthVisibleFrame(std::list<RefPtr<FrameNode>> & visibleList)928 void FrameNode::OnGenerateOneDepthVisibleFrame(std::list<RefPtr<FrameNode>>& visibleList)
929 {
930     if (isActive_ && IsVisible()) {
931         visibleList.emplace_back(Claim(this));
932     }
933 }
934 
OnGenerateOneDepthAllFrame(std::list<RefPtr<FrameNode>> & allList)935 void FrameNode::OnGenerateOneDepthAllFrame(std::list<RefPtr<FrameNode>>& allList)
936 {
937     allList.emplace_back(Claim(this));
938 }
939 
IsMeasureBoundary()940 bool FrameNode::IsMeasureBoundary()
941 {
942     return isMeasureBoundary_ || pattern_->IsMeasureBoundary();
943 }
944 
IsRenderBoundary()945 bool FrameNode::IsRenderBoundary()
946 {
947     return pattern_->IsRenderBoundary();
948 }
949 
GetPattern() const950 const RefPtr<Pattern>& FrameNode::GetPattern() const
951 {
952     return pattern_;
953 }
954 
IsAtomicNode() const955 bool FrameNode::IsAtomicNode() const
956 {
957     return pattern_->IsAtomicNode();
958 }
959 
GetHitTestMode() const960 HitTestMode FrameNode::GetHitTestMode() const
961 {
962     auto gestureHub = eventHub_->GetGestureEventHub();
963     return gestureHub ? gestureHub->GetHitTestMode() : HitTestMode::HTMDEFAULT;
964 }
965 
GetTouchable() const966 bool FrameNode::GetTouchable() const
967 {
968     auto gestureHub = eventHub_->GetGestureEventHub();
969     return gestureHub ? gestureHub->GetTouchable() : true;
970 }
971 
IsResponseRegion() const972 bool FrameNode::IsResponseRegion() const
973 {
974     if (!pattern_->UsResRegion()) {
975         return false;
976     }
977     auto gestureHub = eventHub_->GetGestureEventHub();
978     return gestureHub ? gestureHub->IsResponseRegion() : false;
979 }
980 
MarkResponseRegion(bool isResponseRegion)981 void FrameNode::MarkResponseRegion(bool isResponseRegion)
982 {
983     auto gestureHub = eventHub_->GetOrCreateGestureEventHub();
984     if (gestureHub) {
985         gestureHub->MarkResponseRegion(isResponseRegion);
986     }
987 }
988 
IsOutOfTouchTestRegion(const PointF & parentLocalPoint)989 bool FrameNode::IsOutOfTouchTestRegion(const PointF& parentLocalPoint)
990 {
991     bool isInChildRegion = false;
992     auto paintRect = renderContext_->GetPaintRectWithTransform();
993     auto responseRegionList = GetResponseRegionList(paintRect);
994     auto localPoint = parentLocalPoint - paintRect.GetOffset();
995     if (!InResponseRegionList(parentLocalPoint, responseRegionList) || !GetTouchable()) {
996         if (!pattern_->UsResRegion()) {
997             LOGD("TouchTest: not use resRegion, point is out of region in %{public}s", GetTag().c_str());
998             return true;
999         }
1000         for (auto iter = frameChildren_.rbegin(); iter != frameChildren_.rend(); ++iter) {
1001             const auto& child = *iter;
1002             if (!child->IsOutOfTouchTestRegion(localPoint)) {
1003                 LOGD("TouchTest: point is out of region in %{public}s, but is in child region", GetTag().c_str());
1004                 isInChildRegion = true;
1005                 break;
1006             }
1007         }
1008         if (!isInChildRegion) {
1009             LOGD("TouchTest: point is out of region in %{public}s", GetTag().c_str());
1010             return true;
1011         }
1012     }
1013     return false;
1014 }
1015 
TouchTest(const PointF & globalPoint,const PointF & parentLocalPoint,const TouchRestrict & touchRestrict,TouchTestResult & result,int32_t touchId)1016 HitTestResult FrameNode::TouchTest(const PointF& globalPoint, const PointF& parentLocalPoint,
1017     const TouchRestrict& touchRestrict, TouchTestResult& result, int32_t touchId)
1018 {
1019     if (!isActive_ || !eventHub_->IsEnabled()) {
1020         LOGE("%{public}s is inActive, need't do touch test", GetTag().c_str());
1021         return HitTestResult::OUT_OF_REGION;
1022     }
1023     auto paintRect = renderContext_->GetPaintRectWithTransform();
1024     auto responseRegionList = GetResponseRegionList(paintRect);
1025     if (SystemProperties::GetDebugEnabled()) {
1026         LOGD("TouchTest: point is %{public}s in %{public}s, depth: %{public}d", parentLocalPoint.ToString().c_str(),
1027             GetTag().c_str(), GetDepth());
1028         for (const auto& rect : responseRegionList) {
1029             LOGD("TouchTest: responseRegionList is %{public}s, point is %{public}s", rect.ToString().c_str(),
1030                 parentLocalPoint.ToString().c_str());
1031         }
1032     }
1033 
1034     if (IsOutOfTouchTestRegion(parentLocalPoint)) {
1035         return HitTestResult::OUT_OF_REGION;
1036     }
1037 
1038     HitTestResult testResult = HitTestResult::OUT_OF_REGION;
1039     bool preventBubbling = false;
1040     // Child nodes are repackaged into gesture groups (parallel gesture groups, exclusive gesture groups, etc.) based on
1041     // the gesture attributes set by the current parent node (high and low priority, parallel gestures, etc.), the
1042     // newComingTargets is the template object to collect child nodes gesture and used by gestureHub to pack gesture
1043     // group.
1044     TouchTestResult newComingTargets;
1045     auto tmp = parentLocalPoint - paintRect.GetOffset();
1046     renderContext_->GetPointWithTransform(tmp);
1047     const auto localPoint = tmp;
1048     bool consumed = false;
1049     for (auto iter = frameChildren_.rbegin(); iter != frameChildren_.rend(); ++iter) {
1050         if (GetHitTestMode() == HitTestMode::HTMBLOCK) {
1051             break;
1052         }
1053 
1054         const auto& child = *iter;
1055         auto childHitResult = child->TouchTest(globalPoint, localPoint, touchRestrict, newComingTargets, touchId);
1056         if (childHitResult == HitTestResult::STOP_BUBBLING) {
1057             preventBubbling = true;
1058             consumed = true;
1059             if ((child->GetHitTestMode() == HitTestMode::HTMDEFAULT) ||
1060                 (child->GetHitTestMode() == HitTestMode::HTMTRANSPARENT_SELF)) {
1061                 break;
1062             }
1063         }
1064 
1065         // In normal process, the node block the brother node.
1066         if (childHitResult == HitTestResult::BUBBLING &&
1067             ((child->GetHitTestMode() == HitTestMode::HTMDEFAULT) ||
1068                 (child->GetHitTestMode() == HitTestMode::HTMTRANSPARENT_SELF))) {
1069             consumed = true;
1070             break;
1071         }
1072     }
1073 
1074     // first update HitTestResult by children status.
1075     if (consumed) {
1076         testResult = preventBubbling ? HitTestResult::STOP_BUBBLING : HitTestResult::BUBBLING;
1077         consumed = false;
1078     }
1079 
1080     if (!preventBubbling && (GetHitTestMode() != HitTestMode::HTMNONE) &&
1081         InResponseRegionList(parentLocalPoint, responseRegionList)) {
1082         consumed = true;
1083         if (touchRestrict.hitTestType == SourceType::TOUCH) {
1084             auto gestureHub = eventHub_->GetGestureEventHub();
1085             if (gestureHub) {
1086                 TouchTestResult finalResult;
1087                 const auto coordinateOffset = globalPoint - localPoint;
1088                 preventBubbling = gestureHub->ProcessTouchTestHit(
1089                     coordinateOffset, touchRestrict, newComingTargets, finalResult, touchId);
1090                 newComingTargets.swap(finalResult);
1091             }
1092         } else if (touchRestrict.hitTestType == SourceType::MOUSE) {
1093             auto mouseHub = eventHub_->GetInputEventHub();
1094             if (mouseHub) {
1095                 const auto coordinateOffset = globalPoint - localPoint;
1096                 preventBubbling = mouseHub->ProcessMouseTestHit(coordinateOffset, newComingTargets);
1097             }
1098         }
1099     }
1100 
1101     result.splice(result.end(), std::move(newComingTargets));
1102     if (touchRestrict.hitTestType == SourceType::TOUCH) {
1103         // combine into exclusive recognizer group.
1104         auto gestureHub = eventHub_->GetGestureEventHub();
1105         if (gestureHub) {
1106             gestureHub->CombineIntoExclusiveRecognizer(globalPoint, localPoint, result, touchId);
1107         }
1108     }
1109 
1110     // consumed by children and return result.
1111     if (!consumed) {
1112         return testResult;
1113     }
1114 
1115     if (testResult == HitTestResult::OUT_OF_REGION) {
1116         // consume only by self.
1117         if (preventBubbling) {
1118             return HitTestResult::STOP_BUBBLING;
1119         }
1120         return (GetHitTestMode() == HitTestMode::HTMTRANSPARENT_SELF) ? HitTestResult::SELF_TRANSPARENT
1121                                                                       : HitTestResult::BUBBLING;
1122     }
1123     // consume by self and children.
1124     return testResult;
1125 }
1126 
GetResponseRegionList(const RectF & rect)1127 std::vector<RectF> FrameNode::GetResponseRegionList(const RectF& rect)
1128 {
1129     std::vector<RectF> responseRegionList;
1130     auto gestureHub = eventHub_->GetGestureEventHub();
1131     if (!gestureHub) {
1132         responseRegionList.emplace_back(rect);
1133         return responseRegionList;
1134     }
1135 
1136     if (gestureHub->GetResponseRegion().empty()) {
1137         responseRegionList.emplace_back(rect);
1138         return responseRegionList;
1139     }
1140 
1141     auto scaleProperty = ScaleProperty::CreateScaleProperty();
1142     for (const auto& region : gestureHub->GetResponseRegion()) {
1143         auto x = ConvertToPx(region.GetOffset().GetX(), scaleProperty, rect.Width());
1144         auto y = ConvertToPx(region.GetOffset().GetY(), scaleProperty, rect.Height());
1145         auto width = ConvertToPx(region.GetWidth(), scaleProperty, rect.Width());
1146         auto height = ConvertToPx(region.GetHeight(), scaleProperty, rect.Height());
1147         RectF responseRegion(
1148             rect.GetOffset().GetX() + x.value(), rect.GetOffset().GetY() + y.value(), width.value(), height.value());
1149         responseRegionList.emplace_back(responseRegion);
1150     }
1151     return responseRegionList;
1152 }
1153 
InResponseRegionList(const PointF & parentLocalPoint,const std::vector<RectF> & responseRegionList) const1154 bool FrameNode::InResponseRegionList(const PointF& parentLocalPoint, const std::vector<RectF>& responseRegionList) const
1155 {
1156     for (const auto& rect : responseRegionList) {
1157         if (rect.IsInRegion(parentLocalPoint)) {
1158             return true;
1159         }
1160     }
1161     return false;
1162 }
1163 
MouseTest(const PointF & globalPoint,const PointF & parentLocalPoint,MouseTestResult & onMouseResult,MouseTestResult & onHoverResult,RefPtr<FrameNode> & hoverNode)1164 HitTestResult FrameNode::MouseTest(const PointF& globalPoint, const PointF& parentLocalPoint,
1165     MouseTestResult& onMouseResult, MouseTestResult& onHoverResult, RefPtr<FrameNode>& hoverNode)
1166 {
1167     // unuseable function. do nothing.
1168     return HitTestResult::BUBBLING;
1169 }
1170 
AxisTest(const PointF & globalPoint,const PointF & parentLocalPoint,AxisTestResult & onAxisResult)1171 HitTestResult FrameNode::AxisTest(
1172     const PointF& globalPoint, const PointF& parentLocalPoint, AxisTestResult& onAxisResult)
1173 {
1174     const auto& rect = renderContext_->GetPaintRectWithTransform();
1175     LOGD("AxisTest: type is %{public}s, the region is %{public}lf, %{public}lf, %{public}lf, %{public}lf",
1176         GetTag().c_str(), rect.Left(), rect.Top(), rect.Width(), rect.Height());
1177     // TODO: disableTouchEvent || disabled_ need handle
1178 
1179     // TODO: Region need change to RectList
1180     if (!rect.IsInRegion(parentLocalPoint)) {
1181         return HitTestResult::OUT_OF_REGION;
1182     }
1183 
1184     bool preventBubbling = false;
1185 
1186     const auto localPoint = parentLocalPoint - rect.GetOffset();
1187     const auto& children = GetChildren();
1188     for (auto iter = children.rbegin(); iter != children.rend(); ++iter) {
1189         auto& child = *iter;
1190         auto childHitResult = child->AxisTest(globalPoint, localPoint, onAxisResult);
1191         if (childHitResult == HitTestResult::STOP_BUBBLING) {
1192             preventBubbling = true;
1193         }
1194         // In normal process, the node block the brother node.
1195         if (childHitResult == HitTestResult::BUBBLING) {
1196             // TODO: add hit test mode judge.
1197             break;
1198         }
1199     }
1200 
1201     AxisTestResult axisResult;
1202     bool isPrevent = false;
1203     auto inputHub = eventHub_->GetInputEventHub();
1204     if (inputHub) {
1205         const auto coordinateOffset = globalPoint - localPoint;
1206         isPrevent = inputHub->ProcessAxisTestHit(coordinateOffset, axisResult);
1207     }
1208 
1209     if (!preventBubbling) {
1210         preventBubbling = isPrevent;
1211         onAxisResult.splice(onAxisResult.end(), std::move(axisResult));
1212     }
1213     if (preventBubbling) {
1214         return HitTestResult::STOP_BUBBLING;
1215     }
1216     return HitTestResult::BUBBLING;
1217 }
1218 
AnimateHoverEffect(bool isHovered) const1219 void FrameNode::AnimateHoverEffect(bool isHovered) const
1220 {
1221     auto renderContext = GetRenderContext();
1222     if (!renderContext) {
1223         return;
1224     }
1225     HoverEffectType animationType = HoverEffectType::UNKNOWN;
1226     auto inputEventHub = eventHub_->GetInputEventHub();
1227     if (inputEventHub) {
1228         animationType = inputEventHub->GetHoverEffect();
1229         if (animationType == HoverEffectType::UNKNOWN || animationType == HoverEffectType::AUTO) {
1230             animationType = inputEventHub->GetHoverEffectAuto();
1231         }
1232     }
1233     if (animationType == HoverEffectType::SCALE) {
1234         renderContext->AnimateHoverEffectScale(isHovered);
1235     } else if (animationType == HoverEffectType::BOARD) {
1236         renderContext->AnimateHoverEffectBoard(isHovered);
1237     }
1238 }
1239 
GetOrCreateFocusHub() const1240 RefPtr<FocusHub> FrameNode::GetOrCreateFocusHub() const
1241 {
1242     if (!pattern_) {
1243         return eventHub_->GetOrCreateFocusHub();
1244     }
1245     return eventHub_->GetOrCreateFocusHub(pattern_->GetFocusPattern().GetFocusType(),
1246         pattern_->GetFocusPattern().GetFocusable(), pattern_->GetFocusPattern().GetStyleType(),
1247         pattern_->GetFocusPattern().GetFocusPaintParams());
1248 }
1249 
OnWindowShow()1250 void FrameNode::OnWindowShow()
1251 {
1252     pattern_->OnWindowShow();
1253 }
1254 
OnWindowHide()1255 void FrameNode::OnWindowHide()
1256 {
1257     pattern_->OnWindowHide();
1258 }
1259 
OnWindowFocused()1260 void FrameNode::OnWindowFocused()
1261 {
1262     pattern_->OnWindowFocused();
1263 }
1264 
OnWindowUnfocused()1265 void FrameNode::OnWindowUnfocused()
1266 {
1267     pattern_->OnWindowUnfocused();
1268 }
1269 
GetOffsetRelativeToWindow() const1270 OffsetF FrameNode::GetOffsetRelativeToWindow() const
1271 {
1272     auto offset = geometryNode_->GetFrameOffset();
1273     auto parent = GetAncestorNodeOfFrame();
1274     if (renderContext_ && renderContext_->GetPositionProperty()) {
1275         if (renderContext_->GetPositionProperty()->HasPosition()) {
1276             offset.SetX(static_cast<float>(renderContext_->GetPositionProperty()->GetPosition()->GetX().Value()));
1277             offset.SetY(static_cast<float>(renderContext_->GetPositionProperty()->GetPosition()->GetY().Value()));
1278         }
1279     }
1280     while (parent) {
1281         auto parentRenderContext = parent->GetRenderContext();
1282         if (parentRenderContext && parentRenderContext->GetPositionProperty()) {
1283             if (parentRenderContext->GetPositionProperty()->HasPosition()) {
1284                 offset.AddX(
1285                     static_cast<float>(parentRenderContext->GetPositionProperty()->GetPosition()->GetX().Value()));
1286                 offset.AddY(
1287                     static_cast<float>(parentRenderContext->GetPositionProperty()->GetPosition()->GetY().Value()));
1288                 parent = parent->GetAncestorNodeOfFrame();
1289                 continue;
1290             }
1291         }
1292 
1293         offset += parent->geometryNode_->GetFrameOffset();
1294         parent = parent->GetAncestorNodeOfFrame();
1295     }
1296 
1297     return offset;
1298 }
1299 
GetTransformRectRelativeToWindow() const1300 RectF FrameNode::GetTransformRectRelativeToWindow() const
1301 {
1302     auto context = GetRenderContext();
1303     CHECK_NULL_RETURN(context, RectF());
1304     RectF rect = context->GetPaintRectWithTransform();
1305     auto offset = rect.GetOffset();
1306     auto parent = GetAncestorNodeOfFrame();
1307     while (parent) {
1308         auto parentRenderContext = parent->GetRenderContext();
1309         CHECK_NULL_RETURN(parentRenderContext, rect);
1310         auto parentScale = parentRenderContext->GetTransformScale();
1311         if (parentScale) {
1312             auto oldSize = rect.GetSize();
1313             auto newSize = SizeF(oldSize.Width() * parentScale.value().x, oldSize.Height() * parentScale.value().y);
1314             rect.SetSize(newSize);
1315 
1316             offset = OffsetF(offset.GetX() * parentScale.value().x, offset.GetY() * parentScale.value().y);
1317         }
1318 
1319         offset += parentRenderContext->GetPaintRectWithTransform().GetOffset();
1320 
1321         parent = parent->GetAncestorNodeOfFrame();
1322     }
1323     rect.SetOffset(offset);
1324     return rect;
1325 }
1326 
GetTransformRelativeOffset() const1327 OffsetF FrameNode::GetTransformRelativeOffset() const
1328 {
1329     auto context = GetRenderContext();
1330     CHECK_NULL_RETURN(context, OffsetF());
1331     auto offset = context->GetPaintRectWithTransform().GetOffset();
1332     auto parent = GetAncestorNodeOfFrame();
1333 
1334     while (parent) {
1335         auto parentRenderContext = parent->GetRenderContext();
1336         offset += parentRenderContext->GetPaintRectWithTransform().GetOffset();
1337         parent = parent->GetAncestorNodeOfFrame();
1338     }
1339 
1340     return offset;
1341 }
1342 
GetPaintRectOffset() const1343 OffsetF FrameNode::GetPaintRectOffset() const
1344 {
1345     auto context = GetRenderContext();
1346     CHECK_NULL_RETURN(context, OffsetF());
1347     auto offset = context->GetPaintRectWithTransform().GetOffset();
1348     auto parent = GetAncestorNodeOfFrame();
1349     while (parent) {
1350         auto renderContext = parent->GetRenderContext();
1351         CHECK_NULL_RETURN(renderContext, OffsetF());
1352         offset += renderContext->GetPaintRectWithTransform().GetOffset();
1353         parent = parent->GetAncestorNodeOfFrame();
1354     }
1355     return offset;
1356 }
1357 
GetPaintRectOffsetToPage() const1358 OffsetF FrameNode::GetPaintRectOffsetToPage() const
1359 {
1360     auto context = GetRenderContext();
1361     CHECK_NULL_RETURN(context, OffsetF());
1362     OffsetF offset = context->GetPaintRectWithTransform().GetOffset();
1363     auto parent = GetAncestorNodeOfFrame();
1364     while (parent && parent->GetTag() != V2::PAGE_ETS_TAG) {
1365         auto renderContext = parent->GetRenderContext();
1366         CHECK_NULL_RETURN(renderContext, OffsetF());
1367         offset += renderContext->GetPaintRectWithTransform().GetOffset();
1368         parent = parent->GetAncestorNodeOfFrame();
1369     }
1370     return (parent && parent->GetTag() == V2::PAGE_ETS_TAG) ? offset : OffsetF();
1371 }
1372 
OnNotifyMemoryLevel(int32_t level)1373 void FrameNode::OnNotifyMemoryLevel(int32_t level)
1374 {
1375     pattern_->OnNotifyMemoryLevel(level);
1376 }
1377 
GetAllDepthChildrenCount()1378 int32_t FrameNode::GetAllDepthChildrenCount()
1379 {
1380     int32_t result = 0;
1381     std::list<RefPtr<FrameNode>> children;
1382     children.emplace_back(Claim(this));
1383     while (!children.empty()) {
1384         auto& node = children.front();
1385         if (!node->IsInternal()) {
1386             result++;
1387             node->GenerateOneDepthVisibleFrame(children);
1388         }
1389         children.pop_front();
1390     }
1391     return result;
1392 }
1393 
OnAccessibilityEvent(AccessibilityEventType eventType) const1394 void FrameNode::OnAccessibilityEvent(AccessibilityEventType eventType) const
1395 {
1396     if (AceApplicationInfo::GetInstance().IsAccessibilityEnabled()) {
1397         AccessibilityEvent event;
1398         event.type = eventType;
1399         event.nodeId = GetAccessibilityId();
1400         auto pipeline = PipelineContext::GetCurrentContext();
1401         CHECK_NULL_VOID(pipeline);
1402         pipeline->SendEventToAccessibility(event);
1403     }
1404 }
1405 
AddHotZoneRect(const DimensionRect & hotZoneRect) const1406 void FrameNode::AddHotZoneRect(const DimensionRect& hotZoneRect) const
1407 {
1408     auto gestureHub = GetOrCreateGestureEventHub();
1409     gestureHub->AddResponseRect(hotZoneRect);
1410 }
1411 
RemoveLastHotZoneRect() const1412 void FrameNode::RemoveLastHotZoneRect() const
1413 {
1414     auto gestureHub = GetOrCreateGestureEventHub();
1415     gestureHub->RemoveLastResponseRect();
1416 }
1417 
1418 } // namespace OHOS::Ace::NG
1419