1 // Copyright 2019 Google LLC. 2 #ifndef TextLine_DEFINED 3 #define TextLine_DEFINED 4 5 #include "include/core/SkPoint.h" 6 #include "include/core/SkRect.h" 7 #include "include/core/SkScalar.h" 8 #include "include/private/SkTArray.h" 9 #include "modules/skparagraph/include/DartTypes.h" 10 #include "modules/skparagraph/include/Metrics.h" 11 #include "modules/skparagraph/include/TextStyle.h" 12 #include "modules/skparagraph/src/Run.h" 13 14 #include <stddef.h> 15 #include <functional> 16 #include <memory> 17 #include <vector> 18 19 class SkCanvas; 20 class SkString; 21 22 namespace skia { 23 namespace textlayout { 24 25 class ParagraphImpl; 26 27 class TextLine { 28 public: 29 30 struct ClipContext { 31 const Run* run; 32 size_t pos; 33 size_t size; 34 SkScalar fTextShift; // Shifts the text inside the run so it's placed at the right position 35 SkRect clip; 36 SkScalar fExcludedTrailingSpaces; 37 bool clippingNeeded; 38 }; 39 40 TextLine() = default; 41 TextLine(const TextLine&) = delete; 42 TextLine& operator=(const TextLine&) = delete; 43 TextLine(TextLine&&) = default; 44 TextLine& operator=(TextLine&&) = default; 45 ~TextLine() = default; 46 47 TextLine(ParagraphImpl* owner, 48 SkVector offset, 49 SkVector advance, 50 BlockRange blocks, 51 TextRange textExcludingSpaces, 52 TextRange text, 53 TextRange textIncludingNewlines, 54 ClusterRange clusters, 55 ClusterRange clustersWithGhosts, 56 SkScalar widthWithSpaces, 57 InternalLineMetrics sizes); 58 trimmedText()59 TextRange trimmedText() const { return fTextExcludingSpaces; } textWithNewlines()60 TextRange textWithNewlines() const { return fTextIncludingNewlines; } text()61 TextRange text() const { return fText; } clusters()62 ClusterRange clusters() const { return fClusterRange; } clustersWithSpaces()63 ClusterRange clustersWithSpaces() { return fGhostClusterRange; } ellipsis()64 Run* ellipsis() const { return fEllipsis.get(); } sizes()65 InternalLineMetrics sizes() const { return fSizes; } empty()66 bool empty() const { return fTextExcludingSpaces.empty(); } 67 spacesWidth()68 SkScalar spacesWidth() const { return fWidthWithSpaces - width(); } height()69 SkScalar height() const { return fAdvance.fY; } width()70 SkScalar width() const { 71 return fAdvance.fX + (fEllipsis != nullptr ? fEllipsis->fAdvance.fX : 0); 72 } shift()73 SkScalar shift() const { return fShift; } 74 SkVector offset() const; 75 alphabeticBaseline()76 SkScalar alphabeticBaseline() const { return fSizes.alphabeticBaseline(); } ideographicBaseline()77 SkScalar ideographicBaseline() const { return fSizes.ideographicBaseline(); } baseline()78 SkScalar baseline() const { return fSizes.baseline(); } 79 80 using RunVisitor = std::function<bool(const Run* run, SkScalar runOffset, TextRange textRange, SkScalar* width)>; 81 void iterateThroughVisualRuns(bool includingGhostSpaces, const RunVisitor& runVisitor) const; 82 using RunStyleVisitor = std::function<void(TextRange textRange, const TextStyle& style, const ClipContext& context)>; 83 SkScalar iterateThroughSingleRunByStyles(const Run* run, SkScalar runOffset, TextRange textRange, 84 StyleType styleType, const RunStyleVisitor& visitor) const; 85 86 using ClustersVisitor = std::function<bool(const Cluster* cluster, bool ghost)>; 87 void iterateThroughClustersInGlyphsOrder(bool reverse, bool includeGhosts, const ClustersVisitor& visitor) const; 88 89 void format(TextAlign align, SkScalar maxWidth); 90 SkRect paint(SkCanvas* canvas, SkScalar x, SkScalar y); 91 void visit(SkScalar x, SkScalar y); 92 void ensureTextBlobCachePopulated(); 93 94 void createEllipsis(SkScalar maxWidth, const SkString& ellipsis, bool ltr); 95 96 // For testing internal structures 97 void scanStyles(StyleType style, const RunStyleVisitor& visitor); 98 setMaxRunMetrics(const InternalLineMetrics & metrics)99 void setMaxRunMetrics(const InternalLineMetrics& metrics) { fMaxRunMetrics = metrics; } getMaxRunMetrics()100 InternalLineMetrics getMaxRunMetrics() const { return fMaxRunMetrics; } 101 102 bool isFirstLine(); 103 bool isLastLine(); 104 void getRectsForRange(TextRange textRange, RectHeightStyle rectHeightStyle, RectWidthStyle rectWidthStyle, std::vector<TextBox>& boxes); 105 void getRectsForPlaceholders(std::vector<TextBox>& boxes); 106 PositionWithAffinity getGlyphPositionAtCoordinate(SkScalar dx); 107 108 ClipContext measureTextInsideOneRun(TextRange textRange, 109 const Run* run, 110 SkScalar runOffsetInLine, 111 SkScalar textOffsetInRunInLine, 112 bool includeGhostSpaces, 113 bool limitToGraphemes) const; 114 115 LineMetrics getMetrics() const; 116 117 SkRect extendHeight(const ClipContext& context) const; 118 119 SkScalar metricsWithoutMultiplier(TextHeightBehavior correction); shiftVertically(SkScalar shift)120 void shiftVertically(SkScalar shift) { fOffset.fY += shift; } 121 122 bool endsWithHardLineBreak() const; 123 124 private: 125 126 std::unique_ptr<Run> shapeEllipsis(const SkString& ellipsis, const Run& run); 127 void justify(SkScalar maxWidth); 128 129 void buildTextBlob(TextRange textRange, const TextStyle& style, const ClipContext& context); 130 void paintBackground(SkCanvas* canvas, SkScalar x, SkScalar y, TextRange textRange, const TextStyle& style, const ClipContext& context) const; 131 SkRect paintShadow(SkCanvas* canvas, SkScalar x, SkScalar y, TextRange textRange, const TextStyle& style, const ClipContext& context) const; 132 void paintDecorations(SkCanvas* canvas, SkScalar x, SkScalar y, TextRange textRange, const TextStyle& style, const ClipContext& context) const; 133 134 void shiftCluster(const Cluster* cluster, SkScalar shift, SkScalar prevShift); 135 136 ParagraphImpl* fOwner; 137 BlockRange fBlockRange; 138 TextRange fTextExcludingSpaces; 139 TextRange fText; 140 TextRange fTextIncludingNewlines; 141 ClusterRange fClusterRange; 142 ClusterRange fGhostClusterRange; 143 // Avoid the malloc/free in the common case of one run per line 144 SkSTArray<1, size_t, true> fRunsInVisualOrder; 145 SkVector fAdvance; // Text size 146 SkVector fOffset; // Text position 147 SkScalar fShift; // Let right 148 SkScalar fWidthWithSpaces; 149 std::unique_ptr<Run> fEllipsis; // In case the line ends with the ellipsis 150 InternalLineMetrics fSizes; // Line metrics as a max of all run metrics and struts 151 InternalLineMetrics fMaxRunMetrics; // No struts - need it for GetRectForRange(max height) 152 bool fHasBackground; 153 bool fHasShadows; 154 bool fHasDecorations; 155 156 LineMetricStyle fAscentStyle; 157 LineMetricStyle fDescentStyle; 158 159 struct TextBlobRecord { 160 void paint(SkCanvas* canvas, SkScalar x, SkScalar y); 161 162 sk_sp<SkTextBlob> fBlob; 163 SkPoint fOffset = SkPoint::Make(0.0f, 0.0f); 164 SkPaint fPaint; 165 SkRect fBounds = SkRect::MakeEmpty(); 166 bool fClippingNeeded = false; 167 SkRect fClipRect = SkRect::MakeEmpty(); 168 169 // Extra fields only used for the (experimental) visitor 170 const Run* fVisitor_Run; 171 size_t fVisitor_Pos; 172 }; 173 bool fTextBlobCachePopulated; 174 public: 175 std::vector<TextBlobRecord> fTextBlobCache; 176 }; 177 } // namespace textlayout 178 } // namespace skia 179 180 #endif // TextLine_DEFINED 181