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/pattern/form/form_node.h"
17 
18 #include "base/log/log.h"
19 #include "base/utils/utils.h"
20 #include "core/components/form/sub_container.h"
21 #include "core/components_ng/pattern/form/form_pattern.h"
22 #include "core/pipeline/pipeline_context.h"
23 #include "core/pipeline_ng/pipeline_context.h"
24 #include "pointer_event.h"
25 
26 namespace OHOS::Ace::NG {
27 namespace {
28 const std::unordered_map<SourceType, int32_t> SOURCE_TYPE_MAP = {
29     { SourceType::TOUCH, MMI::PointerEvent::SOURCE_TYPE_TOUCHSCREEN },
30     { SourceType::TOUCH_PAD, MMI::PointerEvent::SOURCE_TYPE_TOUCHPAD },
31     { SourceType::MOUSE, MMI::PointerEvent::SOURCE_TYPE_TOUCHSCREEN },
32 };
33 
34 const std::unordered_map<TouchType, int32_t> TOUCH_TYPE_MAP = {
35     { TouchType::CANCEL, MMI::PointerEvent::POINTER_ACTION_CANCEL },
36     { TouchType::DOWN, MMI::PointerEvent::POINTER_ACTION_DOWN },
37     { TouchType::MOVE, MMI::PointerEvent::POINTER_ACTION_MOVE },
38     { TouchType::UP, MMI::PointerEvent::POINTER_ACTION_UP },
39     { TouchType::PULL_DOWN, MMI::PointerEvent::POINTER_ACTION_PULL_DOWN },
40     { TouchType::PULL_MOVE, MMI::PointerEvent::POINTER_ACTION_PULL_MOVE },
41     { TouchType::PULL_UP, MMI::PointerEvent::POINTER_ACTION_PULL_UP },
42     { TouchType::PULL_IN_WINDOW, MMI::PointerEvent::POINTER_ACTION_PULL_IN_WINDOW },
43     { TouchType::PULL_OUT_WINDOW, MMI::PointerEvent::POINTER_ACTION_PULL_OUT_WINDOW },
44 };
45 
ConvertPointerEvent(const OffsetF offsetF,const TouchEvent & point,const WeakPtr<FrameNode> & node)46 std::shared_ptr<MMI::PointerEvent> ConvertPointerEvent(const OffsetF offsetF, const TouchEvent& point,
47     const WeakPtr<FrameNode>& node)
48 {
49     std::shared_ptr<MMI::PointerEvent> pointerEvent = MMI::PointerEvent::Create();
50     if (pointerEvent == nullptr) {
51         TAG_LOGE(AceLogTag::ACE_FORM, "pointerEvent is nullptr");
52         return nullptr;
53     }
54 
55     OHOS::MMI::PointerEvent::PointerItem item;
56     PointF transformPoint(point.x, point.y);
57     NGGestureRecognizer::Transform(transformPoint, node);
58     item.SetWindowX(static_cast<int32_t>(transformPoint.GetX()));
59     item.SetWindowY(static_cast<int32_t>(transformPoint.GetY()));
60     item.SetWindowXPos(transformPoint.GetX());
61     item.SetWindowYPos(transformPoint.GetY());
62     item.SetDisplayX(static_cast<int32_t>(point.screenX));
63     item.SetDisplayY(static_cast<int32_t>(point.screenY));
64     item.SetPointerId(point.id);
65     pointerEvent->AddPointerItem(item);
66 
67     int32_t sourceType = MMI::PointerEvent::SOURCE_TYPE_UNKNOWN;
68     auto sourceTypeIter = SOURCE_TYPE_MAP.find(point.sourceType);
69     if (sourceTypeIter != SOURCE_TYPE_MAP.end()) {
70         sourceType = sourceTypeIter->second;
71     }
72     pointerEvent->SetSourceType(sourceType);
73 
74     int32_t pointerAction = OHOS::MMI::PointerEvent::POINTER_ACTION_UNKNOWN;
75     auto pointerActionIter = TOUCH_TYPE_MAP.find(point.type);
76     if (pointerActionIter != TOUCH_TYPE_MAP.end()) {
77         pointerAction = pointerActionIter->second;
78     }
79     pointerEvent->SetPointerAction(pointerAction);
80     pointerEvent->SetPointerId(point.id);
81     return pointerEvent;
82 }
83 
84 class FormAccessibilityChildTreeCallback : public AccessibilityChildTreeCallback {
85 public:
FormAccessibilityChildTreeCallback(const WeakPtr<FormNode> & weakFormNode,int64_t accessibilityId)86     FormAccessibilityChildTreeCallback(const WeakPtr<FormNode> &weakFormNode, int64_t accessibilityId)
87         : AccessibilityChildTreeCallback(accessibilityId), weakFormNode_(weakFormNode)
88     {}
89 
90     ~FormAccessibilityChildTreeCallback() override = default;
91 
OnRegister(uint32_t windowId,int32_t treeId)92     bool OnRegister(uint32_t windowId, int32_t treeId) override
93     {
94         auto formNode = weakFormNode_.Upgrade();
95         if (formNode == nullptr) {
96             return false;
97         }
98         if (isReg_) {
99             return true;
100         }
101         formNode->OnAccessibilityChildTreeRegister(windowId, treeId);
102         isReg_ = true;
103         return true;
104     }
105 
OnDeregister()106     bool OnDeregister() override
107     {
108         auto formNode = weakFormNode_.Upgrade();
109         if (formNode == nullptr) {
110             return false;
111         }
112         if (!isReg_) {
113             return true;
114         }
115         formNode->OnAccessibilityChildTreeDeregister();
116         isReg_ = false;
117         return true;
118     }
119 
OnSetChildTree(int32_t childWindowId,int32_t childTreeId)120     bool OnSetChildTree(int32_t childWindowId, int32_t childTreeId) override
121     {
122         auto formNode = weakFormNode_.Upgrade();
123         if (formNode == nullptr) {
124             return false;
125         }
126         formNode->OnSetAccessibilityChildTree(childWindowId, childTreeId);
127         return true;
128     }
129 
OnDumpChildInfo(const std::vector<std::string> & params,std::vector<std::string> & info)130     bool OnDumpChildInfo(const std::vector<std::string>& params, std::vector<std::string>& info) override
131     {
132         auto formNode = weakFormNode_.Upgrade();
133         if (formNode == nullptr) {
134             return false;
135         }
136         formNode->OnAccessibilityDumpChildInfo(params, info);
137         return true;
138     }
139 
OnClearRegisterFlag()140     void OnClearRegisterFlag() override
141     {
142         auto formNode = weakFormNode_.Upgrade();
143         if (formNode == nullptr) {
144             return;
145         }
146         isReg_ = false;
147     }
148 private:
149     bool isReg_ = false;
150     WeakPtr<FormNode> weakFormNode_;
151 };
152 }
153 
~FormNode()154 FormNode::~FormNode()
155 {
156     auto pipeline = PipelineContext::GetCurrentContext();
157     CHECK_NULL_VOID(pipeline);
158     auto accessibilityManager = pipeline->GetAccessibilityManager();
159     CHECK_NULL_VOID(accessibilityManager);
160     accessibilityManager->DeregisterAccessibilityChildTreeCallback(GetAccessibilityId());
161 }
162 
TouchTest(const PointF & globalPoint,const PointF & parentLocalPoint,const PointF & parentRevertPoint,TouchRestrict & touchRestrict,TouchTestResult & result,int32_t touchId,ResponseLinkResult & responseLinkResult,bool isDispatch)163 HitTestResult FormNode::TouchTest(const PointF& globalPoint, const PointF& parentLocalPoint,
164     const PointF& parentRevertPoint, TouchRestrict& touchRestrict, TouchTestResult& result, int32_t touchId,
165     ResponseLinkResult& responseLinkResult, bool isDispatch)
166 {
167     // The mousetest has been merged into touchtest.
168     // FormComponent does not support some mouse event(eg. Hover, HoverAnimation..).
169     // Mouse event like LEFT_BUTTON, RELEASE use touchevent to dispatch, so they work well on FormComponent
170     if (touchRestrict.hitTestType == SourceType::MOUSE) {
171         return HitTestResult::OUT_OF_REGION;
172     }
173 
174     auto testResult = FrameNode::TouchTest(
175         globalPoint, parentLocalPoint, parentRevertPoint, touchRestrict, result, touchId, responseLinkResult);
176     if (testResult == HitTestResult::OUT_OF_REGION) {
177         return HitTestResult::OUT_OF_REGION;
178     }
179 
180     auto context = GetContext();
181     CHECK_NULL_RETURN(context, testResult);
182 
183     auto selfGlobalOffset = GetTransformRelativeOffset();
184     auto pattern = GetPattern<FormPattern>();
185     CHECK_NULL_RETURN(pattern, testResult);
186     auto subContainer = pattern->GetSubContainer();
187     CHECK_NULL_RETURN(subContainer, testResult);
188 
189     // Send TouchEvent Info to FormRenderService when Provider is ArkTS Card.
190     if (subContainer->GetUISyntaxType() == FrontendType::ETS_CARD) {
191         auto callback = [weak = WeakClaim(this)](const TouchEvent& touchEvent, SerializedGesture& serializedGesture) {
192             auto formNode = weak.Upgrade();
193             CHECK_NULL_VOID(formNode);
194             formNode->DispatchPointerEvent(touchEvent, serializedGesture);
195         };
196         context->AddEtsCardTouchEventCallback(touchRestrict.touchEvent.id, callback);
197         return testResult;
198     }
199     auto subContext = DynamicCast<OHOS::Ace::PipelineBase>(subContainer->GetPipelineContext());
200     CHECK_NULL_RETURN(subContext, testResult);
201     subContext->SetPluginEventOffset(Offset(selfGlobalOffset.GetX(), selfGlobalOffset.GetY()));
202     context->SetTouchPipeline(WeakPtr<PipelineBase>(subContext));
203 
204     return testResult;
205 }
206 
DispatchPointerEvent(const TouchEvent & touchEvent,SerializedGesture & serializedGesture)207 void FormNode::DispatchPointerEvent(const TouchEvent& touchEvent,
208     SerializedGesture& serializedGesture)
209 {
210     auto pattern = GetPattern<FormPattern>();
211     CHECK_NULL_VOID(pattern);
212     auto selfGlobalOffset = GetFormOffset();
213     auto pointerEvent = ConvertPointerEvent(selfGlobalOffset, touchEvent, WeakClaim(this));
214     pattern->DispatchPointerEvent(pointerEvent, serializedGesture);
215 }
216 
GetFormOffset() const217 OffsetF FormNode::GetFormOffset() const
218 {
219     auto context = GetRenderContext();
220     CHECK_NULL_RETURN(context, OffsetF());
221     auto offset = context->GetPaintRectWithoutTransform().GetOffset();
222     auto parent = GetAncestorNodeOfFrame();
223 
224     while (parent) {
225         auto parentRenderContext = parent->GetRenderContext();
226         offset += parentRenderContext->GetPaintRectWithTransform().GetOffset();
227         parent = parent->GetAncestorNodeOfFrame();
228     }
229 
230     return offset;
231 }
232 
GetOrCreateFormNode(const std::string & tag,int32_t nodeId,const std::function<RefPtr<Pattern> (void)> & patternCreator)233 RefPtr<FormNode> FormNode::GetOrCreateFormNode(
234     const std::string& tag, int32_t nodeId, const std::function<RefPtr<Pattern>(void)>& patternCreator)
235 {
236     auto formNode = ElementRegister::GetInstance()->GetSpecificItemById<FormNode>(nodeId);
237     if (formNode) {
238         if (formNode->GetTag() == tag) {
239             return formNode;
240         }
241         ElementRegister::GetInstance()->RemoveItemSilently(nodeId);
242         auto parent = formNode->GetParent();
243         if (parent) {
244             parent->RemoveChild(formNode);
245         }
246     }
247 
248     auto pattern = patternCreator ? patternCreator() : AceType::MakeRefPtr<Pattern>();
249     formNode = AceType::MakeRefPtr<FormNode>(tag, nodeId, pattern, false);
250     formNode->InitializePatternAndContext();
251     formNode->InitializeFormAccessibility();
252     ElementRegister::GetInstance()->AddUINode(formNode);
253     return formNode;
254 }
255 
OnDetachFromMainTree(bool recursive,PipelineContext * context)256 void FormNode::OnDetachFromMainTree(bool recursive, PipelineContext* context)
257 {
258     auto eventHub = GetEventHub<FormEventHub>();
259     eventHub->FireOnCache();
260     FrameNode::OnDetachFromMainTree(recursive, context);
261 }
262 
InitializeFormAccessibility()263 void FormNode::InitializeFormAccessibility()
264 {
265     auto pipeline = PipelineContext::GetCurrentContext();
266     CHECK_NULL_VOID(pipeline);
267     auto accessibilityManager = pipeline->GetAccessibilityManager();
268     CHECK_NULL_VOID(accessibilityManager);
269     accessibilityChildTreeCallback_ = std::make_shared<FormAccessibilityChildTreeCallback>(
270         WeakClaim(this), GetAccessibilityId());
271     accessibilityManager->RegisterAccessibilityChildTreeCallback(GetAccessibilityId(), accessibilityChildTreeCallback_);
272 
273 }
274 
NotifyAccessibilityChildTreeRegister()275 void FormNode::NotifyAccessibilityChildTreeRegister()
276 {
277     auto pipeline = PipelineContext::GetCurrentContext();
278     CHECK_NULL_VOID(pipeline);
279     auto accessibilityManager = pipeline->GetAccessibilityManager();
280     CHECK_NULL_VOID(accessibilityManager);
281     if (accessibilityManager->IsRegister()) {
282         accessibilityChildTreeCallback_->OnRegister(pipeline->GetWindowId(), 0);
283     }
284 }
285 
OnAccessibilityChildTreeRegister(uint32_t windowId,int32_t treeId)286 void FormNode::OnAccessibilityChildTreeRegister(uint32_t windowId, int32_t treeId)
287 {
288     auto accessibilityId = GetAccessibilityId();
289     auto pattern = GetPattern<FormPattern>();
290     if (pattern == nullptr) {
291         TAG_LOGE(AceLogTag::ACE_FORM, "pattern is null");
292         return;
293     }
294     pattern->OnAccessibilityChildTreeRegister(windowId, treeId, accessibilityId);
295 }
296 
OnAccessibilityChildTreeDeregister()297 void FormNode::OnAccessibilityChildTreeDeregister()
298 {
299     auto pattern = GetPattern<FormPattern>();
300     CHECK_NULL_VOID(pattern);
301     pattern->OnAccessibilityChildTreeDeregister();
302 }
303 
OnSetAccessibilityChildTree(int32_t childWindowId,int32_t childTreeId)304 void FormNode::OnSetAccessibilityChildTree(int32_t childWindowId, int32_t childTreeId)
305 {
306     auto accessibilityProperty = GetAccessibilityProperty<AccessibilityProperty>();
307     if (accessibilityProperty != nullptr) {
308         accessibilityProperty->SetChildWindowId(childWindowId);
309         accessibilityProperty->SetChildTreeId(childTreeId);
310     }
311 }
312 
OnAccessibilityDumpChildInfo(const std::vector<std::string> & params,std::vector<std::string> & info)313 void FormNode::OnAccessibilityDumpChildInfo(const std::vector<std::string>& params, std::vector<std::string>& info)
314 {
315     auto pattern = GetPattern<FormPattern>();
316     if (pattern == nullptr) {
317         TAG_LOGE(AceLogTag::ACE_FORM, "pattern is null");
318         return;
319     }
320     pattern->OnAccessibilityDumpChildInfo(params, info);
321 }
322 
ClearAccessibilityChildTreeRegisterFlag()323 void FormNode::ClearAccessibilityChildTreeRegisterFlag()
324 {
325     CHECK_NULL_VOID(accessibilityChildTreeCallback_);
326     accessibilityChildTreeCallback_->OnClearRegisterFlag();
327 }
328 } // namespace OHOS::Ace::NG
329