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/RunBase.h" 15 #include "modules/skparagraph/include/TextStyle.h" 16 #include "modules/skparagraph/src/Run.h" 17 18 #include <stddef.h> 19 #include <functional> 20 #include <memory> 21 #include <vector> 22 23 class SkString; 24 25 namespace skia { 26 namespace textlayout { 27 28 class ParagraphImpl; 29 struct DecorationContext { 30 SkScalar thickness = 0.0f; 31 SkScalar underlinePosition = 0.0f; 32 SkScalar textBlobTop = 0.0f; 33 }; 34 class TextLine { 35 public: 36 37 struct ClipContext { 38 const Run* run; 39 size_t pos; 40 size_t size; 41 SkScalar fTextShift; // Shifts the text inside the run so it's placed at the right position 42 SkRect clip; 43 SkScalar fExcludedTrailingSpaces; 44 bool clippingNeeded; 45 }; 46 47 struct PathParameters { 48 const RSPath* recordPath = nullptr; 49 SkScalar hOffset = 0; 50 SkScalar vOffset = 0; 51 } pathParameters; 52 53 enum TextAdjustment { 54 GlyphCluster = 0x01, // All text producing glyphs pointing to the same ClusterIndex 55 GlyphemeCluster = 0x02, // base glyph + all attached diacritics 56 Grapheme = 0x04, // Text adjusted to graphemes 57 GraphemeGluster = 0x05, // GlyphCluster & Grapheme 58 }; 59 60 #ifdef OHOS_SUPPORT 61 enum EllipsisReadStrategy { 62 DEFAULT = 0, // default 63 READ_REPLACED_WORD = 1, // read replaced word 64 READ_ELLIPSIS_WORD = 2, // read ellipsis word 65 }; 66 #endif 67 68 TextLine() = default; 69 TextLine(const TextLine&) = delete; 70 TextLine& operator=(const TextLine&) = delete; 71 TextLine(TextLine&&) = default; 72 TextLine& operator=(TextLine&&) = default; 73 ~TextLine() = default; 74 75 TextLine(ParagraphImpl* owner, 76 SkVector offset, 77 SkVector advance, 78 BlockRange blocks, 79 TextRange textExcludingSpaces, 80 TextRange text, 81 TextRange textIncludingNewlines, 82 ClusterRange clusters, 83 ClusterRange clustersWithGhosts, 84 SkScalar widthWithSpaces, 85 InternalLineMetrics sizes); 86 trimmedText()87 TextRange trimmedText() const { return fTextExcludingSpaces; } textWithNewlines()88 TextRange textWithNewlines() const { return fTextIncludingNewlines; } text()89 TextRange text() const { return fText; } clusters()90 ClusterRange clusters() const { return fClusterRange; } clustersWithSpaces()91 ClusterRange clustersWithSpaces() const { return fGhostClusterRange; } ellipsis()92 Run* ellipsis() const { return fEllipsis.get(); } sizes()93 InternalLineMetrics sizes() const { return fSizes; } empty()94 bool empty() const { return fTextExcludingSpaces.empty(); } 95 spacesWidth()96 SkScalar spacesWidth() const { return fWidthWithSpaces - width(); } height()97 SkScalar height() const { return fAdvance.fY; } width()98 SkScalar width() const { 99 return fAdvance.fX + (fEllipsis != nullptr ? fEllipsis->fAdvance.fX : 0); 100 } widthWithoutEllipsis()101 SkScalar widthWithoutEllipsis() const { return fAdvance.fX; } widthWithEllipsisSpaces()102 SkScalar widthWithEllipsisSpaces() const { 103 return fWidthWithSpaces + (fEllipsis != nullptr ? fEllipsis->fAdvance.fX : 0); 104 } 105 SkVector offset() const; setLineOffsetX(SkScalar x)106 void setLineOffsetX(SkScalar x) { 107 fOffset.set(x, fOffset.y()); 108 } 109 alphabeticBaseline()110 SkScalar alphabeticBaseline() const { return fSizes.alphabeticBaseline(); } ideographicBaseline()111 SkScalar ideographicBaseline() const { return fSizes.ideographicBaseline(); } baseline()112 SkScalar baseline() const { return fSizes.baseline(); } 113 114 using RunVisitor = std::function<bool( 115 const Run* run, SkScalar runOffset, TextRange textRange, SkScalar* width)>; 116 117 #ifdef OHOS_SUPPORT 118 bool processEllipsisRun(bool& isAlreadyUseEllipsis, 119 SkScalar& runOffset, 120 EllipsisReadStrategy ellipsisReadStrategy, 121 const RunVisitor& visitor, 122 SkScalar& runWidthInLine) const; 123 #endif 124 125 #ifdef OHOS_SUPPORT 126 void iterateThroughVisualRuns(EllipsisReadStrategy ellipsisReadStrategy, 127 bool includingGhostSpaces, 128 const RunVisitor& runVisitor) const; 129 #else 130 void iterateThroughVisualRuns(bool includingGhostSpaces, const RunVisitor& runVisitor) const; 131 #endif 132 using RunStyleVisitor = std::function<void( 133 TextRange textRange, const TextStyle& style, const ClipContext& context)>; 134 SkScalar iterateThroughSingleRunByStyles(TextAdjustment textAdjustment, 135 const Run* run, 136 SkScalar runOffset, 137 TextRange textRange, 138 StyleType styleType, 139 const RunStyleVisitor& visitor) const; 140 141 using ClustersVisitor = std::function<bool(const Cluster* cluster, ClusterIndex index, bool ghost)>; 142 void iterateThroughClustersInGlyphsOrder(bool reverse, 143 bool includeGhosts, 144 const ClustersVisitor& visitor) const; 145 146 void format(TextAlign align, SkScalar maxWidth, EllipsisModal ellipsisModal); 147 SkScalar calculateSpacing(const Cluster prevCluster, const Cluster curCluster); 148 SkScalar autoSpacing(); 149 void paint(ParagraphPainter* painter, SkScalar x, SkScalar y); 150 void paint(ParagraphPainter* painter, const RSPath* path, SkScalar hOffset, SkScalar vOffset); 151 void visit(SkScalar x, SkScalar y); 152 void ensureTextBlobCachePopulated(); setParagraphImpl(ParagraphImpl * newpara)153 void setParagraphImpl(ParagraphImpl* newpara) { fOwner = newpara; } setBlockRange(const BlockRange & blockRange)154 void setBlockRange(const BlockRange& blockRange) { fBlockRange = blockRange; } 155 void countWord(int& wordCount, bool& inWord); 156 void ellipsisNotFitProcess(EllipsisModal ellipsisModal); 157 void createTailEllipsis(SkScalar maxWidth, const SkString& ellipsis, bool ltr, WordBreakType wordBreakType); 158 void createHeadEllipsis(SkScalar maxWidth, const SkString& ellipsis, bool ltr); 159 // For testing internal structures 160 void scanStyles(StyleType style, const RunStyleVisitor& visitor); 161 setMaxRunMetrics(const InternalLineMetrics & metrics)162 void setMaxRunMetrics(const InternalLineMetrics& metrics) { fMaxRunMetrics = metrics; } getMaxRunMetrics()163 InternalLineMetrics getMaxRunMetrics() const { return fMaxRunMetrics; } 164 165 bool isFirstLine() const; 166 bool isLastLine() const; 167 void getRectsForRange(TextRange textRange, 168 RectHeightStyle rectHeightStyle, 169 RectWidthStyle rectWidthStyle, 170 std::vector<TextBox>& boxes) const; 171 void getRectsForPlaceholders(std::vector<TextBox>& boxes); 172 PositionWithAffinity getGlyphPositionAtCoordinate(SkScalar dx); 173 174 ClipContext measureTextInsideOneRun(TextRange textRange, 175 const Run* run, 176 SkScalar runOffsetInLine, 177 SkScalar textOffsetInRunInLine, 178 bool includeGhostSpaces, 179 TextAdjustment textAdjustment) const; 180 181 LineMetrics getMetrics() const; 182 183 SkRect extendHeight(const ClipContext& context) const; 184 shiftVertically(SkScalar shift)185 void shiftVertically(SkScalar shift) { fOffset.fY += shift; } 186 setAscentStyle(LineMetricStyle style)187 void setAscentStyle(LineMetricStyle style) { fAscentStyle = style; } setDescentStyle(LineMetricStyle style)188 void setDescentStyle(LineMetricStyle style) { fDescentStyle = style; } 189 190 bool endsWithHardLineBreak() const; 191 std::unique_ptr<Run> shapeEllipsis(const SkString& ellipsis, const Cluster* cluster); getLineAllRuns()192 SkSTArray<1, size_t, true> getLineAllRuns() const { return fRunsInVisualOrder; }; 193 194 size_t getGlyphCount() const; 195 std::vector<std::unique_ptr<RunBase>> getGlyphRuns() const; 196 TextLine CloneSelf(); getTextRangeReplacedByEllipsis()197 TextRange getTextRangeReplacedByEllipsis() const { return fTextRangeReplacedByEllipsis; } setTextBlobCachePopulated(const bool textBlobCachePopulated)198 void setTextBlobCachePopulated(const bool textBlobCachePopulated) { 199 fTextBlobCachePopulated = textBlobCachePopulated; 200 } 201 202 #ifdef OHOS_SUPPORT 203 SkRect generatePaintRegion(SkScalar x, SkScalar y); 204 #endif 205 206 private: 207 struct RoundRectAttr { 208 int styleId; 209 RectStyle roundRectStyle; 210 SkRect rect; 211 }; 212 213 void justify(SkScalar maxWidth); 214 215 void buildTextBlob(TextRange textRange, const TextStyle& style, const ClipContext& context); 216 void paintBackground(ParagraphPainter* painter, 217 SkScalar x, 218 SkScalar y, 219 TextRange textRange, 220 const TextStyle& style, 221 const ClipContext& context) const; 222 void paintRoundRect(ParagraphPainter* painter, SkScalar x, SkScalar y, const Run* run) const; 223 void paintShadow(ParagraphPainter* painter, 224 SkScalar x, 225 SkScalar y, 226 TextRange textRange, 227 const TextStyle& style, 228 const ClipContext& context) const; 229 void paintDecorations(ParagraphPainter* painter, 230 SkScalar x, 231 SkScalar y, 232 TextRange textRange, 233 const TextStyle& style, 234 const ClipContext& context) const; 235 236 void shiftCluster(const Cluster* cluster, SkScalar shift, SkScalar prevShift); 237 void spacingCluster(const Cluster* cluster, SkScalar spacing, SkScalar prevSpacing); 238 bool hasBackgroundRect(const RoundRectAttr& attr); 239 void computeRoundRect(int& index, int& preIndex, std::vector<Run*>& groupRuns, Run* run); 240 void prepareRoundRect(); 241 SkScalar calculateThickness(const TextStyle& style, const ClipContext& context); 242 #ifdef OHOS_SUPPORT 243 void measureTextWithSpacesAtTheEnd(ClipContext& context, bool includeGhostSpaces) const; 244 void computeNextPaintGlyphRange(ClipContext& context, const TextRange& lastGlyphRange, StyleType styleType) const; 245 SkRect computeShadowRect(SkScalar x, SkScalar y, const TextStyle& style, const ClipContext& context) const; 246 SkRect getAllShadowsRect(SkScalar x, SkScalar y) const; 247 #endif 248 249 ParagraphImpl* fOwner; 250 BlockRange fBlockRange; 251 TextRange fTextExcludingSpaces; 252 TextRange fText; 253 TextRange fTextIncludingNewlines; 254 ClusterRange fClusterRange; 255 ClusterRange fGhostClusterRange; 256 // Avoid the malloc/free in the common case of one run per line 257 SkSTArray<1, size_t, true> fRunsInVisualOrder; 258 SkVector fAdvance; // Text size 259 SkVector fOffset; // Text position 260 SkScalar fShift; // Let right 261 SkScalar fWidthWithSpaces; 262 std::unique_ptr<Run> fEllipsis; // In case the line ends with the ellipsis 263 TextRange fTextRangeReplacedByEllipsis; // text range replaced by ellipsis 264 InternalLineMetrics fSizes; // Line metrics as a max of all run metrics and struts 265 InternalLineMetrics fMaxRunMetrics; // No struts - need it for GetRectForRange(max height) 266 size_t fEllipsisIndex = EMPTY_INDEX; 267 268 bool fHasBackground; 269 bool fHasShadows; 270 bool fHasDecorations; 271 bool fIsArcText; 272 bool fArcTextState; 273 bool fLastClipRunLtr; 274 275 LineMetricStyle fAscentStyle; 276 LineMetricStyle fDescentStyle; 277 278 struct TextBlobRecord { 279 void paint(ParagraphPainter* painter, SkScalar x, SkScalar y); 280 void paint(ParagraphPainter* painter); 281 282 #ifndef USE_SKIA_TXT 283 sk_sp<SkTextBlob> fBlob; 284 #else 285 std::shared_ptr<RSTextBlob> fBlob; 286 #endif 287 SkPoint fOffset = SkPoint::Make(0.0f, 0.0f); 288 ParagraphPainter::SkPaintOrID fPaint; 289 SkRect fBounds = SkRect::MakeEmpty(); 290 bool fClippingNeeded = false; 291 SkRect fClipRect = SkRect::MakeEmpty(); 292 293 // Extra fields only used for the (experimental) visitor 294 const Run* fVisitor_Run; 295 size_t fVisitor_Pos; 296 size_t fVisitor_Size; 297 }; 298 bool fTextBlobCachePopulated; 299 DecorationContext fDecorationContext; 300 std::vector<RoundRectAttr> roundRectAttrs = {}; 301 public: 302 std::vector<TextBlobRecord> fTextBlobCache; 303 }; 304 } // namespace textlayout 305 } // namespace skia 306 307 namespace sknonstd { 308 template <> struct is_bitmask_enum<skia::textlayout::TextLine::TextAdjustment> : std::true_type {}; 309 } // namespace sknonstd 310 311 #endif // TextLine_DEFINED 312