• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 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/text_drag/text_drag_overlay_modifier.h"
17 
18 #include <variant>
19 
20 #include "base/geometry/rect.h"
21 #include "base/utils/utils.h"
22 #include "core/components_ng/pattern/image/image_pattern.h"
23 #include "core/components_ng/pattern/text_drag/text_drag_pattern.h"
24 #include "core/components_ng/render/adapter/pixelmap_image.h"
25 #include "core/components_ng/render/drawing_prop_convertor.h"
26 #include "core/components_ng/pattern/rich_editor_drag/rich_editor_drag_info.h"
27 #include "core/components/text_overlay/text_overlay_theme.h"
28 #include "core/components/text/text_theme.h"
29 
30 namespace OHOS::Ace::NG {
31 constexpr float DEFAULT_LIGHT_HEIGHT = 600.0f;
32 constexpr uint32_t DEFAULT_AMBIENT_COLOR = 0X0A000000;
33 constexpr float DEFAULT_SHADOW_COLOR = 0x33000000;
34 constexpr float DEFAULT_LIGHT_RADIUS = 800.0f;
35 constexpr float DEFAULT_ELEVATION = 120.0f;
36 constexpr int32_t HANDLE_RING_DEGREE = 360;
37 constexpr float CONSTANT_DOUBLE = 2.0f;
38 
TextDragOverlayModifier(const WeakPtr<OHOS::Ace::NG::Pattern> & pattern)39 TextDragOverlayModifier::TextDragOverlayModifier(const WeakPtr<OHOS::Ace::NG::Pattern>& pattern) : pattern_(pattern)
40 {
41     backgroundOffset_ = AceType::MakeRefPtr<AnimatablePropertyFloat>(TEXT_DRAG_OFFSET.ConvertToPx());
42     selectedBackgroundOpacity_ = AceType::MakeRefPtr<AnimatablePropertyFloat>(0.0);
43     shadowOpacity_ = AceType::MakeRefPtr<AnimatablePropertyFloat>(0.0);
44     handleOpacity_ = AceType::MakeRefPtr<AnimatablePropertyFloat>(0.0);
45     firstHandle_ = AceType::MakeRefPtr<PropertyRectF>(RectF(0, 0, 0, 0));
46     secondHandle_ = AceType::MakeRefPtr<PropertyRectF>(RectF(0, 0, 0, 0));
47     handleRadius_ = AceType::MakeRefPtr<PropertyFloat>(0.0);
48     innerHandleRadius_ = AceType::MakeRefPtr<PropertyFloat>(0.0);
49     innerHandleColor_ = AceType::MakeRefPtr<PropertyColor>(Color::BLACK);
50     handleColor_ = AceType::MakeRefPtr<PropertyColor>(Color::BLACK);
51     selectedColor_ = AceType::MakeRefPtr<PropertyInt>(0);
52     AttachProperty(backgroundOffset_);
53     AttachProperty(selectedBackgroundOpacity_);
54     AttachProperty(shadowOpacity_);
55     AttachProperty(firstHandle_);
56     AttachProperty(secondHandle_);
57     AttachProperty(handleOpacity_);
58     AttachProperty(handleRadius_);
59     AttachProperty(innerHandleRadius_);
60     AttachProperty(innerHandleColor_);
61     AttachProperty(handleColor_);
62     AttachProperty(selectedColor_);
63 }
64 
StartFloatingAnimate()65 void TextDragOverlayModifier::StartFloatingAnimate()
66 {
67     isAnimating_ = true;
68     type_ = DragAnimType::FLOATING;
69     SetHandleOpacity(IsHandlesShow() ? 1.0 : 0.0);
70     AnimationOption handleOption;
71     handleOption.SetDuration(TEXT_FLOATING_ANIMATE_HANDLE_OPACITY_DURATION);
72     handleOption.SetCurve(Curves::LINEAR);
73     handleOption.SetDelay(0);
74     handleOption.SetFillMode(FillMode::FORWARDS);
75     auto handlePropertyCallback = [weakModifier = WeakClaim(this)]() {
76         auto modifier = weakModifier.Upgrade();
77         CHECK_NULL_VOID(modifier);
78         modifier->SetHandleOpacity(0.0);
79     };
80     AnimationUtils::Animate(handleOption, handlePropertyCallback, nullptr);
81     SetShadowOpacity(0.0);
82     AnimationOption shadowOption;
83     shadowOption.SetDuration(TEXT_ANIMATION_DURATION);
84     shadowOption.SetCurve(Curves::SHARP);
85     shadowOption.SetDelay(0);
86     shadowOption.SetFillMode(FillMode::FORWARDS);
87     auto shadowPropertyCallback = [weakModifier = WeakClaim(this)]() {
88         auto modifier = weakModifier.Upgrade();
89         CHECK_NULL_VOID(modifier);
90         modifier->SetShadowOpacity(1.0);
91     };
92     AnimationUtils::Animate(shadowOption, shadowPropertyCallback, nullptr);
93     StartFloatingSelBackgroundAnimate();
94 }
95 
StartFloatingSelBackgroundAnimate()96 void TextDragOverlayModifier::StartFloatingSelBackgroundAnimate()
97 {
98     SetBackgroundOffset(0);
99     SetSelectedBackgroundOpacity(IsHandlesShow() ? 1.0 : 0.0);
100     AnimationOption option;
101     option.SetDuration(TEXT_ANIMATION_DURATION);
102     option.SetCurve(Curves::FRICTION);
103     option.SetDelay(0);
104     auto finishFuc = [weakModifier = WeakClaim(this)]() {
105         auto modifier = weakModifier.Upgrade();
106         CHECK_NULL_VOID(modifier);
107         modifier->SetAnimateFlag(false);
108     };
109     option.SetOnFinishEvent(finishFuc);
110     option.SetFillMode(FillMode::FORWARDS);
111     auto propertyCallback = [weakModifier = WeakClaim(this)]() {
112         auto modifier = weakModifier.Upgrade();
113         CHECK_NULL_VOID(modifier);
114         modifier->SetBackgroundOffset(TEXT_DRAG_DEFAULT_OFFSET.ConvertToPx());
115         modifier->SetSelectedBackgroundOpacity(0.0);
116     };
117     AnimationUtils::Animate(option, propertyCallback, option.GetOnFinishEvent());
118 }
119 
PaintShadow(const RSPath & path,const Shadow & shadow,RSCanvas & canvas)120 void TextDragOverlayModifier::PaintShadow(const RSPath& path, const Shadow& shadow, RSCanvas& canvas)
121 {
122     if (type_ == DragAnimType::DEFAULT) {
123         return;
124     }
125     RSRecordingPath rsPath;
126     rsPath.AddPath(path);
127     rsPath.Offset(shadow.GetOffset().GetX(), shadow.GetOffset().GetY());
128     Color color = shadow.GetColor();
129     color = color.BlendOpacity(shadowOpacity_->Get());
130     RSColor spotColor = ToRSColor(color);
131     RSPoint3 planeParams = { 0.0, 0.0, shadow.GetElevation() };
132     auto bounds = rsPath.GetBounds();
133     RSPoint3 lightPos = { bounds.GetLeft() + bounds.GetWidth() / 2.0, bounds.GetTop() + bounds.GetHeight() / 2.0,
134         DEFAULT_LIGHT_HEIGHT };
135     RSColor ambientColor = ToRSColor(Color(DEFAULT_AMBIENT_COLOR));
136     canvas.DrawShadowStyle(rsPath, planeParams, lightPos, DEFAULT_LIGHT_RADIUS, ambientColor, spotColor,
137         RSShadowFlags::TRANSPARENT_OCCLUDER, true);
138     canvas.Restore();
139 }
140 
PaintBackground(const RSPath & path,RSCanvas & canvas,RefPtr<TextDragPattern> textDragPattern)141 void TextDragOverlayModifier::PaintBackground(const RSPath& path, RSCanvas& canvas,
142     RefPtr<TextDragPattern> textDragPattern)
143 {
144     auto shadow = Shadow(DEFAULT_ELEVATION, {0.0, 0.0}, Color(DEFAULT_SHADOW_COLOR), ShadowStyle::OuterFloatingSM);
145     PaintShadow(path, shadow, canvas);
146     auto pattern = DynamicCast<TextDragPattern>(pattern_.Upgrade());
147     CHECK_NULL_VOID(pattern);
148     Color color = pattern->GetDragBackgroundColor();
149     RSBrush brush;
150     brush.SetColor(ToRSColor(color));
151     brush.SetAntiAlias(true);
152     canvas.AttachBrush(brush);
153     canvas.DrawPath(path);
154     canvas.DetachBrush();
155     if (type_ == DragAnimType::DEFAULT) {
156         return;
157     }
158     canvas.Save();
159     canvas.ClipPath(path, RSClipOp::INTERSECT, true);
160     std::shared_ptr<RSPath> selPath = textDragPattern->GetSelBackgroundPath();
161     RSBrush selBrush;
162     Color selColor = Color::WHITE;
163     if (type_ == DragAnimType::FLOATING) {
164         selColor = selColor.BlendOpacity(selectedBackgroundOpacity_->Get());
165     }
166     selBrush.SetColor(ToRSColor(selColor));
167     selBrush.SetAntiAlias(true);
168     canvas.AttachBrush(selBrush);
169     canvas.DrawPath(*selPath);
170     canvas.DetachBrush();
171     canvas.Restore();
172 }
173 
PaintHandle(RSCanvas & canvas,const RectF & handleRect,bool isFirstHandle,float startX,float startY)174 void TextDragOverlayModifier::PaintHandle(RSCanvas& canvas, const RectF& handleRect, bool isFirstHandle,
175     float startX, float startY)
176 {
177     if (!isAnimating_ || type_ == DragAnimType::DEFAULT) {
178         return;
179     }
180     if (NearZero(handleOpacity_->Get()) || NearZero(handleRect.Width())) {
181         return;
182     }
183     auto rectTopX = (handleRect.Right() - handleRect.Left()) / CONSTANT_DOUBLE + startX;
184     auto centerOffset = OffsetF(rectTopX, 0.0);
185     OffsetF startPoint(0.0, 0.0);
186     OffsetF endPoint(0.0, 0.0);
187     float offset = backgroundOffset_->Get();
188     auto outerHandleRadius = handleRadius_->Get();
189     auto handleRectHeight = handleRect.Height();
190     if (isFirstHandle) {
191         centerOffset.SetX(centerOffset.GetX() - offset);
192         centerOffset.SetY(startY - outerHandleRadius);
193         startPoint.SetY(outerHandleRadius - 1.0);
194         endPoint.SetY(outerHandleRadius + handleRectHeight);
195     } else {
196         centerOffset.SetX(centerOffset.GetX() + offset);
197         centerOffset.SetY(startY + outerHandleRadius);
198         startPoint.SetY(-outerHandleRadius + 1.0);
199         endPoint.SetY(-outerHandleRadius - handleRectHeight);
200     }
201     canvas.Save();
202     canvas.Translate(centerOffset.GetX(), centerOffset.GetY());
203     PaintHandleRing(canvas);
204     PaintHandleHold(canvas, handleRect, startPoint, endPoint);
205     canvas.Restore();
206 }
207 
PaintHandleRing(RSCanvas & canvas)208 void TextDragOverlayModifier::PaintHandleRing(RSCanvas& canvas)
209 {
210     RSPen pen;
211     pen.SetAntiAlias(true);
212     Color handleColor = handleColor_->Get();
213     auto handleOpacity = handleOpacity_->Get();
214     handleColor = handleColor.BlendOpacity(handleOpacity);
215     pen.SetColor(handleColor.GetValue());
216     auto outerHandleRadius = handleRadius_->Get();
217     auto innerHandleRadius = innerHandleRadius_->Get();
218     pen.SetWidth(outerHandleRadius - innerHandleRadius);
219     pen.SetCapStyle(RSPen::CapStyle::ROUND_CAP);
220     canvas.AttachPen(pen);
221     auto radius = (innerHandleRadius + outerHandleRadius) / 2;
222     RSPath ringPath;
223     ringPath.AddArc({ -radius, -radius, radius, radius }, 0, HANDLE_RING_DEGREE);
224     canvas.DrawPath(ringPath);
225     canvas.DetachPen();
226     Color innerHandleColor = innerHandleColor_->Get();
227     innerHandleColor = innerHandleColor.BlendOpacity(handleOpacity);
228     RSBrush brush;
229     brush.SetAntiAlias(true);
230     brush.SetColor(innerHandleColor.GetValue());
231     canvas.AttachBrush(brush);
232     canvas.DrawCircle(RSPoint(0.0, 0.0), innerHandleRadius);
233     canvas.DetachBrush();
234 }
235 
PaintHandleHold(RSCanvas & canvas,const RectF & handleRect,const OffsetF & startPoint,const OffsetF & endPoint)236 void TextDragOverlayModifier::PaintHandleHold(RSCanvas& canvas, const RectF& handleRect,
237     const OffsetF& startPoint, const OffsetF& endPoint)
238 {
239     Color handleColor = handleColor_->Get();
240     auto handleOpacity = handleOpacity_->Get();
241     handleColor = handleColor.BlendOpacity(handleOpacity);
242     RSPen linePen;
243     linePen.SetAntiAlias(true);
244     linePen.SetColor(handleColor.GetValue());
245     linePen.SetWidth(handleRect.Width());
246     linePen.SetCapStyle(RSPen::CapStyle::ROUND_CAP);
247     canvas.AttachPen(linePen);
248     canvas.DrawLine(RSPoint(startPoint.GetX(), startPoint.GetY()), RSPoint(endPoint.GetX(), endPoint.GetY()));
249     canvas.DetachPen();
250 }
251 
PaintSelBackground(RSCanvas & canvas,const RefPtr<TextDragPattern> & textDragPattern)252 void TextDragOverlayModifier::PaintSelBackground(RSCanvas& canvas, const RefPtr<TextDragPattern>& textDragPattern)
253 {
254     if (type_ == DragAnimType::DEFAULT || NearZero(selectedBackgroundOpacity_->Get())) {
255         return;
256     }
257     std::shared_ptr<RSPath> path = textDragPattern->GetSelBackgroundPath();
258     float offset = isAnimating_ ? backgroundOffset_->Get() : 0.0;
259     if (!NearZero(offset)) {
260         path = textDragPattern->GenerateSelBackgroundPath(offset);
261     }
262     RSBrush selBrush;
263     Color selColor = Color(selectedColor_->Get());
264     selColor = selColor.BlendOpacity(selectedBackgroundOpacity_->Get());
265     selBrush.SetColor(ToRSColor(selColor));
266     selBrush.SetAntiAlias(true);
267     canvas.AttachBrush(selBrush);
268     canvas.DrawPath(*path);
269     canvas.DetachBrush();
270 }
271 
onDraw(DrawingContext & context)272 void TextDragOverlayModifier::onDraw(DrawingContext& context)
273 {
274     auto pattern = DynamicCast<TextDragPattern>(pattern_.Upgrade());
275     CHECK_NULL_VOID(pattern);
276     auto& canvas = context.canvas;
277     std::shared_ptr<RSPath> path;
278     if (!isAnimating_) {
279         path = pattern->GetBackgroundPath();
280     } else {
281         path = pattern->GenerateBackgroundPath(backgroundOffset_->Get(), 1 - selectedBackgroundOpacity_->Get());
282     }
283     PaintBackground(*path, canvas, pattern);
284     canvas.Save();
285     canvas.ClipPath(*pattern->GetClipPath(), RSClipOp::INTERSECT, true);
286     auto paragraph = pattern->GetParagraph().Upgrade();
287     if (paragraph) {
288         paragraph->Paint(canvas, pattern->GetTextRect().GetX(), pattern->GetTextRect().GetY());
289     }
290     PaintImage(canvas);
291     canvas.Restore();
292     canvas.Save();
293     canvas.ClipPath(*path, RSClipOp::INTERSECT, true);
294     PaintSelBackground(canvas, pattern);
295     canvas.Restore();
296     if (firstHandle_ && isFirstHandleAnimated_) {
297         auto selectPosition = pattern->GetSelectPosition();
298         auto rect = firstHandle_->Get();
299         auto startY = rect.Top() - selectPosition.globalY_;
300         PaintHandle(canvas, firstHandle_->Get(), true, rect.Left() - selectPosition.globalX_, startY);
301     }
302     if (secondHandle_ && isSecondHandleAnimated_) {
303         auto selectPosition = pattern->GetSelectPosition();
304         auto rect = secondHandle_->Get();
305         auto startY = rect.Bottom() - selectPosition.globalY_;
306         PaintHandle(canvas, secondHandle_->Get(), false, rect.Left() - selectPosition.globalX_, startY);
307     }
308 }
309 
PaintImage(RSCanvas & canvas)310 void TextDragOverlayModifier::PaintImage(RSCanvas& canvas)
311 {
312     auto pattern = DynamicCast<TextDragPattern>(pattern_.Upgrade());
313     CHECK_NULL_VOID(pattern);
314     size_t index = 0;
315     auto contentOffset = pattern->GetContentOffset();
316     auto imageChildren = pattern->GetImageChildren();
317     auto rectsForPlaceholders = pattern->GetRectsForPlaceholders();
318     for (const auto& child : imageChildren) {
319         auto rect = rectsForPlaceholders.at(index);
320         auto offset = OffsetF(rect.Left(), rect.Top()) - contentOffset;
321         auto imageChild = DynamicCast<ImagePattern>(child->GetPattern());
322         if (imageChild) {
323             RectF imageRect(offset.GetX(), offset.GetY(), rect.Width(), rect.Height());
324             auto canvasImage = imageChild->GetCanvasImage();
325             CHECK_NULL_VOID(canvasImage);
326             auto pixelMapImage = DynamicCast<PixelMapImage>(canvasImage);
327             CHECK_NULL_VOID(pixelMapImage);
328             pixelMapImage->DrawRect(canvas, ToRSRect(imageRect));
329         }
330         ++index;
331     }
332 }
333 
SetBackgroundOffset(float offset)334 void TextDragOverlayModifier::SetBackgroundOffset(float offset)
335 {
336     backgroundOffset_->Set(offset);
337 }
338 
SetSelectedBackgroundOpacity(float offset)339 void TextDragOverlayModifier::SetSelectedBackgroundOpacity(float offset)
340 {
341     selectedBackgroundOpacity_->Set(offset);
342 }
343 } // namespace OHOS::Ace::NG
344