mirror of
https://github.com/RGBCube/serenity
synced 2025-06-01 11:28:11 +00:00
LibWeb: Convert InlineLevelIterator/LineBox/LineBuilder to new px units
This commit is contained in:
parent
700ba0007f
commit
76047d1932
8 changed files with 74 additions and 74 deletions
|
@ -713,7 +713,7 @@ void BlockFormattingContext::layout_floating_box(Box const& box, BlockContainer
|
|||
// First we place the box normally (to get the right y coordinate.)
|
||||
// If we have a LineBuilder, we're in the middle of inline layout, otherwise this is block layout.
|
||||
if (line_builder) {
|
||||
auto y = line_builder->y_for_float_to_be_inserted_here(box);
|
||||
auto y = line_builder->y_for_float_to_be_inserted_here(box).value();
|
||||
box_state.set_content_y(y + box_state.margin_box_top());
|
||||
} else {
|
||||
place_block_level_element_in_normal_flow_vertically(box, y + box_state.margin_box_top());
|
||||
|
|
|
@ -121,7 +121,7 @@ void InlineLevelIterator::skip_to_next()
|
|||
compute_next();
|
||||
}
|
||||
|
||||
Optional<InlineLevelIterator::Item> InlineLevelIterator::next(float available_width)
|
||||
Optional<InlineLevelIterator::Item> InlineLevelIterator::next(CSSPixels available_width)
|
||||
{
|
||||
if (!m_current_node)
|
||||
return {};
|
||||
|
@ -144,7 +144,7 @@ Optional<InlineLevelIterator::Item> InlineLevelIterator::next(float available_wi
|
|||
m_text_node_context->is_last_chunk = true;
|
||||
|
||||
auto& chunk = chunk_opt.value();
|
||||
float chunk_width = text_node.font().width(chunk.view) + text_node.font().glyph_spacing();
|
||||
CSSPixels chunk_width = text_node.font().width(chunk.view) + text_node.font().glyph_spacing();
|
||||
|
||||
if (m_text_node_context->do_respect_linebreaks && chunk.has_breaking_newline) {
|
||||
return Item {
|
||||
|
|
|
@ -34,16 +34,16 @@ public:
|
|||
Layout::Node const* node { nullptr };
|
||||
size_t offset_in_node { 0 };
|
||||
size_t length_in_node { 0 };
|
||||
float width { 0.0f };
|
||||
float padding_start { 0.0f };
|
||||
float padding_end { 0.0f };
|
||||
float border_start { 0.0f };
|
||||
float border_end { 0.0f };
|
||||
float margin_start { 0.0f };
|
||||
float margin_end { 0.0f };
|
||||
CSSPixels width { 0.0f };
|
||||
CSSPixels padding_start { 0.0f };
|
||||
CSSPixels padding_end { 0.0f };
|
||||
CSSPixels border_start { 0.0f };
|
||||
CSSPixels border_end { 0.0f };
|
||||
CSSPixels margin_start { 0.0f };
|
||||
CSSPixels margin_end { 0.0f };
|
||||
bool is_collapsible_whitespace { false };
|
||||
|
||||
float border_box_width() const
|
||||
CSSPixels border_box_width() const
|
||||
{
|
||||
return border_start + padding_start + width + padding_end + border_end;
|
||||
}
|
||||
|
@ -51,7 +51,7 @@ public:
|
|||
|
||||
InlineLevelIterator(Layout::InlineFormattingContext&, LayoutState&, Layout::BlockContainer const&, LayoutMode);
|
||||
|
||||
Optional<Item> next(float available_width);
|
||||
Optional<Item> next(CSSPixels available_width);
|
||||
|
||||
private:
|
||||
void skip_to_next();
|
||||
|
@ -87,9 +87,9 @@ private:
|
|||
Optional<TextNodeContext> m_text_node_context;
|
||||
|
||||
struct ExtraBoxMetrics {
|
||||
float margin { 0 };
|
||||
float border { 0 };
|
||||
float padding { 0 };
|
||||
CSSPixels margin { 0 };
|
||||
CSSPixels border { 0 };
|
||||
CSSPixels padding { 0 };
|
||||
};
|
||||
|
||||
Optional<ExtraBoxMetrics> m_extra_leading_metrics;
|
||||
|
|
|
@ -123,7 +123,7 @@ float box_baseline(LayoutState const& state, Box const& box)
|
|||
}
|
||||
|
||||
if (!box_state.line_boxes.is_empty())
|
||||
return box_state.border_box_top() + box_state.offset.y() + box_state.line_boxes.last().baseline();
|
||||
return box_state.border_box_top() + box_state.offset.y() + box_state.line_boxes.last().baseline().value();
|
||||
if (box.has_children() && !box.children_are_inline()) {
|
||||
auto const* child_box = box.last_child_of_type<Box>();
|
||||
VERIFY(child_box);
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
namespace Web::Layout {
|
||||
|
||||
void LineBox::add_fragment(Node const& layout_node, int start, int length, float leading_size, float trailing_size, float leading_margin, float trailing_margin, float content_width, float content_height, float border_box_top, float border_box_bottom, LineBoxFragment::Type fragment_type)
|
||||
void LineBox::add_fragment(Node const& layout_node, int start, int length, CSSPixels leading_size, CSSPixels trailing_size, CSSPixels leading_margin, CSSPixels trailing_margin, CSSPixels content_width, CSSPixels content_height, CSSPixels border_box_top, CSSPixels border_box_bottom, LineBoxFragment::Type fragment_type)
|
||||
{
|
||||
bool text_align_is_justify = layout_node.computed_values().text_align() == CSS::TextAlign::Justify;
|
||||
if (!text_align_is_justify && !m_fragments.is_empty() && &m_fragments.last().layout_node() == &layout_node) {
|
||||
|
@ -24,8 +24,8 @@ void LineBox::add_fragment(Node const& layout_node, int start, int length, float
|
|||
m_fragments.last().m_length = (start - m_fragments.last().m_start) + length;
|
||||
m_fragments.last().set_width(m_fragments.last().width() + content_width);
|
||||
} else {
|
||||
float x_offset = leading_margin + leading_size + m_width;
|
||||
float y_offset = 0.0f;
|
||||
CSSPixels x_offset = leading_margin + leading_size + m_width;
|
||||
CSSPixels y_offset = 0.0f;
|
||||
m_fragments.append(LineBoxFragment { layout_node, start, length, CSSPixelPoint(x_offset, y_offset), CSSPixelSize(content_width, content_height), border_box_top, border_box_bottom, fragment_type });
|
||||
}
|
||||
m_width += leading_margin + leading_size + content_width + trailing_size + trailing_margin;
|
||||
|
|
|
@ -15,12 +15,12 @@ class LineBox {
|
|||
public:
|
||||
LineBox() = default;
|
||||
|
||||
float width() const { return m_width; }
|
||||
float height() const { return m_height; }
|
||||
float bottom() const { return m_bottom; }
|
||||
float baseline() const { return m_baseline; }
|
||||
CSSPixels width() const { return m_width; }
|
||||
CSSPixels height() const { return m_height; }
|
||||
CSSPixels bottom() const { return m_bottom; }
|
||||
CSSPixels baseline() const { return m_baseline; }
|
||||
|
||||
void add_fragment(Node const& layout_node, int start, int length, float leading_size, float trailing_size, float leading_margin, float trailing_margin, float content_width, float content_height, float border_box_top, float border_box_bottom, LineBoxFragment::Type = LineBoxFragment::Type::Normal);
|
||||
void add_fragment(Node const& layout_node, int start, int length, CSSPixels leading_size, CSSPixels trailing_size, CSSPixels leading_margin, CSSPixels trailing_margin, CSSPixels content_width, CSSPixels content_height, CSSPixels border_box_top, CSSPixels border_box_bottom, LineBoxFragment::Type = LineBoxFragment::Type::Normal);
|
||||
|
||||
Vector<LineBoxFragment> const& fragments() const { return m_fragments; }
|
||||
Vector<LineBoxFragment>& fragments() { return m_fragments; }
|
||||
|
@ -36,10 +36,10 @@ private:
|
|||
friend class LineBuilder;
|
||||
|
||||
Vector<LineBoxFragment> m_fragments;
|
||||
float m_width { 0 };
|
||||
float m_height { 0 };
|
||||
float m_bottom { 0 };
|
||||
float m_baseline { 0 };
|
||||
CSSPixels m_width { 0 };
|
||||
CSSPixels m_height { 0 };
|
||||
CSSPixels m_bottom { 0 };
|
||||
CSSPixels m_baseline { 0 };
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ LineBuilder::~LineBuilder()
|
|||
update_last_line();
|
||||
}
|
||||
|
||||
void LineBuilder::break_line(Optional<float> next_item_width)
|
||||
void LineBuilder::break_line(Optional<CSSPixels> next_item_width)
|
||||
{
|
||||
update_last_line();
|
||||
size_t break_count = 0;
|
||||
|
@ -51,7 +51,7 @@ void LineBuilder::begin_new_line(bool increment_y, bool is_first_break_in_sequen
|
|||
// This means we're trying to squeeze past intruding floats.
|
||||
// Scan 1px at a time until we find a Y value where a new line can fit.
|
||||
// FIXME: This is super dumb and inefficient.
|
||||
float candidate_y = m_current_y + 1;
|
||||
CSSPixels candidate_y = m_current_y + 1;
|
||||
while (true) {
|
||||
if (m_context.can_fit_new_line_at_y(candidate_y))
|
||||
break;
|
||||
|
@ -73,7 +73,7 @@ LineBox& LineBuilder::ensure_last_line_box()
|
|||
return line_boxes.last();
|
||||
}
|
||||
|
||||
void LineBuilder::append_box(Box const& box, float leading_size, float trailing_size, float leading_margin, float trailing_margin)
|
||||
void LineBuilder::append_box(Box const& box, CSSPixels leading_size, CSSPixels trailing_size, CSSPixels leading_margin, CSSPixels trailing_margin)
|
||||
{
|
||||
auto& box_state = m_layout_state.get_mutable(box);
|
||||
auto& line_box = ensure_last_line_box();
|
||||
|
@ -86,21 +86,21 @@ void LineBuilder::append_box(Box const& box, float leading_size, float trailing_
|
|||
};
|
||||
}
|
||||
|
||||
void LineBuilder::append_text_chunk(TextNode const& text_node, size_t offset_in_node, size_t length_in_node, float leading_size, float trailing_size, float leading_margin, float trailing_margin, float content_width, float content_height)
|
||||
void LineBuilder::append_text_chunk(TextNode const& text_node, size_t offset_in_node, size_t length_in_node, CSSPixels leading_size, CSSPixels trailing_size, CSSPixels leading_margin, CSSPixels trailing_margin, CSSPixels content_width, CSSPixels content_height)
|
||||
{
|
||||
ensure_last_line_box().add_fragment(text_node, offset_in_node, length_in_node, leading_size, trailing_size, leading_margin, trailing_margin, content_width, content_height, 0, 0);
|
||||
m_max_height_on_current_line = max(m_max_height_on_current_line, content_height);
|
||||
}
|
||||
|
||||
float LineBuilder::y_for_float_to_be_inserted_here(Box const& box)
|
||||
CSSPixels LineBuilder::y_for_float_to_be_inserted_here(Box const& box)
|
||||
{
|
||||
auto const& box_state = m_layout_state.get(box);
|
||||
auto const width = box_state.margin_box_width();
|
||||
auto const height = box_state.margin_box_height();
|
||||
CSSPixels const width = box_state.margin_box_width();
|
||||
CSSPixels const height = box_state.margin_box_height();
|
||||
|
||||
float candidate_y = m_current_y;
|
||||
CSSPixels candidate_y = m_current_y;
|
||||
|
||||
float current_line_width = ensure_last_line_box().width();
|
||||
CSSPixels current_line_width = ensure_last_line_box().width();
|
||||
// If there's already inline content on the current line, check if the new float can fit
|
||||
// alongside the content. If not, place it on the next line.
|
||||
if (current_line_width > 0 && (current_line_width + width) > m_available_width_for_current_line)
|
||||
|
@ -110,8 +110,8 @@ float LineBuilder::y_for_float_to_be_inserted_here(Box const& box)
|
|||
// FIXME: This is super dumb, we move 1px downwards per iteration and stop
|
||||
// when we find an Y value where we don't collide with other floats.
|
||||
while (true) {
|
||||
auto space_at_y_top = m_context.available_space_for_line(candidate_y).value();
|
||||
auto space_at_y_bottom = m_context.available_space_for_line(candidate_y + height).value();
|
||||
auto space_at_y_top = m_context.available_space_for_line(candidate_y);
|
||||
auto space_at_y_bottom = m_context.available_space_for_line(candidate_y + height);
|
||||
if (width > space_at_y_top || width > space_at_y_bottom) {
|
||||
if (!m_context.any_floats_intrude_at_y(candidate_y) && !m_context.any_floats_intrude_at_y(candidate_y + height)) {
|
||||
return candidate_y;
|
||||
|
@ -123,9 +123,9 @@ float LineBuilder::y_for_float_to_be_inserted_here(Box const& box)
|
|||
}
|
||||
}
|
||||
|
||||
bool LineBuilder::should_break(float next_item_width)
|
||||
bool LineBuilder::should_break(CSSPixels next_item_width)
|
||||
{
|
||||
if (!isfinite(m_available_width_for_current_line))
|
||||
if (!isfinite(m_available_width_for_current_line.value()))
|
||||
return false;
|
||||
|
||||
auto const& line_boxes = m_containing_block_state.line_boxes;
|
||||
|
@ -154,11 +154,11 @@ void LineBuilder::update_last_line()
|
|||
auto text_align = m_context.containing_block().computed_values().text_align();
|
||||
|
||||
auto current_line_height = max(m_max_height_on_current_line, m_context.containing_block().line_height());
|
||||
float x_offset_top = m_context.leftmost_x_offset_at(m_current_y).value();
|
||||
float x_offset_bottom = m_context.leftmost_x_offset_at(m_current_y + current_line_height - 1).value();
|
||||
float x_offset = max(x_offset_top, x_offset_bottom);
|
||||
CSSPixels x_offset_top = m_context.leftmost_x_offset_at(m_current_y);
|
||||
CSSPixels x_offset_bottom = m_context.leftmost_x_offset_at(m_current_y + current_line_height - 1);
|
||||
CSSPixels x_offset = max(x_offset_top, x_offset_bottom);
|
||||
|
||||
float excess_horizontal_space = m_available_width_for_current_line - line_box.width();
|
||||
CSSPixels excess_horizontal_space = m_available_width_for_current_line - line_box.width();
|
||||
|
||||
switch (text_align) {
|
||||
case CSS::TextAlign::Center:
|
||||
|
@ -185,7 +185,7 @@ void LineBuilder::update_last_line()
|
|||
}();
|
||||
|
||||
auto line_box_baseline = [&] {
|
||||
float line_box_baseline = strut_baseline;
|
||||
CSSPixels line_box_baseline = strut_baseline;
|
||||
for (auto& fragment : line_box.fragments()) {
|
||||
auto const& font = fragment.layout_node().font();
|
||||
auto const line_height = fragment.layout_node().line_height();
|
||||
|
@ -196,7 +196,7 @@ void LineBuilder::update_last_line()
|
|||
|
||||
// The CSS specification calls this AD (A+D, Ascent + Descent).
|
||||
|
||||
float fragment_baseline = 0;
|
||||
CSSPixels fragment_baseline = 0;
|
||||
if (fragment.layout_node().is_text_node()) {
|
||||
fragment_baseline = font_metrics.ascent + half_leading;
|
||||
} else {
|
||||
|
@ -221,21 +221,21 @@ void LineBuilder::update_last_line()
|
|||
auto strut_top = m_current_y;
|
||||
auto strut_bottom = m_current_y + m_context.containing_block().line_height();
|
||||
|
||||
float uppermost_box_top = strut_top;
|
||||
float lowermost_box_bottom = strut_bottom;
|
||||
CSSPixels uppermost_box_top = strut_top;
|
||||
CSSPixels lowermost_box_bottom = strut_bottom;
|
||||
|
||||
for (size_t i = 0; i < line_box.fragments().size(); ++i) {
|
||||
auto& fragment = line_box.fragments()[i];
|
||||
|
||||
float new_fragment_x = roundf(x_offset + fragment.offset().x().value());
|
||||
float new_fragment_y = 0;
|
||||
CSSPixels new_fragment_x = round(x_offset + fragment.offset().x());
|
||||
CSSPixels new_fragment_y = 0;
|
||||
|
||||
auto y_value_for_alignment = [&](CSS::VerticalAlign vertical_align) {
|
||||
switch (vertical_align) {
|
||||
case CSS::VerticalAlign::Baseline:
|
||||
return m_current_y + line_box_baseline - fragment.baseline().value() + fragment.border_box_top().value();
|
||||
return m_current_y + line_box_baseline - fragment.baseline() + fragment.border_box_top();
|
||||
case CSS::VerticalAlign::Top:
|
||||
return m_current_y + fragment.border_box_top().value();
|
||||
return m_current_y + fragment.border_box_top();
|
||||
case CSS::VerticalAlign::Middle:
|
||||
case CSS::VerticalAlign::Bottom:
|
||||
case CSS::VerticalAlign::Sub:
|
||||
|
@ -243,7 +243,7 @@ void LineBuilder::update_last_line()
|
|||
case CSS::VerticalAlign::TextBottom:
|
||||
case CSS::VerticalAlign::TextTop:
|
||||
// FIXME: These are all 'baseline'
|
||||
return m_current_y + line_box_baseline - fragment.baseline().value() + fragment.border_box_top().value();
|
||||
return m_current_y + line_box_baseline - fragment.baseline() + fragment.border_box_top();
|
||||
}
|
||||
VERIFY_NOT_REACHED();
|
||||
};
|
||||
|
@ -258,23 +258,23 @@ void LineBuilder::update_last_line()
|
|||
}
|
||||
}
|
||||
|
||||
fragment.set_offset({ new_fragment_x, floorf(new_fragment_y) });
|
||||
fragment.set_offset({ new_fragment_x, floor(new_fragment_y) });
|
||||
|
||||
float top_of_inline_box = 0;
|
||||
float bottom_of_inline_box = 0;
|
||||
CSSPixels top_of_inline_box = 0;
|
||||
CSSPixels bottom_of_inline_box = 0;
|
||||
{
|
||||
// FIXME: Support inline-table elements.
|
||||
if (fragment.layout_node().is_replaced_box() || (fragment.layout_node().display().is_inline_outside() && !fragment.layout_node().display().is_flow_inside())) {
|
||||
auto const& fragment_box_state = m_layout_state.get(static_cast<Box const&>(fragment.layout_node()));
|
||||
top_of_inline_box = (fragment.offset().y() - fragment_box_state.margin_box_top()).value();
|
||||
bottom_of_inline_box = (fragment.offset().y() + fragment_box_state.content_height() + fragment_box_state.margin_box_bottom()).value();
|
||||
top_of_inline_box = (fragment.offset().y() - fragment_box_state.margin_box_top());
|
||||
bottom_of_inline_box = (fragment.offset().y() + fragment_box_state.content_height() + fragment_box_state.margin_box_bottom());
|
||||
} else {
|
||||
auto font_metrics = fragment.layout_node().font().pixel_metrics();
|
||||
auto typographic_height = font_metrics.ascent + font_metrics.descent;
|
||||
auto leading = fragment.layout_node().line_height() - typographic_height;
|
||||
auto half_leading = leading / 2;
|
||||
top_of_inline_box = (fragment.offset().y() + fragment.baseline() - font_metrics.ascent - half_leading).value();
|
||||
bottom_of_inline_box = (fragment.offset().y() + fragment.baseline() + font_metrics.descent + half_leading).value();
|
||||
top_of_inline_box = (fragment.offset().y() + fragment.baseline() - font_metrics.ascent - half_leading);
|
||||
bottom_of_inline_box = (fragment.offset().y() + fragment.baseline() + font_metrics.descent + half_leading);
|
||||
}
|
||||
if (auto length_percentage = fragment.layout_node().computed_values().vertical_align().template get_pointer<CSS::LengthPercentage>(); length_percentage && length_percentage->is_length())
|
||||
bottom_of_inline_box += length_percentage->length().to_px(fragment.layout_node());
|
||||
|
@ -306,7 +306,7 @@ void LineBuilder::recalculate_available_space()
|
|||
auto current_line_height = max(m_max_height_on_current_line, m_context.containing_block().line_height());
|
||||
auto available_at_top_of_line_box = m_context.available_space_for_line(m_current_y);
|
||||
auto available_at_bottom_of_line_box = m_context.available_space_for_line(m_current_y + current_line_height - 1);
|
||||
m_available_width_for_current_line = min(available_at_bottom_of_line_box, available_at_top_of_line_box).value();
|
||||
m_available_width_for_current_line = min(available_at_bottom_of_line_box, available_at_top_of_line_box);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -18,12 +18,12 @@ public:
|
|||
LineBuilder(InlineFormattingContext&, LayoutState&);
|
||||
~LineBuilder();
|
||||
|
||||
void break_line(Optional<float> next_item_width = {});
|
||||
void append_box(Box const&, float leading_size, float trailing_size, float leading_margin, float trailing_margin);
|
||||
void append_text_chunk(TextNode const&, size_t offset_in_node, size_t length_in_node, float leading_size, float trailing_size, float leading_margin, float trailing_margin, float content_width, float content_height);
|
||||
void break_line(Optional<CSSPixels> next_item_width = {});
|
||||
void append_box(Box const&, CSSPixels leading_size, CSSPixels trailing_size, CSSPixels leading_margin, CSSPixels trailing_margin);
|
||||
void append_text_chunk(TextNode const&, size_t offset_in_node, size_t length_in_node, CSSPixels leading_size, CSSPixels trailing_size, CSSPixels leading_margin, CSSPixels trailing_margin, CSSPixels content_width, CSSPixels content_height);
|
||||
|
||||
// Returns whether a line break occurred.
|
||||
bool break_if_needed(float next_item_width)
|
||||
bool break_if_needed(CSSPixels next_item_width)
|
||||
{
|
||||
if (should_break(next_item_width)) {
|
||||
break_line(next_item_width);
|
||||
|
@ -32,31 +32,31 @@ public:
|
|||
return false;
|
||||
}
|
||||
|
||||
float available_width_for_current_line() const { return m_available_width_for_current_line; }
|
||||
CSSPixels available_width_for_current_line() const { return m_available_width_for_current_line; }
|
||||
|
||||
void update_last_line();
|
||||
|
||||
void remove_last_line_if_empty();
|
||||
|
||||
float current_y() const { return m_current_y; }
|
||||
void set_current_y(float y) { m_current_y = y; }
|
||||
CSSPixels current_y() const { return m_current_y; }
|
||||
void set_current_y(CSSPixels y) { m_current_y = y; }
|
||||
|
||||
void recalculate_available_space();
|
||||
float y_for_float_to_be_inserted_here(Box const&);
|
||||
CSSPixels y_for_float_to_be_inserted_here(Box const&);
|
||||
|
||||
private:
|
||||
void begin_new_line(bool increment_y, bool is_first_break_in_sequence = true);
|
||||
|
||||
bool should_break(float next_item_width);
|
||||
bool should_break(CSSPixels next_item_width);
|
||||
|
||||
LineBox& ensure_last_line_box();
|
||||
|
||||
InlineFormattingContext& m_context;
|
||||
LayoutState& m_layout_state;
|
||||
LayoutState::UsedValues& m_containing_block_state;
|
||||
float m_available_width_for_current_line { 0 };
|
||||
float m_current_y { 0 };
|
||||
float m_max_height_on_current_line { 0 };
|
||||
CSSPixels m_available_width_for_current_line { 0 };
|
||||
CSSPixels m_current_y { 0 };
|
||||
CSSPixels m_max_height_on_current_line { 0 };
|
||||
|
||||
bool m_last_line_needs_update { false };
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue