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