• 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 #include "modules/skparagraph/include/TextStyle.h"
16 #include "modules/skparagraph/src/Run.h"
17 
18 #include <stddef.h>
19 #include <functional>
20 #include <memory>
21 #include <vector>
22 
23 class SkString;
24 
25 namespace skia {
26 namespace textlayout {
27 
28 class ParagraphImpl;
29 struct DecorationContext {
30     SkScalar thickness = 0.0f;
31     SkScalar underlinePosition = 0.0f;
32     SkScalar textBlobTop = 0.0f;
33 };
34 class TextLine {
35 public:
36 
37     struct ClipContext {
38       const Run* run;
39       size_t pos;
40       size_t size;
41       SkScalar fTextShift; // Shifts the text inside the run so it's placed at the right position
42       SkRect clip;
43       SkScalar fExcludedTrailingSpaces;
44       bool clippingNeeded;
45     };
46 
47     struct PathParameters {
48         const RSPath* recordPath = nullptr;
49         SkScalar hOffset = 0;
50         SkScalar vOffset = 0;
51     } pathParameters;
52 
53     enum TextAdjustment {
54         GlyphCluster = 0x01,    // All text producing glyphs pointing to the same ClusterIndex
55         GlyphemeCluster = 0x02, // base glyph + all attached diacritics
56         Grapheme = 0x04,        // Text adjusted to graphemes
57         GraphemeGluster = 0x05, // GlyphCluster & Grapheme
58     };
59 
60 #ifdef OHOS_SUPPORT
61     enum EllipsisReadStrategy {
62         DEFAULT = 0,            // default
63         READ_REPLACED_WORD = 1,  // read replaced word
64         READ_ELLIPSIS_WORD = 2, // read ellipsis word
65     };
66 #endif
67 
68     TextLine() = default;
69     TextLine(const TextLine&) = delete;
70     TextLine& operator=(const TextLine&) = delete;
71     TextLine(TextLine&&) = default;
72     TextLine& operator=(TextLine&&) = default;
73     ~TextLine() = default;
74 
75     TextLine(ParagraphImpl* owner,
76              SkVector offset,
77              SkVector advance,
78              BlockRange blocks,
79              TextRange textExcludingSpaces,
80              TextRange text,
81              TextRange textIncludingNewlines,
82              ClusterRange clusters,
83              ClusterRange clustersWithGhosts,
84              SkScalar widthWithSpaces,
85              InternalLineMetrics sizes);
86 
trimmedText()87     TextRange trimmedText() const { return fTextExcludingSpaces; }
textWithNewlines()88     TextRange textWithNewlines() const { return fTextIncludingNewlines; }
text()89     TextRange text() const { return fText; }
clusters()90     ClusterRange clusters() const { return fClusterRange; }
clustersWithSpaces()91     ClusterRange clustersWithSpaces() const { return fGhostClusterRange; }
ellipsis()92     Run* ellipsis() const { return fEllipsis.get(); }
sizes()93     InternalLineMetrics sizes() const { return fSizes; }
empty()94     bool empty() const { return fTextExcludingSpaces.empty(); }
95 
spacesWidth()96     SkScalar spacesWidth() const { return fWidthWithSpaces - width(); }
height()97     SkScalar height() const { return fAdvance.fY; }
width()98     SkScalar width() const {
99         return fAdvance.fX + (fEllipsis != nullptr ? fEllipsis->fAdvance.fX : 0);
100     }
widthWithoutEllipsis()101     SkScalar widthWithoutEllipsis() const { return fAdvance.fX; }
widthWithEllipsisSpaces()102     SkScalar widthWithEllipsisSpaces() const {
103         return fWidthWithSpaces + (fEllipsis != nullptr ? fEllipsis->fAdvance.fX : 0);
104     }
105     SkVector offset() const;
setLineOffsetX(SkScalar x)106     void setLineOffsetX(SkScalar x) {
107         fOffset.set(x, fOffset.y());
108     }
109 
alphabeticBaseline()110     SkScalar alphabeticBaseline() const { return fSizes.alphabeticBaseline(); }
ideographicBaseline()111     SkScalar ideographicBaseline() const { return fSizes.ideographicBaseline(); }
baseline()112     SkScalar baseline() const { return fSizes.baseline(); }
113 
114     using RunVisitor = std::function<bool(
115             const Run* run, SkScalar runOffset, TextRange textRange, SkScalar* width)>;
116 
117 #ifdef OHOS_SUPPORT
118     bool processEllipsisRun(bool& isAlreadyUseEllipsis,
119                             SkScalar& runOffset,
120                             EllipsisReadStrategy ellipsisReadStrategy,
121                             const RunVisitor& visitor,
122                             SkScalar& runWidthInLine) const;
123 #endif
124 
125 #ifdef OHOS_SUPPORT
126     void iterateThroughVisualRuns(EllipsisReadStrategy ellipsisReadStrategy,
127                                   bool includingGhostSpaces,
128                                   const RunVisitor& runVisitor) const;
129 #else
130     void iterateThroughVisualRuns(bool includingGhostSpaces, const RunVisitor& runVisitor) const;
131 #endif
132     using RunStyleVisitor = std::function<void(
133             TextRange textRange, const TextStyle& style, const ClipContext& context)>;
134     SkScalar iterateThroughSingleRunByStyles(TextAdjustment textAdjustment,
135                                              const Run* run,
136                                              SkScalar runOffset,
137                                              TextRange textRange,
138                                              StyleType styleType,
139                                              const RunStyleVisitor& visitor) const;
140 
141     using ClustersVisitor = std::function<bool(const Cluster* cluster, ClusterIndex index, bool ghost)>;
142     void iterateThroughClustersInGlyphsOrder(bool reverse,
143                                              bool includeGhosts,
144                                              const ClustersVisitor& visitor) const;
145 
146     void format(TextAlign align, SkScalar maxWidth, EllipsisModal ellipsisModal);
147     SkScalar calculateSpacing(const Cluster prevCluster, const Cluster curCluster);
148     SkScalar autoSpacing();
149     void paint(ParagraphPainter* painter, SkScalar x, SkScalar y);
150     void paint(ParagraphPainter* painter, const RSPath* path, SkScalar hOffset, SkScalar vOffset);
151     void visit(SkScalar x, SkScalar y);
152     void ensureTextBlobCachePopulated();
setParagraphImpl(ParagraphImpl * newpara)153     void setParagraphImpl(ParagraphImpl* newpara) { fOwner = newpara; }
setBlockRange(const BlockRange & blockRange)154     void setBlockRange(const BlockRange& blockRange) { fBlockRange = blockRange; }
155     void countWord(int& wordCount, bool& inWord);
156     void ellipsisNotFitProcess(EllipsisModal ellipsisModal);
157     void createTailEllipsis(SkScalar maxWidth, const SkString& ellipsis, bool ltr, WordBreakType wordBreakType);
158     void createHeadEllipsis(SkScalar maxWidth, const SkString& ellipsis, bool ltr);
159     // For testing internal structures
160     void scanStyles(StyleType style, const RunStyleVisitor& visitor);
161 
setMaxRunMetrics(const InternalLineMetrics & metrics)162     void setMaxRunMetrics(const InternalLineMetrics& metrics) { fMaxRunMetrics = metrics; }
getMaxRunMetrics()163     InternalLineMetrics getMaxRunMetrics() const { return fMaxRunMetrics; }
164 
165     bool isFirstLine() const;
166     bool isLastLine() const;
167     void getRectsForRange(TextRange textRange,
168                           RectHeightStyle rectHeightStyle,
169                           RectWidthStyle rectWidthStyle,
170                           std::vector<TextBox>& boxes) const;
171     void getRectsForPlaceholders(std::vector<TextBox>& boxes);
172     PositionWithAffinity getGlyphPositionAtCoordinate(SkScalar dx);
173 
174     ClipContext measureTextInsideOneRun(TextRange textRange,
175                                         const Run* run,
176                                         SkScalar runOffsetInLine,
177                                         SkScalar textOffsetInRunInLine,
178                                         bool includeGhostSpaces,
179                                         TextAdjustment textAdjustment) const;
180 
181     LineMetrics getMetrics() const;
182 
183     SkRect extendHeight(const ClipContext& context) const;
184 
shiftVertically(SkScalar shift)185     void shiftVertically(SkScalar shift) { fOffset.fY += shift; }
186 
setAscentStyle(LineMetricStyle style)187     void setAscentStyle(LineMetricStyle style) { fAscentStyle = style; }
setDescentStyle(LineMetricStyle style)188     void setDescentStyle(LineMetricStyle style) { fDescentStyle = style; }
189 
190     bool endsWithHardLineBreak() const;
191     std::unique_ptr<Run> shapeEllipsis(const SkString& ellipsis, const Cluster* cluster);
getLineAllRuns()192     SkSTArray<1, size_t, true> getLineAllRuns() const { return fRunsInVisualOrder; };
193 
194     size_t getGlyphCount() const;
195     std::vector<std::unique_ptr<RunBase>> getGlyphRuns() const;
196     TextLine CloneSelf();
getTextRangeReplacedByEllipsis()197     TextRange getTextRangeReplacedByEllipsis() const { return fTextRangeReplacedByEllipsis; }
setTextBlobCachePopulated(const bool textBlobCachePopulated)198     void setTextBlobCachePopulated(const bool textBlobCachePopulated) {
199         fTextBlobCachePopulated = textBlobCachePopulated;
200     }
201 
202 #ifdef OHOS_SUPPORT
203     SkRect generatePaintRegion(SkScalar x, SkScalar y);
204 #endif
205 
206 private:
207     struct RoundRectAttr {
208         int styleId;
209         RectStyle roundRectStyle;
210         SkRect rect;
211     };
212 
213     void justify(SkScalar maxWidth);
214 
215     void buildTextBlob(TextRange textRange, const TextStyle& style, const ClipContext& context);
216     void paintBackground(ParagraphPainter* painter,
217                          SkScalar x,
218                          SkScalar y,
219                          TextRange textRange,
220                          const TextStyle& style,
221                          const ClipContext& context) const;
222     void paintRoundRect(ParagraphPainter* painter, SkScalar x, SkScalar y, const Run* run) const;
223     void paintShadow(ParagraphPainter* painter,
224                      SkScalar x,
225                      SkScalar y,
226                      TextRange textRange,
227                      const TextStyle& style,
228                      const ClipContext& context) const;
229     void paintDecorations(ParagraphPainter* painter,
230                           SkScalar x,
231                           SkScalar y,
232                           TextRange textRange,
233                           const TextStyle& style,
234                           const ClipContext& context) const;
235 
236     void shiftCluster(const Cluster* cluster, SkScalar shift, SkScalar prevShift);
237     void spacingCluster(const Cluster* cluster, SkScalar spacing, SkScalar prevSpacing);
238     bool hasBackgroundRect(const RoundRectAttr& attr);
239     void computeRoundRect(int& index, int& preIndex, std::vector<Run*>& groupRuns, Run* run);
240     void prepareRoundRect();
241     SkScalar calculateThickness(const TextStyle& style, const ClipContext& context);
242 #ifdef OHOS_SUPPORT
243     void measureTextWithSpacesAtTheEnd(ClipContext& context, bool includeGhostSpaces) const;
244     void computeNextPaintGlyphRange(ClipContext& context, const TextRange& lastGlyphRange, StyleType styleType) const;
245     SkRect computeShadowRect(SkScalar x, SkScalar y, const TextStyle& style, const ClipContext& context) const;
246     SkRect getAllShadowsRect(SkScalar x, SkScalar y) const;
247 #endif
248 
249     ParagraphImpl* fOwner;
250     BlockRange fBlockRange;
251     TextRange fTextExcludingSpaces;
252     TextRange fText;
253     TextRange fTextIncludingNewlines;
254     ClusterRange fClusterRange;
255     ClusterRange fGhostClusterRange;
256     // Avoid the malloc/free in the common case of one run per line
257     SkSTArray<1, size_t, true> fRunsInVisualOrder;
258     SkVector fAdvance;                  // Text size
259     SkVector fOffset;                   // Text position
260     SkScalar fShift;                    // Let right
261     SkScalar fWidthWithSpaces;
262     std::unique_ptr<Run> fEllipsis;     // In case the line ends with the ellipsis
263     TextRange fTextRangeReplacedByEllipsis;     // text range replaced by ellipsis
264     InternalLineMetrics fSizes;                 // Line metrics as a max of all run metrics and struts
265     InternalLineMetrics fMaxRunMetrics;         // No struts - need it for GetRectForRange(max height)
266     size_t fEllipsisIndex = EMPTY_INDEX;
267 
268     bool fHasBackground;
269     bool fHasShadows;
270     bool fHasDecorations;
271     bool fIsArcText;
272     bool fArcTextState;
273     bool fLastClipRunLtr;
274 
275     LineMetricStyle fAscentStyle;
276     LineMetricStyle fDescentStyle;
277 
278     struct TextBlobRecord {
279         void paint(ParagraphPainter* painter, SkScalar x, SkScalar y);
280         void paint(ParagraphPainter* painter);
281 
282 #ifndef USE_SKIA_TXT
283         sk_sp<SkTextBlob> fBlob;
284 #else
285         std::shared_ptr<RSTextBlob> fBlob;
286 #endif
287         SkPoint fOffset = SkPoint::Make(0.0f, 0.0f);
288         ParagraphPainter::SkPaintOrID fPaint;
289         SkRect fBounds = SkRect::MakeEmpty();
290         bool fClippingNeeded = false;
291         SkRect fClipRect = SkRect::MakeEmpty();
292 
293         // Extra fields only used for the (experimental) visitor
294         const Run* fVisitor_Run;
295         size_t     fVisitor_Pos;
296         size_t     fVisitor_Size;
297     };
298     bool fTextBlobCachePopulated;
299     DecorationContext fDecorationContext;
300     std::vector<RoundRectAttr> roundRectAttrs = {};
301 public:
302     std::vector<TextBlobRecord> fTextBlobCache;
303 };
304 }  // namespace textlayout
305 }  // namespace skia
306 
307 namespace sknonstd {
308     template <> struct is_bitmask_enum<skia::textlayout::TextLine::TextAdjustment> : std::true_type {};
309 }  // namespace sknonstd
310 
311 #endif  // TextLine_DEFINED
312