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