• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021 Google LLC.
2 #ifndef Interface_DEFINED
3 #define Interface_DEFINED
4 #include <string>
5 #include "experimental/sktext/include/Types.h"
6 #include "experimental/sktext/src/Line.h"
7 #include "include/core/SkCanvas.h"
8 #include "include/core/SkFontMgr.h"
9 #include "include/core/SkFontStyle.h"
10 #include "include/core/SkPaint.h"
11 #include "include/core/SkSize.h"
12 #include "include/core/SkString.h"
13 #include "include/core/SkTextBlob.h"
14 #include "modules/skshaper/include/SkShaper.h"
15 #include "modules/skunicode/include/SkUnicode.h"
16 
17 using namespace skia::text;
18 namespace skia {
19 namespace API {
20 /**
21  * This class contains all the SKUnicode/ICU information.
22  */
23 class UnicodeText {
24 public:
25     /** Makes calls to SkShaper and collects all the shaped data.
26         @param blocks         a range of FontBlock elements that keep information about
27                               fonts required to shape the text.
28                               It's utf16 range but internally it will have to be converted
29                               to utf8 (since all shaping operations use utf8 encoding)
30         @param textDirection  a starting text direction value
31         @return               an object that contains the result of shaping operations
32     */
33     std::unique_ptr<ShapedText> shape(SkSpan<FontBlock> blocks, TextDirection textDirection);
34 
35     UnicodeText(std::unique_ptr<SkUnicode> unicode, SkSpan<uint16_t> utf16);
36     UnicodeText(std::unique_ptr<SkUnicode> unicode, const SkString& utf8);
37 
38     bool hasProperty(TextIndex index, CodeUnitFlags flag) const
39     bool isHardLineBreak(TextIndex index) const ;
40     bool isSoftLineBreak(TextIndex index) const;
41     bool isWhitespaces(TextRange range) const;
42 
43     SkUnicode* getUnicode() const;
44     SkSpan<const char16_t> getText16() const;
45 };
46 
47 class WrappedText;
48 /**
49  * This class provides all the information from SkShaper/harfbuzz in a raw format.
50  * It does require a single existing font for each codepoint.
51  */
52  // Question: do we provide a visitor for ShapedText?
53 class ShapedText {
54 public:
55     /** Break text by lines with a given width (and possible new lines).
56         @param unicodeText    a reference to UnicodeText that is used to query Unicode information
57         @param width          a line width at which the text gets wrapped
58         @param height         a text height, currently not supported
59         @return               an object that contains the result of shaping operations (wrapping and formatting).
60     */
61     std::unique_ptr<WrappedText> wrap(UnicodeText* unicodeText, float width, float height);
62     SkSpan<const LogicalRun> getLogicalRuns() const;
63 };
64 
65 /**
66  * This is a helper visitor class that allows a user to process the wrapped text
67  * structures: lines and runs (to draw them, for instance)
68  */
69 class Visitor {
70 public:
71     virtual ~Visitor() = default;
onBeginLine(size_t index,TextRange lineText,bool hardBreak,SkRect bounds)72     virtual void onBeginLine(size_t index, TextRange lineText, bool hardBreak, SkRect bounds) { }
onEndLine(size_t index,TextRange lineText,GlyphRange trailingSpaces,size_t glyphCount)73     virtual void onEndLine(size_t index, TextRange lineText, GlyphRange trailingSpaces, size_t glyphCount) { }
onGlyphRun(const SkFont & font,TextRange textRange,SkRect bounds,int trailingSpaces,int glyphCount,const uint16_t glyphs[],const SkPoint positions[],const TextIndex clusters[])74     virtual void onGlyphRun(const SkFont& font,
75                             TextRange textRange,        // Currently we make sure that the run edges are the grapheme cluster edges
76                             SkRect bounds,              // bounds contains the physical boundaries of the run
77                             int trailingSpaces,         // Depending of TextDirection it goes right to the end (LTR) or left to the start (RTL)
78                             int glyphCount,             // Just the number of glyphs
79                             const uint16_t glyphs[],
80                             const SkPoint positions[],        // Positions relative to the line
81                             const TextIndex clusters[])       // Text indices inside the entire text
82     { }
onPlaceholder(TextRange,const SkRect & bounds)83     virtual void onPlaceholder(TextRange, const SkRect& bounds) { }
84 };
85 
86 class DrawableText;
87 class SelectableText;
88 /**
89  * This class provides all the information about wrapped/formatted text.
90  */
91 class WrappedText {
92 public:
93     /** Builds a list of SkTextBlobs to draw on a canvas.
94         @param positionType   specifies a text adjustment granularity (grapheme cluster, grapheme, glypheme, glyph)
95         @param blocks         a range of text indices that cause an additional run breaking to be used for styling
96         @return               an object that contains a list of SkTextBlobs to draw on a canvas
97     */
98     std::unique_ptr<DrawableText> prepareToDraw(UnicodeText* unicodeText, PositionType positionType, SkSpan<TextIndex> blocks) const;
99     /** Aggregates all the data to navigate the text (move up, down, left, right),
100         select some text near the cursor point, adjust all text position to word,
101         grapheme cluster and such.
102         @return               an object that contains all the data for navigation
103     */
104     std::unique_ptr<SelectableText> prepareToEdit(UnicodeText* unicodeText) const;
105     /** Formats a text line by line.
106         @param textAlign     specifies a text placement on the line:
107                              left, right, center and justified (last one currently not supported)
108         @param textDirection specifies a text direction that also used in formatting
109     */
110     void format(TextAlign textAlign, TextDirection textDirection);
111     /** Breaks the text runs into smaller runs by given list of chunks to be used for styling.
112         @param unicodeText    a reference to UnicodeText object
113         @param chunks         a range of text indices that cause an additional run breaking to be used for styling
114     */
115     void decorate(UnicodeText* unicodeText, SkSpan<TextIndex> chunks);
116 
117     /** Walks though the data structures and makes certain callbacks on visitor so the visitor can collect all the information.
118         @param visitor      a reference to Visitor object
119     */
120     void visit(Visitor* visitor) const;
121     /** Walks though the data structures and makes certain callbacks on visitor so the visitor can collect all the information.
122         @param unicodeText  a reference to UnicodeText object
123         @param visitor      a reference to Visitor object
124         @param positionType specifies a text adjustment granularity (grapheme cluster, grapheme, glypheme, glyph)
125                             to map text blocks to glyph ranges.
126         @param blocks       a range of text indices that cause an additional run breaking to be used for styling
127     */
128     void visit(UnicodeText* unicodeText, Visitor* visitor, PositionType positionType, SkSpan<TextIndex> blocks) const;
129 };
130 
131 /** This class contains all the data that allows easily paint the text on canvas.
132     Strictly speaking, it is not an important part of SkText API but
133     it presents a good example of SkText usages and simplifies testing.
134 */
135 class DrawableText : public Visitor {
136 public:
137     std::vector<sk_sp<SkTextBlob>>& getTextBlobs();
138 };
139 
140 struct Position {
141     Position(PositionType positionType, size_t lineIndex, GlyphRange glyphRange, TextRange textRange, SkRect rect);
142     Position(PositionType positionType);
143     PositionType fPositionType;
144     size_t fLineIndex;
145     GlyphRange fGlyphRange;
146     TextRange fTextRange;
147     SkRect fBoundaries;
148 };
149 struct BoxLine {
150     BoxLine(size_t index, TextRange text, bool hardBreak, SkRect bounds);
151     SkTArray<SkRect, true> fBoxGlyphs;
152     SkTArray<TextIndex, true> fTextByGlyph; // by glyph cluster
153     GlyphIndex fTextEnd;
154     GlyphIndex fTrailingSpacesEnd;
155     TextRange fTextRange;
156     size_t fIndex;
157     bool fIsHardBreak;
158     SkRect fBounds;
159 };
160 
161 /** This class contains all the data that allows all navigation operations on the text:
162     move up/down/left/right, select some units of text and such.
163 */
164 class SelectableText : public Visitor {
165 public:
166     SelectableText() = default;
167 
168     /** Find the drawable unit (specified by positionType) closest to the screen point
169         @param positionType   specifies a text adjustment granularity (grapheme cluster, grapheme, glypheme, glyph)
170         @param point          a physical coordinates on a screen to find the closest glyph
171         @return               a position object that contains all required information
172     */
173     Position adjustedPosition(PositionType positionType, SkPoint point) const;
174 
175     Position previousPosition(Position current) const;
176     Position nextPosition(Position current) const;
177     Position firstPosition(PositionType positionType) const;
178     Position lastPosition(PositionType positionType) const;
179     Position firstInLinePosition(PositionType positionType, LineIndex lineIndex) const;
180     Position lastInLinePosition(PositionType positionType, LineIndex lineIndex) const;
181 
182     bool isFirstOnTheLine(Position element) const;
183     bool isLastOnTheLine(Position element) const;
184 
185     size_t countLines() const;
186     BoxLine getLine(size_t lineIndex) const;
187 };
188 }  // namespace text
189 }  // namespace skia
190 
191 #endif  // Processor_DEFINED
192