mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-09-06 09:36:08 +00:00
LibWeb: Parse TokenizedFeatures from window.open
This commit is contained in:
parent
e2d50dc5dd
commit
46e00a8f5e
Notes:
sideshowbarker
2024-07-16 22:14:49 +09:00
Author: https://github.com/ADKaster
Commit: 46e00a8f5e
Pull-request: https://github.com/SerenityOS/serenity/pull/24477
Reviewed-by: https://github.com/trflynn89
5 changed files with 136 additions and 15 deletions
|
@ -335,7 +335,7 @@ void Navigable::set_ongoing_navigation(Variant<Empty, Traversal, String> ongoing
|
|||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/document-sequences.html#the-rules-for-choosing-a-navigable
|
||||
Navigable::ChosenNavigable Navigable::choose_a_navigable(StringView name, TokenizedFeature::NoOpener no_opener, ActivateTab activate_tab)
|
||||
Navigable::ChosenNavigable Navigable::choose_a_navigable(StringView name, TokenizedFeature::NoOpener no_opener, ActivateTab activate_tab, Optional<TokenizedFeature::Map const&> window_features)
|
||||
{
|
||||
// NOTE: Implementation for step 7 here.
|
||||
JS::GCPtr<Navigable> same_name_navigable = nullptr;
|
||||
|
@ -442,12 +442,8 @@ Navigable::ChosenNavigable Navigable::choose_a_navigable(StringView name, Tokeni
|
|||
if (!Infra::is_ascii_case_insensitive_match(name, "_blank"sv))
|
||||
target_name = MUST(String::from_utf8(name));
|
||||
|
||||
auto create_new_traversable_closure = [this, window_type, no_opener, target_name, activate_tab](JS::GCPtr<BrowsingContext> opener) -> JS::NonnullGCPtr<Navigable> {
|
||||
// FIXME: The popup state for window.open is calculated after this call (somehow?)
|
||||
// Probably want to deviate from the spec and pass the popup state in here
|
||||
auto hints = WebViewHints {
|
||||
.popup = window_type != WindowType::ExistingOrNone,
|
||||
};
|
||||
auto create_new_traversable_closure = [this, no_opener, target_name, activate_tab, window_features](JS::GCPtr<BrowsingContext> opener) -> JS::NonnullGCPtr<Navigable> {
|
||||
auto hints = WebViewHints::from_tokenised_features(window_features.value_or({}), traversable_navigable()->page());
|
||||
auto [page, window_handle] = traversable_navigable()->page().client().page_did_request_new_web_view(activate_tab, hints, no_opener);
|
||||
auto traversable = TraversableNavigable::create_a_new_top_level_traversable(*page, opener, target_name).release_value_but_fixme_should_propagate_errors();
|
||||
page->set_top_level_traversable(traversable);
|
||||
|
|
|
@ -107,7 +107,7 @@ public:
|
|||
WindowType window_type;
|
||||
};
|
||||
|
||||
ChosenNavigable choose_a_navigable(StringView name, TokenizedFeature::NoOpener no_opener, ActivateTab = ActivateTab::Yes);
|
||||
ChosenNavigable choose_a_navigable(StringView name, TokenizedFeature::NoOpener no_opener, ActivateTab = ActivateTab::Yes, Optional<TokenizedFeature::Map const&> window_features = {});
|
||||
|
||||
static JS::GCPtr<Navigable> navigable_with_active_document(JS::NonnullGCPtr<DOM::Document>);
|
||||
|
||||
|
|
|
@ -6,7 +6,128 @@
|
|||
|
||||
#include <LibIPC/Decoder.h>
|
||||
#include <LibIPC/Encoder.h>
|
||||
#include <LibWeb/HTML/Numbers.h>
|
||||
#include <LibWeb/HTML/WebViewHints.h>
|
||||
#include <LibWeb/Page/Page.h>
|
||||
#include <LibWeb/PixelUnits.h>
|
||||
|
||||
namespace Web::HTML {
|
||||
|
||||
static void set_up_browsing_context_features(WebViewHints& target, TokenizedFeature::Map const& tokenized_features, Page const& page);
|
||||
|
||||
WebViewHints WebViewHints::from_tokenised_features(TokenizedFeature::Map const& tokenized_features, Page const& page)
|
||||
{
|
||||
WebViewHints hints;
|
||||
hints.popup = check_if_a_popup_window_is_requested(tokenized_features) == TokenizedFeature::Popup::Yes;
|
||||
set_up_browsing_context_features(hints, tokenized_features, page);
|
||||
return hints;
|
||||
}
|
||||
|
||||
// https://drafts.csswg.org/cssom-view/#set-up-browsing-context-features
|
||||
static void set_up_browsing_context_features(WebViewHints& target, TokenizedFeature::Map const& tokenized_features, Page const& page)
|
||||
{
|
||||
// 1. Let x be null.
|
||||
Optional<CSSPixels> x;
|
||||
|
||||
// 2. Let y be null.
|
||||
Optional<CSSPixels> y;
|
||||
|
||||
// 3. Let width be null.
|
||||
Optional<CSSPixels> width;
|
||||
|
||||
// 4. Let height be null.
|
||||
Optional<CSSPixels> height;
|
||||
|
||||
auto screen_rect = page.web_exposed_screen_area();
|
||||
|
||||
// 5. If tokenizedFeatures["left"] exists:
|
||||
if (auto left = tokenized_features.get("left"sv); left.has_value()) {
|
||||
// 1. Set x to the result of invoking the rules for parsing integers on tokenizedFeatures["left"].
|
||||
// 2. If x is an error, set x to 0.
|
||||
x = parse_integer(*left).value_or(0);
|
||||
|
||||
// 3. Optionally, clamp x in a user-agent-defined manner so that the window does not move outside the Web-exposed available screen area.
|
||||
x = min(*x, screen_rect.x());
|
||||
|
||||
// 4. Optionally, move target’s window such that the window’s left edge is at the horizontal coordinate x relative
|
||||
// to the left edge of the Web-exposed screen area, measured in CSS pixels of target. The positive axis is rightward.
|
||||
// Note: Handled in the UI process when creating the traversable navigable.
|
||||
}
|
||||
|
||||
// 6. If tokenizedFeatures["top"] exists:
|
||||
if (auto top = tokenized_features.get("top"sv); top.has_value()) {
|
||||
// 1. Set y to the result of invoking the rules for parsing integers on tokenizedFeatures["top"].
|
||||
// 2. If y is an error, set y to 0.
|
||||
y = parse_integer(*top).value_or(0);
|
||||
|
||||
// 3. Optionally, clamp y in a user-agent-defined manner so that the window does not move outside the Web-exposed available screen area.
|
||||
y = min(*y, screen_rect.y());
|
||||
|
||||
// 4. Optionally, move target’s window such that the window’s top edge is at the vertical coordinate y relative
|
||||
// to the top edge of the Web-exposed screen area, measured in CSS pixels of target. The positive axis is downward.
|
||||
// Note: Handled in the UI process when creating the traversable navigable.
|
||||
}
|
||||
|
||||
// 7. If tokenizedFeatures["width"] exists:
|
||||
if (auto width_token = tokenized_features.get("width"sv); width_token.has_value()) {
|
||||
// 1. Set width to the result of invoking the rules for parsing integers on tokenizedFeatures["width"].
|
||||
// 2. If width is an error, set width to 0.
|
||||
width = parse_integer(*width_token).value_or(0);
|
||||
|
||||
// 3. If width is not 0:
|
||||
if (width != 0) {
|
||||
// 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.
|
||||
width = clamp(*width, 100, screen_rect.width());
|
||||
|
||||
// 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.
|
||||
// 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.
|
||||
// Note: Handled in the UI process when creating the traversable navigable.
|
||||
}
|
||||
}
|
||||
|
||||
// 8. If tokenizedFeatures["height"] exists:
|
||||
if (auto height_token = tokenized_features.get("height"sv); height_token.has_value()) {
|
||||
// 1. Set height to the result of invoking the rules for parsing integers on tokenizedFeatures["height"].
|
||||
// 2. If height is an error, set height to 0.
|
||||
height = parse_integer(*height_token).value_or(0);
|
||||
|
||||
// 3. If height is not 0:
|
||||
if (height != 0) {
|
||||
// 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.
|
||||
height = clamp(*height, 100, screen_rect.height());
|
||||
|
||||
// 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.
|
||||
// 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.
|
||||
// Note: Handled in the UI process when creating the traversable navigable.
|
||||
}
|
||||
}
|
||||
|
||||
auto scale = page.client().device_pixels_per_css_pixel();
|
||||
|
||||
if (x.has_value()) {
|
||||
// Make sure we don't fly off the screen to the right
|
||||
if (x.value() + width.value_or(0) > screen_rect.width())
|
||||
x = screen_rect.width() - width.value_or(0);
|
||||
target.screen_x = x.value() / scale;
|
||||
}
|
||||
|
||||
if (y.has_value()) {
|
||||
// Make sure we don't fly off the screen to the bottom
|
||||
if (y.value() + height.value_or(0) > screen_rect.height())
|
||||
y = screen_rect.height() - height.value_or(0);
|
||||
target.screen_y = y.value() / scale;
|
||||
}
|
||||
|
||||
if (width.has_value()) {
|
||||
target.width = width.value() / scale;
|
||||
}
|
||||
|
||||
if (height.has_value()) {
|
||||
target.height = height.value() / scale;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace IPC {
|
||||
|
||||
|
|
|
@ -9,16 +9,20 @@
|
|||
#include <AK/Optional.h>
|
||||
#include <AK/Types.h>
|
||||
#include <LibIPC/Forward.h>
|
||||
#include <LibWeb/Forward.h>
|
||||
#include <LibWeb/HTML/TokenizedFeatures.h>
|
||||
#include <LibWeb/PixelUnits.h>
|
||||
|
||||
namespace Web::HTML {
|
||||
|
||||
struct WebViewHints {
|
||||
bool popup = false;
|
||||
Optional<DevicePixels> width = {};
|
||||
Optional<DevicePixels> height = {};
|
||||
Optional<DevicePixels> screen_x = {};
|
||||
Optional<DevicePixels> screen_y = {};
|
||||
Optional<DevicePixels> width;
|
||||
Optional<DevicePixels> height;
|
||||
Optional<DevicePixels> screen_x;
|
||||
Optional<DevicePixels> screen_y;
|
||||
|
||||
static WebViewHints from_tokenised_features(TokenizedFeature::Map const&, Page const&);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -189,7 +189,7 @@ WebIDL::ExceptionOr<JS::GCPtr<WindowProxy>> Window::open_impl(StringView url, St
|
|||
|
||||
// 10. Let targetNavigable and windowType be the result of applying the rules for choosing a navigable given target, sourceDocument's node navigable, and noopener.
|
||||
VERIFY(source_document.navigable());
|
||||
auto [target_navigable, window_type] = source_document.navigable()->choose_a_navigable(target, no_opener);
|
||||
auto [target_navigable, window_type] = source_document.navigable()->choose_a_navigable(target, no_opener, ActivateTab::Yes, tokenized_features);
|
||||
|
||||
// 11. If targetNavigable is null, then return null.
|
||||
if (target_navigable == nullptr)
|
||||
|
@ -200,8 +200,8 @@ WebIDL::ExceptionOr<JS::GCPtr<WindowProxy>> Window::open_impl(StringView url, St
|
|||
// 1. Set the target browsing context's is popup to the result of checking if a popup window is requested, given tokenizedFeatures.
|
||||
target_navigable->set_is_popup(check_if_a_popup_window_is_requested(tokenized_features));
|
||||
|
||||
// FIXME: 2. Set up browsing context features for target browsing context given tokenizedFeatures. [CSSOMVIEW]
|
||||
// NOTE: While this is not implemented yet, all of observable actions taken by this operation are optional (implementation-defined).
|
||||
// 2. Set up browsing context features for target browsing context given tokenizedFeatures. [CSSOMVIEW]
|
||||
// NOTE: This is implemented in choose_a_navigable when creating the top level traversable.
|
||||
|
||||
// 3. Let urlRecord be the URL record about:blank.
|
||||
auto url_record = URL::URL("about:blank"sv);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue