2 #include "render_inline_context.h"
6 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
)
11 white_space ws
= src_el()->css().get_white_space();
12 bool skip_spaces
= false;
13 if (ws
== white_space_normal
||
14 ws
== white_space_nowrap
||
15 ws
== white_space_pre_line
)
20 bool was_space
= false;
22 go_inside_inline go_inside_inlines_selector
;
23 inline_selector select_inlines
;
24 elements_iterator
inlines_iter(true, &go_inside_inlines_selector
, &select_inlines
);
26 inlines_iter
.process(shared_from_this(), [&](const std::shared_ptr
<render_item
>& el
, iterator_item_type item_type
)
30 case iterator_item_type_child
:
32 // skip spaces to make rendering a bit faster
35 if (el
->src_el()->is_white_space())
47 // skip all spaces after line break
48 was_space
= el
->src_el()->is_break();
51 // place element into rendering flow
52 place_inline(std::unique_ptr
<line_box_item
>(new line_box_item(el
)), self_size
, fmt_ctx
);
56 case iterator_item_type_start_parent
:
58 el
->clear_inline_boxes();
59 place_inline(std::unique_ptr
<lbi_start
>(new lbi_start(el
)), self_size
, fmt_ctx
);
63 case iterator_item_type_end_parent
:
65 place_inline(std::unique_ptr
<lbi_end
>(new lbi_end(el
)), self_size
, fmt_ctx
);
71 finish_last_box(true, self_size
);
73 if (!m_line_boxes
.empty())
75 if (collapse_top_margin())
77 int old_top
= m_margins
.top
;
78 m_margins
.top
= std::max(m_line_boxes
.front()->top_margin(), m_margins
.top
);
79 if (m_margins
.top
!= old_top
)
81 fmt_ctx
->update_floats(m_margins
.top
- old_top
, shared_from_this());
84 if (collapse_bottom_margin())
86 m_margins
.bottom
= std::max(m_line_boxes
.back()->bottom_margin(), m_margins
.bottom
);
87 m_pos
.height
= m_line_boxes
.back()->bottom() - m_line_boxes
.back()->bottom_margin();
91 m_pos
.height
= m_line_boxes
.back()->bottom();
95 return m_max_line_width
;
98 void litehtml::render_item_inline_context::fix_line_width(element_float flt
,
99 const containing_block_context
&self_size
,
100 formatting_context
* fmt_ctx
)
102 if(!m_line_boxes
.empty())
104 auto el_front
= m_line_boxes
.back()->get_first_text_part();
106 std::vector
<std::shared_ptr
<render_item
>> els
;
107 bool was_cleared
= false;
108 if(el_front
&& el_front
->src_el()->css().get_clear() != clear_none
)
110 if(el_front
->src_el()->css().get_clear() == clear_both
)
115 if( (flt
== float_left
&& el_front
->src_el()->css().get_clear() == clear_left
) ||
116 (flt
== float_right
&& el_front
->src_el()->css().get_clear() == clear_right
) )
125 std::list
<std::unique_ptr
<line_box_item
> > items
= std::move(m_line_boxes
.back()->items());
126 m_line_boxes
.pop_back();
128 for(auto& item
: items
)
130 place_inline(std::move(item
), self_size
, fmt_ctx
);
135 line_top
= m_line_boxes
.back()->top();
138 int line_right
= self_size
.render_width
;
139 fmt_ctx
->get_line_left_right(line_top
, self_size
.render_width
, line_left
, line_right
);
141 if(m_line_boxes
.size() == 1)
143 if (src_el()->css().get_list_style_type() != list_style_type_none
&& src_el()->css().get_list_style_position() == list_style_position_inside
)
145 int sz_font
= src_el()->css().get_font_size();
146 line_left
+= sz_font
;
149 if (src_el()->css().get_text_indent().val() != 0)
151 line_left
+= src_el()->css().get_text_indent().calc_percent(self_size
.width
);
156 auto items
= m_line_boxes
.back()->new_width(line_left
, line_right
);
157 for(auto& item
: items
)
159 place_inline(std::move(item
), self_size
, fmt_ctx
);
165 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
)
167 std::list
<std::unique_ptr
<line_box_item
> > ret
;
169 if(!m_line_boxes
.empty())
171 ret
= m_line_boxes
.back()->finish(end_of_render
, self_size
);
173 if(m_line_boxes
.back()->is_empty() && end_of_render
)
175 // remove the last empty line
176 m_line_boxes
.pop_back();
179 m_max_line_width
= std::max(m_max_line_width
, m_line_boxes
.back()->min_width());
185 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
)
187 auto items
= finish_last_box(false, self_size
);
189 if(!m_line_boxes
.empty())
191 line_top
= m_line_boxes
.back()->bottom();
193 line_ctx
.top
= fmt_ctx
->get_cleared_top(el
->get_el(), line_top
);
196 line_ctx
.right
= self_size
.render_width
;
198 fmt_ctx
->get_line_left_right(line_ctx
.top
, self_size
.render_width
, line_ctx
.left
, line_ctx
.right
);
200 if(el
->get_el()->src_el()->is_inline() || el
->get_el()->src_el()->is_block_formatting_context())
202 if (el
->get_el()->width() > line_ctx
.right
- line_ctx
.left
)
204 line_ctx
.top
= fmt_ctx
->find_next_line_top(line_ctx
.top
, el
->get_el()->width(), self_size
.render_width
);
206 line_ctx
.right
= self_size
.render_width
;
208 fmt_ctx
->get_line_left_right(line_ctx
.top
, self_size
.render_width
, line_ctx
.left
, line_ctx
.right
);
212 int first_line_margin
= 0;
214 if(m_line_boxes
.empty())
216 if(src_el()->css().get_list_style_type() != list_style_type_none
&& src_el()->css().get_list_style_position() == list_style_position_inside
)
218 int sz_font
= src_el()->css().get_font_size();
219 first_line_margin
= sz_font
;
221 if(src_el()->css().get_text_indent().val() != 0)
223 text_indent
= src_el()->css().get_text_indent().calc_percent(self_size
.width
);
227 m_line_boxes
.emplace_back(std::unique_ptr
<line_box
>(new line_box(
229 line_ctx
.left
+ first_line_margin
+ text_indent
, line_ctx
.right
,
230 css().get_line_height(),
231 css().get_font_metrics(),
232 css().get_text_align())));
234 // Add items returned by finish_last_box function into the new line
235 for(auto& it
: items
)
237 m_line_boxes
.back()->add_item(std::move(it
));
243 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
)
245 if(item
->get_el()->src_el()->css().get_display() == display_none
) return;
247 if(item
->get_el()->src_el()->is_float())
250 if(!m_line_boxes
.empty())
252 line_top
= m_line_boxes
.back()->top();
254 int ret
= place_float(item
->get_el(), line_top
, self_size
, fmt_ctx
);
255 if(ret
> m_max_line_width
)
257 m_max_line_width
= ret
;
262 line_context line_ctx
= {0};
264 if (!m_line_boxes
.empty())
266 line_ctx
.top
= m_line_boxes
.back().get()->top();
269 line_ctx
.right
= self_size
.render_width
;
271 fmt_ctx
->get_line_left_right(line_ctx
.top
, self_size
.render_width
, line_ctx
.left
, line_ctx
.right
);
273 if(item
->get_type() == line_box_item::type_text_part
)
275 if(item
->get_el()->src_el()->is_inline_box())
277 int min_rendered_width
= item
->get_el()->render(line_ctx
.left
, line_ctx
.top
, self_size
.new_width(line_ctx
.right
), fmt_ctx
);
278 if(min_rendered_width
< item
->get_el()->width() && item
->get_el()->src_el()->css().get_width().is_predefined())
280 item
->get_el()->render(line_ctx
.left
, line_ctx
.top
, self_size
.new_width(min_rendered_width
), fmt_ctx
);
282 item
->set_rendered_min_width(min_rendered_width
);
283 } else if(item
->get_el()->src_el()->css().get_display() == display_inline_text
)
286 item
->get_el()->src_el()->get_content_size(sz
, line_ctx
.right
);
287 item
->get_el()->pos() = sz
;
288 item
->set_rendered_min_width(sz
.width
);
293 if(!m_line_boxes
.empty())
295 if(m_line_boxes
.back()->can_hold(item
, src_el()->css().get_white_space()))
302 new_box(item
, line_ctx
, self_size
, fmt_ctx
);
303 } else if(!m_line_boxes
.empty())
305 line_ctx
.top
= m_line_boxes
.back()->top();
308 if (line_ctx
.top
!= line_ctx
.calculatedTop
)
311 line_ctx
.right
= self_size
.render_width
;
313 fmt_ctx
->get_line_left_right(line_ctx
.top
, self_size
.render_width
, line_ctx
.left
, line_ctx
.right
);
316 if(!item
->get_el()->src_el()->is_inline())
318 if(m_line_boxes
.size() == 1)
320 if(collapse_top_margin())
322 int shift
= item
->get_el()->margin_top();
325 line_ctx
.top
-= shift
;
326 m_line_boxes
.back()->y_shift(-shift
);
332 int prev_margin
= m_line_boxes
[m_line_boxes
.size() - 2]->bottom_margin();
334 if(prev_margin
> item
->get_el()->margin_top())
336 shift
= item
->get_el()->margin_top();
343 line_ctx
.top
-= shift
;
344 m_line_boxes
.back()->y_shift(-shift
);
349 m_line_boxes
.back()->add_item(std::move(item
));
352 void litehtml::render_item_inline_context::apply_vertical_align()
354 if(!m_line_boxes
.empty())
357 int content_height
= m_line_boxes
.back()->bottom();
359 if(m_pos
.height
> content_height
)
361 switch(src_el()->css().get_vertical_align())
364 add
= (m_pos
.height
- content_height
) / 2;
367 add
= m_pos
.height
- content_height
;
377 for(auto & box
: m_line_boxes
)
385 int litehtml::render_item_inline_context::get_base_line()
387 auto el_parent
= parent();
388 if(el_parent
&& src_el()->css().get_display() == display_inline_flex
)
390 return el_parent
->get_base_line();
392 if(src_el()->is_replaced())
397 if(!m_line_boxes
.empty())
399 bl
= m_line_boxes
.back()->baseline() + content_offset_bottom();