1// Copyright 2019 Google LLC.
2#ifndef ParagraphImpl_DEFINED
3#define ParagraphImpl_DEFINED
4
5#include "include/core/SkFont.h"
6#include "include/core/SkPaint.h"
7#include "include/core/SkPicture.h"
8#include "include/core/SkPoint.h"
9#include "include/core/SkRect.h"
10#include "include/core/SkRefCnt.h"
11#include "include/core/SkScalar.h"
12#include "include/core/SkString.h"
13#include "include/core/SkTypes.h"
14#include "include/private/SkBitmaskEnum.h"
15#include "include/private/SkTArray.h"
16#include "include/private/SkTHash.h"
17#include "include/private/SkTemplates.h"
18#include "modules/skparagraph/include/DartTypes.h"
19#include "modules/skparagraph/include/FontCollection.h"
20#include "modules/skparagraph/include/Paragraph.h"
21#include "modules/skparagraph/include/ParagraphCache.h"
22#include "modules/skparagraph/include/ParagraphStyle.h"
23#include "modules/skparagraph/include/TextShadow.h"
24#include "modules/skparagraph/include/TextStyle.h"
25#include "modules/skparagraph/src/Run.h"
26#include "modules/skparagraph/src/TextLine.h"
27#include "modules/skshaper/src/SkUnicode.h"
28#include "src/core/SkSpan.h"
29
30#include <memory>
31#include <string>
32#include <vector>
33
34class SkCanvas;
35
36namespace skia {
37namespace textlayout {
38
39enum CodeUnitFlags {
40 kNoCodeUnitFlag = 0x0,
41 kPartOfWhiteSpace = 0x1,
42 kGraphemeStart = 0x2,
43 kSoftLineBreakBefore = 0x4,
44 kHardLineBreakBefore = 0x8,
45};
46} // namespace textlayout
47} // namespace skia
48
49namespace sknonstd {
50template <> struct is_bitmask_enum<skia::textlayout::CodeUnitFlags> : std::true_type {};
51} // namespace sknonstd
52
53namespace skia {
54namespace textlayout {
55
56class LineMetrics;
57class TextLine;
58
59template <typename T> bool operator==(const SkSpan<T>& a, const SkSpan<T>& b) {
60 return a.size() == b.size() && a.begin() == b.begin();
61}
62
63template <typename T> bool operator<=(const SkSpan<T>& a, const SkSpan<T>& b) {
64 return a.begin() >= b.begin() && a.end() <= b.end();
65}
66
67template <typename TStyle>
68struct StyleBlock {
69 StyleBlock() : fRange(EMPTY_RANGE), fStyle() { }
70 StyleBlock(size_t start, size_t end, const TStyle& style) : fRange(start, end), fStyle(style) {}
71 StyleBlock(TextRange textRange, const TStyle& style) : fRange(textRange), fStyle(style) {}
72 void add(TextRange tail) {
73 SkASSERT(fRange.end == tail.start);
74 fRange = TextRange(fRange.start, fRange.start + fRange.width() + tail.width());
75 }
76 TextRange fRange;
77 TStyle fStyle;
78};
79
80struct ResolvedFontDescriptor {
81
82 ResolvedFontDescriptor(TextIndex index, SkFont font)
83 : fFont(font), fTextStart(index) { }
84 SkFont fFont;
85 TextIndex fTextStart;
86};
87/*
88struct BidiRegion {
89 BidiRegion(size_t start, size_t end, uint8_t dir)
90 : text(start, end), direction(dir) { }
91 TextRange text;
92 uint8_t direction;
93};
94*/
95class ParagraphImpl final : public Paragraph {
96
97public:
98
99 ParagraphImpl(const SkString& text,
100 ParagraphStyle style,
101 SkTArray<Block, true> blocks,
102 SkTArray<Placeholder, true> placeholders,
103 sk_sp<FontCollection> fonts);
104
105 ParagraphImpl(const std::u16string& utf16text,
106 ParagraphStyle style,
107 SkTArray<Block, true> blocks,
108 SkTArray<Placeholder, true> placeholders,
109 sk_sp<FontCollection> fonts);
110 ~ParagraphImpl() override;
111
112 void layout(SkScalar width) override;
113 void paint(SkCanvas* canvas, SkScalar x, SkScalar y) override;
114 std::vector<TextBox> getRectsForRange(unsigned start,
115 unsigned end,
116 RectHeightStyle rectHeightStyle,
117 RectWidthStyle rectWidthStyle) override;
118 std::vector<TextBox> getRectsForPlaceholders() override;
119 void getLineMetrics(std::vector<LineMetrics>&) override;
120 PositionWithAffinity getGlyphPositionAtCoordinate(SkScalar dx, SkScalar dy) override;
121 SkRange<size_t> getWordBoundary(unsigned offset) override;
122
123 size_t lineNumber() override { return fLines.size(); }
124
125 TextLine& addLine(SkVector offset, SkVector advance, TextRange text, TextRange textWithSpaces,
126 ClusterRange clusters, ClusterRange clustersWithGhosts, SkScalar widthWithSpaces,
127 InternalLineMetrics sizes);
128
129 SkSpan<const char> text() const { return SkSpan<const char>(fText.c_str(), fText.size()); }
130 InternalState state() const { return fState; }
131 SkSpan<Run> runs() { return SkSpan<Run>(fRuns.data(), fRuns.size()); }
132 SkSpan<Block> styles() {
133 return SkSpan<Block>(fTextStyles.data(), fTextStyles.size());
134 }
135 SkSpan<Placeholder> placeholders() {
136 return SkSpan<Placeholder>(fPlaceholders.data(), fPlaceholders.size());
137 }
138 SkSpan<TextLine> lines() { return SkSpan<TextLine>(fLines.data(), fLines.size()); }
139 const ParagraphStyle& paragraphStyle() const { return fParagraphStyle; }
140 SkSpan<Cluster> clusters() { return SkSpan<Cluster>(fClusters.begin(), fClusters.size()); }
141 sk_sp<FontCollection> fontCollection() const { return fFontCollection; }
142 void formatLines(SkScalar maxWidth);
143 void ensureUTF16Mapping();
144 TextIndex findGraphemeStart(TextIndex index);
145 size_t getUTF16Index(TextIndex index) {
146 return fUTF16IndexForUTF8Index[index];
147 }
148
149 bool strutEnabled() const { return paragraphStyle().getStrutStyle().getStrutEnabled(); }
150 bool strutForceHeight() const {
151 return paragraphStyle().getStrutStyle().getForceStrutHeight();
152 }
153 bool strutHeightOverride() const {
154 return paragraphStyle().getStrutStyle().getHeightOverride();
155 }
156 InternalLineMetrics strutMetrics() const { return fStrutMetrics; }
157
158 SkSpan<const char> text(TextRange textRange);
159 SkSpan<Cluster> clusters(ClusterRange clusterRange);
160 Cluster& cluster(ClusterIndex clusterIndex);
161 ClusterIndex clusterIndex(TextIndex textIndex) {
162 auto clusterIndex = this->fClustersIndexFromCodeUnit[textIndex];
163 SkASSERT(clusterIndex != EMPTY_INDEX);
164 return clusterIndex;
165 }
166 Run& run(RunIndex runIndex) {
167 SkASSERT(runIndex < fRuns.size());
168 return fRuns[runIndex];
169 }
170
171 Run& runByCluster(ClusterIndex clusterIndex);
172 SkSpan<Block> blocks(BlockRange blockRange);
173 Block& block(BlockIndex blockIndex);
174 SkTArray<ResolvedFontDescriptor> resolvedFonts() const { return fFontSwitches; }
175
176 void markDirty() override { fState = kUnknown; }
177
178 int32_t unresolvedGlyphs() override;
179
180 void setState(InternalState state);
181 sk_sp<SkPicture> getPicture() { return fPicture; }
182 SkRect getBoundaries() const { return fOrigin; }
183
184 SkScalar widthWithTrailingSpaces() { return fMaxWidthWithTrailingSpaces; }
185
186 void resetContext();
187 void resolveStrut();
188
189 bool computeCodeUnitProperties();
190
191 void buildClusterTable();
192 void spaceGlyphs();
193 bool shapeTextIntoEndlessLine();
194 void breakShapedTextIntoLines(SkScalar maxWidth);
195 void paintLinesIntoPicture();
196
197 void updateTextAlign(TextAlign textAlign) override;
198 void updateText(size_t from, SkString text) override;
199 void updateFontSize(size_t from, size_t to, SkScalar fontSize) override;
200 void updateForegroundPaint(size_t from, size_t to, SkPaint paint) override;
201 void updateBackgroundPaint(size_t from, size_t to, SkPaint paint) override;
202
203 InternalLineMetrics getEmptyMetrics() const { return fEmptyMetrics; }
204 InternalLineMetrics getStrutMetrics() const { return fStrutMetrics; }
205
206 BlockRange findAllBlocks(TextRange textRange);
207
208 void resetShifts() {
209 for (auto& run : fRuns) {
210 run.resetJustificationShifts();
211 run.resetShifts();
212 }
213 }
214
215 using CodeUnitRangeVisitor = std::function<bool(TextRange textRange)>;
216 void forEachCodeUnitPropertyRange(CodeUnitFlags property, CodeUnitRangeVisitor visitor);
217 size_t getWhitespacesLength(TextRange textRange);
218
219 bool codeUnitHasProperty(size_t index, CodeUnitFlags property) const { return (fCodeUnitProperties[index] & property) == property; }
220
221 SkUnicode* getICU() { return fICU.get(); }
222
223private:
224 friend class ParagraphBuilder;
225 friend class ParagraphCacheKey;
226 friend class ParagraphCacheValue;
227 friend class ParagraphCache;
228
229 friend class TextWrapper;
230 friend class OneLineShaper;
231
232 void calculateBoundaries();
233
234 void computeEmptyMetrics();
235
236 // Input
237 SkTArray<StyleBlock<SkScalar>> fLetterSpaceStyles;
238 SkTArray<StyleBlock<SkScalar>> fWordSpaceStyles;
239 SkTArray<StyleBlock<SkPaint>> fBackgroundStyles;
240 SkTArray<StyleBlock<SkPaint>> fForegroundStyles;
241 SkTArray<StyleBlock<std::vector<TextShadow>>> fShadowStyles;
242 SkTArray<StyleBlock<Decoration>> fDecorationStyles;
243 SkTArray<Block, true> fTextStyles; // TODO: take out only the font stuff
244 SkTArray<Placeholder, true> fPlaceholders;
245 SkString fText;
246
247 // Internal structures
248 InternalState fState;
249 SkTArray<Run, false> fRuns; // kShaped
250 SkTArray<Cluster, true> fClusters; // kClusterized (cached: text, word spacing, letter spacing, resolved fonts)
251 SkTArray<CodeUnitFlags> fCodeUnitProperties;
252 SkTArray<size_t> fClustersIndexFromCodeUnit;
253 std::vector<size_t> fWords;
254 std::vector<BidiRegion> fBidiRegions;
255 // These two arrays are used in measuring methods (getRectsForRange, getGlyphPositionAtCoordinate)
256 // They are filled lazily whenever they need and cached
257 SkTArray<TextIndex, true> fUTF8IndexForUTF16Index;
258 SkTArray<size_t, true> fUTF16IndexForUTF8Index;
259 size_t fUnresolvedGlyphs;
260
261 SkTArray<TextLine, false> fLines; // kFormatted (cached: width, max lines, ellipsis, text align)
262 sk_sp<SkPicture> fPicture; // kRecorded (cached: text styles)
263
264 SkTArray<ResolvedFontDescriptor> fFontSwitches;
265
266 InternalLineMetrics fEmptyMetrics;
267 InternalLineMetrics fStrutMetrics;
268
269 SkScalar fOldWidth;
270 SkScalar fOldHeight;
271 SkScalar fMaxWidthWithTrailingSpaces;
272 SkRect fOrigin;
273
274 std::unique_ptr<SkUnicode> fICU;
275};
276} // namespace textlayout
277} // namespace skia
278
279
280#endif // ParagraphImpl_DEFINED
281