summaryrefslogtreecommitdiff
path: root/Userland/Libraries
diff options
context:
space:
mode:
authorIdan Horowitz <idan.horowitz@gmail.com>2022-11-15 02:03:14 +0200
committerLinus Groh <mail@linusgroh.de>2022-11-15 21:48:19 +0000
commitd15d7636e56418714c175555ebed9da3712afd79 (patch)
treeea0005383ed1e34c4bbd6e66b77eb0fc7d66ea69 /Userland/Libraries
parent798d7c6fae3396b79f24bb98da4d959509b48102 (diff)
downloadserenity-d15d7636e56418714c175555ebed9da3712afd79.zip
LibWeb: Add window.open feature detection abstract operations
Diffstat (limited to 'Userland/Libraries')
-rw-r--r--Userland/Libraries/LibWeb/HTML/Window.cpp177
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())