• 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     auto pattern = pattern_.Upgrade();
81     auto host = pattern ? pattern->GetHost() : nullptr;
82     auto contextPtr = host ? host->GetContextRefPtr() : nullptr;
83     AnimationUtils::Animate(handleOption, handlePropertyCallback, nullptr, nullptr, contextPtr);
84     SetShadowOpacity(0.0);
85     AnimationOption shadowOption;
86     shadowOption.SetDuration(TEXT_ANIMATION_DURATION);
87     shadowOption.SetCurve(Curves::SHARP);
88     shadowOption.SetDelay(0);
89     shadowOption.SetFillMode(FillMode::FORWARDS);
90     auto shadowPropertyCallback = [weakModifier = WeakClaim(this)]() {
91         auto modifier = weakModifier.Upgrade();
92         CHECK_NULL_VOID(modifier);
93         modifier->SetShadowOpacity(1.0);
94     };
95     AnimationUtils::Animate(shadowOption, shadowPropertyCallback, nullptr, nullptr, contextPtr);
96     StartFloatingSelBackgroundAnimate();
97 }
98 
StartFloatingSelBackgroundAnimate()99 void TextDragOverlayModifier::StartFloatingSelBackgroundAnimate()
100 {
101     SetBackgroundOffset(0);
102     SetSelectedBackgroundOpacity(IsHandlesShow() ? 1.0 : 0.0);
103     AnimationOption option;
104     option.SetDuration(TEXT_ANIMATION_DURATION);
105     option.SetCurve(Curves::FRICTION);
106     option.SetDelay(0);
107     auto finishFuc = [weakModifier = WeakClaim(this)]() {
108         auto modifier = weakModifier.Upgrade();
109         CHECK_NULL_VOID(modifier);
110         modifier->SetAnimateFlag(false);
111     };
112     option.SetOnFinishEvent(finishFuc);
113     option.SetFillMode(FillMode::FORWARDS);
114     auto propertyCallback = [weakModifier = WeakClaim(this)]() {
115         auto modifier = weakModifier.Upgrade();
116         CHECK_NULL_VOID(modifier);
117         modifier->SetBackgroundOffset(TEXT_DRAG_DEFAULT_OFFSET.ConvertToPx());
118         modifier->SetSelectedBackgroundOpacity(0.0);
119     };
120     auto pattern = pattern_.Upgrade();
121     auto host = pattern ? pattern->GetHost() : nullptr;
122     auto contextPtr = host ? host->GetContextRefPtr() : nullptr;
123     AnimationUtils::Animate(option, propertyCallback, option.GetOnFinishEvent(), nullptr, contextPtr);
124 }
125 
PaintShadow(const RSPath & path,const Shadow & shadow,RSCanvas & canvas)126 void TextDragOverlayModifier::PaintShadow(const RSPath& path, const Shadow& shadow, RSCanvas& canvas)
127 {
128     if (type_ == DragAnimType::DEFAULT) {
129         return;
130     }
131     RSRecordingPath rsPath;
132     rsPath.AddPath(path);
133     rsPath.Offset(shadow.GetOffset().GetX(), shadow.GetOffset().GetY());
134     Color color = shadow.GetColor();
135     color = color.BlendOpacity(shadowOpacity_->Get());
136     RSColor spotColor = ToRSColor(color);
137     RSPoint3 planeParams = { 0.0, 0.0, shadow.GetElevation() };
138     auto bounds = rsPath.GetBounds();
139     RSPoint3 lightPos = { bounds.GetLeft() + bounds.GetWidth() / 2.0, bounds.GetTop() + bounds.GetHeight() / 2.0,
140         DEFAULT_LIGHT_HEIGHT };
141     RSColor ambientColor = ToRSColor(Color(DEFAULT_AMBIENT_COLOR));
142     canvas.DrawShadowStyle(rsPath, planeParams, lightPos, DEFAULT_LIGHT_RADIUS, ambientColor, spotColor,
143         RSShadowFlags::TRANSPARENT_OCCLUDER, true);
144     canvas.Restore();
145 }
146 
PaintBackground(const RSPath & path,RSCanvas & canvas,RefPtr<TextDragPattern> textDragPattern)147 void TextDragOverlayModifier::PaintBackground(const RSPath& path, RSCanvas& canvas,
148     RefPtr<TextDragPattern> textDragPattern)
149 {
150     auto shadow = Shadow(DEFAULT_ELEVATION, {0.0, 0.0}, Color(DEFAULT_SHADOW_COLOR), ShadowStyle::OuterFloatingSM);
151     PaintShadow(path, shadow, canvas);
152     auto pattern = DynamicCast<TextDragPattern>(pattern_.Upgrade());
153     CHECK_NULL_VOID(pattern);
154     Color color = pattern->GetDragBackgroundColor();
155     RSBrush brush;
156     brush.SetColor(ToRSColor(color));
157     brush.SetAntiAlias(true);
158     canvas.AttachBrush(brush);
159     canvas.DrawPath(path);
160     canvas.DetachBrush();
161     if (type_ == DragAnimType::DEFAULT) {
162         return;
163     }
164     canvas.Save();
165     canvas.ClipPath(path, RSClipOp::INTERSECT, true);
166     std::shared_ptr<RSPath> selPath = textDragPattern->GetSelBackgroundPath();
167     RSBrush selBrush;
168     Color selColor = pattern->GetDragBackgroundColor();
169     if (type_ == DragAnimType::FLOATING) {
170         selColor = selColor.BlendOpacity(selectedBackgroundOpacity_->Get());
171     }
172     selBrush.SetColor(ToRSColor(selColor));
173     selBrush.SetAntiAlias(true);
174     canvas.AttachBrush(selBrush);
175     canvas.DrawPath(*selPath);
176     canvas.DetachBrush();
177     canvas.Restore();
178 }
179 
PaintHandle(RSCanvas & canvas,const RectF & handleRect,bool isFirstHandle,float startX,float startY)180 void TextDragOverlayModifier::PaintHandle(RSCanvas& canvas, const RectF& handleRect, bool isFirstHandle,
181     float startX, float startY)
182 {
183     if (!isAnimating_ || type_ == DragAnimType::DEFAULT) {
184         return;
185     }
186     if (NearZero(handleOpacity_->Get()) || NearZero(handleRect.Width())) {
187         return;
188     }
189     auto rectTopX = (handleRect.Right() - handleRect.Left()) / CONSTANT_DOUBLE + startX;
190     auto centerOffset = OffsetF(rectTopX, 0.0);
191     OffsetF startPoint(0.0, 0.0);
192     OffsetF endPoint(0.0, 0.0);
193     float offset = backgroundOffset_->Get();
194     auto outerHandleRadius = handleRadius_->Get();
195     auto handleRectHeight = handleRect.Height();
196     if (isFirstHandle) {
197         centerOffset.SetX(centerOffset.GetX() - offset);
198         centerOffset.SetY(startY - outerHandleRadius);
199         startPoint.SetY(outerHandleRadius - 1.0);
200         endPoint.SetY(outerHandleRadius + handleRectHeight);
201     } else {
202         centerOffset.SetX(centerOffset.GetX() + offset);
203         centerOffset.SetY(startY + outerHandleRadius);
204         startPoint.SetY(-outerHandleRadius + 1.0);
205         endPoint.SetY(-outerHandleRadius - handleRectHeight);
206     }
207     canvas.Save();
208     canvas.Translate(centerOffset.GetX(), centerOffset.GetY());
209     PaintHandleRing(canvas);
210     PaintHandleHold(canvas, handleRect, startPoint, endPoint);
211     canvas.Restore();
212 }
213 
PaintHandleRing(RSCanvas & canvas)214 void TextDragOverlayModifier::PaintHandleRing(RSCanvas& canvas)
215 {
216     RSPen pen;
217     pen.SetAntiAlias(true);
218     Color handleColor = handleColor_->Get();
219     auto handleOpacity = handleOpacity_->Get();
220     handleColor = handleColor.BlendOpacity(handleOpacity);
221     pen.SetColor(handleColor.GetValue());
222     auto outerHandleRadius = handleRadius_->Get();
223     auto innerHandleRadius = innerHandleRadius_->Get();
224     pen.SetWidth(outerHandleRadius - innerHandleRadius);
225     pen.SetCapStyle(RSPen::CapStyle::ROUND_CAP);
226     canvas.AttachPen(pen);
227     auto radius = (innerHandleRadius + outerHandleRadius) / 2;
228     RSPath ringPath;
229     ringPath.AddArc({ -radius, -radius, radius, radius }, 0, HANDLE_RING_DEGREE);
230     canvas.DrawPath(ringPath);
231     canvas.DetachPen();
232     Color innerHandleColor = innerHandleColor_->Get();
233     innerHandleColor = innerHandleColor.BlendOpacity(handleOpacity);
234     RSBrush brush;
235     brush.SetAntiAlias(true);
236     brush.SetColor(innerHandleColor.GetValue());
237     canvas.AttachBrush(brush);
238     canvas.DrawCircle(RSPoint(0.0, 0.0), innerHandleRadius);
239     canvas.DetachBrush();
240 }
241 
PaintHandleHold(RSCanvas & canvas,const RectF & handleRect,const OffsetF & startPoint,const OffsetF & endPoint)242 void TextDragOverlayModifier::PaintHandleHold(RSCanvas& canvas, const RectF& handleRect,
243     const OffsetF& startPoint, const OffsetF& endPoint)
244 {
245     Color handleColor = handleColor_->Get();
246     auto handleOpacity = handleOpacity_->Get();
247     handleColor = handleColor.BlendOpacity(handleOpacity);
248     RSPen linePen;
249     linePen.SetAntiAlias(true);
250     linePen.SetColor(handleColor.GetValue());
251     linePen.SetWidth(handleRect.Width());
252     linePen.SetCapStyle(RSPen::CapStyle::ROUND_CAP);
253     canvas.AttachPen(linePen);
254     canvas.DrawLine(RSPoint(startPoint.GetX(), startPoint.GetY()), RSPoint(endPoint.GetX(), endPoint.GetY()));
255     canvas.DetachPen();
256 }
257 
PaintSelBackground(RSCanvas & canvas,const RefPtr<TextDragPattern> & textDragPattern)258 void TextDragOverlayModifier::PaintSelBackground(RSCanvas& canvas, const RefPtr<TextDragPattern>& textDragPattern)
259 {
260     if (type_ == DragAnimType::DEFAULT || NearZero(selectedBackgroundOpacity_->Get())) {
261         return;
262     }
263     std::shared_ptr<RSPath> path = textDragPattern->GetSelBackgroundPath();
264     float offset = isAnimating_ ? backgroundOffset_->Get() : 0.0;
265     if (!NearZero(offset)) {
266         path = textDragPattern->GenerateSelBackgroundPath(offset);
267     }
268     RSBrush selBrush;
269     Color selColor = Color(selectedColor_->Get());
270     selColor = selColor.BlendOpacity(selectedBackgroundOpacity_->Get());
271     selBrush.SetColor(ToRSColor(selColor));
272     selBrush.SetAntiAlias(true);
273     canvas.AttachBrush(selBrush);
274     canvas.DrawPath(*path);
275     canvas.DetachBrush();
276 }
277 
onDraw(DrawingContext & context)278 void TextDragOverlayModifier::onDraw(DrawingContext& context)
279 {
280     auto pattern = DynamicCast<TextDragPattern>(pattern_.Upgrade());
281     CHECK_NULL_VOID(pattern);
282     auto& canvas = context.canvas;
283     std::shared_ptr<RSPath> path;
284     if (!isAnimating_) {
285         path = pattern->GetBackgroundPath();
286     } else {
287         path = pattern->GenerateBackgroundPath(backgroundOffset_->Get(), 1 - selectedBackgroundOpacity_->Get());
288     }
289     PaintBackground(*path, canvas, pattern);
290     canvas.Save();
291     canvas.ClipPath(*pattern->GetClipPath(), RSClipOp::INTERSECT, true);
292     auto paragraph = pattern->GetParagraph().Upgrade();
293     if (paragraph) {
294         paragraph->Paint(canvas, pattern->GetTextRect().GetX(), pattern->GetTextRect().GetY());
295     }
296     PaintImage(canvas);
297     canvas.Restore();
298     canvas.Save();
299     canvas.ClipPath(*path, RSClipOp::INTERSECT, true);
300     PaintSelBackground(canvas, pattern);
301     canvas.Restore();
302     if (firstHandle_ && isFirstHandleAnimated_) {
303         auto selectPosition = pattern->GetSelectPosition();
304         auto rect = firstHandle_->Get();
305         auto startY = rect.Top() - selectPosition.globalY_;
306         PaintHandle(canvas, firstHandle_->Get(), true, rect.Left() - selectPosition.globalX_, startY);
307     }
308     if (secondHandle_ && isSecondHandleAnimated_) {
309         auto selectPosition = pattern->GetSelectPosition();
310         auto rect = secondHandle_->Get();
311         auto startY = rect.Bottom() - selectPosition.globalY_;
312         PaintHandle(canvas, secondHandle_->Get(), false, rect.Left() - selectPosition.globalX_, startY);
313     }
314 }
315 
PaintImage(RSCanvas & canvas)316 void TextDragOverlayModifier::PaintImage(RSCanvas& canvas)
317 {
318     auto pattern = DynamicCast<TextDragPattern>(pattern_.Upgrade());
319     CHECK_NULL_VOID(pattern);
320     size_t index = 0;
321     auto contentOffset = pattern->GetContentOffset();
322     auto imageChildren = pattern->GetImageChildren();
323     auto rectsForPlaceholders = pattern->GetRectsForPlaceholders();
324     for (const auto& child : imageChildren) {
325         auto rect = rectsForPlaceholders.at(index);
326         auto offset = OffsetF(rect.Left(), rect.Top()) - contentOffset;
327         auto imageChild = DynamicCast<ImagePattern>(child->GetPattern());
328         if (imageChild) {
329             RectF imageRect(offset.GetX(), offset.GetY(), rect.Width(), rect.Height());
330             auto canvasImage = imageChild->GetCanvasImage();
331             CHECK_NULL_VOID(canvasImage);
332             auto pixelMapImage = DynamicCast<PixelMapImage>(canvasImage);
333             CHECK_NULL_VOID(pixelMapImage);
334             pixelMapImage->DrawRect(canvas, ToRSRect(imageRect));
335         }
336         ++index;
337     }
338 }
339 
SetBackgroundOffset(float offset)340 void TextDragOverlayModifier::SetBackgroundOffset(float offset)
341 {
342     backgroundOffset_->Set(offset);
343 }
344 
SetSelectedBackgroundOpacity(float offset)345 void TextDragOverlayModifier::SetSelectedBackgroundOpacity(float offset)
346 {
347     selectedBackgroundOpacity_->Set(offset);
348 }
349 
SetAnimateFlag(bool isAnimate)350 void TextDragOverlayModifier::SetAnimateFlag(bool isAnimate)
351 {
352     isAnimating_ = isAnimate;
353     if (!isAnimating_) {
354         auto pattern = DynamicCast<TextDragPattern>(pattern_.Upgrade());
355         CHECK_NULL_VOID(pattern);
356         pattern->ResetAnimatingParagraph();
357     }
358 }
359 } // namespace OHOS::Ace::NG
360