Repository: LadybirdBrowser/ladybird
Pull request #3810: LibWeb: Implement BarProp properties for Window
Author: login: Totto16
Created: 2025-03-04T21:55:37Z | Merged: 2025-03-29T02:35:27Z

This fixes a few WPT tests, that crash after 72 seconds. e.g. all [these](https://wpt.fyi/results/html/browsers/the-window-object/open-close?label=master&product=ladybird&q=status%3Acrash)


Diff:
diff --git a/Libraries/LibWeb/CMakeLists.txt b/Libraries/LibWeb/CMakeLists.txt
index 64b0e557c4800..8dd32119facf0 100644
--- a/Libraries/LibWeb/CMakeLists.txt
+++ b/Libraries/LibWeb/CMakeLists.txt
@@ -314,6 +314,7 @@ set(SOURCES
     HTML/AudioTrack.cpp
     HTML/AudioTrackList.cpp
     HTML/AutocompleteElement.cpp
+    HTML/BarProp.cpp
     HTML/BeforeUnloadEvent.cpp
     HTML/BroadcastChannel.cpp
     HTML/BrowsingContext.cpp
diff --git a/Libraries/LibWeb/Forward.h b/Libraries/LibWeb/Forward.h
index f25a6cf5a4c2e..5481b19c46c79 100644
--- a/Libraries/LibWeb/Forward.h
+++ b/Libraries/LibWeb/Forward.h
@@ -417,6 +417,7 @@ namespace Web::HTML {
 class AnimationFrameCallbackDriver;
 class AudioTrack;
 class AudioTrackList;
+class BarProp;
 class BeforeUnloadEvent;
 class BroadcastChannel;
 class BrowsingContext;
diff --git a/Libraries/LibWeb/HTML/BarProp.cpp b/Libraries/LibWeb/HTML/BarProp.cpp
new file mode 100644
index 0000000000000..ee7657c5cb0ce
--- /dev/null
+++ b/Libraries/LibWeb/HTML/BarProp.cpp
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2025, the Ladybird developers.
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <LibJS/Runtime/Realm.h>
+#include <LibWeb/Bindings/BarPropPrototype.h>
+#include <LibWeb/HTML/BarProp.h>
+#include <LibWeb/HTML/Window.h>
+
+namespace Web::HTML {
+
+GC_DEFINE_ALLOCATOR(BarProp);
+
+GC::Ref<BarProp> BarProp::create(JS::Realm& realm)
+{
+    return realm.create<BarProp>(realm);
+}
+
+BarProp::BarProp(JS::Realm& realm)
+    : Bindings::PlatformObject(realm)
+{
+}
+
+// https://html.spec.whatwg.org/multipage/nav-history-apis.html#dom-barprop-visible
+bool BarProp::visible() const
+{
+    // 1. Let browsingContext be this's relevant global object's browsing context.
+    auto& global_object = HTML::relevant_global_object(*this);
+    auto* browsing_context = as<HTML::Window>(global_object).associated_document().browsing_context();
+
+    // 2. If browsingContext is null, then return true.
+    if (!browsing_context) {
+        return true;
+    }
+
+    // 3. Return the negation of browsingContext's top-level browsing context's is popup.
+    return browsing_context->top_level_browsing_context()->is_popup() != TokenizedFeature::Popup::Yes;
+}
+
+void BarProp::initialize(JS::Realm& realm)
+{
+    Base::initialize(realm);
+    WEB_SET_PROTOTYPE_FOR_INTERFACE(BarProp);
+}
+}
diff --git a/Libraries/LibWeb/HTML/BarProp.h b/Libraries/LibWeb/HTML/BarProp.h
new file mode 100644
index 0000000000000..d3b0a47778dea
--- /dev/null
+++ b/Libraries/LibWeb/HTML/BarProp.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2025, the Ladybird developers.
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <LibGC/CellAllocator.h>
+#include <LibWeb/Bindings/PlatformObject.h>
+#include <LibWeb/Forward.h>
+#include <LibWeb/WebIDL/Types.h>
+
+namespace Web::HTML {
+
+// https://html.spec.whatwg.org/multipage/nav-history-apis.html#barprop
+class BarProp : public Bindings::PlatformObject {
+    WEB_PLATFORM_OBJECT(BarProp, Bindings::PlatformObject);
+    GC_DECLARE_ALLOCATOR(BarProp);
+
+public:
+    BarProp(JS::Realm&);
+    static GC::Ref<BarProp> create(JS::Realm&);
+
+    [[nodiscard]] bool visible() const;
+
+private:
+    virtual void initialize(JS::Realm&) override;
+};
+}
diff --git a/Libraries/LibWeb/HTML/BarProp.idl b/Libraries/LibWeb/HTML/BarProp.idl
new file mode 100644
index 0000000000000..2143bae3091a3
--- /dev/null
+++ b/Libraries/LibWeb/HTML/BarProp.idl
@@ -0,0 +1,6 @@
+
+// https://html.spec.whatwg.org/multipage/nav-history-apis.html#barprop
+[Exposed=Window]
+interface BarProp {
+    readonly attribute boolean visible;
+};
diff --git a/Libraries/LibWeb/HTML/BrowsingContext.h b/Libraries/LibWeb/HTML/BrowsingContext.h
index d0f5bf302567e..466de1f3aa324 100644
--- a/Libraries/LibWeb/HTML/BrowsingContext.h
+++ b/Libraries/LibWeb/HTML/BrowsingContext.h
@@ -77,6 +77,7 @@ class BrowsingContext final : public JS::Cell {
     void set_opener_browsing_context(GC::Ptr<BrowsingContext> browsing_context) { m_opener_browsing_context = browsing_context; }
 
     void set_is_popup(TokenizedFeature::Popup is_popup) { m_is_popup = is_popup; }
+    [[nodiscard]] TokenizedFeature::Popup is_popup() const { return m_is_popup; }
 
     SandboxingFlagSet popup_sandboxing_flag_set() const { return m_popup_sandboxing_flag_set; }
     void set_popup_sandboxing_flag_set(SandboxingFlagSet value) { m_popup_sandboxing_flag_set = value; }
diff --git a/Libraries/LibWeb/HTML/Window.cpp b/Libraries/LibWeb/HTML/Window.cpp
index 646f5d6981a0f..a665b2dbbdff1 100644
--- a/Libraries/LibWeb/HTML/Window.cpp
+++ b/Libraries/LibWeb/HTML/Window.cpp
@@ -128,6 +128,12 @@ void Window::visit_edges(JS::Cell::Visitor& visitor)
     visitor.visit(m_pdf_viewer_plugin_objects);
     visitor.visit(m_pdf_viewer_mime_type_objects);
     visitor.visit(m_close_watcher_manager);
+    visitor.visit(m_locationbar);
+    visitor.visit(m_menubar);
+    visitor.visit(m_personalbar);
+    visitor.visit(m_scrollbars);
+    visitor.visit(m_statusbar);
+    visitor.visit(m_toolbar);
 }
 
 void Window::finalize()
@@ -920,6 +926,60 @@ void Window::blur()
     // The blur() method steps are to do nothing.
 }
 
+// https://html.spec.whatwg.org/multipage/nav-history-apis.html#dom-window-locationbar
+GC::Ref<BarProp const> Window::locationbar()
+{
+    if (!m_locationbar)
+        m_locationbar = BarProp::create(realm());
+
+    return *m_locationbar;
+}
+
+// https://html.spec.whatwg.org/multipage/nav-history-apis.html#dom-window-menubar
+GC::Ref<BarProp const> Window::menubar()
+{
+    if (!m_menubar)
+        m_menubar = BarProp::create(realm());
+
+    return *m_menubar;
+}
+
+// https://html.spec.whatwg.org/multipage/nav-history-apis.html#dom-window-personalbar
+GC::Ref<BarProp const> Window::personalbar()
+{
+    if (!m_personalbar)
+        m_personalbar = BarProp::create(realm());
+
+    return *m_personalbar;
+}
+
+// https://html.spec.whatwg.org/multipage/nav-history-apis.html#dom-window-scrollbars
+GC::Ref<BarProp const> Window::scrollbars()
+{
+    if (!m_scrollbars)
+        m_scrollbars = BarProp::create(realm());
+
+    return *m_scrollbars;
+}
+
+// https://html.spec.whatwg.org/multipage/nav-history-apis.html#dom-window-statusbar
+GC::Ref<BarProp const> Window::statusbar()
+{
+    if (!m_statusbar)
+        m_statusbar = BarProp::create(realm());
+
+    return *m_statusbar;
+}
+
+// https://html.spec.whatwg.org/multipage/nav-history-apis.html#dom-window-toolbar
+GC::Ref<BarProp const> Window::toolbar()
+{
+    if (!m_toolbar)
+        m_toolbar = BarProp::create(realm());
+
+    return *m_toolbar;
+}
+
 // https://html.spec.whatwg.org/multipage/window-object.html#dom-frames
 GC::Ref<WindowProxy> Window::frames() const
 {
diff --git a/Libraries/LibWeb/HTML/Window.h b/Libraries/LibWeb/HTML/Window.h
index 4a8645973c05d..7b427d034430f 100644
--- a/Libraries/LibWeb/HTML/Window.h
+++ b/Libraries/LibWeb/HTML/Window.h
@@ -16,6 +16,7 @@
 #include <LibWeb/Bindings/WindowGlobalMixin.h>
 #include <LibWeb/DOM/EventTarget.h>
 #include <LibWeb/Forward.h>
+#include <LibWeb/HTML/BarProp.h>
 #include <LibWeb/HTML/CrossOrigin/CrossOriginPropertyDescriptorMap.h>
 #include <LibWeb/HTML/GlobalEventHandlers.h>
 #include <LibWeb/HTML/MimeType.h>
@@ -173,6 +174,15 @@ class Window final
     void focus();
     void blur();
 
+    // For historical reasons, the Window interface had some properties that represented the visibility of certain web browser interface elements.
+    // For privacy and interoperability reasons, those properties now return values that represent whether the Window's browsing context's is popup property is true or false.
+    GC::Ref<BarProp const> locationbar();
+    GC::Ref<BarProp const> menubar();
+    GC::Ref<BarProp const> personalbar();
+    GC::Ref<BarProp const> scrollbars();
+    GC::Ref<BarProp const> statusbar();
+    GC::Ref<BarProp const> toolbar();
+
     GC::Ref<WindowProxy> frames() const;
     u32 length();
     GC::Ptr<WindowProxy const> top() const;
@@ -332,6 +342,13 @@ class Window final
     // https://html.spec.whatwg.org/multipage/nav-history-apis.html#dom-window-status
     // When the Window object is created, the attribute must be set to the empty string. It does not do anything else.
     String m_status;
+
+    GC::Ptr<BarProp const> m_locationbar;
+    GC::Ptr<BarProp const> m_menubar;
+    GC::Ptr<BarProp const> m_personalbar;
+    GC::Ptr<BarProp const> m_scrollbars;
+    GC::Ptr<BarProp const> m_statusbar;
+    GC::Ptr<BarProp const> m_toolbar;
 };
 
 void run_animation_frame_callbacks(DOM::Document&, double now);
diff --git a/Libraries/LibWeb/HTML/Window.idl b/Libraries/LibWeb/HTML/Window.idl
index 37c546ac6355b..cd1e11585ab07 100644
--- a/Libraries/LibWeb/HTML/Window.idl
+++ b/Libraries/LibWeb/HTML/Window.idl
@@ -34,6 +34,13 @@ interface Window : EventTarget {
     undefined focus();
     undefined blur();
 
+    [Replaceable] readonly attribute BarProp locationbar;
+    [Replaceable] readonly attribute BarProp menubar;
+    [Replaceable] readonly attribute BarProp personalbar;
+    [Replaceable] readonly attribute BarProp scrollbars;
+    [Replaceable] readonly attribute BarProp statusbar;
+    [Replaceable] readonly attribute BarProp toolbar;
+
     // other browsing contexts
     [Replaceable] readonly attribute WindowProxy frames;
     [Replaceable] readonly attribute unsigned long length;
diff --git a/Libraries/LibWeb/idl_files.cmake b/Libraries/LibWeb/idl_files.cmake
index 54d1da8b7fb0a..6d6af4e6a62ac 100644
--- a/Libraries/LibWeb/idl_files.cmake
+++ b/Libraries/LibWeb/idl_files.cmake
@@ -110,6 +110,7 @@ libweb_js_bindings(Geometry/DOMRectList)
 libweb_js_bindings(Geometry/DOMRectReadOnly)
 libweb_js_bindings(HTML/AudioTrack)
 libweb_js_bindings(HTML/AudioTrackList)
+libweb_js_bindings(HTML/BarProp)
 libweb_js_bindings(HTML/BeforeUnloadEvent)
 libweb_js_bindings(HTML/BroadcastChannel)
 libweb_js_bindings(HTML/CanvasGradient)
diff --git a/Tests/LibWeb/Text/data/window-barprops-popout-window.html b/Tests/LibWeb/Text/data/window-barprops-popout-window.html
new file mode 100644
index 0000000000000..259f354f9fea0
--- /dev/null
+++ b/Tests/LibWeb/Text/data/window-barprops-popout-window.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<script>
+    try {
+        const availableProps = [
+            "locationbar",
+            "menubar",
+            "personalbar",
+            "scrollbars",
+            "statusbar",
+            "toolbar",
+        ];
+
+        let results = [];
+
+        for (const propName of availableProps) {
+            const windowProp = window[propName];
+            results.push(
+                `${propName} is BarProp: ${windowProp instanceof BarProp} visible: ${
+                    windowProp.visible
+                }`
+            );
+        }
+
+        window.opener.postMessage(results.join("\n"), "*");
+    } catch (e) {
+        window.opener.postMessage(`ERROR: ${e}`, "*");
+    }
+</script>
diff --git a/Tests/LibWeb/Text/expected/HTML/window-barprops-popout.txt b/Tests/LibWeb/Text/expected/HTML/window-barprops-popout.txt
new file mode 100644
index 0000000000000..8a8908472c875
--- /dev/null
+++ b/Tests/LibWeb/Text/expected/HTML/window-barprops-popout.txt
@@ -0,0 +1,6 @@
+locationbar is BarProp: true visible: false
+menubar is BarProp: true visible: false
+personalbar is BarProp: true visible: false
+scrollbars is BarProp: true visible: false
+statusbar is BarProp: true visible: false
+toolbar is BarProp: true visible: false
diff --git a/Tests/LibWeb/Text/expected/HTML/window-barprops.txt b/Tests/LibWeb/Text/expected/HTML/window-barprops.txt
new file mode 100644
index 0000000000000..1255fc7530758
--- /dev/null
+++ b/Tests/LibWeb/Text/expected/HTML/window-barprops.txt
@@ -0,0 +1,6 @@
+locationbar is BarProp: true visible: true
+menubar is BarProp: true visible: true
+personalbar is BarProp: true visible: true
+scrollbars is BarProp: true visible: true
+statusbar is BarProp: true visible: true
+toolbar is BarProp: true visible: true
diff --git a/Tests/LibWeb/Text/expected/all-window-properties.txt b/Tests/LibWeb/Text/expected/all-window-properties.txt
index df057954b11a9..4406c33fe378a 100644
--- a/Tests/LibWeb/Text/expected/all-window-properties.txt
+++ b/Tests/LibWeb/Text/expected/all-window-properties.txt
@@ -23,6 +23,7 @@ AudioParam
 AudioScheduledSourceNode
 AudioTrack
 AudioTrackList
+BarProp
 BaseAudioContext
 BeforeUnloadEvent
 BigInt
diff --git a/Tests/LibWeb/Text/input/HTML/window-barprops-popout.html b/Tests/LibWeb/Text/input/HTML/window-barprops-popout.html
new file mode 100644
index 0000000000000..28baadff3a37f
--- /dev/null
+++ b/Tests/LibWeb/Text/input/HTML/window-barprops-popout.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<script src="../include.js"></script>
+<script>
+    asyncTest(async done => {
+        window.addEventListener("message", event => {
+            println(event.data);
+            done();
+        });
+
+        let win = window.open("../../data/window-barprops-popout-window.html", "_blank", "popup=true");
+
+        if (!win) {
+            println("Couldn't open window");
+            done();
+        }
+    });
+</script>
diff --git a/Tests/LibWeb/Text/input/HTML/window-barprops.html b/Tests/LibWeb/Text/input/HTML/window-barprops.html
new file mode 100644
index 0000000000000..c5fcbe24e02b9
--- /dev/null
+++ b/Tests/LibWeb/Text/input/HTML/window-barprops.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<script src="../include.js"></script>
+<script>
+    test(() => {
+        const availableProps = [
+            "locationbar",
+            "menubar",
+            "personalbar",
+            "scrollbars",
+            "statusbar",
+            "toolbar",
+        ];
+
+        for (const propName of availableProps) {
+            const windowProp = window[propName];
+            println(
+                `${propName} is BarProp: ${windowProp instanceof BarProp} visible: ${
+                    windowProp.visible
+                }`
+            );
+        }
+    });
+</script>


Reviews:
user: login: tcl3
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-05T09:35:40Z
user: login: Totto16
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-05T11:08:08Z
user: login: AtkinsSJ
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-05T11:29:40Z
user: login: tcl3
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-05T11:33:53Z
user: login: Totto16
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-05T11:44:57Z
user: login: ADKaster
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-05T12:00:30Z
user: login: Totto16
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-05T12:04:18Z
user: login: AtkinsSJ
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-05T12:07:27Z
user: login: Totto16
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-05T12:10:22Z
user: login: ADKaster
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-05T12:14:11Z
user: login: tcl3
body: Looks good now, just one small thing.
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-05T13:52:37Z
user: login: tcl3
body: Sorry this took so long to get to, just one small thing then this can be merged.
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-29T01:00:55Z
user: login: Totto16
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-29T01:05:51Z
user: login: tcl3
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-29T01:20:18Z
user: login: tcl3
state: APPROVED
author_association: MEMBER
submitted_at: 2025-03-29T01:29:07Z

Review comments:
diff_hunk: @@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2025, Ladybird contributors
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <LibJS/Runtime/Realm.h>
+#include <LibWeb/Bindings/BarPropPrototype.h>
+#include <LibWeb/HTML/BarProp.h>
+#include <LibWeb/HTML/Window.h>
+
+namespace Web::HTML {
+
+GC_DEFINE_ALLOCATOR(BarProp);
+
+GC::Ref<BarProp> BarProp::create(JS::Realm& realm)
+{
+    return realm.create<BarProp>(realm);
+}
+
+BarProp::BarProp(JS::Realm& realm)
+    : Bindings::PlatformObject(realm)
+{
+}
+
+// https://html.spec.whatwg.org/multipage/nav-history-apis.html#dom-barprop-visible
+bool BarProp::visible() const
+{
+    // 1. Let browsingContext be this's relevant global object's browsing context.
+    HTML::BrowsingContext* browsing_context = nullptr;
+
+    auto& global_object = realm().global_object();
+    if (is<HTML::Window>(global_object)) {
path: Libraries/LibWeb/HTML/BarProp.cpp
user: login: tcl3
body: `global_object` should always be a `Window` here since `BarProp` is only exposed to `Window`,  so this `is` check shouldn't be necessary.
created_at: 2025-03-05T08:59:34Z
author_association: MEMBER
diff_hunk: @@ -69,7 +69,6 @@
 #include <LibWeb/Selection/Selection.h>
 #include <LibWeb/StorageAPI/StorageBottle.h>
 #include <LibWeb/WebIDL/AbstractOperations.h>
-
path: Libraries/LibWeb/HTML/Window.cpp
user: login: tcl3
body: This space should be kept.
created_at: 2025-03-05T09:03:14Z
author_association: MEMBER
diff_hunk: @@ -925,6 +924,44 @@ void Window::blur()
     // The blur() method steps are to do nothing.
 }
 
+static GC::Ptr<BarProp const> bar_prop_impl(JS::Realm& realm)
+{
+    // NOTE: as this is called rarely, we create a new BarProp every time, instead of storing one on the window object,
+    // which is used often and would increase memory size unnecessary
+
+    return BarProp::create(realm);
+}
+// https://html.spec.whatwg.org/multipage/nav-history-apis.html#dom-window-locationbar
+GC::Ptr<BarProp const> Window::locationbar() const
+{
+    return bar_prop_impl(realm());
+}
+
+GC::Ptr<BarProp const> Window::menubar() const
+{
+    return bar_prop_impl(realm());
+}
+
+GC::Ptr<BarProp const> Window::personalbar() const
+{
+    return bar_prop_impl(realm());
+}
+
+GC::Ptr<BarProp const> Window::scrollbars() const
+{
+    return bar_prop_impl(realm());
+}
+
+GC::Ptr<BarProp const> Window::statusbar() const
+{
+    return bar_prop_impl(realm());
+}
+
+GC::Ptr<BarProp const> Window::toolbar() const
+{
+    return bar_prop_impl(realm());
+}
path: Libraries/LibWeb/HTML/Window.cpp
user: login: tcl3
body: Users of these methods may rely on repeated calls returning the same object, so each should return a `BarProp` object which is stored on `Window`. The `BarProp` object only needs to be created when the method is first called, so the memory overhead is pretty small.

It would be great if you could include spec links for each of these methods.
created_at: 2025-03-05T09:20:35Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2025, Ladybird contributors
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <LibJS/Runtime/Realm.h>
+#include <LibWeb/Bindings/BarPropPrototype.h>
+#include <LibWeb/HTML/BarProp.h>
+#include <LibWeb/HTML/Window.h>
+
+namespace Web::HTML {
+
+GC_DEFINE_ALLOCATOR(BarProp);
+
+GC::Ref<BarProp> BarProp::create(JS::Realm& realm)
+{
+    return realm.create<BarProp>(realm);
+}
+
+BarProp::BarProp(JS::Realm& realm)
+    : Bindings::PlatformObject(realm)
+{
+}
+
+// https://html.spec.whatwg.org/multipage/nav-history-apis.html#dom-barprop-visible
+bool BarProp::visible() const
+{
+    // 1. Let browsingContext be this's relevant global object's browsing context.
+    HTML::BrowsingContext* browsing_context = nullptr;
+
+    auto& global_object = realm().global_object();
path: Libraries/LibWeb/HTML/BarProp.cpp
user: login: tcl3
body: `HTML::relevant_global_object(*this)` should be used here.
created_at: 2025-03-05T09:24:46Z
author_association: MEMBER
diff_hunk: @@ -925,6 +924,44 @@ void Window::blur()
     // The blur() method steps are to do nothing.
 }
 
+static GC::Ptr<BarProp const> bar_prop_impl(JS::Realm& realm)
+{
+    // NOTE: as this is called rarely, we create a new BarProp every time, instead of storing one on the window object,
+    // which is used often and would increase memory size unnecessary
+
+    return BarProp::create(realm);
+}
+// https://html.spec.whatwg.org/multipage/nav-history-apis.html#dom-window-locationbar
+GC::Ptr<BarProp const> Window::locationbar() const
+{
+    return bar_prop_impl(realm());
+}
+
+GC::Ptr<BarProp const> Window::menubar() const
+{
+    return bar_prop_impl(realm());
+}
+
+GC::Ptr<BarProp const> Window::personalbar() const
+{
+    return bar_prop_impl(realm());
+}
+
+GC::Ptr<BarProp const> Window::scrollbars() const
+{
+    return bar_prop_impl(realm());
+}
+
+GC::Ptr<BarProp const> Window::statusbar() const
+{
+    return bar_prop_impl(realm());
+}
+
+GC::Ptr<BarProp const> Window::toolbar() const
+{
+    return bar_prop_impl(realm());
+}
path: Libraries/LibWeb/HTML/Window.cpp
user: login: Totto16
body: How am I supposed to store it? I don't like the idea of adding 6 or 1 new member variable(s), as they increase the base size of the Window class. Should I add them to the named properties, alias using `internal_get_own_property` and `internal_define_own_property` or `internal_set` or something similar.
created_at: 2025-03-05T11:08:08Z
author_association: CONTRIBUTOR
diff_hunk: @@ -925,6 +924,44 @@ void Window::blur()
     // The blur() method steps are to do nothing.
 }
 
+static GC::Ptr<BarProp const> bar_prop_impl(JS::Realm& realm)
+{
+    // NOTE: as this is called rarely, we create a new BarProp every time, instead of storing one on the window object,
+    // which is used often and would increase memory size unnecessary
+
+    return BarProp::create(realm);
+}
+// https://html.spec.whatwg.org/multipage/nav-history-apis.html#dom-window-locationbar
+GC::Ptr<BarProp const> Window::locationbar() const
+{
+    return bar_prop_impl(realm());
+}
+
+GC::Ptr<BarProp const> Window::menubar() const
+{
+    return bar_prop_impl(realm());
+}
+
+GC::Ptr<BarProp const> Window::personalbar() const
+{
+    return bar_prop_impl(realm());
+}
+
+GC::Ptr<BarProp const> Window::scrollbars() const
+{
+    return bar_prop_impl(realm());
+}
+
+GC::Ptr<BarProp const> Window::statusbar() const
+{
+    return bar_prop_impl(realm());
+}
+
+GC::Ptr<BarProp const> Window::toolbar() const
+{
+    return bar_prop_impl(realm());
+}
path: Libraries/LibWeb/HTML/Window.cpp
user: login: AtkinsSJ
body: Store them as `GC::Ptr<>`s. It's unfortunate to make Window bigger for something like this, but we have so few Window objects that it's not going to really matter if we add 6 pointers to it.
created_at: 2025-03-05T11:29:39Z
author_association: MEMBER
diff_hunk: @@ -925,6 +924,44 @@ void Window::blur()
     // The blur() method steps are to do nothing.
 }
 
+static GC::Ptr<BarProp const> bar_prop_impl(JS::Realm& realm)
+{
+    // NOTE: as this is called rarely, we create a new BarProp every time, instead of storing one on the window object,
+    // which is used often and would increase memory size unnecessary
+
+    return BarProp::create(realm);
+}
+// https://html.spec.whatwg.org/multipage/nav-history-apis.html#dom-window-locationbar
+GC::Ptr<BarProp const> Window::locationbar() const
+{
+    return bar_prop_impl(realm());
+}
+
+GC::Ptr<BarProp const> Window::menubar() const
+{
+    return bar_prop_impl(realm());
+}
+
+GC::Ptr<BarProp const> Window::personalbar() const
+{
+    return bar_prop_impl(realm());
+}
+
+GC::Ptr<BarProp const> Window::scrollbars() const
+{
+    return bar_prop_impl(realm());
+}
+
+GC::Ptr<BarProp const> Window::statusbar() const
+{
+    return bar_prop_impl(realm());
+}
+
+GC::Ptr<BarProp const> Window::toolbar() const
+{
+    return bar_prop_impl(realm());
+}
path: Libraries/LibWeb/HTML/Window.cpp
user: login: tcl3
body: Sam beat me to it. To be clear, I would implement each of these methods like this:

```c++
GC::Ref<BarProp const> Window::locationbar() const
{
    if (!m_locationbar)
        m_locationbar = BarProp::create(realm());

    return *m_locationbar;
}
```

Note that these methods can return `GC::Ref<>` rather than `GC::Ptr<>` since they never return null.
created_at: 2025-03-05T11:33:52Z
author_association: MEMBER
diff_hunk: @@ -925,6 +924,44 @@ void Window::blur()
     // The blur() method steps are to do nothing.
 }
 
+static GC::Ptr<BarProp const> bar_prop_impl(JS::Realm& realm)
+{
+    // NOTE: as this is called rarely, we create a new BarProp every time, instead of storing one on the window object,
+    // which is used often and would increase memory size unnecessary
+
+    return BarProp::create(realm);
+}
+// https://html.spec.whatwg.org/multipage/nav-history-apis.html#dom-window-locationbar
+GC::Ptr<BarProp const> Window::locationbar() const
+{
+    return bar_prop_impl(realm());
+}
+
+GC::Ptr<BarProp const> Window::menubar() const
+{
+    return bar_prop_impl(realm());
+}
+
+GC::Ptr<BarProp const> Window::personalbar() const
+{
+    return bar_prop_impl(realm());
+}
+
+GC::Ptr<BarProp const> Window::scrollbars() const
+{
+    return bar_prop_impl(realm());
+}
+
+GC::Ptr<BarProp const> Window::statusbar() const
+{
+    return bar_prop_impl(realm());
+}
+
+GC::Ptr<BarProp const> Window::toolbar() const
+{
+    return bar_prop_impl(realm());
+}
path: Libraries/LibWeb/HTML/Window.cpp
user: login: Totto16
body: > Store them as `GC::Ptr<>`s. It's unfortunate to make Window bigger for something like this, but we have so few Window objects that it's not going to really matter if we add 6 pointers to it.

I find it also unnecessary to store 6 pointers in it, could we compromise on 1? I would use a `BarProperties*` as member variable, that is `nullptr` at the start, and just has 6 members, it gets allocated with all 5 members inside it, once one of them is used. So we only add 1 pointer to the most common use case  🤔 


My other idea, which really has flaws, would be something like this:
```cpp
GC::Ptr<BarProp const> Window::bar_prop_getter(JS::PropertyKey const& name)
{
    // AD-HOC: Define this property only when it's used, so that we don't waste space for it otherwise
    auto result = internal_get_own_property(name);
    if (result.has_value()) {
        auto value = result.value()->value;
        if (value.has_value()) {
            return as<BarProp const>(value.value());
        }
    }

    auto value = BarProp::create(realm());
    auto property = JS::PropertyDescriptor {
        .value = value,
        .writable = false,
        .enumerable = true,
        .configurable = false,
    };

    MUST(internal_define_own_property(name, property, {}));

    return value;
}


GC::Ptr<BarProp const> Window::locationbar()
{
    return bar_prop_getter("locationbar");
}
...

```

created_at: 2025-03-05T11:44:56Z
author_association: CONTRIBUTOR
diff_hunk: @@ -925,6 +924,44 @@ void Window::blur()
     // The blur() method steps are to do nothing.
 }
 
+static GC::Ptr<BarProp const> bar_prop_impl(JS::Realm& realm)
+{
+    // NOTE: as this is called rarely, we create a new BarProp every time, instead of storing one on the window object,
+    // which is used often and would increase memory size unnecessary
+
+    return BarProp::create(realm);
+}
+// https://html.spec.whatwg.org/multipage/nav-history-apis.html#dom-window-locationbar
+GC::Ptr<BarProp const> Window::locationbar() const
+{
+    return bar_prop_impl(realm());
+}
+
+GC::Ptr<BarProp const> Window::menubar() const
+{
+    return bar_prop_impl(realm());
+}
+
+GC::Ptr<BarProp const> Window::personalbar() const
+{
+    return bar_prop_impl(realm());
+}
+
+GC::Ptr<BarProp const> Window::scrollbars() const
+{
+    return bar_prop_impl(realm());
+}
+
+GC::Ptr<BarProp const> Window::statusbar() const
+{
+    return bar_prop_impl(realm());
+}
+
+GC::Ptr<BarProp const> Window::toolbar() const
+{
+    return bar_prop_impl(realm());
+}
path: Libraries/LibWeb/HTML/Window.cpp
user: login: ADKaster
body: Storing a JS property in the Shape of an object uses a lot more memory than 1 pointer. And doing a property lookup is a lot more expensive than a lazy pointer check. 

Just slap the 6 pointers with the usual pattern in there. If it turns into a problem, and I doubt it does, we can change every place we already use that pattern rather than micro-optimizing this one case.
created_at: 2025-03-05T12:00:29Z
author_association: MEMBER
diff_hunk: @@ -925,6 +924,44 @@ void Window::blur()
     // The blur() method steps are to do nothing.
 }
 
+static GC::Ptr<BarProp const> bar_prop_impl(JS::Realm& realm)
+{
+    // NOTE: as this is called rarely, we create a new BarProp every time, instead of storing one on the window object,
+    // which is used often and would increase memory size unnecessary
+
+    return BarProp::create(realm);
+}
+// https://html.spec.whatwg.org/multipage/nav-history-apis.html#dom-window-locationbar
+GC::Ptr<BarProp const> Window::locationbar() const
+{
+    return bar_prop_impl(realm());
+}
+
+GC::Ptr<BarProp const> Window::menubar() const
+{
+    return bar_prop_impl(realm());
+}
+
+GC::Ptr<BarProp const> Window::personalbar() const
+{
+    return bar_prop_impl(realm());
+}
+
+GC::Ptr<BarProp const> Window::scrollbars() const
+{
+    return bar_prop_impl(realm());
+}
+
+GC::Ptr<BarProp const> Window::statusbar() const
+{
+    return bar_prop_impl(realm());
+}
+
+GC::Ptr<BarProp const> Window::toolbar() const
+{
+    return bar_prop_impl(realm());
+}
path: Libraries/LibWeb/HTML/Window.cpp
user: login: Totto16
body: Alright, I bend to 3 maintainers 😄, but adding 6 pointers is really much (your arguments are valid and the window object is really not used that often, but nevertheless)

I'll just look away, while I am adding those 6 pointers😂 😓 
created_at: 2025-03-05T12:04:18Z
author_association: CONTRIBUTOR
diff_hunk: @@ -925,6 +924,44 @@ void Window::blur()
     // The blur() method steps are to do nothing.
 }
 
+static GC::Ptr<BarProp const> bar_prop_impl(JS::Realm& realm)
+{
+    // NOTE: as this is called rarely, we create a new BarProp every time, instead of storing one on the window object,
+    // which is used often and would increase memory size unnecessary
+
+    return BarProp::create(realm);
+}
+// https://html.spec.whatwg.org/multipage/nav-history-apis.html#dom-window-locationbar
+GC::Ptr<BarProp const> Window::locationbar() const
+{
+    return bar_prop_impl(realm());
+}
+
+GC::Ptr<BarProp const> Window::menubar() const
+{
+    return bar_prop_impl(realm());
+}
+
+GC::Ptr<BarProp const> Window::personalbar() const
+{
+    return bar_prop_impl(realm());
+}
+
+GC::Ptr<BarProp const> Window::scrollbars() const
+{
+    return bar_prop_impl(realm());
+}
+
+GC::Ptr<BarProp const> Window::statusbar() const
+{
+    return bar_prop_impl(realm());
+}
+
+GC::Ptr<BarProp const> Window::toolbar() const
+{
+    return bar_prop_impl(realm());
+}
path: Libraries/LibWeb/HTML/Window.cpp
user: login: AtkinsSJ
body: For reference: `Window` is 744 bytes currently. Adding 8*6 to that is less than a 7% increase.
created_at: 2025-03-05T12:07:27Z
author_association: MEMBER
diff_hunk: @@ -925,6 +924,44 @@ void Window::blur()
     // The blur() method steps are to do nothing.
 }
 
+static GC::Ptr<BarProp const> bar_prop_impl(JS::Realm& realm)
+{
+    // NOTE: as this is called rarely, we create a new BarProp every time, instead of storing one on the window object,
+    // which is used often and would increase memory size unnecessary
+
+    return BarProp::create(realm);
+}
+// https://html.spec.whatwg.org/multipage/nav-history-apis.html#dom-window-locationbar
+GC::Ptr<BarProp const> Window::locationbar() const
+{
+    return bar_prop_impl(realm());
+}
+
+GC::Ptr<BarProp const> Window::menubar() const
+{
+    return bar_prop_impl(realm());
+}
+
+GC::Ptr<BarProp const> Window::personalbar() const
+{
+    return bar_prop_impl(realm());
+}
+
+GC::Ptr<BarProp const> Window::scrollbars() const
+{
+    return bar_prop_impl(realm());
+}
+
+GC::Ptr<BarProp const> Window::statusbar() const
+{
+    return bar_prop_impl(realm());
+}
+
+GC::Ptr<BarProp const> Window::toolbar() const
+{
+    return bar_prop_impl(realm());
+}
path: Libraries/LibWeb/HTML/Window.cpp
user: login: Totto16
body: But for a feature that is used 0.00001% of the time 🙈 
But it's indeed not that much
created_at: 2025-03-05T12:10:22Z
author_association: CONTRIBUTOR
diff_hunk: @@ -925,6 +924,44 @@ void Window::blur()
     // The blur() method steps are to do nothing.
 }
 
+static GC::Ptr<BarProp const> bar_prop_impl(JS::Realm& realm)
+{
+    // NOTE: as this is called rarely, we create a new BarProp every time, instead of storing one on the window object,
+    // which is used often and would increase memory size unnecessary
+
+    return BarProp::create(realm);
+}
+// https://html.spec.whatwg.org/multipage/nav-history-apis.html#dom-window-locationbar
+GC::Ptr<BarProp const> Window::locationbar() const
+{
+    return bar_prop_impl(realm());
+}
+
+GC::Ptr<BarProp const> Window::menubar() const
+{
+    return bar_prop_impl(realm());
+}
+
+GC::Ptr<BarProp const> Window::personalbar() const
+{
+    return bar_prop_impl(realm());
+}
+
+GC::Ptr<BarProp const> Window::scrollbars() const
+{
+    return bar_prop_impl(realm());
+}
+
+GC::Ptr<BarProp const> Window::statusbar() const
+{
+    return bar_prop_impl(realm());
+}
+
+GC::Ptr<BarProp const> Window::toolbar() const
+{
+    return bar_prop_impl(realm());
+}
path: Libraries/LibWeb/HTML/Window.cpp
user: login: ADKaster
body: Look at it this way: the mental energy for someone looking at the code later is very important. We have tons of read-only and read-write properties throughout the codebase. If someone looks at the implementation of these Bar properties and sees something bespoke and tailored, they'll have to look at it and scratch their head and think "hmm why go to all this trouble?". But like you said, they're super-legacy. The maintainability of these barely used features is super high of they just follow the standard pattern. We can look at them, and say "ah yep some more readonly properties that return an IDL interface class, and not think twice about them 
created_at: 2025-03-05T12:14:11Z
author_association: MEMBER
diff_hunk: @@ -1851,5 +1911,4 @@ bool Window::find(String const& string)
 
     return result.has_value() && result->total_match_count.has_value() && *result->total_match_count > 0;
 }
-
path: Libraries/LibWeb/HTML/Window.cpp
user: login: tcl3
body: Please keep this space.
created_at: 2025-03-05T13:52:16Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2025, Ladybird contributors
path: Libraries/LibWeb/HTML/BarProp.cpp
user: login: tcl3
body: nit: The majority of copyrights with anonymous authorship are written like so `Copyright (c) 2025, the Ladybird developers.`. It would be nice if we could stay consistent.
created_at: 2025-03-29T00:47:53Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2025, Ladybird contributors
path: Libraries/LibWeb/HTML/BarProp.cpp
user: login: Totto16
body: There are a few places, where it's done that way, I just copied the first place I found something like that 😓
created_at: 2025-03-29T01:05:51Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2025, Ladybird contributors
path: Libraries/LibWeb/HTML/BarProp.h
user: login: tcl3
body: Can we change the copyright line here too, please?
created_at: 2025-03-29T01:20:18Z
author_association: MEMBER

PR comments:
user: login: ladybird-bot
created_at: 2025-03-05T11:47:56Z
body: Hello!

One or more of the commit messages in this PR do not match the Ladybird [code submission policy](https://github.com/LadybirdBrowser/ladybird/blob/master/CONTRIBUTING.md#code-submission-policy), please check the `lint_commits` CI job for more details on which commits were flagged and why.
Please do not close this PR and open another, instead modify your commit message(s) with [git commit --amend](https://docs.github.com/en/pull-requests/committing-changes-to-your-project/creating-and-editing-commits/changing-a-commit-message) and force push those changes to update this PR.
author_association: COLLABORATOR
user: login: Totto16
created_at: 2025-03-05T15:49:08Z
body: The CI failure is due a timeout in the sanitized run 🤔 not sure why though, as this PR shouldn't add that much more work for the tests.
author_association: CONTRIBUTOR