1// Copyright 2019 Google LLC.
2#ifndef TextLine_DEFINED
3#define TextLine_DEFINED
4
5#include "include/core/SkPoint.h"
6#include "include/core/SkRect.h"
7#include "include/core/SkScalar.h"
8#include "include/private/SkTArray.h"
9#include "modules/skparagraph/include/DartTypes.h"
10#include "modules/skparagraph/include/Metrics.h"
11#include "modules/skparagraph/include/TextStyle.h"
12#include "modules/skparagraph/src/Run.h"
13
14#include <stddef.h>
15#include <functional>
16#include <memory>
17#include <vector>
18
19class SkCanvas;
20class SkString;
21
22namespace skia {
23namespace textlayout {
24
25class ParagraphImpl;
26
27class TextLine {
28public:
29
30 struct ClipContext {
31 const Run* run;
32 size_t pos;
33 size_t size;
34 SkScalar fTextShift; // Shifts the text inside the run so it's placed at the right position
35 SkRect clip;
36 bool clippingNeeded;
37 };
38
39 TextLine() = default;
40 TextLine(const TextLine&) = delete;
41 TextLine& operator=(const TextLine&) = delete;
42 TextLine(TextLine&&) = default;
43 TextLine& operator=(TextLine&&) = default;
44 ~TextLine() = default;
45
46 TextLine(ParagraphImpl* owner,
47 SkVector offset,
48 SkVector advance,
49 BlockRange blocks,
50 TextRange text,
51 TextRange textWithSpaces,
52 ClusterRange clusters,
53 ClusterRange clustersWithGhosts,
54 SkScalar widthWithSpaces,
55 InternalLineMetrics sizes);
56
57 TextRange trimmedText() const { return fTextRange; }
58 TextRange textWithSpaces() const { return fTextWithWhitespacesRange; }
59 ClusterRange clusters() const { return fClusterRange; }
60 ClusterRange clustersWithSpaces() { return fGhostClusterRange; }
61 Run* ellipsis() const { return fEllipsis.get(); }
62 InternalLineMetrics sizes() const { return fSizes; }
63 bool empty() const { return fTextRange.empty(); }
64
65 SkScalar spacesWidth() { return fWidthWithSpaces - width(); }
66 SkScalar height() const { return fAdvance.fY; }
67 SkScalar width() const {
68 return fAdvance.fX + (fEllipsis != nullptr ? fEllipsis->fAdvance.fX : 0);
69 }
70 SkScalar shift() const { return fShift; }
71 SkVector offset() const;
72
73 SkScalar alphabeticBaseline() const { return fSizes.alphabeticBaseline(); }
74 SkScalar ideographicBaseline() const { return fSizes.ideographicBaseline(); }
75 SkScalar baseline() const { return fSizes.baseline(); }
76
77 using RunVisitor = std::function<bool(const Run* run, SkScalar runOffset, TextRange textRange, SkScalar* width)>;
78 void iterateThroughVisualRuns(bool includingGhostSpaces, const RunVisitor& runVisitor) const;
79 using RunStyleVisitor = std::function<void(TextRange textRange, const TextStyle& style, const ClipContext& context)>;
80 SkScalar iterateThroughSingleRunByStyles(const Run* run, SkScalar runOffset, TextRange textRange,
81 StyleType styleType, const RunStyleVisitor& visitor) const;
82
83 using ClustersVisitor = std::function<bool(const Cluster* cluster, bool ghost)>;
84 void iterateThroughClustersInGlyphsOrder(bool reverse, bool includeGhosts, const ClustersVisitor& visitor) const;
85
86 void format(TextAlign align, SkScalar maxWidth);
87 void paint(SkCanvas* canvas);
88
89 void createEllipsis(SkScalar maxWidth, const SkString& ellipsis, bool ltr);
90
91 // For testing internal structures
92 void scanStyles(StyleType style, const RunStyleVisitor& visitor);
93
94 void setMaxRunMetrics(const InternalLineMetrics& metrics) { fMaxRunMetrics = metrics; }
95 InternalLineMetrics getMaxRunMetrics() const { return fMaxRunMetrics; }
96
97 bool isFirstLine();
98 bool isLastLine();
99 void getRectsForRange(TextRange textRange, RectHeightStyle rectHeightStyle, RectWidthStyle rectWidthStyle, std::vector<TextBox>& boxes);
100 void getRectsForPlaceholders(std::vector<TextBox>& boxes);
101 PositionWithAffinity getGlyphPositionAtCoordinate(SkScalar dx);
102
103 ClipContext measureTextInsideOneRun(TextRange textRange,
104 const Run* run,
105 SkScalar runOffsetInLine,
106 SkScalar textOffsetInRunInLine,
107 bool includeGhostSpaces,
108 bool limitToClusters) const;
109
110 LineMetrics getMetrics() const;
111
112 SkRect calculateBoundaries();
113
114 SkRect extendHeight(const ClipContext& context) const;
115
116 SkScalar metricsWithoutMultiplier(TextHeightBehavior correction);
117 void shiftVertically(SkScalar shift) { fOffset.fY += shift; }
118
119 bool endsWithHardLineBreak() const;
120
121private:
122
123 std::unique_ptr<Run> shapeEllipsis(const SkString& ellipsis, Run* run);
124 void justify(SkScalar maxWidth);
125
126 void paintText(SkCanvas* canvas, TextRange textRange, const TextStyle& style, const ClipContext& context) const;
127 void paintBackground(SkCanvas* canvas, TextRange textRange, const TextStyle& style, const ClipContext& context) const;
128 void paintShadow(SkCanvas* canvas, TextRange textRange, const TextStyle& style, const ClipContext& context) const;
129 void paintDecorations(SkCanvas* canvas, TextRange textRange, const TextStyle& style, const ClipContext& context) const;
130
131 void shiftCluster(const Cluster* cluster, SkScalar shift, SkScalar prevShift);
132
133 ParagraphImpl* fOwner;
134 BlockRange fBlockRange;
135 TextRange fTextRange;
136 TextRange fTextWithWhitespacesRange;
137 ClusterRange fClusterRange;
138 ClusterRange fGhostClusterRange;
139 // Avoid the malloc/free in the common case of one run per line
140 SkSTArray<1, size_t, true> fRunsInVisualOrder;
141 SkVector fAdvance; // Text size
142 SkVector fOffset; // Text position
143 SkScalar fShift; // Let right
144 SkScalar fWidthWithSpaces;
145 std::unique_ptr<Run> fEllipsis; // In case the line ends with the ellipsis
146 InternalLineMetrics fSizes; // Line metrics as a max of all run metrics and struts
147 InternalLineMetrics fMaxRunMetrics; // No struts - need it for GetRectForRange(max height)
148 bool fHasBackground;
149 bool fHasShadows;
150 bool fHasDecorations;
151
152 LineMetricStyle fAscentStyle;
153 LineMetricStyle fDescentStyle;
154};
155} // namespace textlayout
156} // namespace skia
157
158#endif // TextLine_DEFINED
159