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