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/TextStyle.h" 10 #include "modules/skparagraph/src/Run.h" 11 #include "src/core/SkSpan.h" 12 13 namespace skia { 14 namespace textlayout { 15 16 class TextLine { 17 public: 18 TextLine() = default; 19 ~TextLine() = default; 20 21 TextLine(ParagraphImpl* master, 22 SkVector offset, 23 SkVector advance, 24 BlockRange blocks, 25 TextRange text, 26 TextRange textWithSpaces, 27 ClusterRange clusters, 28 ClusterRange clustersWithGhosts, 29 SkScalar widthWithSpaces, 30 LineMetrics sizes); 31 setMaster(ParagraphImpl * master)32 void setMaster(ParagraphImpl* master) { fMaster = master; } 33 trimmedText()34 TextRange trimmedText() const { return fTextRange; } textWithSpaces()35 TextRange textWithSpaces() const { return fTextWithWhitespacesRange; } clusters()36 ClusterRange clusters() const { return fClusterRange; } clustersWithSpaces()37 ClusterRange clustersWithSpaces() { return fGhostClusterRange; } ellipsis()38 Run* ellipsis() const { return fEllipsis.get(); } sizes()39 LineMetrics sizes() const { return fSizes; } empty()40 bool empty() const { return fTextRange.empty(); } 41 height()42 SkScalar height() const { return fAdvance.fY; } width()43 SkScalar width() const { 44 return fAdvance.fX + (fEllipsis != nullptr ? fEllipsis->fAdvance.fX : 0); 45 } shift()46 SkScalar shift() const { return fShift; } widthWithSpaces()47 SkScalar widthWithSpaces() const { return fWidthWithSpaces; } 48 SkVector offset() const; 49 alphabeticBaseline()50 SkScalar alphabeticBaseline() const { return fSizes.alphabeticBaseline(); } ideographicBaseline()51 SkScalar ideographicBaseline() const { return fSizes.ideographicBaseline(); } baseline()52 SkScalar baseline() const { return fSizes.baseline(); } roundingDelta()53 SkScalar roundingDelta() const { return fSizes.delta(); } 54 55 using StyleVisitor = std::function<SkScalar(TextRange textRange, const TextStyle& style, 56 SkScalar offsetX)>; 57 void iterateThroughStylesInTextOrder(StyleType styleType, const StyleVisitor& visitor) const; 58 59 SkScalar calculateLeftVisualOffset(TextRange textRange) const; 60 61 using RunVisitor = std::function<bool(Run* run, size_t pos, size_t size, TextRange text, 62 SkRect clip, SkScalar shift, bool clippingNeeded)>; 63 SkScalar iterateThroughRuns(TextRange textRange, 64 SkScalar offsetX, 65 bool includeGhostWhitespaces, 66 const RunVisitor& visitor) const; 67 68 using ClustersVisitor = std::function<bool(const Cluster* cluster, ClusterIndex index, bool leftToRight, bool ghost)>; 69 void iterateThroughClustersInGlyphsOrder(bool reverse, bool includeGhosts, const ClustersVisitor& visitor) const; 70 71 void format(TextAlign effectiveAlign, SkScalar maxWidth); 72 void paint(SkCanvas* canvas); 73 74 void createEllipsis(SkScalar maxWidth, const SkString& ellipsis, bool ltr); 75 76 // For testing internal structures 77 void scanStyles(StyleType style, const StyleVisitor& visitor); 78 void scanRuns(const RunVisitor& visitor); 79 80 TextAlign assumedTextAlign() const; 81 82 private: 83 84 Run* shapeEllipsis(const SkString& ellipsis, Run* run); 85 void justify(SkScalar maxWidth); 86 87 SkRect measureTextInsideOneRun(TextRange textRange, 88 Run* run, 89 size_t& pos, 90 size_t& size, 91 bool includeGhostSpaces, 92 bool& clippingNeeded) const; 93 94 SkScalar paintText(SkCanvas* canvas, TextRange textRange, const TextStyle& style, SkScalar offsetX) const; 95 SkScalar paintBackground(SkCanvas* canvas, TextRange textRange, const TextStyle& style, 96 SkScalar offsetX) const; 97 SkScalar paintShadow(SkCanvas* canvas, TextRange textRange, const TextStyle& style, 98 SkScalar offsetX) const; 99 SkScalar paintDecorations(SkCanvas* canvas, TextRange textRange, const TextStyle& style, 100 SkScalar offsetX) const; 101 102 void computeDecorationPaint(SkPaint& paint, SkRect clip, const TextStyle& style, 103 SkPath& path) const; 104 contains(const Cluster * cluster)105 bool contains(const Cluster* cluster) const { 106 return fTextRange.contains(cluster->textRange()); 107 } 108 109 ParagraphImpl* fMaster; 110 BlockRange fBlockRange; 111 TextRange fTextRange; 112 TextRange fTextWithWhitespacesRange; 113 ClusterRange fClusterRange; 114 ClusterRange fGhostClusterRange; 115 116 SkTArray<size_t, true> fLogical; 117 SkVector fAdvance; // Text size 118 SkVector fOffset; // Text position 119 SkScalar fShift; // Left right 120 SkScalar fWidthWithSpaces; 121 std::shared_ptr<Run> fEllipsis; // In case the line ends with the ellipsis 122 LineMetrics fSizes; // Line metrics as a max of all run metrics 123 bool fHasBackground; 124 bool fHasShadows; 125 bool fHasDecorations; 126 127 // TODO: use for ellipsis the common cache 128 static SkTHashMap<SkFont, Run> fEllipsisCache; // All found so far shapes of ellipsis 129 }; 130 } // namespace textlayout 131 } // namespace skia 132 133 #endif // TextLine_DEFINED 134