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