1 // Copyright 2019 Google LLC. 2 #ifndef TextLine_DEFINED 3 #define TextLine_DEFINED 4 5 #include "include/ParagraphStyle.h" 6 #include "include/core/SkPoint.h" 7 #include "include/core/SkRect.h" 8 #include "include/core/SkScalar.h" 9 #include "include/private/SkBitmaskEnum.h" // IWYU pragma: keep 10 #include "include/private/SkTArray.h" 11 #include "modules/skparagraph/include/DartTypes.h" 12 #include "modules/skparagraph/include/Metrics.h" 13 #include "modules/skparagraph/include/ParagraphPainter.h" 14 #include "modules/skparagraph/include/RunBase.h" 15 #ifdef OHOS_SUPPORT 16 #include "modules/skparagraph/include/TextLineBase.h" 17 #endif 18 #include "modules/skparagraph/include/TextStyle.h" 19 #include "modules/skparagraph/src/Run.h" 20 21 #include <stddef.h> 22 #include <functional> 23 #include <memory> 24 #include <vector> 25 26 class SkString; 27 28 namespace skia { 29 namespace textlayout { 30 31 class ParagraphImpl; 32 struct DecorationContext { 33 SkScalar thickness = 0.0f; 34 SkScalar underlinePosition = 0.0f; 35 SkScalar textBlobTop = 0.0f; 36 }; 37 class TextLine { 38 public: 39 struct ClipContext { 40 const Run* run; 41 size_t pos; 42 size_t size; 43 SkScalar fTextShift; // Shifts the text inside the run so it's placed at the right position 44 SkRect clip; 45 SkScalar fExcludedTrailingSpaces; 46 bool clippingNeeded; 47 }; 48 49 struct PathParameters { 50 const RSPath* recordPath = nullptr; 51 SkScalar hOffset = 0; 52 SkScalar vOffset = 0; 53 } pathParameters; 54 55 enum TextAdjustment { 56 GlyphCluster = 0x01, // All text producing glyphs pointing to the same ClusterIndex 57 GlyphemeCluster = 0x02, // base glyph + all attached diacritics 58 Grapheme = 0x04, // Text adjusted to graphemes 59 GraphemeGluster = 0x05, // GlyphCluster & Grapheme 60 }; 61 62 #ifdef OHOS_SUPPORT 63 enum EllipsisReadStrategy { 64 DEFAULT = 0, // default 65 READ_REPLACED_WORD = 1, // read replaced word 66 READ_ELLIPSIS_WORD = 2, // read ellipsis word 67 }; 68 69 struct HighLevelInfo { 70 ClusterIndex clusterIndex{SIZE_MAX}; 71 bool isClusterPunct{false}; 72 SkScalar punctWidths{0.0f}; 73 SkScalar highLevelOffset{0.0f}; 74 }; 75 76 struct MiddleLevelInfo { 77 ClusterIndex clusterIndex{SIZE_MAX}; 78 bool isPrevClusterSpace{true}; 79 }; 80 81 struct ClusterLevelsIndices { 82 std::vector<HighLevelInfo> highLevelIndices; 83 std::vector<MiddleLevelInfo> middleLevelIndices; 84 std::vector<ClusterIndex> LowLevelIndices; 85 SkScalar middleLevelOffset{0.0f}; 86 SkScalar lowLevelOffset{0.0f}; 87 emptyClusterLevelsIndices88 bool empty() 89 { 90 return highLevelIndices.empty() && middleLevelIndices.empty() && LowLevelIndices.empty(); 91 } 92 }; 93 94 enum class ShiftLevel { 95 Undefined, 96 HighLevel, // Level 1 Label: Punctuation 97 MiddleLevel, // Level-2 label: WhitespaceBreak, between ideographic and non-ideographic characters 98 LowLevel // Level-3 label: Between ideographic characters 99 }; 100 #endif 101 102 TextLine() = default; 103 TextLine(const TextLine&) = delete; 104 TextLine& operator=(const TextLine&) = delete; 105 TextLine(TextLine&&) = default; 106 TextLine& operator=(TextLine&&) = default; 107 ~TextLine() = default; 108 109 TextLine(ParagraphImpl* owner, 110 SkVector offset, 111 SkVector advance, 112 BlockRange blocks, 113 TextRange textExcludingSpaces, 114 TextRange text, 115 TextRange textIncludingNewlines, 116 ClusterRange clusters, 117 ClusterRange clustersWithGhosts, 118 SkScalar widthWithSpaces, 119 InternalLineMetrics sizes); 120 trimmedText()121 TextRange trimmedText() const { return fTextExcludingSpaces; } textWithNewlines()122 TextRange textWithNewlines() const { return fTextIncludingNewlines; } text()123 TextRange text() const { return fText; } clusters()124 ClusterRange clusters() const { return fClusterRange; } clustersWithSpaces()125 ClusterRange clustersWithSpaces() const { return fGhostClusterRange; } ellipsis()126 Run* ellipsis() const { return fEllipsis.get(); } sizes()127 InternalLineMetrics sizes() const { return fSizes; } empty()128 bool empty() const { return fTextExcludingSpaces.empty(); } 129 spacesWidth()130 SkScalar spacesWidth() const { return fWidthWithSpaces - width(); } height()131 SkScalar height() const { return fAdvance.fY; } width()132 SkScalar width() const { 133 return fAdvance.fX + (fEllipsis != nullptr ? fEllipsis->fAdvance.fX : 0); 134 } widthWithoutEllipsis()135 SkScalar widthWithoutEllipsis() const { return fAdvance.fX; } widthWithEllipsisSpaces()136 SkScalar widthWithEllipsisSpaces() const { 137 return fWidthWithSpaces + (fEllipsis != nullptr ? fEllipsis->fAdvance.fX : 0); 138 } 139 SkVector offset() const; setLineOffsetX(SkScalar x)140 void setLineOffsetX(SkScalar x) { 141 fOffset.set(x, fOffset.y()); 142 } 143 alphabeticBaseline()144 SkScalar alphabeticBaseline() const { return fSizes.alphabeticBaseline(); } ideographicBaseline()145 SkScalar ideographicBaseline() const { return fSizes.ideographicBaseline(); } baseline()146 SkScalar baseline() const { return fSizes.baseline(); } 147 #ifdef OHOS_SUPPORT 148 void extendCoordinateRange(PositionWithAffinity& positionWithAffinity); 149 #endif 150 151 using RunVisitor = std::function<bool( 152 const Run* run, SkScalar runOffset, TextRange textRange, SkScalar* width)>; 153 154 #ifdef OHOS_SUPPORT 155 bool processEllipsisRun(bool& isAlreadyUseEllipsis, 156 SkScalar& runOffset, 157 EllipsisReadStrategy ellipsisReadStrategy, 158 const RunVisitor& visitor, 159 SkScalar& runWidthInLine) const; 160 bool processInsertedRun(const Run* run, 161 SkScalar& runOffset, 162 EllipsisReadStrategy ellipsisReadStrategy, 163 const RunVisitor& visitor, 164 SkScalar& runWidthInLine) const; 165 #endif 166 167 #ifdef OHOS_SUPPORT 168 void iterateThroughVisualRuns(EllipsisReadStrategy ellipsisReadStrategy, 169 bool includingGhostSpaces, 170 const RunVisitor& runVisitor) const; 171 #else 172 void iterateThroughVisualRuns(bool includingGhostSpaces, const RunVisitor& runVisitor) const; 173 #endif 174 using RunStyleVisitor = std::function<void( 175 TextRange textRange, const TextStyle& style, const ClipContext& context)>; 176 SkScalar iterateThroughSingleRunByStyles(TextAdjustment textAdjustment, 177 const Run* run, 178 SkScalar runOffset, 179 TextRange textRange, 180 StyleType styleType, 181 const RunStyleVisitor& visitor) const; 182 183 using ClustersVisitor = std::function<bool(const Cluster* cluster, ClusterIndex index, bool ghost)>; 184 void iterateThroughClustersInGlyphsOrder(bool reverse, 185 bool includeGhosts, 186 const ClustersVisitor& visitor) const; 187 188 void format(TextAlign align, SkScalar maxWidth, EllipsisModal ellipsisModal); 189 SkScalar autoSpacing(); 190 void paint(ParagraphPainter* painter, SkScalar x, SkScalar y); 191 void paint(ParagraphPainter* painter, const RSPath* path, SkScalar hOffset, SkScalar vOffset); 192 void visit(SkScalar x, SkScalar y); 193 void ensureTextBlobCachePopulated(); setParagraphImpl(ParagraphImpl * newpara)194 void setParagraphImpl(ParagraphImpl* newpara) { fOwner = newpara; } setBlockRange(const BlockRange & blockRange)195 void setBlockRange(const BlockRange& blockRange) { fBlockRange = blockRange; } 196 void countWord(int& wordCount, bool& inWord); 197 void ellipsisNotFitProcess(EllipsisModal ellipsisModal); 198 #ifdef OHOS_SUPPORT 199 void createTailEllipsis(SkScalar maxWidth, const SkString& ellipsis, bool ltr, WordBreakType wordBreakType); 200 void handleTailEllipsisInEmptyLine(std::unique_ptr<Run>& ellipsisRun, const SkString& ellipsis, 201 SkScalar width, WordBreakType wordBreakType); 202 void TailEllipsisUpdateLine(Cluster& cluster, float width, size_t clusterIndex, WordBreakType wordBreakType); 203 void createHeadEllipsis(SkScalar maxWidth, const SkString& ellipsis, bool ltr); 204 #endif 205 // For testing internal structures 206 void scanStyles(StyleType style, const RunStyleVisitor& visitor); 207 setMaxRunMetrics(const InternalLineMetrics & metrics)208 void setMaxRunMetrics(const InternalLineMetrics& metrics) { fMaxRunMetrics = metrics; } getMaxRunMetrics()209 InternalLineMetrics getMaxRunMetrics() const { return fMaxRunMetrics; } 210 211 bool isFirstLine() const; 212 bool isLastLine() const; 213 void getRectsForRange(TextRange textRange, 214 RectHeightStyle rectHeightStyle, 215 RectWidthStyle rectWidthStyle, 216 std::vector<TextBox>& boxes) const; 217 void getRectsForPlaceholders(std::vector<TextBox>& boxes); 218 PositionWithAffinity getGlyphPositionAtCoordinate(SkScalar dx); 219 220 ClipContext measureTextInsideOneRun(TextRange textRange, 221 const Run* run, 222 SkScalar runOffsetInLine, 223 SkScalar textOffsetInRunInLine, 224 bool includeGhostSpaces, 225 TextAdjustment textAdjustment) const; 226 227 LineMetrics getMetrics() const; 228 229 SkRect extendHeight(const ClipContext& context) const; 230 shiftVertically(SkScalar shift)231 void shiftVertically(SkScalar shift) { fOffset.fY += shift; } 232 setAscentStyle(LineMetricStyle style)233 void setAscentStyle(LineMetricStyle style) { fAscentStyle = style; } setDescentStyle(LineMetricStyle style)234 void setDescentStyle(LineMetricStyle style) { fDescentStyle = style; } 235 236 bool endsWithHardLineBreak() const; 237 #ifdef OHOS_SUPPORT 238 bool endsWithOnlyHardBreak() const; 239 #endif 240 std::unique_ptr<Run> shapeString(const SkString& string, const Cluster* cluster); 241 std::unique_ptr<Run> shapeEllipsis(const SkString& ellipsis, const Cluster* cluster); getLineAllRuns()242 SkSTArray<1, size_t, true> getLineAllRuns() const { return fRunsInVisualOrder; }; 243 244 size_t getGlyphCount() const; 245 std::vector<std::unique_ptr<RunBase>> getGlyphRuns() const; 246 TextLine CloneSelf(); getTextRangeReplacedByEllipsis()247 TextRange getTextRangeReplacedByEllipsis() const { return fTextRangeReplacedByEllipsis; } setTextBlobCachePopulated(const bool textBlobCachePopulated)248 void setTextBlobCachePopulated(const bool textBlobCachePopulated) { 249 fTextBlobCachePopulated = textBlobCachePopulated; 250 } 251 252 #ifdef OHOS_SUPPORT 253 std::unique_ptr<TextLineBase> createTruncatedLine(double width, EllipsisModal ellipsisMode, 254 const std::string& ellipsisStr); 255 double getTypographicBounds(double* ascent, double* descent, double* leading) const; 256 RSRect getImageBounds() const; 257 double getTrailingSpaceWidth() const; 258 int32_t getStringIndexForPosition(SkPoint point) const; 259 double getOffsetForStringIndex(int32_t index) const; 260 std::map<int32_t, double> getIndexAndOffsets(bool& isHardBreak) const; 261 double getAlignmentOffset(double alignmentFactor, double alignmentWidth) const; 262 SkRect generatePaintRegion(SkScalar x, SkScalar y); 263 void updateClusterOffsets(const Cluster* cluster, SkScalar shift, SkScalar prevShift); 264 void justifyUpdateRtlWidth(const SkScalar maxWidth, const SkScalar textLen); 265 void setBreakWithHyphen(bool breakWithHyphen); 266 bool getBreakWithHyphen() const; 267 void updateTextLinePaintAttributes(); 268 #endif 269 270 private: 271 struct RoundRectAttr { 272 int styleId; 273 RectStyle roundRectStyle; 274 SkRect rect; 275 }; 276 void justify(SkScalar maxWidth); 277 void buildTextBlob(TextRange textRange, const TextStyle& style, const ClipContext& context); 278 void paintBackground(ParagraphPainter* painter, 279 SkScalar x, 280 SkScalar y, 281 TextRange textRange, 282 const TextStyle& style, 283 const ClipContext& context) const; 284 void paintRoundRect(ParagraphPainter* painter, SkScalar x, SkScalar y, const Run* run) const; 285 void paintShadow(ParagraphPainter* painter, 286 SkScalar x, 287 SkScalar y, 288 TextRange textRange, 289 const TextStyle& style, 290 const ClipContext& context) const; 291 void paintDecorations(ParagraphPainter* painter, 292 SkScalar x, 293 SkScalar y, 294 TextRange textRange, 295 const TextStyle& style, 296 const ClipContext& context) const; 297 298 void shiftCluster(const Cluster* cluster, SkScalar shift, SkScalar prevShift); 299 void spacingCluster(const Cluster* cluster, SkScalar spacing, SkScalar prevSpacing); 300 bool hasBackgroundRect(const RoundRectAttr& attr); 301 void computeRoundRect(int& index, int& preIndex, std::vector<Run*>& groupRuns, Run* run); 302 void prepareRoundRect(); 303 SkScalar calculateThickness(const TextStyle& style, const ClipContext& context); 304 #ifdef OHOS_SUPPORT 305 void measureTextWithSpacesAtTheEnd(ClipContext& context, bool includeGhostSpaces) const; 306 void computeNextPaintGlyphRange(ClipContext& context, const TextRange& lastGlyphRange, StyleType styleType) const; 307 SkRect computeShadowRect(SkScalar x, SkScalar y, const TextStyle& style, const ClipContext& context) const; 308 SkRect getAllShadowsRect(SkScalar x, SkScalar y) const; 309 #endif 310 311 ParagraphImpl* fOwner; 312 BlockRange fBlockRange; 313 TextRange fTextExcludingSpaces; 314 TextRange fText; 315 TextRange fTextIncludingNewlines; 316 ClusterRange fClusterRange; 317 ClusterRange fGhostClusterRange; 318 // Avoid the malloc/free in the common case of one run per line 319 SkSTArray<1, size_t, true> fRunsInVisualOrder; 320 SkVector fAdvance; // Text size 321 SkVector fOffset; // Text position 322 SkScalar fShift; // Let right 323 SkScalar fWidthWithSpaces; 324 std::unique_ptr<Run> fEllipsis; // In case the line ends with the ellipsis 325 TextRange fTextRangeReplacedByEllipsis; // text range replaced by ellipsis 326 InternalLineMetrics fSizes; // Line metrics as a max of all run metrics and struts 327 InternalLineMetrics fMaxRunMetrics; // No struts - need it for GetRectForRange(max height) 328 size_t fEllipsisIndex = EMPTY_INDEX; 329 330 bool fHasBackground; 331 bool fHasShadows; 332 bool fHasDecorations; 333 bool fIsArcText; 334 bool fArcTextState; 335 bool fLastClipRunLtr; 336 337 LineMetricStyle fAscentStyle; 338 LineMetricStyle fDescentStyle; 339 340 struct TextBlobRecord { 341 void paint(ParagraphPainter* painter, SkScalar x, SkScalar y); 342 void paint(ParagraphPainter* painter); 343 344 #ifndef USE_SKIA_TXT 345 sk_sp<SkTextBlob> fBlob; 346 #else 347 std::shared_ptr<RSTextBlob> fBlob; 348 #endif 349 SkPoint fOffset = SkPoint::Make(0.0f, 0.0f); 350 ParagraphPainter::SkPaintOrID fPaint; 351 SkRect fBounds = SkRect::MakeEmpty(); 352 bool fClippingNeeded = false; 353 SkRect fClipRect = SkRect::MakeEmpty(); 354 355 // Extra fields only used for the (experimental) visitor 356 const Run* fVisitor_Run; 357 size_t fVisitor_Pos; 358 size_t fVisitor_Size; 359 }; 360 bool fTextBlobCachePopulated; 361 DecorationContext fDecorationContext; 362 std::vector<RoundRectAttr> roundRectAttrs = {}; 363 #ifdef OHOS_SUPPORT 364 bool fIsTextLineEllipsisHeadModal = false; 365 #endif 366 public: 367 std::vector<TextBlobRecord> fTextBlobCache; 368 #ifdef OHOS_SUPPORT 369 SkString fEllipsisString; 370 bool fBreakWithHyphen{false}; 371 std::unique_ptr<Run> fHyphenRun; 372 size_t fHyphenIndex = EMPTY_INDEX; 373 #endif 374 }; 375 } // namespace textlayout 376 } // namespace skia 377 378 namespace sknonstd { 379 template <> struct is_bitmask_enum<skia::textlayout::TextLine::TextAdjustment> : std::true_type {}; 380 } // namespace sknonstd 381 382 #endif // TextLine_DEFINED 383