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