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