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