Serenity Operating System
1/*
2 * Copyright (c) 2022, Andreas Kling <kling@serenityos.org>
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7#pragma once
8
9#include <AK/Noncopyable.h>
10#include <LibWeb/Layout/BlockContainer.h>
11#include <LibWeb/Layout/InlineNode.h>
12#include <LibWeb/Layout/LayoutState.h>
13#include <LibWeb/Layout/TextNode.h>
14
15namespace Web::Layout {
16
17// This class iterates over all the inline-level objects within an inline formatting context.
18// By repeatedly calling next() with the remaining available width on the current line,
19// it returns an "Item" representing the next piece of inline-level content to be placed on the line.
20class InlineLevelIterator {
21 AK_MAKE_NONCOPYABLE(InlineLevelIterator);
22 AK_MAKE_NONMOVABLE(InlineLevelIterator);
23
24public:
25 struct Item {
26 enum class Type {
27 Text,
28 Element,
29 ForcedBreak,
30 AbsolutelyPositionedElement,
31 FloatingElement,
32 };
33 Type type {};
34 Layout::Node const* node { nullptr };
35 size_t offset_in_node { 0 };
36 size_t length_in_node { 0 };
37 CSSPixels width { 0.0f };
38 CSSPixels padding_start { 0.0f };
39 CSSPixels padding_end { 0.0f };
40 CSSPixels border_start { 0.0f };
41 CSSPixels border_end { 0.0f };
42 CSSPixels margin_start { 0.0f };
43 CSSPixels margin_end { 0.0f };
44 bool is_collapsible_whitespace { false };
45
46 CSSPixels border_box_width() const
47 {
48 return border_start + padding_start + width + padding_end + border_end;
49 }
50 };
51
52 InlineLevelIterator(Layout::InlineFormattingContext&, LayoutState&, Layout::BlockContainer const&, LayoutMode);
53
54 Optional<Item> next(CSSPixels available_width);
55
56private:
57 void skip_to_next();
58 void compute_next();
59
60 void enter_text_node(Layout::TextNode const&);
61
62 void enter_node_with_box_model_metrics(Layout::NodeWithStyleAndBoxModelMetrics const&);
63 void exit_node_with_box_model_metrics();
64
65 void add_extra_box_model_metrics_to_item(Item&, bool add_leading_metrics, bool add_trailing_metrics);
66
67 Layout::Node const* next_inline_node_in_pre_order(Layout::Node const& current, Layout::Node const* stay_within);
68
69 Layout::InlineFormattingContext& m_inline_formatting_context;
70 Layout::LayoutState& m_layout_state;
71 Layout::BlockContainer const& m_container;
72 Layout::LayoutState::UsedValues const& m_container_state;
73 Layout::Node const* m_current_node { nullptr };
74 Layout::Node const* m_next_node { nullptr };
75 LayoutMode const m_layout_mode;
76
77 struct TextNodeContext {
78 bool do_collapse {};
79 bool do_wrap_lines {};
80 bool do_respect_linebreaks {};
81 bool is_first_chunk {};
82 bool is_last_chunk {};
83 TextNode::ChunkIterator chunk_iterator;
84 Optional<TextNode::Chunk> next_chunk {};
85 };
86
87 Optional<TextNodeContext> m_text_node_context;
88
89 struct ExtraBoxMetrics {
90 CSSPixels margin { 0 };
91 CSSPixels border { 0 };
92 CSSPixels padding { 0 };
93 };
94
95 Optional<ExtraBoxMetrics> m_extra_leading_metrics;
96 Optional<ExtraBoxMetrics> m_extra_trailing_metrics;
97
98 Vector<NodeWithStyleAndBoxModelMetrics const&> m_box_model_node_stack;
99};
100
101}