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