Coverage Report

Created: 2026-09-26 06:49

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}