diff --git a/Tests/LibWeb/Layout/expected/writing-modes-vertical-rl.txt b/Tests/LibWeb/Layout/expected/writing-modes-vertical-rl.txt new file mode 100644 index 00000000000..6e9480a83ce --- /dev/null +++ b/Tests/LibWeb/Layout/expected/writing-modes-vertical-rl.txt @@ -0,0 +1,11 @@ +Viewport <#document> at (0,0) content-size 800x600 children: not-inline + BlockContainer at (0,0) content-size 800x186.265625 [BFC] children: not-inline + BlockContainer at (8,8) content-size 784x170.265625 children: inline + frag 0 from TextNode start: 0, length: 24, rect: [775,8 17x170.265625] baseline: 13.296875 + "Well, hello friends! :-)" + TextNode <#text> + +ViewportPaintable (Viewport<#document>) [0,0 800x600] + PaintableWithLines (BlockContainer) [0,0 800x186.265625] + PaintableWithLines (BlockContainer) [8,8 784x170.265625] + TextPaintable (TextNode<#text>) diff --git a/Tests/LibWeb/Layout/input/writing-modes-vertical-rl.html b/Tests/LibWeb/Layout/input/writing-modes-vertical-rl.html new file mode 100644 index 00000000000..f42b13d8162 --- /dev/null +++ b/Tests/LibWeb/Layout/input/writing-modes-vertical-rl.html @@ -0,0 +1,6 @@ + +Well, hello friends! :-) diff --git a/Userland/Libraries/LibWeb/Layout/InlineFormattingContext.cpp b/Userland/Libraries/LibWeb/Layout/InlineFormattingContext.cpp index 6f2e686d56e..3204f2f3de1 100644 --- a/Userland/Libraries/LibWeb/Layout/InlineFormattingContext.cpp +++ b/Userland/Libraries/LibWeb/Layout/InlineFormattingContext.cpp @@ -250,9 +250,10 @@ void InlineFormattingContext::generate_line_boxes() line_boxes.clear_with_capacity(); auto direction = m_context_box->computed_values().direction(); + auto writing_mode = m_context_box->computed_values().writing_mode(); InlineLevelIterator iterator(*this, m_state, containing_block(), m_containing_block_used_values, m_layout_mode); - LineBuilder line_builder(*this, m_state, m_containing_block_used_values, direction); + LineBuilder line_builder(*this, m_state, m_containing_block_used_values, direction, writing_mode); // NOTE: When we ignore collapsible whitespace chunks at the start of a line, // we have to remember how much start margin that chunk had in the inline diff --git a/Userland/Libraries/LibWeb/Layout/LineBox.cpp b/Userland/Libraries/LibWeb/Layout/LineBox.cpp index 4a5823b3076..a5bcff175ca 100644 --- a/Userland/Libraries/LibWeb/Layout/LineBox.cpp +++ b/Userland/Libraries/LibWeb/Layout/LineBox.cpp @@ -16,6 +16,27 @@ namespace Web::Layout { +CSSPixels LineBox::width() const +{ + if (m_writing_mode != CSS::WritingMode::HorizontalTb) + return m_block_length; + return m_inline_length; +} + +CSSPixels LineBox::height() const +{ + if (m_writing_mode != CSS::WritingMode::HorizontalTb) + return m_inline_length; + return m_block_length; +} + +CSSPixels LineBox::bottom() const +{ + if (m_writing_mode != CSS::WritingMode::HorizontalTb) + return m_inline_length; + return m_bottom; +} + 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, RefPtr glyph_run) { bool text_align_is_justify = layout_node.computed_values().text_align() == CSS::TextAlign::Justify; @@ -27,7 +48,7 @@ void LineBox::add_fragment(Node const& layout_node, int start, int length, CSSPi } else { CSSPixels inline_offset = leading_margin + leading_size + m_inline_length; CSSPixels block_offset = 0; - m_fragments.append(LineBoxFragment { layout_node, start, length, inline_offset, block_offset, content_width, content_height, border_box_top, m_direction, move(glyph_run) }); + m_fragments.append(LineBoxFragment { layout_node, start, length, inline_offset, block_offset, content_width, content_height, border_box_top, m_direction, m_writing_mode, move(glyph_run) }); } m_inline_length += leading_margin + leading_size + content_width + trailing_size + trailing_margin; m_block_length = max(m_block_length, content_height + border_box_top + border_box_bottom); diff --git a/Userland/Libraries/LibWeb/Layout/LineBox.h b/Userland/Libraries/LibWeb/Layout/LineBox.h index 7d063fed4b6..0f22a5e39d6 100644 --- a/Userland/Libraries/LibWeb/Layout/LineBox.h +++ b/Userland/Libraries/LibWeb/Layout/LineBox.h @@ -13,14 +13,15 @@ namespace Web::Layout { class LineBox { public: - LineBox(CSS::Direction direction) + LineBox(CSS::Direction direction, CSS::WritingMode writing_mode) : m_direction(direction) + , m_writing_mode(writing_mode) { } - CSSPixels width() const { return m_inline_length; } - CSSPixels height() const { return m_block_length; } - CSSPixels bottom() const { return m_bottom; } + CSSPixels width() const; + CSSPixels height() const; + CSSPixels bottom() const; CSSPixels inline_length() const { return m_inline_length; } CSSPixels block_length() const { return m_block_length; } @@ -49,6 +50,7 @@ private: CSSPixels m_bottom { 0 }; CSSPixels m_baseline { 0 }; CSS::Direction m_direction { CSS::Direction::Ltr }; + CSS::WritingMode m_writing_mode { CSS::WritingMode::HorizontalTb }; // The amount of available width that was originally available when creating this line box. Used for text justification. AvailableSize m_original_available_width { AvailableSize::make_indefinite() }; diff --git a/Userland/Libraries/LibWeb/Layout/LineBoxFragment.cpp b/Userland/Libraries/LibWeb/Layout/LineBoxFragment.cpp index 3002c565735..91ca4342d5b 100644 --- a/Userland/Libraries/LibWeb/Layout/LineBoxFragment.cpp +++ b/Userland/Libraries/LibWeb/Layout/LineBoxFragment.cpp @@ -13,7 +13,7 @@ namespace Web::Layout { -LineBoxFragment::LineBoxFragment(Node const& layout_node, int start, int length, CSSPixels inline_offset, CSSPixels block_offset, CSSPixels inline_length, CSSPixels block_length, CSSPixels border_box_top, CSS::Direction direction, RefPtr glyph_run) +LineBoxFragment::LineBoxFragment(Node const& layout_node, int start, int length, CSSPixels inline_offset, CSSPixels block_offset, CSSPixels inline_length, CSSPixels block_length, CSSPixels border_box_top, CSS::Direction direction, CSS::WritingMode writing_mode, RefPtr glyph_run) : m_layout_node(layout_node) , m_start(start) , m_length(length) @@ -23,6 +23,7 @@ LineBoxFragment::LineBoxFragment(Node const& layout_node, int start, int length, , m_block_length(block_length) , m_border_box_top(border_box_top) , m_direction(direction) + , m_writing_mode(writing_mode) , m_glyph_run(move(glyph_run)) { if (m_glyph_run) { @@ -34,11 +35,15 @@ LineBoxFragment::LineBoxFragment(Node const& layout_node, int start, int length, CSSPixelPoint LineBoxFragment::offset() const { + if (m_writing_mode != CSS::WritingMode::HorizontalTb) + return { m_block_offset, m_inline_offset }; return { m_inline_offset, m_block_offset }; } CSSPixelSize LineBoxFragment::size() const { + if (m_writing_mode != CSS::WritingMode::HorizontalTb) + return { m_block_length, m_inline_length }; return { m_inline_length, m_block_length }; } diff --git a/Userland/Libraries/LibWeb/Layout/LineBoxFragment.h b/Userland/Libraries/LibWeb/Layout/LineBoxFragment.h index 32a7e7a8916..01e75c707e8 100644 --- a/Userland/Libraries/LibWeb/Layout/LineBoxFragment.h +++ b/Userland/Libraries/LibWeb/Layout/LineBoxFragment.h @@ -19,7 +19,7 @@ class LineBoxFragment { friend class LineBox; public: - LineBoxFragment(Node const& layout_node, int start, int length, CSSPixels inline_offset, CSSPixels block_offset, CSSPixels inline_length, CSSPixels block_length, CSSPixels border_box_top, CSS::Direction, RefPtr); + LineBoxFragment(Node const& layout_node, int start, int length, CSSPixels inline_offset, CSSPixels block_offset, CSSPixels inline_length, CSSPixels block_length, CSSPixels border_box_top, CSS::Direction, CSS::WritingMode, RefPtr); Node const& layout_node() const { return m_layout_node; } int start() const { return m_start; } @@ -70,6 +70,7 @@ private: CSSPixels m_border_box_top { 0 }; CSSPixels m_baseline { 0 }; CSS::Direction m_direction { CSS::Direction::Ltr }; + CSS::WritingMode m_writing_mode { CSS::WritingMode::HorizontalTb }; RefPtr m_glyph_run; float m_insert_position { 0 }; diff --git a/Userland/Libraries/LibWeb/Layout/LineBuilder.cpp b/Userland/Libraries/LibWeb/Layout/LineBuilder.cpp index 3afb82b570c..8d3f9933d76 100644 --- a/Userland/Libraries/LibWeb/Layout/LineBuilder.cpp +++ b/Userland/Libraries/LibWeb/Layout/LineBuilder.cpp @@ -10,11 +10,12 @@ namespace Web::Layout { -LineBuilder::LineBuilder(InlineFormattingContext& context, LayoutState& layout_state, LayoutState::UsedValues& containing_block_used_values, CSS::Direction direction) +LineBuilder::LineBuilder(InlineFormattingContext& context, LayoutState& layout_state, LayoutState::UsedValues& containing_block_used_values, CSS::Direction direction, CSS::WritingMode writing_mode) : m_context(context) , m_layout_state(layout_state) , m_containing_block_used_values(containing_block_used_values) , m_direction(direction) + , m_writing_mode(writing_mode) { m_text_indent = m_context.containing_block().computed_values().text_indent().to_px(m_context.containing_block(), m_containing_block_used_values.content_width()); begin_new_line(false); @@ -38,7 +39,7 @@ void LineBuilder::break_line(ForcedBreak forced_break, Optional next_ size_t break_count = 0; bool floats_intrude_at_current_y = false; do { - m_containing_block_used_values.line_boxes.append(LineBox(m_direction)); + m_containing_block_used_values.line_boxes.append(LineBox(m_direction, m_writing_mode)); begin_new_line(true, break_count == 0); break_count++; floats_intrude_at_current_y = m_context.any_floats_intrude_at_block_offset(m_current_block_offset); @@ -83,7 +84,7 @@ LineBox& LineBuilder::ensure_last_line_box() { auto& line_boxes = m_containing_block_used_values.line_boxes; if (line_boxes.is_empty()) - line_boxes.append(LineBox(m_direction)); + line_boxes.append(LineBox(m_direction, m_writing_mode)); return line_boxes.last(); } @@ -179,6 +180,10 @@ void LineBuilder::update_last_line() // FIXME: Respect inline direction. CSSPixels excess_inline_space = m_available_width_for_current_line.to_px_or_zero() - line_box.inline_length(); + if (m_writing_mode != CSS::WritingMode::HorizontalTb) { + block_offset = m_available_width_for_current_line.to_px_or_zero() - line_box.block_length(); + } + // If (after justification, if any) the inline contents of a line box are too long to fit within it, // then the contents are start-aligned: any content that doesn't fit overflows the line box’s end edge. if (excess_inline_space > 0) { diff --git a/Userland/Libraries/LibWeb/Layout/LineBuilder.h b/Userland/Libraries/LibWeb/Layout/LineBuilder.h index 8c96ed86da9..26525e6d9bb 100644 --- a/Userland/Libraries/LibWeb/Layout/LineBuilder.h +++ b/Userland/Libraries/LibWeb/Layout/LineBuilder.h @@ -15,7 +15,7 @@ class LineBuilder { AK_MAKE_NONMOVABLE(LineBuilder); public: - LineBuilder(InlineFormattingContext&, LayoutState&, LayoutState::UsedValues& containing_block_used_values, CSS::Direction); + LineBuilder(InlineFormattingContext&, LayoutState&, LayoutState::UsedValues& containing_block_used_values, CSS::Direction, CSS::WritingMode); ~LineBuilder(); enum class ForcedBreak { @@ -64,6 +64,7 @@ private: CSSPixels m_max_height_on_current_line { 0 }; CSSPixels m_text_indent { 0 }; CSS::Direction m_direction { CSS::Direction::Ltr }; + CSS::WritingMode m_writing_mode { CSS::WritingMode::HorizontalTb }; bool m_last_line_needs_update { false }; };