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 10 namespace skia { 11 namespace textlayout { 12 13 class ParagraphImpl; 14 15 class TextWrapper { 16 class ClusterPos { 17 public: ClusterPos()18 ClusterPos() : fCluster(nullptr), fPos(0) {} ClusterPos(Cluster * cluster,size_t pos)19 ClusterPos(Cluster* cluster, size_t pos) : fCluster(cluster), fPos(pos) {} cluster()20 inline Cluster* cluster() const { return fCluster; } position()21 inline size_t position() const { return fPos; } setPosition(size_t pos)22 inline void setPosition(size_t pos) { fPos = pos; } clean()23 void clean() { 24 fCluster = nullptr; 25 fPos = 0; 26 } move(bool up)27 void move(bool up) { 28 fCluster += up ? 1 : -1; 29 fPos = up ? 0 : fCluster->endPos(); 30 } 31 32 private: 33 Cluster* fCluster; 34 size_t fPos; 35 }; 36 class TextStretch { 37 public: TextStretch()38 TextStretch() : fStart(), fEnd(), fWidth(0), fWidthWithGhostSpaces(0) {} TextStretch(Cluster * s,Cluster * e,bool forceStrut)39 TextStretch(Cluster* s, Cluster* e, bool forceStrut) 40 : fStart(s, 0), fEnd(e, e->endPos()), fMetrics(forceStrut), fWidth(0), fWidthWithGhostSpaces(0) { 41 for (auto c = s; c <= e; ++c) { 42 if (auto r = c->runOrNull()) { 43 fMetrics.add(r); 44 } 45 if (c < e) { 46 fWidth += c->width(); 47 } 48 } 49 fWidthWithGhostSpaces = fWidth; 50 } 51 width()52 inline SkScalar width() const { return fWidth; } widthWithGhostSpaces()53 SkScalar widthWithGhostSpaces() const { return fWidthWithGhostSpaces; } startCluster()54 inline Cluster* startCluster() const { return fStart.cluster(); } endCluster()55 inline Cluster* endCluster() const { return fEnd.cluster(); } breakCluster()56 inline Cluster* breakCluster() const { return fBreak.cluster(); } metrics()57 inline InternalLineMetrics& metrics() { return fMetrics; } startPos()58 inline size_t startPos() const { return fStart.position(); } endPos()59 inline size_t endPos() const { return fEnd.position(); } endOfCluster()60 bool endOfCluster() { return fEnd.position() == fEnd.cluster()->endPos(); } endOfWord()61 bool endOfWord() { 62 return endOfCluster() && 63 (fEnd.cluster()->isHardBreak() || fEnd.cluster()->isSoftBreak()); 64 } 65 extend(TextStretch & stretch)66 void extend(TextStretch& stretch) { 67 fMetrics.add(stretch.fMetrics); 68 fEnd = stretch.fEnd; 69 fWidth += stretch.fWidth; 70 stretch.clean(); 71 } 72 empty()73 bool empty() { return fStart.cluster() == fEnd.cluster() && 74 fStart.position() == fEnd.position(); } 75 setMetrics(const InternalLineMetrics & metrics)76 void setMetrics(const InternalLineMetrics& metrics) { fMetrics = metrics; } 77 extend(Cluster * cluster)78 void extend(Cluster* cluster) { 79 if (fStart.cluster() == nullptr) { 80 fStart = ClusterPos(cluster, cluster->startPos()); 81 } 82 fEnd = ClusterPos(cluster, cluster->endPos()); 83 // TODO: Make sure all the checks are correct and there are no unnecessary checks 84 auto& r = cluster->run(); 85 if (!cluster->isHardBreak() && !r.isPlaceholder()) { 86 // We ignore metrics for \n as the Flutter does 87 fMetrics.add(&r); 88 } 89 fWidth += cluster->width(); 90 } 91 extend(Cluster * cluster,size_t pos)92 void extend(Cluster* cluster, size_t pos) { 93 fEnd = ClusterPos(cluster, pos); 94 if (auto r = cluster->runOrNull()) { 95 fMetrics.add(r); 96 } 97 } 98 startFrom(Cluster * cluster,size_t pos)99 void startFrom(Cluster* cluster, size_t pos) { 100 fStart = ClusterPos(cluster, pos); 101 fEnd = ClusterPos(cluster, pos); 102 if (auto r = cluster->runOrNull()) { 103 // In case of placeholder we should ignore the default text style - 104 // we will pick up the correct one from the placeholder 105 if (!r->isPlaceholder()) { 106 fMetrics.add(r); 107 } 108 } 109 fWidth = 0; 110 } 111 saveBreak()112 void saveBreak() { 113 fWidthWithGhostSpaces = fWidth; 114 fBreak = fEnd; 115 } 116 restoreBreak()117 void restoreBreak() { 118 fWidth = fWidthWithGhostSpaces; 119 fEnd = fBreak; 120 } 121 shiftBreak()122 void shiftBreak() { 123 fBreak.move(true); 124 } 125 trim()126 void trim() { 127 128 if (fEnd.cluster() != nullptr && 129 fEnd.cluster()->owner() != nullptr && 130 fEnd.cluster()->runOrNull() != nullptr && 131 fEnd.cluster()->run().placeholderStyle() == nullptr && 132 fWidth > 0) { 133 fWidth -= (fEnd.cluster()->width() - fEnd.cluster()->trimmedWidth(fEnd.position())); 134 } 135 } 136 trim(Cluster * cluster)137 void trim(Cluster* cluster) { 138 SkASSERT(fEnd.cluster() == cluster); 139 if (fEnd.cluster() > fStart.cluster()) { 140 fEnd.move(false); 141 fWidth -= cluster->width(); 142 } else { 143 fEnd.setPosition(fStart.position()); 144 fWidth = 0; 145 } 146 } 147 clean()148 void clean() { 149 fStart.clean(); 150 fEnd.clean(); 151 fWidth = 0; 152 fMetrics.clean(); 153 } 154 155 private: 156 ClusterPos fStart; 157 ClusterPos fEnd; 158 ClusterPos fBreak; 159 InternalLineMetrics fMetrics; 160 SkScalar fWidth; 161 SkScalar fWidthWithGhostSpaces; 162 }; 163 164 public: TextWrapper()165 TextWrapper() { 166 fLineNumber = 1; 167 fHardLineBreak = false; 168 fExceededMaxLines = false; 169 } 170 171 using AddLineToParagraph = std::function<void(TextRange textExcludingSpaces, 172 TextRange text, 173 TextRange textIncludingNewlines, 174 ClusterRange clusters, 175 ClusterRange clustersWithGhosts, 176 SkScalar addLineToParagraph, 177 size_t startClip, 178 size_t endClip, 179 SkVector offset, 180 SkVector advance, 181 InternalLineMetrics metrics, 182 bool addEllipsis, 183 SkScalar lineIndent, 184 SkScalar noIndentWidth)>; 185 void breakTextIntoLines(ParagraphImpl* parent, 186 SkScalar maxWidth, 187 const AddLineToParagraph& addLine); 188 void updateMetricsWithPlaceholder(std::vector<Run*>& runs, bool iterateByCluster); 189 height()190 SkScalar height() const { return fHeight; } minIntrinsicWidth()191 SkScalar minIntrinsicWidth() const { return fMinIntrinsicWidth; } maxIntrinsicWidth()192 SkScalar maxIntrinsicWidth() const { return fMaxIntrinsicWidth; } exceededMaxLines()193 bool exceededMaxLines() const { return fExceededMaxLines; } 194 195 private: 196 TextStretch fWords; 197 TextStretch fClusters; 198 TextStretch fClip; 199 TextStretch fEndLine; 200 size_t fLineNumber; 201 bool fTooLongWord; 202 bool fTooLongCluster; 203 204 bool fHardLineBreak; 205 bool fExceededMaxLines; 206 207 SkScalar fHeight; 208 SkScalar fMinIntrinsicWidth; 209 SkScalar fMaxIntrinsicWidth; 210 reset()211 void reset() { 212 fWords.clean(); 213 fClusters.clean(); 214 fClip.clean(); 215 fTooLongCluster = false; 216 fTooLongWord = false; 217 fHardLineBreak = false; 218 } 219 220 SkScalar calculateFakeSpacing(Cluster* cluster, bool autoSpacingEnable); 221 void lookAhead(SkScalar maxWidth, Cluster* endOfClusters, bool applyRoundingHack, WordBreakType wordBreakType, 222 bool autoSpacingEnable); 223 void moveForward(bool hasEllipsis, bool breakAll); // breakAll = true, break occurs after each character 224 void trimEndSpaces(TextAlign align); 225 std::tuple<Cluster*, size_t, SkScalar> trimStartSpaces(Cluster* endOfClusters); 226 SkScalar getClustersTrimmedWidth(); 227 uint64_t CalculateBestScore(std::vector<SkScalar>& widthOut, 228 SkScalar maxWidth, ParagraphImpl* parent, size_t maxLines); 229 }; 230 } // namespace textlayout 231 } // namespace skia 232 233 #endif // TextWrapper_DEFINED 234