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