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