diff options
author | Idan Horowitz <idan.horowitz@gmail.com> | 2022-11-15 02:03:14 +0200 |
---|---|---|
committer | Linus Groh <mail@linusgroh.de> | 2022-11-15 21:48:19 +0000 |
commit | d15d7636e56418714c175555ebed9da3712afd79 (patch) | |
tree | ea0005383ed1e34c4bbd6e66b77eb0fc7d66ea69 /Userland/Libraries | |
parent | 798d7c6fae3396b79f24bb98da4d959509b48102 (diff) | |
download | serenity-d15d7636e56418714c175555ebed9da3712afd79.zip |
LibWeb: Add window.open feature detection abstract operations
Diffstat (limited to 'Userland/Libraries')
-rw-r--r-- | Userland/Libraries/LibWeb/HTML/Window.cpp | 177 |
1 files changed, 177 insertions, 0 deletions
diff --git a/Userland/Libraries/LibWeb/HTML/Window.cpp b/Userland/Libraries/LibWeb/HTML/Window.cpp index a30131472b..8a911c0684 100644 --- a/Userland/Libraries/LibWeb/HTML/Window.cpp +++ b/Userland/Libraries/LibWeb/HTML/Window.cpp @@ -6,6 +6,7 @@ */ #include <AK/Base64.h> +#include <AK/GenericLexer.h> #include <AK/String.h> #include <AK/Utf8View.h> #include <LibJS/Runtime/AbstractOperations.h> @@ -47,6 +48,7 @@ #include <LibWeb/HTML/WindowProxy.h> #include <LibWeb/HighResolutionTime/Performance.h> #include <LibWeb/HighResolutionTime/TimeOrigin.h> +#include <LibWeb/Infra/CharacterTypes.h> #include <LibWeb/Layout/InitialContainingBlock.h> #include <LibWeb/Page/Page.h> #include <LibWeb/RequestIdleCallback/IdleDeadline.h> @@ -120,6 +122,181 @@ CSS::Screen& Window::screen() return *m_screen; } +// https://html.spec.whatwg.org/multipage/nav-history-apis.html#normalizing-the-feature-name +static StringView normalize_feature_name(StringView name) +{ + // For legacy reasons, there are some aliases of some feature names. To normalize a feature name name, switch on name: + + // "screenx" + if (name == "screenx"sv) { + // Return "left". + return "left"sv; + } + // "screeny" + else if (name == "screeny"sv) { + // Return "top". + return "top"sv; + } + // "innerwidth" + else if (name == "innerwidth"sv) { + // Return "width". + return "width"sv; + } + // "innerheight" + else if (name == "innerheight") { + // Return "height". + return "height"sv; + } + // Anything else + else { + // Return name. + return name; + } +} + +// https://html.spec.whatwg.org/multipage/nav-history-apis.html#concept-window-open-features-tokenize +static OrderedHashMap<String, String> tokenize_open_features(StringView features) +{ + // 1. Let tokenizedFeatures be a new ordered map. + OrderedHashMap<String, String> tokenized_features; + + // 2. Let position point at the first code point of features. + GenericLexer lexer(features); + + // https://html.spec.whatwg.org/multipage/nav-history-apis.html#feature-separator + auto is_feature_separator = [](auto character) { + return Infra::is_ascii_whitespace(character) || character == '=' || character == ','; + }; + + // 3. While position is not past the end of features: + while (!lexer.is_eof()) { + // 1. Let name be the empty string. + String name; + + // 2. Let value be the empty string. + String value; + + // 3. Collect a sequence of code points that are feature separators from features given position. This skips past leading separators before the name. + lexer.ignore_while(is_feature_separator); + + // 4. Collect a sequence of code points that are not feature separators from features given position. Set name to the collected characters, converted to ASCII lowercase. + name = lexer.consume_until(is_feature_separator).to_lowercase_string(); + + // 5. Set name to the result of normalizing the feature name name. + name = normalize_feature_name(name); + + // 6. While position is not past the end of features and the code point at position in features is not U+003D (=): + // 1. If the code point at position in features is U+002C (,), or if it is not a feature separator, then break. + // 2. Advance position by 1. + lexer.ignore_while(Infra::is_ascii_whitespace); + + // 7. If the code point at position in features is a feature separator: + // 1. While position is not past the end of features and the code point at position in features is a feature separator: + // 1. If the code point at position in features is U+002C (,), then break. + // 2. Advance position by 1. + lexer.ignore_while([](auto character) { return Infra::is_ascii_whitespace(character) || character == '='; }); + + // 2. Collect a sequence of code points that are not feature separators code points from features given position. Set value to the collected code points, converted to ASCII lowercase. + value = lexer.consume_until(is_feature_separator).to_lowercase_string(); + + // 8. If name is not the empty string, then set tokenizedFeatures[name] to value. + if (!name.is_empty()) + tokenized_features.set(move(name), move(value)); + } + + // 4. Return tokenizedFeatures. + return tokenized_features; +} + +// https://html.spec.whatwg.org/multipage/nav-history-apis.html#concept-window-open-features-parse-boolean +static bool parse_boolean_feature(StringView value) +{ + // 1. If value is the empty string, then return true. + if (value.is_empty()) + return true; + + // 2. If value is "yes", then return true. + if (value == "yes"sv) + return true; + + // 3. If value is "true", then return true. + if (value == "true"sv) + return true; + + // 4. Let parsed be the result of parsing value as an integer. + auto parsed = value.to_int<i64>(); + + // 5. If parsed is an error, then set it to 0. + if (!parsed.has_value()) + parsed = 0; + + // 6. Return false if parsed is 0, and true otherwise. + return *parsed != 0; +} + +// https://html.spec.whatwg.org/multipage/window-object.html#popup-window-is-requested +static bool check_if_a_popup_window_is_requested(OrderedHashMap<String, String> const& tokenized_features) +{ + // 1. If tokenizedFeatures is empty, then return false. + if (tokenized_features.is_empty()) + return false; + + // 2. If tokenizedFeatures["popup"] exists, then return the result of parsing tokenizedFeatures["popup"] as a boolean feature. + if (auto popup_feature = tokenized_features.get("popup"sv); popup_feature.has_value()) + return parse_boolean_feature(*popup_feature); + + // https://html.spec.whatwg.org/multipage/window-object.html#window-feature-is-set + auto check_if_a_window_feature_is_set = [&](StringView feature_name, bool default_value) { + // 1. If tokenizedFeatures[featureName] exists, then return the result of parsing tokenizedFeatures[featureName] as a boolean feature. + if (auto feature = tokenized_features.get(feature_name); feature.has_value()) + return parse_boolean_feature(*feature); + + // 2. Return defaultValue. + return default_value; + }; + + // 3. Let location be the result of checking if a window feature is set, given tokenizedFeatures, "location", and false. + auto location = check_if_a_window_feature_is_set("location"sv, false); + + // 4. Let toolbar be the result of checking if a window feature is set, given tokenizedFeatures, "toolbar", and false. + auto toolbar = check_if_a_window_feature_is_set("toolbar"sv, false); + + // 5. If location and toolbar are both false, then return true. + if (!location && !toolbar) + return true; + + // 6. Let menubar be the result of checking if a window feature is set, given tokenizedFeatures, menubar", and false. + auto menubar = check_if_a_window_feature_is_set("menubar"sv, false); + + // 7. If menubar is false, then return true. + if (!menubar) + return true; + + // 8. Let resizable be the result of checking if a window feature is set, given tokenizedFeatures, "resizable", and true. + auto resizable = check_if_a_window_feature_is_set("resizable"sv, true); + + // 9. If resizable is false, then return true. + if (!resizable) + return true; + + // 10. Let scrollbars be the result of checking if a window feature is set, given tokenizedFeatures, "scrollbars", and false. + auto scrollbars = check_if_a_window_feature_is_set("scrollbars"sv, false); + + // 11. If scrollbars is false, then return true. + if (!scrollbars) + return true; + + // 12. Let status be the result of checking if a window feature is set, given tokenizedFeatures, "status", and false. + auto status = check_if_a_window_feature_is_set("status"sv, false); + + // 13. If status is false, then return true. + if (!status) + return true; + + // 14. Return false. + return false; +} + void Window::alert_impl(String const& message) { if (auto* page = this->page()) |