• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2019 Google LLC.
2 #ifndef TextLine_DEFINED
3 #define TextLine_DEFINED
4 
5 #include "include/ParagraphStyle.h"
6 #include "include/core/SkPoint.h"
7 #include "include/core/SkRect.h"
8 #include "include/core/SkScalar.h"
9 #include "include/private/SkBitmaskEnum.h" // IWYU pragma: keep
10 #include "include/private/SkTArray.h"
11 #include "modules/skparagraph/include/DartTypes.h"
12 #include "modules/skparagraph/include/Metrics.h"
13 #include "modules/skparagraph/include/ParagraphPainter.h"
14 #include "modules/skparagraph/include/RunBase.h"
15 #ifdef OHOS_SUPPORT
16 #include "modules/skparagraph/include/TextLineBase.h"
17 #endif
18 #include "modules/skparagraph/include/TextStyle.h"
19 #include "modules/skparagraph/src/Run.h"
20 
21 #include <stddef.h>
22 #include <functional>
23 #include <memory>
24 #include <vector>
25 
26 class SkString;
27 
28 namespace skia {
29 namespace textlayout {
30 
31 class ParagraphImpl;
32 struct DecorationContext {
33     SkScalar thickness = 0.0f;
34     SkScalar underlinePosition = 0.0f;
35     SkScalar textBlobTop = 0.0f;
36 };
37 class TextLine {
38 public:
39     struct ClipContext {
40       const Run* run;
41       size_t pos;
42       size_t size;
43       SkScalar fTextShift; // Shifts the text inside the run so it's placed at the right position
44       SkRect clip;
45       SkScalar fExcludedTrailingSpaces;
46       bool clippingNeeded;
47     };
48 
49     struct PathParameters {
50         const RSPath* recordPath = nullptr;
51         SkScalar hOffset = 0;
52         SkScalar vOffset = 0;
53     } pathParameters;
54 
55     enum TextAdjustment {
56         GlyphCluster = 0x01,    // All text producing glyphs pointing to the same ClusterIndex
57         GlyphemeCluster = 0x02, // base glyph + all attached diacritics
58         Grapheme = 0x04,        // Text adjusted to graphemes
59         GraphemeGluster = 0x05, // GlyphCluster & Grapheme
60     };
61 
62 #ifdef OHOS_SUPPORT
63     enum EllipsisReadStrategy {
64         DEFAULT = 0,            // default
65         READ_REPLACED_WORD = 1,  // read replaced word
66         READ_ELLIPSIS_WORD = 2, // read ellipsis word
67     };
68 
69     struct HighLevelInfo {
70         ClusterIndex clusterIndex{SIZE_MAX};
71         bool isClusterPunct{false};
72         SkScalar punctWidths{0.0f};
73         SkScalar highLevelOffset{0.0f};
74     };
75 
76     struct MiddleLevelInfo {
77         ClusterIndex clusterIndex{SIZE_MAX};
78         bool isPrevClusterSpace{true};
79     };
80 
81     struct ClusterLevelsIndices {
82         std::vector<HighLevelInfo> highLevelIndices;
83         std::vector<MiddleLevelInfo> middleLevelIndices;
84         std::vector<ClusterIndex> LowLevelIndices;
85         SkScalar middleLevelOffset{0.0f};
86         SkScalar lowLevelOffset{0.0f};
87 
emptyClusterLevelsIndices88         bool empty()
89         {
90             return highLevelIndices.empty() && middleLevelIndices.empty() && LowLevelIndices.empty();
91         }
92     };
93 
94     enum class ShiftLevel {
95         Undefined,
96         HighLevel, // Level 1 Label: Punctuation
97         MiddleLevel, // Level-2 label: WhitespaceBreak, between ideographic and non-ideographic characters
98         LowLevel // Level-3 label: Between ideographic characters
99     };
100 #endif
101 
102     TextLine() = default;
103     TextLine(const TextLine&) = delete;
104     TextLine& operator=(const TextLine&) = delete;
105     TextLine(TextLine&&) = default;
106     TextLine& operator=(TextLine&&) = default;
107     ~TextLine() = default;
108 
109     TextLine(ParagraphImpl* owner,
110              SkVector offset,
111              SkVector advance,
112              BlockRange blocks,
113              TextRange textExcludingSpaces,
114              TextRange text,
115              TextRange textIncludingNewlines,
116              ClusterRange clusters,
117              ClusterRange clustersWithGhosts,
118              SkScalar widthWithSpaces,
119              InternalLineMetrics sizes);
120 
trimmedText()121     TextRange trimmedText() const { return fTextExcludingSpaces; }
textWithNewlines()122     TextRange textWithNewlines() const { return fTextIncludingNewlines; }
text()123     TextRange text() const { return fText; }
clusters()124     ClusterRange clusters() const { return fClusterRange; }
clustersWithSpaces()125     ClusterRange clustersWithSpaces() const { return fGhostClusterRange; }
ellipsis()126     Run* ellipsis() const { return fEllipsis.get(); }
sizes()127     InternalLineMetrics sizes() const { return fSizes; }
empty()128     bool empty() const { return fTextExcludingSpaces.empty(); }
129 
spacesWidth()130     SkScalar spacesWidth() const { return fWidthWithSpaces - width(); }
height()131     SkScalar height() const { return fAdvance.fY; }
width()132     SkScalar width() const {
133         return fAdvance.fX + (fEllipsis != nullptr ? fEllipsis->fAdvance.fX : 0);
134     }
widthWithoutEllipsis()135     SkScalar widthWithoutEllipsis() const { return fAdvance.fX; }
widthWithEllipsisSpaces()136     SkScalar widthWithEllipsisSpaces() const {
137         return fWidthWithSpaces + (fEllipsis != nullptr ? fEllipsis->fAdvance.fX : 0);
138     }
139     SkVector offset() const;
setLineOffsetX(SkScalar x)140     void setLineOffsetX(SkScalar x) {
141         fOffset.set(x, fOffset.y());
142     }
143 
alphabeticBaseline()144     SkScalar alphabeticBaseline() const { return fSizes.alphabeticBaseline(); }
ideographicBaseline()145     SkScalar ideographicBaseline() const { return fSizes.ideographicBaseline(); }
baseline()146     SkScalar baseline() const { return fSizes.baseline(); }
147 #ifdef OHOS_SUPPORT
148     void extendCoordinateRange(PositionWithAffinity& positionWithAffinity);
149 #endif
150 
151     using RunVisitor = std::function<bool(
152             const Run* run, SkScalar runOffset, TextRange textRange, SkScalar* width)>;
153 
154 #ifdef OHOS_SUPPORT
155     bool processEllipsisRun(bool& isAlreadyUseEllipsis,
156                             SkScalar& runOffset,
157                             EllipsisReadStrategy ellipsisReadStrategy,
158                             const RunVisitor& visitor,
159                             SkScalar& runWidthInLine) const;
160     bool processInsertedRun(const Run* run,
161                             SkScalar& runOffset,
162                             EllipsisReadStrategy ellipsisReadStrategy,
163                             const RunVisitor& visitor,
164                             SkScalar& runWidthInLine) const;
165 #endif
166 
167 #ifdef OHOS_SUPPORT
168     void iterateThroughVisualRuns(EllipsisReadStrategy ellipsisReadStrategy,
169                                   bool includingGhostSpaces,
170                                   const RunVisitor& runVisitor) const;
171 #else
172     void iterateThroughVisualRuns(bool includingGhostSpaces, const RunVisitor& runVisitor) const;
173 #endif
174     using RunStyleVisitor = std::function<void(
175             TextRange textRange, const TextStyle& style, const ClipContext& context)>;
176     SkScalar iterateThroughSingleRunByStyles(TextAdjustment textAdjustment,
177                                              const Run* run,
178                                              SkScalar runOffset,
179                                              TextRange textRange,
180                                              StyleType styleType,
181                                              const RunStyleVisitor& visitor) const;
182 
183     using ClustersVisitor = std::function<bool(const Cluster* cluster, ClusterIndex index, bool ghost)>;
184     void iterateThroughClustersInGlyphsOrder(bool reverse,
185                                              bool includeGhosts,
186                                              const ClustersVisitor& visitor) const;
187 
188     void format(TextAlign align, SkScalar maxWidth, EllipsisModal ellipsisModal);
189     SkScalar autoSpacing();
190     void paint(ParagraphPainter* painter, SkScalar x, SkScalar y);
191     void paint(ParagraphPainter* painter, const RSPath* path, SkScalar hOffset, SkScalar vOffset);
192     void visit(SkScalar x, SkScalar y);
193     void ensureTextBlobCachePopulated();
setParagraphImpl(ParagraphImpl * newpara)194     void setParagraphImpl(ParagraphImpl* newpara) { fOwner = newpara; }
setBlockRange(const BlockRange & blockRange)195     void setBlockRange(const BlockRange& blockRange) { fBlockRange = blockRange; }
196     void countWord(int& wordCount, bool& inWord);
197     void ellipsisNotFitProcess(EllipsisModal ellipsisModal);
198 #ifdef OHOS_SUPPORT
199     void createTailEllipsis(SkScalar maxWidth, const SkString& ellipsis, bool ltr, WordBreakType wordBreakType);
200     void handleTailEllipsisInEmptyLine(std::unique_ptr<Run>& ellipsisRun, const SkString& ellipsis,
201         SkScalar width, WordBreakType wordBreakType);
202     void TailEllipsisUpdateLine(Cluster& cluster, float width, size_t clusterIndex, WordBreakType wordBreakType);
203     void createHeadEllipsis(SkScalar maxWidth, const SkString& ellipsis, bool ltr);
204 #endif
205     // For testing internal structures
206     void scanStyles(StyleType style, const RunStyleVisitor& visitor);
207 
setMaxRunMetrics(const InternalLineMetrics & metrics)208     void setMaxRunMetrics(const InternalLineMetrics& metrics) { fMaxRunMetrics = metrics; }
getMaxRunMetrics()209     InternalLineMetrics getMaxRunMetrics() const { return fMaxRunMetrics; }
210 
211     bool isFirstLine() const;
212     bool isLastLine() const;
213     void getRectsForRange(TextRange textRange,
214                           RectHeightStyle rectHeightStyle,
215                           RectWidthStyle rectWidthStyle,
216                           std::vector<TextBox>& boxes) const;
217     void getRectsForPlaceholders(std::vector<TextBox>& boxes);
218     PositionWithAffinity getGlyphPositionAtCoordinate(SkScalar dx);
219 
220     ClipContext measureTextInsideOneRun(TextRange textRange,
221                                         const Run* run,
222                                         SkScalar runOffsetInLine,
223                                         SkScalar textOffsetInRunInLine,
224                                         bool includeGhostSpaces,
225                                         TextAdjustment textAdjustment) const;
226 
227     LineMetrics getMetrics() const;
228 
229     SkRect extendHeight(const ClipContext& context) const;
230 
shiftVertically(SkScalar shift)231     void shiftVertically(SkScalar shift) { fOffset.fY += shift; }
232 
setAscentStyle(LineMetricStyle style)233     void setAscentStyle(LineMetricStyle style) { fAscentStyle = style; }
setDescentStyle(LineMetricStyle style)234     void setDescentStyle(LineMetricStyle style) { fDescentStyle = style; }
235 
236     bool endsWithHardLineBreak() const;
237 #ifdef OHOS_SUPPORT
238     bool endsWithOnlyHardBreak() const;
239 #endif
240     std::unique_ptr<Run> shapeString(const SkString& string, const Cluster* cluster);
241     std::unique_ptr<Run> shapeEllipsis(const SkString& ellipsis, const Cluster* cluster);
getLineAllRuns()242     SkSTArray<1, size_t, true> getLineAllRuns() const { return fRunsInVisualOrder; };
243 
244     size_t getGlyphCount() const;
245     std::vector<std::unique_ptr<RunBase>> getGlyphRuns() const;
246     TextLine CloneSelf();
getTextRangeReplacedByEllipsis()247     TextRange getTextRangeReplacedByEllipsis() const { return fTextRangeReplacedByEllipsis; }
setTextBlobCachePopulated(const bool textBlobCachePopulated)248     void setTextBlobCachePopulated(const bool textBlobCachePopulated) {
249         fTextBlobCachePopulated = textBlobCachePopulated;
250     }
251 
252 #ifdef OHOS_SUPPORT
253     std::unique_ptr<TextLineBase> createTruncatedLine(double width, EllipsisModal ellipsisMode,
254         const std::string& ellipsisStr);
255     double getTypographicBounds(double* ascent, double* descent, double* leading) const;
256     RSRect getImageBounds() const;
257     double getTrailingSpaceWidth() const;
258     int32_t getStringIndexForPosition(SkPoint point) const;
259     double getOffsetForStringIndex(int32_t index) const;
260     std::map<int32_t, double> getIndexAndOffsets(bool& isHardBreak) const;
261     double getAlignmentOffset(double alignmentFactor, double alignmentWidth) const;
262     SkRect generatePaintRegion(SkScalar x, SkScalar y);
263     void updateClusterOffsets(const Cluster* cluster, SkScalar shift, SkScalar prevShift);
264     void justifyUpdateRtlWidth(const SkScalar maxWidth, const SkScalar textLen);
265     void setBreakWithHyphen(bool breakWithHyphen);
266     bool getBreakWithHyphen() const;
267     void updateTextLinePaintAttributes();
268 #endif
269 
270 private:
271     struct RoundRectAttr {
272         int styleId;
273         RectStyle roundRectStyle;
274         SkRect rect;
275     };
276     void justify(SkScalar maxWidth);
277     void buildTextBlob(TextRange textRange, const TextStyle& style, const ClipContext& context);
278     void paintBackground(ParagraphPainter* painter,
279                          SkScalar x,
280                          SkScalar y,
281                          TextRange textRange,
282                          const TextStyle& style,
283                          const ClipContext& context) const;
284     void paintRoundRect(ParagraphPainter* painter, SkScalar x, SkScalar y, const Run* run) const;
285     void paintShadow(ParagraphPainter* painter,
286                      SkScalar x,
287                      SkScalar y,
288                      TextRange textRange,
289                      const TextStyle& style,
290                      const ClipContext& context) const;
291     void paintDecorations(ParagraphPainter* painter,
292                           SkScalar x,
293                           SkScalar y,
294                           TextRange textRange,
295                           const TextStyle& style,
296                           const ClipContext& context) const;
297 
298     void shiftCluster(const Cluster* cluster, SkScalar shift, SkScalar prevShift);
299     void spacingCluster(const Cluster* cluster, SkScalar spacing, SkScalar prevSpacing);
300     bool hasBackgroundRect(const RoundRectAttr& attr);
301     void computeRoundRect(int& index, int& preIndex, std::vector<Run*>& groupRuns, Run* run);
302     void prepareRoundRect();
303     SkScalar calculateThickness(const TextStyle& style, const ClipContext& context);
304 #ifdef OHOS_SUPPORT
305     void measureTextWithSpacesAtTheEnd(ClipContext& context, bool includeGhostSpaces) const;
306     void computeNextPaintGlyphRange(ClipContext& context, const TextRange& lastGlyphRange, StyleType styleType) const;
307     SkRect computeShadowRect(SkScalar x, SkScalar y, const TextStyle& style, const ClipContext& context) const;
308     SkRect getAllShadowsRect(SkScalar x, SkScalar y) const;
309 #endif
310 
311     ParagraphImpl* fOwner;
312     BlockRange fBlockRange;
313     TextRange fTextExcludingSpaces;
314     TextRange fText;
315     TextRange fTextIncludingNewlines;
316     ClusterRange fClusterRange;
317     ClusterRange fGhostClusterRange;
318     // Avoid the malloc/free in the common case of one run per line
319     SkSTArray<1, size_t, true> fRunsInVisualOrder;
320     SkVector fAdvance;                  // Text size
321     SkVector fOffset;                   // Text position
322     SkScalar fShift;                    // Let right
323     SkScalar fWidthWithSpaces;
324     std::unique_ptr<Run> fEllipsis;     // In case the line ends with the ellipsis
325     TextRange fTextRangeReplacedByEllipsis;     // text range replaced by ellipsis
326     InternalLineMetrics fSizes;                 // Line metrics as a max of all run metrics and struts
327     InternalLineMetrics fMaxRunMetrics;         // No struts - need it for GetRectForRange(max height)
328     size_t fEllipsisIndex = EMPTY_INDEX;
329 
330     bool fHasBackground;
331     bool fHasShadows;
332     bool fHasDecorations;
333     bool fIsArcText;
334     bool fArcTextState;
335     bool fLastClipRunLtr;
336 
337     LineMetricStyle fAscentStyle;
338     LineMetricStyle fDescentStyle;
339 
340     struct TextBlobRecord {
341         void paint(ParagraphPainter* painter, SkScalar x, SkScalar y);
342         void paint(ParagraphPainter* painter);
343 
344 #ifndef USE_SKIA_TXT
345         sk_sp<SkTextBlob> fBlob;
346 #else
347         std::shared_ptr<RSTextBlob> fBlob;
348 #endif
349         SkPoint fOffset = SkPoint::Make(0.0f, 0.0f);
350         ParagraphPainter::SkPaintOrID fPaint;
351         SkRect fBounds = SkRect::MakeEmpty();
352         bool fClippingNeeded = false;
353         SkRect fClipRect = SkRect::MakeEmpty();
354 
355         // Extra fields only used for the (experimental) visitor
356         const Run* fVisitor_Run;
357         size_t     fVisitor_Pos;
358         size_t     fVisitor_Size;
359     };
360     bool fTextBlobCachePopulated;
361     DecorationContext fDecorationContext;
362     std::vector<RoundRectAttr> roundRectAttrs = {};
363 #ifdef OHOS_SUPPORT
364     bool fIsTextLineEllipsisHeadModal = false;
365 #endif
366 public:
367     std::vector<TextBlobRecord> fTextBlobCache;
368 #ifdef OHOS_SUPPORT
369     SkString fEllipsisString;
370     bool fBreakWithHyphen{false};
371     std::unique_ptr<Run> fHyphenRun;
372     size_t fHyphenIndex = EMPTY_INDEX;
373 #endif
374 };
375 }  // namespace textlayout
376 }  // namespace skia
377 
378 namespace sknonstd {
379     template <> struct is_bitmask_enum<skia::textlayout::TextLine::TextAdjustment> : std::true_type {};
380 }  // namespace sknonstd
381 
382 #endif  // TextLine_DEFINED
383