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