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