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