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 10namespace skia { 11namespace textlayout { 12 13class ParagraphImpl; 14#ifdef OHOS_SUPPORT 15class TextTabAlign; 16#endif 17 18class TextWrapper { 19 class ClusterPos { 20 public: 21 ClusterPos() : fCluster(nullptr), fPos(0) {} 22 ClusterPos(Cluster* cluster, size_t pos) : fCluster(cluster), fPos(pos) {} 23 inline Cluster* cluster() const { return fCluster; } 24 inline size_t position() const { return fPos; } 25 inline void setPosition(size_t pos) { fPos = pos; } 26 void clean() { 27 fCluster = nullptr; 28 fPos = 0; 29 } 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: 41 TextStretch() : fStart(), fEnd(), fWidth(0), fWidthWithGhostSpaces(0) {} 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 55 inline SkScalar width() const { return fWidth; } 56 SkScalar widthWithGhostSpaces() const { return fWidthWithGhostSpaces; } 57 inline Cluster* startCluster() const { return fStart.cluster(); } 58 inline Cluster* endCluster() const { return fEnd.cluster(); } 59 inline Cluster* breakCluster() const { return fBreak.cluster(); } 60 inline InternalLineMetrics& metrics() { return fMetrics; } 61 inline size_t startPos() const { return fStart.position(); } 62 inline size_t endPos() const { return fEnd.position(); } 63 bool endOfCluster() { return fEnd.position() == fEnd.cluster()->endPos(); } 64 bool endOfWord() { 65 return endOfCluster() && 66 (fEnd.cluster()->isHardBreak() || fEnd.cluster()->isSoftBreak()); 67 } 68 69 void extend(TextStretch& stretch) { 70 fMetrics.add(stretch.fMetrics); 71 fEnd = stretch.fEnd; 72 fWidth += stretch.fWidth; 73 stretch.clean(); 74 } 75 76 bool empty() { return fStart.cluster() == fEnd.cluster() && 77 fStart.position() == fEnd.position(); } 78 79 void setMetrics(const InternalLineMetrics& metrics) { fMetrics = metrics; } 80 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 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 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 115 void saveBreak() { 116 fWidthWithGhostSpaces = fWidth; 117 fBreak = fEnd; 118 } 119 120 void restoreBreak() { 121 fWidth = fWidthWithGhostSpaces; 122 fEnd = fBreak; 123 } 124 125 void shiftBreak() { 126 fBreak.move(true); 127 } 128 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 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 151 void clean() { 152 fStart.clean(); 153 fEnd.clean(); 154 fWidth = 0; 155 fMetrics.clean(); 156 } 157 158#ifdef OHOS_SUPPORT 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 172public: 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 198 SkScalar height() const { return fHeight; } 199 SkScalar minIntrinsicWidth() const { return fMinIntrinsicWidth; } 200 SkScalar maxIntrinsicWidth() const { return fMaxIntrinsicWidth; } 201 bool exceededMaxLines() const { return fExceededMaxLines; } 202 203private: 204#ifdef OHOS_SUPPORT 205 friend TextTabAlign; 206#endif 207 TextStretch fWords; 208 TextStretch fClusters; 209 TextStretch fClip; 210 TextStretch fEndLine; 211 size_t fLineNumber; 212 bool fTooLongWord; 213 bool fTooLongCluster; 214 215 bool fHardLineBreak; 216 bool fExceededMaxLines; 217 218 SkScalar fHeight; 219 SkScalar fMinIntrinsicWidth; 220 SkScalar fMaxIntrinsicWidth; 221 222 void reset() { 223 fWords.clean(); 224 fClusters.clean(); 225 fClip.clean(); 226 fTooLongCluster = false; 227 fTooLongWord = false; 228 fHardLineBreak = false; 229 } 230 231 SkScalar calculateFakeSpacing(Cluster* cluster, bool autoSpacingEnable); 232 void lookAhead(SkScalar maxWidth, Cluster* endOfClusters, bool applyRoundingHack, WordBreakType wordBreakType, 233 bool autoSpacingEnable); 234 void moveForward(bool hasEllipsis, bool breakAll); // breakAll = true, break occurs after each character 235 void trimEndSpaces(TextAlign align); 236 std::tuple<Cluster*, size_t, SkScalar> trimStartSpaces(Cluster* endOfClusters); 237 SkScalar getClustersTrimmedWidth(); 238 uint64_t CalculateBestScore(std::vector<SkScalar>& widthOut, 239 SkScalar maxWidth, ParagraphImpl* parent, size_t maxLines); 240}; 241} // namespace textlayout 242} // namespace skia 243 244#endif // TextWrapper_DEFINED 245