1 // Copyright 2019 Google LLC. 2 #ifndef TextLine_DEFINED 3 #define TextLine_DEFINED 4 5 #include "include/core/SkCanvas.h" 6 #include "include/private/SkTArray.h" 7 #include "include/private/SkTHash.h" 8 #include "modules/skparagraph/include/DartTypes.h" 9 #include "modules/skparagraph/include/Metrics.h" 10 #include "modules/skparagraph/include/TextStyle.h" 11 #include "modules/skparagraph/src/Run.h" 12 #include "src/core/SkSpan.h" 13 14 namespace skia { 15 namespace textlayout { 16 17 class TextLine { 18 public: 19 20 struct ClipContext { 21 const Run* run; 22 size_t pos; 23 size_t size; 24 SkScalar fTextShift; // Shifts the text inside the run so it's placed at the right position 25 SkRect clip; 26 bool clippingNeeded; 27 }; 28 29 TextLine() = default; 30 ~TextLine() = default; 31 32 TextLine(ParagraphImpl* master, 33 SkVector offset, 34 SkVector advance, 35 BlockRange blocks, 36 TextRange text, 37 TextRange textWithSpaces, 38 ClusterRange clusters, 39 ClusterRange clustersWithGhosts, 40 SkScalar widthWithSpaces, 41 InternalLineMetrics sizes); 42 setMaster(ParagraphImpl * master)43 void setMaster(ParagraphImpl* master) { fMaster = master; } 44 trimmedText()45 TextRange trimmedText() const { return fTextRange; } textWithSpaces()46 TextRange textWithSpaces() const { return fTextWithWhitespacesRange; } clusters()47 ClusterRange clusters() const { return fClusterRange; } clustersWithSpaces()48 ClusterRange clustersWithSpaces() { return fGhostClusterRange; } ellipsis()49 Run* ellipsis() const { return fEllipsis.get(); } sizes()50 InternalLineMetrics sizes() const { return fSizes; } empty()51 bool empty() const { return fTextRange.empty(); } 52 spacesWidth()53 SkScalar spacesWidth() { return fWidthWithSpaces - width(); } height()54 SkScalar height() const { return fAdvance.fY; } width()55 SkScalar width() const { 56 return fAdvance.fX + (fEllipsis != nullptr ? fEllipsis->fAdvance.fX : 0); 57 } shift()58 SkScalar shift() const { return fShift; } 59 SkVector offset() const; 60 alphabeticBaseline()61 SkScalar alphabeticBaseline() const { return fSizes.alphabeticBaseline(); } ideographicBaseline()62 SkScalar ideographicBaseline() const { return fSizes.ideographicBaseline(); } baseline()63 SkScalar baseline() const { return fSizes.baseline(); } 64 65 using RunVisitor = std::function<bool(const Run* run, SkScalar runOffset, TextRange textRange, SkScalar* width)>; 66 void iterateThroughVisualRuns(bool includingGhostSpaces, const RunVisitor& runVisitor) const; 67 using RunStyleVisitor = std::function<void(TextRange textRange, const TextStyle& style, const ClipContext& context)>; 68 SkScalar iterateThroughSingleRunByStyles(const Run* run, SkScalar runOffset, TextRange textRange, 69 StyleType styleType, const RunStyleVisitor& visitor) const; 70 71 72 using ClustersVisitor = std::function<bool(const Cluster* cluster, ClusterIndex index, bool leftToRight, bool ghost)>; 73 void iterateThroughClustersInGlyphsOrder(bool reverse, bool includeGhosts, const ClustersVisitor& visitor) const; 74 75 void format(TextAlign effectiveAlign, SkScalar maxWidth); 76 void paint(SkCanvas* canvas); 77 78 void createEllipsis(SkScalar maxWidth, const SkString& ellipsis, bool ltr); 79 80 // For testing internal structures 81 void scanStyles(StyleType style, const RunStyleVisitor& visitor); 82 83 TextAlign assumedTextAlign() const; 84 setMaxRunMetrics(const InternalLineMetrics & metrics)85 void setMaxRunMetrics(const InternalLineMetrics& metrics) { fMaxRunMetrics = metrics; } getMaxRunMetrics()86 InternalLineMetrics getMaxRunMetrics() const { return fMaxRunMetrics; } 87 88 ClipContext measureTextInsideOneRun(TextRange textRange, 89 const Run* run, 90 SkScalar runOffsetInLine, 91 SkScalar textOffsetInRunInLine, 92 bool includeGhostSpaces, 93 bool limitToClusters) const; 94 95 LineMetrics getMetrics() const; 96 97 SkRect calculateBoundaries(); 98 99 SkRect extendHeight(const ClipContext& context) const; 100 101 private: 102 103 Run* shapeEllipsis(const SkString& ellipsis, Run* run); 104 void justify(SkScalar maxWidth); 105 106 void paintText(SkCanvas* canvas, TextRange textRange, const TextStyle& style, const ClipContext& context) const; 107 void paintBackground(SkCanvas* canvas, TextRange textRange, const TextStyle& style, const ClipContext& context) const; 108 void paintShadow(SkCanvas* canvas, TextRange textRange, const TextStyle& style, const ClipContext& context) const; 109 void paintDecorations(SkCanvas* canvas, TextRange textRange, const TextStyle& style, const ClipContext& context) const; 110 111 void computeDecorationPaint(SkPaint& paint, SkRect clip, const TextStyle& style, SkScalar thickness, 112 SkPath& path) const; 113 contains(const Cluster * cluster)114 bool contains(const Cluster* cluster) const { 115 return fTextRange.contains(cluster->textRange()); 116 } 117 118 ParagraphImpl* fMaster; 119 BlockRange fBlockRange; 120 TextRange fTextRange; 121 TextRange fTextWithWhitespacesRange; 122 ClusterRange fClusterRange; 123 ClusterRange fGhostClusterRange; 124 125 SkTArray<size_t, true> fRunsInVisualOrder; 126 SkVector fAdvance; // Text size 127 SkVector fOffset; // Text position 128 SkScalar fShift; // Left right 129 SkScalar fWidthWithSpaces; 130 std::shared_ptr<Run> fEllipsis; // In case the line ends with the ellipsis 131 InternalLineMetrics fSizes; // Line metrics as a max of all run metrics and struts 132 InternalLineMetrics fMaxRunMetrics; // No struts - need it for GetRectForRange(max height) 133 bool fHasBackground; 134 bool fHasShadows; 135 bool fHasDecorations; 136 }; 137 } // namespace textlayout 138 } // namespace skia 139 140 #endif // TextLine_DEFINED 141