2 #include "render_block.h"
3 #include "render_inline_context.h"
4 #include "render_block_context.h"
7 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
)
9 int line_top
= fmt_ctx
->get_cleared_top(el
, top
);
11 int line_right
= self_size
.render_width
;
12 fmt_ctx
->get_line_left_right(line_top
, self_size
.render_width
, line_left
, line_right
);
16 int min_rendered_width
= el
->render(line_left
, line_top
, self_size
.new_width(line_right
), fmt_ctx
);
17 if(min_rendered_width
< el
->width() && el
->src_el()->css().get_width().is_predefined())
19 el
->render(line_left
, line_top
, self_size
.new_width(min_rendered_width
), fmt_ctx
);
22 if (el
->src_el()->css().get_float() == float_left
)
24 if(el
->right() > line_right
)
26 line_top
= fmt_ctx
->find_next_line_top(el
->top(), el
->width(), self_size
.render_width
);
27 el
->pos().x
= fmt_ctx
->get_line_left(line_top
) + el
->content_offset_left();
28 el
->pos().y
= line_top
+ el
->content_offset_top();
30 fmt_ctx
->add_float(el
, min_rendered_width
, self_size
.context_idx
);
31 fix_line_width(float_left
, self_size
, fmt_ctx
);
33 ret_width
= fmt_ctx
->find_min_left(line_top
, self_size
.context_idx
);
34 } else if (el
->src_el()->css().get_float() == float_right
)
36 if(line_left
+ el
->width() > line_right
)
38 int new_top
= fmt_ctx
->find_next_line_top(el
->top(), el
->width(), self_size
.render_width
);
39 el
->pos().x
= fmt_ctx
->get_line_right(new_top
, self_size
.render_width
) - el
->width() + el
->content_offset_left();
40 el
->pos().y
= new_top
+ el
->content_offset_top();
43 el
->pos().x
= line_right
- el
->width() + el
->content_offset_left();
45 fmt_ctx
->add_float(el
, min_rendered_width
, self_size
.context_idx
);
46 fix_line_width(float_right
, self_size
, fmt_ctx
);
47 line_right
= fmt_ctx
->find_min_right(line_top
, self_size
.render_width
, self_size
.context_idx
);
48 ret_width
= self_size
.render_width
- line_right
;
53 std::shared_ptr
<litehtml::render_item
> litehtml::render_item_block::init()
57 sel
.parse(".inline_rating");
58 if(src_el()->select(sel
))
64 std::shared_ptr
<render_item
> ret
;
66 // Initialize indexes for list items
67 if(src_el()->css().get_display() == display_list_item
&& src_el()->css().get_list_style_type() >= list_style_type_armenian
)
69 if (auto p
= src_el()->parent())
71 int val
= atoi(p
->get_attr("start", "1"));
72 for(const auto &child
: p
->children())
74 if (child
== src_el())
76 src_el()->set_attr("list_index", std::to_string(val
).c_str());
79 else if (child
->css().get_display() == display_list_item
)
84 // Split inline blocks with box blocks inside
85 auto iter
= m_children
.begin();
86 while (iter
!= m_children
.end())
88 const auto& el
= *iter
;
89 if(el
->src_el()->css().get_display() == display_inline
&& !el
->children().empty())
91 auto split_el
= el
->split_inlines();
92 if(std::get
<0>(split_el
))
94 iter
= m_children
.erase(iter
);
95 iter
= m_children
.insert(iter
, std::get
<2>(split_el
));
96 iter
= m_children
.insert(iter
, std::get
<1>(split_el
));
97 iter
= m_children
.insert(iter
, std::get
<0>(split_el
));
99 std::get
<0>(split_el
)->parent(shared_from_this());
100 std::get
<1>(split_el
)->parent(shared_from_this());
101 std::get
<2>(split_el
)->parent(shared_from_this());
108 bool has_block_level
= false;
109 bool has_inlines
= false;
110 bool has_floats
= false;
111 for (const auto& el
: m_children
)
113 if(!el
->src_el()->is_float())
115 if (el
->src_el()->is_block_box())
117 has_block_level
= true;
118 } else if (el
->src_el()->is_inline())
123 if(has_block_level
&& has_inlines
)
128 ret
= std::make_shared
<render_item_block_context
>(src_el());
129 ret
->parent(parent());
131 auto doc
= src_el()->get_document();
132 decltype(m_children
) new_children
;
133 decltype(m_children
) inlines
;
134 bool not_ws_added
= false;
135 for (const auto& el
: m_children
)
137 if(el
->src_el()->is_inline())
139 inlines
.push_back(el
);
140 if(!el
->src_el()->is_white_space())
146 auto anon_el
= std::make_shared
<html_tag
>(src_el());
147 auto anon_ri
= std::make_shared
<render_item_block
>(anon_el
);
148 for(const auto& inl
: inlines
)
150 anon_ri
->add_child(inl
);
153 not_ws_added
= false;
154 new_children
.push_back(anon_ri
);
155 anon_ri
->parent(ret
);
157 new_children
.push_back(el
);
162 if(!inlines
.empty() && not_ws_added
)
164 auto anon_el
= std::make_shared
<html_tag
>(src_el());
165 auto anon_ri
= std::make_shared
<render_item_block
>(anon_el
);
166 for(const auto& inl
: inlines
)
168 anon_ri
->add_child(inl
);
171 new_children
.push_back(anon_ri
);
172 anon_ri
->parent(ret
);
174 ret
->children() = new_children
;
179 ret
= std::make_shared
<render_item_inline_context
>(src_el());
180 ret
->parent(parent());
181 ret
->children() = children();
182 for (const auto &el
: ret
->children())
188 ret
->src_el()->add_render(ret
);
190 for(auto& el
: ret
->children())
198 int litehtml::render_item_block::_render(int x
, int y
, const containing_block_context
&containing_block_size
, formatting_context
* fmt_ctx
, bool second_pass
)
200 containing_block_context self_size
= calculate_containing_block_context(containing_block_size
);
202 //*****************************************
204 //*****************************************
205 int ret_width
= _render_content(x
, y
, second_pass
, self_size
, fmt_ctx
);
206 //*****************************************
208 bool requires_rerender
= false; // when true, the second pass for content rendering is required
211 if(!(containing_block_size
.size_mode
& containing_block_context::size_mode_content
))
213 if(self_size
.width
.type
== containing_block_context::cbc_value_type_absolute
)
215 ret_width
= m_pos
.width
= self_size
.render_width
;
218 m_pos
.width
= self_size
.render_width
;
222 m_pos
.width
= ret_width
;
223 if(self_size
.width
.type
== containing_block_context::cbc_value_type_absolute
&& ret_width
> self_size
.width
)
225 ret_width
= self_size
.width
;
229 // Fix width with max-width attribute
230 if(self_size
.max_width
.type
!= containing_block_context::cbc_value_type_none
)
232 if(m_pos
.width
> self_size
.max_width
)
234 m_pos
.width
= self_size
.max_width
;
235 requires_rerender
= true;
239 // Fix width with min-width attribute
240 if(self_size
.min_width
.type
!= containing_block_context::cbc_value_type_none
)
242 if(m_pos
.width
< self_size
.min_width
)
244 m_pos
.width
= self_size
.min_width
;
245 requires_rerender
= true;
247 } else if(m_pos
.width
< 0)
252 // re-render content with new width if required
253 if (requires_rerender
&& !second_pass
&& !is_root())
255 if(src_el()->is_block_formatting_context())
257 fmt_ctx
->clear_floats(-1);
260 fmt_ctx
->clear_floats(self_size
.context_idx
);
263 _render_content(x
, y
, true, self_size
.new_width(m_pos
.width
), fmt_ctx
);
267 if (self_size
.height
.type
!= containing_block_context::cbc_value_type_auto
&&
268 !(containing_block_size
.size_mode
& containing_block_context::size_mode_content
))
270 // TODO: Something wrong here
271 // Percentage height from undefined containing block height is usually <= 0
272 if(self_size
.height
.type
== containing_block_context::cbc_value_type_percentage
)
274 if (self_size
.height
> 0)
276 m_pos
.height
= self_size
.height
;
280 m_pos
.height
= self_size
.height
;
282 if (src_el()->css().get_box_sizing() == box_sizing_border_box
)
284 m_pos
.height
-= box_sizing_height();
286 } else if (src_el()->is_block_formatting_context())
288 // add the floats' height to the block height
289 int floats_height
= fmt_ctx
->get_floats_height();
290 if (floats_height
> m_pos
.height
)
292 m_pos
.height
= floats_height
;
295 if(containing_block_size
.size_mode
& containing_block_context::size_mode_content
)
297 if(self_size
.height
.type
== containing_block_context::cbc_value_type_absolute
)
299 if(m_pos
.height
> self_size
.height
)
301 m_pos
.height
= self_size
.height
;
306 // Fix height with min-height attribute
307 if(self_size
.min_height
.type
!= containing_block_context::cbc_value_type_none
)
309 if(m_pos
.height
< self_size
.min_height
)
311 m_pos
.height
= self_size
.min_height
;
313 } else if(m_pos
.height
< 0)
318 // Fix width with max-width attribute
319 if(self_size
.max_height
.type
!= containing_block_context::cbc_value_type_none
)
321 if(m_pos
.height
> self_size
.max_height
)
323 m_pos
.height
= self_size
.max_height
;
327 // calculate the final position
329 m_pos
.x
+= content_offset_left();
330 m_pos
.y
+= content_offset_top();
332 if (src_el()->css().get_display() == display_list_item
)
334 string list_image
= src_el()->css().get_list_style_image();
335 if (!list_image
.empty())
338 string list_image_baseurl
= src_el()->css().get_list_style_image_baseurl();
339 src_el()->get_document()->container()->get_image_size(list_image
.c_str(), list_image_baseurl
.c_str(), sz
);
340 if (m_pos
.height
< sz
.height
)
342 m_pos
.height
= sz
.height
;
348 return ret_width
+ content_offset_width();