1 // Copyright 2019 Google LLC. 2 #ifndef Paragraph_DEFINED 3 #define Paragraph_DEFINED 4 5 #include "include/core/SkPath.h" 6 #include "modules/skparagraph/include/FontCollection.h" 7 #include "modules/skparagraph/include/Metrics.h" 8 #include "modules/skparagraph/include/ParagraphStyle.h" 9 #include "modules/skparagraph/include/TextStyle.h" 10 #include <unordered_set> 11 12 class SkCanvas; 13 14 namespace skia { 15 namespace textlayout { 16 17 class ParagraphPainter; 18 19 class Paragraph { 20 21 public: 22 Paragraph(ParagraphStyle style, sk_sp<FontCollection> fonts); 23 24 virtual ~Paragraph() = default; 25 getMaxWidth()26 SkScalar getMaxWidth() { return fWidth; } 27 getHeight()28 SkScalar getHeight() { return fHeight; } 29 getMinIntrinsicWidth()30 SkScalar getMinIntrinsicWidth() { return fMinIntrinsicWidth; } 31 getMaxIntrinsicWidth()32 SkScalar getMaxIntrinsicWidth() { return fMaxIntrinsicWidth; } 33 getAlphabeticBaseline()34 SkScalar getAlphabeticBaseline() { return fAlphabeticBaseline; } 35 getIdeographicBaseline()36 SkScalar getIdeographicBaseline() { return fIdeographicBaseline; } 37 getLongestLine()38 SkScalar getLongestLine() { return fLongestLine; } 39 didExceedMaxLines()40 bool didExceedMaxLines() { return fExceededMaxLines; } 41 42 virtual void layout(SkScalar width) = 0; 43 44 virtual void paint(SkCanvas* canvas, SkScalar x, SkScalar y) = 0; 45 46 virtual void paint(ParagraphPainter* painter, SkScalar x, SkScalar y) = 0; 47 48 // Returns a vector of bounding boxes that enclose all text between 49 // start and end glyph indexes, including start and excluding end 50 virtual std::vector<TextBox> getRectsForRange(unsigned start, 51 unsigned end, 52 RectHeightStyle rectHeightStyle, 53 RectWidthStyle rectWidthStyle) = 0; 54 55 virtual std::vector<TextBox> getRectsForPlaceholders() = 0; 56 57 // Returns the index of the glyph that corresponds to the provided coordinate, 58 // with the top left corner as the origin, and +y direction as down 59 virtual PositionWithAffinity getGlyphPositionAtCoordinate(SkScalar dx, SkScalar dy) = 0; 60 61 // Finds the first and last glyphs that define a word containing 62 // the glyph at index offset 63 virtual SkRange<size_t> getWordBoundary(unsigned offset) = 0; 64 65 virtual void getLineMetrics(std::vector<LineMetrics>&) = 0; 66 67 virtual size_t lineNumber() = 0; 68 69 virtual void markDirty() = 0; 70 71 // This function will return the number of unresolved glyphs or 72 // -1 if not applicable (has not been shaped yet - valid case) 73 virtual int32_t unresolvedGlyphs() = 0; 74 virtual std::unordered_set<SkUnichar> unresolvedCodepoints() = 0; 75 76 // Experimental API that allows fast way to update some of "immutable" paragraph attributes 77 // but not the text itself 78 virtual void updateTextAlign(TextAlign textAlign) = 0; 79 virtual void updateFontSize(size_t from, size_t to, SkScalar fontSize) = 0; 80 virtual void updateForegroundPaint(size_t from, size_t to, SkPaint paint) = 0; 81 virtual void updateBackgroundPaint(size_t from, size_t to, SkPaint paint) = 0; 82 83 enum VisitorFlags { 84 kWhiteSpace_VisitorFlag = 1 << 0, 85 }; 86 struct VisitorInfo { 87 const SkFont& font; 88 SkPoint origin; 89 SkScalar advanceX; 90 int count; 91 const uint16_t* glyphs; // count values 92 const SkPoint* positions; // count values 93 const uint32_t* utf8Starts; // count+1 values 94 unsigned flags; 95 }; 96 97 // lineNumber begins at 0. If info is null, this signals the end of that line. 98 using Visitor = std::function<void(int lineNumber, const VisitorInfo*)>; 99 virtual void visit(const Visitor&) = 0; 100 101 struct ExtendedVisitorInfo { 102 const SkFont& font; 103 SkPoint origin; 104 SkSize advance; 105 int count; 106 const uint16_t* glyphs; // count values 107 SkPoint* positions; // count values 108 const SkRect* bounds; // count values 109 const uint32_t* utf8Starts; // count+1 values 110 unsigned flags; 111 }; 112 using ExtendedVisitor = std::function<void(int lineNumber, const ExtendedVisitorInfo*)>; 113 virtual void extendedVisit(const ExtendedVisitor&) = 0; 114 115 /* Returns path for a given line 116 * 117 * @param lineNumber a line number 118 * @param dest a resulting path 119 * @return a number glyphs that could not be converted to path 120 */ 121 virtual int getPath(int lineNumber, SkPath* dest) = 0; 122 123 /* Returns path for a text blob 124 * 125 * @param textBlob a text blob 126 * @return a path 127 */ 128 static SkPath GetPath(SkTextBlob* textBlob); 129 130 /* Checks if a given text blob contains 131 * glyph with emoji 132 * 133 * @param textBlob a text blob 134 * @return true if there is such a glyph 135 */ 136 virtual bool containsEmoji(SkTextBlob* textBlob) = 0; 137 138 /* Checks if a given text blob contains colored font or bitmap 139 * 140 * @param textBlob a text blob 141 * @return true if there is such a glyph 142 */ 143 virtual bool containsColorFontOrBitmap(SkTextBlob* textBlob) = 0; 144 145 // Editing API 146 147 /* Finds the line number of the line that contains the given UTF-8 index. 148 * 149 * @param index a UTF-8 TextIndex into the paragraph 150 * @return the line number the glyph that corresponds to the 151 * given codeUnitIndex is in, or -1 if the codeUnitIndex 152 * is out of bounds, or when the glyph is truncated or 153 * ellipsized away. 154 */ 155 virtual int getLineNumberAt(TextIndex codeUnitIndex) const = 0; 156 157 /* Finds the line number of the line that contains the given UTF-16 index. 158 * 159 * @param index a UTF-16 offset into the paragraph 160 * @return the line number the glyph that corresponds to the 161 * given codeUnitIndex is in, or -1 if the codeUnitIndex 162 * is out of bounds, or when the glyph is truncated or 163 * ellipsized away. 164 */ 165 virtual int getLineNumberAtUTF16Offset(size_t codeUnitIndex) = 0; 166 167 /* Returns line metrics info for the line 168 * 169 * @param lineNumber a line number 170 * @param lineMetrics an address to return the info (in case of null just skipped) 171 * @return true if the line is found; false if not 172 */ 173 virtual bool getLineMetricsAt(int lineNumber, LineMetrics* lineMetrics) const = 0; 174 175 /* Returns the visible text on the line (excluding a possible ellipsis) 176 * 177 * @param lineNumber a line number 178 * @param includeSpaces indicates if the whitespaces should be included 179 * @return the range of the text that is shown in the line 180 */ 181 virtual TextRange getActualTextRange(int lineNumber, bool includeSpaces) const = 0; 182 183 struct GlyphClusterInfo { 184 SkRect fBounds; 185 TextRange fClusterTextRange; 186 TextDirection fGlyphClusterPosition; 187 }; 188 189 /** Finds a glyph cluster for text index 190 * 191 * @param codeUnitIndex a text index 192 * @param glyphInfo a glyph cluster info filled if not null 193 * @return true if glyph cluster was found; false if not 194 */ 195 virtual bool getGlyphClusterAt(TextIndex codeUnitIndex, GlyphClusterInfo* glyphInfo) = 0; 196 197 /** Finds the closest glyph cluster for a visual text position 198 * 199 * @param dx x coordinate 200 * @param dy y coordinate 201 * @param glyphInfo a glyph cluster info filled if not null 202 * @return true if glyph cluster was found; false if not 203 * (which usually means the paragraph is empty) 204 */ 205 virtual bool getClosestGlyphClusterAt(SkScalar dx, 206 SkScalar dy, 207 GlyphClusterInfo* glyphInfo) = 0; 208 209 // The glyph and grapheme cluster information assoicated with a unicode 210 // codepoint in the paragraph. 211 struct GlyphInfo { 212 SkRect fGraphemeLayoutBounds; 213 TextRange fGraphemeClusterTextRange; 214 TextDirection fDirection; 215 bool fIsEllipsis; 216 }; 217 218 /** Retrives the information associated with the glyph located at the given 219 * codeUnitIndex. 220 * 221 * @param codeUnitIndex a UTF-16 offset into the paragraph 222 * @param glyphInfo an optional GlyphInfo struct to hold the 223 * information associated with the glyph found at the 224 * given index 225 * @return false only if the offset is out of bounds 226 */ 227 virtual bool getGlyphInfoAtUTF16Offset(size_t codeUnitIndex, GlyphInfo* glyphInfo) = 0; 228 229 /** Finds the information associated with the closest glyph to the given 230 * paragraph coordinates. 231 * 232 * @param dx x coordinate 233 * @param dy y coordinate 234 * @param glyphInfo an optional GlyphInfo struct to hold the 235 * information associated with the glyph found. The 236 * text indices and text ranges are described using 237 * UTF-16 offsets 238 * @return true if a graphme cluster was found; false if not 239 * (which usually means the paragraph is empty) 240 */ 241 virtual bool getClosestUTF16GlyphInfoAt(SkScalar dx, SkScalar dy, GlyphInfo* glyphInfo) = 0; 242 243 struct FontInfo { FontInfoFontInfo244 FontInfo(const SkFont& font, const TextRange textRange) 245 : fFont(font), fTextRange(textRange) {} 246 virtual ~FontInfo() = default; 247 FontInfo(const FontInfo& ) = default; 248 SkFont fFont; 249 TextRange fTextRange; 250 }; 251 252 /** Returns the font that is used to shape the text at the position 253 * 254 * @param codeUnitIndex text index 255 * @return font info or an empty font info if the text is not found 256 */ 257 virtual SkFont getFontAt(TextIndex codeUnitIndex) const = 0; 258 259 /** Returns the font used to shape the text at the given UTF-16 offset. 260 * 261 * @param codeUnitIndex a UTF-16 offset in the paragraph 262 * @return font info or an empty font info if the text is not found 263 */ 264 virtual SkFont getFontAtUTF16Offset(size_t codeUnitIndex) = 0; 265 266 /** Returns the information about all the fonts used to shape the paragraph text 267 * 268 * @return a list of fonts and text ranges 269 */ 270 virtual std::vector<FontInfo> getFonts() const = 0; 271 272 protected: 273 sk_sp<FontCollection> fFontCollection; 274 ParagraphStyle fParagraphStyle; 275 276 // Things for Flutter 277 SkScalar fAlphabeticBaseline; 278 SkScalar fIdeographicBaseline; 279 SkScalar fHeight; 280 SkScalar fWidth; 281 SkScalar fMaxIntrinsicWidth; 282 SkScalar fMinIntrinsicWidth; 283 SkScalar fLongestLine; 284 bool fExceededMaxLines; 285 }; 286 } // namespace textlayout 287 } // namespace skia 288 289 #endif // Paragraph_DEFINED 290