summaryrefslogtreecommitdiff
path: root/libs/litehtml/src/render_inline_context.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libs/litehtml/src/render_inline_context.cpp')
-rw-r--r--libs/litehtml/src/render_inline_context.cpp409
1 files changed, 409 insertions, 0 deletions
diff --git a/libs/litehtml/src/render_inline_context.cpp b/libs/litehtml/src/render_inline_context.cpp
new file mode 100644
index 0000000000..b1ca1fcadc
--- /dev/null
+++ b/libs/litehtml/src/render_inline_context.cpp
@@ -0,0 +1,409 @@
+#include "html.h"
+#include "render_inline_context.h"
+#include "document.h"
+#include "iterators.h"
+
+int litehtml::render_item_inline_context::_render_content(int /*x*/, int /*y*/, bool /*second_pass*/, const containing_block_context &self_size, formatting_context* fmt_ctx)
+{
+ m_line_boxes.clear();
+ m_max_line_width = 0;
+
+ white_space ws = src_el()->css().get_white_space();
+ bool skip_spaces = false;
+ if (ws == white_space_normal ||
+ ws == white_space_nowrap ||
+ ws == white_space_pre_line)
+ {
+ skip_spaces = true;
+ }
+
+ bool was_space = false;
+
+ go_inside_inline go_inside_inlines_selector;
+ inline_selector select_inlines;
+ elements_iterator inlines_iter(true, &go_inside_inlines_selector, &select_inlines);
+
+ inlines_iter.process(shared_from_this(), [&](const std::shared_ptr<render_item>& el, iterator_item_type item_type)
+ {
+ switch (item_type)
+ {
+ case iterator_item_type_child:
+ {
+ // skip spaces to make rendering a bit faster
+ if (skip_spaces)
+ {
+ if (el->src_el()->is_white_space())
+ {
+ if (was_space)
+ {
+ el->skip(true);
+ return;
+ } else
+ {
+ was_space = true;
+ }
+ } else
+ {
+ // skip all spaces after line break
+ was_space = el->src_el()->is_break();
+ }
+ }
+ // place element into rendering flow
+ place_inline(std::unique_ptr<line_box_item>(new line_box_item(el)), self_size, fmt_ctx);
+ }
+ break;
+
+ case iterator_item_type_start_parent:
+ {
+ el->clear_inline_boxes();
+ place_inline(std::unique_ptr<lbi_start>(new lbi_start(el)), self_size, fmt_ctx);
+ }
+ break;
+
+ case iterator_item_type_end_parent:
+ {
+ place_inline(std::unique_ptr<lbi_end>(new lbi_end(el)), self_size, fmt_ctx);
+ }
+ break;
+ }
+ });
+
+ finish_last_box(true, self_size);
+
+ if (!m_line_boxes.empty())
+ {
+ if (collapse_top_margin())
+ {
+ int old_top = m_margins.top;
+ m_margins.top = std::max(m_line_boxes.front()->top_margin(), m_margins.top);
+ if (m_margins.top != old_top)
+ {
+ fmt_ctx->update_floats(m_margins.top - old_top, shared_from_this());
+ }
+ }
+ if (collapse_bottom_margin())
+ {
+ m_margins.bottom = std::max(m_line_boxes.back()->bottom_margin(), m_margins.bottom);
+ m_pos.height = m_line_boxes.back()->bottom() - m_line_boxes.back()->bottom_margin();
+ }
+ else
+ {
+ m_pos.height = m_line_boxes.back()->bottom();
+ }
+ }
+
+ return m_max_line_width;
+}
+
+void litehtml::render_item_inline_context::fix_line_width(element_float flt,
+ const containing_block_context &self_size,
+ formatting_context* fmt_ctx)
+{
+ if(!m_line_boxes.empty())
+ {
+ auto el_front = m_line_boxes.back()->get_first_text_part();
+
+ std::vector<std::shared_ptr<render_item>> els;
+ bool was_cleared = false;
+ if(el_front && el_front->src_el()->css().get_clear() != clear_none)
+ {
+ if(el_front->src_el()->css().get_clear() == clear_both)
+ {
+ was_cleared = true;
+ } else
+ {
+ if( (flt == float_left && el_front->src_el()->css().get_clear() == clear_left) ||
+ (flt == float_right && el_front->src_el()->css().get_clear() == clear_right) )
+ {
+ was_cleared = true;
+ }
+ }
+ }
+
+ if(!was_cleared)
+ {
+ std::list<std::unique_ptr<line_box_item> > items = std::move(m_line_boxes.back()->items());
+ m_line_boxes.pop_back();
+
+ for(auto& item : items)
+ {
+ place_inline(std::move(item), self_size, fmt_ctx);
+ }
+ } else
+ {
+ int line_top = 0;
+ line_top = m_line_boxes.back()->top();
+
+ int line_left = 0;
+ int line_right = self_size.render_width;
+ fmt_ctx->get_line_left_right(line_top, self_size.render_width, line_left, line_right);
+
+ if(m_line_boxes.size() == 1)
+ {
+ if (src_el()->css().get_list_style_type() != list_style_type_none && src_el()->css().get_list_style_position() == list_style_position_inside)
+ {
+ int sz_font = src_el()->css().get_font_size();
+ line_left += sz_font;
+ }
+
+ if (src_el()->css().get_text_indent().val() != 0)
+ {
+ line_left += src_el()->css().get_text_indent().calc_percent(self_size.width);
+ }
+
+ }
+
+ auto items = m_line_boxes.back()->new_width(line_left, line_right);
+ for(auto& item : items)
+ {
+ place_inline(std::move(item), self_size, fmt_ctx);
+ }
+ }
+ }
+}
+
+std::list<std::unique_ptr<litehtml::line_box_item> > litehtml::render_item_inline_context::finish_last_box(bool end_of_render, const containing_block_context &self_size)
+{
+ std::list<std::unique_ptr<line_box_item> > ret;
+
+ if(!m_line_boxes.empty())
+ {
+ ret = m_line_boxes.back()->finish(end_of_render, self_size);
+
+ if(m_line_boxes.back()->is_empty() && end_of_render)
+ {
+ // remove the last empty line
+ m_line_boxes.pop_back();
+ } else
+ {
+ m_max_line_width = std::max(m_max_line_width, m_line_boxes.back()->min_width());
+ }
+ }
+ return ret;
+}
+
+int litehtml::render_item_inline_context::new_box(const std::unique_ptr<line_box_item>& el, line_context& line_ctx, const containing_block_context &self_size, formatting_context* fmt_ctx)
+{
+ auto items = finish_last_box(false, self_size);
+ int line_top = 0;
+ if(!m_line_boxes.empty())
+ {
+ line_top = m_line_boxes.back()->bottom();
+ }
+ line_ctx.top = fmt_ctx->get_cleared_top(el->get_el(), line_top);
+
+ line_ctx.left = 0;
+ line_ctx.right = self_size.render_width;
+ line_ctx.fix_top();
+ fmt_ctx->get_line_left_right(line_ctx.top, self_size.render_width, line_ctx.left, line_ctx.right);
+
+ if(el->get_el()->src_el()->is_inline() || el->get_el()->src_el()->is_block_formatting_context())
+ {
+ if (el->get_el()->width() > line_ctx.right - line_ctx.left)
+ {
+ line_ctx.top = fmt_ctx->find_next_line_top(line_ctx.top, el->get_el()->width(), self_size.render_width);
+ line_ctx.left = 0;
+ line_ctx.right = self_size.render_width;
+ line_ctx.fix_top();
+ fmt_ctx->get_line_left_right(line_ctx.top, self_size.render_width, line_ctx.left, line_ctx.right);
+ }
+ }
+
+ int first_line_margin = 0;
+ int text_indent = 0;
+ if(m_line_boxes.empty())
+ {
+ if(src_el()->css().get_list_style_type() != list_style_type_none && src_el()->css().get_list_style_position() == list_style_position_inside)
+ {
+ int sz_font = src_el()->css().get_font_size();
+ first_line_margin = sz_font;
+ }
+ if(src_el()->css().get_text_indent().val() != 0)
+ {
+ text_indent = src_el()->css().get_text_indent().calc_percent(self_size.width);
+ }
+ }
+
+ m_line_boxes.emplace_back(std::unique_ptr<line_box>(new line_box(
+ line_ctx.top,
+ line_ctx.left + first_line_margin + text_indent, line_ctx.right,
+ css().get_line_height(),
+ css().get_font_metrics(),
+ css().get_text_align())));
+
+ // Add items returned by finish_last_box function into the new line
+ for(auto& it : items)
+ {
+ m_line_boxes.back()->add_item(std::move(it));
+ }
+
+ return line_ctx.top;
+}
+
+void litehtml::render_item_inline_context::place_inline(std::unique_ptr<line_box_item> item, const containing_block_context &self_size, formatting_context* fmt_ctx)
+{
+ if(item->get_el()->src_el()->css().get_display() == display_none) return;
+
+ if(item->get_el()->src_el()->is_float())
+ {
+ int line_top = 0;
+ if(!m_line_boxes.empty())
+ {
+ line_top = m_line_boxes.back()->top();
+ }
+ int ret = place_float(item->get_el(), line_top, self_size, fmt_ctx);
+ if(ret > m_max_line_width)
+ {
+ m_max_line_width = ret;
+ }
+ return;
+ }
+
+ line_context line_ctx;
+ if (!m_line_boxes.empty())
+ {
+ line_ctx.top = m_line_boxes.back().get()->top();
+ }
+ line_ctx.right = self_size.render_width;
+ line_ctx.fix_top();
+ fmt_ctx->get_line_left_right(line_ctx.top, self_size.render_width, line_ctx.left, line_ctx.right);
+
+ if(item->get_type() == line_box_item::type_text_part)
+ {
+ if(item->get_el()->src_el()->is_inline_box())
+ {
+ int min_rendered_width = item->get_el()->render(line_ctx.left, line_ctx.top, self_size.new_width(line_ctx.right), fmt_ctx);
+ if(min_rendered_width < item->get_el()->width() && item->get_el()->src_el()->css().get_width().is_predefined())
+ {
+ item->get_el()->render(line_ctx.left, line_ctx.top, self_size.new_width(min_rendered_width), fmt_ctx);
+ }
+ item->set_rendered_min_width(min_rendered_width);
+ } else if(item->get_el()->src_el()->css().get_display() == display_inline_text)
+ {
+ litehtml::size sz;
+ item->get_el()->src_el()->get_content_size(sz, line_ctx.right);
+ item->get_el()->pos() = sz;
+ item->set_rendered_min_width(sz.width);
+ }
+ }
+
+ bool add_box = true;
+ if(!m_line_boxes.empty())
+ {
+ if(m_line_boxes.back()->can_hold(item, src_el()->css().get_white_space()))
+ {
+ add_box = false;
+ }
+ }
+ if(add_box)
+ {
+ new_box(item, line_ctx, self_size, fmt_ctx);
+ } else if(!m_line_boxes.empty())
+ {
+ line_ctx.top = m_line_boxes.back()->top();
+ }
+
+ if (line_ctx.top != line_ctx.calculatedTop)
+ {
+ line_ctx.left = 0;
+ line_ctx.right = self_size.render_width;
+ line_ctx.fix_top();
+ fmt_ctx->get_line_left_right(line_ctx.top, self_size.render_width, line_ctx.left, line_ctx.right);
+ }
+
+ if(!item->get_el()->src_el()->is_inline())
+ {
+ if(m_line_boxes.size() == 1)
+ {
+ if(collapse_top_margin())
+ {
+ int shift = item->get_el()->margin_top();
+ if(shift >= 0)
+ {
+ line_ctx.top -= shift;
+ m_line_boxes.back()->y_shift(-shift);
+ }
+ }
+ } else
+ {
+ int shift = 0;
+ int prev_margin = m_line_boxes[m_line_boxes.size() - 2]->bottom_margin();
+
+ if(prev_margin > item->get_el()->margin_top())
+ {
+ shift = item->get_el()->margin_top();
+ } else
+ {
+ shift = prev_margin;
+ }
+ if(shift >= 0)
+ {
+ line_ctx.top -= shift;
+ m_line_boxes.back()->y_shift(-shift);
+ }
+ }
+ }
+
+ m_line_boxes.back()->add_item(std::move(item));
+}
+
+void litehtml::render_item_inline_context::apply_vertical_align()
+{
+ if(!m_line_boxes.empty())
+ {
+ int add = 0;
+ int content_height = m_line_boxes.back()->bottom();
+
+ if(m_pos.height > content_height)
+ {
+ switch(src_el()->css().get_vertical_align())
+ {
+ case va_middle:
+ add = (m_pos.height - content_height) / 2;
+ break;
+ case va_bottom:
+ add = m_pos.height - content_height;
+ break;
+ default:
+ add = 0;
+ break;
+ }
+ }
+
+ if(add)
+ {
+ for(auto & box : m_line_boxes)
+ {
+ box->y_shift(add);
+ }
+ }
+ }
+}
+
+int litehtml::render_item_inline_context::get_first_baseline()
+{
+ int bl;
+ if(!m_line_boxes.empty())
+ {
+ const auto &line = m_line_boxes.front();
+ bl = line->bottom() - line->baseline() + content_offset_top();
+ } else
+ {
+ bl = height() - margin_bottom();
+ }
+ return bl;
+}
+
+int litehtml::render_item_inline_context::get_last_baseline()
+{
+ int bl;
+ if(!m_line_boxes.empty())
+ {
+ const auto &line = m_line_boxes.back();
+ bl = line->bottom() - line->baseline() + content_offset_top();
+ } else
+ {
+ bl = height() - margin_bottom();
+ }
+ return bl;
+}