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