xref: /aosp_15_r20/external/skia/modules/skparagraph/src/TextLine.h (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker // Copyright 2019 Google LLC.
2*c8dee2aaSAndroid Build Coastguard Worker #ifndef TextLine_DEFINED
3*c8dee2aaSAndroid Build Coastguard Worker #define TextLine_DEFINED
4*c8dee2aaSAndroid Build Coastguard Worker 
5*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPoint.h"
6*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRect.h"
7*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkScalar.h"
8*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTArray.h"
9*c8dee2aaSAndroid Build Coastguard Worker #include "modules/skparagraph/include/DartTypes.h"
10*c8dee2aaSAndroid Build Coastguard Worker #include "modules/skparagraph/include/Metrics.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "modules/skparagraph/include/ParagraphPainter.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "modules/skparagraph/include/TextStyle.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "modules/skparagraph/src/Run.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkBitmaskEnum.h"
15*c8dee2aaSAndroid Build Coastguard Worker 
16*c8dee2aaSAndroid Build Coastguard Worker #include <stddef.h>
17*c8dee2aaSAndroid Build Coastguard Worker #include <functional>
18*c8dee2aaSAndroid Build Coastguard Worker #include <memory>
19*c8dee2aaSAndroid Build Coastguard Worker #include <vector>
20*c8dee2aaSAndroid Build Coastguard Worker 
21*c8dee2aaSAndroid Build Coastguard Worker class SkString;
22*c8dee2aaSAndroid Build Coastguard Worker 
23*c8dee2aaSAndroid Build Coastguard Worker namespace skia {
24*c8dee2aaSAndroid Build Coastguard Worker namespace textlayout {
25*c8dee2aaSAndroid Build Coastguard Worker 
26*c8dee2aaSAndroid Build Coastguard Worker class ParagraphImpl;
27*c8dee2aaSAndroid Build Coastguard Worker 
28*c8dee2aaSAndroid Build Coastguard Worker class TextLine {
29*c8dee2aaSAndroid Build Coastguard Worker public:
30*c8dee2aaSAndroid Build Coastguard Worker 
31*c8dee2aaSAndroid Build Coastguard Worker     struct ClipContext {
32*c8dee2aaSAndroid Build Coastguard Worker       const Run* run;
33*c8dee2aaSAndroid Build Coastguard Worker       size_t pos;
34*c8dee2aaSAndroid Build Coastguard Worker       size_t size;
35*c8dee2aaSAndroid Build Coastguard Worker       SkScalar fTextShift; // Shifts the text inside the run so it's placed at the right position
36*c8dee2aaSAndroid Build Coastguard Worker       SkRect clip;
37*c8dee2aaSAndroid Build Coastguard Worker       SkScalar fExcludedTrailingSpaces;
38*c8dee2aaSAndroid Build Coastguard Worker       bool clippingNeeded;
39*c8dee2aaSAndroid Build Coastguard Worker     };
40*c8dee2aaSAndroid Build Coastguard Worker 
41*c8dee2aaSAndroid Build Coastguard Worker     enum TextAdjustment {
42*c8dee2aaSAndroid Build Coastguard Worker         GlyphCluster = 0x01,    // All text producing glyphs pointing to the same ClusterIndex
43*c8dee2aaSAndroid Build Coastguard Worker         GlyphemeCluster = 0x02, // base glyph + all attached diacritics
44*c8dee2aaSAndroid Build Coastguard Worker         Grapheme = 0x04,        // Text adjusted to graphemes
45*c8dee2aaSAndroid Build Coastguard Worker         GraphemeGluster = 0x05, // GlyphCluster & Grapheme
46*c8dee2aaSAndroid Build Coastguard Worker     };
47*c8dee2aaSAndroid Build Coastguard Worker 
48*c8dee2aaSAndroid Build Coastguard Worker     TextLine() = default;
49*c8dee2aaSAndroid Build Coastguard Worker     TextLine(const TextLine&) = delete;
50*c8dee2aaSAndroid Build Coastguard Worker     TextLine& operator=(const TextLine&) = delete;
51*c8dee2aaSAndroid Build Coastguard Worker     TextLine(TextLine&&) = default;
52*c8dee2aaSAndroid Build Coastguard Worker     TextLine& operator=(TextLine&&) = default;
53*c8dee2aaSAndroid Build Coastguard Worker     ~TextLine() = default;
54*c8dee2aaSAndroid Build Coastguard Worker 
55*c8dee2aaSAndroid Build Coastguard Worker     TextLine(ParagraphImpl* owner,
56*c8dee2aaSAndroid Build Coastguard Worker              SkVector offset,
57*c8dee2aaSAndroid Build Coastguard Worker              SkVector advance,
58*c8dee2aaSAndroid Build Coastguard Worker              BlockRange blocks,
59*c8dee2aaSAndroid Build Coastguard Worker              TextRange textExcludingSpaces,
60*c8dee2aaSAndroid Build Coastguard Worker              TextRange text,
61*c8dee2aaSAndroid Build Coastguard Worker              TextRange textIncludingNewlines,
62*c8dee2aaSAndroid Build Coastguard Worker              ClusterRange clusters,
63*c8dee2aaSAndroid Build Coastguard Worker              ClusterRange clustersWithGhosts,
64*c8dee2aaSAndroid Build Coastguard Worker              SkScalar widthWithSpaces,
65*c8dee2aaSAndroid Build Coastguard Worker              InternalLineMetrics sizes);
66*c8dee2aaSAndroid Build Coastguard Worker 
trimmedText()67*c8dee2aaSAndroid Build Coastguard Worker     TextRange trimmedText() const { return fTextExcludingSpaces; }
textWithNewlines()68*c8dee2aaSAndroid Build Coastguard Worker     TextRange textWithNewlines() const { return fTextIncludingNewlines; }
text()69*c8dee2aaSAndroid Build Coastguard Worker     TextRange text() const { return fText; }
clusters()70*c8dee2aaSAndroid Build Coastguard Worker     ClusterRange clusters() const { return fClusterRange; }
clustersWithSpaces()71*c8dee2aaSAndroid Build Coastguard Worker     ClusterRange clustersWithSpaces() const { return fGhostClusterRange; }
ellipsis()72*c8dee2aaSAndroid Build Coastguard Worker     Run* ellipsis() const { return fEllipsis.get(); }
sizes()73*c8dee2aaSAndroid Build Coastguard Worker     InternalLineMetrics sizes() const { return fSizes; }
empty()74*c8dee2aaSAndroid Build Coastguard Worker     bool empty() const { return fTextExcludingSpaces.empty(); }
75*c8dee2aaSAndroid Build Coastguard Worker 
spacesWidth()76*c8dee2aaSAndroid Build Coastguard Worker     SkScalar spacesWidth() const { return fWidthWithSpaces - width(); }
height()77*c8dee2aaSAndroid Build Coastguard Worker     SkScalar height() const { return fAdvance.fY; }
width()78*c8dee2aaSAndroid Build Coastguard Worker     SkScalar width() const {
79*c8dee2aaSAndroid Build Coastguard Worker         return fAdvance.fX + (fEllipsis != nullptr ? fEllipsis->fAdvance.fX : 0);
80*c8dee2aaSAndroid Build Coastguard Worker     }
widthWithoutEllipsis()81*c8dee2aaSAndroid Build Coastguard Worker     SkScalar widthWithoutEllipsis() const { return fAdvance.fX; }
82*c8dee2aaSAndroid Build Coastguard Worker     SkVector offset() const;
83*c8dee2aaSAndroid Build Coastguard Worker 
alphabeticBaseline()84*c8dee2aaSAndroid Build Coastguard Worker     SkScalar alphabeticBaseline() const { return fSizes.alphabeticBaseline(); }
ideographicBaseline()85*c8dee2aaSAndroid Build Coastguard Worker     SkScalar ideographicBaseline() const { return fSizes.ideographicBaseline(); }
baseline()86*c8dee2aaSAndroid Build Coastguard Worker     SkScalar baseline() const { return fSizes.baseline(); }
87*c8dee2aaSAndroid Build Coastguard Worker 
88*c8dee2aaSAndroid Build Coastguard Worker     using RunVisitor = std::function<bool(
89*c8dee2aaSAndroid Build Coastguard Worker             const Run* run, SkScalar runOffset, TextRange textRange, SkScalar* width)>;
90*c8dee2aaSAndroid Build Coastguard Worker     void iterateThroughVisualRuns(bool includingGhostSpaces, const RunVisitor& runVisitor) const;
91*c8dee2aaSAndroid Build Coastguard Worker     using RunStyleVisitor = std::function<void(
92*c8dee2aaSAndroid Build Coastguard Worker             TextRange textRange, const TextStyle& style, const ClipContext& context)>;
93*c8dee2aaSAndroid Build Coastguard Worker     SkScalar iterateThroughSingleRunByStyles(TextAdjustment textAdjustment,
94*c8dee2aaSAndroid Build Coastguard Worker                                              const Run* run,
95*c8dee2aaSAndroid Build Coastguard Worker                                              SkScalar runOffset,
96*c8dee2aaSAndroid Build Coastguard Worker                                              TextRange textRange,
97*c8dee2aaSAndroid Build Coastguard Worker                                              StyleType styleType,
98*c8dee2aaSAndroid Build Coastguard Worker                                              const RunStyleVisitor& visitor) const;
99*c8dee2aaSAndroid Build Coastguard Worker 
100*c8dee2aaSAndroid Build Coastguard Worker     using ClustersVisitor = std::function<bool(const Cluster* cluster, ClusterIndex index, bool ghost)>;
101*c8dee2aaSAndroid Build Coastguard Worker     void iterateThroughClustersInGlyphsOrder(bool reverse,
102*c8dee2aaSAndroid Build Coastguard Worker                                              bool includeGhosts,
103*c8dee2aaSAndroid Build Coastguard Worker                                              const ClustersVisitor& visitor) const;
104*c8dee2aaSAndroid Build Coastguard Worker 
105*c8dee2aaSAndroid Build Coastguard Worker     void format(TextAlign align, SkScalar maxWidth);
106*c8dee2aaSAndroid Build Coastguard Worker     void paint(ParagraphPainter* painter, SkScalar x, SkScalar y);
107*c8dee2aaSAndroid Build Coastguard Worker     void visit(SkScalar x, SkScalar y);
108*c8dee2aaSAndroid Build Coastguard Worker     void ensureTextBlobCachePopulated();
109*c8dee2aaSAndroid Build Coastguard Worker 
110*c8dee2aaSAndroid Build Coastguard Worker     void createEllipsis(SkScalar maxWidth, const SkString& ellipsis, bool ltr);
111*c8dee2aaSAndroid Build Coastguard Worker 
112*c8dee2aaSAndroid Build Coastguard Worker     // For testing internal structures
113*c8dee2aaSAndroid Build Coastguard Worker     void scanStyles(StyleType style, const RunStyleVisitor& visitor);
114*c8dee2aaSAndroid Build Coastguard Worker 
setMaxRunMetrics(const InternalLineMetrics & metrics)115*c8dee2aaSAndroid Build Coastguard Worker     void setMaxRunMetrics(const InternalLineMetrics& metrics) { fMaxRunMetrics = metrics; }
getMaxRunMetrics()116*c8dee2aaSAndroid Build Coastguard Worker     InternalLineMetrics getMaxRunMetrics() const { return fMaxRunMetrics; }
117*c8dee2aaSAndroid Build Coastguard Worker 
118*c8dee2aaSAndroid Build Coastguard Worker     bool isFirstLine() const;
119*c8dee2aaSAndroid Build Coastguard Worker     bool isLastLine() const;
120*c8dee2aaSAndroid Build Coastguard Worker     void getRectsForRange(TextRange textRange,
121*c8dee2aaSAndroid Build Coastguard Worker                           RectHeightStyle rectHeightStyle,
122*c8dee2aaSAndroid Build Coastguard Worker                           RectWidthStyle rectWidthStyle,
123*c8dee2aaSAndroid Build Coastguard Worker                           std::vector<TextBox>& boxes) const;
124*c8dee2aaSAndroid Build Coastguard Worker     void getRectsForPlaceholders(std::vector<TextBox>& boxes);
125*c8dee2aaSAndroid Build Coastguard Worker     PositionWithAffinity getGlyphPositionAtCoordinate(SkScalar dx);
126*c8dee2aaSAndroid Build Coastguard Worker 
127*c8dee2aaSAndroid Build Coastguard Worker     ClipContext measureTextInsideOneRun(TextRange textRange,
128*c8dee2aaSAndroid Build Coastguard Worker                                         const Run* run,
129*c8dee2aaSAndroid Build Coastguard Worker                                         SkScalar runOffsetInLine,
130*c8dee2aaSAndroid Build Coastguard Worker                                         SkScalar textOffsetInRunInLine,
131*c8dee2aaSAndroid Build Coastguard Worker                                         bool includeGhostSpaces,
132*c8dee2aaSAndroid Build Coastguard Worker                                         TextAdjustment textAdjustment) const;
133*c8dee2aaSAndroid Build Coastguard Worker 
134*c8dee2aaSAndroid Build Coastguard Worker     LineMetrics getMetrics() const;
135*c8dee2aaSAndroid Build Coastguard Worker 
136*c8dee2aaSAndroid Build Coastguard Worker     SkRect extendHeight(const ClipContext& context) const;
137*c8dee2aaSAndroid Build Coastguard Worker 
shiftVertically(SkScalar shift)138*c8dee2aaSAndroid Build Coastguard Worker     void shiftVertically(SkScalar shift) { fOffset.fY += shift; }
139*c8dee2aaSAndroid Build Coastguard Worker 
setAscentStyle(LineMetricStyle style)140*c8dee2aaSAndroid Build Coastguard Worker     void setAscentStyle(LineMetricStyle style) { fAscentStyle = style; }
setDescentStyle(LineMetricStyle style)141*c8dee2aaSAndroid Build Coastguard Worker     void setDescentStyle(LineMetricStyle style) { fDescentStyle = style; }
142*c8dee2aaSAndroid Build Coastguard Worker 
143*c8dee2aaSAndroid Build Coastguard Worker     bool endsWithHardLineBreak() const;
144*c8dee2aaSAndroid Build Coastguard Worker 
145*c8dee2aaSAndroid Build Coastguard Worker private:
146*c8dee2aaSAndroid Build Coastguard Worker     std::unique_ptr<Run> shapeEllipsis(const SkString& ellipsis, const Cluster* cluster);
147*c8dee2aaSAndroid Build Coastguard Worker     void justify(SkScalar maxWidth);
148*c8dee2aaSAndroid Build Coastguard Worker 
149*c8dee2aaSAndroid Build Coastguard Worker     void buildTextBlob(TextRange textRange, const TextStyle& style, const ClipContext& context);
150*c8dee2aaSAndroid Build Coastguard Worker     void paintBackground(ParagraphPainter* painter,
151*c8dee2aaSAndroid Build Coastguard Worker                          SkScalar x,
152*c8dee2aaSAndroid Build Coastguard Worker                          SkScalar y,
153*c8dee2aaSAndroid Build Coastguard Worker                          TextRange textRange,
154*c8dee2aaSAndroid Build Coastguard Worker                          const TextStyle& style,
155*c8dee2aaSAndroid Build Coastguard Worker                          const ClipContext& context) const;
156*c8dee2aaSAndroid Build Coastguard Worker     void paintShadow(ParagraphPainter* painter,
157*c8dee2aaSAndroid Build Coastguard Worker                      SkScalar x,
158*c8dee2aaSAndroid Build Coastguard Worker                      SkScalar y,
159*c8dee2aaSAndroid Build Coastguard Worker                      TextRange textRange,
160*c8dee2aaSAndroid Build Coastguard Worker                      const TextStyle& style,
161*c8dee2aaSAndroid Build Coastguard Worker                      const ClipContext& context) const;
162*c8dee2aaSAndroid Build Coastguard Worker     void paintDecorations(ParagraphPainter* painter,
163*c8dee2aaSAndroid Build Coastguard Worker                           SkScalar x,
164*c8dee2aaSAndroid Build Coastguard Worker                           SkScalar y,
165*c8dee2aaSAndroid Build Coastguard Worker                           TextRange textRange,
166*c8dee2aaSAndroid Build Coastguard Worker                           const TextStyle& style,
167*c8dee2aaSAndroid Build Coastguard Worker                           const ClipContext& context) const;
168*c8dee2aaSAndroid Build Coastguard Worker 
169*c8dee2aaSAndroid Build Coastguard Worker     void shiftCluster(const Cluster* cluster, SkScalar shift, SkScalar prevShift);
170*c8dee2aaSAndroid Build Coastguard Worker 
171*c8dee2aaSAndroid Build Coastguard Worker     ParagraphImpl* fOwner;
172*c8dee2aaSAndroid Build Coastguard Worker     BlockRange fBlockRange;
173*c8dee2aaSAndroid Build Coastguard Worker     TextRange fTextExcludingSpaces;
174*c8dee2aaSAndroid Build Coastguard Worker     TextRange fText;
175*c8dee2aaSAndroid Build Coastguard Worker     TextRange fTextIncludingNewlines;
176*c8dee2aaSAndroid Build Coastguard Worker     ClusterRange fClusterRange;
177*c8dee2aaSAndroid Build Coastguard Worker     ClusterRange fGhostClusterRange;
178*c8dee2aaSAndroid Build Coastguard Worker     // Avoid the malloc/free in the common case of one run per line
179*c8dee2aaSAndroid Build Coastguard Worker     skia_private::STArray<1, size_t, true> fRunsInVisualOrder;
180*c8dee2aaSAndroid Build Coastguard Worker     SkVector fAdvance;                  // Text size
181*c8dee2aaSAndroid Build Coastguard Worker     SkVector fOffset;                   // Text position
182*c8dee2aaSAndroid Build Coastguard Worker     SkScalar fShift;                    // Let right
183*c8dee2aaSAndroid Build Coastguard Worker     SkScalar fWidthWithSpaces;
184*c8dee2aaSAndroid Build Coastguard Worker     std::unique_ptr<Run> fEllipsis;     // In case the line ends with the ellipsis
185*c8dee2aaSAndroid Build Coastguard Worker     InternalLineMetrics fSizes;                 // Line metrics as a max of all run metrics and struts
186*c8dee2aaSAndroid Build Coastguard Worker     InternalLineMetrics fMaxRunMetrics;         // No struts - need it for GetRectForRange(max height)
187*c8dee2aaSAndroid Build Coastguard Worker     bool fHasBackground;
188*c8dee2aaSAndroid Build Coastguard Worker     bool fHasShadows;
189*c8dee2aaSAndroid Build Coastguard Worker     bool fHasDecorations;
190*c8dee2aaSAndroid Build Coastguard Worker 
191*c8dee2aaSAndroid Build Coastguard Worker     LineMetricStyle fAscentStyle;
192*c8dee2aaSAndroid Build Coastguard Worker     LineMetricStyle fDescentStyle;
193*c8dee2aaSAndroid Build Coastguard Worker 
194*c8dee2aaSAndroid Build Coastguard Worker     struct TextBlobRecord {
195*c8dee2aaSAndroid Build Coastguard Worker         void paint(ParagraphPainter* painter, SkScalar x, SkScalar y);
196*c8dee2aaSAndroid Build Coastguard Worker 
197*c8dee2aaSAndroid Build Coastguard Worker         sk_sp<SkTextBlob> fBlob;
198*c8dee2aaSAndroid Build Coastguard Worker         SkPoint fOffset = SkPoint::Make(0.0f, 0.0f);
199*c8dee2aaSAndroid Build Coastguard Worker         ParagraphPainter::SkPaintOrID fPaint;
200*c8dee2aaSAndroid Build Coastguard Worker         SkRect fBounds = SkRect::MakeEmpty();
201*c8dee2aaSAndroid Build Coastguard Worker         bool fClippingNeeded = false;
202*c8dee2aaSAndroid Build Coastguard Worker         SkRect fClipRect = SkRect::MakeEmpty();
203*c8dee2aaSAndroid Build Coastguard Worker 
204*c8dee2aaSAndroid Build Coastguard Worker         // Extra fields only used for the (experimental) visitor
205*c8dee2aaSAndroid Build Coastguard Worker         const Run* fVisitor_Run;
206*c8dee2aaSAndroid Build Coastguard Worker         size_t     fVisitor_Pos;
207*c8dee2aaSAndroid Build Coastguard Worker     };
208*c8dee2aaSAndroid Build Coastguard Worker     bool fTextBlobCachePopulated;
209*c8dee2aaSAndroid Build Coastguard Worker public:
210*c8dee2aaSAndroid Build Coastguard Worker     std::vector<TextBlobRecord> fTextBlobCache;
211*c8dee2aaSAndroid Build Coastguard Worker };
212*c8dee2aaSAndroid Build Coastguard Worker }  // namespace textlayout
213*c8dee2aaSAndroid Build Coastguard Worker }  // namespace skia
214*c8dee2aaSAndroid Build Coastguard Worker 
215*c8dee2aaSAndroid Build Coastguard Worker namespace sknonstd {
216*c8dee2aaSAndroid Build Coastguard Worker     template <> struct is_bitmask_enum<skia::textlayout::TextLine::TextAdjustment> : std::true_type {};
217*c8dee2aaSAndroid Build Coastguard Worker }  // namespace sknonstd
218*c8dee2aaSAndroid Build Coastguard Worker 
219*c8dee2aaSAndroid Build Coastguard Worker #endif  // TextLine_DEFINED
220