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