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