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 shiftBreak()121 void shiftBreak() { 122 fBreak.move(true); 123 } 124 trim()125 void trim() { 126 127 if (fEnd.cluster() != nullptr && 128 fEnd.cluster()->owner() != nullptr && 129 fEnd.cluster()->runOrNull() != nullptr && 130 fEnd.cluster()->run().placeholderStyle() == nullptr && 131 fWidth > 0) { 132 fWidth -= (fEnd.cluster()->width() - fEnd.cluster()->trimmedWidth(fEnd.position())); 133 } 134 } 135 trim(Cluster * cluster)136 void trim(Cluster* cluster) { 137 SkASSERT(fEnd.cluster() == cluster); 138 if (fEnd.cluster() > fStart.cluster()) { 139 fEnd.move(false); 140 fWidth -= cluster->width(); 141 } else { 142 fEnd.setPosition(fStart.position()); 143 fWidth = 0; 144 } 145 } 146 clean()147 void clean() { 148 fStart.clean(); 149 fEnd.clean(); 150 fWidth = 0; 151 fMetrics.clean(); 152 } 153 154 private: 155 ClusterPos fStart; 156 ClusterPos fEnd; 157 ClusterPos fBreak; 158 InternalLineMetrics fMetrics; 159 SkScalar fWidth; 160 SkScalar fWidthWithGhostSpaces; 161 }; 162 163 public: TextWrapper()164 TextWrapper() { 165 fLineNumber = 1; 166 fHardLineBreak = false; 167 fExceededMaxLines = false; 168 } 169 170 using AddLineToParagraph = std::function<void(TextRange textExcludingSpaces, 171 TextRange text, 172 TextRange textIncludingNewlines, 173 ClusterRange clusters, 174 ClusterRange clustersWithGhosts, 175 SkScalar AddLineToParagraph, 176 size_t startClip, 177 size_t endClip, 178 SkVector offset, 179 SkVector advance, 180 InternalLineMetrics metrics, 181 bool addEllipsis)>; 182 void breakTextIntoLines(ParagraphImpl* parent, 183 SkScalar maxWidth, 184 const AddLineToParagraph& addLine); 185 height()186 SkScalar height() const { return fHeight; } minIntrinsicWidth()187 SkScalar minIntrinsicWidth() const { return fMinIntrinsicWidth; } maxIntrinsicWidth()188 SkScalar maxIntrinsicWidth() const { return fMaxIntrinsicWidth; } exceededMaxLines()189 bool exceededMaxLines() const { return fExceededMaxLines; } 190 191 private: 192 TextStretch fWords; 193 TextStretch fClusters; 194 TextStretch fClip; 195 TextStretch fEndLine; 196 size_t fLineNumber; 197 bool fTooLongWord; 198 bool fTooLongCluster; 199 200 bool fHardLineBreak; 201 bool fExceededMaxLines; 202 203 SkScalar fHeight; 204 SkScalar fMinIntrinsicWidth; 205 SkScalar fMaxIntrinsicWidth; 206 reset()207 void reset() { 208 fWords.clean(); 209 fClusters.clean(); 210 fClip.clean(); 211 fTooLongCluster = false; 212 fTooLongWord = false; 213 } 214 215 void lookAhead(SkScalar maxWidth, Cluster* endOfClusters); 216 void moveForward(bool hasEllipsis); 217 void trimEndSpaces(TextAlign align); 218 std::tuple<Cluster*, size_t, SkScalar> trimStartSpaces(Cluster* endOfClusters); 219 SkScalar getClustersTrimmedWidth(); 220 }; 221 } // namespace textlayout 222 } // namespace skia 223 224 #endif // TextWrapper_DEFINED 225