Coverage Report

Created: 2025-11-02 07:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/serenity/Userland/Libraries/LibWeb/Geometry/DOMQuad.cpp
Line
Count
Source
1
/*
2
 * Copyright (c) 2023, Bastiaan van der Plaat <bastiaan.v.d.plaat@gmail.com>
3
 *
4
 * SPDX-License-Identifier: BSD-2-Clause
5
 */
6
7
#include <LibWeb/Bindings/DOMQuadPrototype.h>
8
#include <LibWeb/Bindings/Intrinsics.h>
9
#include <LibWeb/Geometry/DOMQuad.h>
10
11
namespace Web::Geometry {
12
13
JS_DEFINE_ALLOCATOR(DOMQuad);
14
15
JS::NonnullGCPtr<DOMQuad> DOMQuad::construct_impl(JS::Realm& realm, DOMPointInit const& p1, DOMPointInit const& p2, DOMPointInit const& p3, DOMPointInit const& p4)
16
0
{
17
0
    return realm.heap().allocate<DOMQuad>(realm, realm, p1, p2, p3, p4);
18
0
}
19
20
JS::NonnullGCPtr<DOMQuad> DOMQuad::create(JS::Realm& realm)
21
0
{
22
0
    return realm.heap().allocate<DOMQuad>(realm, realm);
23
0
}
24
25
DOMQuad::DOMQuad(JS::Realm& realm, DOMPointInit const& p1, DOMPointInit const& p2, DOMPointInit const& p3, DOMPointInit const& p4)
26
0
    : PlatformObject(realm)
27
0
    , m_p1(DOMPoint::from_point(realm.vm(), p1))
28
0
    , m_p2(DOMPoint::from_point(realm.vm(), p2))
29
0
    , m_p3(DOMPoint::from_point(realm.vm(), p3))
30
0
    , m_p4(DOMPoint::from_point(realm.vm(), p4))
31
0
{
32
0
}
33
34
DOMQuad::DOMQuad(JS::Realm& realm)
35
0
    : PlatformObject(realm)
36
0
    , m_p1(DOMPoint::create(realm))
37
0
    , m_p2(DOMPoint::create(realm))
38
0
    , m_p3(DOMPoint::create(realm))
39
0
    , m_p4(DOMPoint::create(realm))
40
0
{
41
0
}
42
43
0
DOMQuad::~DOMQuad() = default;
44
45
// https://drafts.fxtf.org/geometry/#dom-domquad-fromrect
46
JS::NonnullGCPtr<DOMQuad> DOMQuad::from_rect(JS::VM& vm, DOMRectInit const& other)
47
0
{
48
    // The fromRect(other) static method on DOMQuad must create a DOMQuad from the DOMRectInit dictionary other.
49
0
    return construct_impl(*vm.current_realm(), { other.x, other.y },
50
0
        { other.x + other.width, other.y },
51
0
        { other.x + other.width, other.y + other.height },
52
0
        { other.x, other.y + other.height });
53
0
}
54
55
// https://drafts.fxtf.org/geometry/#dom-domquad-fromquad
56
JS::NonnullGCPtr<DOMQuad> DOMQuad::from_quad(JS::VM& vm, DOMQuadInit const& other)
57
0
{
58
    // The fromQuad(other) static method on DOMQuad must create a DOMQuad from the DOMQuadInit dictionary other.
59
0
    return construct_impl(*vm.current_realm(), other.p1, other.p2, other.p3, other.p4);
60
0
}
61
62
// https://drafts.fxtf.org/geometry/#dom-domquad-getbounds
63
JS::NonnullGCPtr<DOMRect> DOMQuad::get_bounds() const
64
0
{
65
    // The NaN-safe minimum of a non-empty list of unrestricted double values is NaN if any member of the list is NaN, or the minimum of the list otherwise.
66
0
    auto nan_safe_minimum = [](double a, double b, double c, double d) -> double {
67
0
        if (isnan(a) || isnan(b) || isnan(c) || isnan(d))
68
0
            return NAN;
69
0
        return min(a, min(b, min(c, d)));
70
0
    };
71
72
    // Analogously, the NaN-safe maximum of a non-empty list of unrestricted double values is NaN if any member of the list is NaN, or the maximum of the list otherwise.
73
0
    auto nan_safe_maximum = [](double a, double b, double c, double d) -> double {
74
0
        if (isnan(a) || isnan(b) || isnan(c) || isnan(d))
75
0
            return NAN;
76
0
        return max(a, max(b, max(c, d)));
77
0
    };
78
79
    // 1. Let bounds be a DOMRect object.
80
0
    auto bounds = DOMRect::create(realm(), {});
81
82
    // 2. Let left be the NaN-safe minimum of point 1’s x coordinate, point 2’s x coordinate, point 3’s x coordinate and point 4’s x coordinate.
83
0
    auto left = nan_safe_minimum(m_p1->x(), m_p2->x(), m_p3->x(), m_p4->x());
84
85
    // 3. Let top be the NaN-safe minimum of point 1’s y coordinate, point 2’s y coordinate, point 3’s y coordinate and point 4’s y coordinate.
86
0
    auto top = nan_safe_minimum(m_p1->y(), m_p2->y(), m_p3->y(), m_p4->y());
87
88
    // 4. Let right be the NaN-safe maximum of point 1’s x coordinate, point 2’s x coordinate, point 3’s x coordinate and point 4’s x coordinate.
89
0
    auto right = nan_safe_maximum(m_p1->x(), m_p2->x(), m_p3->x(), m_p4->x());
90
91
    // 5. Let bottom be the NaN-safe maximum of point 1’s y coordinate, point 2’s y coordinate, point 3’s y coordinate and point 4’s y coordinate.
92
0
    auto bottom = nan_safe_maximum(m_p1->y(), m_p2->y(), m_p3->y(), m_p4->y());
93
94
    // 6. Set x coordinate of bounds to left, y coordinate of bounds to top, width dimension of bounds to right - left and height dimension of bounds to bottom - top.
95
0
    bounds->set_x(left);
96
0
    bounds->set_y(top);
97
0
    bounds->set_width(right - left);
98
0
    bounds->set_height(bottom - top);
99
100
    // 7. Return bounds.
101
0
    return bounds;
102
0
}
103
104
// https://drafts.fxtf.org/geometry/#structured-serialization
105
WebIDL::ExceptionOr<void> DOMQuad::serialization_steps(HTML::SerializationRecord& serialzied, bool for_storage, HTML::SerializationMemory& memory)
106
0
{
107
0
    auto& vm = this->vm();
108
    // 1. Set serialized.[[P1]] to the sub-serialization of value’s point 1.
109
0
    serialzied.extend(TRY(HTML::structured_serialize_internal(vm, m_p1, for_storage, memory)));
110
    // 2. Set serialized.[[P2]] to the sub-serialization of value’s point 2.
111
0
    serialzied.extend(TRY(HTML::structured_serialize_internal(vm, m_p2, for_storage, memory)));
112
    // 3. Set serialized.[[P3]] to the sub-serialization of value’s point 3.
113
0
    serialzied.extend(TRY(HTML::structured_serialize_internal(vm, m_p3, for_storage, memory)));
114
    // 4. Set serialized.[[P4]] to the sub-serialization of value’s point 4.
115
0
    serialzied.extend(TRY(HTML::structured_serialize_internal(vm, m_p4, for_storage, memory)));
116
117
0
    return {};
118
0
}
119
120
// https://drafts.fxtf.org/geometry/#structured-serialization
121
WebIDL::ExceptionOr<void> DOMQuad::deserialization_steps(ReadonlySpan<u32> const& serialized, size_t& position, HTML::DeserializationMemory& memory)
122
0
{
123
0
    auto& realm = this->realm();
124
    // 1. Set value’s point 1 to the sub-deserialization of serialized.[[P1]].
125
0
    auto deserialized_record = TRY(HTML::structured_deserialize_internal(vm(), serialized, realm, memory, position));
126
0
    if (deserialized_record.value.has_value() && is<DOMPoint>(deserialized_record.value.value().as_object()))
127
0
        m_p1 = dynamic_cast<DOMPoint&>(deserialized_record.value.release_value().as_object());
128
0
    position = deserialized_record.position;
129
130
    // 2. Set value’s point 2 to the sub-deserialization of serialized.[[P2]].
131
0
    deserialized_record = TRY(HTML::structured_deserialize_internal(vm(), serialized, realm, memory, position));
132
0
    if (deserialized_record.value.has_value() && is<DOMPoint>(deserialized_record.value.value().as_object()))
133
0
        m_p2 = dynamic_cast<DOMPoint&>(deserialized_record.value.release_value().as_object());
134
0
    position = deserialized_record.position;
135
136
    // 3. Set value’s point 3 to the sub-deserialization of serialized.[[P3]].
137
0
    deserialized_record = TRY(HTML::structured_deserialize_internal(vm(), serialized, realm, memory, position));
138
0
    if (deserialized_record.value.has_value() && is<DOMPoint>(deserialized_record.value.value().as_object()))
139
0
        m_p3 = dynamic_cast<DOMPoint&>(deserialized_record.value.release_value().as_object());
140
0
    position = deserialized_record.position;
141
142
    // 4. Set value’s point 4 to the sub-deserialization of serialized.[[P4]].
143
0
    deserialized_record = TRY(HTML::structured_deserialize_internal(vm(), serialized, realm, memory, position));
144
0
    if (deserialized_record.value.has_value() && is<DOMPoint>(deserialized_record.value.value().as_object()))
145
0
        m_p4 = dynamic_cast<DOMPoint&>(deserialized_record.value.release_value().as_object());
146
0
    position = deserialized_record.position;
147
148
0
    return {};
149
0
}
150
151
void DOMQuad::initialize(JS::Realm& realm)
152
0
{
153
0
    Base::initialize(realm);
154
0
    WEB_SET_PROTOTYPE_FOR_INTERFACE(DOMQuad);
155
0
}
156
157
void DOMQuad::visit_edges(Cell::Visitor& visitor)
158
0
{
159
0
    Base::visit_edges(visitor);
160
0
    visitor.visit(m_p1);
161
0
    visitor.visit(m_p2);
162
0
    visitor.visit(m_p3);
163
0
    visitor.visit(m_p4);
164
0
}
165
166
}