Disable stack execution on plugins
[claws.git] / src / plugins / litehtml_viewer / litehtml / render_item.cpp
blob4eb25757da29e77cbe45df3386e26333140c732d
1 #include "html.h"
2 #include "render_item.h"
3 #include "document.h"
4 #include <typeinfo>
5 #include <utf8_strings.h>
7 litehtml::render_item::render_item(std::shared_ptr<element> _src_el) :
8 m_element(std::move(_src_el)),
9 m_skip(false)
11 document::ptr doc = src_el()->get_document();
12 auto fnt_size = src_el()->css().get_font_size();
14 m_margins.left = doc->to_pixels(src_el()->css().get_margins().left, fnt_size);
15 m_margins.right = doc->to_pixels(src_el()->css().get_margins().right, fnt_size);
16 m_margins.top = doc->to_pixels(src_el()->css().get_margins().top, fnt_size);
17 m_margins.bottom = doc->to_pixels(src_el()->css().get_margins().bottom, fnt_size);
19 m_padding.left = doc->to_pixels(src_el()->css().get_padding().left, fnt_size);
20 m_padding.right = doc->to_pixels(src_el()->css().get_padding().right, fnt_size);
21 m_padding.top = doc->to_pixels(src_el()->css().get_padding().top, fnt_size);
22 m_padding.bottom = doc->to_pixels(src_el()->css().get_padding().bottom, fnt_size);
24 m_borders.left = doc->to_pixels(src_el()->css().get_borders().left.width, fnt_size);
25 m_borders.right = doc->to_pixels(src_el()->css().get_borders().right.width, fnt_size);
26 m_borders.top = doc->to_pixels(src_el()->css().get_borders().top.width, fnt_size);
27 m_borders.bottom = doc->to_pixels(src_el()->css().get_borders().bottom.width, fnt_size);
30 int litehtml::render_item::render(int x, int y, const containing_block_context& containing_block_size, formatting_context* fmt_ctx, bool second_pass)
32 int ret;
34 calc_outlines(containing_block_size.width);
36 m_pos.clear();
37 m_pos.move_to(x, y);
39 int content_left = content_offset_left();
40 int content_top = content_offset_top();
42 m_pos.x += content_left;
43 m_pos.y += content_top;
46 if(src_el()->is_block_formatting_context() || ! fmt_ctx)
48 formatting_context fmt;
49 fmt.push_position(content_left, content_top);
50 ret = _render(x, y, containing_block_size, &fmt, second_pass);
51 fmt.apply_relative_shift(containing_block_size);
52 } else
54 fmt_ctx->push_position(x + content_left, y + content_top);
55 ret = _render(x, y, containing_block_size, fmt_ctx, second_pass);
56 fmt_ctx->pop_position(x + content_left, y + content_top);
58 return ret;
61 void litehtml::render_item::calc_outlines( int parent_width )
63 m_padding.left = m_element->css().get_padding().left.calc_percent(parent_width);
64 m_padding.right = m_element->css().get_padding().right.calc_percent(parent_width);
66 m_borders.left = m_element->css().get_borders().left.width.calc_percent(parent_width);
67 m_borders.right = m_element->css().get_borders().right.width.calc_percent(parent_width);
69 m_margins.left = m_element->css().get_margins().left.calc_percent(parent_width);
70 m_margins.right = m_element->css().get_margins().right.calc_percent(parent_width);
72 m_margins.top = m_element->css().get_margins().top.calc_percent(parent_width);
73 m_margins.bottom = m_element->css().get_margins().bottom.calc_percent(parent_width);
75 m_padding.top = m_element->css().get_padding().top.calc_percent(parent_width);
76 m_padding.bottom = m_element->css().get_padding().bottom.calc_percent(parent_width);
79 int litehtml::render_item::calc_auto_margins(int parent_width)
81 if ((src_el()->css().get_display() == display_block || src_el()->css().get_display() == display_table) &&
82 src_el()->css().get_position() != element_position_absolute &&
83 src_el()->css().get_float() == float_none)
85 if (src_el()->css().get_margins().left.is_predefined() && src_el()->css().get_margins().right.is_predefined())
87 int el_width = m_pos.width + m_borders.left + m_borders.right + m_padding.left + m_padding.right;
88 if (el_width <= parent_width)
90 m_margins.left = (parent_width - el_width) / 2;
91 m_margins.right = (parent_width - el_width) - m_margins.left;
93 else
95 m_margins.left = 0;
96 m_margins.right = 0;
98 return m_margins.left;
100 else if (src_el()->css().get_margins().left.is_predefined() && !src_el()->css().get_margins().right.is_predefined())
102 int el_width = m_pos.width + m_borders.left + m_borders.right + m_padding.left + m_padding.right + m_margins.right;
103 m_margins.left = parent_width - el_width;
104 if (m_margins.left < 0) m_margins.left = 0;
105 return m_margins.left;
107 else if (!src_el()->css().get_margins().left.is_predefined() && src_el()->css().get_margins().right.is_predefined())
109 int el_width = m_pos.width + m_borders.left + m_borders.right + m_padding.left + m_padding.right + m_margins.left;
110 m_margins.right = parent_width - el_width;
111 if (m_margins.right < 0) m_margins.right = 0;
114 return 0;
117 void litehtml::render_item::apply_relative_shift(const containing_block_context &containing_block_size)
119 if (src_el()->css().get_position() == element_position_relative)
121 css_offsets offsets = src_el()->css().get_offsets();
122 if (!offsets.left.is_predefined())
124 m_pos.x += offsets.left.calc_percent(containing_block_size.width);
126 else if (!offsets.right.is_predefined())
128 m_pos.x -= offsets.right.calc_percent(containing_block_size.width);
130 if (!offsets.top.is_predefined())
132 m_pos.y += offsets.top.calc_percent(containing_block_size.height);
134 else if (!offsets.bottom.is_predefined())
136 m_pos.y -= offsets.bottom.calc_percent(containing_block_size.height);
141 bool litehtml::render_item::get_predefined_height(int& p_height, int containing_block_height) const
143 css_length h = src_el()->css().get_height();
144 if(h.is_predefined())
146 p_height = m_pos.height;
147 return false;
149 if(h.units() == css_units_percentage)
151 p_height = h.calc_percent(containing_block_height);
152 return containing_block_height > 0;
154 p_height = src_el()->get_document()->to_pixels(h, src_el()->css().get_font_size());
155 return p_height > 0;
158 int litehtml::render_item::calc_width(int defVal, int containing_block_width) const
160 css_length w = src_el()->css().get_width();
161 if(w.is_predefined() || src_el()->css().get_display() == display_table_cell)
163 return defVal;
165 if(w.units() == css_units_percentage)
167 return w.calc_percent(containing_block_width);
169 return src_el()->get_document()->to_pixels(w, src_el()->css().get_font_size());
172 std::tuple<
173 std::shared_ptr<litehtml::render_item>,
174 std::shared_ptr<litehtml::render_item>,
175 std::shared_ptr<litehtml::render_item>
176 > litehtml::render_item::split_inlines()
178 std::tuple<
179 std::shared_ptr<litehtml::render_item>,
180 std::shared_ptr<litehtml::render_item>,
181 std::shared_ptr<litehtml::render_item>
182 > ret;
183 for(const auto& child: m_children)
185 if(child->src_el()->is_block_box() && child->src_el()->css().get_float() == float_none)
187 std::get<0>(ret) = clone();
188 std::get<1>(ret) = child;
189 std::get<2>(ret) = clone();
191 std::get<1>(ret)->parent(std::get<0>(ret));
192 std::get<2>(ret)->parent(std::get<0>(ret));
194 bool found = false;
195 for(const auto& ch: m_children)
197 if(ch == child)
199 found = true;
200 continue;
202 if(!found)
204 std::get<0>(ret)->add_child(ch);
205 } else
207 std::get<2>(ret)->add_child(ch);
210 break;
212 if(!child->children().empty())
214 auto child_split = child->split_inlines();
215 if(std::get<0>(child_split))
217 std::get<0>(ret) = clone();
218 std::get<1>(ret) = std::get<1>(child_split);
219 std::get<2>(ret) = clone();
221 std::get<2>(ret)->parent(std::get<0>(ret));
223 bool found = false;
224 for(const auto& ch: m_children)
226 if(ch == child)
228 found = true;
229 continue;
231 if(!found)
233 std::get<0>(ret)->add_child(ch);
234 } else
236 std::get<2>(ret)->add_child(ch);
239 std::get<0>(ret)->add_child(std::get<0>(child_split));
240 std::get<2>(ret)->add_child(std::get<2>(child_split));
241 break;
245 return ret;
248 bool litehtml::render_item::fetch_positioned()
250 bool ret = false;
252 m_positioned.clear();
254 litehtml::element_position el_pos;
256 for(auto& el : m_children)
258 el_pos = el->src_el()->css().get_position();
259 if (el_pos != element_position_static)
261 add_positioned(el);
263 if (!ret && (el_pos == element_position_absolute || el_pos == element_position_fixed))
265 ret = true;
267 if(el->fetch_positioned())
269 ret = true;
272 return ret;
275 void litehtml::render_item::render_positioned(render_type rt)
277 position wnd_position;
278 src_el()->get_document()->container()->get_client_rect(wnd_position);
280 element_position el_position;
281 bool process;
282 for (auto& el : m_positioned)
284 el_position = el->src_el()->css().get_position();
286 process = false;
287 if(el->src_el()->css().get_display() != display_none)
289 if(el_position == element_position_absolute)
291 if(rt != render_fixed_only)
293 process = true;
295 } else if(el_position == element_position_fixed)
297 if(rt != render_no_fixed)
299 process = true;
304 if(process)
306 containing_block_context containing_block_size;
307 int client_x = 0;
308 int client_y = 0;
309 if(el_position == element_position_fixed)
311 containing_block_size.height = wnd_position.height;
312 containing_block_size.width = wnd_position.width;
313 client_x = wnd_position.left();
314 client_y = wnd_position.top();
315 } else
317 containing_block_size.height = m_pos.height;
318 containing_block_size.width = m_pos.width;
321 css_length css_left = el->src_el()->css().get_offsets().left;
322 css_length css_right = el->src_el()->css().get_offsets().right;
323 css_length css_top = el->src_el()->css().get_offsets().top;
324 css_length css_bottom = el->src_el()->css().get_offsets().bottom;
326 bool need_render = false;
328 css_length el_w = el->src_el()->css().get_width();
329 css_length el_h = el->src_el()->css().get_height();
331 int new_width = -1;
332 int new_height = -1;
333 if(el_w.units() == css_units_percentage && containing_block_size.width)
335 new_width = el_w.calc_percent(containing_block_size.width);
336 if(el->m_pos.width != new_width)
338 need_render = true;
339 el->m_pos.width = new_width;
343 if(el_h.units() == css_units_percentage && containing_block_size.height)
345 new_height = el_h.calc_percent(containing_block_size.height);
346 if(el->m_pos.height != new_height)
348 need_render = true;
349 el->m_pos.height = new_height;
353 bool cvt_x = false;
354 bool cvt_y = false;
356 if(el_position == element_position_fixed)
358 if(!css_left.is_predefined() || !css_right.is_predefined())
360 if(!css_left.is_predefined() && css_right.is_predefined())
362 el->m_pos.x = css_left.calc_percent(containing_block_size.width) + el->content_offset_left();
363 } else if(css_left.is_predefined() && !css_right.is_predefined())
365 el->m_pos.x = containing_block_size.width - css_right.calc_percent(containing_block_size.width) - el->m_pos.width -
366 el->content_offset_right();
367 } else
369 el->m_pos.x = css_left.calc_percent(containing_block_size.width) + el->content_offset_left();
370 el->m_pos.width = containing_block_size.width -
371 css_left.calc_percent(containing_block_size.width) -
372 css_right.calc_percent(containing_block_size.width) -
373 (el->content_offset_left() + el->content_offset_right());
374 need_render = true;
378 if(!css_top.is_predefined() || !css_bottom.is_predefined())
380 if(!css_top.is_predefined() && css_bottom.is_predefined())
382 el->m_pos.y = css_top.calc_percent(containing_block_size.height) + el->content_offset_top();
383 } else if(css_top.is_predefined() && !css_bottom.is_predefined())
385 el->m_pos.y = containing_block_size.height - css_bottom.calc_percent(containing_block_size.height) - el->m_pos.height -
386 el->content_offset_bottom();
387 } else
389 el->m_pos.y = css_top.calc_percent(containing_block_size.height) + el->content_offset_top();
390 el->m_pos.height = containing_block_size.height -
391 css_top.calc_percent(containing_block_size.height) -
392 css_bottom.calc_percent(containing_block_size.height) -
393 (el->content_offset_top() + el->content_offset_bottom());
394 need_render = true;
397 } else
399 if(!css_left.is_predefined() || !css_right.is_predefined())
401 if(!css_left.is_predefined() && css_right.is_predefined())
403 el->m_pos.x = css_left.calc_percent(containing_block_size.height) + el->content_offset_left() - m_padding.left;
404 } else if(css_left.is_predefined() && !css_right.is_predefined())
406 el->m_pos.x = m_pos.width + m_padding.right - css_right.calc_percent(containing_block_size.height) - el->m_pos.width -
407 el->content_offset_right();
408 } else
410 el->m_pos.x = css_left.calc_percent(containing_block_size.height) + el->content_offset_left() - m_padding.left;
411 el->m_pos.width = m_pos.width + m_padding.left + m_padding.right -
412 css_left.calc_percent(containing_block_size.height) -
413 css_right.calc_percent(containing_block_size.height) -
414 (el->content_offset_left() + el->content_offset_right());
415 if (new_width != -1)
417 el->m_pos.x += (el->m_pos.width - new_width) / 2;
418 el->m_pos.width = new_width;
420 need_render = true;
422 cvt_x = true;
425 if(!css_top.is_predefined() || !css_bottom.is_predefined())
427 if(!css_top.is_predefined() && css_bottom.is_predefined())
429 el->m_pos.y = css_top.calc_percent(containing_block_size.height) + el->content_offset_top() - m_padding.top;
430 } else if(css_top.is_predefined() && !css_bottom.is_predefined())
432 el->m_pos.y = m_pos.height + m_padding.bottom - css_bottom.calc_percent(containing_block_size.height) - el->m_pos.height -
433 el->content_offset_bottom();
434 } else
436 el->m_pos.y = css_top.calc_percent(containing_block_size.height) + el->content_offset_top() - m_padding.top;
437 el->m_pos.height = m_pos.height + m_padding.top + m_padding.bottom -
438 css_top.calc_percent(containing_block_size.height) -
439 css_bottom.calc_percent(containing_block_size.height) -
440 (el->content_offset_top() + el->content_offset_bottom());
441 if (new_height != -1)
443 el->m_pos.y += (el->m_pos.height - new_height) / 2;
444 el->m_pos.height = new_height;
446 need_render = true;
448 cvt_y = true;
452 if(cvt_x || cvt_y)
454 int offset_x = 0;
455 int offset_y = 0;
456 auto cur_el = el->parent();
457 auto this_el = shared_from_this();
458 while(cur_el && cur_el != this_el)
460 offset_x += cur_el->m_pos.x;
461 offset_y += cur_el->m_pos.y;
462 cur_el = cur_el->parent();
464 if(cvt_x) el->m_pos.x -= offset_x;
465 if(cvt_y) el->m_pos.y -= offset_y;
468 if(need_render)
470 position pos = el->m_pos;
471 el->render(el->left(), el->top(), containing_block_size.new_width(el->width()), nullptr, true);
472 el->m_pos = pos;
475 if(el_position == element_position_fixed)
477 position fixed_pos;
478 el->get_redraw_box(fixed_pos);
479 src_el()->get_document()->add_fixed_box(fixed_pos);
483 el->render_positioned();
486 if(!m_positioned.empty())
488 std::stable_sort(m_positioned.begin(), m_positioned.end(), [](const std::shared_ptr<render_item>& Left, const std::shared_ptr<render_item>& Right)
490 return (Left->src_el()->css().get_z_index() < Right->src_el()->css().get_z_index());
495 void litehtml::render_item::add_positioned(const std::shared_ptr<litehtml::render_item> &el)
497 if (src_el()->css().get_position() != element_position_static || is_root())
499 m_positioned.push_back(el);
500 } else
502 auto el_parent = parent();
503 if (el_parent)
505 el_parent->add_positioned(el);
510 void litehtml::render_item::get_redraw_box(litehtml::position& pos, int x /*= 0*/, int y /*= 0*/)
512 if(is_visible())
514 int p_left = std::min(pos.left(), x + m_pos.left() - m_padding.left - m_borders.left);
515 int p_right = std::max(pos.right(), x + m_pos.right() + m_padding.left + m_borders.left);
516 int p_top = std::min(pos.top(), y + m_pos.top() - m_padding.top - m_borders.top);
517 int p_bottom = std::max(pos.bottom(), y + m_pos.bottom() + m_padding.bottom + m_borders.bottom);
519 pos.x = p_left;
520 pos.y = p_top;
521 pos.width = p_right - p_left;
522 pos.height = p_bottom - p_top;
524 if(src_el()->css().get_overflow() == overflow_visible)
526 for(auto& el : m_children)
528 if(el->src_el()->css().get_position() != element_position_fixed)
530 el->get_redraw_box(pos, x + m_pos.x, y + m_pos.y);
537 void litehtml::render_item::calc_document_size( litehtml::size& sz, litehtml::size& content_size, int x /*= 0*/, int y /*= 0*/ )
539 if(is_visible() && src_el()->css().get_position() != element_position_fixed)
541 sz.width = std::max(sz.width, x + right());
542 sz.height = std::max(sz.height, y + bottom());
544 if(!src_el()->is_root() && !src_el()->is_body())
546 content_size.width = std::max(content_size.width, x + right());
547 content_size.height = std::max(content_size.height, y + bottom());
550 // All children of tables and blocks with style other than "overflow: visible" are inside element.
551 // We can skip calculating size of children
552 if(src_el()->css().get_overflow() == overflow_visible && src_el()->css().get_display() != display_table)
554 for(auto& el : m_children)
556 el->calc_document_size(sz, content_size, x + m_pos.x, y + m_pos.y);
560 if(src_el()->is_root() || src_el()->is_body())
562 content_size.width += content_offset_right();
563 content_size.height += content_offset_bottom();
568 void litehtml::render_item::draw_stacking_context( uint_ptr hdc, int x, int y, const position* clip, bool with_positioned )
570 if(!is_visible()) return;
572 std::map<int, bool> z_indexes;
573 if(with_positioned)
575 for(const auto& idx : m_positioned)
577 z_indexes[idx->src_el()->css().get_z_index()];
580 for(const auto& idx : z_indexes)
582 if(idx.first < 0)
584 draw_children(hdc, x, y, clip, draw_positioned, idx.first);
588 draw_children(hdc, x, y, clip, draw_block, 0);
589 draw_children(hdc, x, y, clip, draw_floats, 0);
590 draw_children(hdc, x, y, clip, draw_inlines, 0);
591 if(with_positioned)
593 for(auto& z_index : z_indexes)
595 if(z_index.first == 0)
597 draw_children(hdc, x, y, clip, draw_positioned, z_index.first);
601 for(auto& z_index : z_indexes)
603 if(z_index.first > 0)
605 draw_children(hdc, x, y, clip, draw_positioned, z_index.first);
611 void litehtml::render_item::draw_children(uint_ptr hdc, int x, int y, const position* clip, draw_flag flag, int zindex)
613 position pos = m_pos;
614 pos.x += x;
615 pos.y += y;
617 document::ptr doc = src_el()->get_document();
619 if (src_el()->css().get_overflow() > overflow_visible)
621 // TODO: Process overflow for inline elements
622 if(src_el()->css().get_display() != display_inline)
624 position border_box = pos;
625 border_box += m_padding;
626 border_box += m_borders;
628 border_radiuses bdr_radius = src_el()->css().get_borders().radius.calc_percents(border_box.width,
629 border_box.height);
631 bdr_radius -= m_borders;
632 bdr_radius -= m_padding;
634 doc->container()->set_clip(pos, bdr_radius);
638 for (const auto& el : m_children)
640 if (el->is_visible())
642 bool process = true;
643 switch (flag)
645 case draw_positioned:
646 if (el->src_el()->is_positioned() && el->src_el()->css().get_z_index() == zindex)
648 if (el->src_el()->css().get_position() == element_position_fixed)
650 position browser_wnd;
651 doc->container()->get_client_rect(browser_wnd);
653 el->src_el()->draw(hdc, browser_wnd.x, browser_wnd.y, clip, el);
654 el->draw_stacking_context(hdc, browser_wnd.x, browser_wnd.y, clip, true);
656 else
658 el->src_el()->draw(hdc, pos.x, pos.y, clip, el);
659 el->draw_stacking_context(hdc, pos.x, pos.y, clip, true);
661 process = false;
663 break;
664 case draw_block:
665 if (!el->src_el()->is_inline() && el->src_el()->css().get_float() == float_none && !el->src_el()->is_positioned())
667 el->src_el()->draw(hdc, pos.x, pos.y, clip, el);
669 break;
670 case draw_floats:
671 if (el->src_el()->css().get_float() != float_none && !el->src_el()->is_positioned())
673 el->src_el()->draw(hdc, pos.x, pos.y, clip, el);
674 el->draw_stacking_context(hdc, pos.x, pos.y, clip, false);
675 process = false;
677 break;
678 case draw_inlines:
679 if (el->src_el()->is_inline() && el->src_el()->css().get_float() == float_none && !el->src_el()->is_positioned())
681 el->src_el()->draw(hdc, pos.x, pos.y, clip, el);
682 if (el->src_el()->css().get_display() == display_inline_block)
684 el->draw_stacking_context(hdc, pos.x, pos.y, clip, false);
685 process = false;
688 break;
689 default:
690 break;
693 if (process)
695 if (flag == draw_positioned)
697 if (!el->src_el()->is_positioned())
699 el->draw_children(hdc, pos.x, pos.y, clip, flag, zindex);
702 else
704 if (el->src_el()->css().get_float() == float_none &&
705 el->src_el()->css().get_display() != display_inline_block &&
706 !el->src_el()->is_positioned())
708 el->draw_children(hdc, pos.x, pos.y, clip, flag, zindex);
715 if (src_el()->css().get_overflow() > overflow_visible)
717 doc->container()->del_clip();
721 std::shared_ptr<litehtml::element> litehtml::render_item::get_child_by_point(int x, int y, int client_x, int client_y, draw_flag flag, int zindex)
723 element::ptr ret = nullptr;
725 if(src_el()->css().get_overflow() > overflow_visible)
727 if(!m_pos.is_point_inside(x, y))
729 return ret;
733 position el_pos = m_pos;
734 el_pos.x = x - el_pos.x;
735 el_pos.y = y - el_pos.y;
737 for(auto i = m_children.rbegin(); i != m_children.rend() && !ret; std::advance(i, 1))
739 auto el = (*i);
741 if(el->is_visible() && el->src_el()->css().get_display() != display_inline_text)
743 switch(flag)
745 case draw_positioned:
746 if(el->src_el()->is_positioned() && el->src_el()->css().get_z_index() == zindex)
748 if(el->src_el()->css().get_position() == element_position_fixed)
750 ret = el->get_element_by_point(client_x, client_y, client_x, client_y);
751 if(!ret && (*i)->is_point_inside(client_x, client_y))
753 ret = (*i)->src_el();
755 } else
757 ret = el->get_element_by_point(el_pos.x, el_pos.y, client_x, client_y);
758 if(!ret && (*i)->is_point_inside(el_pos.x, el_pos.y))
760 ret = (*i)->src_el();
763 el = nullptr;
765 break;
766 case draw_block:
767 if(!el->src_el()->is_inline() && el->src_el()->css().get_float() == float_none && !el->src_el()->is_positioned())
769 if(el->is_point_inside(el_pos.x, el_pos.y))
771 ret = el->src_el();
774 break;
775 case draw_floats:
776 if(el->src_el()->css().get_float() != float_none && !el->src_el()->is_positioned())
778 ret = el->get_element_by_point(el_pos.x, el_pos.y, client_x, client_y);
780 if(!ret && (*i)->is_point_inside(el_pos.x, el_pos.y))
782 ret = (*i)->src_el();
784 el = nullptr;
786 break;
787 case draw_inlines:
788 if(el->src_el()->is_inline() && el->src_el()->css().get_float() == float_none && !el->src_el()->is_positioned())
790 if(el->src_el()->css().get_display() == display_inline_block ||
791 el->src_el()->css().get_display() == display_inline_table ||
792 el->src_el()->css().get_display() == display_inline_flex)
794 ret = el->get_element_by_point(el_pos.x, el_pos.y, client_x, client_y);
795 el = nullptr;
797 if(!ret && (*i)->is_point_inside(el_pos.x, el_pos.y))
799 ret = (*i)->src_el();
802 break;
803 default:
804 break;
807 if(el && !el->src_el()->is_positioned())
809 if(flag == draw_positioned)
811 element::ptr child = el->get_child_by_point(el_pos.x, el_pos.y, client_x, client_y, flag, zindex);
812 if(child)
814 ret = child;
816 } else
818 if( el->src_el()->css().get_float() == float_none &&
819 el->src_el()->css().get_display() != display_inline_block)
821 element::ptr child = el->get_child_by_point(el_pos.x, el_pos.y, client_x, client_y, flag, zindex);
822 if(child)
824 ret = child;
832 return ret;
835 std::shared_ptr<litehtml::element> litehtml::render_item::get_element_by_point(int x, int y, int client_x, int client_y)
837 if(!is_visible()) return nullptr;
839 element::ptr ret;
841 std::map<int, bool> z_indexes;
843 for(const auto& i : m_positioned)
845 z_indexes[i->src_el()->css().get_z_index()];
848 for(const auto& zindex : z_indexes)
850 if(zindex.first > 0)
852 ret = get_child_by_point(x, y, client_x, client_y, draw_positioned, zindex.first);
853 break;
856 if(ret) return ret;
858 for(const auto& z_index : z_indexes)
860 if(z_index.first == 0)
862 ret = get_child_by_point(x, y, client_x, client_y, draw_positioned, z_index.first);
863 break;
866 if(ret) return ret;
868 ret = get_child_by_point(x, y, client_x, client_y, draw_inlines, 0);
869 if(ret) return ret;
871 ret = get_child_by_point(x, y, client_x, client_y, draw_floats, 0);
872 if(ret) return ret;
874 ret = get_child_by_point(x, y, client_x, client_y, draw_block, 0);
875 if(ret) return ret;
878 for(const auto& z_index : z_indexes)
880 if(z_index.first < 0)
882 ret = get_child_by_point(x, y, client_x, client_y, draw_positioned, z_index.first);
883 break;
886 if(ret) return ret;
888 if(src_el()->css().get_position() == element_position_fixed)
890 if(is_point_inside(client_x, client_y))
892 ret = src_el();
894 } else
896 if(is_point_inside(x, y))
898 ret = src_el();
902 return ret;
905 bool litehtml::render_item::is_point_inside( int x, int y )
907 if(src_el()->css().get_display() != display_inline && src_el()->css().get_display() != display_table_row)
909 position pos = m_pos;
910 pos += m_padding;
911 pos += m_borders;
912 if(pos.is_point_inside(x, y))
914 return true;
915 } else
917 return false;
919 } else
921 position::vector boxes;
922 get_inline_boxes(boxes);
923 for(auto & box : boxes)
925 if(box.is_point_inside(x, y))
927 return true;
931 return false;
934 void litehtml::render_item::get_rendering_boxes( position::vector& redraw_boxes)
936 if(src_el()->css().get_display() == display_inline || src_el()->css().get_display() == display_table_row)
938 get_inline_boxes(redraw_boxes);
939 } else
941 position pos = m_pos;
942 pos += m_padding;
943 pos += m_borders;
944 redraw_boxes.push_back(pos);
947 if(src_el()->css().get_position() != element_position_fixed)
949 auto cur_el = parent();
950 while(cur_el)
952 for(auto& box : redraw_boxes)
954 box.x += cur_el->m_pos.x;
955 box.y += cur_el->m_pos.y;
957 cur_el = cur_el->parent();
962 void litehtml::render_item::dump(litehtml::dumper& cout)
964 cout.begin_node(src_el()->dump_get_name() + "{" + string(typeid(*this).name()) + "}");
966 auto attrs = src_el()->dump_get_attrs();
967 if(!attrs.empty())
969 cout.begin_attrs_group("attributes");
970 for (const auto &attr: attrs)
972 cout.add_attr(std::get<0>(attr), std::get<1>(attr));
974 cout.end_attrs_group();
977 if(!m_children.empty())
979 cout.begin_attrs_group("children");
980 for (const auto &el: m_children)
982 el->dump(cout);
984 cout.end_attrs_group();
987 cout.end_node();
990 litehtml::position litehtml::render_item::get_placement() const
992 litehtml::position pos = m_pos;
993 auto cur_el = parent();
994 while(cur_el)
996 pos.x += cur_el->m_pos.x;
997 pos.y += cur_el->m_pos.y;
998 cur_el = cur_el->parent();
1000 return pos;
1003 std::shared_ptr<litehtml::render_item> litehtml::render_item::init()
1005 src_el()->add_render(shared_from_this());
1007 for(auto& el : children())
1009 el = el->init();
1012 return shared_from_this();
1015 void litehtml::render_item::calc_cb_length(const css_length& len, int percent_base, containing_block_context::typed_int& out_value) const
1017 if (!len.is_predefined())
1019 if(len.units() == litehtml::css_units_percentage)
1021 out_value.value = len.calc_percent(percent_base);
1022 out_value.type = litehtml::containing_block_context::cbc_value_type_percentage;
1023 } else
1025 out_value.value = src_el()->get_document()->to_pixels(len, src_el()->css().get_font_size());
1026 out_value.type = containing_block_context::cbc_value_type_absolute;
1031 litehtml::containing_block_context litehtml::render_item::calculate_containing_block_context(const containing_block_context& cb_context)
1033 containing_block_context ret;
1034 ret.context_idx = cb_context.context_idx + 1;
1035 ret.width.value = ret.max_width.value = cb_context.width.value - content_offset_width();
1036 if(src_el()->css().get_position() != element_position_absolute && src_el()->css().get_position() != element_position_fixed)
1038 ret.height.value = cb_context.height.value - content_offset_height();
1041 // Calculate width if css property is not auto
1042 // We have to use aut value for display_table_cell also.
1043 if (src_el()->css().get_display() != display_table_cell)
1045 calc_cb_length(src_el()->css().get_width(), cb_context.width, ret.width);
1046 calc_cb_length(src_el()->css().get_height(), cb_context.height, ret.height);
1047 if (ret.width.type != containing_block_context::cbc_value_type_auto && (src_el()->css().get_display() == display_table || src_el()->is_root()))
1049 ret.width.value -= content_offset_width();
1051 if (ret.height.type != containing_block_context::cbc_value_type_auto && (src_el()->css().get_display() == display_table || src_el()->is_root()))
1053 ret.height.value -= content_offset_height();
1056 ret.render_width = ret.width;
1058 calc_cb_length(src_el()->css().get_min_width(), cb_context.width, ret.min_width);
1059 calc_cb_length(src_el()->css().get_max_width(), cb_context.width, ret.max_width);
1061 calc_cb_length(src_el()->css().get_min_height(), cb_context.height, ret.min_height);
1062 calc_cb_length(src_el()->css().get_max_height(), cb_context.height, ret.max_height);
1064 if (src_el()->css().get_box_sizing() == box_sizing_border_box)
1066 if(ret.width.type != containing_block_context::cbc_value_type_auto)
1068 ret.render_width = ret.width - box_sizing_width();
1070 if(ret.min_width.type != containing_block_context::cbc_value_type_none)
1072 ret.min_width.value -= box_sizing_width();
1074 if(ret.max_width.type != containing_block_context::cbc_value_type_none)
1076 ret.max_width.value -= box_sizing_width();
1078 if(ret.min_height.type != containing_block_context::cbc_value_type_none)
1080 ret.min_height.value -= box_sizing_height();
1082 if(ret.max_height.type != containing_block_context::cbc_value_type_none)
1084 ret.max_height.value -= box_sizing_height();
1087 return ret;