blob: de71e385998f75b5305ca53f672de1ff8c225cc2 [file] [log] [blame]
Julia Lavrovaa3552c52019-05-30 16:12:56 -04001// Copyright 2019 Google LLC.
2#ifndef TextLine_DEFINED
3#define TextLine_DEFINED
4
5#include "modules/skparagraph/src/Run.h"
6#include "include/core/SkCanvas.h"
7#include "include/private/SkTArray.h"
8#include "include/private/SkTHash.h"
9#include "modules/skparagraph/include/DartTypes.h"
10#include "modules/skparagraph/include/TextStyle.h"
11#include "src/core/SkSpan.h"
12
13namespace skia {
14namespace textlayout {
15
16class TextBlock {
17public:
18 TextBlock() : fText(), fTextStyle() {}
19 TextBlock(SkSpan<const char> text, const TextStyle& style) : fText(text), fTextStyle(style) {}
20
21 SkSpan<const char> text() const { return fText; }
22 TextStyle style() const { return fTextStyle; }
23
24 void add(SkSpan<const char> tail) {
25 SkASSERT(fText.end() == tail.begin());
26 fText = SkSpan<const char>(fText.begin(), fText.size() + tail.size());
27 }
28
29protected:
30 SkSpan<const char> fText;
31 TextStyle fTextStyle;
32};
33
34class TextLine {
35public:
36 TextLine() = default;
37 TextLine(TextLine&&);
38 ~TextLine() = default;
39
40 TextLine(SkVector offset, SkVector advance, SkSpan<const TextBlock> blocks,
41 SkSpan<const char> text, SkSpan<const char> textWithSpaces,
42 SkSpan<const Cluster> clusters, size_t start, size_t end, LineMetrics sizes);
43
44 SkSpan<const char> trimmedText() const { return fText; }
45 SkSpan<const char> textWithSpaces() const { return fTextWithSpaces; }
46 SkSpan<const Cluster> clusters() const { return fClusters; }
47 SkVector offset() const { return fOffset + SkVector::Make(fShift, 0); }
48 Run* ellipsis() const { return fEllipsis.get(); }
49 LineMetrics sizes() const { return fSizes; }
50 bool empty() const { return fText.empty(); }
51
52 SkScalar shift() const { return fShift; }
53 SkScalar height() const { return fAdvance.fY; }
54 SkScalar width() const {
55 return fAdvance.fX + (fEllipsis != nullptr ? fEllipsis->fAdvance.fX : 0);
56 }
57 void shiftTo(SkScalar shift) { fShift = shift; }
58
59 SkScalar alphabeticBaseline() const { return fSizes.alphabeticBaseline(); }
60 SkScalar ideographicBaseline() const { return fSizes.ideographicBaseline(); }
61 SkScalar baseline() const { return fSizes.baseline(); }
62 SkScalar roundingDelta() const { return fSizes.delta(); }
63
64 using StyleVisitor = std::function<SkScalar(SkSpan<const char> text, const TextStyle& style,
65 SkScalar offsetX)>;
66 void iterateThroughStylesInTextOrder(StyleType styleType, const StyleVisitor& visitor) const;
67
68 using RunVisitor = std::function<bool(Run* run, size_t pos, size_t size, SkRect clip,
69 SkScalar shift, bool clippingNeeded)>;
70 SkScalar iterateThroughRuns(SkSpan<const char> text,
71 SkScalar offsetX,
72 bool includeEmptyText,
73 const RunVisitor& visitor) const;
74
75 using ClustersVisitor = std::function<bool(const Cluster* cluster)>;
76 void iterateThroughClustersInGlyphsOrder(bool reverse, const ClustersVisitor& visitor) const;
77
78 void format(TextAlign effectiveAlign, SkScalar maxWidth, bool last);
79 void paint(SkCanvas* canvas);
80
81 void createEllipsis(SkScalar maxWidth, const SkString& ellipsis, bool ltr);
82
83 // For testing internal structures
84 void scanStyles(StyleType style, const StyleVisitor& visitor);
85 void scanRuns(const RunVisitor& visitor);
86
87private:
88 Run* shapeEllipsis(const SkString& ellipsis, Run* run);
89 void justify(SkScalar maxWidth);
90
91 SkRect measureTextInsideOneRun(SkSpan<const char> text,
92 Run* run,
93 size_t& pos,
94 size_t& size,
95 bool& clippingNeeded) const;
96
97 SkScalar paintText(SkCanvas* canvas, SkSpan<const char> text, const TextStyle& style,
98 SkScalar offsetX) const;
99 SkScalar paintBackground(SkCanvas* canvas, SkSpan<const char> text, const TextStyle& style,
100 SkScalar offsetX) const;
101 SkScalar paintShadow(SkCanvas* canvas, SkSpan<const char> text, const TextStyle& style,
102 SkScalar offsetX) const;
103 SkScalar paintDecorations(SkCanvas* canvas, SkSpan<const char> text, const TextStyle& style,
104 SkScalar offsetX) const;
105
106 void computeDecorationPaint(SkPaint& paint, SkRect clip, const TextStyle& style,
107 SkPath& path) const;
108
109 bool contains(const Cluster* cluster) const {
110 return cluster->text().begin() >= fText.begin() && cluster->text().end() <= fText.end();
111 }
112
113 SkSpan<const TextBlock> fBlocks;
114 SkSpan<const char> fText;
115 SkSpan<const char> fTextWithSpaces;
116 SkSpan<const Cluster> fClusters;
117 // TODO: To clip by glyph:
118 //size_t fStartPos;
119 //size_t fEndPos;
120 SkTArray<Run*, true> fLogical;
121 SkScalar fShift; // Shift to left - right - center
122 SkVector fAdvance; // Text size
123 SkVector fOffset; // Text position
124 std::unique_ptr<Run> fEllipsis; // In case the line ends with the ellipsis
125 LineMetrics fSizes; // Line metrics as a max of all run metrics
126
127 static SkTHashMap<SkFont, Run> fEllipsisCache; // All found so far shapes of ellipsis
128};
129} // namespace textlayout
130} // namespace skia
131
132#endif // TextLine_DEFINED