summaryrefslogtreecommitdiff
path: root/libs/litehtml/src/render_item.cpp
diff options
context:
space:
mode:
authorGeorge Hazan <george.hazan@gmail.com>2024-10-09 18:13:40 +0300
committerGeorge Hazan <george.hazan@gmail.com>2024-10-09 18:13:40 +0300
commit0e86b853be3b5f809ed1decbf636221c1144a386 (patch)
tree4ce84d9849646a559d5afece33fc6e64d39e4a50 /libs/litehtml/src/render_item.cpp
parent834cbb58d74215980165eab257538ba918a378cd (diff)
litehtml update
Diffstat (limited to 'libs/litehtml/src/render_item.cpp')
-rw-r--r--libs/litehtml/src/render_item.cpp593
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};
+}