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