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