1 /* 2 * Copyright 2013, Stephan Aßmus <superstippi@gmx.de>. 3 * Copyright 2021, Andrew Lindesay <apl@lindesay.co.nz>. 4 * All rights reserved. Distributed under the terms of the MIT License. 5 */ 6 #ifndef PARAGRAPH_LAYOUT_H 7 #define PARAGRAPH_LAYOUT_H 8 9 #include <vector> 10 11 #include <Font.h> 12 #include <Referenceable.h> 13 #include <String.h> 14 15 #include "CharacterStyle.h" 16 #include "List.h" 17 #include "Paragraph.h" 18 19 20 class BView; 21 22 23 class GlyphInfo { 24 public: 25 GlyphInfo() 26 : 27 charCode(0), 28 x(0.0f), 29 width(0.0f), 30 lineIndex(0) 31 { 32 } 33 34 GlyphInfo(uint32 charCode, float x, float width, int32 lineIndex) 35 : 36 charCode(charCode), 37 x(x), 38 width(width), 39 lineIndex(lineIndex) 40 { 41 } 42 43 GlyphInfo(const GlyphInfo& other) 44 : 45 charCode(other.charCode), 46 x(other.x), 47 width(other.width), 48 lineIndex(other.lineIndex) 49 { 50 } 51 52 GlyphInfo& operator=(const GlyphInfo& other) 53 { 54 charCode = other.charCode; 55 x = other.x; 56 width = other.width; 57 lineIndex = other.lineIndex; 58 return *this; 59 } 60 61 bool operator==(const GlyphInfo& other) const 62 { 63 return charCode == other.charCode 64 && x == other.x 65 && width == other.width 66 && lineIndex == other.lineIndex; 67 } 68 69 bool operator!=(const GlyphInfo& other) const 70 { 71 return !(*this == other); 72 } 73 74 public: 75 uint32 charCode; 76 77 float x; 78 float width; 79 80 int32 lineIndex; 81 }; 82 83 84 class LineInfo { 85 public: 86 LineInfo() 87 : 88 textOffset(0), 89 y(0.0f), 90 height(0.0f), 91 maxAscent(0.0f), 92 maxDescent(0.0f), 93 extraGlyphSpacing(0.0f), 94 extraWhiteSpacing(0.0f), 95 layoutedSpans() 96 { 97 } 98 99 LineInfo(int32 textOffset, float y, float height, float maxAscent, 100 float maxDescent) 101 : 102 textOffset(textOffset), 103 y(y), 104 height(height), 105 maxAscent(maxAscent), 106 maxDescent(maxDescent), 107 extraGlyphSpacing(0.0f), 108 extraWhiteSpacing(0.0f), 109 layoutedSpans() 110 { 111 } 112 113 LineInfo(const LineInfo& other) 114 : 115 textOffset(other.textOffset), 116 y(other.y), 117 height(other.height), 118 maxAscent(other.maxAscent), 119 maxDescent(other.maxDescent), 120 extraGlyphSpacing(other.extraGlyphSpacing), 121 extraWhiteSpacing(other.extraWhiteSpacing), 122 layoutedSpans(other.layoutedSpans) 123 { 124 } 125 126 LineInfo& operator=(const LineInfo& other) 127 { 128 textOffset = other.textOffset; 129 y = other.y; 130 height = other.height; 131 maxAscent = other.maxAscent; 132 maxDescent = other.maxDescent; 133 extraGlyphSpacing = other.extraGlyphSpacing; 134 extraWhiteSpacing = other.extraWhiteSpacing; 135 layoutedSpans = other.layoutedSpans; 136 return *this; 137 } 138 139 bool operator==(const LineInfo& other) const 140 { 141 return textOffset == other.textOffset 142 && y == other.y 143 && height == other.height 144 && maxAscent == other.maxAscent 145 && maxDescent == other.maxDescent 146 && extraGlyphSpacing == other.extraGlyphSpacing 147 && extraWhiteSpacing == other.extraWhiteSpacing 148 && layoutedSpans == other.layoutedSpans; 149 } 150 151 bool operator!=(const LineInfo& other) const 152 { 153 return !(*this == other); 154 } 155 156 public: 157 int32 textOffset; 158 159 float y; 160 float height; 161 162 float maxAscent; 163 float maxDescent; 164 165 float extraGlyphSpacing; 166 float extraWhiteSpacing; 167 168 std::vector<TextSpan> 169 layoutedSpans; 170 }; 171 172 173 class ParagraphLayout : public BReferenceable { 174 public: 175 ParagraphLayout(); 176 ParagraphLayout(const Paragraph& paragraph); 177 ParagraphLayout(const ParagraphLayout& other); 178 virtual ~ParagraphLayout(); 179 180 void SetParagraph(const Paragraph& paragraph); 181 const ParagraphStyle& Style() const 182 { return fParagraphStyle; } 183 184 void SetWidth(float width); 185 float Width() const 186 { return fWidth; } 187 188 float Height(); 189 void Draw(BView* view, const BPoint& offset); 190 191 int32 CountGlyphs() const; 192 int32 CountLines(); 193 194 int32 LineIndexForOffset(int32 textOffset); 195 int32 FirstOffsetOnLine(int32 lineIndex); 196 int32 LastOffsetOnLine(int32 lineIndex); 197 198 void GetLineBounds(int32 lineIndex, 199 float& x1, float& y1, 200 float& x2, float& y2); 201 202 void GetTextBounds(int32 textOffset, 203 float& x1, float& y1, 204 float& x2, float& y2); 205 206 int32 TextOffsetAt(float x, float y, 207 bool& rightOfCenter); 208 209 private: 210 void _Init(); 211 212 void _ValidateLayout(); 213 void _Layout(); 214 void _ApplyAlignment(); 215 216 bool _AppendGlyphInfos(const TextSpan& span); 217 bool _AppendGlyphInfo(uint32 charCode, 218 float advanceX, 219 const CharacterStyle& style); 220 221 bool _FinalizeLine(int lineStart, int lineEnd, 222 int lineIndex, float y, float& lineHeight); 223 224 void _IncludeStyleInLine(LineInfo& line, 225 const CharacterStyle& style); 226 227 void _DrawLine(BView* view, const BPoint& offset, 228 const LineInfo& line) const; 229 void _DrawSpan(BView* view, BPoint offset, 230 const TextSpan& span, 231 int32 textOffset) const; 232 233 void _GetEmptyLayoutBounds(float& x1, float& y1, 234 float& x2, float& y2) const; 235 236 void _AppendTextSpans(const Paragraph& paragraph); 237 238 private: 239 std::vector<TextSpan> 240 fTextSpans; 241 ParagraphStyle fParagraphStyle; 242 243 float fWidth; 244 bool fLayoutValid; 245 246 std::vector<GlyphInfo> 247 fGlyphInfos; 248 std::vector<LineInfo> 249 fLineInfos; 250 }; 251 252 253 typedef BReference<ParagraphLayout> ParagraphLayoutRef; 254 255 256 #endif // PARAGRAPH_LAYOUT_H 257