1 // Copyright 2019 Google LLC. 2 #ifndef TextWrapper_DEFINED 3 #define TextWrapper_DEFINED 4 5 #include <string> 6 #include "modules/skparagraph/src/TextLine.h" 7 #include "src/core/SkSpan.h" 8 9 namespace skia { 10 namespace textlayout { 11 12 class ParagraphImpl; 13 14 class TextWrapper { 15 class ClusterPos { 16 public: ClusterPos()17 ClusterPos() : fCluster(nullptr), fPos(0) {} ClusterPos(Cluster * cluster,size_t pos)18 ClusterPos(Cluster* cluster, size_t pos) : fCluster(cluster), fPos(pos) {} cluster()19 inline Cluster* cluster() const { return fCluster; } position()20 inline size_t position() const { return fPos; } setPosition(size_t pos)21 inline void setPosition(size_t pos) { fPos = pos; } clean()22 void clean() { 23 fCluster = nullptr; 24 fPos = 0; 25 } move(bool up)26 void move(bool up) { 27 fCluster += up ? 1 : -1; 28 fPos = up ? 0 : fCluster->endPos(); 29 } 30 31 private: 32 Cluster* fCluster; 33 size_t fPos; 34 }; 35 class TextStretch { 36 public: TextStretch()37 TextStretch() : fStart(), fEnd(), fWidth(0), fWidthWithGhostSpaces(0) {} TextStretch(Cluster * s,Cluster * e,bool forceStrut)38 TextStretch(Cluster* s, Cluster* e, bool forceStrut) 39 : fStart(s, 0), fEnd(e, e->endPos()), fMetrics(forceStrut), fWidth(0), fWidthWithGhostSpaces(0) { 40 for (auto c = s; c <= e; ++c) { 41 if (c->run() != nullptr) { 42 fMetrics.add(c->run()); 43 } 44 } 45 } 46 width()47 inline SkScalar width() const { return fWidth; } withWithGhostSpaces()48 SkScalar withWithGhostSpaces() const { return fWidthWithGhostSpaces; } startCluster()49 inline Cluster* startCluster() const { return fStart.cluster(); } endCluster()50 inline Cluster* endCluster() const { return fEnd.cluster(); } breakCluster()51 inline Cluster* breakCluster() const { return fBreak.cluster(); } metrics()52 inline LineMetrics& metrics() { return fMetrics; } startPos()53 inline size_t startPos() const { return fStart.position(); } endPos()54 inline size_t endPos() const { return fEnd.position(); } breakPos()55 inline size_t breakPos() const { return fBreak.position(); } endOfCluster()56 bool endOfCluster() { return fEnd.position() == fEnd.cluster()->endPos(); } endOfWord()57 bool endOfWord() { 58 return endOfCluster() && 59 (fEnd.cluster()->isHardBreak() || fEnd.cluster()->isSoftBreak()); 60 } 61 extend(TextStretch & stretch)62 void extend(TextStretch& stretch) { 63 fMetrics.add(stretch.fMetrics); 64 fEnd = stretch.fEnd; 65 fWidth += stretch.fWidth; 66 stretch.clean(); 67 } 68 extend(Cluster * cluster)69 void extend(Cluster* cluster) { 70 if (fStart.cluster() == nullptr) { 71 fStart = ClusterPos(cluster, cluster->startPos()); 72 } 73 fEnd = ClusterPos(cluster, cluster->endPos()); 74 fMetrics.add(cluster->run()); 75 fWidth += cluster->width(); 76 } 77 extend(Cluster * cluster,size_t pos)78 void extend(Cluster* cluster, size_t pos) { 79 fEnd = ClusterPos(cluster, pos); 80 if (cluster->run() != nullptr) { 81 fMetrics.add(cluster->run()); 82 } 83 } 84 startFrom(Cluster * cluster,size_t pos)85 void startFrom(Cluster* cluster, size_t pos) { 86 fStart = ClusterPos(cluster, pos); 87 fEnd = ClusterPos(cluster, pos); 88 if (cluster->run() != nullptr) { 89 fMetrics.add(cluster->run()); 90 } 91 fWidth = 0; 92 } 93 nextBreakPos(Cluster * endOfClusters)94 void nextBreakPos(Cluster* endOfClusters) { 95 if (fBreak.position() == fBreak.cluster()->endPos()) { 96 if (fBreak.cluster() < endOfClusters) { 97 fBreak.move(true); 98 } else { 99 fBreak.setPosition(0); 100 } 101 } else { 102 fBreak.setPosition(fBreak.cluster()->endPos()); 103 } 104 } 105 saveBreak()106 void saveBreak() { 107 fWidthWithGhostSpaces = fWidth; 108 fBreak = fEnd; 109 } 110 restoreBreak()111 void restoreBreak() { fEnd = fBreak; } 112 trim()113 void trim() { 114 fWidth -= (fEnd.cluster()->width() - fEnd.cluster()->trimmedWidth(fEnd.position())); 115 } 116 trim(Cluster * cluster)117 void trim(Cluster* cluster) { 118 SkASSERT(fEnd.cluster() == cluster); 119 if (fEnd.cluster() > fStart.cluster()) { 120 fEnd.move(false); 121 fWidth -= cluster->width(); 122 } else { 123 fWidth = 0; 124 } 125 } 126 clean()127 void clean() { 128 fStart.clean(); 129 fEnd.clean(); 130 fWidth = 0; 131 fMetrics.clean(); 132 } 133 134 private: 135 ClusterPos fStart; 136 ClusterPos fEnd; 137 ClusterPos fBreak; 138 LineMetrics fMetrics; 139 SkScalar fWidth; 140 SkScalar fWidthWithGhostSpaces; 141 }; 142 143 public: TextWrapper()144 TextWrapper() { fLineNumber = 1; } 145 146 using AddLineToParagraph = std::function<void(TextRange text, 147 TextRange textWithSpaces, 148 ClusterRange clusters, 149 ClusterRange clustersWithGhosts, 150 SkScalar AddLineToParagraph, 151 size_t startClip, 152 size_t endClip, 153 SkVector offset, 154 SkVector advance, 155 LineMetrics metrics, 156 bool addEllipsis)>; 157 void breakTextIntoLines(ParagraphImpl* parent, 158 SkScalar maxWidth, 159 const AddLineToParagraph& addLine); 160 height()161 inline SkScalar height() const { return fHeight; } minIntrinsicWidth()162 inline SkScalar minIntrinsicWidth() const { return fMinIntrinsicWidth; } maxIntrinsicWidth()163 inline SkScalar maxIntrinsicWidth() const { return fMaxIntrinsicWidth; } 164 165 private: 166 TextStretch fWords; 167 TextStretch fClusters; 168 TextStretch fClip; 169 TextStretch fEndLine; 170 size_t fLineNumber; 171 bool fTooLongWord; 172 bool fTooLongCluster; 173 174 bool fHardLineBreak; 175 176 SkScalar fHeight; 177 SkScalar fMinIntrinsicWidth; 178 SkScalar fMaxIntrinsicWidth; 179 reset()180 void reset() { 181 fWords.clean(); 182 fClusters.clean(); 183 fClip.clean(); 184 fTooLongCluster = false; 185 fTooLongWord = false; 186 } 187 188 void lookAhead(SkScalar maxWidth, Cluster* endOfClusters); 189 void moveForward(); 190 void trimEndSpaces(TextAlign align); 191 std::tuple<Cluster*, size_t, SkScalar> trimStartSpaces(Cluster* endOfClusters); 192 SkScalar getClustersTrimmedWidth(); 193 }; 194 } // namespace textlayout 195 } // namespace skia 196 197 #endif // TextWrapper_DEFINED 198