1 // Copyright 2019 Google LLC. 2 #ifndef TextWrapper_DEFINED 3 #define TextWrapper_DEFINED 4 5 #include <string> 6 #include "include/core/SkSpan.h" 7 #include "modules/skparagraph/src/TextLine.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 (auto r = c->runOrNull()) { 42 fMetrics.add(r); 43 } 44 if (c < e) { 45 fWidth += c->width(); 46 } 47 } 48 fWidthWithGhostSpaces = fWidth; 49 } 50 width()51 inline SkScalar width() const { return fWidth; } widthWithGhostSpaces()52 SkScalar widthWithGhostSpaces() const { return fWidthWithGhostSpaces; } startCluster()53 inline Cluster* startCluster() const { return fStart.cluster(); } endCluster()54 inline Cluster* endCluster() const { return fEnd.cluster(); } breakCluster()55 inline Cluster* breakCluster() const { return fBreak.cluster(); } metrics()56 inline InternalLineMetrics& metrics() { return fMetrics; } startPos()57 inline size_t startPos() const { return fStart.position(); } endPos()58 inline size_t endPos() const { return fEnd.position(); } endOfCluster()59 bool endOfCluster() { return fEnd.position() == fEnd.cluster()->endPos(); } endOfWord()60 bool endOfWord() { 61 return endOfCluster() && 62 (fEnd.cluster()->isHardBreak() || fEnd.cluster()->isSoftBreak()); 63 } 64 extend(TextStretch & stretch)65 void extend(TextStretch& stretch) { 66 fMetrics.add(stretch.fMetrics); 67 fEnd = stretch.fEnd; 68 fWidth += stretch.fWidth; 69 stretch.clean(); 70 } 71 empty()72 bool empty() { return fStart.cluster() == fEnd.cluster() && 73 fStart.position() == fEnd.position(); } 74 setMetrics(const InternalLineMetrics & metrics)75 void setMetrics(const InternalLineMetrics& metrics) { fMetrics = metrics; } 76 extend(Cluster * cluster)77 void extend(Cluster* cluster) { 78 if (fStart.cluster() == nullptr) { 79 fStart = ClusterPos(cluster, cluster->startPos()); 80 } 81 fEnd = ClusterPos(cluster, cluster->endPos()); 82 // TODO: Make sure all the checks are correct and there are no unnecessary checks 83 auto& r = cluster->run(); 84 if (!cluster->isHardBreak() && !r.isPlaceholder()) { 85 // We ignore metrics for \n as the Flutter does 86 fMetrics.add(&r); 87 } 88 fWidth += cluster->width(); 89 } 90 extend(Cluster * cluster,size_t pos)91 void extend(Cluster* cluster, size_t pos) { 92 fEnd = ClusterPos(cluster, pos); 93 if (auto r = cluster->runOrNull()) { 94 fMetrics.add(r); 95 } 96 } 97 startFrom(Cluster * cluster,size_t pos)98 void startFrom(Cluster* cluster, size_t pos) { 99 fStart = ClusterPos(cluster, pos); 100 fEnd = ClusterPos(cluster, pos); 101 if (auto r = cluster->runOrNull()) { 102 // In case of placeholder we should ignore the default text style - 103 // we will pick up the correct one from the placeholder 104 if (!r->isPlaceholder()) { 105 fMetrics.add(r); 106 } 107 } 108 fWidth = 0; 109 } 110 saveBreak()111 void saveBreak() { 112 fWidthWithGhostSpaces = fWidth; 113 fBreak = fEnd; 114 } 115 restoreBreak()116 void restoreBreak() { 117 fWidth = fWidthWithGhostSpaces; 118 fEnd = fBreak; 119 } 120 trim()121 void trim() { 122 123 if (fEnd.cluster() != nullptr && 124 fEnd.cluster()->owner() != nullptr && 125 fEnd.cluster()->runOrNull() != nullptr && 126 fEnd.cluster()->run().placeholderStyle() == nullptr && 127 fWidth > 0) { 128 fWidth -= (fEnd.cluster()->width() - fEnd.cluster()->trimmedWidth(fEnd.position())); 129 } 130 } 131 trim(Cluster * cluster)132 void trim(Cluster* cluster) { 133 SkASSERT(fEnd.cluster() == cluster); 134 if (fEnd.cluster() > fStart.cluster()) { 135 fEnd.move(false); 136 fWidth -= cluster->width(); 137 } else { 138 fEnd.setPosition(fStart.position()); 139 fWidth = 0; 140 } 141 } 142 clean()143 void clean() { 144 fStart.clean(); 145 fEnd.clean(); 146 fWidth = 0; 147 fMetrics.clean(); 148 } 149 150 private: 151 ClusterPos fStart; 152 ClusterPos fEnd; 153 ClusterPos fBreak; 154 InternalLineMetrics fMetrics; 155 SkScalar fWidth; 156 SkScalar fWidthWithGhostSpaces; 157 }; 158 159 public: TextWrapper()160 TextWrapper() { 161 fLineNumber = 1; 162 fHardLineBreak = false; 163 fExceededMaxLines = false; 164 } 165 166 using AddLineToParagraph = std::function<void(TextRange text, 167 TextRange textWithSpaces, 168 ClusterRange clusters, 169 ClusterRange clustersWithGhosts, 170 SkScalar AddLineToParagraph, 171 size_t startClip, 172 size_t endClip, 173 SkVector offset, 174 SkVector advance, 175 InternalLineMetrics metrics, 176 bool addEllipsis)>; 177 void breakTextIntoLines(ParagraphImpl* parent, 178 SkScalar maxWidth, 179 const AddLineToParagraph& addLine); 180 height()181 SkScalar height() const { return fHeight; } minIntrinsicWidth()182 SkScalar minIntrinsicWidth() const { return fMinIntrinsicWidth; } maxIntrinsicWidth()183 SkScalar maxIntrinsicWidth() const { return fMaxIntrinsicWidth; } exceededMaxLines()184 bool exceededMaxLines() const { return fExceededMaxLines; } 185 186 private: 187 TextStretch fWords; 188 TextStretch fClusters; 189 TextStretch fClip; 190 TextStretch fEndLine; 191 size_t fLineNumber; 192 bool fTooLongWord; 193 bool fTooLongCluster; 194 195 bool fHardLineBreak; 196 bool fExceededMaxLines; 197 198 SkScalar fHeight; 199 SkScalar fMinIntrinsicWidth; 200 SkScalar fMaxIntrinsicWidth; 201 reset()202 void reset() { 203 fWords.clean(); 204 fClusters.clean(); 205 fClip.clean(); 206 fTooLongCluster = false; 207 fTooLongWord = false; 208 } 209 210 void lookAhead(SkScalar maxWidth, Cluster* endOfClusters); 211 void moveForward(bool hasEllipsis); 212 void trimEndSpaces(TextAlign align); 213 std::tuple<Cluster*, size_t, SkScalar> trimStartSpaces(Cluster* endOfClusters); 214 SkScalar getClustersTrimmedWidth(); 215 }; 216 } // namespace textlayout 217 } // namespace skia 218 219 #endif // TextWrapper_DEFINED 220