• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2019 Google LLC.
2 #ifndef TextWrapper_DEFINED
3 #define TextWrapper_DEFINED
4 
5 #include <string>
6 #include "include/ParagraphStyle.h"
7 #include "include/core/SkSpan.h"
8 #include "modules/skparagraph/src/TextLine.h"
9 #include "src/Run.h"
10 
11 #ifdef OHOS_SUPPORT
12 #include <list>
13 #include <vector>
14 
15 #include "include/TextStyle.h"
16 #include "modules/skparagraph/src/ParagraphImpl.h"
17 #include "SkScalar.h"
18 #endif
19 
20 namespace skia {
21 namespace textlayout {
22 
23 #ifdef OHOS_SUPPORT
24 const size_t STRATEGY_START_POS{2};
25 const size_t MIN_COST_POS{2};
26 const size_t MAX_LINES_LIMIT{1000000000};
27 #endif
28 
29 class ParagraphImpl;
30 #ifdef OHOS_SUPPORT
31 class TextTabAlign;
32 #endif
33 
34 class TextWrapper {
35     class ClusterPos {
36     public:
ClusterPos()37         ClusterPos() : fCluster(nullptr), fPos(0) {}
ClusterPos(Cluster * cluster,size_t pos)38         ClusterPos(Cluster* cluster, size_t pos) : fCluster(cluster), fPos(pos) {}
cluster()39         inline Cluster* cluster() const { return fCluster; }
position()40         inline size_t position() const { return fPos; }
setPosition(size_t pos)41         inline void setPosition(size_t pos) { fPos = pos; }
clean()42         void clean() {
43             fCluster = nullptr;
44             fPos = 0;
45         }
move(bool up)46         void move(bool up) {
47             fCluster += up ? 1 : -1;
48             fPos = up ? 0 : fCluster->endPos();
49         }
50 #ifdef OHOS_SUPPORT
setCluster(Cluster * cluster)51         void setCluster(Cluster* cluster) { fCluster = cluster; }
52 #endif
53 
54     private:
55         Cluster* fCluster;
56         size_t fPos;
57     };
58     class TextStretch {
59     public:
TextStretch()60         TextStretch() : fStart(), fEnd(), fWidth(0), fWidthWithGhostSpaces(0) {}
TextStretch(Cluster * s,Cluster * e,bool forceStrut)61         TextStretch(Cluster* s, Cluster* e, bool forceStrut)
62                 : fStart(s, 0), fEnd(e, e->endPos()), fMetrics(forceStrut), fWidth(0), fWidthWithGhostSpaces(0) {
63             for (auto c = s; c <= e; ++c) {
64                 if (auto r = c->runOrNull()) {
65                     fMetrics.add(r);
66                 }
67                 if (c < e) {
68                     fWidth += c->width();
69                 }
70             }
71             fWidthWithGhostSpaces = fWidth;
72         }
73 
74 #ifdef OHOS_SUPPORT
TextStretch(Cluster * c,bool forceStrut)75         TextStretch(Cluster* c, bool forceStrut)
76                 : fStart(c, 0), fEnd(c, c->endPos()), fMetrics(forceStrut), fWidth(0), fWidthWithGhostSpaces(0) {
77             if (auto r = c->runOrNull()) {
78                 fMetrics.add(r);
79             }
80             fWidth = c->width();
81             fWidthWithGhostSpaces = fWidth;
82         }
83 
split()84         std::vector<TextStretch> split() {
85             ParagraphImpl* owner = fStart.cluster()->getOwner();
86             Cluster* cluster = fStart.cluster();
87             std::vector<TextStretch> result{};
88             while(cluster <= fEnd.cluster()) {
89                 auto endIndex = (cluster)->textRange().end;
90                 Cluster* endCluster = &owner->cluster(
91                     std::min(owner->fClustersIndexFromCodeUnit[endIndex], owner->clusters().size() - 1));
92                 TextStretch singleClusterStretch = TextStretch(cluster, metrics().getForceStrut());
93                 result.push_back(singleClusterStretch);
94                 cluster = endCluster;
95             }
96             return result;
97         }
98 
setStartCluster(Cluster * cluster)99         void setStartCluster(Cluster* cluster) { fStart.setCluster(cluster); }
100 #endif
101 
width()102         inline SkScalar width() const { return fWidth; }
widthWithGhostSpaces()103         SkScalar widthWithGhostSpaces() const { return fWidthWithGhostSpaces; }
startCluster()104         inline Cluster* startCluster() const { return fStart.cluster(); }
endCluster()105         inline Cluster* endCluster() const { return fEnd.cluster(); }
breakCluster()106         inline Cluster* breakCluster() const { return fBreak.cluster(); }
metrics()107         inline InternalLineMetrics& metrics() { return fMetrics; }
startPos()108         inline size_t startPos() const { return fStart.position(); }
endPos()109         inline size_t endPos() const { return fEnd.position(); }
endOfCluster()110         bool endOfCluster() { return fEnd.position() == fEnd.cluster()->endPos(); }
endOfWord()111         bool endOfWord() {
112             return endOfCluster() &&
113                    (fEnd.cluster()->isHardBreak() || fEnd.cluster()->isSoftBreak());
114         }
115 
extend(TextStretch & stretch)116         void extend(TextStretch& stretch) {
117             fMetrics.add(stretch.fMetrics);
118             fEnd = stretch.fEnd;
119             fWidth += stretch.fWidth;
120             stretch.clean();
121         }
122 
empty()123         bool empty() { return fStart.cluster() == fEnd.cluster() &&
124                               fStart.position() == fEnd.position(); }
125 
setMetrics(const InternalLineMetrics & metrics)126         void setMetrics(const InternalLineMetrics& metrics) { fMetrics = metrics; }
127 
extend(Cluster * cluster)128         void extend(Cluster* cluster) {
129             if (fStart.cluster() == nullptr) {
130                 fStart = ClusterPos(cluster, cluster->startPos());
131             }
132             fEnd = ClusterPos(cluster, cluster->endPos());
133             // TODO: Make sure all the checks are correct and there are no unnecessary checks
134             auto& r = cluster->run();
135             if (!cluster->isHardBreak() && !r.isPlaceholder()) {
136                 // We ignore metrics for \n as the Flutter does
137                 fMetrics.add(&r);
138             }
139             fWidth += cluster->width();
140         }
141 
extend(Cluster * cluster,size_t pos)142         void extend(Cluster* cluster, size_t pos) {
143             fEnd = ClusterPos(cluster, pos);
144             if (auto r = cluster->runOrNull()) {
145                 fMetrics.add(r);
146             }
147         }
148 
startFrom(Cluster * cluster,size_t pos)149         void startFrom(Cluster* cluster, size_t pos) {
150             fStart = ClusterPos(cluster, pos);
151             fEnd = ClusterPos(cluster, pos);
152             if (auto r = cluster->runOrNull()) {
153                 // In case of placeholder we should ignore the default text style -
154                 // we will pick up the correct one from the placeholder
155                 if (!r->isPlaceholder()) {
156                     fMetrics.add(r);
157                 }
158             }
159             fWidth = 0;
160         }
161 
saveBreak()162         void saveBreak() {
163             fWidthWithGhostSpaces = fWidth;
164             fBreak = fEnd;
165         }
166 
restoreBreak()167         void restoreBreak() {
168             fWidth = fWidthWithGhostSpaces;
169             fEnd = fBreak;
170         }
171 
shiftBreak()172         void shiftBreak() {
173             fBreak.move(true);
174         }
175 
trim()176         void trim() {
177 
178             if (fEnd.cluster() != nullptr &&
179                 fEnd.cluster()->owner() != nullptr &&
180                 fEnd.cluster()->runOrNull() != nullptr &&
181                 fEnd.cluster()->run().placeholderStyle() == nullptr &&
182                 fWidth > 0) {
183                 fWidth -= (fEnd.cluster()->width() - fEnd.cluster()->trimmedWidth(fEnd.position()));
184             }
185         }
186 
trim(Cluster * cluster)187         void trim(Cluster* cluster) {
188             SkASSERT(fEnd.cluster() == cluster);
189             if (fEnd.cluster() > fStart.cluster()) {
190                 fEnd.move(false);
191                 fWidth -= cluster->width();
192             } else {
193                 fEnd.setPosition(fStart.position());
194                 fWidth = 0;
195             }
196         }
197 
clean()198         void clean() {
199             fStart.clean();
200             fEnd.clean();
201             fWidth = 0;
202             fMetrics.clean();
203         }
204 
205 #ifdef OHOS_SUPPORT
shiftWidth(SkScalar width)206         void shiftWidth(SkScalar width) {
207             fWidth += width;
208         }
209 #endif
210     private:
211         ClusterPos fStart;
212         ClusterPos fEnd;
213         ClusterPos fBreak;
214         InternalLineMetrics fMetrics;
215         SkScalar fWidth;
216         SkScalar fWidthWithGhostSpaces;
217     };
218 
219 public:
TextWrapper()220     TextWrapper() {
221          fLineNumber = 1;
222          fHardLineBreak = false;
223          fExceededMaxLines = false;
224     }
225 
226     using AddLineToParagraph = std::function<void(TextRange textExcludingSpaces,
227                                                   TextRange text,
228                                                   TextRange textIncludingNewlines,
229                                                   ClusterRange clusters,
230                                                   ClusterRange clustersWithGhosts,
231                                                   SkScalar addLineToParagraph,
232                                                   size_t startClip,
233                                                   size_t endClip,
234                                                   SkVector offset,
235                                                   SkVector advance,
236                                                   InternalLineMetrics metrics,
237                                                   bool addEllipsis,
238                                                   SkScalar lineIndent,
239                                                   SkScalar noIndentWidth)>;
240     void breakTextIntoLines(ParagraphImpl* parent,
241                             SkScalar maxWidth,
242                             const AddLineToParagraph& addLine);
243     void updateMetricsWithPlaceholder(std::vector<Run*>& runs, bool iterateByCluster);
244 
height()245     SkScalar height() const { return fHeight; }
minIntrinsicWidth()246     SkScalar minIntrinsicWidth() const { return fMinIntrinsicWidth; }
maxIntrinsicWidth()247     SkScalar maxIntrinsicWidth() const { return fMaxIntrinsicWidth; }
exceededMaxLines()248     bool exceededMaxLines() const { return fExceededMaxLines; }
249 #ifdef OHOS_SUPPORT
brokeLineWithHyphen()250     bool brokeLineWithHyphen() const { return fBrokeLineWithHyphen; }
251 #endif
252 
253 private:
254 #ifdef OHOS_SUPPORT
255     struct FormattingContext {
256         bool unlimitedLines{false};
257         bool endlessLine{false};
258         bool hasEllipsis{false};
259         bool disableFirstAscent{false};
260         bool disableLastDescent{false};
261         size_t maxLines{0};
262         TextAlign align{TextAlign::kLeft};
263     };
264 
265     struct LineTextRanges {
266         TextRange textExcludingSpaces;
267         TextRange text;
268         TextRange textIncludingNewlines;
269         ClusterRange clusters;
270         ClusterRange clustersWithGhosts;
271     };
272 
273     friend TextTabAlign;
274 #endif
275     TextStretch fWords;
276     TextStretch fClusters;
277     TextStretch fClip;
278     TextStretch fEndLine;
279     size_t fLineNumber;
280     bool fTooLongWord;
281     bool fTooLongCluster;
282 
283     bool fHardLineBreak;
284     bool fExceededMaxLines;
285 
286 #ifdef OHOS_SUPPORT
287     SkScalar fHeight{0};
288     SkScalar fMinIntrinsicWidth{std::numeric_limits<SkScalar>::min()};
289     SkScalar fMaxIntrinsicWidth{std::numeric_limits<SkScalar>::min()};
290     bool fBrokeLineWithHyphen{false};
291     std::vector<TextStretch> fWordStretches;
292     std::vector<TextStretch> fLineStretches;
293     std::vector<SkScalar> fWordWidthGroups;
294     std::vector<std::vector<TextStretch>> fWordStretchesBatch;
295     std::vector<std::vector<SkScalar>> fWordWidthGroupsBatch;
296 #else
297     SkScalar fHeight;
298     SkScalar fMinIntrinsicWidth;
299     SkScalar fMaxIntrinsicWidth;
300 #endif
301 
reset()302     void reset() {
303         fWords.clean();
304         fClusters.clean();
305         fClip.clean();
306         fTooLongCluster = false;
307         fTooLongWord = false;
308         fHardLineBreak = false;
309 #ifdef OHOS_SUPPORT
310         fBrokeLineWithHyphen = false;
311         fWordStretches.clear();
312         fLineStretches.clear();
313         fStart = nullptr;
314         fEnd = nullptr;
315 #endif
316     }
317 
318 #ifdef OHOS_SUPPORT
319     void lookAhead(SkScalar maxWidth, Cluster* endOfClusters, bool applyRoundingHack, WordBreakType wordBreakType,
320                    bool needEllipsis);
321     void moveForward(bool hasEllipsis, bool breakAll); // breakAll = true, break occurs after each character
322     bool lookAheadByHyphen(Cluster* endOfClusters, SkScalar widthBeforeCluster, SkScalar maxWidth);
323     uint64_t CalculateBestScore(std::vector<SkScalar>& widthOut,
324         SkScalar maxWidth, ParagraphImpl* parent, size_t maxLines);
325     static size_t tryBreakWord(Cluster* startCluster,
326                                Cluster* endOfClusters,
327                                SkScalar widthBeforeCluster,
328                                SkScalar maxWidth);
329 
330     static void matchHyphenResult(const std::vector<uint8_t>& result, ParagraphImpl* owner, size_t& pos,
331                                   SkScalar maxWidth, SkScalar length);
332     static std::vector<uint8_t> findBreakPositions(Cluster* startCluster,
333                                                    Cluster* endOfClusters,
334                                                    SkScalar widthBeforeCluster,
335                                                    SkScalar maxWidth);
initParent(ParagraphImpl * parent)336     void initParent(ParagraphImpl* parent) { fParent = parent; }
337     void pushToWordStretches();
338     void pushToWordStretchesBatch();
339     void layoutLinesBalanced(
340         ParagraphImpl* parent, SkScalar maxWidth, const AddLineToParagraph& addLine);
341     void layoutLinesSimple(
342         ParagraphImpl* parent, SkScalar maxWidth, const AddLineToParagraph& addLine);
343     std::vector<SkScalar> generateWordsWidthInfo(const std::vector<TextStretch>& wordStretches);
344     std::vector<std::pair<size_t, size_t>> generateLinesGroupInfo(
345         const std::vector<float>& clustersWidth, SkScalar maxWidth);
346     void generateWordStretches(const SkSpan<Cluster>& span, WordBreakType wordBreakType);
347     void generateLineStretches(const std::vector<std::pair<size_t, size_t>>& linesGroupInfo,
348         std::vector<TextStretch>& wordStretches);
349     void preProcessingForLineStretches();
350     void extendCommonCluster(Cluster* cluster, TextTabAlign& textTabAlign,
351         SkScalar& totalFakeSpacing, WordBreakType wordBreakType);
352     SkScalar getTextStretchTrimmedEndSpaceWidth(const TextStretch& stretch);
353     void formalizedClusters(std::vector<TextStretch>& clusters, SkScalar limitWidth);
354     void generateTextLines(SkScalar maxWidth,
355                             const AddLineToParagraph& addLine,
356                             const SkSpan<Cluster>& span);
357     void initializeFormattingState(SkScalar maxWidth, const SkSpan<Cluster>& span);
358     void processLineStretches(SkScalar maxWidth, const AddLineToParagraph& addLine);
359     void finalizeTextLayout(const AddLineToParagraph& addLine);
360     void prepareLineForFormatting(TextStretch& line);
361     void formatCurrentLine(const AddLineToParagraph& addLine);
362     bool determineIfEllipsisNeeded();
363     void trimLineSpaces();
364     void handleSpecialCases(bool needEllipsis);
365     void updateLineMetrics();
366     void updatePlaceholderMetrics();
367     void adjustLineMetricsForFirstLastLine();
368     void applyStrutMetrics();
369     LineTextRanges calculateLineTextRanges();
370     SkScalar calculateLineHeight();
371     void addFormattedLineToParagraph(const AddLineToParagraph& addLine, bool needEllipsis);
372     void updateIntrinsicWidths();
373     bool shouldBreakFormattingLoop();
374     bool isLastLine() const;
375     void advanceToNextLine();
376     void prepareForNextLine();
377     void processRemainingClusters();
378     void handleHardBreak(float& lastWordLength);
379     void handleWhitespaceBreak(Cluster* cluster, float& lastWordLength);
380     void handlePlaceholder(Cluster* cluster, float& lastWordLength);
381     void handleRegularCluster(Cluster* cluster, float& lastWordLength);
382     void adjustMetricsForEmptyParagraph();
383     void addFinalLineBreakIfNeeded(const AddLineToParagraph& addLine);
384     void adjustFirstLastLineMetrics();
385 #else
386     void lookAhead(SkScalar maxWidth, Cluster* endOfClusters, bool applyRoundingHack);
387     void moveForward(bool hasEllipsis);
388 #endif
389     void trimEndSpaces(TextAlign align);
390     std::tuple<Cluster*, size_t, SkScalar> trimStartSpaces(Cluster* endOfClusters);
391     SkScalar getClustersTrimmedWidth();
392 
393 #ifdef OHOS_SUPPORT
394     ParagraphImpl* fParent{nullptr};
395     FormattingContext fFormattingContext;
396     InternalLineMetrics fMaxRunMetrics;
397     SkScalar fSoftLineMaxIntrinsicWidth{0.0f};
398     SkScalar fCurrentLineWidthWithSpaces{0.0f};
399     SkScalar fNoIndentWidth{0.0f};
400     bool fFirstLine{false};
401     Cluster* fCurrentStartLine{nullptr};
402     size_t fCurrentStartPos{0};
403     Cluster* fStart{nullptr};
404     Cluster* fEnd{nullptr};
405 #endif
406 };
407 }  // namespace textlayout
408 }  // namespace skia
409 
410 #endif  // TextWrapper_DEFINED
411