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