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; } widthWithGhostSpaces()48 SkScalar widthWithGhostSpaces() 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 InternalLineMetrics& metrics() { return fMetrics; } startPos()53 inline size_t startPos() const { return fStart.position(); } endPos()54 inline size_t endPos() const { return fEnd.position(); } endOfCluster()55 bool endOfCluster() { return fEnd.position() == fEnd.cluster()->endPos(); } endOfWord()56 bool endOfWord() { 57 return endOfCluster() && 58 (fEnd.cluster()->isHardBreak() || fEnd.cluster()->isSoftBreak()); 59 } 60 extend(TextStretch & stretch)61 void extend(TextStretch& stretch) { 62 fMetrics.add(stretch.fMetrics); 63 fEnd = stretch.fEnd; 64 fWidth += stretch.fWidth; 65 stretch.clean(); 66 } 67 empty()68 bool empty() { return fStart.cluster() == fEnd.cluster() && 69 fStart.position() == fEnd.position(); } 70 setMetrics(const InternalLineMetrics & metrics)71 void setMetrics(const InternalLineMetrics& metrics) { fMetrics = metrics; } 72 extend(Cluster * cluster)73 void extend(Cluster* cluster) { 74 if (fStart.cluster() == nullptr) { 75 fStart = ClusterPos(cluster, cluster->startPos()); 76 } 77 fEnd = ClusterPos(cluster, cluster->endPos()); 78 if (!cluster->run()->isPlaceholder()) { 79 fMetrics.add(cluster->run()); 80 } 81 fWidth += cluster->width(); 82 } 83 extend(Cluster * cluster,size_t pos)84 void extend(Cluster* cluster, size_t pos) { 85 fEnd = ClusterPos(cluster, pos); 86 if (cluster->run() != nullptr) { 87 fMetrics.add(cluster->run()); 88 } 89 } 90 startFrom(Cluster * cluster,size_t pos)91 void startFrom(Cluster* cluster, size_t pos) { 92 fStart = ClusterPos(cluster, pos); 93 fEnd = ClusterPos(cluster, pos); 94 if (cluster->run() != nullptr) { 95 fMetrics.add(cluster->run()); 96 } 97 fWidth = 0; 98 } 99 saveBreak()100 void saveBreak() { 101 fWidthWithGhostSpaces = fWidth; 102 fBreak = fEnd; 103 } 104 restoreBreak()105 void restoreBreak() { 106 fWidth = fWidthWithGhostSpaces; 107 fEnd = fBreak; 108 } 109 trim()110 void trim() { 111 112 if (fEnd.cluster() != nullptr && 113 fEnd.cluster()->master() != nullptr && 114 fEnd.cluster()->run() != nullptr && 115 fEnd.cluster()->run()->placeholderStyle() == nullptr && 116 fWidth > 0) { 117 fWidth -= (fEnd.cluster()->width() - fEnd.cluster()->trimmedWidth(fEnd.position())); 118 } 119 } 120 trim(Cluster * cluster)121 void trim(Cluster* cluster) { 122 SkASSERT(fEnd.cluster() == cluster); 123 if (fEnd.cluster() > fStart.cluster()) { 124 fEnd.move(false); 125 fWidth -= cluster->width(); 126 } else { 127 fWidth = 0; 128 } 129 } 130 clean()131 void clean() { 132 fStart.clean(); 133 fEnd.clean(); 134 fWidth = 0; 135 fMetrics.clean(); 136 } 137 138 private: 139 ClusterPos fStart; 140 ClusterPos fEnd; 141 ClusterPos fBreak; 142 InternalLineMetrics fMetrics; 143 SkScalar fWidth; 144 SkScalar fWidthWithGhostSpaces; 145 }; 146 147 public: TextWrapper()148 TextWrapper() { 149 fLineNumber = 1; 150 fHardLineBreak = false; 151 fExceededMaxLines = false; 152 } 153 154 using AddLineToParagraph = std::function<void(TextRange text, 155 TextRange textWithSpaces, 156 ClusterRange clusters, 157 ClusterRange clustersWithGhosts, 158 SkScalar AddLineToParagraph, 159 size_t startClip, 160 size_t endClip, 161 SkVector offset, 162 SkVector advance, 163 InternalLineMetrics metrics, 164 bool addEllipsis)>; 165 void breakTextIntoLines(ParagraphImpl* parent, 166 SkScalar maxWidth, 167 const AddLineToParagraph& addLine); 168 height()169 SkScalar height() const { return fHeight; } minIntrinsicWidth()170 SkScalar minIntrinsicWidth() const { return fMinIntrinsicWidth; } maxIntrinsicWidth()171 SkScalar maxIntrinsicWidth() const { return fMaxIntrinsicWidth; } exceededMaxLines()172 bool exceededMaxLines() const { return fExceededMaxLines; } 173 174 private: 175 TextStretch fWords; 176 TextStretch fClusters; 177 TextStretch fClip; 178 TextStretch fEndLine; 179 size_t fLineNumber; 180 bool fTooLongWord; 181 bool fTooLongCluster; 182 183 bool fHardLineBreak; 184 bool fExceededMaxLines; 185 186 SkScalar fHeight; 187 SkScalar fMinIntrinsicWidth; 188 SkScalar fMaxIntrinsicWidth; 189 reset()190 void reset() { 191 fWords.clean(); 192 fClusters.clean(); 193 fClip.clean(); 194 fTooLongCluster = false; 195 fTooLongWord = false; 196 } 197 198 void lookAhead(SkScalar maxWidth, Cluster* endOfClusters); 199 void moveForward(bool hasEllipsis); 200 void trimEndSpaces(TextAlign align); 201 std::tuple<Cluster*, size_t, SkScalar> trimStartSpaces(Cluster* endOfClusters); 202 SkScalar getClustersTrimmedWidth(); 203 }; 204 } // namespace textlayout 205 } // namespace skia 206 207 #endif // TextWrapper_DEFINED 208