• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2019 Google LLC.
2 #ifndef ParagraphImpl_DEFINED
3 #define ParagraphImpl_DEFINED
4 
5 #include "include/core/SkFont.h"
6 #include "include/core/SkPaint.h"
7 #include "include/core/SkPicture.h"
8 #include "include/core/SkPoint.h"
9 #include "include/core/SkRect.h"
10 #include "include/core/SkRefCnt.h"
11 #include "include/core/SkScalar.h"
12 #include "include/core/SkSpan.h"
13 #include "include/core/SkString.h"
14 #include "include/core/SkTypes.h"
15 #include "include/private/base/SkOnce.h"
16 #include "include/private/base/SkTArray.h"
17 #include "include/private/base/SkTemplates.h"
18 #include "modules/skparagraph/include/DartTypes.h"
19 #include "modules/skparagraph/include/FontCollection.h"
20 #include "modules/skparagraph/include/Paragraph.h"
21 #include "modules/skparagraph/include/ParagraphCache.h"
22 #include "modules/skparagraph/include/ParagraphStyle.h"
23 #ifdef ENABLE_TEXT_ENHANCE
24 #include "modules/skparagraph/include/TextLineBase.h"
25 #endif
26 #include "modules/skparagraph/include/TextShadow.h"
27 #include "modules/skparagraph/include/TextStyle.h"
28 #include "modules/skparagraph/src/Run.h"
29 #include "modules/skparagraph/src/TextLine.h"
30 #include "modules/skunicode/include/SkUnicode.h"
31 #include "src/base/SkBitmaskEnum.h"
32 #include "src/core/SkTHash.h"
33 
34 #include <memory>
35 #include <string>
36 #include <vector>
37 
38 class SkCanvas;
39 
40 namespace skia {
41 namespace textlayout {
42 
43 class LineMetrics;
44 class TextLine;
45 
46 template <typename T> bool operator==(const SkSpan<T>& a, const SkSpan<T>& b) {
47     return a.size() == b.size() && a.begin() == b.begin();
48 }
49 
50 template <typename T> bool operator<=(const SkSpan<T>& a, const SkSpan<T>& b) {
51     return a.begin() >= b.begin() && a.end() <= b.end();
52 }
53 
54 template <typename TStyle>
55 struct StyleBlock {
StyleBlockStyleBlock56     StyleBlock() : fRange(EMPTY_RANGE), fStyle() { }
StyleBlockStyleBlock57     StyleBlock(size_t start, size_t end, const TStyle& style) : fRange(start, end), fStyle(style) {}
StyleBlockStyleBlock58     StyleBlock(TextRange textRange, const TStyle& style) : fRange(textRange), fStyle(style) {}
addStyleBlock59     void add(TextRange tail) {
60         SkASSERT(fRange.end == tail.start);
61         fRange = TextRange(fRange.start, fRange.start + fRange.width() + tail.width());
62     }
63     TextRange fRange;
64     TStyle fStyle;
65 };
66 
67 struct ResolvedFontDescriptor {
68 #ifdef ENABLE_TEXT_ENHANCE
ResolvedFontDescriptorResolvedFontDescriptor69     ResolvedFontDescriptor(TextIndex index, RSFont font)
70         : fFont(font), fTextStart(index) { }
71     RSFont fFont;
72 #else
73     ResolvedFontDescriptor(TextIndex index, SkFont font)
74             : fFont(std::move(font)), fTextStart(index) {}
75     SkFont fFont;
76 #endif
77     TextIndex fTextStart;
78 };
79 
80 #ifndef ENABLE_TEXT_ENHANCE
81 enum InternalState {
82   kUnknown = 0,
83   kIndexed = 1,     // Text is indexed
84   kShaped = 2,      // Text is shaped
85   kLineBroken = 5,
86   kFormatted = 6,
87   kDrawn = 7
88 };
89 #endif
90 
91 /*
92 struct BidiRegion {
93     BidiRegion(size_t start, size_t end, uint8_t dir)
94         : text(start, end), direction(dir) { }
95     TextRange text;
96     uint8_t direction;
97 };
98 */
99 class ParagraphImpl final : public Paragraph {
100 
101 public:
102 #ifdef ENABLE_TEXT_ENHANCE
103     ParagraphImpl() = default;
104 
105 #endif // ENABLE_TEXT_ENHANCE
106 
107     ParagraphImpl(const SkString& text,
108                   ParagraphStyle style,
109                   skia_private::TArray<Block, true> blocks,
110                   skia_private::TArray<Placeholder, true> placeholders,
111                   sk_sp<FontCollection> fonts,
112                   sk_sp<SkUnicode> unicode);
113 
114     ParagraphImpl(const std::u16string& utf16text,
115                   ParagraphStyle style,
116                   skia_private::TArray<Block, true> blocks,
117                   skia_private::TArray<Placeholder, true> placeholders,
118                   sk_sp<FontCollection> fonts,
119                   sk_sp<SkUnicode> unicode);
120 
121     ~ParagraphImpl() override;
122 
123     void layout(SkScalar width) override;
124     void paint(SkCanvas* canvas, SkScalar x, SkScalar y) override;
125     void paint(ParagraphPainter* canvas, SkScalar x, SkScalar y) override;
126 #ifdef ENABLE_TEXT_ENHANCE
127     void paint(ParagraphPainter* canvas, RSPath* path, SkScalar hOffset, SkScalar vOffset) override;
128     std::string GetDumpInfo() const override;
129 #endif // ENABLE_TEXT_ENHANCE
130     std::vector<TextBox> getRectsForRange(unsigned start,
131                                           unsigned end,
132                                           RectHeightStyle rectHeightStyle,
133                                           RectWidthStyle rectWidthStyle) override;
134     std::vector<TextBox> getRectsForPlaceholders() override;
135     void getLineMetrics(std::vector<LineMetrics>&) override;
136     PositionWithAffinity getGlyphPositionAtCoordinate(SkScalar dx, SkScalar dy) override;
137     SkRange<size_t> getWordBoundary(unsigned offset) override;
138 #ifdef ENABLE_TEXT_ENHANCE
getApplyRoundingHack()139     bool getApplyRoundingHack() const { return false; }
lineNumber()140     size_t lineNumber() override { return fLineNumber; }
141     TextRange getEllipsisTextRange() override;
isRunCombinated()142     bool isRunCombinated() const override { return fRuns.size() < fTextStyles.size(); }
143 #else
getApplyRoundingHack()144     bool getApplyRoundingHack() const { return fParagraphStyle.getApplyRoundingHack(); }
lineNumber()145     size_t lineNumber() override { return fLines.size(); }
146 #endif
147 
148     TextLine& addLine(SkVector offset, SkVector advance,
149                       TextRange textExcludingSpaces, TextRange text, TextRange textIncludingNewlines,
150                       ClusterRange clusters, ClusterRange clustersWithGhosts, SkScalar widthWithSpaces,
151                       InternalLineMetrics sizes);
152 
text()153     SkSpan<const char> text() const { return SkSpan<const char>(fText.c_str(), fText.size()); }
154 
155 #ifdef ENABLE_TEXT_ENHANCE
156     std::vector<SkUnichar> convertUtf8ToUnicode(const SkString& utf8);
157     std::unique_ptr<Paragraph> createCroppedCopy(
158             size_t startIndex, size_t count = std::numeric_limits<size_t>::max()) override;
159     void initUnicodeText() override;
unicodeText()160     const std::vector<SkUnichar>& unicodeText() const override { return fUnicodeText; }
getUnicodeIndex(TextIndex index)161     size_t getUnicodeIndex(TextIndex index) const override {
162         if (index >= fUnicodeIndexForUTF8Index.size()) {
163             return fUnicodeIndexForUTF8Index.empty() ? 0 : fUnicodeIndexForUTF8Index.back() + 1;
164         }
165         return fUnicodeIndexForUTF8Index[index];
166     }
167 #endif
state()168     InternalState state() const { return fState; }
runs()169     SkSpan<Run> runs() { return SkSpan<Run>(fRuns.data(), fRuns.size()); }
styles()170     SkSpan<Block> styles() {
171         return SkSpan<Block>(fTextStyles.data(), fTextStyles.size());
172     }
placeholders()173     SkSpan<Placeholder> placeholders() {
174         return SkSpan<Placeholder>(fPlaceholders.data(), fPlaceholders.size());
175     }
lines()176     SkSpan<TextLine> lines() { return SkSpan<TextLine>(fLines.data(), fLines.size()); }
paragraphStyle()177     const ParagraphStyle& paragraphStyle() const { return fParagraphStyle; }
clusters()178     SkSpan<Cluster> clusters() { return SkSpan<Cluster>(fClusters.begin(), fClusters.size()); }
fontCollection()179     sk_sp<FontCollection> fontCollection() const { return fFontCollection; }
180     void formatLines(SkScalar maxWidth);
181     void ensureUTF16Mapping();
182     skia_private::TArray<TextIndex> countSurroundingGraphemes(TextRange textRange) const;
183     TextIndex findNextGraphemeBoundary(TextIndex utf8) const;
184     TextIndex findPreviousGraphemeBoundary(TextIndex utf8) const;
185     TextIndex findNextGlyphClusterBoundary(TextIndex utf8) const;
186     TextIndex findPreviousGlyphClusterBoundary(TextIndex utf8) const;
getUTF16Index(TextIndex index)187     size_t getUTF16Index(TextIndex index) const {
188         return fUTF16IndexForUTF8Index[index];
189     }
190 
191 #ifdef ENABLE_TEXT_ENHANCE
getUTF16IndexWithOverflowCheck(TextIndex index)192     size_t getUTF16IndexWithOverflowCheck(TextIndex index) const {
193         if (index >= fUTF16IndexForUTF8Index.size()) {
194             // This branch is entered only if the index of the ellipsis exceeds the size of the fUTF16IndexForUTF8Index
195             return fUTF16IndexForUTF8Index.back();
196         }
197         return fUTF16IndexForUTF8Index[index];
198     }
199     WordBreakType getWordBreakType() const;
200     LineBreakStrategy getLineBreakStrategy() const;
201     void positionShapedTextIntoLine(SkScalar maxWidth);
202     void buildClusterPlaceholder(Run& run, size_t runIndex);
203     std::vector<ParagraphPainter::PaintID> updateColor(size_t from, size_t to, SkColor color,
204         UtfEncodeType encodeType) override;
205     SkIRect generatePaintRegion(SkScalar x, SkScalar y) override;
exportTextStyles()206     skia_private::TArray<Block, true>& exportTextStyles() override { return fTextStyles; }
207     bool preCalculateSingleRunAutoSpaceWidth(SkScalar floorWidth);
208     void setIndents(const std::vector<SkScalar>& indents) override;
209     SkScalar detectIndents(size_t index) override;
getTextSplitRatio()210     SkScalar getTextSplitRatio() const override { return fParagraphStyle.getTextSplitRatio(); }
211     std::vector<std::unique_ptr<TextLineBase>> GetTextLines() override;
212     std::unique_ptr<Paragraph> CloneSelf() override;
hash()213     uint32_t& hash() {
214         return hash_;
215     }
216     RSFontMetrics measureText() override;
217     bool GetLineFontMetrics(const size_t lineNumber, size_t& charNumber,
218         std::vector<RSFontMetrics>& fontMetrics) override;
GetMaxLines()219     size_t GetMaxLines() const override { return fParagraphStyle.getMaxLines(); }
setLastAutoSpacingFlag(Cluster::AutoSpacingFlag flag)220     void setLastAutoSpacingFlag(Cluster::AutoSpacingFlag flag) { fLastAutoSpacingFlag = flag; }
getLastAutoSpacingFlag()221     const Cluster::AutoSpacingFlag& getLastAutoSpacingFlag() const { return fLastAutoSpacingFlag; }
resetAutoSpacing()222     void resetAutoSpacing() {
223         for (auto& run : fRuns) {
224             run.resetAutoSpacing();
225         }
226     }
227     bool isAutoSpaceEnabled() const;
228     SkScalar clusterUsingAutoSpaceWidth(const Cluster& cluster) const;
getText()229     const SkString& getText() const { return fText; }
230     void updateSplitRunClusterInfo(const Run& run, bool isSplitRun);
231     void refreshLines();
232     bool isTailOfLineNeedSplit(const Run& lineLastRun, size_t lineEnd, bool hasGenerated);
233     void generateSplitPoint(
234         std::vector<SplitPoint>& splitPoints, const Run& run, ClusterRange lineRange, size_t lineIndex);
235     void generateSplitPoints(std::vector<SplitPoint>& splitPoints);
236     void generateRunsBySplitPoints(std::vector<SplitPoint>& splitPoints, skia_private::TArray<Run, false>& runs);
237     void splitRuns();
238 #endif
239 
strutEnabled()240     bool strutEnabled() const { return paragraphStyle().getStrutStyle().getStrutEnabled(); }
strutForceHeight()241     bool strutForceHeight() const {
242         return paragraphStyle().getStrutStyle().getForceStrutHeight();
243     }
strutHeightOverride()244     bool strutHeightOverride() const {
245         return paragraphStyle().getStrutStyle().getHeightOverride();
246     }
strutMetrics()247     InternalLineMetrics strutMetrics() const { return fStrutMetrics; }
248 
249     SkString getEllipsis() const;
250 
251     SkSpan<const char> text(TextRange textRange);
252     SkSpan<Cluster> clusters(ClusterRange clusterRange);
253     Cluster& cluster(ClusterIndex clusterIndex);
clusterIndex(TextIndex textIndex)254     ClusterIndex clusterIndex(TextIndex textIndex) {
255         auto clusterIndex = this->fClustersIndexFromCodeUnit[textIndex];
256         SkASSERT(clusterIndex != EMPTY_INDEX);
257         return clusterIndex;
258     }
run(RunIndex runIndex)259     Run& run(RunIndex runIndex) {
260         SkASSERT(runIndex < SkToSizeT(fRuns.size()));
261         return fRuns[runIndex];
262     }
263 
264     Run& runByCluster(ClusterIndex clusterIndex);
265     SkSpan<Block> blocks(BlockRange blockRange);
266     Block& block(BlockIndex blockIndex);
resolvedFonts()267     skia_private::TArray<ResolvedFontDescriptor> resolvedFonts() const { return fFontSwitches; }
268 
markDirty()269     void markDirty() override {
270         if (fState > kIndexed) {
271             fState = kIndexed;
272         }
273     }
274 
275     int32_t unresolvedGlyphs() override;
276     std::unordered_set<SkUnichar> unresolvedCodepoints() override;
277     void addUnresolvedCodepoints(TextRange textRange);
278 
279 #ifdef ENABLE_TEXT_ENHANCE
280     void setState(InternalState state) override;
getState()281     InternalState getState() const override { return state(); }
282     std::vector<TextBlobRecordInfo> getTextBlobRecordInfo() override;
hasSkipTextBlobDrawing()283     bool hasSkipTextBlobDrawing() const override { return fSkipTextBlobDrawing; }
setSkipTextBlobDrawing(bool state)284     void setSkipTextBlobDrawing(bool state) override { fSkipTextBlobDrawing = state; }
285     bool canPaintAllText() const override;
286 #else
287     void setState(InternalState state);
288 #endif
289 
getPicture()290     sk_sp<SkPicture> getPicture() { return fPicture; }
291 
widthWithTrailingSpaces()292     SkScalar widthWithTrailingSpaces() { return fMaxWidthWithTrailingSpaces; }
293 
294     void resetContext();
295     void resolveStrut();
296 
297     bool computeCodeUnitProperties();
298     void applySpacingAndBuildClusterTable();
299     void buildClusterTable();
300     bool shapeTextIntoEndlessLine();
301     void breakShapedTextIntoLines(SkScalar maxWidth);
302 
303     void updateTextAlign(TextAlign textAlign) override;
304     void updateFontSize(size_t from, size_t to, SkScalar fontSize) override;
305     void updateForegroundPaint(size_t from, size_t to, SkPaint paint) override;
306     void updateBackgroundPaint(size_t from, size_t to, SkPaint paint) override;
307 
308     void visit(const Visitor&) override;
309 #ifndef ENABLE_TEXT_ENHANCE
310     void extendedVisit(const ExtendedVisitor&) override;
311     int getPath(int lineNumber, SkPath* dest) override;
312 #endif
313     bool containsColorFontOrBitmap(SkTextBlob* textBlob) override;
314     bool containsEmoji(SkTextBlob* textBlob) override;
315 
316     int getLineNumberAt(TextIndex codeUnitIndex) const override;
317     int getLineNumberAtUTF16Offset(size_t codeUnitIndex) override;
318     bool getLineMetricsAt(int lineNumber, LineMetrics* lineMetrics) const override;
319     TextRange getActualTextRange(int lineNumber, bool includeSpaces) const override;
320     bool getGlyphClusterAt(TextIndex codeUnitIndex, GlyphClusterInfo* glyphInfo) override;
321     bool getClosestGlyphClusterAt(SkScalar dx,
322                                   SkScalar dy,
323                                   GlyphClusterInfo* glyphInfo) override;
324 
325     bool getGlyphInfoAtUTF16Offset(size_t codeUnitIndex, GlyphInfo* graphemeInfo) override;
326     bool getClosestUTF16GlyphInfoAt(SkScalar dx, SkScalar dy, GlyphInfo* graphemeInfo) override;
327 
328 #ifdef ENABLE_TEXT_ENHANCE
329     RSFont getFontAt(TextIndex codeUnitIndex) const override;
330 #else
331     SkFont getFontAt(TextIndex codeUnitIndex) const override;
332 #endif
333 #ifndef ENABLE_TEXT_ENHANCE
334     SkFont getFontAtUTF16Offset(size_t codeUnitIndex) override;
335 #endif
336     std::vector<FontInfo> getFonts() const override;
337 
getEmptyMetrics()338     InternalLineMetrics getEmptyMetrics() const { return fEmptyMetrics; }
getStrutMetrics()339     InternalLineMetrics getStrutMetrics() const { return fStrutMetrics; }
340 
341     BlockRange findAllBlocks(TextRange textRange);
342 
resetShifts()343     void resetShifts() {
344         for (auto& run : fRuns) {
345             run.resetJustificationShifts();
346         }
347     }
348 
codeUnitHasProperty(size_t index,SkUnicode::CodeUnitFlags property)349     bool codeUnitHasProperty(size_t index, SkUnicode::CodeUnitFlags property) const {
350         return (fCodeUnitProperties[index] & property) == property;
351     }
getUnicode()352     sk_sp<SkUnicode> getUnicode() { return fUnicode; }
353 
354 #ifdef ENABLE_TEXT_ENHANCE
355     bool needCreateMiddleEllipsis();
356     Placeholder* getPlaceholderByIndex(size_t placeholderIndex);
357     bool IsPlaceholderAlignedFollowParagraph(size_t placeholderIndex);
358     bool setPlaceholderAlignment(size_t placeholderIndex, PlaceholderAlignment alignment);
359     Block& getBlockByRun(const Run& run);
360 #endif
361 private:
362     friend class ParagraphBuilder;
363     friend class ParagraphCacheKey;
364     friend class ParagraphCacheValue;
365     friend class ParagraphCache;
366 
367     friend class TextWrapper;
368     friend class OneLineShaper;
369     void computeEmptyMetrics();
370 #ifdef ENABLE_TEXT_ENHANCE
371     friend struct TextWrapScorer;
372     TextRange resetRangeWithDeletedRange(const TextRange& sourceRange,
373         const TextRange& deletedRange, const size_t& ellSize);
374     void resetTextStyleRange(const TextRange& deletedRange);
375     void resetPlaceholderRange(const TextRange& deletedRange);
setSize(SkScalar height,SkScalar width,SkScalar longestLine)376     void setSize(SkScalar height, SkScalar width, SkScalar longestLine) {
377         fHeight = height;
378         fWidth = width;
379         fLongestLine = longestLine;
380     }
getSize(SkScalar & height,SkScalar & width,SkScalar & longestLine)381     void getSize(SkScalar& height, SkScalar& width, SkScalar& longestLine) {
382         height = fHeight;
383         width = fWidth;
384         longestLine = fLongestLine;
385     }
setIntrinsicSize(SkScalar maxIntrinsicWidth,SkScalar minIntrinsicWidth,SkScalar alphabeticBaseline,SkScalar ideographicBaseline,bool exceededMaxLines)386     void setIntrinsicSize(SkScalar maxIntrinsicWidth, SkScalar minIntrinsicWidth, SkScalar alphabeticBaseline,
387                           SkScalar ideographicBaseline, bool exceededMaxLines) {
388         fMaxIntrinsicWidth = maxIntrinsicWidth;
389         fMinIntrinsicWidth = minIntrinsicWidth;
390         fAlphabeticBaseline = alphabeticBaseline;
391         fIdeographicBaseline = ideographicBaseline;
392         fExceededMaxLines = exceededMaxLines;
393     }
getIntrinsicSize(SkScalar & maxIntrinsicWidth,SkScalar & minIntrinsicWidth,SkScalar & alphabeticBaseline,SkScalar & ideographicBaseline,bool & exceededMaxLines)394     void getIntrinsicSize(SkScalar& maxIntrinsicWidth, SkScalar& minIntrinsicWidth, SkScalar& alphabeticBaseline,
395                           SkScalar& ideographicBaseline, bool& exceededMaxLines) {
396         maxIntrinsicWidth = fMaxIntrinsicWidth;
397         minIntrinsicWidth = fMinIntrinsicWidth;
398         alphabeticBaseline = fAlphabeticBaseline ;
399         ideographicBaseline = fIdeographicBaseline;
400         exceededMaxLines = fExceededMaxLines;
401     }
402 
403     ParagraphPainter::PaintID updateTextStyleColorAndForeground(TextStyle& TextStyle, SkColor color);
404     TextBox getEmptyTextRect(RectHeightStyle rectHeightStyle) const;
405     size_t prefixByteCountUntilChar(size_t index);
406     void copyProperties(const ParagraphImpl& source);
407     std::string_view GetState() const;
408 #endif
409 
410     // Input
411     skia_private::TArray<StyleBlock<SkScalar>> fLetterSpaceStyles;
412     skia_private::TArray<StyleBlock<SkScalar>> fWordSpaceStyles;
413     skia_private::TArray<StyleBlock<SkPaint>> fBackgroundStyles;
414     skia_private::TArray<StyleBlock<SkPaint>> fForegroundStyles;
415     skia_private::TArray<StyleBlock<std::vector<TextShadow>>> fShadowStyles;
416     skia_private::TArray<StyleBlock<Decoration>> fDecorationStyles;
417     skia_private::TArray<Block, true> fTextStyles; // TODO: take out only the font stuff
418     skia_private::TArray<Placeholder, true> fPlaceholders;
419     SkString fText;
420 
421     // Internal structures
422     InternalState fState;
423     skia_private::TArray<Run, false> fRuns;         // kShaped
424     skia_private::TArray<Cluster, true> fClusters;  // kClusterized (cached: text, word spacing, letter spacing, resolved fonts)
425     skia_private::TArray<SkUnicode::CodeUnitFlags, true> fCodeUnitProperties;
426     skia_private::TArray<size_t, true> fClustersIndexFromCodeUnit;
427     std::vector<size_t> fWords;
428     std::vector<SkUnicode::BidiRegion> fBidiRegions;
429     // These two arrays are used in measuring methods (getRectsForRange, getGlyphPositionAtCoordinate)
430     // They are filled lazily whenever they need and cached
431     skia_private::TArray<TextIndex, true> fUTF8IndexForUTF16Index;
432     skia_private::TArray<size_t, true> fUTF16IndexForUTF8Index;
433     SkOnce fillUTF16MappingOnce;
434     size_t fUnresolvedGlyphs;
435     std::unordered_set<SkUnichar> fUnresolvedCodepoints;
436 
437     skia_private::TArray<TextLine, false> fLines;   // kFormatted   (cached: width, max lines, ellipsis, text align)
438     sk_sp<SkPicture> fPicture;          // kRecorded    (cached: text styles)
439 
440     skia_private::TArray<ResolvedFontDescriptor> fFontSwitches;
441 
442     InternalLineMetrics fEmptyMetrics;
443     InternalLineMetrics fStrutMetrics;
444 
445     SkScalar fOldWidth;
446     SkScalar fOldHeight;
447     SkScalar fMaxWidthWithTrailingSpaces;
448 
449     sk_sp<SkUnicode> fUnicode;
450     bool fHasLineBreaks;
451     bool fHasWhitespacesInside;
452     TextIndex fTrailingSpaces;
453 
454 #ifdef ENABLE_TEXT_ENHANCE
455     std::vector<SkScalar> fIndents;
456     std::vector<SkUnichar> fUnicodeText;
457     skia_private::TArray<size_t, true> fUnicodeIndexForUTF8Index;
458     SkScalar fLayoutRawWidth{0};
459 
460     size_t fLineNumber{0};
461     uint32_t hash_{0u};
462 
463     TextRange fEllipsisRange{EMPTY_RANGE};
464     std::optional<SkRect> fPaintRegion;
465     // just for building cluster table, record the last built unicode autospacing flag;
466     Cluster::AutoSpacingFlag fLastAutoSpacingFlag;
467     bool fSkipTextBlobDrawing{false};
468 #endif
469 };
470 }  // namespace textlayout
471 }  // namespace skia
472 
473 
474 #endif  // ParagraphImpl_DEFINED
475