/src/skia/modules/skparagraph/include/Paragraph.h
Line | Count | Source (jump to first uncovered line) |
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 | 0 | virtual ~Paragraph() = default; |
25 | | |
26 | 0 | SkScalar getMaxWidth() { return fWidth; } |
27 | | |
28 | 0 | SkScalar getHeight() { return fHeight; } |
29 | | |
30 | 0 | SkScalar getMinIntrinsicWidth() { return fMinIntrinsicWidth; } |
31 | | |
32 | 0 | SkScalar getMaxIntrinsicWidth() { return fMaxIntrinsicWidth; } |
33 | | |
34 | 0 | SkScalar getAlphabeticBaseline() { return fAlphabeticBaseline; } |
35 | | |
36 | 0 | SkScalar getIdeographicBaseline() { return fIdeographicBaseline; } |
37 | | |
38 | 0 | SkScalar getLongestLine() { return fLongestLine; } |
39 | | |
40 | 0 | 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 { |
244 | | FontInfo(const SkFont& font, const TextRange textRange) |
245 | 0 | : fFont(font), fTextRange(textRange) {} |
246 | 0 | virtual ~FontInfo() = default; |
247 | 0 | 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 |