summaryrefslogtreecommitdiff
path: root/libs/litehtml/src/render_block.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libs/litehtml/src/render_block.cpp')
-rw-r--r--libs/litehtml/src/render_block.cpp348
1 files changed, 348 insertions, 0 deletions
diff --git a/libs/litehtml/src/render_block.cpp b/libs/litehtml/src/render_block.cpp
new file mode 100644
index 0000000000..49e6f8fa2d
--- /dev/null
+++ b/libs/litehtml/src/render_block.cpp
@@ -0,0 +1,348 @@
+#include "html.h"
+#include "render_block.h"
+#include "render_inline_context.h"
+#include "render_block_context.h"
+#include "document.h"
+
+int litehtml::render_item_block::place_float(const std::shared_ptr<render_item> &el, int top, const containing_block_context &self_size, formatting_context* fmt_ctx)
+{
+ int line_top = fmt_ctx->get_cleared_top(el, 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);
+
+ int ret_width = 0;
+
+ int min_rendered_width = el->render(line_left, line_top, self_size.new_width(line_right), fmt_ctx);
+ if(min_rendered_width < el->width() && el->src_el()->css().get_width().is_predefined())
+ {
+ el->render(line_left, line_top, self_size.new_width(min_rendered_width), fmt_ctx);
+ }
+
+ if (el->src_el()->css().get_float() == float_left)
+ {
+ if(el->right() > line_right)
+ {
+ line_top = fmt_ctx->find_next_line_top(el->top(), el->width(), self_size.render_width);
+ el->pos().x = fmt_ctx->get_line_left(line_top) + el->content_offset_left();
+ el->pos().y = line_top + el->content_offset_top();
+ }
+ fmt_ctx->add_float(el, min_rendered_width, self_size.context_idx);
+ fix_line_width(float_left, self_size, fmt_ctx);
+
+ ret_width = fmt_ctx->find_min_left(line_top, self_size.context_idx);
+ } else if (el->src_el()->css().get_float() == float_right)
+ {
+ if(line_left + el->width() > line_right)
+ {
+ int new_top = fmt_ctx->find_next_line_top(el->top(), el->width(), self_size.render_width);
+ el->pos().x = fmt_ctx->get_line_right(new_top, self_size.render_width) - el->width() + el->content_offset_left();
+ el->pos().y = new_top + el->content_offset_top();
+ } else
+ {
+ el->pos().x = line_right - el->width() + el->content_offset_left();
+ }
+ fmt_ctx->add_float(el, min_rendered_width, self_size.context_idx);
+ fix_line_width(float_right, self_size, fmt_ctx);
+ line_right = fmt_ctx->find_min_right(line_top, self_size.render_width, self_size.context_idx);
+ ret_width = self_size.render_width - line_right;
+ }
+ return ret_width;
+}
+
+std::shared_ptr<litehtml::render_item> litehtml::render_item_block::init()
+{
+ {
+ css_selector sel;
+ sel.parse(".inline_rating");
+ if(src_el()->select(sel))
+ {
+ int i = 0;
+ i++;
+ }
+ }
+ std::shared_ptr<render_item> ret;
+
+ // Initialize indexes for list items
+ if(src_el()->css().get_display() == display_list_item && src_el()->css().get_list_style_type() >= list_style_type_armenian)
+ {
+ if (auto p = src_el()->parent())
+ {
+ int val = atoi(p->get_attr("start", "1"));
+ for(const auto &child : p->children())
+ {
+ if (child == src_el())
+ {
+ src_el()->set_attr("list_index", std::to_string(val).c_str());
+ break;
+ }
+ else if (child->css().get_display() == display_list_item)
+ val++;
+ }
+ }
+ }
+ // Split inline blocks with box blocks inside
+ auto iter = m_children.begin();
+ while (iter != m_children.end())
+ {
+ const auto& el = *iter;
+ if(el->src_el()->css().get_display() == display_inline && !el->children().empty())
+ {
+ auto split_el = el->split_inlines();
+ if(std::get<0>(split_el))
+ {
+ iter = m_children.erase(iter);
+ iter = m_children.insert(iter, std::get<2>(split_el));
+ iter = m_children.insert(iter, std::get<1>(split_el));
+ iter = m_children.insert(iter, std::get<0>(split_el));
+
+ std::get<0>(split_el)->parent(shared_from_this());
+ std::get<1>(split_el)->parent(shared_from_this());
+ std::get<2>(split_el)->parent(shared_from_this());
+ continue;
+ }
+ }
+ ++iter;
+ }
+
+ bool has_block_level = false;
+ bool has_inlines = false;
+ for (const auto& el : m_children)
+ {
+ if(!el->src_el()->is_float())
+ {
+ if (el->src_el()->is_block_box())
+ {
+ has_block_level = true;
+ } else if (el->src_el()->is_inline())
+ {
+ has_inlines = true;
+ }
+ }
+ if(has_block_level && has_inlines)
+ break;
+ }
+ if(has_block_level)
+ {
+ ret = std::make_shared<render_item_block_context>(src_el());
+ ret->parent(parent());
+
+ auto doc = src_el()->get_document();
+ decltype(m_children) new_children;
+ decltype(m_children) inlines;
+ bool not_ws_added = false;
+ for (const auto& el : m_children)
+ {
+ if(el->src_el()->is_inline())
+ {
+ inlines.push_back(el);
+ if(!el->src_el()->is_white_space())
+ not_ws_added = true;
+ } else
+ {
+ if(not_ws_added)
+ {
+ auto anon_el = std::make_shared<html_tag>(src_el());
+ auto anon_ri = std::make_shared<render_item_block>(anon_el);
+ for(const auto& inl : inlines)
+ {
+ anon_ri->add_child(inl);
+ }
+
+ not_ws_added = false;
+ new_children.push_back(anon_ri);
+ anon_ri->parent(ret);
+ }
+ new_children.push_back(el);
+ el->parent(ret);
+ inlines.clear();
+ }
+ }
+ if(!inlines.empty() && not_ws_added)
+ {
+ auto anon_el = std::make_shared<html_tag>(src_el());
+ auto anon_ri = std::make_shared<render_item_block>(anon_el);
+ for(const auto& inl : inlines)
+ {
+ anon_ri->add_child(inl);
+ }
+
+ new_children.push_back(anon_ri);
+ anon_ri->parent(ret);
+ }
+ ret->children() = new_children;
+ }
+
+ if(!ret)
+ {
+ ret = std::make_shared<render_item_inline_context>(src_el());
+ ret->parent(parent());
+ ret->children() = children();
+ for (const auto &el: ret->children())
+ {
+ el->parent(ret);
+ }
+ }
+
+ ret->src_el()->add_render(ret);
+
+ for(auto& el : ret->children())
+ {
+ el = el->init();
+ }
+
+ return ret;
+}
+
+int litehtml::render_item_block::_render(int x, int y, const containing_block_context &containing_block_size, formatting_context* fmt_ctx, bool second_pass)
+{
+ containing_block_context self_size = calculate_containing_block_context(containing_block_size);
+
+ //*****************************************
+ // Render content
+ //*****************************************
+ int ret_width = _render_content(x, y, second_pass, self_size, fmt_ctx);
+ //*****************************************
+
+ bool requires_rerender = false; // when true, the second pass for content rendering is required
+
+ // Set block width
+ if(!(containing_block_size.size_mode & containing_block_context::size_mode_content))
+ {
+ if(self_size.width.type == containing_block_context::cbc_value_type_absolute)
+ {
+ ret_width = m_pos.width = self_size.render_width;
+ } else
+ {
+ m_pos.width = self_size.render_width;
+ }
+ } else
+ {
+ m_pos.width = ret_width;
+ if(self_size.width.type == containing_block_context::cbc_value_type_absolute && ret_width > self_size.width)
+ {
+ ret_width = self_size.width;
+ }
+ }
+
+ // Fix width with max-width attribute
+ if(self_size.max_width.type != containing_block_context::cbc_value_type_none)
+ {
+ if(m_pos.width > self_size.max_width)
+ {
+ m_pos.width = self_size.max_width;
+ requires_rerender = true;
+ }
+ }
+
+ // Fix width with min-width attribute
+ if(self_size.min_width.type != containing_block_context::cbc_value_type_none)
+ {
+ if(m_pos.width < self_size.min_width)
+ {
+ m_pos.width = self_size.min_width;
+ requires_rerender = true;
+ }
+ } else if(m_pos.width < 0)
+ {
+ m_pos.width = 0;
+ }
+
+ // re-render content with new width if required
+ if (requires_rerender && !second_pass && !is_root())
+ {
+ if(src_el()->is_block_formatting_context())
+ {
+ fmt_ctx->clear_floats(-1);
+ } else
+ {
+ fmt_ctx->clear_floats(self_size.context_idx);
+ }
+
+ _render_content(x, y, true, self_size.new_width(m_pos.width), fmt_ctx);
+ }
+
+ // Set block height
+ if (self_size.height.type != containing_block_context::cbc_value_type_auto &&
+ !(containing_block_size.size_mode & containing_block_context::size_mode_content))
+ {
+ // TODO: Something wrong here
+ // Percentage height from undefined containing block height is usually <= 0
+ if(self_size.height.type == containing_block_context::cbc_value_type_percentage)
+ {
+ if (self_size.height > 0)
+ {
+ m_pos.height = self_size.height;
+ }
+ } else
+ {
+ m_pos.height = self_size.height;
+ }
+ if (src_el()->css().get_box_sizing() == box_sizing_border_box)
+ {
+ m_pos.height -= box_sizing_height();
+ }
+ } else if (src_el()->is_block_formatting_context())
+ {
+ // add the floats' height to the block height
+ int floats_height = fmt_ctx->get_floats_height();
+ if (floats_height > m_pos.height)
+ {
+ m_pos.height = floats_height;
+ }
+ }
+ if(containing_block_size.size_mode & containing_block_context::size_mode_content)
+ {
+ if(self_size.height.type == containing_block_context::cbc_value_type_absolute)
+ {
+ if(m_pos.height > self_size.height)
+ {
+ m_pos.height = self_size.height;
+ }
+ }
+ }
+
+ // Fix height with min-height attribute
+ if(self_size.min_height.type != containing_block_context::cbc_value_type_none)
+ {
+ if(m_pos.height < self_size.min_height)
+ {
+ m_pos.height = self_size.min_height;
+ }
+ } else if(m_pos.height < 0)
+ {
+ m_pos.height = 0;
+ }
+
+ // Fix width with max-width attribute
+ if(self_size.max_height.type != containing_block_context::cbc_value_type_none)
+ {
+ if(m_pos.height > self_size.max_height)
+ {
+ m_pos.height = self_size.max_height;
+ }
+ }
+
+ // calculate the final position
+ m_pos.move_to(x, y);
+ m_pos.x += content_offset_left();
+ m_pos.y += content_offset_top();
+
+ if (src_el()->css().get_display() == display_list_item)
+ {
+ string list_image = src_el()->css().get_list_style_image();
+ if (!list_image.empty())
+ {
+ size sz;
+ string list_image_baseurl = src_el()->css().get_list_style_image_baseurl();
+ src_el()->get_document()->container()->get_image_size(list_image.c_str(), list_image_baseurl.c_str(), sz);
+ if (m_pos.height < sz.height)
+ {
+ m_pos.height = sz.height;
+ }
+ }
+
+ }
+
+ return ret_width + content_offset_width();
+}