add support for Ayatana indicator to Notification plugin
[claws.git] / src / plugins / litehtml_viewer / litehtml / render_inline_context.cpp
blob4f5d77015e130e4b02e9b6f6280bbecb0a25ac9a
1 #include "html.h"
2 #include "render_inline_context.h"
3 #include "document.h"
4 #include "iterators.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)
8 m_line_boxes.clear();
9 m_max_line_width = 0;
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)
17 skip_spaces = true;
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)
28 switch (item_type)
30 case iterator_item_type_child:
32 // skip spaces to make rendering a bit faster
33 if (skip_spaces)
35 if (el->src_el()->is_white_space())
37 if (was_space)
39 el->skip(true);
40 return;
41 } else
43 was_space = true;
45 } else
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);
54 break;
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);
61 break;
63 case iterator_item_type_end_parent:
65 place_inline(std::unique_ptr<lbi_end>(new lbi_end(el)), self_size, fmt_ctx);
67 break;
69 });
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();
89 else
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)
112 was_cleared = true;
113 } else
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) )
118 was_cleared = true;
123 if(!was_cleared)
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);
132 } else
134 int line_top = 0;
135 line_top = m_line_boxes.back()->top();
137 int line_left = 0;
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();
177 } else
179 m_max_line_width = std::max(m_max_line_width, m_line_boxes.back()->min_width());
182 return ret;
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);
188 int line_top = 0;
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);
195 line_ctx.left = 0;
196 line_ctx.right = self_size.render_width;
197 line_ctx.fix_top();
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);
205 line_ctx.left = 0;
206 line_ctx.right = self_size.render_width;
207 line_ctx.fix_top();
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;
213 int text_indent = 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(
228 line_ctx.top,
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));
240 return line_ctx.top;
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())
249 int line_top = 0;
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;
259 return;
262 line_context line_ctx = {0};
263 line_ctx.top = 0;
264 if (!m_line_boxes.empty())
266 line_ctx.top = m_line_boxes.back().get()->top();
268 line_ctx.left = 0;
269 line_ctx.right = self_size.render_width;
270 line_ctx.fix_top();
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)
285 litehtml::size sz;
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);
292 bool add_box = true;
293 if(!m_line_boxes.empty())
295 if(m_line_boxes.back()->can_hold(item, src_el()->css().get_white_space()))
297 add_box = false;
300 if(add_box)
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)
310 line_ctx.left = 0;
311 line_ctx.right = self_size.render_width;
312 line_ctx.fix_top();
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();
323 if(shift >= 0)
325 line_ctx.top -= shift;
326 m_line_boxes.back()->y_shift(-shift);
329 } else
331 int shift = 0;
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();
337 } else
339 shift = prev_margin;
341 if(shift >= 0)
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())
356 int add = 0;
357 int content_height = m_line_boxes.back()->bottom();
359 if(m_pos.height > content_height)
361 switch(src_el()->css().get_vertical_align())
363 case va_middle:
364 add = (m_pos.height - content_height) / 2;
365 break;
366 case va_bottom:
367 add = m_pos.height - content_height;
368 break;
369 default:
370 add = 0;
371 break;
375 if(add)
377 for(auto & box : m_line_boxes)
379 box->y_shift(add);
385 int litehtml::render_item_inline_context::get_first_baseline()
387 int bl;
388 if(!m_line_boxes.empty())
390 const auto &line = m_line_boxes.front();
391 bl = line->bottom() - line->baseline() + content_offset_top();
392 } else
394 bl = height() - margin_bottom();
396 return bl;
399 int litehtml::render_item_inline_context::get_last_baseline()
401 int bl;
402 if(!m_line_boxes.empty())
404 const auto &line = m_line_boxes.back();
405 bl = line->bottom() - line->baseline() + content_offset_top();
406 } else
408 bl = height() - margin_bottom();
410 return bl;