diff --git a/Libraries/LibWeb/Layout/BlockFormattingContext.cpp b/Libraries/LibWeb/Layout/BlockFormattingContext.cpp index 48f64dbc94..64c06198ed 100644 --- a/Libraries/LibWeb/Layout/BlockFormattingContext.cpp +++ b/Libraries/LibWeb/Layout/BlockFormattingContext.cpp @@ -83,8 +83,7 @@ void BlockFormattingContext::compute_width(Box& box) // FIXME: This should not be done *by* ReplacedBox auto& replaced = downcast(box); replaced.prepare_for_replaced_layout(); - auto width = replaced.calculate_width(); - replaced.set_width(width); + compute_width_for_block_level_replaced_element_in_normal_flow(replaced); return; } @@ -257,6 +256,16 @@ void BlockFormattingContext::compute_width_for_floating_box(Box& box) box.set_width(final_width); } +void BlockFormattingContext::compute_width_for_block_level_replaced_element_in_normal_flow(ReplacedBox& box) +{ + box.set_width(compute_width_for_replaced_element(box)); +} + +void BlockFormattingContext::compute_height_for_block_level_replaced_element_in_normal_flow(ReplacedBox& box) +{ + box.set_height(compute_height_for_replaced_element(box)); +} + void BlockFormattingContext::compute_width_for_absolutely_positioned_block(Box& box) { auto& containing_block = context_box(); @@ -400,9 +409,7 @@ void BlockFormattingContext::compute_width_for_absolutely_positioned_block(Box& void BlockFormattingContext::compute_height(Box& box) { if (box.is_replaced()) { - // FIXME: This should not be done *by* ReplacedBox - auto height = downcast(box).calculate_height(); - box.set_height(height); + compute_height_for_block_level_replaced_element_in_normal_flow(downcast(box)); return; } diff --git a/Libraries/LibWeb/Layout/BlockFormattingContext.h b/Libraries/LibWeb/Layout/BlockFormattingContext.h index 21e4a57794..d4d830a8f7 100644 --- a/Libraries/LibWeb/Layout/BlockFormattingContext.h +++ b/Libraries/LibWeb/Layout/BlockFormattingContext.h @@ -54,6 +54,9 @@ private: void compute_width_for_absolutely_positioned_block(Box&); void compute_width_for_floating_box(Box&); + void compute_width_for_block_level_replaced_element_in_normal_flow(ReplacedBox&); + void compute_height_for_block_level_replaced_element_in_normal_flow(ReplacedBox&); + void layout_initial_containing_block(LayoutMode); void layout_block_level_children(Box&, LayoutMode); diff --git a/Libraries/LibWeb/Layout/FormattingContext.cpp b/Libraries/LibWeb/Layout/FormattingContext.cpp index ba5c7ca610..40e4b1bc29 100644 --- a/Libraries/LibWeb/Layout/FormattingContext.cpp +++ b/Libraries/LibWeb/Layout/FormattingContext.cpp @@ -25,10 +25,12 @@ */ #include +#include #include #include #include #include +#include #include namespace Web::Layout { @@ -118,4 +120,81 @@ FormattingContext::ShrinkToFitResult FormattingContext::calculate_shrink_to_fit_ return { preferred_width, preferred_minimum_width }; } +float FormattingContext::compute_width_for_replaced_element(const ReplacedBox& box) +{ + // 10.3.4 Block-level, replaced elements in normal flow... + // 10.3.2 Inline, replaced elements + + auto zero_value = CSS::Length::make_px(0); + auto& containing_block = *box.containing_block(); + + auto margin_left = box.style().margin().left.resolved_or_zero(box, containing_block.width()); + auto margin_right = box.style().margin().right.resolved_or_zero(box, containing_block.width()); + + // A computed value of 'auto' for 'margin-left' or 'margin-right' becomes a used value of '0'. + if (margin_left.is_auto()) + margin_left = zero_value; + if (margin_right.is_auto()) + margin_right = zero_value; + + auto specified_width = box.style().width().resolved_or_auto(box, containing_block.width()); + auto specified_height = box.style().height().resolved_or_auto(box, containing_block.height()); + + // FIXME: Actually compute 'width' + auto computed_width = specified_width; + + float used_width = specified_width.to_px(box); + + // If 'height' and 'width' both have computed values of 'auto' and the element also has an intrinsic width, + // then that intrinsic width is the used value of 'width'. + if (specified_height.is_auto() && specified_width.is_auto() && box.has_intrinsic_width()) { + used_width = box.intrinsic_width(); + } + + // If 'height' and 'width' both have computed values of 'auto' and the element has no intrinsic width, + // but does have an intrinsic height and intrinsic ratio; + // or if 'width' has a computed value of 'auto', + // 'height' has some other computed value, and the element does have an intrinsic ratio; then the used value of 'width' is: + // + // (used height) * (intrinsic ratio) + else if ((specified_height.is_auto() && specified_width.is_auto() && !box.has_intrinsic_width() && box.has_intrinsic_height() && box.has_intrinsic_ratio()) || (computed_width.is_auto() && box.has_intrinsic_ratio())) { + used_width = compute_height_for_replaced_element(box) * box.intrinsic_ratio(); + } + + else if (computed_width.is_auto() && box.has_intrinsic_width()) { + used_width = box.intrinsic_width(); + } + + else if (computed_width.is_auto()) { + used_width = 300; + } + + return used_width; +} + +float FormattingContext::compute_height_for_replaced_element(const ReplacedBox& box) +{ + // 10.6.2 Inline replaced elements, block-level replaced elements in normal flow, + // 'inline-block' replaced elements in normal flow and floating replaced elements + auto& containing_block = *box.containing_block(); + + auto specified_width = box.style().width().resolved_or_auto(box, containing_block.width()); + auto specified_height = box.style().height().resolved_or_auto(box, containing_block.height()); + + float used_height = specified_height.to_px(box); + + // If 'height' and 'width' both have computed values of 'auto' and the element also has + // an intrinsic height, then that intrinsic height is the used value of 'height'. + if (specified_width.is_auto() && specified_height.is_auto() && box.has_intrinsic_height()) + used_height = box.intrinsic_height(); + else if (specified_height.is_auto() && box.has_intrinsic_ratio()) + used_height = compute_width_for_replaced_element(box) / box.intrinsic_ratio(); + else if (specified_height.is_auto() && box.has_intrinsic_height()) + used_height = box.intrinsic_height(); + else if (specified_height.is_auto()) + used_height = 150; + + return used_height; +} + } diff --git a/Libraries/LibWeb/Layout/FormattingContext.h b/Libraries/LibWeb/Layout/FormattingContext.h index c1a305ed43..34f39c1c39 100644 --- a/Libraries/LibWeb/Layout/FormattingContext.h +++ b/Libraries/LibWeb/Layout/FormattingContext.h @@ -44,6 +44,9 @@ public: static bool creates_block_formatting_context(const Box&); + static float compute_width_for_replaced_element(const ReplacedBox&); + static float compute_height_for_replaced_element(const ReplacedBox&); + protected: FormattingContext(Box&, FormattingContext* parent = nullptr); virtual ~FormattingContext(); diff --git a/Libraries/LibWeb/Layout/InlineFormattingContext.cpp b/Libraries/LibWeb/Layout/InlineFormattingContext.cpp index d94f7ab04f..602ba31be3 100644 --- a/Libraries/LibWeb/Layout/InlineFormattingContext.cpp +++ b/Libraries/LibWeb/Layout/InlineFormattingContext.cpp @@ -203,9 +203,9 @@ void InlineFormattingContext::run(Box&, LayoutMode layout_mode) void InlineFormattingContext::dimension_box_on_line(Box& box, LayoutMode layout_mode) { if (box.is_replaced()) { - auto& replaced = const_cast(downcast(box)); - replaced.set_width(replaced.calculate_width()); - replaced.set_height(replaced.calculate_height()); + auto& replaced = downcast(box); + replaced.set_width(compute_width_for_replaced_element(replaced)); + replaced.set_height(compute_height_for_replaced_element(replaced)); return; } diff --git a/Libraries/LibWeb/Layout/ReplacedBox.cpp b/Libraries/LibWeb/Layout/ReplacedBox.cpp index 9373ea5ffd..7cbf37524b 100644 --- a/Libraries/LibWeb/Layout/ReplacedBox.cpp +++ b/Libraries/LibWeb/Layout/ReplacedBox.cpp @@ -42,91 +42,13 @@ ReplacedBox::~ReplacedBox() { } -float ReplacedBox::calculate_width() const -{ - // 10.3.2 [Inline,] replaced elements - - auto zero_value = CSS::Length::make_px(0); - auto& containing_block = *this->containing_block(); - - auto margin_left = style().margin().left.resolved_or_zero(*this, containing_block.width()); - auto margin_right = style().margin().right.resolved_or_zero(*this, containing_block.width()); - - // A computed value of 'auto' for 'margin-left' or 'margin-right' becomes a used value of '0'. - if (margin_left.is_auto()) - margin_left = zero_value; - if (margin_right.is_auto()) - margin_right = zero_value; - - auto specified_width = style().width().resolved_or_auto(*this, containing_block.width()); - auto specified_height = style().height().resolved_or_auto(*this, containing_block.height()); - - // FIXME: Actually compute 'width' - auto computed_width = specified_width; - - float used_width = specified_width.to_px(*this); - - // If 'height' and 'width' both have computed values of 'auto' and the element also has an intrinsic width, - // then that intrinsic width is the used value of 'width'. - if (specified_height.is_auto() && specified_width.is_auto() && has_intrinsic_width()) { - used_width = intrinsic_width(); - } - - // If 'height' and 'width' both have computed values of 'auto' and the element has no intrinsic width, - // but does have an intrinsic height and intrinsic ratio; - // or if 'width' has a computed value of 'auto', - // 'height' has some other computed value, and the element does have an intrinsic ratio; then the used value of 'width' is: - // - // (used height) * (intrinsic ratio) - else if ((specified_height.is_auto() && specified_width.is_auto() && !has_intrinsic_width() && has_intrinsic_height() && has_intrinsic_ratio()) || (computed_width.is_auto() && has_intrinsic_ratio())) { - used_width = calculate_height() * intrinsic_ratio(); - } - - else if (computed_width.is_auto() && has_intrinsic_width()) { - used_width = intrinsic_width(); - } - - else if (computed_width.is_auto()) { - used_width = 300; - } - - return used_width; -} - -float ReplacedBox::calculate_height() const -{ - // 10.6.2 Inline replaced elements, block-level replaced elements in normal flow, - // 'inline-block' replaced elements in normal flow and floating replaced elements - auto& containing_block = *this->containing_block(); - - auto specified_width = style().width().resolved_or_auto(*this, containing_block.width()); - auto specified_height = style().height().resolved_or_auto(*this, containing_block.height()); - - float used_height = specified_height.to_px(*this); - - // If 'height' and 'width' both have computed values of 'auto' and the element also has - // an intrinsic height, then that intrinsic height is the used value of 'height'. - if (specified_width.is_auto() && specified_height.is_auto() && has_intrinsic_height()) - used_height = intrinsic_height(); - else if (specified_height.is_auto() && has_intrinsic_ratio()) - used_height = calculate_width() / intrinsic_ratio(); - else if (specified_height.is_auto() && has_intrinsic_height()) - used_height = intrinsic_height(); - else if (specified_height.is_auto()) - used_height = 150; - - return used_height; -} - void ReplacedBox::split_into_lines(InlineFormattingContext& context, LayoutMode) { auto& containing_block = context.containing_block(); - // FIXME: This feels out of place. It would be nice if someone at a higher level - // made sure we had usable geometry by the time we start splitting. prepare_for_replaced_layout(); - auto width = calculate_width(); - auto height = calculate_height(); + auto width = context.compute_width_for_replaced_element(*this); + auto height = context.compute_height_for_replaced_element(*this); auto* line_box = &containing_block.ensure_last_line_box(); if (line_box->width() > 0 && line_box->width() + width > context.available_width_at_line(containing_block.line_boxes().size() - 1)) diff --git a/Libraries/LibWeb/Layout/ReplacedBox.h b/Libraries/LibWeb/Layout/ReplacedBox.h index 081bfd8348..e64be16db0 100644 --- a/Libraries/LibWeb/Layout/ReplacedBox.h +++ b/Libraries/LibWeb/Layout/ReplacedBox.h @@ -57,9 +57,6 @@ public: void set_intrinsic_height(float height) { m_intrinsic_height = height; } void set_intrinsic_ratio(float ratio) { m_intrinsic_ratio = ratio; } - float calculate_width() const; - float calculate_height() const; - virtual void prepare_for_replaced_layout() { } virtual bool can_have_children() const override { return false; }