1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-26 20:07:36 +00:00

LibWeb: Support inline-level padding and border properly

Here's roughly how this works:

- InlineLevelIterator keeps a nesting stack of inline-level nodes with
  box model metrics.
- When entering a node with box model metrics, we add them to the
  current "leading metrics".
- When exiting a node with box model metrics, we add them to the
  current "trailing metrics".
- Pending leading metrics are consumed by the first fragment added
  to the line.
- Pending trailing metrics are consumed by the last fragment added
  to the line.

Like before, the position of a line box fragment is the top left of its
content box. However, fragments are placed horizontally along the line
with space inserted for padding and border.

InlineNode::paint() now expands the content rect as appropriate when
painting background and borders.

Note that margins and margin collapsing is not yet implemented.

This makes the eyes on ACID2 horizontally centered. :^)
This commit is contained in:
Andreas Kling 2022-02-14 15:52:29 +01:00
parent 7d2a49eeb8
commit f2a917229a
8 changed files with 191 additions and 36 deletions

View file

@ -8,6 +8,7 @@
#include <AK/Noncopyable.h>
#include <LibWeb/Layout/BlockContainer.h>
#include <LibWeb/Layout/InlineNode.h>
#include <LibWeb/Layout/TextNode.h>
namespace Web::Layout {
@ -31,36 +32,66 @@ public:
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 };
bool should_force_break { false };
bool is_collapsible_whitespace { false };
float border_box_width() const
{
return border_start + padding_start + width + padding_end + border_end;
}
};
explicit InlineLevelIterator(Layout::BlockContainer& container, LayoutMode layout_mode)
: m_container(container)
, m_current_node(container.first_child())
, m_layout_mode(layout_mode)
{
}
InlineLevelIterator(Layout::InlineFormattingContext&, Layout::BlockContainer&, LayoutMode);
Optional<Item> next(float available_width);
private:
void skip_to_next();
void compute_next();
void enter_text_node(Layout::TextNode&, bool previous_is_empty_or_ends_in_whitespace);
void enter_node_with_box_model_metrics(Layout::NodeWithStyleAndBoxModelMetrics&);
void exit_node_with_box_model_metrics();
void add_extra_box_model_metrics_to_item(Item&, bool add_leading_metrics, bool add_trailing_metrics);
Layout::Node* next_inline_node_in_pre_order(Layout::Node& current, Layout::Node const* stay_within);
Layout::InlineFormattingContext& m_inline_formatting_context;
Layout::BlockContainer& m_container;
Layout::Node* m_current_node { nullptr };
Layout::Node* m_next_node { nullptr };
LayoutMode const m_layout_mode;
struct TextNodeContext {
bool do_collapse {};
bool do_wrap_lines {};
bool do_respect_linebreaks {};
bool is_first_chunk {};
bool is_last_chunk {};
TextNode::ChunkIterator chunk_iterator;
Optional<TextNode::Chunk> next_chunk {};
};
Optional<TextNodeContext> m_text_node_context;
struct ExtraBoxMetrics {
float margin { 0 };
float border { 0 };
float padding { 0 };
};
Optional<ExtraBoxMetrics> m_extra_leading_metrics;
Optional<ExtraBoxMetrics> m_extra_trailing_metrics;
Vector<NodeWithStyleAndBoxModelMetrics&> m_box_model_node_stack;
};
}