diff options
author | George Hazan <george.hazan@gmail.com> | 2024-10-09 18:13:40 +0300 |
---|---|---|
committer | George Hazan <george.hazan@gmail.com> | 2024-10-09 18:13:40 +0300 |
commit | 0e86b853be3b5f809ed1decbf636221c1144a386 (patch) | |
tree | 4ce84d9849646a559d5afece33fc6e64d39e4a50 /libs/litehtml/src/render_item.cpp | |
parent | 834cbb58d74215980165eab257538ba918a378cd (diff) |
litehtml update
Diffstat (limited to 'libs/litehtml/src/render_item.cpp')
-rw-r--r-- | libs/litehtml/src/render_item.cpp | 593 |
1 files changed, 420 insertions, 173 deletions
diff --git a/libs/litehtml/src/render_item.cpp b/libs/litehtml/src/render_item.cpp index fa39510e5a..5ec65ab049 100644 --- a/libs/litehtml/src/render_item.cpp +++ b/libs/litehtml/src/render_item.cpp @@ -9,22 +9,22 @@ litehtml::render_item::render_item(std::shared_ptr<element> _src_el) : m_skip(false) { document::ptr doc = src_el()->get_document(); - auto fnt_size = src_el()->css().get_font_size(); - - m_margins.left = doc->to_pixels(src_el()->css().get_margins().left, fnt_size); - m_margins.right = doc->to_pixels(src_el()->css().get_margins().right, fnt_size); - m_margins.top = doc->to_pixels(src_el()->css().get_margins().top, fnt_size); - m_margins.bottom = doc->to_pixels(src_el()->css().get_margins().bottom, fnt_size); - - m_padding.left = doc->to_pixels(src_el()->css().get_padding().left, fnt_size); - m_padding.right = doc->to_pixels(src_el()->css().get_padding().right, fnt_size); - m_padding.top = doc->to_pixels(src_el()->css().get_padding().top, fnt_size); - m_padding.bottom = doc->to_pixels(src_el()->css().get_padding().bottom, fnt_size); - - m_borders.left = doc->to_pixels(src_el()->css().get_borders().left.width, fnt_size); - m_borders.right = doc->to_pixels(src_el()->css().get_borders().right.width, fnt_size); - m_borders.top = doc->to_pixels(src_el()->css().get_borders().top.width, fnt_size); - m_borders.bottom = doc->to_pixels(src_el()->css().get_borders().bottom.width, fnt_size); + auto fm = css().get_font_metrics(); + + m_margins.left = doc->to_pixels(src_el()->css().get_margins().left, fm, 0); + m_margins.right = doc->to_pixels(src_el()->css().get_margins().right, fm, 0); + m_margins.top = doc->to_pixels(src_el()->css().get_margins().top, fm, 0); + m_margins.bottom = doc->to_pixels(src_el()->css().get_margins().bottom, fm, 0); + + m_padding.left = doc->to_pixels(src_el()->css().get_padding().left, fm, 0); + m_padding.right = doc->to_pixels(src_el()->css().get_padding().right, fm, 0); + m_padding.top = doc->to_pixels(src_el()->css().get_padding().top, fm, 0); + m_padding.bottom = doc->to_pixels(src_el()->css().get_padding().bottom, fm, 0); + + m_borders.left = doc->to_pixels(src_el()->css().get_borders().left.width, fm, 0); + m_borders.right = doc->to_pixels(src_el()->css().get_borders().right.width, fm, 0); + m_borders.top = doc->to_pixels(src_el()->css().get_borders().top.width, fm, 0); + m_borders.bottom = doc->to_pixels(src_el()->css().get_borders().bottom.width, fm, 0); } int litehtml::render_item::render(int x, int y, const containing_block_context& containing_block_size, formatting_context* fmt_ctx, bool second_pass) @@ -273,14 +273,14 @@ void litehtml::render_item::render_positioned(render_type rt) if(process) { containing_block_context containing_block_size; - if(el_position == element_position_fixed) + if(el_position == element_position_fixed || (is_root() && !src_el()->is_positioned())) { containing_block_size.height = wnd_position.height; containing_block_size.width = wnd_position.width; } else { - containing_block_size.height = m_pos.height; - containing_block_size.width = m_pos.width; + containing_block_size.height = m_pos.height + m_padding.height(); + containing_block_size.width = m_pos.width + m_padding.width(); } css_length css_left = el->src_el()->css().get_offsets().left; @@ -290,144 +290,353 @@ void litehtml::render_item::render_positioned(render_type rt) bool need_render = false; - css_length el_w = el->src_el()->css().get_width(); - css_length el_h = el->src_el()->css().get_height(); - - int new_width = -1; - int new_height = -1; - if(el_w.units() == css_units_percentage && containing_block_size.width) - { - new_width = el_w.calc_percent(containing_block_size.width); - if(el->m_pos.width != new_width) - { - need_render = true; - el->m_pos.width = new_width; - } - } + css_length el_width = el->src_el()->css().get_width(); + css_length el_height = el->src_el()->css().get_height(); - if(el_h.units() == css_units_percentage && containing_block_size.height) - { - new_height = el_h.calc_percent(containing_block_size.height); - if(el->m_pos.height != new_height) - { - need_render = true; - el->m_pos.height = new_height; - } - } + auto fix_height_min_max = [&] (int height) + { + auto max_height = el->css().get_max_height(); + auto min_height = el->css().get_max_height(); + if(!max_height.is_predefined()) + { + int max_height_value = max_height.calc_percent(containing_block_size.height); + if(height > max_height_value) + { + height = max_height_value; + } + } + if(!min_height.is_predefined()) + { + int min_height_value = min_height.calc_percent(containing_block_size.height); + if(height < min_height_value) + { + height = min_height_value; + } + } + height += el->content_offset_height(); + return height; + }; - bool cvt_x = false; - bool cvt_y = false; + auto fix_width_min_max = [&] (int width) + { + auto max_width = el->css().get_max_width(); + auto min_width = el->css().get_min_width(); + if(!max_width.is_predefined()) + { + int max_width_value = max_width.calc_percent(containing_block_size.width); + if(width > max_width_value) + { + width = max_width_value; + } + } + if(!min_width.is_predefined()) + { + int min_width_value = min_width.calc_percent(containing_block_size.width); + if(width < min_width_value) + { + width = min_width_value; + } + } + width += el->content_offset_width(); + return width; + }; + + int bottom = 0; + int top = 0; + int height = 0; + auto [el_static_offset_x, el_static_offset_y] = element_static_offset(el); + int el_static_x = el->m_pos.x + el_static_offset_x; + int el_static_y = el->m_pos.y + el_static_offset_y; + // Calculate vertical position + // https://www.w3.org/TR/CSS22/visudet.html#abs-non-replaced-height + // 10.6.4 Absolutely positioned, non-replaced elements + if(css_top.is_predefined() && !css_bottom.is_predefined() && el_height.is_predefined()) + { + // 1. 'top' and 'height' are 'auto' and 'bottom' is not 'auto', then the height is based on the + // content per 10.6.7, set 'auto' values for 'margin-top' and 'margin-bottom' to 0, and solve for 'top' + if(el->css().get_margins().top.is_predefined()) el->m_margins.top = 0; + if(el->css().get_margins().bottom.is_predefined()) el->m_margins.bottom = 0; + height = el->height(); + bottom = css_bottom.calc_percent(containing_block_size.height); + top = containing_block_size.height - height - bottom; + } else if(css_top.is_predefined() && css_bottom.is_predefined() && !el_height.is_predefined()) + { + // 2. 'top' and 'bottom' are 'auto' and 'height' is not 'auto', then set 'top' to the static position, + // set 'auto' values for 'margin-top' and 'margin-bottom' to 0, and solve for 'bottom' + if(el->css().get_margins().top.is_predefined()) el->m_margins.top = 0; + if(el->css().get_margins().bottom.is_predefined()) el->m_margins.bottom = 0; + top = el_static_y - el->content_offset_top(); + height = fix_height_min_max(el_height.calc_percent(containing_block_size.height)); + } else if(!css_top.is_predefined() && css_bottom.is_predefined() && el_height.is_predefined()) + { + // 3. 'height' and 'bottom' are 'auto' and 'top' is not 'auto', then the height is based on the + // content per 10.6.7, set 'auto' values for 'margin-top' and 'margin-bottom' to 0, + // and solve for 'bottom' + if(el->css().get_margins().top.is_predefined()) el->m_margins.top = 0; + if(el->css().get_margins().bottom.is_predefined()) el->m_margins.bottom = 0; + height = el->height(); + top = css_top.calc_percent(containing_block_size.height); + } else if(css_top.is_predefined() && !css_bottom.is_predefined() && !el_height.is_predefined()) + { + // 4. 'top' is 'auto', 'height' and 'bottom' are not 'auto', then set 'auto' values for 'margin-top' + // and 'margin-bottom' to 0, and solve for 'top' + if(el->css().get_margins().top.is_predefined()) el->m_margins.top = 0; + if(el->css().get_margins().bottom.is_predefined()) el->m_margins.bottom = 0; + height = fix_height_min_max(el_height.calc_percent(containing_block_size.height)); + bottom = css_bottom.calc_percent(containing_block_size.height); + top = containing_block_size.height - height - bottom; + } else if(!css_top.is_predefined() && !css_bottom.is_predefined() && el_height.is_predefined()) + { + // 5. 'height' is 'auto', 'top' and 'bottom' are not 'auto', then 'auto' values for 'margin-top' and + // 'margin-bottom' are set to 0 and solve for 'height' + if(el->css().get_margins().top.is_predefined()) el->m_margins.top = 0; + if(el->css().get_margins().bottom.is_predefined()) el->m_margins.bottom = 0; + bottom = css_bottom.calc_percent(containing_block_size.height); + top = css_top.calc_percent(containing_block_size.height); + if(el->src_el()->is_replaced()) + { + height = el->height() - el->content_offset_height(); + int reminded = (containing_block_size.height - top - bottom) - height - el->content_offset_height(); + if(reminded > 0) + { + int divider = 0; + if (el->css().get_margins().top.is_predefined()) divider++; + if (el->css().get_margins().bottom.is_predefined()) divider++; + if (divider != 0) + { + if (el->css().get_margins().top.is_predefined()) el->m_margins.top = reminded / divider; + if (el->css().get_margins().bottom.is_predefined()) el->m_margins.bottom = reminded / divider; + } + } + height += el->content_offset_height(); + } else + { + height = containing_block_size.height - top - bottom; + } + if(!el->css().get_max_height().is_predefined()) + { + int max_height = el->css().get_max_height().calc_percent(containing_block_size.height); + if(height - el->content_offset_height() > max_height) + { + int reminded = height - el->content_offset_height() - max_height; + height = max_height; + int divider = 0; + if(el->css().get_margins().top.is_predefined()) divider++; + if(el->css().get_margins().bottom.is_predefined()) divider++; + if(divider != 0) + { + if(el->css().get_margins().top.is_predefined()) el->m_margins.top = reminded / divider; + if(el->css().get_margins().bottom.is_predefined()) el->m_margins.bottom = reminded / divider; + } + height += el->content_offset_height(); + } + } + } else if(!css_top.is_predefined() && css_bottom.is_predefined() && !el_height.is_predefined()) + { + // 6. 'bottom' is 'auto', 'top' and 'height' are not 'auto', then set 'auto' values for 'margin-top' + // and 'margin-bottom' to 0 and solve for 'bottom' + if(el->css().get_margins().top.is_predefined()) el->m_margins.top = 0; + if(el->css().get_margins().bottom.is_predefined()) el->m_margins.bottom = 0; + height = fix_height_min_max(el_height.calc_percent(containing_block_size.height)); + top = css_top.calc_percent(containing_block_size.height); + } else if(css_top.is_predefined() && css_bottom.is_predefined() && el_height.is_predefined()) + { + // If all three of 'top', 'height', and 'bottom' are auto, set 'top' to the static position and + // apply rule number three. + if(el->css().get_margins().top.is_predefined()) el->m_margins.top = 0; + if(el->css().get_margins().bottom.is_predefined()) el->m_margins.bottom = 0; + height = el->height(); + top = el_static_y - el->content_offset_top(); + } else + { + // If none of the three are 'auto': + height = fix_height_min_max(el_height.calc_percent(containing_block_size.height)); + top = css_top.calc_percent(containing_block_size.height); + bottom = css_bottom.calc_percent(containing_block_size.height); + int remained = containing_block_size.height - height - top - bottom; - if(el_position == element_position_fixed) - { - if(!css_left.is_predefined() || !css_right.is_predefined()) - { - if(!css_left.is_predefined() && css_right.is_predefined()) - { - el->m_pos.x = css_left.calc_percent(containing_block_size.width) + el->content_offset_left(); - } else if(css_left.is_predefined() && !css_right.is_predefined()) - { - el->m_pos.x = containing_block_size.width - css_right.calc_percent(containing_block_size.width) - el->m_pos.width - - el->content_offset_right(); - } else - { - el->m_pos.x = css_left.calc_percent(containing_block_size.width) + el->content_offset_left(); - el->m_pos.width = containing_block_size.width - - css_left.calc_percent(containing_block_size.width) - - css_right.calc_percent(containing_block_size.width) - - (el->content_offset_left() + el->content_offset_right()); - need_render = true; - } - } + if(el->css().get_margins().top.is_predefined() && el->css().get_margins().bottom.is_predefined()) + { + // If both 'margin-top' and 'margin-bottom' are 'auto', solve the equation under the extra + // constraint that the two margins get equal values. + el->m_margins.top = el->m_margins.bottom = remained / 2; + height += el->m_margins.top + el->m_margins.bottom; + } else + { + // If one of 'margin-top' or 'margin-bottom' is 'auto', solve the equation for that value. + if(el->css().get_margins().top.is_predefined()) + { + el->m_margins.top = remained; + height += el->m_margins.top; + } + if(el->css().get_margins().bottom.is_predefined()) + { + el->m_margins.bottom = remained; + height += el->m_margins.bottom; + } + } + } + el->m_pos.y = top + el->content_offset_top(); + if(el->m_pos.height != height - el->content_offset_height()) + { + el->m_pos.height = height - el->content_offset_height(); + need_render = true; + } - if(!css_top.is_predefined() || !css_bottom.is_predefined()) - { - if(!css_top.is_predefined() && css_bottom.is_predefined()) - { - el->m_pos.y = css_top.calc_percent(containing_block_size.height) + el->content_offset_top(); - } else if(css_top.is_predefined() && !css_bottom.is_predefined()) - { - el->m_pos.y = containing_block_size.height - css_bottom.calc_percent(containing_block_size.height) - el->m_pos.height - - el->content_offset_bottom(); - } else - { - el->m_pos.y = css_top.calc_percent(containing_block_size.height) + el->content_offset_top(); - el->m_pos.height = containing_block_size.height - - css_top.calc_percent(containing_block_size.height) - - css_bottom.calc_percent(containing_block_size.height) - - (el->content_offset_top() + el->content_offset_bottom()); - need_render = true; - } - } - } else - { - if(!css_left.is_predefined() || !css_right.is_predefined()) - { - if(!css_left.is_predefined() && css_right.is_predefined()) - { - el->m_pos.x = css_left.calc_percent(containing_block_size.height) + el->content_offset_left() - m_padding.left; - } else if(css_left.is_predefined() && !css_right.is_predefined()) - { - el->m_pos.x = m_pos.width + m_padding.right - css_right.calc_percent(containing_block_size.height) - el->m_pos.width - - el->content_offset_right(); - } else - { - el->m_pos.x = css_left.calc_percent(containing_block_size.height) + el->content_offset_left() - m_padding.left; - el->m_pos.width = m_pos.width + m_padding.left + m_padding.right - - css_left.calc_percent(containing_block_size.height) - - css_right.calc_percent(containing_block_size.height) - - (el->content_offset_left() + el->content_offset_right()); - if (new_width != -1) - { - el->m_pos.x += (el->m_pos.width - new_width) / 2; - el->m_pos.width = new_width; - } - need_render = true; - } - cvt_x = true; - } + // Calculate horizontal position + int right = 0; + int left = 0; + int width = 0; + // https://www.w3.org/TR/CSS22/visudet.html#abs-non-replaced-width + // 10.3.7 Absolutely positioned, non-replaced elements + if(css_left.is_predefined() && !css_right.is_predefined() && el_width.is_predefined()) + { + // 1. 'left' and 'width' are 'auto' and 'right' is not 'auto', then the width is shrink-to-fit. + // Then solve for 'left' + if(el->css().get_margins().left.is_predefined()) el->m_margins.left = 0; + if(el->css().get_margins().right.is_predefined()) el->m_margins.right = 0; + width = el->width(); + right = css_right.calc_percent(containing_block_size.width); + left = containing_block_size.width - width - right; + } else if(css_left.is_predefined() && css_right.is_predefined() && !el_width.is_predefined()) + { + // 2. 'left' and 'right' are 'auto' and 'width' is not 'auto', then if the 'direction' property of + // the element establishing the static-position containing block is 'ltr' set 'left' to the + // static position, otherwise set 'right' to the static position. Then solve for 'left' + // (if 'direction is 'rtl') or 'right' (if 'direction' is 'ltr'). + if(el->css().get_margins().left.is_predefined()) el->m_margins.left = 0; + if(el->css().get_margins().right.is_predefined()) el->m_margins.right = 0; + left = el_static_x - el->content_offset_left(); + width = fix_width_min_max(el_width.calc_percent(containing_block_size.width)); + } else if(!css_left.is_predefined() && css_right.is_predefined() && el_width.is_predefined()) + { + // 3. 'width' and 'right' are 'auto' and 'left' is not 'auto', then the width is shrink-to-fit . + // Then solve for 'right' + if(el->css().get_margins().left.is_predefined()) el->m_margins.left = 0; + if(el->css().get_margins().right.is_predefined()) el->m_margins.right = 0; + width = el->width(); + left = css_left.calc_percent(containing_block_size.width); + } else if(css_left.is_predefined() && !css_right.is_predefined() && !el_width.is_predefined()) + { + // 4. 'left' is 'auto', 'width' and 'right' are not 'auto', then solve for 'left' + if(el->css().get_margins().left.is_predefined()) el->m_margins.left = 0; + if(el->css().get_margins().right.is_predefined()) el->m_margins.right = 0; + right = css_right.calc_percent(containing_block_size.width); + width = fix_width_min_max(el_width.calc_percent(containing_block_size.width)); + left = containing_block_size.width - right - width; + } else if(!css_left.is_predefined() && !css_right.is_predefined() && el_width.is_predefined()) + { + // 5. 'width' is 'auto', 'left' and 'right' are not 'auto', then solve for 'width' + if(el->css().get_margins().left.is_predefined()) el->m_margins.left = 0; + if(el->css().get_margins().right.is_predefined()) el->m_margins.right = 0; + left = css_left.calc_percent(containing_block_size.width); + right = css_right.calc_percent(containing_block_size.width); + if(el->src_el()->is_replaced()) + { + width = el->width() - el->content_offset_width(); + int reminded = (containing_block_size.width - left - right) - width - el->content_offset_width(); + if(reminded) + { + int divider = 0; + if (el->css().get_margins().left.is_predefined()) divider++; + if (el->css().get_margins().right.is_predefined()) divider++; + if (divider != 0) + { + if (el->css().get_margins().left.is_predefined()) el->m_margins.left = reminded / divider; + if (el->css().get_margins().right.is_predefined()) el->m_margins.right = reminded / divider; + } + } + width += el->content_offset_width(); + } else + { + width = containing_block_size.width - left - right; + } + if(!el->css().get_max_width().is_predefined()) + { + int max_width = el->css().get_max_width().calc_percent(containing_block_size.height); + if(width - el->content_offset_width() > max_width) + { + int reminded = width - el->content_offset_width() - max_width; + width = max_width; + int divider = 0; + if(el->css().get_margins().left.is_predefined()) divider++; + if(el->css().get_margins().right.is_predefined()) divider++; + if(divider != 0) + { + if(el->css().get_margins().left.is_predefined()) el->m_margins.left = reminded / divider; + if(el->css().get_margins().right.is_predefined()) el->m_margins.right = reminded / divider; + } + width += el->content_offset_width(); + } + } + } else if(!css_left.is_predefined() && css_right.is_predefined() && !el_width.is_predefined()) + { + // 6. 'right' is 'auto', 'left' and 'width' are not 'auto', then solve for 'right' + if(el->css().get_margins().left.is_predefined()) el->m_margins.left = 0; + if(el->css().get_margins().right.is_predefined()) el->m_margins.right = 0; + left = css_left.calc_percent(containing_block_size.width); + width = fix_width_min_max(el_width.calc_percent(containing_block_size.width)); + } else if(css_left.is_predefined() && css_right.is_predefined() && el_width.is_predefined()) + { + // If all three of 'left', 'width', and 'right' are 'auto': First set any 'auto' values for + // 'margin-left' and 'margin-right' to 0. Then, if the 'direction' property of the element + // establishing the static-position containing block is 'ltr' set 'left' to the static position + // and apply rule number three below; otherwise, set 'right' to the static position and apply + // rule number one below. + if(el->css().get_margins().left.is_predefined()) el->m_margins.left = 0; + if(el->css().get_margins().right.is_predefined()) el->m_margins.right = 0; + width = el->width(); + left = el_static_x - el->content_offset_left(); + } else + { + // If none of the three is 'auto': + width = fix_width_min_max(el_width.calc_percent(containing_block_size.width)); + left = css_left.calc_percent(containing_block_size.width); + right = css_right.calc_percent(containing_block_size.width); + int remained = containing_block_size.width - width - left - right; - if(!css_top.is_predefined() || !css_bottom.is_predefined()) - { - if(!css_top.is_predefined() && css_bottom.is_predefined()) - { - el->m_pos.y = css_top.calc_percent(containing_block_size.height) + el->content_offset_top() - m_padding.top; - } else if(css_top.is_predefined() && !css_bottom.is_predefined()) - { - el->m_pos.y = m_pos.height + m_padding.bottom - css_bottom.calc_percent(containing_block_size.height) - el->m_pos.height - - el->content_offset_bottom(); - } else - { - el->m_pos.y = css_top.calc_percent(containing_block_size.height) + el->content_offset_top() - m_padding.top; - el->m_pos.height = m_pos.height + m_padding.top + m_padding.bottom - - css_top.calc_percent(containing_block_size.height) - - css_bottom.calc_percent(containing_block_size.height) - - (el->content_offset_top() + el->content_offset_bottom()); - if (new_height != -1) - { - el->m_pos.y += (el->m_pos.height - new_height) / 2; - el->m_pos.height = new_height; - } - need_render = true; - } - cvt_y = true; - } - } + if(el->css().get_margins().left.is_predefined() && el->css().get_margins().right.is_predefined()) + { + // If both 'margin-left' and 'margin-right' are 'auto', solve the equation under the extra + // constraint that the two margins get equal values, unless this would make them negative, + // in which case when direction of the containing block is 'ltr' ('rtl'), set 'margin-left' + // ('margin-right') to zero and solve for 'margin-right' ('margin-left'). + el->m_margins.left = el->m_margins.right = remained / 2; + if(el->m_margins.left < 0) + { + el->m_margins.left = 0; + el->m_margins.right = remained; + } + width += el->m_margins.left + el->m_margins.right; + } else + { + // If one of 'margin-left' or 'margin-right' is 'auto', solve the equation + // for that value. If the values are over-constrained, ignore the value for 'left' + // (in case the 'direction' property of the containing block is 'rtl') or 'right' (in case + // 'direction' is 'ltr') and solve for that value. + if(el->css().get_margins().left.is_predefined()) + { + el->m_margins.left = remained; + width += el->m_margins.left; + } + if(el->css().get_margins().right.is_predefined()) + { + el->m_margins.right = remained; + width += el->m_margins.right; + } + } + } + el->m_pos.x = left + el->content_offset_left(); + if(el->m_pos.width != width - el->content_offset_width()) + { + el->m_pos.width = width - el->content_offset_width(); + need_render = true; + } - if(cvt_x || cvt_y) + if(el_position != element_position_fixed) { - int offset_x = 0; - int offset_y = 0; - auto cur_el = el->parent(); - auto this_el = shared_from_this(); - while(cur_el && cur_el != this_el) - { - offset_x += cur_el->m_pos.x; - offset_y += cur_el->m_pos.y; - cur_el = cur_el->parent(); - } - if(cvt_x) el->m_pos.x -= offset_x; - if(cvt_y) el->m_pos.y -= offset_y; + el->m_pos.x -= el_static_offset_x; + el->m_pos.y -= el_static_offset_y; } if(need_render) @@ -501,33 +710,45 @@ void litehtml::render_item::get_redraw_box(litehtml::position& pos, int x /*= 0* void litehtml::render_item::calc_document_size( litehtml::size& sz, litehtml::size& content_size, int x /*= 0*/, int y /*= 0*/ ) { - if(is_visible() && src_el()->css().get_position() != element_position_fixed) - { - sz.width = std::max(sz.width, x + right()); - sz.height = std::max(sz.height, y + bottom()); - - if(!src_el()->is_root() && !src_el()->is_body()) + if(css().get_display() != display_inline && css().get_display() != display_table_row) + { + if (is_visible() && src_el()->css().get_position() != element_position_fixed) { - content_size.width = std::max(content_size.width, x + right()); - content_size.height = std::max(content_size.height, y + bottom()); - } + sz.width = std::max(sz.width, x + right()); + sz.height = std::max(sz.height, y + bottom()); - // All children of tables and blocks with style other than "overflow: visible" are inside element. - // We can skip calculating size of children - if(src_el()->css().get_overflow() == overflow_visible && src_el()->css().get_display() != display_table) - { - for(auto& el : m_children) - { - el->calc_document_size(sz, content_size, x + m_pos.x, y + m_pos.y); - } - } + if (!src_el()->is_root() && !src_el()->is_body()) + { + content_size.width = std::max(content_size.width, x + right()); + content_size.height = std::max(content_size.height, y + bottom()); + } + + // All children of tables and blocks with style other than "overflow: visible" are inside element. + // We can skip calculating size of children + if (src_el()->css().get_overflow() == overflow_visible && src_el()->css().get_display() != display_table) + { + for (auto &el: m_children) + { + el->calc_document_size(sz, content_size, x + m_pos.x, y + m_pos.y); + } + } - if(src_el()->is_root() || src_el()->is_body()) + if (src_el()->is_root() || src_el()->is_body()) + { + content_size.width = std::max(content_size.width, x + right()); + content_size.height = std::max(content_size.height, y + bottom()); + } + } + } else + { + position::vector boxes; + get_inline_boxes(boxes); + for(auto& box : boxes) { - content_size.width += content_offset_right(); - content_size.height += content_offset_bottom(); + content_size.width = std::max(content_size.width, x + box.x + box.width); + content_size.height = std::max(content_size.height, y + box.y + box.height); } - } + } } void litehtml::render_item::draw_stacking_context( uint_ptr hdc, int x, int y, const position* clip, bool with_positioned ) @@ -984,7 +1205,7 @@ void litehtml::render_item::calc_cb_length(const css_length& len, int percent_ba out_value.type = litehtml::containing_block_context::cbc_value_type_percentage; } else { - out_value.value = src_el()->get_document()->to_pixels(len, src_el()->css().get_font_size()); + out_value.value = src_el()->get_document()->to_pixels(len, css().get_font_metrics(), 0); out_value.type = containing_block_context::cbc_value_type_absolute; } } @@ -1094,3 +1315,29 @@ litehtml::containing_block_context litehtml::render_item::calculate_containing_b return ret; } + +std::tuple<int, int> litehtml::render_item::element_static_offset(const std::shared_ptr<litehtml::render_item>& el) +{ + int offset_x = 0; + int offset_y = 0; + auto cur_el = el->parent(); + auto this_el = el->css().get_position() != element_position_fixed ? shared_from_this() : src_el()->get_document()->root_render(); + while(cur_el && cur_el != this_el) + { + offset_x += cur_el->m_pos.x; + offset_y += cur_el->m_pos.y; + cur_el = cur_el->parent(); + } + + if(el->css().get_position() == element_position_fixed || (is_root() && !src_el()->is_positioned())) + { + offset_x += this_el->m_pos.x; + offset_y += this_el->m_pos.y; + } else + { + offset_x += m_padding.left; + offset_y += m_padding.top; + } + + return {offset_x, offset_y}; +} |