xref: /aosp_15_r20/external/skia/modules/skparagraph/include/Paragraph.h (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 // Copyright 2019 Google LLC.
2 #ifndef Paragraph_DEFINED
3 #define Paragraph_DEFINED
4 
5 #include "include/core/SkPath.h"
6 #include "modules/skparagraph/include/FontCollection.h"
7 #include "modules/skparagraph/include/Metrics.h"
8 #include "modules/skparagraph/include/ParagraphStyle.h"
9 #include "modules/skparagraph/include/TextStyle.h"
10 #include <unordered_set>
11 
12 class SkCanvas;
13 
14 namespace skia {
15 namespace textlayout {
16 
17 class ParagraphPainter;
18 
19 class Paragraph {
20 
21 public:
22     Paragraph(ParagraphStyle style, sk_sp<FontCollection> fonts);
23 
24     virtual ~Paragraph() = default;
25 
getMaxWidth()26     SkScalar getMaxWidth() { return fWidth; }
27 
getHeight()28     SkScalar getHeight() { return fHeight; }
29 
getMinIntrinsicWidth()30     SkScalar getMinIntrinsicWidth() { return fMinIntrinsicWidth; }
31 
getMaxIntrinsicWidth()32     SkScalar getMaxIntrinsicWidth() { return fMaxIntrinsicWidth; }
33 
getAlphabeticBaseline()34     SkScalar getAlphabeticBaseline() { return fAlphabeticBaseline; }
35 
getIdeographicBaseline()36     SkScalar getIdeographicBaseline() { return fIdeographicBaseline; }
37 
getLongestLine()38     SkScalar getLongestLine() { return fLongestLine; }
39 
didExceedMaxLines()40     bool didExceedMaxLines() { return fExceededMaxLines; }
41 
42     virtual void layout(SkScalar width) = 0;
43 
44     virtual void paint(SkCanvas* canvas, SkScalar x, SkScalar y) = 0;
45 
46     virtual void paint(ParagraphPainter* painter, SkScalar x, SkScalar y) = 0;
47 
48     // Returns a vector of bounding boxes that enclose all text between
49     // start and end glyph indexes, including start and excluding end
50     virtual std::vector<TextBox> getRectsForRange(unsigned start,
51                                                   unsigned end,
52                                                   RectHeightStyle rectHeightStyle,
53                                                   RectWidthStyle rectWidthStyle) = 0;
54 
55     virtual std::vector<TextBox> getRectsForPlaceholders() = 0;
56 
57     // Returns the index of the glyph that corresponds to the provided coordinate,
58     // with the top left corner as the origin, and +y direction as down
59     virtual PositionWithAffinity getGlyphPositionAtCoordinate(SkScalar dx, SkScalar dy) = 0;
60 
61     // Finds the first and last glyphs that define a word containing
62     // the glyph at index offset
63     virtual SkRange<size_t> getWordBoundary(unsigned offset) = 0;
64 
65     virtual void getLineMetrics(std::vector<LineMetrics>&) = 0;
66 
67     virtual size_t lineNumber() = 0;
68 
69     virtual void markDirty() = 0;
70 
71     // This function will return the number of unresolved glyphs or
72     // -1 if not applicable (has not been shaped yet - valid case)
73     virtual int32_t unresolvedGlyphs() = 0;
74     virtual std::unordered_set<SkUnichar> unresolvedCodepoints() = 0;
75 
76     // Experimental API that allows fast way to update some of "immutable" paragraph attributes
77     // but not the text itself
78     virtual void updateTextAlign(TextAlign textAlign) = 0;
79     virtual void updateFontSize(size_t from, size_t to, SkScalar fontSize) = 0;
80     virtual void updateForegroundPaint(size_t from, size_t to, SkPaint paint) = 0;
81     virtual void updateBackgroundPaint(size_t from, size_t to, SkPaint paint) = 0;
82 
83     enum VisitorFlags {
84         kWhiteSpace_VisitorFlag = 1 << 0,
85     };
86     struct VisitorInfo {
87         const SkFont&   font;
88         SkPoint         origin;
89         SkScalar        advanceX;
90         int             count;
91         const uint16_t* glyphs;     // count values
92         const SkPoint*  positions;  // count values
93         const uint32_t* utf8Starts; // count+1 values
94         unsigned        flags;
95     };
96 
97     // lineNumber begins at 0. If info is null, this signals the end of that line.
98     using Visitor = std::function<void(int lineNumber, const VisitorInfo*)>;
99     virtual void visit(const Visitor&) = 0;
100 
101     struct ExtendedVisitorInfo {
102         const SkFont&   font;
103         SkPoint         origin;
104         SkSize          advance;
105         int             count;
106         const uint16_t* glyphs;     // count values
107         SkPoint*        positions;  // count values
108         const SkRect*   bounds;     // count values
109         const uint32_t* utf8Starts; // count+1 values
110         unsigned        flags;
111     };
112     using ExtendedVisitor = std::function<void(int lineNumber, const ExtendedVisitorInfo*)>;
113     virtual void extendedVisit(const ExtendedVisitor&) = 0;
114 
115     /* Returns path for a given line
116      *
117      * @param lineNumber  a line number
118      * @param dest        a resulting path
119      * @return            a number glyphs that could not be converted to path
120      */
121     virtual int getPath(int lineNumber, SkPath* dest) = 0;
122 
123     /* Returns path for a text blob
124      *
125      * @param textBlob    a text blob
126      * @return            a path
127      */
128     static SkPath GetPath(SkTextBlob* textBlob);
129 
130     /* Checks if a given text blob contains
131      * glyph with emoji
132      *
133      * @param textBlob    a text blob
134      * @return            true if there is such a glyph
135      */
136     virtual bool containsEmoji(SkTextBlob* textBlob) = 0;
137 
138     /* Checks if a given text blob contains colored font or bitmap
139      *
140      * @param textBlob    a text blob
141      * @return            true if there is such a glyph
142      */
143     virtual bool containsColorFontOrBitmap(SkTextBlob* textBlob) = 0;
144 
145     // Editing API
146 
147     /* Finds the line number of the line that contains the given UTF-8 index.
148     *
149     * @param index         a UTF-8 TextIndex into the paragraph
150     * @return              the line number the glyph that corresponds to the
151     *                      given codeUnitIndex is in, or -1 if the codeUnitIndex
152     *                      is out of bounds, or when the glyph is truncated or
153     *                      ellipsized away.
154     */
155     virtual int getLineNumberAt(TextIndex codeUnitIndex) const = 0;
156 
157     /* Finds the line number of the line that contains the given UTF-16 index.
158     *
159     * @param index         a UTF-16 offset into the paragraph
160     * @return              the line number the glyph that corresponds to the
161     *                      given codeUnitIndex is in, or -1 if the codeUnitIndex
162     *                      is out of bounds, or when the glyph is truncated or
163     *                      ellipsized away.
164     */
165     virtual int getLineNumberAtUTF16Offset(size_t codeUnitIndex) = 0;
166 
167     /* Returns line metrics info for the line
168      *
169      * @param lineNumber    a line number
170      * @param lineMetrics   an address to return the info (in case of null just skipped)
171      * @return              true if the line is found; false if not
172      */
173     virtual bool getLineMetricsAt(int lineNumber, LineMetrics* lineMetrics) const = 0;
174 
175     /* Returns the visible text on the line (excluding a possible ellipsis)
176      *
177      * @param lineNumber    a line number
178      * @param includeSpaces indicates if the whitespaces should be included
179      * @return              the range of the text that is shown in the line
180      */
181     virtual TextRange getActualTextRange(int lineNumber, bool includeSpaces) const = 0;
182 
183     struct GlyphClusterInfo {
184         SkRect fBounds;
185         TextRange fClusterTextRange;
186         TextDirection fGlyphClusterPosition;
187     };
188 
189     /** Finds a glyph cluster for text index
190      *
191      * @param codeUnitIndex   a text index
192      * @param glyphInfo       a glyph cluster info filled if not null
193      * @return                true if glyph cluster was found; false if not
194      */
195     virtual bool getGlyphClusterAt(TextIndex codeUnitIndex, GlyphClusterInfo* glyphInfo) = 0;
196 
197     /** Finds the closest glyph cluster for a visual text position
198      *
199      * @param dx              x coordinate
200      * @param dy              y coordinate
201      * @param glyphInfo       a glyph cluster info filled if not null
202      * @return                true if glyph cluster was found; false if not
203      *                        (which usually means the paragraph is empty)
204      */
205     virtual bool getClosestGlyphClusterAt(SkScalar dx,
206                                           SkScalar dy,
207                                           GlyphClusterInfo* glyphInfo) = 0;
208 
209     // The glyph and grapheme cluster information assoicated with a unicode
210     // codepoint in the paragraph.
211     struct GlyphInfo {
212         SkRect fGraphemeLayoutBounds;
213         TextRange fGraphemeClusterTextRange;
214         TextDirection fDirection;
215         bool fIsEllipsis;
216     };
217 
218     /** Retrives the information associated with the glyph located at the given
219      *  codeUnitIndex.
220      *
221      * @param codeUnitIndex   a UTF-16 offset into the paragraph
222      * @param glyphInfo       an optional GlyphInfo struct to hold the
223      *                        information associated with the glyph found at the
224      *                        given index
225      * @return                false only if the offset is out of bounds
226      */
227     virtual bool getGlyphInfoAtUTF16Offset(size_t codeUnitIndex, GlyphInfo* glyphInfo) = 0;
228 
229     /** Finds the information associated with the closest glyph to the given
230      *  paragraph coordinates.
231      *
232      * @param dx              x coordinate
233      * @param dy              y coordinate
234      * @param glyphInfo       an optional GlyphInfo struct to hold the
235      *                        information associated with the glyph found. The
236      *                        text indices and text ranges are described using
237      *                        UTF-16 offsets
238      * @return                true if a graphme cluster was found; false if not
239      *                        (which usually means the paragraph is empty)
240      */
241     virtual bool getClosestUTF16GlyphInfoAt(SkScalar dx, SkScalar dy, GlyphInfo* glyphInfo) = 0;
242 
243     struct FontInfo {
FontInfoFontInfo244         FontInfo(const SkFont& font, const TextRange textRange)
245                 : fFont(font), fTextRange(textRange) {}
246         virtual ~FontInfo() = default;
247         FontInfo(const FontInfo& ) = default;
248         SkFont fFont;
249         TextRange fTextRange;
250     };
251 
252     /** Returns the font that is used to shape the text at the position
253      *
254      * @param codeUnitIndex   text index
255      * @return                font info or an empty font info if the text is not found
256      */
257     virtual SkFont getFontAt(TextIndex codeUnitIndex) const = 0;
258 
259     /** Returns the font used to shape the text at the given UTF-16 offset.
260      *
261      * @param codeUnitIndex   a UTF-16 offset in the paragraph
262      * @return                font info or an empty font info if the text is not found
263      */
264     virtual SkFont getFontAtUTF16Offset(size_t codeUnitIndex) = 0;
265 
266     /** Returns the information about all the fonts used to shape the paragraph text
267      *
268      * @return                a list of fonts and text ranges
269      */
270     virtual std::vector<FontInfo> getFonts() const = 0;
271 
272 protected:
273     sk_sp<FontCollection> fFontCollection;
274     ParagraphStyle fParagraphStyle;
275 
276     // Things for Flutter
277     SkScalar fAlphabeticBaseline;
278     SkScalar fIdeographicBaseline;
279     SkScalar fHeight;
280     SkScalar fWidth;
281     SkScalar fMaxIntrinsicWidth;
282     SkScalar fMinIntrinsicWidth;
283     SkScalar fLongestLine;
284     bool fExceededMaxLines;
285 };
286 }  // namespace textlayout
287 }  // namespace skia
288 
289 #endif  // Paragraph_DEFINED
290