#include "html.h"
#include "box.h"
#include "html_tag.h"
litehtml::box_type litehtml::block_box::get_type()
{
return box_block;
}
int litehtml::block_box::height()
{
return m_element->height();
}
int litehtml::block_box::width()
{
return m_element->width();
}
void litehtml::block_box::add_element(const element::ptr &el)
{
m_element = el;
el->m_box = this;
}
void litehtml::block_box::finish(bool last_box)
{
if(!m_element) return;
m_element->apply_relative_shift(m_box_right - m_box_left);
}
bool litehtml::block_box::can_hold(const element::ptr &el, white_space ws)
{
if(m_element || el->is_inline_box())
{
return false;
}
return true;
}
bool litehtml::block_box::is_empty()
{
if(m_element)
{
return false;
}
return true;
}
int litehtml::block_box::baseline()
{
if(m_element)
{
return m_element->get_base_line();
}
return 0;
}
void litehtml::block_box::get_elements( elements_vector& els )
{
els.push_back(m_element);
}
int litehtml::block_box::top_margin()
{
if(m_element && m_element->collapse_top_margin())
{
return m_element->m_margins.top;
}
return 0;
}
int litehtml::block_box::bottom_margin()
{
if(m_element && m_element->collapse_bottom_margin())
{
return m_element->m_margins.bottom;
}
return 0;
}
void litehtml::block_box::y_shift( int shift )
{
m_box_top += shift;
if(m_element)
{
m_element->m_pos.y += shift;
}
}
void litehtml::block_box::new_width( int left, int right, elements_vector& els )
{
}
//////////////////////////////////////////////////////////////////////////
litehtml::box_type litehtml::line_box::get_type()
{
return box_line;
}
int litehtml::line_box::height()
{
return m_height;
}
int litehtml::line_box::width()
{
return m_width;
}
void litehtml::line_box::add_element(const element::ptr &el)
{
el->m_skip = false;
el->m_box = 0;
bool add = true;
if( (m_items.empty() && el->is_white_space()) || el->is_break() )
{
el->m_skip = true;
} else if(el->is_white_space())
{
if (have_last_space())
{
add = false;
el->m_skip = true;
}
}
if(add)
{
el->m_box = this;
m_items.push_back(el);
if(!el->m_skip)
{
int el_shift_left = el->get_inline_shift_left();
int el_shift_right = el->get_inline_shift_right();
el->m_pos.x = m_box_left + m_width + el_shift_left + el->content_margins_left();
el->m_pos.y = m_box_top + el->content_margins_top();
m_width += el->width() + el_shift_left + el_shift_right;
}
}
}
void litehtml::line_box::finish(bool last_box)
{
if( is_empty() || (!is_empty() && last_box && is_break_only()) )
{
m_height = 0;
return;
}
for(auto i = m_items.rbegin(); i != m_items.rend(); i++)
{
if((*i)->is_white_space() || (*i)->is_break())
{
if(!(*i)->m_skip)
{
(*i)->m_skip = true;
m_width -= (*i)->width();
}
} else
{
break;
}
}
int base_line = m_font_metrics.base_line();
int line_height = m_line_height;
int add_x = 0;
switch(m_text_align)
{
case text_align_right:
if(m_width < (m_box_right - m_box_left))
{
add_x = (m_box_right - m_box_left) - m_width;
}
break;
case text_align_center:
if(m_width < (m_box_right - m_box_left))
{
add_x = ((m_box_right - m_box_left) - m_width) / 2;
}
break;
default:
add_x = 0;
}
m_height = 0;
// find line box baseline and line-height
for(const auto& el : m_items)
{
if(el->get_display() == display_inline_text)
{
font_metrics fm;
el->get_font(&fm);
base_line = std::max(base_line, fm.base_line());
line_height = std::max(line_height, el->line_height());
m_height = std::max(m_height, fm.height);
}
el->m_pos.x += add_x;
}
if(m_height)
{
base_line += (line_height - m_height) / 2;
}
m_height = line_height;
int y1 = 0;
int y2 = m_height;
for (const auto& el : m_items)
{
if(el->get_display() == display_inline_text)
{
font_metrics fm;
el->get_font(&fm);
el->m_pos.y = m_height - base_line - fm.ascent;
} else
{
switch(el->get_vertical_align())
{
case va_super:
case va_sub:
case va_baseline:
el->m_pos.y = m_height - base_line - el->height() + el->get_base_line() + el->content_margins_top();
break;
case va_top:
el->m_pos.y = y1 + el->content_margins_top();
break;
case va_text_top:
el->m_pos.y = m_height - base_line - m_font_metrics.ascent + el->content_margins_top();
break;
case va_middle:
el->m_pos.y = m_height - base_line - m_font_metrics.x_height / 2 - el->height() / 2 + el->content_margins_top();
break;
case va_bottom:
el->m_pos.y = y2 - el->height() + el->content_margins_top();
break;
case va_text_bottom:
el->m_pos.y = m_height - base_line + m_font_metrics.descent - el->height() + el->content_margins_top();
break;
}
y1 = std::min(y1, el->top());
y2 = std::max(y2, el->bottom());
}
}
css_offsets offsets;
for (const auto& el : m_items)
{
el->m_pos.y -= y1;
el->m_pos.y += m_box_top;
if(el->get_display() != display_inline_text)
{
switch(el->get_vertical_align())
{
case va_top:
el->m_pos.y = m_box_top + el->content_margins_top();
break;
case va_bottom:
el->m_pos.y = m_box_top + (y2 - y1) - el->height() + el->content_margins_top();
break;
case va_baseline:
//TODO: process vertical align "baseline"
break;
case va_middle:
//TODO: process vertical align "middle"
break;
case va_sub:
//TODO: process vertical align "sub"
break;
case va_super:
//TODO: process vertical align "super"
break;
case va_text_bottom:
//TODO: process vertical align "text-bottom"
break;
case va_text_top:
//TODO: process vertical align "text-top"
break;
}
}
el->apply_relative_shift(m_box_right - m_box_left);
}
m_height = y2 - y1;
m_baseline = (base_line - y1) - (m_height - line_height);
}
bool litehtml::line_box::can_hold(const element::ptr &el, white_space ws)
{
if(!el->is_inline_box()) return false;
if(el->is_break())
{
return false;
}
if(ws == white_space_nowrap || ws == white_space_pre)
{
return true;
}
if(m_box_left + m_width + el->width() + el->get_inline_shift_left() + el->get_inline_shift_right() > m_box_right)
{
return false;
}
return true;
}
bool litehtml::line_box::have_last_space()
{
bool ret = false;
for (auto i = m_items.rbegin(); i != m_items.rend() && !ret; i++)
{
if((*i)->is_white_space() || (*i)->is_break())
{
ret = true;
} else
{
break;
}
}
return ret;
}
bool litehtml::line_box::is_empty()
{
if(m_items.empty()) return true;
for (auto i = m_items.rbegin(); i != m_items.rend(); i++)
{
if(!(*i)->m_skip || (*i)->is_break())
{
return false;
}
}
return true;
}
int litehtml::line_box::baseline()
{
return m_baseline;
}
void litehtml::line_box::get_elements( elements_vector& els )
{
els.insert(els.begin(), m_items.begin(), m_items.end());
}
int litehtml::line_box::top_margin()
{
return 0;
}
int litehtml::line_box::bottom_margin()
{
return 0;
}
void litehtml::line_box::y_shift( int shift )
{
m_box_top += shift;
for (auto& el : m_items)
{
el->m_pos.y += shift;
}
}
bool litehtml::line_box::is_break_only()
{
if(m_items.empty()) return true;
if(m_items.front()->is_break())
{
for (auto& el : m_items)
{
if(!el->m_skip)
{
return false;
}
}
return true;
}
return false;
}
void litehtml::line_box::new_width( int left, int right, elements_vector& els )
{
int add = left - m_box_left;
if(add)
{
m_box_left = left;
m_box_right = right;
m_width = 0;
auto remove_begin = m_items.end();
for (auto i = m_items.begin() + 1; i != m_items.end(); i++)
{
element::ptr el = (*i);
if(!el->m_skip)
{
if(m_box_left + m_width + el->width() + el->get_inline_shift_right() + el->get_inline_shift_left() > m_box_right)
{
remove_begin = i;
break;
} else
{
el->m_pos.x += add;
m_width += el->width() + el->get_inline_shift_right() + el->get_inline_shift_left();
}
}
}
if(remove_begin != m_items.end())
{
els.insert(els.begin(), remove_begin, m_items.end());
m_items.erase(remove_begin, m_items.end());
for(const auto& el : els)
{
el->m_box = 0;
}
}
}
}