1 | |
2 | /* |
3 | * Copyright 2017 Google Inc. |
4 | * |
5 | * Licensed under the Apache License, Version 2.0 (the "License"); |
6 | * you may not use this file except in compliance with the License. |
7 | * You may obtain a copy of the License at |
8 | * |
9 | * http://www.apache.org/licenses/LICENSE-2.0 |
10 | * |
11 | * Unless required by applicable law or agreed to in writing, software |
12 | * distributed under the License is distributed on an "AS IS" BASIS, |
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
14 | * See the License for the specific language governing permissions and |
15 | * limitations under the License. |
16 | */ |
17 | |
18 | #ifndef LIB_TXT_SRC_PARAGRAPH_H_ |
19 | #define LIB_TXT_SRC_PARAGRAPH_H_ |
20 | |
21 | #include "line_metrics.h" |
22 | #include "paragraph_style.h" |
23 | |
24 | class SkCanvas; |
25 | |
26 | namespace txt { |
27 | |
28 | // Interface for text layout engines. The original implementation was based on |
29 | // the Minikin text layout library used by Android. Another implementation is |
30 | // available based on Skia's SkShaper/SkParagraph text layout module. |
31 | class Paragraph { |
32 | public: |
33 | enum Affinity { UPSTREAM, DOWNSTREAM }; |
34 | |
35 | // Options for various types of bounding boxes provided by |
36 | // GetRectsForRange(...). |
37 | enum class RectHeightStyle { |
38 | // Provide tight bounding boxes that fit heights per run. |
39 | kTight, |
40 | |
41 | // The height of the boxes will be the maximum height of all runs in the |
42 | // line. All rects in the same line will be the same height. |
43 | kMax, |
44 | |
45 | // Extends the top and/or bottom edge of the bounds to fully cover any line |
46 | // spacing. The top edge of each line should be the same as the bottom edge |
47 | // of the line above. There should be no gaps in vertical coverage given any |
48 | // ParagraphStyle line_height. |
49 | // |
50 | // The top and bottom of each rect will cover half of the |
51 | // space above and half of the space below the line. |
52 | kIncludeLineSpacingMiddle, |
53 | // The line spacing will be added to the top of the rect. |
54 | kIncludeLineSpacingTop, |
55 | // The line spacing will be added to the bottom of the rect. |
56 | kIncludeLineSpacingBottom, |
57 | |
58 | // Calculate boxes based on the strut's metrics. |
59 | kStrut |
60 | }; |
61 | |
62 | enum class RectWidthStyle { |
63 | // Provide tight bounding boxes that fit widths to the runs of each line |
64 | // independently. |
65 | kTight, |
66 | |
67 | // Extends the width of the last rect of each line to match the position of |
68 | // the widest rect over all the lines. |
69 | kMax |
70 | }; |
71 | |
72 | struct PositionWithAffinity { |
73 | const size_t position; |
74 | const Affinity affinity; |
75 | |
76 | PositionWithAffinity(size_t p, Affinity a) : position(p), affinity(a) {} |
77 | }; |
78 | |
79 | struct TextBox { |
80 | SkRect rect; |
81 | TextDirection direction; |
82 | |
83 | TextBox(SkRect r, TextDirection d) : rect(r), direction(d) {} |
84 | }; |
85 | |
86 | template <typename T> |
87 | struct Range { |
88 | Range() : start(), end() {} |
89 | Range(T s, T e) : start(s), end(e) {} |
90 | |
91 | T start, end; |
92 | |
93 | bool operator==(const Range<T>& other) const { |
94 | return start == other.start && end == other.end; |
95 | } |
96 | |
97 | T width() const { return end - start; } |
98 | |
99 | void Shift(T delta) { |
100 | start += delta; |
101 | end += delta; |
102 | } |
103 | }; |
104 | |
105 | virtual ~Paragraph() = default; |
106 | |
107 | // Returns the width provided in the Layout() method. This is the maximum |
108 | // width any line in the laid out paragraph can occupy. We expect that |
109 | // GetMaxWidth() >= GetLayoutWidth(). |
110 | virtual double GetMaxWidth() = 0; |
111 | |
112 | // Returns the height of the laid out paragraph. NOTE this is not a tight |
113 | // bounding height of the glyphs, as some glyphs do not reach as low as they |
114 | // can. |
115 | virtual double GetHeight() = 0; |
116 | |
117 | // Returns the width of the longest line as found in Layout(), which is |
118 | // defined as the horizontal distance from the left edge of the leftmost glyph |
119 | // to the right edge of the rightmost glyph. We expect that |
120 | // GetLongestLine() <= GetMaxWidth(). |
121 | virtual double GetLongestLine() = 0; |
122 | |
123 | // Returns the actual max width of the longest line after Layout(). |
124 | virtual double GetMinIntrinsicWidth() = 0; |
125 | |
126 | // Returns the total width covered by the paragraph without linebreaking. |
127 | virtual double GetMaxIntrinsicWidth() = 0; |
128 | |
129 | // Distance from top of paragraph to the Alphabetic baseline of the first |
130 | // line. Used for alphabetic fonts (A-Z, a-z, greek, etc.) |
131 | virtual double GetAlphabeticBaseline() = 0; |
132 | |
133 | // Distance from top of paragraph to the Ideographic baseline of the first |
134 | // line. Used for ideographic fonts (Chinese, Japanese, Korean, etc.) |
135 | virtual double GetIdeographicBaseline() = 0; |
136 | |
137 | // Checks if the layout extends past the maximum lines and had to be |
138 | // truncated. |
139 | virtual bool DidExceedMaxLines() = 0; |
140 | |
141 | // Layout calculates the positioning of all the glyphs. Must call this method |
142 | // before Painting and getting any statistics from this class. |
143 | virtual void Layout(double width) = 0; |
144 | |
145 | // Paints the laid out text onto the supplied SkCanvas at (x, y) offset from |
146 | // the origin. Only valid after Layout() is called. |
147 | virtual void Paint(SkCanvas* canvas, double x, double y) = 0; |
148 | |
149 | // Returns a vector of bounding boxes that enclose all text between start and |
150 | // end glyph indexes, including start and excluding end. |
151 | virtual std::vector<TextBox> GetRectsForRange( |
152 | size_t start, |
153 | size_t end, |
154 | RectHeightStyle rect_height_style, |
155 | RectWidthStyle rect_width_style) = 0; |
156 | |
157 | // Returns a vector of bounding boxes that bound all inline placeholders in |
158 | // the paragraph. |
159 | // |
160 | // There will be one box for each inline placeholder. The boxes will be in the |
161 | // same order as they were added to the paragraph. The bounds will always be |
162 | // tight and should fully enclose the area where the placeholder should be. |
163 | // |
164 | // More granular boxes may be obtained through GetRectsForRange, which will |
165 | // return bounds on both text as well as inline placeholders. |
166 | virtual std::vector<TextBox> GetRectsForPlaceholders() = 0; |
167 | |
168 | // Returns the index of the glyph that corresponds to the provided coordinate, |
169 | // with the top left corner as the origin, and +y direction as down. |
170 | virtual PositionWithAffinity GetGlyphPositionAtCoordinate(double dx, |
171 | double dy) = 0; |
172 | |
173 | // Finds the first and last glyphs that define a word containing the glyph at |
174 | // index offset. |
175 | virtual Range<size_t> GetWordBoundary(size_t offset) = 0; |
176 | |
177 | virtual std::vector<LineMetrics>& GetLineMetrics() = 0; |
178 | }; |
179 | |
180 | } // namespace txt |
181 | |
182 | #endif // LIB_TXT_SRC_PARAGRAPH_H_ |
183 | |