1 /*
2  * Copyright (c) 2022-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 #ifndef FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_RENDER_PAPAGRAPH_H
17 #define FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_RENDER_PAPAGRAPH_H
18 
19 #include "base/geometry/ng/size_t.h"
20 #include "base/image/pixel_map.h"
21 #include "base/memory/ace_type.h"
22 #include "core/components/common/layout/constants.h"
23 #include "core/components/common/properties/alignment.h"
24 #include "core/components/common/properties/text_style.h"
25 #include "core/components_ng/render/drawing_forward.h"
26 #include "core/components_ng/render/font_collection.h"
27 #include "core/components_v2/inspector/utils.h"
28 #include "core/pipeline_ng/pipeline_context.h"
29 #include "core/components/common/properties/text_layout_info.h"
30 
31 namespace OHOS::Ace::NG {
32 
33 enum RectHeightPolicy {
34     COVER_TEXT,
35     COVER_LINE
36 };
37 
38 class LeadingMarginSize {
39 public:
40     LeadingMarginSize() = default;
41     ~LeadingMarginSize() = default;
42 
LeadingMarginSize(Dimension width,Dimension height)43     LeadingMarginSize(Dimension width, Dimension height)
44     {
45         width_ = UnitFilter(width);
46         height_ = UnitFilter(height);
47     }
48 
ToString()49     std::string ToString() const
50     {
51         static const int32_t precision = 2;
52         std::stringstream ss;
53         ss << std::fixed << std::setprecision(precision);
54         ss << "width: " << width_.ToString();
55         ss << " height: " << height_.ToString();
56         return ss.str();
57     }
58 
59     bool operator==(const LeadingMarginSize& size) const
60     {
61         return NearEqual(width_, size.width_) && NearEqual(height_, size.height_);
62     }
63 
Width()64     Dimension Width() const
65     {
66         return width_;
67     }
68 
Height()69     Dimension Height() const
70     {
71         return height_;
72     }
73 
74 private:
UnitFilter(Dimension & value)75     Dimension UnitFilter(Dimension& value)
76     {
77         return value.Unit() == DimensionUnit::PERCENT ? Dimension(0.0) : value;
78     }
79 
80     Dimension width_;
81     Dimension height_;
82 };
83 
84 struct LineMetrics {
85     float ascender = 0.0f;
86     float descender = 0.0f;
87     float capHeight = 0.0f;
88     float xHeight = 0.0f;
89     float width = 0.0f;
90     float height = 0.0f;
91     float x = 0.0f;
92     float y = 0.0f;
93 };
94 
95 struct LeadingMargin {
96     LeadingMarginSize size;
97     RefPtr<PixelMap> pixmap;
98 
99     bool operator==(const LeadingMargin& other) const
100     {
101         return size == other.size && pixmap == other.pixmap;
102     }
103 
ToStringLeadingMargin104     std::string ToString() const
105     {
106         auto jsonValue = JsonUtil::Create(true);
107         JSON_STRING_PUT_STRINGABLE(jsonValue, size);
108         jsonValue->Put("pixmap",
109             pixmap ? ("size=" + std::to_string(pixmap->GetWidth()) + "," + std::to_string(pixmap->GetHeight())).c_str()
110                    : "nullptr");
111         return jsonValue->ToString();
112     }
113 
CheckLeadingMarginLeadingMargin114     bool CheckLeadingMargin(const LeadingMargin& other) const
115     {
116         auto flag = size == other.size;
117         if (pixmap && other.pixmap) {
118             flag &= pixmap->GetRawPixelMapPtr() == other.pixmap->GetRawPixelMapPtr();
119         } else if (!other.pixmap && !pixmap) {
120             flag &= true;
121         } else {
122             flag &= false;
123         }
124         return flag;
125     }
126 };
127 
128 struct ParagraphStyle {
129     TextDirection direction = TextDirection::AUTO;
130     TextAlign align = TextAlign::LEFT;
131     uint32_t maxLines = UINT32_MAX;
132     std::string fontLocale;
133     WordBreak wordBreak = WordBreak::NORMAL;
134     EllipsisMode ellipsisMode = EllipsisMode::TAIL;
135     LineBreakStrategy lineBreakStrategy = LineBreakStrategy::GREEDY;
136     TextOverflow textOverflow = TextOverflow::CLIP;
137     std::optional<LeadingMargin> leadingMargin;
138     double fontSize = 14.0;
139     Dimension lineHeight;
140     Dimension indent;
141     Alignment leadingMarginAlign = Alignment::TOP_CENTER;
142 
143     bool operator==(const ParagraphStyle others) const
144     {
145         return direction == others.direction && align == others.align && maxLines == others.maxLines &&
146                fontLocale == others.fontLocale && wordBreak == others.wordBreak &&
147                ellipsisMode == others.ellipsisMode && textOverflow == others.textOverflow &&
148                leadingMargin == others.leadingMargin && fontSize == others.fontSize && indent == others.indent;
149     }
150 
151     bool operator!=(const ParagraphStyle others) const
152     {
153         return !(*this == others);
154     }
155 
ToStringParagraphStyle156     std::string ToString() const
157     {
158         std::string result = "TextAlign: ";
159         result += V2::ConvertWrapTextAlignToString(align);
160         result += ", maxLines: ";
161         result += std::to_string(maxLines);
162         result += ", wordBreak: ";
163         result += V2::ConvertWrapWordBreakToString(wordBreak);
164         result += ", textOverflow: ";
165         result += V2::ConvertWrapTextOverflowToString(textOverflow);
166         result += ", leadingMargin: ";
167         result += leadingMargin.has_value() ? leadingMargin.value().ToString().c_str() : "nullptr";
168         result += ", fontSize: ";
169         result += std::to_string(fontSize);
170         result += ", indent: ";
171         result += indent.ToString();
172         return result;
173     }
174 };
175 
176 struct CaretMetricsF {
177     CaretMetricsF() = default;
CaretMetricsFCaretMetricsF178     CaretMetricsF(const OffsetF& position, float h)
179     {
180         offset = position;
181         height = h;
182     }
ResetCaretMetricsF183     void Reset()
184     {
185         offset.Reset();
186         height = 0.0;
187     }
188 
189     OffsetF offset;
190     // When caret is close to different glyphs, the height will be different.
191     float height = 0.0f;
ToStringCaretMetricsF192     std::string ToString() const
193     {
194         std::string result = "Offset: ";
195         result += offset.ToString();
196         result += ", height: ";
197         result += std::to_string(height);
198         return result;
199     }
200 };
201 
202 struct PositionWithAffinity {
PositionWithAffinityPositionWithAffinity203     PositionWithAffinity(size_t pos, TextAffinity affinity)
204     {
205         position_ = pos;
206         affinity_ = affinity;
207     }
208     size_t position_;
209     TextAffinity affinity_;
210 };
211 
212 // Paragraph is interface for drawing text and text paragraph.
213 class Paragraph : public virtual AceType {
214     DECLARE_ACE_TYPE(NG::Paragraph, AceType)
215 
216 public:
217     static RefPtr<Paragraph> Create(const ParagraphStyle& paraStyle, const RefPtr<FontCollection>& fontCollection);
218 
219     static RefPtr<Paragraph> Create(void* paragraph);
220     // whether the paragraph has been build
221     virtual bool IsValid() = 0;
222 
223     // interfaces for build text paragraph
224     virtual void PushStyle(const TextStyle& style) = 0;
225     virtual void PopStyle() = 0;
226     virtual void AddText(const std::u16string& text) = 0;
227     virtual void AddSymbol(const std::uint32_t& symbolId) = 0;
228     virtual int32_t AddPlaceholder(const PlaceholderRun& span) = 0;
229     virtual void Build() = 0;
230     virtual void Reset() = 0;
231 
232     // interfaces for layout
233     virtual void Layout(float width) = 0;
234     virtual float GetHeight() = 0;
235     virtual float GetTextWidth() = 0;
236     virtual size_t GetLineCount() = 0;
237     virtual float GetMaxIntrinsicWidth() = 0;
238     virtual bool DidExceedMaxLines() = 0;
239     virtual float GetLongestLine() = 0;
240     virtual float GetLongestLineWithIndent() = 0;
241     virtual float GetMaxWidth() = 0;
242     virtual float GetAlphabeticBaseline() = 0;
243     virtual float GetCharacterWidth(int32_t index) = 0;
244     virtual int32_t GetGlyphIndexByCoordinate(const Offset& offset, bool isSelectionPos = false) = 0;
GetGlyphPositionAtCoordinate(const Offset & offset)245     virtual PositionWithAffinity GetGlyphPositionAtCoordinate(const Offset& offset)
246     {
247         PositionWithAffinity finalResult(0, TextAffinity::UPSTREAM);
248         return finalResult;
249     }
250     virtual void GetRectsForRange(int32_t start, int32_t end, std::vector<RectF>& selectedRects) = 0;
251     virtual void GetTightRectsForRange(int32_t start, int32_t end, std::vector<RectF>& selectedRects) = 0;
252     virtual void GetRectsForPlaceholders(std::vector<RectF>& selectedRects) = 0;
253     virtual bool ComputeOffsetForCaretDownstream(
254         int32_t extent, CaretMetricsF& result, bool needLineHighest = true) = 0;
255     virtual bool ComputeOffsetForCaretUpstream(int32_t extent, CaretMetricsF& result, bool needLineHighest = true) = 0;
256     virtual bool CalcCaretMetricsByPosition(
257         int32_t extent, CaretMetricsF& caretCaretMetric, TextAffinity textAffinity, bool needLineHighest = true) = 0;
258     virtual bool CalcCaretMetricsByPosition(int32_t extent, CaretMetricsF& caretCaretMetric,
259         const OffsetF& lastTouchOffset, TextAffinity& textAffinity) = 0;
260     virtual void SetIndents(const std::vector<float>& indents) = 0;
261     virtual bool GetWordBoundary(int32_t offset, int32_t& start, int32_t& end) = 0;
262     virtual std::u16string GetParagraphText() = 0;
263     virtual const ParagraphStyle& GetParagraphStyle() const = 0;
264     // interfaces for pass on Symbol Animation interface
265     virtual void SetParagraphSymbolAnimation(const RefPtr<FrameNode>& frameNode) = 0;
266     // interfaces for painting
267     virtual void Paint(RSCanvas& canvas, float x, float y) = 0;
268 #ifndef USE_ROSEN_DRAWING
269     virtual void Paint(SkCanvas* skCanvas, float x, float y) = 0;
270 #endif
271     virtual LineMetrics GetLineMetricsByRectF(RectF& rect) = 0;
272     virtual TextLineMetrics GetLineMetrics(size_t lineNumber) = 0;
273     virtual RectF GetPaintRegion(float x, float y) = 0;
274     virtual bool GetLineMetricsByCoordinate(const Offset& offset, LineMetrics& lineMetrics) = 0;
275     virtual void UpdateColor(size_t from, size_t to, const Color& color) = 0;
276     virtual void TxtGetRectsForRange(int32_t start, int32_t end,
277         RectHeightStyle heightStyle, RectWidthStyle widthStyle,
278         std::vector<RectF>& selectedRects, std::vector<TextDirection>& textDirections) = 0;
279 };
280 } // namespace OHOS::Ace::NG
281 
282 #endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_RENDER_PAPAGRAPH_H
283