Coverage Report

Created: 2025-03-04 07:22

/src/serenity/Userland/Libraries/LibWeb/HTML/WebViewHints.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (c) 2024, Andrew Kaster <akaster@serenityos.org>
3
 *
4
 * SPDX-License-Identifier: BSD-2-Clause
5
 */
6
7
#include <LibIPC/Decoder.h>
8
#include <LibIPC/Encoder.h>
9
#include <LibWeb/HTML/Numbers.h>
10
#include <LibWeb/HTML/WebViewHints.h>
11
#include <LibWeb/Page/Page.h>
12
#include <LibWeb/PixelUnits.h>
13
14
namespace Web::HTML {
15
16
static void set_up_browsing_context_features(WebViewHints& target, TokenizedFeature::Map const& tokenized_features, Page const& page);
17
18
WebViewHints WebViewHints::from_tokenised_features(TokenizedFeature::Map const& tokenized_features, Page const& page)
19
0
{
20
0
    WebViewHints hints;
21
0
    hints.popup = check_if_a_popup_window_is_requested(tokenized_features) == TokenizedFeature::Popup::Yes;
22
0
    set_up_browsing_context_features(hints, tokenized_features, page);
23
0
    return hints;
24
0
}
25
26
// https://drafts.csswg.org/cssom-view/#set-up-browsing-context-features
27
static void set_up_browsing_context_features(WebViewHints& target, TokenizedFeature::Map const& tokenized_features, Page const& page)
28
0
{
29
    // 1. Let x be null.
30
0
    Optional<CSSPixels> x;
31
32
    // 2. Let y be null.
33
0
    Optional<CSSPixels> y;
34
35
    // 3. Let width be null.
36
0
    Optional<CSSPixels> width;
37
38
    // 4. Let height be null.
39
0
    Optional<CSSPixels> height;
40
41
0
    auto screen_rect = page.web_exposed_screen_area();
42
43
    // 5. If tokenizedFeatures["left"] exists:
44
0
    if (auto left = tokenized_features.get("left"sv); left.has_value()) {
45
        // 1. Set x to the result of invoking the rules for parsing integers on tokenizedFeatures["left"].
46
        // 2. If x is an error, set x to 0.
47
0
        x = parse_integer(*left).value_or(0);
48
49
        // 3. Optionally, clamp x in a user-agent-defined manner so that the window does not move outside the Web-exposed available screen area.
50
0
        x = min(*x, screen_rect.x());
51
52
        // 4. Optionally, move target’s window such that the window’s left edge is at the horizontal coordinate x relative
53
        //    to the left edge of the Web-exposed screen area, measured in CSS pixels of target. The positive axis is rightward.
54
        // Note: Handled in the UI process when creating the traversable navigable.
55
0
    }
56
57
    // 6. If tokenizedFeatures["top"] exists:
58
0
    if (auto top = tokenized_features.get("top"sv); top.has_value()) {
59
        // 1. Set y to the result of invoking the rules for parsing integers on tokenizedFeatures["top"].
60
        // 2. If y is an error, set y to 0.
61
0
        y = parse_integer(*top).value_or(0);
62
63
        // 3. Optionally, clamp y in a user-agent-defined manner so that the window does not move outside the Web-exposed available screen area.
64
0
        y = min(*y, screen_rect.y());
65
66
        // 4. Optionally, move target’s window such that the window’s top edge is at the vertical coordinate y relative
67
        //    to the top edge of the Web-exposed screen area, measured in CSS pixels of target. The positive axis is downward.
68
        // Note: Handled in the UI process when creating the traversable navigable.
69
0
    }
70
71
    // 7. If tokenizedFeatures["width"] exists:
72
0
    if (auto width_token = tokenized_features.get("width"sv); width_token.has_value()) {
73
        // 1. Set width to the result of invoking the rules for parsing integers on tokenizedFeatures["width"].
74
        // 2. If width is an error, set width to 0.
75
0
        width = parse_integer(*width_token).value_or(0);
76
77
        // 3. If width is not 0:
78
0
        if (width != 0) {
79
            // 1. Optionally, clamp width in a user-agent-defined manner so that the window does not get too small or bigger than the Web-exposed available screen area.
80
0
            width = clamp(*width, 100, screen_rect.width());
81
82
            // 2. Optionally, size target’s window by moving its right edge such that the distance between the left and right edges of the viewport are width CSS pixels of target.
83
            // 3. Optionally, move target’s window in a user-agent-defined manner so that it does not grow outside the Web-exposed available screen area.
84
            // Note: Handled in the UI process when creating the traversable navigable.
85
0
        }
86
0
    }
87
88
    // 8. If tokenizedFeatures["height"] exists:
89
0
    if (auto height_token = tokenized_features.get("height"sv); height_token.has_value()) {
90
        // 1. Set height to the result of invoking the rules for parsing integers on tokenizedFeatures["height"].
91
        // 2. If height is an error, set height to 0.
92
0
        height = parse_integer(*height_token).value_or(0);
93
94
        // 3. If height is not 0:
95
0
        if (height != 0) {
96
            // 1. Optionally, clamp height in a user-agent-defined manner so that the window does not get too small or bigger than the Web-exposed available screen area.
97
0
            height = clamp(*height, 100, screen_rect.height());
98
99
            // 2. Optionally, size target’s window by moving its bottom edge such that the distance between the top and bottom edges of the viewport are height CSS pixels of target.
100
            // 3. Optionally, move target’s window in a user-agent-defined manner so that it does not grow outside the Web-exposed available screen area.
101
            // Note: Handled in the UI process when creating the traversable navigable.
102
0
        }
103
0
    }
104
105
0
    auto scale = page.client().device_pixels_per_css_pixel();
106
107
0
    if (x.has_value()) {
108
        // Make sure we don't fly off the screen to the right
109
0
        if (x.value() + width.value_or(0) > screen_rect.width())
110
0
            x = screen_rect.width() - width.value_or(0);
111
0
        target.screen_x = x.value() / scale;
112
0
    }
113
114
0
    if (y.has_value()) {
115
        // Make sure we don't fly off the screen to the bottom
116
0
        if (y.value() + height.value_or(0) > screen_rect.height())
117
0
            y = screen_rect.height() - height.value_or(0);
118
0
        target.screen_y = y.value() / scale;
119
0
    }
120
121
0
    if (width.has_value()) {
122
0
        target.width = width.value() / scale;
123
0
    }
124
125
0
    if (height.has_value()) {
126
0
        target.height = height.value() / scale;
127
0
    }
128
0
}
129
130
}
131
132
namespace IPC {
133
134
template<>
135
ErrorOr<void> encode(Encoder& encoder, ::Web::HTML::WebViewHints const& data_holder)
136
0
{
137
0
    TRY(encoder.encode(data_holder.popup));
138
0
    TRY(encoder.encode(data_holder.width));
139
0
    TRY(encoder.encode(data_holder.height));
140
0
    TRY(encoder.encode(data_holder.screen_x));
141
0
    TRY(encoder.encode(data_holder.screen_y));
142
143
0
    return {};
144
0
}
145
146
template<>
147
ErrorOr<::Web::HTML::WebViewHints> decode(Decoder& decoder)
148
0
{
149
0
    auto popup = TRY(decoder.decode<bool>());
150
0
    auto width = TRY(decoder.decode<Optional<Web::DevicePixels>>());
151
0
    auto height = TRY(decoder.decode<Optional<Web::DevicePixels>>());
152
0
    auto screen_x = TRY(decoder.decode<Optional<Web::DevicePixels>>());
153
0
    auto screen_y = TRY(decoder.decode<Optional<Web::DevicePixels>>());
154
155
0
    return ::Web::HTML::WebViewHints {
156
0
        .popup = popup,
157
0
        .width = width,
158
0
        .height = height,
159
0
        .screen_x = screen_x,
160
0
        .screen_y = screen_y,
161
0
    };
162
0
}
163
164
}