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