1 /*
2  * Copyright (c) 2022 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 #ifndef FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_TEXT_OVERLAY_TEXT_OVERLAY_MANAGER_H
17 #define FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_TEXT_OVERLAY_TEXT_OVERLAY_MANAGER_H
18 
19 #ifdef USE_ROSEN_DRAWING
20 #include "core/components_ng/render/drawing_forward.h"
21 #endif
22 #include "core/components/common/layout/constants.h"
23 #include "core/components/common/properties/color.h"
24 #include "frameworks/base/geometry/offset.h"
25 #include "frameworks/base/geometry/rect.h"
26 #include "frameworks/base/memory/ace_type.h"
27 #include "frameworks/core/common/ime/text_editing_value.h"
28 #include "frameworks/core/pipeline/base/overlay_show_option.h"
29 
30 #ifndef USE_GRAPHIC_TEXT_GINE
31 namespace txt {
32 class Paragraph;
33 }
34 #else
35 namespace OHOS::Rosen {
36 class Typography;
37 }
38 #endif
39 
40 #ifndef USE_ROSEN_DRAWING
41 class SkCanvas;
42 #endif
43 
44 namespace OHOS::Ace {
45 
46 class RenderNode;
47 class Animator;
48 class StackElement;
49 class PipelineContext;
50 class TextOverlayComponent;
51 class TextOverlayManager;
52 
53 enum class CursorPositionType {
54     NONE = 0,
55     END,      // end of paragraph
56     BOUNDARY, // boundary of LTR and RTL
57     NORMAL,
58 };
59 
60 enum class DirectionStatus : uint8_t {
61     LEFT_LEFT = 0, // System direction is LTR, text direction is LTR.
62     LEFT_RIGHT,
63     RIGHT_LEFT,
64     RIGHT_RIGHT,
65 };
66 
67 // Describe where caret is and how tall visually.
68 struct CaretMetrics {
ResetCaretMetrics69     void Reset()
70     {
71         offset.Reset();
72         height = 0.0;
73     }
74 
75     Offset offset;
76     // When caret is close to different glyphs, the height will be different.
77     double height = 0.0;
ToStringCaretMetrics78     std::string ToString() const
79     {
80         std::string result = "Offset: ";
81         result += offset.ToString();
82         result += ", height: ";
83         result += std::to_string(height);
84         return result;
85     }
86 };
87 
88 class TextOverlayBase : public virtual AceType {
89     DECLARE_ACE_TYPE(TextOverlayBase, AceType);
90 
91 public:
92     TextOverlayBase() = default;
93     ~TextOverlayBase() override;
94 
SetUpdateHandlePosition(const std::function<void (const OverlayShowOption &)> & updateHandlePosition)95     void SetUpdateHandlePosition(const std::function<void(const OverlayShowOption&)>& updateHandlePosition)
96     {
97         updateHandlePosition_ = updateHandlePosition;
98     }
99 
SetUpdateHandleDiameter(const std::function<void (const double &)> & updateHandleDiameter)100     void SetUpdateHandleDiameter(const std::function<void(const double&)>& updateHandleDiameter)
101     {
102         updateHandleDiameter_ = updateHandleDiameter;
103     }
104 
SetUpdateHandleDiameterInner(const std::function<void (const double &)> & updateHandleDiameterInner)105     void SetUpdateHandleDiameterInner(const std::function<void(const double&)>& updateHandleDiameterInner)
106     {
107         updateHandleDiameterInner_ = updateHandleDiameterInner;
108     }
109 
SetOnClipRectChanged(const std::function<void (const Rect &)> & onClipRectChanged)110     void SetOnClipRectChanged(const std::function<void(const Rect&)>& onClipRectChanged)
111     {
112         onClipRectChanged_ = onClipRectChanged;
113     }
114 
IsSelectiveDevice()115     static bool IsSelectiveDevice()
116     {
117         return (SystemProperties::GetDeviceType() != DeviceType::TV &&
118                 SystemProperties::GetDeviceType() != DeviceType::WATCH);
119     }
120 
MarkIsOverlayShowed(bool isOverlayShowed)121     void MarkIsOverlayShowed(bool isOverlayShowed)
122     {
123         isOverlayShowed_ = isOverlayShowed;
124     }
125 
IsOverlayShowed()126     bool IsOverlayShowed() const
127     {
128         return isOverlayShowed_;
129     }
130 
GetSelectedRect()131     const std::vector<Rect>& GetSelectedRect() const
132     {
133         return selectedRect_;
134     }
135 
GetSelectHeight()136     double GetSelectHeight() const
137     {
138         return selectHeight_;
139     }
140 
141     void ChangeSelection(int32_t start, int32_t end);
142     void InitAnimation(const WeakPtr<PipelineContext>& pipelineContext);
143     bool GetCaretRect(int32_t extent, Rect& caretRect, double caretHeightOffset = 0.0) const;
144 #ifndef USE_ROSEN_DRAWING
145     void PaintSelection(SkCanvas* canvas, const Offset& globalOffset);
146 #else
147     void PaintSelection(RSCanvas* canvas, const Offset& globalOffset);
148 #endif
149     virtual void InitSelection(const Offset& pos, const Offset& globalOffset);
150     virtual void UpdateStartSelection(int32_t end, const Offset& pos, const Offset& globalOffset);
151     virtual void UpdateEndSelection(int32_t start, const Offset& pos, const Offset& globalOffset);
152     virtual void ShowTextOverlay(const Offset& showOffset) = 0;
153     virtual void RegisterCallbacksToOverlay() = 0;
154     virtual Offset GetHandleOffset(int32_t extend) = 0;
155     virtual std::string GetSelectedContent() const = 0;
156     RefPtr<TextOverlayManager> GetTextOverlayManager(const WeakPtr<PipelineContext>& pipelineContext);
157     bool IsSelectedText(const Offset& pos, const Offset& globalOffset);
158 
159 protected:
160 #ifndef USE_GRAPHIC_TEXT_GINE
161     std::shared_ptr<txt::Paragraph> paragraph_;
162 #else
163     std::shared_ptr<Rosen::Typography> paragraph_;
164 #endif
165     CursorPositionType cursorPositionType_ = CursorPositionType::NORMAL;
166     DirectionStatus directionStatus_ = DirectionStatus::LEFT_LEFT;
167     Offset clickOffset_;
168     // For ensuring caret is visible on screen, we take a strategy that move the whole text painting area.
169     // It maybe seems rough, and doesn't support scrolling smoothly.
170     Offset textOffsetForShowCaret_;
171     // An outline for caret. It is used by default when the actual size cannot be retrieved.
172     Rect caretProto_;
173     Rect textOverlayPaintRect_;
174     Color selectedColor_ = Color(0x330a59f7);
175     double selectHeight_ = 0.0;
176     // Default to the start of text (according to RTL/LTR).
177     TextAlign textAlign_ = TextAlign::START;
178     // RTL/LTR is inherit from parent.
179     TextDirection defaultTextDirection_ = TextDirection::INHERIT;
180     TextDirection realTextDirection_ = TextDirection::INHERIT;
181     TextAffinity textAffinity_ = TextAffinity::DOWNSTREAM;
182     TextEditingValue textValue_;
183     std::string textForDisplay_;
184     int32_t cursorPositionForShow_ = 0;
185     double cursorWidth_ = 0.0;     // The unit is px.
186     bool isOverlayShowed_ = false; // Whether overlay has showed.
187     RefPtr<Animator> animator_;
188     std::function<void(const OverlayShowOption&)> updateHandlePosition_;
189     std::function<void(const double&)> updateHandleDiameter_;
190     std::function<void(const double&)> updateHandleDiameterInner_;
191     std::function<void(const Rect&)> onClipRectChanged_;
192     RefPtr<TextOverlayComponent> textOverlay_;
193     std::vector<Rect> selectedRect_;
194 
195 private:
196     Offset MakeEmptyOffset() const;
197     double GetBoundaryOfParagraph(bool isLeftBoundary) const;
198     bool ComputeOffsetForCaretUpstream(int32_t extent, CaretMetrics& result) const;
199     bool ComputeOffsetForCaretDownstream(int32_t extent, CaretMetrics& result) const;
200     bool ComputeOffsetForCaretCloserToClick(int32_t extent, CaretMetrics& result) const;
201     DirectionStatus GetDirectionStatusOfPosition(int32_t position) const;
202     int32_t GetCursorPositionForClick(const Offset& offset, const Offset& globalOffset);
203     int32_t GetGraphemeClusterLength(int32_t extend, bool isPrefix) const;
204 };
205 
206 class PipelineContext;
207 class TextOverlayManager : public virtual AceType {
208     DECLARE_ACE_TYPE(TextOverlayManager, AceType);
209 
210 public:
211     explicit TextOverlayManager(const WeakPtr<PipelineContext>& context);
212     ~TextOverlayManager() override;
213 
SetTextOverlayBase(const WeakPtr<TextOverlayBase> & textOverlayBase)214     void SetTextOverlayBase(const WeakPtr<TextOverlayBase>& textOverlayBase)
215     {
216         textOverlayBase_ = textOverlayBase;
217     }
218 
GetTextOverlayBase()219     const RefPtr<TextOverlayBase> GetTextOverlayBase() const
220     {
221         auto textOverlayBase = textOverlayBase_.Upgrade();
222         if (!textOverlayBase) {
223             return nullptr;
224         }
225         return textOverlayBase;
226     }
227 
GetTextOverlayRect()228     const std::vector<Rect>& GetTextOverlayRect() const
229     {
230         return textOverlayRect_;
231     }
232 
AddTextOverlayRect(const Rect & textOverlayRect)233     void AddTextOverlayRect(const Rect& textOverlayRect)
234     {
235         textOverlayRect_.emplace_back(textOverlayRect);
236     }
237 
ClearTextOverlayRect()238     void ClearTextOverlayRect()
239     {
240         textOverlayRect_.clear();
241     }
242 
243     // Coordinate offset is used to calculate the local location of the touch point in the event manager.
SetCoordinateOffset(const Offset & coordinateOffset)244     void SetCoordinateOffset(const Offset& coordinateOffset)
245     {
246         coordinateOffset_ = coordinateOffset;
247     }
248 
249     // Gets the coordinate offset to calculate the local location of the touch point by manually.
GetCoordinateOffset()250     const Offset& GetCoordinateOffset() const
251     {
252         return coordinateOffset_;
253     }
254 
255     const RefPtr<RenderNode> GetTargetNode() const;
256     void PopTextOverlay();
257     void PushTextOverlayToStack(
258         const RefPtr<TextOverlayComponent>& textOverlay, const WeakPtr<PipelineContext>& context);
259 
260     void HandleCtrlC() const;
261 
262 private:
263     WeakPtr<TextOverlayBase> textOverlayBase_;
264     WeakPtr<StackElement> stackElement_;
265     WeakPtr<PipelineContext> context_;
266     std::vector<Rect> textOverlayRect_;
267     Offset coordinateOffset_;
268 };
269 
270 } // namespace OHOS::Ace
271 
272 #endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_TEXT_OVERLAY_TEXT_OVERLAY_MANAGER_H
273