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
20class BView;
21
22
23class GlyphInfo {
24public:
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
74public:
75	uint32					charCode;
76
77	float					x;
78	float					width;
79
80	int32					lineIndex;
81};
82
83
84class LineInfo {
85public:
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
156public:
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
173class ParagraphLayout : public BReferenceable {
174public:
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
209private:
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
238private:
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
253typedef BReference<ParagraphLayout> ParagraphLayoutRef;
254
255
256#endif // PARAGRAPH_LAYOUT_H
257