1 /*
2  * Copyright (c) 2024 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/select_overlay/magnifier_controller.h"
17 
18 #include "core/components/common/properties/color.h"
19 #include "core/components/text_field/textfield_theme.h"
20 #include "core/components_ng/pattern/select_overlay/magnifier.h"
21 #include "core/components_ng/pattern/text/text_base.h"
22 #include "core/components_ng/render/drawing_prop_convertor.h"
23 #include "core/pipeline_ng/pipeline_context.h"
24 
25 namespace OHOS::Ace::NG {
UpdateShowMagnifier(bool isShowMagnifier)26 void MagnifierController::UpdateShowMagnifier(bool isShowMagnifier)
27 {
28     isShowMagnifier_ = isShowMagnifier;
29     if (isShowMagnifier_) {
30         OpenMagnifier();
31     } else {
32         CloseMagnifier();
33     }
34 }
35 
UpdateMagnifierOffsetX(OffsetF & magnifierPaintOffset,VectorF & magnifierOffset,const OffsetF & basePaintOffset,const RefPtr<FrameNode> & host)36 bool MagnifierController::UpdateMagnifierOffsetX(OffsetF& magnifierPaintOffset, VectorF& magnifierOffset,
37     const OffsetF& basePaintOffset, const RefPtr<FrameNode>& host)
38 {
39     auto geometryNode = host->GetGeometryNode();
40     auto frameSize = geometryNode->GetFrameSize();
41     if (localOffset_.GetX() < 0 || localOffset_.GetX() > frameSize.Width()) {
42         UpdateShowMagnifier();
43         return false;
44     }
45     float left = basePaintOffset.GetX() + localOffset_.GetX() - magnifierNodeWidth_.ConvertToPx() / 2;
46     auto rootUINode = GetRootNode();
47     CHECK_NULL_RETURN(rootUINode, false);
48     auto rootGeometryNode = rootUINode->GetGeometryNode();
49     CHECK_NULL_RETURN(rootGeometryNode, false);
50     auto rootFrameSize = rootGeometryNode->GetFrameSize();
51     auto magnifierX =
52         std::clamp(left, 0.f, static_cast<float>(rootFrameSize.Width() - magnifierNodeWidth_.ConvertToPx()));
53     magnifierPaintOffset.SetX(magnifierX);
54     magnifierOffset.x = MAGNIFIER_OFFSETX.ConvertToPx();
55     return true;
56 }
57 
UpdateMagnifierOffsetY(OffsetF & magnifierPaintOffset,VectorF & magnifierOffset,const OffsetF & basePaintOffset,const RefPtr<FrameNode> & host)58 bool MagnifierController::UpdateMagnifierOffsetY(OffsetF& magnifierPaintOffset, VectorF& magnifierOffset,
59     const OffsetF& basePaintOffset, const RefPtr<FrameNode>& host)
60 {
61     auto pipeline = PipelineContext::GetCurrentContextSafely();
62     CHECK_NULL_RETURN(pipeline, false);
63     float menuHeight = magnifierNodeHeight_.ConvertToPx();
64     auto safeAreaManager = pipeline->GetSafeAreaManager();
65     auto keyboardInsert = safeAreaManager->GetKeyboardInset();
66     auto hasKeyboard = GreatNotEqual(keyboardInsert.Length(), 0.0f);
67     auto magnifierY = basePaintOffset.GetY() + localOffset_.GetY() - menuHeight / 2;
68     float offsetY_ = 0.f;
69 
70     if (hasKeyboard && basePaintOffset.GetY() + localOffset_.GetY() >= keyboardInsert.start) {
71         UpdateShowMagnifier();
72         return false;
73     }
74     auto geometryNode = host->GetGeometryNode();
75     auto frameSize = geometryNode->GetFrameSize();
76     if (localOffset_.GetY() < 0 || localOffset_.GetY() > frameSize.Height()) {
77         UpdateShowMagnifier();
78         return false;
79     }
80     auto rootUINode = GetRootNode();
81     CHECK_NULL_RETURN(rootUINode, false);
82     auto rootGeometryNode = rootUINode->GetGeometryNode();
83     CHECK_NULL_RETURN(rootGeometryNode, false);
84     auto rootFrameSize = rootGeometryNode->GetFrameSize();
85     magnifierY = std::clamp(magnifierY, 0.f, static_cast<float>(rootFrameSize.Height() - menuHeight));
86     offsetY_ = std::clamp(magnifierY, 0.f, static_cast<float>(MAGNIFIER_OFFSETY.ConvertToPx()));
87     magnifierPaintOffset.SetY(magnifierY - offsetY_);
88     magnifierOffset.y = offsetY_;
89     return true;
90 }
91 
UpdateMagnifierOffset()92 bool MagnifierController::UpdateMagnifierOffset()
93 {
94     auto pattern = pattern_.Upgrade();
95     CHECK_NULL_RETURN(pattern, false);
96     auto textBasePattern = DynamicCast<TextBase>(pattern);
97     CHECK_NULL_RETURN(textBasePattern, false);
98     auto childContext = magnifierFrameNode_->GetRenderContext();
99     CHECK_NULL_RETURN(childContext, false);
100     auto paintOffset = textBasePattern->GetTextPaintOffset();
101     auto host = pattern->GetHost();
102     CHECK_NULL_RETURN(host, false);
103     Color colorhost = ViewAbstract::GetBackgroundColor(AceType::RawPtr(host));
104     Color colorMagnifier = colorhost.ChangeAlpha(0);
105     ViewAbstract::SetBackgroundColor(AceType::RawPtr(magnifierFrameNode_), colorMagnifier);
106     OffsetF magnifierPaintOffset;
107     VectorF magnifierOffset(0.f, 0.f);
108     CHECK_NULL_RETURN(UpdateMagnifierOffsetX(magnifierPaintOffset, magnifierOffset, paintOffset, host), false);
109     CHECK_NULL_RETURN(UpdateMagnifierOffsetY(magnifierPaintOffset, magnifierOffset, paintOffset, host), false);
110     auto geometryNode = magnifierFrameNode_->GetGeometryNode();
111     geometryNode->SetFrameOffset(magnifierPaintOffset);
112     childContext->UpdatePosition(
113         OffsetT<Dimension>(Dimension(magnifierPaintOffset.GetX()), Dimension(magnifierPaintOffset.GetY())));
114     childContext->SetContentRectToFrame(RectF(magnifierPaintOffset.GetX(), magnifierPaintOffset.GetY(), 0.0f, 0.0f));
115     params_.offsetX_ = magnifierOffset.x;
116     params_.offsetY_ = magnifierOffset.y;
117     params_.factor_ = MAGNIFIER_FACTOR;
118     ViewAbstract::SetMagnifier(AceType::RawPtr(magnifierFrameNode_), params_);
119     magnifierFrameNode_->ForceSyncGeometryNode();
120     magnifierFrameNode_->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
121     return true;
122 }
123 
OpenMagnifier()124 void MagnifierController::OpenMagnifier()
125 {
126     auto rootUINode = GetRootNode();
127     CHECK_NULL_VOID(rootUINode);
128     if ((!magnifierFrameNode_) || (rootUINode->GetChildIndexById(magnifierFrameNode_->GetId()) == -1) ||
129         (colorModeChange_)) {
130         colorModeChange_ = false;
131         CreateMagnifierChildNode();
132     }
133     CHECK_NULL_VOID(magnifierFrameNode_);
134     if (rootUINode->GetChildIndexById(magnifierFrameNode_->GetId()) == -1) {
135         magnifierFrameNode_->MountToParent(rootUINode);
136     }
137     CHECK_NULL_VOID(UpdateMagnifierOffset());
138     ChangeMagnifierVisibility(true);
139     auto pattern = pattern_.Upgrade();
140     CHECK_NULL_VOID(pattern);
141     auto textBase = DynamicCast<TextBase>(pattern);
142     CHECK_NULL_VOID(textBase);
143     textBase->SetIsTextDraggable(false);
144 }
145 
GetRootNode()146 RefPtr<FrameNode> MagnifierController::GetRootNode()
147 {
148     auto pipeline = PipelineContext::GetCurrentContextSafely();
149     CHECK_NULL_RETURN(pipeline, nullptr);
150     auto rootNode = pipeline->GetRootElement();
151     CHECK_NULL_RETURN(rootNode, nullptr);
152     auto pattern = pattern_.Upgrade();
153     CHECK_NULL_RETURN(pattern, rootNode);
154     auto host = pattern->GetHost();
155     CHECK_NULL_RETURN(host, rootNode);
156     auto container = Container::Current();
157     if (container && container->IsScenceBoardWindow()) {
158         auto root = FindWindowScene(host);
159         rootNode = DynamicCast<FrameNode>(root);
160     }
161     return rootNode;
162 }
163 
FindWindowScene(const RefPtr<FrameNode> & targetNode)164 RefPtr<UINode> MagnifierController::FindWindowScene(const RefPtr<FrameNode>& targetNode)
165 {
166     CHECK_NULL_RETURN(targetNode, nullptr);
167     auto parent = targetNode->GetParent();
168     while (parent && parent->GetTag() != V2::WINDOW_SCENE_ETS_TAG) {
169         parent = parent->GetParent();
170     }
171     CHECK_NULL_RETURN(parent, nullptr);
172     return parent;
173 }
174 
ChangeMagnifierVisibility(const bool & visible)175 void MagnifierController::ChangeMagnifierVisibility(const bool& visible)
176 {
177     CHECK_NULL_VOID(visible_ != visible);
178     visible_ = visible;
179     double lastOpacity = visible ? 1.0 : 0.0;
180     auto callBack = [weak = WeakClaim(this), lastOpacity]() {
181         auto controller = weak.Upgrade();
182         CHECK_NULL_VOID(controller);
183         auto hostNode = controller->GetMagnifierNode();
184         CHECK_NULL_VOID(hostNode);
185         ViewAbstract::SetOpacity(AceType::RawPtr(hostNode), lastOpacity);
186         hostNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
187     };
188     auto parms = params_;
189     parms.factor_ = 0.f;
190     auto endCallBack = [weak = WeakClaim(this), parms]() {
191         auto controller = weak.Upgrade();
192         CHECK_NULL_VOID(controller);
193         auto hostNode = controller->GetMagnifierNode();
194         CHECK_NULL_VOID(hostNode);
195         ViewAbstract::SetMagnifier(AceType::RawPtr(hostNode), parms);
196         auto parentNode = hostNode->GetParent();
197         CHECK_NULL_VOID(parentNode);
198         parentNode->RemoveChild(hostNode);
199         parentNode->MarkNeedSyncRenderTree();
200         parentNode->RebuildRenderContextTree();
201     };
202     AnimationOption option;
203     option.SetCurve(Curves::FRICTION);
204     option.SetDuration(ANIMATION_DURATION_150);
205     if (removeFrameNode_) {
206         AnimationUtils::Animate(option, callBack, endCallBack);
207     } else {
208         AnimationUtils::Animate(option, callBack);
209     }
210 }
211 
RemoveMagnifierFrameNode()212 void MagnifierController::RemoveMagnifierFrameNode()
213 {
214     magnifierNodeExist_ = false;
215     if (isShowMagnifier_) {
216         removeFrameNode_ = true;
217         UpdateShowMagnifier();
218     } else {
219         CHECK_NULL_VOID(magnifierFrameNode_);
220         auto parentNode = magnifierFrameNode_->GetParent();
221         CHECK_NULL_VOID(parentNode);
222         parentNode->RemoveChild(magnifierFrameNode_);
223         parentNode->MarkNeedSyncRenderTree();
224         parentNode->RebuildRenderContextTree();
225     }
226     removeFrameNode_ = false;
227 }
228 
CloseMagnifier()229 void MagnifierController::CloseMagnifier()
230 {
231     CHECK_NULL_VOID(magnifierFrameNode_);
232     ViewAbstract::ReSetMagnifier(AceType::RawPtr(magnifierFrameNode_));
233     ChangeMagnifierVisibility(false);
234     magnifierFrameNode_->ForceSyncGeometryNode();
235     magnifierFrameNode_->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
236 }
237 
InitMagnifierParams()238 void MagnifierController::InitMagnifierParams()
239 {
240     params_.factor_ = MAGNIFIER_FACTOR;
241     params_.width_ = MAGNIFIER_WIDTH.ConvertToPx();
242     params_.height_ = MAGNIFIER_HEIGHT.ConvertToPx();
243     params_.borderWidth_ = MAGNIFIER_BORDERWIDTH.ConvertToPx();
244     params_.cornerRadius_ = MAGNIFIER_CORNERRADIUS.ConvertToPx();
245     params_.shadowOffsetX_ = MAGNIFIER_SHADOWOFFSETX.ConvertToPx();
246     params_.shadowOffsetY_ = MAGNIFIER_SHADOWOFFSETY.ConvertToPx();
247     params_.shadowSize_ = MAGNIFIER_SHADOWSIZE.ConvertToPx();
248     params_.shadowStrength_ = MAGNIFIER_SHADOWSTRENGTH;
249 
250     auto pipeline = PipelineBase::GetCurrentContextSafely();
251     CHECK_NULL_VOID(pipeline);
252     auto textFieldTheme = pipeline->GetTheme<TextFieldTheme>();
253     CHECK_NULL_VOID(textFieldTheme);
254     uint32_t gradientMaskColor1 = textFieldTheme->GetGlassMaskPrimaryColor().GetValue();
255     uint32_t gradientMaskColor2 = textFieldTheme->GetGlassMaskSecondaryColor().GetValue();
256 
257     Color outlineColor1 = textFieldTheme->GetGlassOutlinePrimaryColor();
258     Color outlineColor2 = textFieldTheme->GetGlassOutlineSecondaryColor();
259     if (SystemProperties::GetColorMode() == ColorMode::DARK) {
260         outlineColor1 = outlineColor1.ChangeAlpha(0xCC); // 0xCC: 80%
261         outlineColor2 = outlineColor2.ChangeAlpha(0xCC); // 0xCC: 80%
262     } else {
263         outlineColor1 = outlineColor1.ChangeAlpha(0x7F); // 0x7F: 50%
264         outlineColor2 = outlineColor2.ChangeAlpha(0x7F); // 0x7F: 50%
265     }
266     uint32_t outerContourColor1 = outlineColor1.GetValue();
267     uint32_t outerContourColor2 = outlineColor2.GetValue();
268     params_.gradientMaskColor1_ = ArgbToRgba(gradientMaskColor1);
269     params_.gradientMaskColor2_ = ArgbToRgba(gradientMaskColor2);
270     params_.outerContourColor1_ = ArgbToRgba(outerContourColor1);
271     params_.outerContourColor2_ = ArgbToRgba(outerContourColor2);
272     magnifierNodeWidth_ =
273         MAGNIFIER_WIDTH + MAGNIFIER_SHADOWOFFSETX + MAGNIFIER_SHADOWSIZE * 1.5; // 1.5: Compute the node width
274     magnifierNodeHeight_ =
275         MAGNIFIER_HEIGHT + MAGNIFIER_SHADOWOFFSETY + MAGNIFIER_SHADOWSIZE * 1.5; // 1.5: Compute the node height
276 }
277 
ArgbToRgba(const uint32_t & color)278 uint32_t MagnifierController::ArgbToRgba(const uint32_t& color)
279 {
280     uint8_t a = (color >> 24) & 0xff; // 24: get alpha
281     uint8_t r = (color >> 16) & 0xff; // 16: get red
282     uint8_t g = (color >> 8) & 0xff; // 8: get green
283     uint8_t b = color & 0xff; // get blue
284     return (r << 24) | (g << 16) | (b << 8) | a; // 24: red, 16: green, 8: blue
285 }
286 
CreateMagnifierChildNode()287 void MagnifierController::CreateMagnifierChildNode()
288 {
289     auto pattern = pattern_.Upgrade();
290     CHECK_NULL_VOID(pattern);
291     auto textBasePattern = DynamicCast<TextBase>(pattern);
292     CHECK_NULL_VOID(textBasePattern);
293 
294     auto nodeId = ElementRegister::GetInstance()->MakeUniqueId();
295     ACE_SCOPED_TRACE("Create[%s][self:%d]", V2::TEXTINPUT_ETS_TAG, nodeId);
296     auto childNode = FrameNode::GetOrCreateFrameNode(
297         V2::TEXTINPUT_ETS_TAG, nodeId, []() { return AceType::MakeRefPtr<Pattern>(); });
298     CHECK_NULL_VOID(childNode);
299     InitMagnifierParams();
300     ViewAbstract::SetWidth(AceType::RawPtr(childNode), CalcLength(magnifierNodeWidth_));
301     ViewAbstract::SetHeight(AceType::RawPtr(childNode), CalcLength(magnifierNodeHeight_));
302     ViewAbstract::SetOpacity(AceType::RawPtr(childNode), 0.0);
303     auto layoutProperty = AceType::DynamicCast<LayoutProperty>(childNode->GetLayoutProperty());
304     CHECK_NULL_VOID(layoutProperty);
305     layoutProperty->UpdateVisibility(VisibleType::VISIBLE);
306     childNode->ForceSyncGeometryNode();
307     childNode->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
308     magnifierFrameNode_ = childNode;
309     visible_ = false;
310 }
311 } // namespace OHOS::Ace::NG
312