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
24class SkCanvas;
25
26namespace 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.
31class 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