1 #include "html.h"
2 #include "box.h"
3 #include "html_tag.h"
4 
5 
get_type()6 litehtml::box_type litehtml::block_box::get_type()
7 {
8 	return box_block;
9 }
10 
height()11 int litehtml::block_box::height()
12 {
13 	return m_element->height();
14 }
15 
width()16 int litehtml::block_box::width()
17 {
18 	return m_element->width();
19 }
20 
add_element(const element::ptr & el)21 void litehtml::block_box::add_element(const element::ptr &el)
22 {
23 	m_element = el;
24 	el->m_box = this;
25 }
26 
finish(bool last_box)27 void litehtml::block_box::finish(bool last_box)
28 {
29 	if(!m_element) return;
30 	m_element->apply_relative_shift(m_box_right - m_box_left);
31 }
32 
can_hold(const element::ptr & el,white_space ws)33 bool litehtml::block_box::can_hold(const element::ptr &el, white_space ws)
34 {
35 	if(m_element || el->is_inline_box())
36 	{
37 		return false;
38 	}
39 	return true;
40 }
41 
is_empty()42 bool litehtml::block_box::is_empty()
43 {
44 	if(m_element)
45 	{
46 		return false;
47 	}
48 	return true;
49 }
50 
baseline()51 int litehtml::block_box::baseline()
52 {
53 	if(m_element)
54 	{
55 		return m_element->get_base_line();
56 	}
57 	return 0;
58 }
59 
get_elements(elements_vector & els)60 void litehtml::block_box::get_elements( elements_vector& els )
61 {
62 	els.push_back(m_element);
63 }
64 
top_margin()65 int litehtml::block_box::top_margin()
66 {
67 	if(m_element && m_element->collapse_top_margin())
68 	{
69 		return m_element->m_margins.top;
70 	}
71 	return 0;
72 }
73 
bottom_margin()74 int litehtml::block_box::bottom_margin()
75 {
76 	if(m_element && m_element->collapse_bottom_margin())
77 	{
78 		return m_element->m_margins.bottom;
79 	}
80 	return 0;
81 }
82 
y_shift(int shift)83 void litehtml::block_box::y_shift( int shift )
84 {
85 	m_box_top += shift;
86 	if(m_element)
87 	{
88 		m_element->m_pos.y += shift;
89 	}
90 }
91 
new_width(int left,int right,elements_vector & els)92 void litehtml::block_box::new_width( int left, int right, elements_vector& els )
93 {
94 
95 }
96 
97 //////////////////////////////////////////////////////////////////////////
98 
get_type()99 litehtml::box_type litehtml::line_box::get_type()
100 {
101 	return box_line;
102 }
103 
height()104 int litehtml::line_box::height()
105 {
106 	return m_height;
107 }
108 
width()109 int litehtml::line_box::width()
110 {
111 	return m_width;
112 }
113 
add_element(const element::ptr & el)114 void litehtml::line_box::add_element(const element::ptr &el)
115 {
116 	el->m_skip	= false;
117 	el->m_box	= 0;
118 	bool add	= true;
119 	if( (m_items.empty() && el->is_white_space()) || el->is_break() )
120 	{
121 		el->m_skip = true;
122 	} else if(el->is_white_space())
123 	{
124 		if (have_last_space())
125 		{
126 			add = false;
127 			el->m_skip = true;
128 		}
129 	}
130 
131 	if(add)
132 	{
133 		el->m_box = this;
134 		m_items.push_back(el);
135 
136 		if(!el->m_skip)
137 		{
138 			int el_shift_left	= el->get_inline_shift_left();
139 			int el_shift_right	= el->get_inline_shift_right();
140 
141 			el->m_pos.x	= m_box_left + m_width + el_shift_left + el->content_margins_left();
142 			el->m_pos.y	= m_box_top + el->content_margins_top();
143 			m_width		+= el->width() + el_shift_left + el_shift_right;
144 		}
145 	}
146 }
147 
finish(bool last_box)148 void litehtml::line_box::finish(bool last_box)
149 {
150 	if( is_empty() || (!is_empty() && last_box && is_break_only()) )
151 	{
152 		m_height = 0;
153 		return;
154 	}
155 
156 	for(auto i = m_items.rbegin(); i != m_items.rend(); i++)
157 	{
158 		if((*i)->is_white_space() || (*i)->is_break())
159 		{
160 			if(!(*i)->m_skip)
161 			{
162 				(*i)->m_skip = true;
163 				m_width -= (*i)->width();
164 			}
165 		} else
166 		{
167 			break;
168 		}
169 	}
170 
171 	int base_line	= m_font_metrics.base_line();
172 	int line_height = m_line_height;
173 
174 	int add_x = 0;
175 	switch(m_text_align)
176 	{
177 	case text_align_right:
178 		if(m_width < (m_box_right - m_box_left))
179 		{
180 			add_x = (m_box_right - m_box_left) - m_width;
181 		}
182 		break;
183 	case text_align_center:
184 		if(m_width < (m_box_right - m_box_left))
185 		{
186 			add_x = ((m_box_right - m_box_left) - m_width) / 2;
187 		}
188 		break;
189 	default:
190 		add_x = 0;
191 	}
192 
193 	m_height = 0;
194 	// find line box baseline and line-height
195 	for(const auto& el : m_items)
196 	{
197 		if(el->get_display() == display_inline_text)
198 		{
199 			font_metrics fm;
200 			el->get_font(&fm);
201 			base_line	= std::max(base_line,	fm.base_line());
202 			line_height = std::max(line_height, el->line_height());
203 			m_height = std::max(m_height, fm.height);
204 		}
205 		el->m_pos.x += add_x;
206 	}
207 
208 	if(m_height)
209 	{
210 		base_line += (line_height - m_height) / 2;
211 	}
212 
213 	m_height = line_height;
214 
215 	int y1	= 0;
216 	int y2	= m_height;
217 
218 	for (const auto& el : m_items)
219 	{
220 		if(el->get_display() == display_inline_text)
221 		{
222 			font_metrics fm;
223 			el->get_font(&fm);
224 			el->m_pos.y = m_height - base_line - fm.ascent;
225 		} else
226 		{
227 			switch(el->get_vertical_align())
228 			{
229 			case va_super:
230 			case va_sub:
231 			case va_baseline:
232 				el->m_pos.y = m_height - base_line - el->height() + el->get_base_line() + el->content_margins_top();
233 				break;
234 			case va_top:
235 				el->m_pos.y = y1 + el->content_margins_top();
236 				break;
237 			case va_text_top:
238 				el->m_pos.y = m_height - base_line - m_font_metrics.ascent + el->content_margins_top();
239 				break;
240 			case va_middle:
241 				el->m_pos.y = m_height - base_line - m_font_metrics.x_height / 2 - el->height() / 2 + el->content_margins_top();
242 				break;
243 			case va_bottom:
244 				el->m_pos.y = y2 - el->height() + el->content_margins_top();
245 				break;
246 			case va_text_bottom:
247 				el->m_pos.y = m_height - base_line + m_font_metrics.descent - el->height() + el->content_margins_top();
248 				break;
249 			}
250 			y1 = std::min(y1, el->top());
251 			y2 = std::max(y2, el->bottom());
252 		}
253 	}
254 
255 	css_offsets offsets;
256 
257 	for (const auto& el : m_items)
258 	{
259 		el->m_pos.y -= y1;
260 		el->m_pos.y += m_box_top;
261 		if(el->get_display() != display_inline_text)
262 		{
263 			switch(el->get_vertical_align())
264 			{
265 			case va_top:
266 				el->m_pos.y = m_box_top + el->content_margins_top();
267 				break;
268 			case va_bottom:
269 				el->m_pos.y = m_box_top + (y2 - y1) - el->height() + el->content_margins_top();
270 				break;
271 			case va_baseline:
272 				//TODO: process vertical align "baseline"
273 				break;
274 			case va_middle:
275 				//TODO: process vertical align "middle"
276 				break;
277 			case va_sub:
278 				//TODO: process vertical align "sub"
279 				break;
280 			case va_super:
281 				//TODO: process vertical align "super"
282 				break;
283 			case va_text_bottom:
284 				//TODO: process vertical align "text-bottom"
285 				break;
286 			case va_text_top:
287 				//TODO: process vertical align "text-top"
288 				break;
289 			}
290 		}
291 
292 		el->apply_relative_shift(m_box_right - m_box_left);
293 	}
294 	m_height = y2 - y1;
295 	m_baseline = (base_line - y1) - (m_height - line_height);
296 }
297 
can_hold(const element::ptr & el,white_space ws)298 bool litehtml::line_box::can_hold(const element::ptr &el, white_space ws)
299 {
300 	if(!el->is_inline_box()) return false;
301 
302 	if(el->is_break())
303 	{
304 		return false;
305 	}
306 
307 	if(ws == white_space_nowrap || ws == white_space_pre)
308 	{
309 		return true;
310 	}
311 
312 	if(m_box_left + m_width + el->width() + el->get_inline_shift_left() + el->get_inline_shift_right() > m_box_right)
313 	{
314 		return false;
315 	}
316 
317 	return true;
318 }
319 
have_last_space()320 bool litehtml::line_box::have_last_space()
321 {
322 	bool ret = false;
323 	for (auto i = m_items.rbegin(); i != m_items.rend() && !ret; i++)
324 	{
325 		if((*i)->is_white_space() || (*i)->is_break())
326 		{
327 			ret = true;
328 		} else
329 		{
330 			break;
331 		}
332 	}
333 	return ret;
334 }
335 
is_empty()336 bool litehtml::line_box::is_empty()
337 {
338 	if(m_items.empty()) return true;
339 	for (auto i = m_items.rbegin(); i != m_items.rend(); i++)
340 	{
341 		if(!(*i)->m_skip || (*i)->is_break())
342 		{
343 			return false;
344 		}
345 	}
346 	return true;
347 }
348 
baseline()349 int litehtml::line_box::baseline()
350 {
351 	return m_baseline;
352 }
353 
get_elements(elements_vector & els)354 void litehtml::line_box::get_elements( elements_vector& els )
355 {
356 	els.insert(els.begin(), m_items.begin(), m_items.end());
357 }
358 
top_margin()359 int litehtml::line_box::top_margin()
360 {
361 	return 0;
362 }
363 
bottom_margin()364 int litehtml::line_box::bottom_margin()
365 {
366 	return 0;
367 }
368 
y_shift(int shift)369 void litehtml::line_box::y_shift( int shift )
370 {
371 	m_box_top += shift;
372 	for (auto& el : m_items)
373 	{
374 		el->m_pos.y += shift;
375 	}
376 }
377 
is_break_only()378 bool litehtml::line_box::is_break_only()
379 {
380 	if(m_items.empty()) return true;
381 
382 	if(m_items.front()->is_break())
383 	{
384 		for (auto& el : m_items)
385 		{
386 			if(!el->m_skip)
387 			{
388 				return false;
389 			}
390 		}
391 		return true;
392 	}
393 	return false;
394 }
395 
new_width(int left,int right,elements_vector & els)396 void litehtml::line_box::new_width( int left, int right, elements_vector& els )
397 {
398 	int add = left - m_box_left;
399 	if(add)
400 	{
401 		m_box_left	= left;
402 		m_box_right	= right;
403 		m_width = 0;
404 		auto remove_begin = m_items.end();
405 		for (auto i = m_items.begin() + 1; i != m_items.end(); i++)
406 		{
407 			element::ptr el = (*i);
408 
409 			if(!el->m_skip)
410 			{
411 				if(m_box_left + m_width + el->width() + el->get_inline_shift_right() + el->get_inline_shift_left() > m_box_right)
412 				{
413 					remove_begin = i;
414 					break;
415 				} else
416 				{
417 					el->m_pos.x += add;
418 					m_width += el->width() + el->get_inline_shift_right() + el->get_inline_shift_left();
419 				}
420 			}
421 		}
422 		if(remove_begin != m_items.end())
423 		{
424 			els.insert(els.begin(), remove_begin, m_items.end());
425 			m_items.erase(remove_begin, m_items.end());
426 
427 			for(const auto& el : els)
428 			{
429 				el->m_box = 0;
430 			}
431 		}
432 	}
433 }
434 
435