/src/serenity/Userland/Libraries/LibWeb/Layout/LineBoxFragment.cpp
Line | Count | Source |
1 | | /* |
2 | | * Copyright (c) 2018-2023, Andreas Kling <kling@serenityos.org> |
3 | | * |
4 | | * SPDX-License-Identifier: BSD-2-Clause |
5 | | */ |
6 | | |
7 | | #include <AK/Utf8View.h> |
8 | | #include <LibWeb/DOM/Range.h> |
9 | | #include <LibWeb/Layout/LayoutState.h> |
10 | | #include <LibWeb/Layout/Viewport.h> |
11 | | #include <ctype.h> |
12 | | |
13 | | namespace Web::Layout { |
14 | | |
15 | | LineBoxFragment::LineBoxFragment(Node const& layout_node, int start, int length, CSSPixelPoint offset, CSSPixelSize size, CSSPixels border_box_top, CSS::Direction direction, RefPtr<Gfx::GlyphRun> glyph_run) |
16 | 0 | : m_layout_node(layout_node) |
17 | 0 | , m_start(start) |
18 | 0 | , m_length(length) |
19 | 0 | , m_offset(offset) |
20 | 0 | , m_size(size) |
21 | 0 | , m_border_box_top(border_box_top) |
22 | 0 | , m_direction(direction) |
23 | 0 | , m_glyph_run(move(glyph_run)) |
24 | 0 | { |
25 | 0 | if (m_glyph_run) { |
26 | 0 | m_current_insert_direction = resolve_glyph_run_direction(m_glyph_run->text_type()); |
27 | 0 | if (m_direction == CSS::Direction::Rtl) |
28 | 0 | m_insert_position = m_size.width().to_float(); |
29 | 0 | } |
30 | 0 | } |
31 | | |
32 | | bool LineBoxFragment::ends_in_whitespace() const |
33 | 0 | { |
34 | 0 | auto text = this->text(); |
35 | 0 | if (text.is_empty()) |
36 | 0 | return false; |
37 | 0 | return isspace(text[text.length() - 1]); |
38 | 0 | } |
39 | | |
40 | | bool LineBoxFragment::is_justifiable_whitespace() const |
41 | 0 | { |
42 | 0 | return text() == " "; |
43 | 0 | } |
44 | | |
45 | | StringView LineBoxFragment::text() const |
46 | 0 | { |
47 | 0 | if (!is<TextNode>(layout_node())) |
48 | 0 | return {}; |
49 | 0 | return verify_cast<TextNode>(layout_node()).text_for_rendering().bytes_as_string_view().substring_view(m_start, m_length); |
50 | 0 | } |
51 | | |
52 | | CSSPixelRect const LineBoxFragment::absolute_rect() const |
53 | 0 | { |
54 | 0 | CSSPixelRect rect { {}, size() }; |
55 | 0 | rect.set_location(m_layout_node->containing_block()->paintable_box()->absolute_position()); |
56 | 0 | rect.translate_by(offset()); |
57 | 0 | return rect; |
58 | 0 | } |
59 | | |
60 | | bool LineBoxFragment::is_atomic_inline() const |
61 | 0 | { |
62 | 0 | return layout_node().is_replaced_box() || (layout_node().display().is_inline_outside() && !layout_node().display().is_flow_inside()); |
63 | 0 | } |
64 | | |
65 | | CSS::Direction LineBoxFragment::resolve_glyph_run_direction(Gfx::GlyphRun::TextType text_type) const |
66 | 0 | { |
67 | 0 | switch (text_type) { |
68 | 0 | case Gfx::GlyphRun::TextType::Common: |
69 | 0 | case Gfx::GlyphRun::TextType::ContextDependent: |
70 | 0 | case Gfx::GlyphRun::TextType::EndPadding: |
71 | 0 | return m_direction; |
72 | 0 | case Gfx::GlyphRun::TextType::Ltr: |
73 | 0 | return CSS::Direction::Ltr; |
74 | 0 | case Gfx::GlyphRun::TextType::Rtl: |
75 | 0 | return CSS::Direction::Rtl; |
76 | 0 | default: |
77 | 0 | VERIFY_NOT_REACHED(); |
78 | 0 | } |
79 | 0 | } |
80 | | |
81 | | void LineBoxFragment::append_glyph_run(RefPtr<Gfx::GlyphRun> const& glyph_run, CSSPixels run_width) |
82 | 0 | { |
83 | 0 | switch (m_direction) { |
84 | 0 | case CSS::Direction::Ltr: |
85 | 0 | append_glyph_run_ltr(glyph_run, run_width); |
86 | 0 | break; |
87 | 0 | case CSS::Direction::Rtl: |
88 | 0 | append_glyph_run_rtl(glyph_run, run_width); |
89 | 0 | break; |
90 | 0 | } |
91 | 0 | } |
92 | | |
93 | | void LineBoxFragment::append_glyph_run_ltr(RefPtr<Gfx::GlyphRun> const& glyph_run, CSSPixels run_width) |
94 | 0 | { |
95 | 0 | auto run_direction = resolve_glyph_run_direction(glyph_run->text_type()); |
96 | |
|
97 | 0 | if (m_current_insert_direction != run_direction) { |
98 | 0 | if (run_direction == CSS::Direction::Rtl) |
99 | 0 | m_insert_position = width().to_float(); |
100 | 0 | m_current_insert_direction = run_direction; |
101 | 0 | } |
102 | |
|
103 | 0 | switch (run_direction) { |
104 | 0 | case CSS::Direction::Ltr: |
105 | 0 | for (auto& glyph : glyph_run->glyphs()) { |
106 | 0 | glyph.visit([&](auto& glyph) { glyph.position.translate_by(width().to_float(), 0); });Unexecuted instantiation: LineBoxFragment.cpp:auto Web::Layout::LineBoxFragment::append_glyph_run_ltr(AK::RefPtr<Gfx::GlyphRun> const&, Web::CSSPixels)::$_0::operator()<Gfx::DrawGlyph>(Gfx::DrawGlyph&) const Unexecuted instantiation: LineBoxFragment.cpp:auto Web::Layout::LineBoxFragment::append_glyph_run_ltr(AK::RefPtr<Gfx::GlyphRun> const&, Web::CSSPixels)::$_0::operator()<Gfx::DrawEmoji>(Gfx::DrawEmoji&) const |
107 | 0 | m_glyph_run->append(glyph); |
108 | 0 | } |
109 | 0 | break; |
110 | 0 | case CSS::Direction::Rtl: |
111 | 0 | for (auto& glyph : m_glyph_run->glyphs()) { |
112 | 0 | glyph.visit([&](auto& glyph) { |
113 | 0 | if (glyph.position.x() >= m_insert_position) |
114 | 0 | glyph.position.translate_by(run_width.to_float(), 0); |
115 | 0 | }); Unexecuted instantiation: LineBoxFragment.cpp:auto Web::Layout::LineBoxFragment::append_glyph_run_ltr(AK::RefPtr<Gfx::GlyphRun> const&, Web::CSSPixels)::$_1::operator()<Gfx::DrawGlyph>(Gfx::DrawGlyph&) const Unexecuted instantiation: LineBoxFragment.cpp:auto Web::Layout::LineBoxFragment::append_glyph_run_ltr(AK::RefPtr<Gfx::GlyphRun> const&, Web::CSSPixels)::$_1::operator()<Gfx::DrawEmoji>(Gfx::DrawEmoji&) const |
116 | 0 | } |
117 | 0 | for (auto& glyph : glyph_run->glyphs()) { |
118 | 0 | glyph.visit([&](auto& glyph) { glyph.position.translate_by(m_insert_position, 0); });Unexecuted instantiation: LineBoxFragment.cpp:auto Web::Layout::LineBoxFragment::append_glyph_run_ltr(AK::RefPtr<Gfx::GlyphRun> const&, Web::CSSPixels)::$_2::operator()<Gfx::DrawGlyph>(Gfx::DrawGlyph&) const Unexecuted instantiation: LineBoxFragment.cpp:auto Web::Layout::LineBoxFragment::append_glyph_run_ltr(AK::RefPtr<Gfx::GlyphRun> const&, Web::CSSPixels)::$_2::operator()<Gfx::DrawEmoji>(Gfx::DrawEmoji&) const |
119 | 0 | m_glyph_run->append(glyph); |
120 | 0 | } |
121 | 0 | break; |
122 | 0 | } |
123 | | |
124 | 0 | m_size.set_width(width() + run_width); |
125 | 0 | } |
126 | | |
127 | | void LineBoxFragment::append_glyph_run_rtl(RefPtr<Gfx::GlyphRun> const& glyph_run, CSSPixels run_width) |
128 | 0 | { |
129 | 0 | auto run_direction = resolve_glyph_run_direction(glyph_run->text_type()); |
130 | |
|
131 | 0 | if (m_current_insert_direction != run_direction) { |
132 | 0 | if (run_direction == CSS::Direction::Ltr) |
133 | 0 | m_insert_position = 0; |
134 | 0 | m_current_insert_direction = run_direction; |
135 | 0 | } |
136 | |
|
137 | 0 | switch (run_direction) { |
138 | 0 | case CSS::Direction::Ltr: |
139 | 0 | for (auto& glyph : m_glyph_run->glyphs()) { |
140 | 0 | glyph.visit([&](auto& glyph) { |
141 | 0 | if (glyph.position.x() >= m_insert_position) |
142 | 0 | glyph.position.translate_by(run_width.to_float(), 0); |
143 | 0 | }); Unexecuted instantiation: LineBoxFragment.cpp:auto Web::Layout::LineBoxFragment::append_glyph_run_rtl(AK::RefPtr<Gfx::GlyphRun> const&, Web::CSSPixels)::$_0::operator()<Gfx::DrawGlyph>(Gfx::DrawGlyph&) const Unexecuted instantiation: LineBoxFragment.cpp:auto Web::Layout::LineBoxFragment::append_glyph_run_rtl(AK::RefPtr<Gfx::GlyphRun> const&, Web::CSSPixels)::$_0::operator()<Gfx::DrawEmoji>(Gfx::DrawEmoji&) const |
144 | 0 | } |
145 | 0 | for (auto& glyph : glyph_run->glyphs()) { |
146 | 0 | glyph.visit([&](auto& glyph) { glyph.position.translate_by(m_insert_position, 0); });Unexecuted instantiation: LineBoxFragment.cpp:auto Web::Layout::LineBoxFragment::append_glyph_run_rtl(AK::RefPtr<Gfx::GlyphRun> const&, Web::CSSPixels)::$_1::operator()<Gfx::DrawGlyph>(Gfx::DrawGlyph&) const Unexecuted instantiation: LineBoxFragment.cpp:auto Web::Layout::LineBoxFragment::append_glyph_run_rtl(AK::RefPtr<Gfx::GlyphRun> const&, Web::CSSPixels)::$_1::operator()<Gfx::DrawEmoji>(Gfx::DrawEmoji&) const |
147 | 0 | m_glyph_run->append(glyph); |
148 | 0 | } |
149 | 0 | break; |
150 | 0 | case CSS::Direction::Rtl: |
151 | 0 | if (glyph_run->text_type() != Gfx::GlyphRun::TextType::EndPadding) { |
152 | 0 | for (auto& glyph : m_glyph_run->glyphs()) { |
153 | 0 | glyph.visit([&](auto& glyph) { glyph.position.translate_by(run_width.to_float(), 0); });Unexecuted instantiation: LineBoxFragment.cpp:auto Web::Layout::LineBoxFragment::append_glyph_run_rtl(AK::RefPtr<Gfx::GlyphRun> const&, Web::CSSPixels)::$_2::operator()<Gfx::DrawGlyph>(Gfx::DrawGlyph&) const Unexecuted instantiation: LineBoxFragment.cpp:auto Web::Layout::LineBoxFragment::append_glyph_run_rtl(AK::RefPtr<Gfx::GlyphRun> const&, Web::CSSPixels)::$_2::operator()<Gfx::DrawEmoji>(Gfx::DrawEmoji&) const |
154 | 0 | } |
155 | 0 | } |
156 | 0 | for (auto& glyph : glyph_run->glyphs()) { |
157 | 0 | m_glyph_run->append(glyph); |
158 | 0 | } |
159 | 0 | break; |
160 | 0 | } |
161 | | |
162 | 0 | m_size.set_width(width() + run_width); |
163 | 0 | m_insert_position += run_width.to_float(); |
164 | 0 | } |
165 | | |
166 | | } |