1// Copyright 2019 Google LLC. 2#ifndef Paragraph_DEFINED 3#define Paragraph_DEFINED 4 5#include "modules/skparagraph/include/FontCollection.h" 6#include "modules/skparagraph/include/Metrics.h" 7#include "modules/skparagraph/include/ParagraphStyle.h" 8#include "modules/skparagraph/include/TextLineBase.h" 9#include "modules/skparagraph/include/TextStyle.h" 10#include <unordered_set> 11#include "drawing.h" 12 13class SkCanvas; 14 15namespace skia { 16namespace textlayout { 17 18class ParagraphPainter; 19 20class Paragraph { 21 22public: 23 Paragraph(); 24 25 Paragraph(ParagraphStyle style, sk_sp<FontCollection> fonts); 26 27 virtual ~Paragraph() = default; 28 29 SkScalar getMaxWidth() { return fWidth; } 30 31 SkScalar getHeight() { return fHeight; } 32 33 SkScalar getMinIntrinsicWidth() { return fMinIntrinsicWidth; } 34 35 SkScalar getMaxIntrinsicWidth() { return fMaxIntrinsicWidth; } 36 37 SkScalar getAlphabeticBaseline() { return fAlphabeticBaseline; } 38 39 SkScalar getIdeographicBaseline() { return fIdeographicBaseline; } 40 41 SkScalar getLongestLine() { return fLongestLine; } 42 43 SkScalar getLongestLineWithIndent() { return fLongestLineWithIndent; } 44 45 void setLongestLineWithIndent(SkScalar longestLineWithIndent) 46 { 47 fLongestLineWithIndent = longestLineWithIndent; 48 } 49 50 SkScalar getGlyphsBoundsTop() { return fGlyphsBoundsTop; } 51 52 SkScalar getGlyphsBoundsBottom() { return fGlyphsBoundsBottom; } 53 54 SkScalar getGlyphsBoundsLeft() { return fGlyphsBoundsLeft; } 55 56 SkScalar getGlyphsBoundsRight() { return fGlyphsBoundsRight; } 57 58 bool didExceedMaxLines() { return fExceededMaxLines; } 59 60 virtual void layout(SkScalar width) = 0; 61 62 virtual void paint(SkCanvas* canvas, SkScalar x, SkScalar y) = 0; 63 64 virtual void paint(ParagraphPainter* painter, SkScalar x, SkScalar y) = 0; 65#ifdef USE_SKIA_TXT 66 virtual void paint(ParagraphPainter* painter, RSPath* path, SkScalar hOffset, SkScalar vOffset) = 0; 67#endif 68 // Returns a vector of bounding boxes that enclose all text between 69 // start and end glyph indexes, including start and excluding end 70 virtual std::vector<TextBox> getRectsForRange(unsigned start, 71 unsigned end, 72 RectHeightStyle rectHeightStyle, 73 RectWidthStyle rectWidthStyle) = 0; 74 75 virtual std::vector<TextBox> getRectsForPlaceholders() = 0; 76 77 // Returns the index of the glyph that corresponds to the provided coordinate, 78 // with the top left corner as the origin, and +y direction as down 79 virtual PositionWithAffinity getGlyphPositionAtCoordinate(SkScalar dx, SkScalar dy) = 0; 80 81 // Finds the first and last glyphs that define a word containing 82 // the glyph at index offset 83 virtual SkRange<size_t> getWordBoundary(unsigned offset) = 0; 84 85 virtual void getLineMetrics(std::vector<LineMetrics>&) = 0; 86 87 virtual size_t lineNumber() = 0; 88 89 virtual TextRange getEllipsisTextRange() = 0; 90 91 virtual void markDirty() = 0; 92 93 // This function will return the number of unresolved glyphs or 94 // -1 if not applicable (has not been shaped yet - valid case) 95 virtual int32_t unresolvedGlyphs() = 0; 96 virtual std::unordered_set<SkUnichar> unresolvedCodepoints() = 0; 97 98 // Experimental API that allows fast way to update some of "immutable" paragraph attributes 99 // but not the text itself 100 virtual void updateTextAlign(TextAlign textAlign) = 0; 101 virtual void updateFontSize(size_t from, size_t to, SkScalar fontSize) = 0; 102 virtual void updateForegroundPaint(size_t from, size_t to, SkPaint paint) = 0; 103 virtual void updateBackgroundPaint(size_t from, size_t to, SkPaint paint) = 0; 104 virtual std::vector<ParagraphPainter::PaintID> updateColor(size_t from, size_t to, SkColor color) = 0; 105 106 enum VisitorFlags { 107 kWhiteSpace_VisitorFlag = 1 << 0, 108 }; 109 struct VisitorInfo { 110 const SkFont& font; 111 SkPoint origin; 112 SkScalar advanceX; 113 int count; 114 const uint16_t* glyphs; // count values 115 const SkPoint* positions; // count values 116 const uint32_t* utf8Starts; // count+1 values 117 unsigned flags; 118 }; 119 120 // lineNumber begins at 0. If info is null, this signals the end of that line. 121 using Visitor = std::function<void(int lineNumber, const VisitorInfo*)>; 122 virtual void visit(const Visitor&) = 0; 123 124 // Editing API 125 virtual int getLineNumberAt(TextIndex codeUnitIndex) const = 0; 126 127 /* Returns line metrics info for the line 128 * 129 * @param lineNumber a line number 130 * @param lineMetrics an address to return the info (in case of null just skipped) 131 * @return true if the line is found; false if not 132 */ 133 virtual bool getLineMetricsAt(int lineNumber, LineMetrics* lineMetrics) const = 0; 134 135 /* Returns the visible text on the line (excluding a possible ellipsis) 136 * 137 * @param lineNumber a line number 138 * @param includeSpaces indicates if the whitespaces should be included 139 * @return the range of the text that is shown in the line 140 */ 141 virtual TextRange getActualTextRange(int lineNumber, bool includeSpaces) const = 0; 142 143 struct GlyphClusterInfo { 144 SkRect fBounds; 145 TextRange fClusterTextRange; 146 TextDirection fGlyphClusterPosition; 147 }; 148 149 /** Finds a glyph cluster for text index 150 * 151 * @param codeUnitIndex a text index 152 * @param glyphInfo a glyph cluster info filled if not null 153 * @return true if glyph cluster was found; false if not 154 */ 155 virtual bool getGlyphClusterAt(TextIndex codeUnitIndex, GlyphClusterInfo* glyphInfo) = 0; 156 157 /** Finds the closest glyph cluster for a visual text position 158 * 159 * @param dx x coordinate 160 * @param dy y coordinate 161 * @param glyphInfo a glyph cluster info filled if not null 162 * @return 163 */ 164 virtual bool getClosestGlyphClusterAt(SkScalar dx, 165 SkScalar dy, 166 GlyphClusterInfo* glyphInfo) = 0; 167 168#ifndef USE_SKIA_TXT 169 struct FontInfo { 170 FontInfo(const SkFont font, const TextRange textRange) 171 : fFont(font), fTextRange(textRange) { } 172 virtual ~FontInfo() = default; 173 FontInfo(const FontInfo& ) = default; 174 SkFont fFont; 175 TextRange fTextRange; 176 }; 177#else 178 struct FontInfo { 179 FontInfo(const RSFont font, const TextRange textRange) 180 : fFont(font), fTextRange(textRange) { } 181 virtual ~FontInfo() = default; 182 FontInfo(const FontInfo& ) = default; 183 RSFont fFont; 184 TextRange fTextRange; 185 }; 186#endif 187 188 struct TextCutRecord { 189 size_t charbegin; 190 size_t charOver; 191 SkScalar phraseWidth; 192 }; 193 194 /** Returns the font that is used to shape the text at the position 195 * 196 * @param codeUnitIndex text index 197 * @return font info or an empty font info if the text is not found 198 */ 199#ifndef USE_SKIA_TXT 200 virtual SkFont getFontAt(TextIndex codeUnitIndex) const = 0; 201#else 202 virtual RSFont getFontAt(TextIndex codeUnitIndex) const = 0; 203#endif 204 205 /** Returns the information about all the fonts used to shape the paragraph text 206 * 207 * @return a list of fonts and text ranges 208 */ 209 virtual std::vector<FontInfo> getFonts() const = 0; 210 211 virtual void setIndents(const std::vector<SkScalar>& indents) = 0; 212 213 virtual SkScalar detectIndents(size_t index) = 0; 214 215 virtual SkScalar getTextSplitRatio() const = 0; 216 217#ifndef USE_SKIA_TXT 218 virtual SkFontMetrics measureText() = 0; 219#else 220 virtual RSFontMetrics measureText() = 0; 221#endif 222 223#ifndef USE_SKIA_TXT 224 virtual bool GetLineFontMetrics(const size_t lineNumber, size_t& charNumber, 225 std::vector<SkFontMetrics>& fontMetrics) = 0; 226#else 227 virtual bool GetLineFontMetrics(const size_t lineNumber, size_t& charNumber, 228 std::vector<RSFontMetrics>& fontMetrics) = 0; 229#endif 230 virtual std::vector<std::unique_ptr<TextLineBase>> GetTextLines() = 0; 231 virtual std::unique_ptr<Paragraph> CloneSelf() = 0; 232 233#ifdef OHOS_SUPPORT 234 virtual size_t getUnicodeIndex(TextIndex index) const = 0; 235 virtual const std::vector<SkUnichar>& unicodeText() const = 0; 236 virtual std::unique_ptr<Paragraph> createCroppedCopy( 237 size_t startIndex, size_t count = std::numeric_limits<size_t>::max()) = 0; 238 virtual void initUnicodeText() = 0; 239 virtual size_t GetMaxLines() const = 0; 240#endif 241 242protected: 243 sk_sp<FontCollection> fFontCollection; 244 ParagraphStyle fParagraphStyle; 245 246 // Things for Flutter 247 SkScalar fAlphabeticBaseline; 248 SkScalar fIdeographicBaseline; 249 SkScalar fGlyphsBoundsTop; 250 SkScalar fGlyphsBoundsBottom; 251 SkScalar fGlyphsBoundsLeft; 252 SkScalar fGlyphsBoundsRight; 253 SkScalar fHeight; 254 SkScalar fWidth; 255 SkScalar fMaxIntrinsicWidth; 256 SkScalar fMinIntrinsicWidth; 257 SkScalar fLongestLine; 258 SkScalar fLongestLineWithIndent; 259 bool fExceededMaxLines; 260}; 261} // namespace textlayout 262} // namespace skia 263 264#endif // Paragraph_DEFINED 265