27 Commits a5df972055 ... 920170f60a

Tác giả SHA1 Thông báo Ngày
  Timothy Flynn 920170f60a LibWebView+UI: Remove native do-not-track setting 1 tuần trước cách đây
  Timothy Flynn 1be3e7fd8a LibWebView: Add do-not-track setting to about:settings 1 tuần trước cách đây
  Timothy Flynn 49dae536a7 Base: Replace bespoke input switch with native element 1 tuần trước cách đây
  Andrew Kaster 04d44c9b26 Meta: Add workaround for CMake 4.0 policy minimum changes 1 tuần trước cách đây
  Andrew Kaster 8e0786641f Meta: Explicitly enable zstd feature for tiff in vcpkg 1 tuần trước cách đây
  Andrew Kaster 6c0f97dcf2 Meta: Omit vcpkg overlay ports from style and EOF lints 1 tuần trước cách đây
  Andrew Kaster 8455d23a4b Revert "Meta: Add fontconfig and freetype vcpkg overlays" 1 tuần trước cách đây
  Andrew Kaster 1fec9d6917 Meta: Update vcpkg to latest master 1 tuần trước cách đây
  Sam Atkins 3af25b9d2f LibWeb/SVG: Mark SVG factory functions as [NewObject] 1 tuần trước cách đây
  Sam Atkins b74ec1ab7e LibWeb/SVG: Remove fixme about SVGSVGElement::getElementById() 1 tuần trước cách đây
  Sam Atkins 07adbddbcd LibWeb/SVG: Remove SVGAElement.text attribute 1 tuần trước cách đây
  Sam Atkins 02e8c0e1d1 LibWeb/HTML: Allow throwing SecurityError for push/replaceState() abuse 1 tuần trước cách đây
  Sam Atkins 7367150536 LibWeb/HTML: Update FIXME to not reset form-associated custom elements 1 tuần trước cách đây
  R-Goc 5226a566e9 AK: Modify IntrusiveRedBlackTree for Windows 1 tháng trước cách đây
  Timothy Flynn e879fd29b3 Base: Use correct color code for Slate Blue 100 1 tuần trước cách đây
  Sam Atkins 405785f584 Tests: Disable 3 tests that are flaky on CI 1 tuần trước cách đây
  Sam Atkins 86b57a5205 LibWeb/CSS: Use font_format_is_supported() when parsing font sources 2 tuần trước cách đây
  Sam Atkins bd7a08da3b Tests: Reimport font-stretch tests as font-width 1 tuần trước cách đây
  Tim Ledbetter cbb169820a LibWeb/CSS: Implement the `CSSImportRule.media` attribute 1 tuần trước cách đây
  Tim Ledbetter b93d2b7be2 IDLGenerators: Don't attempt to set null `[PutForwards]` attribute 1 tuần trước cách đây
  Tim Ledbetter ac19b0cda8 LibWeb/CSS: Support media queries in import at-rules 1 tuần trước cách đây
  Timothy Flynn c1fe912bf9 UI/AppKit: Implement an autocomplete view for the location bar 1 tuần trước cách đây
  Timothy Flynn 60dd5cc4ef UI/Qt: Migrate to LibWebView's autocomplete engine 1 tuần trước cách đây
  Timothy Flynn a87c264088 UI/Qt: Add a couple of missing includes 1 tuần trước cách đây
  Timothy Flynn 5d2e6ffe30 LibWebView: Add autocomplete settings to about:settings 1 tuần trước cách đây
  Timothy Flynn 92e1d297be LibRequests: Protect Request callbacks against stopped requests 1 tuần trước cách đây
  Timothy Flynn 0de017df9b LibRequests: Move NetworkError stringification to LibRequests 1 tuần trước cách đây
89 tập tin đã thay đổi với 1251 bổ sung1566 xóa
  1. 7 0
      AK/IntrusiveRedBlackTree.h
  2. 141 67
      Base/res/ladybird/about-pages/settings.html
  3. 11 51
      Base/res/ladybird/ladybird.css
  4. 1 1
      CMakeLists.txt
  5. 1 1
      Libraries/LibRequests/CMakeLists.txt
  6. 51 0
      Libraries/LibRequests/NetworkError.h
  7. 0 23
      Libraries/LibRequests/NetworkErrorEnum.h
  8. 16 0
      Libraries/LibRequests/Request.cpp
  9. 1 1
      Libraries/LibRequests/Request.h
  10. 17 5
      Libraries/LibWeb/CSS/CSSImportRule.cpp
  11. 4 2
      Libraries/LibWeb/CSS/CSSImportRule.h
  12. 1 1
      Libraries/LibWeb/CSS/CSSImportRule.idl
  13. 2 2
      Libraries/LibWeb/CSS/Parser/Helpers.cpp
  14. 2 2
      Libraries/LibWeb/CSS/Parser/Parser.cpp
  15. 2 2
      Libraries/LibWeb/CSS/Parser/Parser.h
  16. 5 13
      Libraries/LibWeb/CSS/Parser/RuleParsing.cpp
  17. 3 2
      Libraries/LibWeb/HTML/History.cpp
  18. 1 1
      Libraries/LibWeb/HTML/Parser/HTMLParser.cpp
  19. 1 25
      Libraries/LibWeb/Loader/ResourceLoader.cpp
  20. 0 2
      Libraries/LibWeb/SVG/SVGAElement.idl
  21. 9 10
      Libraries/LibWeb/SVG/SVGSVGElement.idl
  22. 194 0
      Libraries/LibWebView/Autocomplete.cpp
  23. 44 0
      Libraries/LibWebView/Autocomplete.h
  24. 1 0
      Libraries/LibWebView/CMakeLists.txt
  25. 2 0
      Libraries/LibWebView/Forward.h
  26. 46 0
      Libraries/LibWebView/Settings.cpp
  27. 16 0
      Libraries/LibWebView/Settings.h
  28. 7 5
      Libraries/LibWebView/ViewImplementation.cpp
  29. 1 2
      Libraries/LibWebView/ViewImplementation.h
  30. 41 7
      Libraries/LibWebView/WebUI/SettingsUI.cpp
  31. 7 1
      Libraries/LibWebView/WebUI/SettingsUI.h
  32. 0 3
      Meta/CMake/all_the_debug_macros.cmake
  33. 5 0
      Meta/CMake/vcpkg/generate_vcpkg_toolchain_variables.cmake
  34. 0 13
      Meta/CMake/vcpkg/overlay-ports/fontconfig/emscripten.diff
  35. 0 14
      Meta/CMake/vcpkg/overlay-ports/fontconfig/fix-wasm-shared-memory-atomics.patch
  36. 0 130
      Meta/CMake/vcpkg/overlay-ports/fontconfig/libgetopt.patch
  37. 0 19
      Meta/CMake/vcpkg/overlay-ports/fontconfig/no-etc-symlinks.patch
  38. 0 109
      Meta/CMake/vcpkg/overlay-ports/fontconfig/portfile.cmake
  39. 0 9
      Meta/CMake/vcpkg/overlay-ports/fontconfig/usage
  40. 0 51
      Meta/CMake/vcpkg/overlay-ports/fontconfig/vcpkg-cmake-wrapper.cmake.in
  41. 0 60
      Meta/CMake/vcpkg/overlay-ports/fontconfig/vcpkg.json
  42. 0 65
      Meta/CMake/vcpkg/overlay-ports/freetype/0003-Fix-UWP.patch
  43. 0 21
      Meta/CMake/vcpkg/overlay-ports/freetype/brotli-static.patch
  44. 0 13
      Meta/CMake/vcpkg/overlay-ports/freetype/bzip2.patch
  45. 0 40
      Meta/CMake/vcpkg/overlay-ports/freetype/fix-exports.patch
  46. 0 98
      Meta/CMake/vcpkg/overlay-ports/freetype/portfile.cmake
  47. 0 13
      Meta/CMake/vcpkg/overlay-ports/freetype/subpixel-rendering.patch
  48. 0 4
      Meta/CMake/vcpkg/overlay-ports/freetype/usage
  49. 0 95
      Meta/CMake/vcpkg/overlay-ports/freetype/vcpkg-cmake-wrapper.cmake
  50. 0 55
      Meta/CMake/vcpkg/overlay-ports/freetype/vcpkg.json
  51. 2 1
      Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/IDLGenerators.cpp
  52. 2 0
      Meta/check-newlines-at-eof.py
  53. 2 0
      Meta/check-style.py
  54. 0 1
      Meta/gn/secondary/Ladybird/BUILD.gn
  55. 1 1
      Services/RequestServer/ConnectionFromClient.cpp
  56. 1 1
      Services/RequestServer/RequestClient.ipc
  57. 32 0
      Tests/LibWeb/Ref/input/wpt-import/css/css-cascade/import-conditional-001.html
  58. 12 0
      Tests/LibWeb/TestConfig.ini
  59. 18 3
      Tests/LibWeb/Text/expected/wpt-import/css/css-fonts/parsing/font-width-computed.txt
  60. 6 2
      Tests/LibWeb/Text/expected/wpt-import/css/css-fonts/parsing/font-width-invalid.txt
  61. 18 3
      Tests/LibWeb/Text/expected/wpt-import/css/css-fonts/parsing/font-width-valid.txt
  62. 0 41
      Tests/LibWeb/Text/input/wpt-import/css/css-fonts/parsing/font-stretch-computed.html
  63. 0 21
      Tests/LibWeb/Text/input/wpt-import/css/css-fonts/parsing/font-stretch-invalid.html
  64. 0 32
      Tests/LibWeb/Text/input/wpt-import/css/css-fonts/parsing/font-stretch-valid.html
  65. 43 0
      Tests/LibWeb/Text/input/wpt-import/css/css-fonts/parsing/font-width-computed.html
  66. 23 0
      Tests/LibWeb/Text/input/wpt-import/css/css-fonts/parsing/font-width-invalid.html
  67. 34 0
      Tests/LibWeb/Text/input/wpt-import/css/css-fonts/parsing/font-width-valid.html
  68. 1 1
      Toolchain/BuildVcpkg.py
  69. 1 0
      UI/AppKit/CMakeLists.txt
  70. 33 0
      UI/AppKit/Interface/Autocomplete.h
  71. 203 0
      UI/AppKit/Interface/Autocomplete.mm
  72. 71 10
      UI/AppKit/Interface/TabController.mm
  73. 0 172
      UI/Qt/AutoComplete.cpp
  74. 0 94
      UI/Qt/AutoComplete.h
  75. 43 0
      UI/Qt/Autocomplete.cpp
  76. 35 0
      UI/Qt/Autocomplete.h
  77. 0 8
      UI/Qt/BrowserWindow.cpp
  78. 1 0
      UI/Qt/BrowserWindow.h
  79. 2 2
      UI/Qt/CMakeLists.txt
  80. 13 17
      UI/Qt/LocationEdit.cpp
  81. 6 4
      UI/Qt/LocationEdit.h
  82. 0 35
      UI/Qt/Settings.cpp
  83. 0 13
      UI/Qt/Settings.h
  84. 0 53
      UI/Qt/SettingsDialog.cpp
  85. 0 5
      UI/Qt/SettingsDialog.h
  86. 0 5
      UI/Qt/Tab.cpp
  87. 0 2
      UI/Qt/Tab.h
  88. 1 0
      UI/Qt/TabBar.cpp
  89. 7 1
      vcpkg.json

+ 7 - 0
AK/IntrusiveRedBlackTree.h

@@ -174,7 +174,14 @@ private:
 
     static V* node_to_value(TreeNode& node)
     {
+#ifdef AK_OS_WINDOWS
+        // NOTE: https://learn.microsoft.com/en-us/cpp/build/reference/vmb-vmg-representation-method?view=msvc-170
+        static_assert(sizeof(member) == 4);
+        auto distance = bit_cast<u8*>(static_cast<FlatPtr>(bit_cast<u32>(member)));
+        return bit_cast<V*>(bit_cast<u8*>(&node) - distance);
+#else
         return bit_cast<V*>(bit_cast<u8*>(&node) - bit_cast<u8*>(member));
+#endif
     }
 };
 

+ 141 - 67
Base/res/ladybird/about-pages/settings.html

@@ -52,6 +52,12 @@
                 float: left;
             }
 
+            hr {
+                height: 1px;
+                background-color: var(--border-color);
+                border: none;
+            }
+
             .card {
                 background-color: var(--card-background-color);
 
@@ -72,6 +78,10 @@
                 padding: 20px;
             }
 
+            .card-body > hr {
+                margin: 0 8px 16px 8px;
+            }
+
             .card-group {
                 margin-bottom: 20px;
             }
@@ -80,6 +90,12 @@
                 margin-bottom: 0;
             }
 
+            .toggle-container {
+                display: flex;
+                align-items: center;
+                justify-content: space-between;
+            }
+
             .permission-container {
                 display: flex;
                 align-items: center;
@@ -165,10 +181,6 @@
             }
 
             dialog .dialog-body hr {
-                height: 1px;
-                background-color: var(--border-color);
-                border: none;
-
                 margin: 8px 4px 10px 4px;
             }
 
@@ -281,19 +293,28 @@
         <div class="card">
             <div class="card-header">Search</div>
             <div class="card-body">
-                <div class="card-group">
-                    <div class="toggle-container">
-                        <label for="search-enabled">Enable Search</label>
-                        <label class="toggle">
-                            <input id="search-enabled" type="checkbox" />
-                            <span class="toggle-button"></span>
-                        </label>
-                    </div>
+                <div class="card-group toggle-container">
+                    <label for="search-toggle">Enable Search</label>
+                    <input id="search-toggle" type="checkbox" switch />
                 </div>
-                <div id="search-engine-list" class="card-group hidden">
+                <div class="card-group hidden">
                     <label for="search-engine">Default Search Engine</label>
                     <select id="search-engine">
-                        <option value="">Please Select a Search Engine</option>
+                        <option value="">Please select a search engine</option>
+                        <hr />
+                    </select>
+                </div>
+
+                <hr />
+
+                <div class="card-group toggle-container">
+                    <label for="autocomplete-toggle">Enable Autocomplete</label>
+                    <input id="autocomplete-toggle" type="checkbox" switch />
+                </div>
+                <div class="card-group hidden">
+                    <label for="autocomplete-engine">Default Autocomplete Engine</label>
+                    <select id="autocomplete-engine">
+                        <option value="">Please select an autocomplete engine</option>
                         <hr />
                     </select>
                 </div>
@@ -313,6 +334,16 @@
             </div>
         </div>
 
+        <div class="card">
+            <div class="card-header">Privacy</div>
+            <div class="card-body">
+                <div class="card-group toggle-container">
+                    <label for="do-not-track-toggle">Send web sites a "Do Not Track" request</label>
+                    <input id="do-not-track-toggle" type="checkbox" switch />
+                </div>
+            </div>
+        </div>
+
         <div class="button-container">
             <button id="restore-defaults" class="primary-button">Restore&nbsp;Defaults</button>
         </div>
@@ -325,10 +356,7 @@
             <div class="dialog-body">
                 <div class="toggle-container">
                     <label for="site-settings-global">Enable on all sites</label>
-                    <label class="toggle">
-                        <input id="site-settings-global" type="checkbox" />
-                        <span class="toggle-button"></span>
-                    </label>
+                    <input id="site-settings-global" type="checkbox" switch />
                 </div>
                 <hr />
                 <label>Allowlist</label>
@@ -347,9 +375,10 @@
 
         <script>
             const newTabPageURL = document.querySelector("#new-tab-page-url");
-            const searchEngineList = document.querySelector("#search-engine-list");
-            const searchEnabled = document.querySelector("#search-enabled");
+            const searchToggle = document.querySelector("#search-toggle");
             const searchEngine = document.querySelector("#search-engine");
+            const autocompleteToggle = document.querySelector("#autocomplete-toggle");
+            const autocompleteEngine = document.querySelector("#autocomplete-engine");
             const autoplaySettings = document.querySelector("#autoplay-settings");
             const siteSettings = document.querySelector("#site-settings");
             const siteSettingsAdd = document.querySelector("#site-settings-add");
@@ -359,6 +388,7 @@
             const siteSettingsInput = document.querySelector("#site-settings-input");
             const siteSettingsRemoveAll = document.querySelector("#site-settings-remove-all");
             const siteSettingsTitle = document.querySelector("#site-settings-title");
+            const doNotTrackToggle = document.querySelector("#do-not-track-toggle");
             const restoreDefaults = document.querySelector("#restore-defaults");
 
             window.settings = {};
@@ -372,57 +402,29 @@
                 newTabPageURL.classList.remove("error");
                 newTabPageURL.value = window.settings.newTabPageURL;
 
-                const searchEngineName = window.settings.searchEngine?.name;
+                const renderEngineSettings = (type, setting) => {
+                    const [name, toggle, engine] = engineForType(type);
 
-                if (searchEngineName) {
-                    searchEnabled.checked = true;
-                    searchEngine.value = searchEngineName;
-                } else {
-                    searchEnabled.checked = false;
-                }
+                    if (setting?.name) {
+                        toggle.checked = true;
+                        engine.value = setting?.name;
+                    } else {
+                        toggle.checked = false;
+                    }
 
-                renderSearchEngine();
+                    renderEngine(type);
+                };
+
+                renderEngineSettings(Engine.search, window.settings.searchEngine);
+                renderEngineSettings(Engine.autocomplete, window.settings.autocompleteEngine);
 
                 const siteSetting = currentSiteSetting();
 
                 if (siteSetting === "autoplay") {
                     showSiteSettings("Autoplay", window.settings.autoplay);
                 }
-            };
 
-            const loadSearchEngines = engines => {
-                for (const engine of engines) {
-                    const option = document.createElement("option");
-                    option.text = engine;
-                    option.value = engine;
-
-                    searchEngine.add(option);
-                }
-            };
-
-            const renderSearchEngine = () => {
-                if (searchEnabled.checked) {
-                    searchEngineList.classList.remove("hidden");
-                } else {
-                    searchEngineList.classList.add("hidden");
-                }
-
-                if (searchEnabled.checked && searchEngine.selectedIndex !== 0) {
-                    searchEngine.item(0).disabled = true;
-                } else if (!searchEnabled.checked) {
-                    searchEngine.item(0).disabled = false;
-                    searchEngine.selectedIndex = 0;
-                }
-            };
-
-            const saveSearchEngine = () => {
-                if (searchEnabled.checked && searchEngine.selectedIndex !== 0) {
-                    ladybird.sendMessage("setSearchEngine", searchEngine.value);
-                } else if (!searchEnabled.checked) {
-                    ladybird.sendMessage("setSearchEngine", null);
-                }
-
-                renderSearchEngine();
+                doNotTrackToggle.checked = window.settings.doNotTrack;
             };
 
             newTabPageURL.addEventListener("change", () => {
@@ -442,8 +444,75 @@
                 }, 1000);
             });
 
-            searchEnabled.addEventListener("change", saveSearchEngine);
-            searchEngine.addEventListener("change", saveSearchEngine);
+            const Engine = Object.freeze({
+                search: 1,
+                autocomplete: 2,
+            });
+
+            const engineForType = engine => {
+                if (engine === Engine.search) {
+                    return ["Search", searchToggle, searchEngine];
+                }
+                if (engine === Engine.autocomplete) {
+                    return ["Autocomplete", autocompleteToggle, autocompleteEngine];
+                }
+                throw Error(`Unrecognized engine type ${engine}`);
+            };
+
+            const loadEngines = (type, engines) => {
+                const [name, toggle, engine] = engineForType(type);
+
+                for (const engineName of engines) {
+                    const option = document.createElement("option");
+                    option.text = engineName;
+                    option.value = engineName;
+
+                    engine.add(option);
+                }
+            };
+
+            const renderEngine = type => {
+                const [name, toggle, engine] = engineForType(type);
+
+                if (toggle.checked) {
+                    engine.parentElement.classList.remove("hidden");
+                } else {
+                    engine.parentElement.classList.add("hidden");
+                }
+
+                if (toggle.checked && engine.selectedIndex !== 0) {
+                    engine.item(0).disabled = true;
+                } else if (!toggle.checked) {
+                    engine.item(0).disabled = false;
+                    engine.selectedIndex = 0;
+                }
+            };
+
+            const saveEngine = type => {
+                const [name, toggle, engine] = engineForType(type);
+
+                if (toggle.checked && engine.selectedIndex !== 0) {
+                    ladybird.sendMessage(`set${name}Engine`, engine.value);
+                } else if (!toggle.checked) {
+                    ladybird.sendMessage(`set${name}Engine`, null);
+                }
+
+                renderEngine(type);
+            };
+
+            const setSaveEngineListeners = type => {
+                const [name, toggle, engine] = engineForType(type);
+
+                toggle.addEventListener("change", () => {
+                    saveEngine(type);
+                });
+                engine.addEventListener("change", () => {
+                    saveEngine(type);
+                });
+            };
+
+            setSaveEngineListeners(Engine.search);
+            setSaveEngineListeners(Engine.autocomplete);
 
             const forciblyEnableSiteSettings = settings => {
                 settings.forEach(setting => {
@@ -553,6 +622,10 @@
                 event.stopPropagation();
             });
 
+            doNotTrackToggle.addEventListener("change", () => {
+                ladybird.sendMessage("setDoNotTrack", doNotTrackToggle.checked);
+            });
+
             restoreDefaults.addEventListener("click", () => {
                 ladybird.sendMessage("restoreDefaultSettings");
             });
@@ -576,7 +649,7 @@
             });
 
             document.addEventListener("WebUILoaded", () => {
-                ladybird.sendMessage("loadAvailableSearchEngines");
+                ladybird.sendMessage("loadAvailableEngines");
                 ladybird.sendMessage("loadCurrentSettings");
                 ladybird.sendMessage("loadForciblyEnabledSiteSettings");
             });
@@ -584,8 +657,9 @@
             document.addEventListener("WebUIMessage", event => {
                 if (event.detail.name === "loadSettings") {
                     loadSettings(event.detail.data);
-                } else if (event.detail.name === "loadSearchEngines") {
-                    loadSearchEngines(event.detail.data);
+                } else if (event.detail.name === "loadEngines") {
+                    loadEngines(Engine.search, event.detail.data.search);
+                    loadEngines(Engine.autocomplete, event.detail.data.autocomplete);
                 } else if (event.detail.name === "forciblyEnableSiteSettings") {
                     forciblyEnableSiteSettings(event.detail.data);
                 }

+ 11 - 51
Base/res/ladybird/ladybird.css

@@ -32,7 +32,7 @@
     --slate-blue-50: #97bce6;
     --slate-blue-60: #86add9;
     --slate-blue-80: #77a1d1;
-    --slate-blue-100: #8a64e5;
+    --slate-blue-100: #6d98cc;
     --slate-blue-300: #5c8ecc;
     --slate-blue-500: #5484bf;
     --slate-blue-900: #4872a3;
@@ -146,67 +146,27 @@ select:focus {
     outline: none;
 }
 
-/**
- * Create a toggle switch as a checkbox alternative:
- *
- * <div class="toggle-container">
- *     <label for="your-toggle">Toggle Label</label>
- *     <label class="toggle">
- *         <input id="your-toggle" type="checkbox" checked />
- *         <span class="toggle-button"></span>
- *     </label>
- * </div>
- */
-
-.toggle-container {
-    display: flex;
-    align-items: center;
-    justify-content: space-between;
-}
-
-.toggle-container .toggle {
+input[type="checkbox"][switch] {
     width: 50px;
     height: 24px;
 
-    display: inline-block;
-    position: relative;
-}
-
-.toggle-container .toggle input {
-    display: none;
-}
-
-.toggle-container .toggle-button {
     background-color: var(--toggle-background-color);
-    border-radius: 24px;
+    cursor: pointer;
 
-    position: absolute;
-    top: 0;
-    right: 0;
-    bottom: 0;
-    left: 0;
+    outline: none;
+}
 
-    cursor: pointer;
+input[type="checkbox"][switch]:checked {
+    background-color: var(--violet-100);
 }
 
-.toggle-container .toggle-button:before {
+input[type="checkbox"][switch]::before {
     background-color: white;
-    border-radius: 50%;
+    border: 0.6em solid white;
 
-    content: "";
-
-    width: 18px;
-    height: 18px;
-
-    position: absolute;
-    bottom: 3px;
     left: 3px;
 }
 
-.toggle-container input:checked + .toggle-button {
-    background-color: var(--violet-100);
-}
-
-.toggle-container input:checked + .toggle-button:before {
-    transform: translateX(26px);
+input[type="checkbox"][switch]:checked::before {
+    left: calc(100% - 1.3em);
 }

+ 1 - 1
CMakeLists.txt

@@ -79,7 +79,7 @@ if (ENABLE_QT AND ENABLE_GUI_TARGETS)
     set(CMAKE_AUTOMOC ON)
     set(CMAKE_AUTORCC ON)
     set(CMAKE_AUTOUIC ON)
-    find_package(Qt6 REQUIRED COMPONENTS Core Widgets Network)
+    find_package(Qt6 REQUIRED COMPONENTS Core Widgets)
 endif()
 
 # We need to find OpenSSL in order to link it explicitly with all targets.

+ 1 - 1
Libraries/LibRequests/CMakeLists.txt

@@ -1,5 +1,5 @@
 set(SOURCES
-    NetworkErrorEnum.h
+    NetworkError.h
     Request.cpp
     RequestClient.cpp
     WebSocket.cpp

+ 51 - 0
Libraries/LibRequests/NetworkError.h

@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2024, the Ladybird developers.
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <AK/StringView.h>
+
+namespace Requests {
+
+enum class NetworkError {
+    UnableToResolveProxy,
+    UnableToResolveHost,
+    UnableToConnect,
+    TimeoutReached,
+    TooManyRedirects,
+    SSLHandshakeFailed,
+    SSLVerificationFailed,
+    MalformedUrl,
+    Unknown
+};
+
+constexpr StringView network_error_to_string(NetworkError network_error)
+{
+    switch (network_error) {
+    case NetworkError::UnableToResolveProxy:
+        return "Unable to resolve proxy"sv;
+    case NetworkError::UnableToResolveHost:
+        return "Unable to resolve host"sv;
+    case NetworkError::UnableToConnect:
+        return "Unable to connect"sv;
+    case NetworkError::TimeoutReached:
+        return "Timeout reached"sv;
+    case NetworkError::TooManyRedirects:
+        return "Too many redirects"sv;
+    case NetworkError::SSLHandshakeFailed:
+        return "SSL handshake failed"sv;
+    case NetworkError::SSLVerificationFailed:
+        return "SSL verification failed"sv;
+    case NetworkError::MalformedUrl:
+        return "The URL is not formatted properly"sv;
+    case NetworkError::Unknown:
+        return "An unexpected network error occurred"sv;
+    }
+
+    VERIFY_NOT_REACHED();
+}
+
+}

+ 0 - 23
Libraries/LibRequests/NetworkErrorEnum.h

@@ -1,23 +0,0 @@
-/*
- * Copyright (c) 2024, the Ladybird developers.
- *
- * SPDX-License-Identifier: BSD-2-Clause
- */
-
-#pragma once
-
-namespace Requests {
-
-enum class NetworkError {
-    UnableToResolveProxy,
-    UnableToResolveHost,
-    UnableToConnect,
-    TimeoutReached,
-    TooManyRedirects,
-    SSLHandshakeFailed,
-    SSLVerificationFailed,
-    MalformedUrl,
-    Unknown
-};
-
-}

+ 16 - 0
Libraries/LibRequests/Request.cpp

@@ -30,6 +30,10 @@ bool Request::stop()
 
 void Request::set_request_fd(Badge<Requests::RequestClient>, int fd)
 {
+    // If the request was stopped while this IPC was in-flight, just bail.
+    if (!m_internal_stream_data)
+        return;
+
     VERIFY(m_fd == -1);
     m_fd = fd;
 
@@ -117,6 +121,10 @@ void Request::set_up_internal_stream_data(DataReceived on_data_available)
 
     auto user_on_finish = move(on_finish);
     on_finish = [this](auto total_size, auto const& timing_info, auto network_error) {
+        // If the request was stopped while this IPC was in-flight, just bail.
+        if (!m_internal_stream_data)
+            return;
+
         m_internal_stream_data->total_size = total_size;
         m_internal_stream_data->network_error = network_error;
         m_internal_stream_data->timing_info = timing_info;
@@ -125,6 +133,10 @@ void Request::set_up_internal_stream_data(DataReceived on_data_available)
     };
 
     m_internal_stream_data->on_finish = [this, user_on_finish = move(user_on_finish)]() {
+        // If the request was stopped while this IPC was in-flight, just bail.
+        if (!m_internal_stream_data)
+            return;
+
         if (!m_internal_stream_data->user_finish_called && (!m_internal_stream_data->read_stream || m_internal_stream_data->read_stream->is_eof())) {
             m_internal_stream_data->user_finish_called = true;
             user_on_finish(m_internal_stream_data->total_size, m_internal_stream_data->timing_info, m_internal_stream_data->network_error);
@@ -135,6 +147,10 @@ void Request::set_up_internal_stream_data(DataReceived on_data_available)
         static constexpr size_t buffer_size = 256 * KiB;
         static char buffer[buffer_size];
 
+        // If the request was stopped while this IPC was in-flight, just bail.
+        if (!m_internal_stream_data)
+            return;
+
         do {
             auto result = m_internal_stream_data->read_stream->read_some({ buffer, buffer_size });
             if (result.is_error() && (!result.error().is_errno() || (result.error().is_errno() && result.error().code() != EINTR)))

+ 1 - 1
Libraries/LibRequests/Request.h

@@ -14,7 +14,7 @@
 #include <AK/WeakPtr.h>
 #include <LibCore/Notifier.h>
 #include <LibHTTP/HeaderMap.h>
-#include <LibRequests/NetworkErrorEnum.h>
+#include <LibRequests/NetworkError.h>
 #include <LibRequests/RequestTimingInfo.h>
 
 namespace Requests {

+ 17 - 5
Libraries/LibWeb/CSS/CSSImportRule.cpp

@@ -23,17 +23,18 @@ namespace Web::CSS {
 
 GC_DEFINE_ALLOCATOR(CSSImportRule);
 
-GC::Ref<CSSImportRule> CSSImportRule::create(URL::URL url, DOM::Document& document, RefPtr<Supports> supports)
+GC::Ref<CSSImportRule> CSSImportRule::create(URL::URL url, DOM::Document& document, RefPtr<Supports> supports, Vector<NonnullRefPtr<MediaQuery>> media_query_list)
 {
     auto& realm = document.realm();
-    return realm.create<CSSImportRule>(move(url), document, supports);
+    return realm.create<CSSImportRule>(move(url), document, supports, move(media_query_list));
 }
 
-CSSImportRule::CSSImportRule(URL::URL url, DOM::Document& document, RefPtr<Supports> supports)
+CSSImportRule::CSSImportRule(URL::URL url, DOM::Document& document, RefPtr<Supports> supports, Vector<NonnullRefPtr<MediaQuery>> media_query_list)
     : CSSRule(document.realm(), Type::Import)
     , m_url(move(url))
     , m_document(document)
     , m_supports(supports)
+    , m_media_query_list(move(media_query_list))
 {
 }
 
@@ -76,7 +77,9 @@ String CSSImportRule::serialized() const
     if (m_supports)
         builder.appendff(" supports({})", m_supports->to_string());
 
-    // FIXME: 3. If the rule’s associated media list is not empty, a single SPACE (U+0020) followed by the result of performing serialize a media query list on the media list.
+    // 3. If the rule’s associated media list is not empty, a single SPACE (U+0020) followed by the result of performing serialize a media query list on the media list.
+    if (!m_media_query_list.is_empty())
+        builder.appendff(" {}", serialize_a_media_query_list(m_media_query_list));
 
     // 4. The string ";", i.e., SEMICOLON (U+003B).
     builder.append(';');
@@ -148,7 +151,7 @@ void CSSImportRule::fetch()
             }
             auto decoded = decoded_or_error.release_value();
 
-            auto* imported_style_sheet = parse_css_stylesheet(Parser::ParsingParams(*strong_this->m_document, strong_this->url()), decoded, strong_this->url());
+            auto* imported_style_sheet = parse_css_stylesheet(Parser::ParsingParams(*strong_this->m_document, strong_this->url()), decoded, strong_this->url(), strong_this->m_media_query_list);
 
             // 5. Set importedStylesheet’s origin-clean flag to parentStylesheet’s origin-clean flag.
             imported_style_sheet->set_origin_clean(parent_style_sheet->is_origin_clean());
@@ -171,6 +174,15 @@ void CSSImportRule::set_style_sheet(GC::Ref<CSSStyleSheet> style_sheet)
     m_document->invalidate_style(DOM::StyleInvalidationReason::CSSImportRule);
 }
 
+// https://drafts.csswg.org/cssom/#dom-cssimportrule-media
+GC::Ptr<MediaList> CSSImportRule::media() const
+{
+    // The media attribute must return the value of the media attribute of the associated CSS style sheet.
+    if (!m_style_sheet)
+        return nullptr;
+    return m_style_sheet->media();
+}
+
 Optional<String> CSSImportRule::supports_text() const
 {
     if (!m_supports)

+ 4 - 2
Libraries/LibWeb/CSS/CSSImportRule.h

@@ -21,7 +21,7 @@ class CSSImportRule final
     GC_DECLARE_ALLOCATOR(CSSImportRule);
 
 public:
-    [[nodiscard]] static GC::Ref<CSSImportRule> create(URL::URL, DOM::Document&, RefPtr<Supports>);
+    [[nodiscard]] static GC::Ref<CSSImportRule> create(URL::URL, DOM::Document&, RefPtr<Supports>, Vector<NonnullRefPtr<MediaQuery>>);
 
     virtual ~CSSImportRule() = default;
 
@@ -31,12 +31,13 @@ public:
 
     CSSStyleSheet* loaded_style_sheet() { return m_style_sheet; }
     CSSStyleSheet const* loaded_style_sheet() const { return m_style_sheet; }
+    GC::Ptr<MediaList> media() const;
     CSSStyleSheet* style_sheet_for_bindings() { return m_style_sheet; }
 
     Optional<String> supports_text() const;
 
 private:
-    CSSImportRule(URL::URL, DOM::Document&, RefPtr<Supports>);
+    CSSImportRule(URL::URL, DOM::Document&, RefPtr<Supports>, Vector<NonnullRefPtr<MediaQuery>>);
 
     virtual void initialize(JS::Realm&) override;
     virtual void visit_edges(Cell::Visitor&) override;
@@ -51,6 +52,7 @@ private:
     URL::URL m_url;
     GC::Ptr<DOM::Document> m_document;
     RefPtr<Supports> m_supports;
+    Vector<NonnullRefPtr<MediaQuery>> m_media_query_list;
     GC::Ptr<CSSStyleSheet> m_style_sheet;
     Optional<DOM::DocumentLoadEventDelayer> m_document_load_event_delayer;
 };

+ 1 - 1
Libraries/LibWeb/CSS/CSSImportRule.idl

@@ -6,7 +6,7 @@
 [Exposed=Window]
 interface CSSImportRule : CSSRule {
     readonly attribute USVString href;
-    // FIXME: [SameObject, PutForwards=mediaText] readonly attribute MediaList media;
+    [SameObject, PutForwards=mediaText] readonly attribute MediaList media;
     [SameObject, ImplementedAs=style_sheet_for_bindings] readonly attribute CSSStyleSheet? styleSheet;
     [FIXME] readonly attribute CSSOMString? layerName;
     readonly attribute CSSOMString? supportsText;

+ 2 - 2
Libraries/LibWeb/CSS/Parser/Helpers.cpp

@@ -42,7 +42,7 @@ GC::Ref<JS::Realm> internal_css_realm()
     return *realm;
 }
 
-CSS::CSSStyleSheet* parse_css_stylesheet(CSS::Parser::ParsingParams const& context, StringView css, Optional<URL::URL> location)
+CSS::CSSStyleSheet* parse_css_stylesheet(CSS::Parser::ParsingParams const& context, StringView css, Optional<URL::URL> location, Vector<NonnullRefPtr<CSS::MediaQuery>> media_query_list)
 {
     if (css.is_empty()) {
         auto rule_list = CSS::CSSRuleList::create_empty(*context.realm);
@@ -51,7 +51,7 @@ CSS::CSSStyleSheet* parse_css_stylesheet(CSS::Parser::ParsingParams const& conte
         style_sheet->set_source_text({});
         return style_sheet;
     }
-    auto* style_sheet = CSS::Parser::Parser::create(context, css).parse_as_css_stylesheet(location);
+    auto* style_sheet = CSS::Parser::Parser::create(context, css).parse_as_css_stylesheet(location, move(media_query_list));
     // FIXME: Avoid this copy
     style_sheet->set_source_text(MUST(String::from_utf8(css)));
     return style_sheet;

+ 2 - 2
Libraries/LibWeb/CSS/Parser/Parser.cpp

@@ -119,7 +119,7 @@ Vector<Rule> Parser::parse_a_stylesheets_contents(TokenStream<T>& input)
 }
 
 // https://drafts.csswg.org/css-syntax/#parse-a-css-stylesheet
-CSSStyleSheet* Parser::parse_as_css_stylesheet(Optional<URL::URL> location)
+CSSStyleSheet* Parser::parse_as_css_stylesheet(Optional<URL::URL> location, Vector<NonnullRefPtr<MediaQuery>> media_query_list)
 {
     // To parse a CSS stylesheet, first parse a stylesheet.
     auto const& style_sheet = parse_a_stylesheet(m_token_stream, {});
@@ -138,7 +138,7 @@ CSSStyleSheet* Parser::parse_as_css_stylesheet(Optional<URL::URL> location)
     }
 
     auto rule_list = CSSRuleList::create(realm(), rules);
-    auto media_list = MediaList::create(realm(), {});
+    auto media_list = MediaList::create(realm(), move(media_query_list));
     return CSSStyleSheet::create(realm(), rule_list, media_list, move(location));
 }
 

+ 2 - 2
Libraries/LibWeb/CSS/Parser/Parser.h

@@ -87,7 +87,7 @@ class Parser {
 public:
     static Parser create(ParsingParams const&, StringView input, StringView encoding = "utf-8"sv);
 
-    CSSStyleSheet* parse_as_css_stylesheet(Optional<URL::URL> location);
+    CSSStyleSheet* parse_as_css_stylesheet(Optional<URL::URL> location, Vector<NonnullRefPtr<MediaQuery>> media_query_list = {});
 
     struct PropertiesAndCustomProperties {
         Vector<StyleProperty> properties;
@@ -512,7 +512,7 @@ private:
 
 namespace Web {
 
-CSS::CSSStyleSheet* parse_css_stylesheet(CSS::Parser::ParsingParams const&, StringView, Optional<URL::URL> location = {});
+CSS::CSSStyleSheet* parse_css_stylesheet(CSS::Parser::ParsingParams const&, StringView, Optional<URL::URL> location = {}, Vector<NonnullRefPtr<CSS::MediaQuery>> = {});
 CSS::Parser::Parser::PropertiesAndCustomProperties parse_css_style_attribute(CSS::Parser::ParsingParams const&, StringView);
 RefPtr<CSS::CSSStyleValue> parse_css_value(CSS::Parser::ParsingParams const&, StringView, CSS::PropertyID property_id = CSS::PropertyID::Invalid);
 Optional<CSS::SelectorList> parse_selector(CSS::Parser::ParsingParams const&, StringView);

+ 5 - 13
Libraries/LibWeb/CSS/Parser/RuleParsing.cpp

@@ -25,6 +25,7 @@
 #include <LibWeb/CSS/CSSStyleProperties.h>
 #include <LibWeb/CSS/CSSStyleRule.h>
 #include <LibWeb/CSS/CSSSupportsRule.h>
+#include <LibWeb/CSS/FontFace.h>
 #include <LibWeb/CSS/Parser/Parser.h>
 #include <LibWeb/CSS/PropertyName.h>
 #include <LibWeb/CSS/StyleValues/CSSKeywordValue.h>
@@ -180,7 +181,7 @@ GC::Ptr<CSSImportRule> Parser::convert_to_import_rule(AtRule const& rule)
         }
     }
 
-    // FIXME: Implement media query support.
+    auto media_query_list = parse_a_media_query_list(tokens);
 
     if (tokens.has_next_token()) {
         if constexpr (CSS_PARSER_DEBUG) {
@@ -190,7 +191,7 @@ GC::Ptr<CSSImportRule> Parser::convert_to_import_rule(AtRule const& rule)
         return {};
     }
 
-    return CSSImportRule::create(url.value(), const_cast<DOM::Document&>(*document()), supports);
+    return CSSImportRule::create(url.value(), const_cast<DOM::Document&>(*document()), supports, move(media_query_list));
 }
 
 Optional<FlyString> Parser::parse_layer_name(TokenStream<ComponentValue>& tokens, AllowBlankLayerName allow_blank_layer_name)
@@ -592,15 +593,6 @@ GC::Ptr<CSSPropertyRule> Parser::convert_to_property_rule(AtRule const& rule)
 template<typename T>
 Vector<ParsedFontFace::Source> Parser::parse_font_face_src(TokenStream<T>& component_values)
 {
-    // FIXME: Get this information from the system somehow?
-    // Format-name table: https://www.w3.org/TR/css-fonts-4/#font-format-definitions
-    auto font_format_is_supported = [](StringView name) {
-        // The spec requires us to treat opentype and truetype as synonymous.
-        if (name.is_one_of_ignoring_ascii_case("opentype"sv, "truetype"sv, "woff"sv, "woff2"sv))
-            return true;
-        return false;
-    };
-
     Vector<ParsedFontFace::Source> supported_sources;
 
     auto list_of_source_token_lists = parse_a_comma_separated_list_of_component_values(component_values);
@@ -637,7 +629,7 @@ Vector<ParsedFontFace::Source> Parser::parse_font_face_src(TokenStream<T>& compo
                 TokenStream format_tokens { function.value };
                 format_tokens.discard_whitespace();
                 auto const& format_name_token = format_tokens.consume_a_token();
-                StringView format_name;
+                FlyString format_name;
                 if (format_name_token.is(Token::Type::Ident)) {
                     format_name = format_name_token.token().ident();
                 } else if (format_name_token.is(Token::Type::String)) {
@@ -652,7 +644,7 @@ Vector<ParsedFontFace::Source> Parser::parse_font_face_src(TokenStream<T>& compo
                     continue;
                 }
 
-                format = FlyString::from_utf8(format_name).release_value_but_fixme_should_propagate_errors();
+                format = move(format_name);
             } else {
                 dbgln_if(CSS_PARSER_DEBUG, "CSSParser: @font-face src invalid (unrecognized function token `{}`); discarding.", function.name);
                 return {};

+ 3 - 2
Libraries/LibWeb/HTML/History.cpp

@@ -180,8 +180,9 @@ WebIDL::ExceptionOr<void> History::shared_history_push_replace_state(JS::Value d
     if (!document->is_fully_active())
         return WebIDL::SecurityError::create(realm(), "Cannot perform pushState or replaceState on a document that isn't fully active."_string);
 
-    // 3. Optionally, return. (For example, the user agent might disallow calls to these methods that are invoked on a timer,
-    //    or from event listeners that are not triggered in response to a clear user action, or that are invoked in rapid succession.)
+    // 3. Optionally, throw a "SecurityError" DOMException. (For example, the user agent might disallow calls to these
+    //    methods that are invoked on a timer, or from event listeners that are not triggered in response to a clear
+    //    user action, or that are invoked in rapid succession.)
 
     // 4. Let serializedData be StructuredSerializeForStorage(data). Rethrow any exceptions.
     //    FIXME: Actually rethrow exceptions here once we start using the serialized data.

+ 1 - 1
Libraries/LibWeb/HTML/Parser/HTMLParser.cpp

@@ -818,7 +818,7 @@ GC::Ref<DOM::Element> HTMLParser::create_element_for(HTMLToken const& token, Opt
     // FIXME: 12. If element has an xmlns attribute in the XMLNS namespace whose value is not exactly the same as the element's namespace, that is a parse error.
     //            Similarly, if element has an xmlns:xlink attribute in the XMLNS namespace whose value is not the XLink Namespace, that is a parse error.
 
-    // FIXME: 13. If element is a resettable element, invoke its reset algorithm. (This initializes the element's value and checkedness based on the element's attributes.)
+    // FIXME: 13. If element is a resettable element and not a form-associated custom element, then invoke its reset algorithm. (This initializes the element's value and checkedness based on the element's attributes.)
 
     // 14. If element is a form-associated element and not a form-associated custom element, the form element pointer is not null, there is no template element on the stack of open elements,
     //     element is either not listed or doesn't have a form attribute, and the intended parent is in the same tree as the element pointed to by the form element pointer,

+ 1 - 25
Libraries/LibWeb/Loader/ResourceLoader.cpp

@@ -182,30 +182,6 @@ static void log_filtered_request(LoadRequest const& request)
     dbgln("ResourceLoader: Filtered request to: \"{}\"", url_for_logging);
 }
 
-static StringView network_error_to_string_view(Requests::NetworkError const& network_error)
-{
-    switch (network_error) {
-    case Requests::NetworkError::UnableToResolveProxy:
-        return "Unable to resolve proxy"sv;
-    case Requests::NetworkError::UnableToResolveHost:
-        return "Unable to resolve host"sv;
-    case Requests::NetworkError::UnableToConnect:
-        return "Unable to connect"sv;
-    case Requests::NetworkError::TimeoutReached:
-        return "Timeout reached"sv;
-    case Requests::NetworkError::TooManyRedirects:
-        return "Too many redirects"sv;
-    case Requests::NetworkError::SSLHandshakeFailed:
-        return "SSL handshake failed"sv;
-    case Requests::NetworkError::SSLVerificationFailed:
-        return "SSL verification failed"sv;
-    case Requests::NetworkError::MalformedUrl:
-        return "The URL is not formatted properly"sv;
-    default:
-        return "An unexpected network error occurred"sv;
-    }
-}
-
 static bool should_block_request(LoadRequest const& request)
 {
     auto const& url = request.url();
@@ -462,7 +438,7 @@ void ResourceLoader::load(LoadRequest& request, GC::Root<SuccessCallback> succes
             if (network_error.has_value() || (status_code.has_value() && *status_code >= 400 && *status_code <= 599 && (payload.is_empty() || !request.is_main_resource()))) {
                 StringBuilder error_builder;
                 if (network_error.has_value())
-                    error_builder.appendff("{}", network_error_to_string_view(*network_error));
+                    error_builder.appendff("{}", Requests::network_error_to_string(*network_error));
                 else
                     error_builder.append("Load failed"sv);
 

+ 0 - 2
Libraries/LibWeb/SVG/SVGAElement.idl

@@ -14,8 +14,6 @@ interface SVGAElement : SVGGraphicsElement {
     [Reflect] attribute DOMString hreflang;
     [Reflect] attribute DOMString type;
 
-    [FIXME] attribute DOMString text;
-
     [FIXME] attribute DOMString referrerPolicy;
 
 };

+ 9 - 10
Libraries/LibWeb/SVG/SVGSVGElement.idl

@@ -20,16 +20,15 @@ interface SVGSVGElement : SVGGraphicsElement {
 
     undefined deselectAll();
 
-    // FIXME: SVGNumber createSVGNumber();
-    SVGLength createSVGLength();
-    [FIXME] SVGAngle createSVGAngle();
-    DOMPoint createSVGPoint();
-    DOMMatrix createSVGMatrix();
-    DOMRect createSVGRect();
-    SVGTransform createSVGTransform();
-    [FIXME] SVGTransform createSVGTransformFromMatrix(optional DOMMatrix2DInit matrix = {});
-
-    // NOTE: The spec says this returns `Element` but that's a bug: https://github.com/w3c/svgwg/issues/923
+    // FIXME: [NewObject] SVGNumber createSVGNumber();
+    [NewObject] SVGLength createSVGLength();
+    [FIXME, NewObject] SVGAngle createSVGAngle();
+    [NewObject] DOMPoint createSVGPoint();
+    [NewObject] DOMMatrix createSVGMatrix();
+    [NewObject] DOMRect createSVGRect();
+    [NewObject] SVGTransform createSVGTransform();
+    [FIXME, NewObject] SVGTransform createSVGTransformFromMatrix(optional DOMMatrix2DInit matrix = {});
+
     Element? getElementById(DOMString elementId);
 
     // Deprecated methods that have no effect when called,

+ 194 - 0
Libraries/LibWebView/Autocomplete.cpp

@@ -0,0 +1,194 @@
+/*
+ * Copyright (c) 2023, Cameron Youell <cameronyouell@gmail.com>
+ * Copyright (c) 2025, Tim Flynn <trflynn89@ladybird.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <AK/Find.h>
+#include <LibCore/EventLoop.h>
+#include <LibRequests/Request.h>
+#include <LibRequests/RequestClient.h>
+#include <LibURL/Parser.h>
+#include <LibURL/URL.h>
+#include <LibWebView/Application.h>
+#include <LibWebView/Autocomplete.h>
+
+namespace WebView {
+
+static constexpr auto builtin_autocomplete_engines = to_array<AutocompleteEngine>({
+    { "DuckDuckGo"sv, "https://duckduckgo.com/ac/?q={}"sv },
+    { "Google"sv, "https://www.google.com/complete/search?client=chrome&q={}"sv },
+    { "Yahoo"sv, "https://search.yahoo.com/sugg/gossip/gossip-us-ura/?output=sd1&command={}"sv },
+});
+
+ReadonlySpan<AutocompleteEngine> autocomplete_engines()
+{
+    return builtin_autocomplete_engines;
+}
+
+Optional<AutocompleteEngine const&> find_autocomplete_engine_by_name(StringView name)
+{
+    auto it = AK::find_if(builtin_autocomplete_engines.begin(), builtin_autocomplete_engines.end(),
+        [&](auto const& engine) {
+            return engine.name == name;
+        });
+
+    if (it == builtin_autocomplete_engines.end())
+        return {};
+    return *it;
+}
+
+Autocomplete::Autocomplete() = default;
+Autocomplete::~Autocomplete() = default;
+
+void Autocomplete::query_autocomplete_engine(String query)
+{
+    if (m_request) {
+        m_request->stop();
+        m_request.clear();
+    }
+
+    if (query.bytes_as_string_view().trim_whitespace().is_empty()) {
+        invoke_autocomplete_query_complete({});
+        return;
+    }
+
+    auto engine = Application::settings().autocomplete_engine();
+    if (!engine.has_value()) {
+        invoke_autocomplete_query_complete({});
+        return;
+    }
+
+    auto url_string = MUST(String::formatted(engine->query_url, URL::percent_encode(query)));
+    auto url = URL::Parser::basic_parse(url_string);
+
+    if (!url.has_value()) {
+        invoke_autocomplete_query_complete({});
+        return;
+    }
+
+    m_request = Application::request_server_client().start_request("GET"sv, *url);
+    m_query = move(query);
+
+    m_request->set_buffered_request_finished_callback(
+        [this, engine = engine.release_value()](u64, Requests::RequestTimingInfo const&, Optional<Requests::NetworkError> const& network_error, HTTP::HeaderMap const&, Optional<u32> response_code, Optional<String> const& reason_phrase, ReadonlyBytes payload) {
+            Core::deferred_invoke([this]() { m_request.clear(); });
+
+            if (network_error.has_value()) {
+                warnln("Unable to fetch autocomplete suggestions: {}", Requests::network_error_to_string(*network_error));
+                invoke_autocomplete_query_complete({});
+                return;
+            }
+            if (response_code.has_value() && *response_code >= 400) {
+                warnln("Received error response code {} from autocomplete engine: {}", *response_code, reason_phrase);
+                invoke_autocomplete_query_complete({});
+                return;
+            }
+
+            if (auto result = received_autocomplete_respsonse(engine, payload); result.is_error()) {
+                warnln("Unable to handle autocomplete response: {}", result.error());
+                invoke_autocomplete_query_complete({});
+            } else {
+                invoke_autocomplete_query_complete(result.release_value());
+            }
+        });
+}
+
+static ErrorOr<Vector<String>> parse_duckduckgo_autocomplete(JsonValue const& json)
+{
+    if (!json.is_array())
+        return Error::from_string_literal("Expected DuckDuckGo autocomplete response to be a JSON array");
+
+    Vector<String> results;
+    results.ensure_capacity(json.as_array().size());
+
+    TRY(json.as_array().try_for_each([&](JsonValue const& suggestion) -> ErrorOr<void> {
+        if (!suggestion.is_object())
+            return Error::from_string_literal("Invalid DuckDuckGo autocomplete response, expected value to be an object");
+
+        if (auto value = suggestion.as_object().get_string("phrase"sv); value.has_value())
+            results.unchecked_append(*value);
+
+        return {};
+    }));
+
+    return results;
+}
+
+static ErrorOr<Vector<String>> parse_google_autocomplete(JsonValue const& json)
+{
+    if (!json.is_array())
+        return Error::from_string_literal("Expected Google autocomplete response to be a JSON array");
+
+    auto const& values = json.as_array();
+
+    if (values.size() != 5)
+        return Error::from_string_literal("Invalid Google autocomplete response, expected 5 elements in array");
+    if (!values[1].is_array())
+        return Error::from_string_literal("Invalid Google autocomplete response, expected second element to be an array");
+
+    auto const& suggestions = values[1].as_array();
+
+    Vector<String> results;
+    results.ensure_capacity(suggestions.size());
+
+    TRY(suggestions.try_for_each([&](JsonValue const& suggestion) -> ErrorOr<void> {
+        if (!suggestion.is_string())
+            return Error::from_string_literal("Invalid Google autocomplete response, expected value to be a string");
+
+        results.unchecked_append(suggestion.as_string());
+        return {};
+    }));
+
+    return results;
+}
+
+static ErrorOr<Vector<String>> parse_yahoo_autocomplete(JsonValue const& json)
+{
+    if (!json.is_object())
+        return Error::from_string_literal("Expected Yahoo autocomplete response to be a JSON array");
+
+    auto suggestions = json.as_object().get_array("r"sv);
+    if (!suggestions.has_value())
+        return Error::from_string_literal("Invalid Yahoo autocomplete response, expected \"r\" to be an object");
+
+    Vector<String> results;
+    results.ensure_capacity(suggestions->size());
+
+    TRY(suggestions->try_for_each([&](JsonValue const& suggestion) -> ErrorOr<void> {
+        if (!suggestion.is_object())
+            return Error::from_string_literal("Invalid Yahoo autocomplete response, expected value to be an object");
+
+        auto result = suggestion.as_object().get_string("k"sv);
+        if (!result.has_value())
+            return Error::from_string_literal("Invalid Yahoo autocomplete response, expected \"k\" to be a string");
+
+        results.unchecked_append(*result);
+        return {};
+    }));
+
+    return results;
+}
+
+ErrorOr<Vector<String>> Autocomplete::received_autocomplete_respsonse(AutocompleteEngine const& engine, StringView response)
+{
+    auto json = TRY(JsonValue::from_string(response));
+
+    if (engine.name == "DuckDuckGo")
+        return parse_duckduckgo_autocomplete(json);
+    if (engine.name == "Google")
+        return parse_google_autocomplete(json);
+    if (engine.name == "Yahoo")
+        return parse_yahoo_autocomplete(json);
+
+    return Error::from_string_literal("Invalid engine name");
+}
+
+void Autocomplete::invoke_autocomplete_query_complete(Vector<String> suggestions) const
+{
+    if (on_autocomplete_query_complete)
+        on_autocomplete_query_complete(move(suggestions));
+}
+
+}

+ 44 - 0
Libraries/LibWebView/Autocomplete.h

@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2023, Cameron Youell <cameronyouell@gmail.com>
+ * Copyright (c) 2025, Tim Flynn <trflynn89@ladybird.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <AK/Error.h>
+#include <AK/Function.h>
+#include <AK/RefPtr.h>
+#include <AK/String.h>
+#include <AK/Vector.h>
+#include <LibRequests/Forward.h>
+
+namespace WebView {
+
+struct AutocompleteEngine {
+    StringView name;
+    StringView query_url;
+};
+
+ReadonlySpan<AutocompleteEngine> autocomplete_engines();
+Optional<AutocompleteEngine const&> find_autocomplete_engine_by_name(StringView name);
+
+class Autocomplete {
+public:
+    Autocomplete();
+    ~Autocomplete();
+
+    Function<void(Vector<String>)> on_autocomplete_query_complete;
+
+    void query_autocomplete_engine(String);
+
+private:
+    static ErrorOr<Vector<String>> received_autocomplete_respsonse(AutocompleteEngine const&, StringView response);
+    void invoke_autocomplete_query_complete(Vector<String> suggestions) const;
+
+    String m_query;
+    RefPtr<Requests::Request> m_request;
+};
+
+}

+ 1 - 0
Libraries/LibWebView/CMakeLists.txt

@@ -3,6 +3,7 @@ include(fontconfig)
 set(SOURCES
     Application.cpp
     Attribute.cpp
+    Autocomplete.cpp
     BrowserProcess.cpp
     ConsoleOutput.cpp
     CookieJar.cpp

+ 2 - 0
Libraries/LibWebView/Forward.h

@@ -11,6 +11,7 @@
 namespace WebView {
 
 class Application;
+class Autocomplete;
 class CookieJar;
 class Database;
 class OutOfProcessWebView;
@@ -21,6 +22,7 @@ class WebContentClient;
 class WebUI;
 
 struct Attribute;
+struct AutocompleteEngine;
 struct ConsoleOutput;
 struct CookieStorageKey;
 struct DOMNodeProperties;

+ 46 - 0
Libraries/LibWebView/Settings.cpp

@@ -24,11 +24,16 @@ static constexpr auto new_tab_page_url_key = "newTabPageURL"sv;
 static constexpr auto search_engine_key = "searchEngine"sv;
 static constexpr auto search_engine_name_key = "name"sv;
 
+static constexpr auto autocomplete_engine_key = "autocompleteEngine"sv;
+static constexpr auto autocomplete_engine_name_key = "name"sv;
+
 static constexpr auto site_setting_enabled_globally_key = "enabledGlobally"sv;
 static constexpr auto site_setting_site_filters_key = "siteFilters"sv;
 
 static constexpr auto autoplay_key = "autoplay"sv;
 
+static constexpr auto do_not_track_key = "doNotTrack"sv;
+
 static ErrorOr<JsonObject> read_settings_file(StringView settings_path)
 {
     auto settings_file = Core::File::open(settings_path, Core::File::OpenMode::Read);
@@ -81,6 +86,11 @@ Settings Settings::create(Badge<Application>)
             settings.m_search_engine = find_search_engine_by_name(*search_engine_name);
     }
 
+    if (auto autocomplete_engine = settings_json.value().get_object(autocomplete_engine_key); autocomplete_engine.has_value()) {
+        if (auto autocomplete_engine_name = autocomplete_engine->get_string(autocomplete_engine_name_key); autocomplete_engine_name.has_value())
+            settings.m_autocomplete_engine = find_autocomplete_engine_by_name(*autocomplete_engine_name);
+    }
+
     auto load_site_setting = [&](SiteSetting& site_setting, StringView key) {
         auto saved_settings = settings_json.value().get_object(key);
         if (!saved_settings.has_value())
@@ -101,6 +111,9 @@ Settings Settings::create(Badge<Application>)
 
     load_site_setting(settings.m_autoplay, autoplay_key);
 
+    if (auto do_not_track = settings_json.value().get_bool(do_not_track_key); do_not_track.has_value())
+        settings.m_do_not_track = *do_not_track ? DoNotTrack::Yes : DoNotTrack::No;
+
     return settings;
 }
 
@@ -122,6 +135,13 @@ JsonValue Settings::serialize_json() const
         settings.set(search_engine_key, move(search_engine));
     }
 
+    if (m_autocomplete_engine.has_value()) {
+        JsonObject autocomplete_engine;
+        autocomplete_engine.set(autocomplete_engine_name_key, m_autocomplete_engine->name);
+
+        settings.set(autocomplete_engine_key, move(autocomplete_engine));
+    }
+
     auto save_site_setting = [&](SiteSetting const& site_setting, StringView key) {
         JsonArray site_filters;
         site_filters.ensure_capacity(site_setting.site_filters.size());
@@ -138,6 +158,8 @@ JsonValue Settings::serialize_json() const
 
     save_site_setting(m_autoplay, autoplay_key);
 
+    settings.set(do_not_track_key, m_do_not_track == DoNotTrack::Yes);
+
     return settings;
 }
 
@@ -145,7 +167,9 @@ void Settings::restore_defaults()
 {
     m_new_tab_page_url = URL::about_newtab();
     m_search_engine.clear();
+    m_autocomplete_engine.clear();
     m_autoplay = SiteSetting {};
+    m_do_not_track = DoNotTrack::No;
 
     persist_settings();
 
@@ -175,6 +199,19 @@ void Settings::set_search_engine(Optional<StringView> search_engine_name)
         observer.search_engine_changed();
 }
 
+void Settings::set_autocomplete_engine(Optional<StringView> autocomplete_engine_name)
+{
+    if (autocomplete_engine_name.has_value())
+        m_autocomplete_engine = find_autocomplete_engine_by_name(*autocomplete_engine_name);
+    else
+        m_autocomplete_engine.clear();
+
+    persist_settings();
+
+    for (auto& observer : m_observers)
+        observer.autocomplete_engine_changed();
+}
+
 void Settings::set_autoplay_enabled_globally(bool enabled_globally)
 {
     m_autoplay.enabled_globally = enabled_globally;
@@ -215,6 +252,15 @@ void Settings::remove_all_autoplay_site_filters()
         observer.autoplay_settings_changed();
 }
 
+void Settings::set_do_not_track(DoNotTrack do_not_track)
+{
+    m_do_not_track = do_not_track;
+    persist_settings();
+
+    for (auto& observer : m_observers)
+        observer.do_not_track_changed();
+}
+
 void Settings::persist_settings()
 {
     auto settings = serialize_json();

+ 16 - 0
Libraries/LibWebView/Settings.h

@@ -11,6 +11,7 @@
 #include <AK/JsonValue.h>
 #include <AK/Optional.h>
 #include <LibURL/URL.h>
+#include <LibWebView/Autocomplete.h>
 #include <LibWebView/Forward.h>
 #include <LibWebView/SearchEngine.h>
 
@@ -23,6 +24,11 @@ struct SiteSetting {
     OrderedHashTable<String> site_filters;
 };
 
+enum class DoNotTrack {
+    No,
+    Yes,
+};
+
 class SettingsObserver {
 public:
     SettingsObserver();
@@ -30,7 +36,9 @@ public:
 
     virtual void new_tab_page_url_changed() { }
     virtual void search_engine_changed() { }
+    virtual void autocomplete_engine_changed() { }
     virtual void autoplay_settings_changed() { }
+    virtual void do_not_track_changed() { }
 };
 
 class Settings {
@@ -47,12 +55,18 @@ public:
     Optional<SearchEngine> const& search_engine() const { return m_search_engine; }
     void set_search_engine(Optional<StringView> search_engine_name);
 
+    Optional<AutocompleteEngine> const& autocomplete_engine() const { return m_autocomplete_engine; }
+    void set_autocomplete_engine(Optional<StringView> autocomplete_engine_name);
+
     SiteSetting const& autoplay_settings() const { return m_autoplay; }
     void set_autoplay_enabled_globally(bool);
     void add_autoplay_site_filter(String const&);
     void remove_autoplay_site_filter(String const&);
     void remove_all_autoplay_site_filters();
 
+    DoNotTrack do_not_track() const { return m_do_not_track; }
+    void set_do_not_track(DoNotTrack);
+
     static void add_observer(Badge<SettingsObserver>, SettingsObserver&);
     static void remove_observer(Badge<SettingsObserver>, SettingsObserver&);
 
@@ -65,7 +79,9 @@ private:
 
     URL::URL m_new_tab_page_url;
     Optional<SearchEngine> m_search_engine;
+    Optional<AutocompleteEngine> m_autocomplete_engine;
     SiteSetting m_autoplay;
+    DoNotTrack m_do_not_track { DoNotTrack::No };
 
     Vector<SettingsObserver&> m_observers;
 };

+ 7 - 5
Libraries/LibWebView/ViewImplementation.cpp

@@ -257,11 +257,6 @@ void ViewImplementation::set_preferred_languages(ReadonlySpan<String> preferred_
     client().async_set_preferred_languages(page_id(), preferred_languages);
 }
 
-void ViewImplementation::set_enable_do_not_track(bool enable)
-{
-    client().async_set_enable_do_not_track(page_id(), enable);
-}
-
 ByteString ViewImplementation::selected_text()
 {
     return client().get_selected_text(page_id());
@@ -605,6 +600,7 @@ void ViewImplementation::initialize_client(CreateNewClient create_new_client)
         client().async_debug_request(m_client_state.page_index, "spoof-user-agent"sv, *user_agents.get(*user_agent_preset));
 
     autoplay_settings_changed();
+    do_not_track_changed();
 }
 
 void ViewImplementation::handle_web_content_process_crash(LoadErrorPage load_error_page)
@@ -663,6 +659,12 @@ void ViewImplementation::autoplay_settings_changed()
         client().async_set_autoplay_allowlist(page_id(), autoplay_settings.site_filters.values());
 }
 
+void ViewImplementation::do_not_track_changed()
+{
+    auto do_not_track = Application::settings().do_not_track();
+    client().async_set_enable_do_not_track(page_id(), do_not_track == DoNotTrack::Yes);
+}
+
 static ErrorOr<LexicalPath> save_screenshot(Gfx::ShareableBitmap const& bitmap)
 {
     if (!bitmap.is_valid())

+ 1 - 2
Libraries/LibWebView/ViewImplementation.h

@@ -82,8 +82,6 @@ public:
 
     void set_preferred_languages(ReadonlySpan<String>);
 
-    void set_enable_do_not_track(bool);
-
     ByteString selected_text();
     Optional<String> selected_text_with_whitespace_collapsed();
     void select_all();
@@ -265,6 +263,7 @@ protected:
     void handle_web_content_process_crash(LoadErrorPage = LoadErrorPage::Yes);
 
     virtual void autoplay_settings_changed() override;
+    virtual void do_not_track_changed() override;
 
     struct SharedBitmap {
         i32 id { -1 };

+ 41 - 7
Libraries/LibWebView/WebUI/SettingsUI.cpp

@@ -20,15 +20,21 @@ void SettingsUI::register_interfaces()
     register_interface("restoreDefaultSettings"sv, [this](auto const&) {
         restore_default_settings();
     });
+
     register_interface("setNewTabPageURL"sv, [this](auto const& data) {
         set_new_tab_page_url(data);
     });
-    register_interface("loadAvailableSearchEngines"sv, [this](auto const&) {
-        load_available_search_engines();
+
+    register_interface("loadAvailableEngines"sv, [this](auto const&) {
+        load_available_engines();
     });
     register_interface("setSearchEngine"sv, [this](auto const& data) {
         set_search_engine(data);
     });
+    register_interface("setAutocompleteEngine"sv, [this](auto const& data) {
+        set_autocomplete_engine(data);
+    });
+
     register_interface("loadForciblyEnabledSiteSettings"sv, [this](auto const&) {
         load_forcibly_enabled_site_settings();
     });
@@ -44,6 +50,10 @@ void SettingsUI::register_interfaces()
     register_interface("removeAllSiteSettingFilters"sv, [this](auto const& data) {
         remove_all_site_setting_filters(data);
     });
+
+    register_interface("setDoNotTrack"sv, [this](auto const& data) {
+        set_do_not_track(data);
+    });
 }
 
 void SettingsUI::load_current_settings()
@@ -70,13 +80,21 @@ void SettingsUI::set_new_tab_page_url(JsonValue const& new_tab_page_url)
     WebView::Application::settings().set_new_tab_page_url(parsed_new_tab_page_url.release_value());
 }
 
-void SettingsUI::load_available_search_engines()
+void SettingsUI::load_available_engines()
 {
-    JsonArray engines;
-    for (auto const& engine : search_engines())
-        engines.must_append(engine.name);
+    JsonArray search_engines;
+    for (auto const& engine : WebView::search_engines())
+        search_engines.must_append(engine.name);
+
+    JsonArray autocomplete_engines;
+    for (auto const& engine : WebView::autocomplete_engines())
+        autocomplete_engines.must_append(engine.name);
+
+    JsonObject engines;
+    engines.set("search"sv, move(search_engines));
+    engines.set("autocomplete"sv, move(autocomplete_engines));
 
-    async_send_message("loadSearchEngines"sv, move(engines));
+    async_send_message("loadEngines"sv, move(engines));
 }
 
 void SettingsUI::set_search_engine(JsonValue const& search_engine)
@@ -87,6 +105,14 @@ void SettingsUI::set_search_engine(JsonValue const& search_engine)
         WebView::Application::settings().set_search_engine(search_engine.as_string());
 }
 
+void SettingsUI::set_autocomplete_engine(JsonValue const& autocomplete_engine)
+{
+    if (autocomplete_engine.is_null())
+        WebView::Application::settings().set_autocomplete_engine({});
+    else if (autocomplete_engine.is_string())
+        WebView::Application::settings().set_autocomplete_engine(autocomplete_engine.as_string());
+}
+
 enum class SiteSettingType {
     Autoplay,
 };
@@ -196,4 +222,12 @@ void SettingsUI::remove_all_site_setting_filters(JsonValue const& site_setting)
     load_current_settings();
 }
 
+void SettingsUI::set_do_not_track(JsonValue const& do_not_track)
+{
+    if (!do_not_track.is_bool())
+        return;
+
+    WebView::Application::settings().set_do_not_track(do_not_track.as_bool() ? DoNotTrack::Yes : DoNotTrack::No);
+}
+
 }

+ 7 - 1
Libraries/LibWebView/WebUI/SettingsUI.h

@@ -18,14 +18,20 @@ private:
 
     void load_current_settings();
     void restore_default_settings();
+
     void set_new_tab_page_url(JsonValue const&);
-    void load_available_search_engines();
+
+    void load_available_engines();
     void set_search_engine(JsonValue const&);
+    void set_autocomplete_engine(JsonValue const&);
+
     void load_forcibly_enabled_site_settings();
     void set_site_setting_enabled_globally(JsonValue const&);
     void add_site_setting_filter(JsonValue const&);
     void remove_site_setting_filter(JsonValue const&);
     void remove_all_site_setting_filters(JsonValue const&);
+
+    void set_do_not_track(JsonValue const&);
 };
 
 }

+ 0 - 3
Meta/CMake/all_the_debug_macros.cmake

@@ -89,6 +89,3 @@ set(XML_PARSER_DEBUG ON)
 # set(gn_include_dirs_DEBUG ON)
 # set(gn_ldflags_DEBUG ON)
 # set(gn_lib_dirs_DEBUG ON)
-# Third-party: fontconfig overlay
-# set(Fontconfig_LIBRARY_DEBUG ON)
-# set(UUID_LIBRARY_DEBUG ON)

+ 5 - 0
Meta/CMake/vcpkg/generate_vcpkg_toolchain_variables.cmake

@@ -17,6 +17,11 @@ if (LINUX AND NOT LAGOM_USE_LINKER)
     string(APPEND EXTRA_VCPKG_VARIABLES "set(ENV{LDFLAGS} -Wl,-z,noseparate-code)\n")
 endif()
 
+# Temporary workaround until a version of vcpkg with https://github.com/microsoft/vcpkg/pull/44712 is released
+if (CMAKE_VERSION VERSION_GREATER_EQUAL "4.0")
+    string(APPEND EXTRA_VCPKG_VARIABLES "set(ENV{CMAKE_POLICY_VERSION_MINIMUM} 3.5)\n")
+endif()
+
 file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/build-vcpkg-variables.cmake" "${EXTRA_VCPKG_VARIABLES}")
 
 # Munge the VCPKG_TRIPLET to correspond to the right one for our presets

+ 0 - 13
Meta/CMake/vcpkg/overlay-ports/fontconfig/emscripten.diff

@@ -1,13 +0,0 @@
-diff --git a/meson.build b/meson.build
-index 08d9532..37cc195 100644
---- a/meson.build
-+++ b/meson.build
-@@ -289,7 +289,7 @@ if fc_cachedir in ['yes', 'no', 'default']
-   endif
- endif
- 
--if host_machine.system() != 'windows'
-+if host_machine.system() != 'windows' and host_machine.system() != 'emscripten'
-   thread_dep = dependency('threads')
-   conf.set('HAVE_PTHREAD', 1)
-   deps += [thread_dep]

+ 0 - 14
Meta/CMake/vcpkg/overlay-ports/fontconfig/fix-wasm-shared-memory-atomics.patch

@@ -1,14 +0,0 @@
-diff --git a/meson.build b/meson.build
-index 8e78700..95bae59 100644
---- a/meson.build
-+++ b/meson.build
-@@ -112,6 +112,9 @@ check_alignofs = [
- ]
- 
- add_project_arguments('-DHAVE_CONFIG_H', language: 'c')
-+if cc.get_id() == 'clang' and host_machine.cpu_family() == 'wasm'
-+    add_project_arguments('-matomics', '-mbulk-memory', language: 'c')
-+endif
- 
- c_args = []
- 

+ 0 - 130
Meta/CMake/vcpkg/overlay-ports/fontconfig/libgetopt.patch

@@ -1,130 +0,0 @@
-diff --git a/fc-cache/meson.build b/fc-cache/meson.build
-index 5e40fac..3c3e46b 100644
---- a/fc-cache/meson.build
-+++ b/fc-cache/meson.build
-@@ -1,6 +1,7 @@
- fccache = executable('fc-cache', ['fc-cache.c', fcstdint_h, alias_headers, ft_alias_headers],
-   include_directories: [incbase, incsrc],
-   link_with: [libfontconfig],
-+  dependencies: [getopt_dep],
-   c_args: c_args,
-   install: true,
- )
-diff --git a/fc-cat/meson.build b/fc-cat/meson.build
-index f26e4b8..476c0f9 100644
---- a/fc-cat/meson.build
-+++ b/fc-cat/meson.build
-@@ -1,6 +1,7 @@
- fccat = executable('fc-cat', ['fc-cat.c', fcstdint_h, alias_headers, ft_alias_headers],
-   include_directories: [incbase, incsrc],
-   link_with: [libfontconfig],
-+  dependencies: [getopt_dep],
-   c_args: c_args,
-   install: true,
- )
-diff --git a/fc-conflist/meson.build b/fc-conflist/meson.build
-index f543cf9..f06640b 100644
---- a/fc-conflist/meson.build
-+++ b/fc-conflist/meson.build
-@@ -1,6 +1,7 @@
- fcconflist = executable('fc-conflist', ['fc-conflist.c', fcstdint_h, alias_headers, ft_alias_headers],
-   include_directories: [incbase, incsrc],
-   link_with: [libfontconfig],
-+  dependencies: [getopt_dep],
-   c_args: c_args,
-   install: true,
- )
-diff --git a/fc-list/meson.build b/fc-list/meson.build
-index 2f679d5..4b0fb62 100644
---- a/fc-list/meson.build
-+++ b/fc-list/meson.build
-@@ -1,6 +1,7 @@
- fclist = executable('fc-list', ['fc-list.c', fcstdint_h, alias_headers, ft_alias_headers],
-   include_directories: [incbase, incsrc],
-   link_with: [libfontconfig],
-+  dependencies: [getopt_dep],
-   c_args: c_args,
-   install: true,
- )
-diff --git a/fc-match/meson.build b/fc-match/meson.build
-index aca8bc8..cab4f09 100644
---- a/fc-match/meson.build
-+++ b/fc-match/meson.build
-@@ -1,6 +1,7 @@
- fcmatch = executable('fc-match', ['fc-match.c', fcstdint_h, alias_headers, ft_alias_headers],
-   include_directories: [incbase, incsrc],
-   link_with: [libfontconfig],
-+  dependencies: [getopt_dep],
-   c_args: c_args,
-   install: true,
- )
-diff --git a/fc-pattern/meson.build b/fc-pattern/meson.build
-index 07de245..b957c67 100644
---- a/fc-pattern/meson.build
-+++ b/fc-pattern/meson.build
-@@ -1,6 +1,7 @@
- fcpattern = executable('fc-pattern', ['fc-pattern.c', fcstdint_h, alias_headers, ft_alias_headers],
-   include_directories: [incbase, incsrc],
-   link_with: [libfontconfig],
-+  dependencies: [getopt_dep],
-   c_args: c_args,
-   install: true,
- )
-diff --git a/fc-query/meson.build b/fc-query/meson.build
-index d0f2dd4..940b021 100644
---- a/fc-query/meson.build
-+++ b/fc-query/meson.build
-@@ -1,7 +1,7 @@
- fcquery = executable('fc-query', ['fc-query.c', fcstdint_h, alias_headers, ft_alias_headers],
-   include_directories: [incbase, incsrc],
-   link_with: [libfontconfig],
--  dependencies: [freetype_dep],
-+  dependencies: [freetype_dep, getopt_dep],
-   c_args: c_args,
-   install: true,
- )
-diff --git a/fc-scan/meson.build b/fc-scan/meson.build
-index 4de2134..c5b2b67 100644
---- a/fc-scan/meson.build
-+++ b/fc-scan/meson.build
-@@ -1,7 +1,7 @@
- fcscan = executable('fc-scan', ['fc-scan.c', fcstdint_h, alias_headers, ft_alias_headers],
-   include_directories: [incbase, incsrc],
-   link_with: [libfontconfig],
--  dependencies: [freetype_dep],
-+  dependencies: [freetype_dep, getopt_dep],
-   c_args: c_args,
-   install: true,
- )
-diff --git a/fc-validate/meson.build b/fc-validate/meson.build
-index e2b956e..8902d59 100644
---- a/fc-validate/meson.build
-+++ b/fc-validate/meson.build
-@@ -1,7 +1,7 @@
- fcvalidate = executable('fc-validate', ['fc-validate.c', fcstdint_h, alias_headers, ft_alias_headers],
-   include_directories: [incbase, incsrc],
-   link_with: [libfontconfig],
--  dependencies: [freetype_dep],
-+  dependencies: [freetype_dep, getopt_dep],
-   c_args: c_args,
-   install: true,
- )
-diff --git a/meson.build b/meson.build
-index f616600..6d82a16 100644
---- a/meson.build
-+++ b/meson.build
-@@ -202,6 +202,14 @@ if cc.links(files('meson-cc-tests/solaris-atomic-operations.c'), name: 'Solaris
-   conf.set('HAVE_SOLARIS_ATOMIC_OPS', 1)
- endif
- 
-+if host_machine.system() == 'windows'
-+  conf.set('HAVE_GETOPT', 1)
-+  conf.set('HAVE_GETOPT_LONG', 1)
-+  getopt_dep = cc.find_library('getopt', required: false)
-+else
-+  getopt_dep = dependency('', required: false)
-+endif
-+
- 
- # Check iconv support
- iconv_dep = []

+ 0 - 19
Meta/CMake/vcpkg/overlay-ports/fontconfig/no-etc-symlinks.patch

@@ -1,19 +0,0 @@
---- a/conf.d/link_confs.py	2022-03-24 04:13:59.000982000 +0900
-+++ b/conf.d/link_confs.py	2022-03-24 04:14:46.271964000 +0900
-@@ -4,6 +4,7 @@
- import sys
- import argparse
- import platform
-+import shutil
- from pathlib import PurePath
- 
- if __name__=='__main__':
-@@ -32,7 +33,7 @@
-         except FileNotFoundError:
-             pass
-         try:
--            os.symlink(os.path.relpath(src, start=args.confpath), dst)
-+            shutil.copyfile(src, dst)
-         except NotImplementedError:
-             # Not supported on this version of Windows
-             break

+ 0 - 109
Meta/CMake/vcpkg/overlay-ports/fontconfig/portfile.cmake

@@ -1,109 +0,0 @@
-vcpkg_from_gitlab(
-    GITLAB_URL https://gitlab.com
-    OUT_SOURCE_PATH SOURCE_PATH
-    REPO freedesktop-sdk/mirrors/freedesktop/fontconfig/fontconfig
-    REF ${VERSION}
-    SHA512 daa6d1e6058e12c694d9e1512e09be957ff7f3fa375246b9d13eb0a8cf2f21e1512a5cabe93f270e96790e2c20420bf7422d213e43ab9749da3255286ea65a7c
-    HEAD_REF master
-    PATCHES
-        emscripten.diff
-        no-etc-symlinks.patch
-        libgetopt.patch
-        fix-wasm-shared-memory-atomics.patch
-)
-
-set(options "")
-if("nls" IN_LIST FEATURES)
-    list(APPEND options "-Dnls=enabled")
-else()
-    list(APPEND options "-Dnls=disabled")
-endif()
-if("tools" IN_LIST FEATURES)
-    list(APPEND options "-Dtools=enabled")
-else()
-    list(APPEND options "-Dtools=disabled")
-endif()
-
-vcpkg_configure_meson(
-    SOURCE_PATH "${SOURCE_PATH}"
-    OPTIONS
-        ${options}
-        -Ddoc=disabled
-        -Dcache-build=disabled
-        -Diconv=enabled
-        -Dtests=disabled
-    ADDITIONAL_BINARIES
-        "gperf = ['${CURRENT_HOST_INSTALLED_DIR}/tools/gperf/gperf${VCPKG_HOST_EXECUTABLE_SUFFIX}']"
-)
-
-# https://www.freedesktop.org/software/fontconfig/fontconfig-user.html
-# Adding OPTIONS for e.g. baseconfig-dir etc. won't work since meson will try to install into those dirs!
-# Since adding OPTIONS does not work use a replacement in the generated config.h instead
-set(replacement "")
-if(VCPKG_TARGET_IS_WINDOWS)
-    set(replacement "**invalid-fontconfig-dir-do-not-use**")
-endif()
-set(configfile "${CURRENT_BUILDTREES_DIR}/${TARGET_TRIPLET}-rel/config.h")
-vcpkg_replace_string("${configfile}" "${CURRENT_PACKAGES_DIR}" "${replacement}")
-vcpkg_replace_string("${configfile}" "#define FC_TEMPLATEDIR \"/share/fontconfig/conf.avail\"" "#define FC_TEMPLATEDIR \"/usr/share/fontconfig/conf.avail\"" IGNORE_UNCHANGED)
-if(NOT VCPKG_BUILD_TYPE)
-    set(configfile "${CURRENT_BUILDTREES_DIR}/${TARGET_TRIPLET}-dbg/config.h")
-    vcpkg_replace_string("${configfile}" "${CURRENT_PACKAGES_DIR}/debug" "${replacement}")
-    vcpkg_replace_string("${configfile}" "#define FC_TEMPLATEDIR \"/share/fontconfig/conf.avail\"" "#define FC_TEMPLATEDIR \"/usr/share/fontconfig/conf.avail\"" IGNORE_UNCHANGED)
-endif()
-
-vcpkg_install_meson(ADD_BIN_TO_PATH)
-
-vcpkg_copy_pdbs()
-#Fix missing libintl static dependency
-if("nls" IN_LIST FEATURES AND VCPKG_TARGET_IS_WINDOWS AND NOT VCPKG_TARGET_IS_MINGW)
-    if(NOT VCPKG_BUILD_TYPE)
-        vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/debug/lib/pkgconfig/fontconfig.pc" "-liconv" "-liconv -lintl" IGNORE_UNCHANGED)
-    endif()
-    vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/lib/pkgconfig/fontconfig.pc" "-liconv" "-liconv -lintl" IGNORE_UNCHANGED)
-endif()
-vcpkg_fixup_pkgconfig()
-
-# Fix paths in debug pc file.
-set(_file "${CURRENT_PACKAGES_DIR}/debug/lib/pkgconfig/fontconfig.pc")
-if(EXISTS "${_file}")
-    file(READ "${_file}" _contents)
-    string(REPLACE "/etc" "/../etc" _contents "${_contents}")
-    string(REPLACE "/var" "/../var" _contents "${_contents}")
-    file(WRITE "${_file}" "${_contents}")
-endif()
-
-# Make path to cache in fonts.conf relative
-set(_file "${CURRENT_PACKAGES_DIR}/etc/fonts/fonts.conf")
-if(EXISTS "${_file}")
-    vcpkg_replace_string("${_file}" "${CURRENT_PACKAGES_DIR}/var/cache/fontconfig" "./../../var/cache/fontconfig" IGNORE_UNCHANGED)
-endif()
-
-file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug/var"
-                    "${CURRENT_PACKAGES_DIR}/debug/share"
-                    "${CURRENT_PACKAGES_DIR}/debug/etc")
-
-if(VCPKG_LIBRARY_LINKAGE STREQUAL "dynamic")
-    if(VCPKG_TARGET_IS_WINDOWS)
-        set(DEFINE_FC_PUBLIC "#define FcPublic __declspec(dllimport)")
-    else()
-        set(DEFINE_FC_PUBLIC "#define FcPublic __attribute__((visibility(\"default\")))")
-    endif()
-    foreach(HEADER IN ITEMS fcfreetype.h fontconfig.h)
-        vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/include/fontconfig/${HEADER}"
-            "#define FcPublic"
-            "${DEFINE_FC_PUBLIC}"
-        )
-    endforeach()
-endif()
-
-if("tools" IN_LIST FEATURES)
-    vcpkg_copy_tools(
-        TOOL_NAMES fc-match fc-cat fc-list fc-pattern fc-query fc-scan fc-cache fc-validate fc-conflist
-        AUTO_CLEAN
-    )
-endif()
-
-configure_file("${CMAKE_CURRENT_LIST_DIR}/vcpkg-cmake-wrapper.cmake.in" "${CURRENT_PACKAGES_DIR}/share/${PORT}/vcpkg-cmake-wrapper.cmake" @ONLY)
-file(INSTALL "${CMAKE_CURRENT_LIST_DIR}/usage" DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}")
-vcpkg_install_copyright(FILE_LIST "${SOURCE_PATH}/COPYING")

+ 0 - 9
Meta/CMake/vcpkg/overlay-ports/fontconfig/usage

@@ -1,9 +0,0 @@
-fontconfig is compatible with built-in CMake targets:
-
-  find_package(Fontconfig REQUIRED) # since CMake 3.14
-  target_link_libraries(main PRIVATE Fontconfig::Fontconfig)
-
-fontconfig provides pkg-config modules:
-
-  # Font configuration and customization library
-  fontconfig

+ 0 - 51
Meta/CMake/vcpkg/overlay-ports/fontconfig/vcpkg-cmake-wrapper.cmake.in

@@ -1,51 +0,0 @@
-_find_package(${ARGS})
-if(Fontconfig_FOUND) # theoretically this could be skipped. If the wrapper is installed it should be found!
-    if(NOT TARGET Fontconfig::Fontconfig)
-        # Simplify wrapper for case of vendored FindFontconfig.cmake
-        add_library(Fontconfig::Fontconfig UNKNOWN IMPORTED)
-    endif()
-    include(SelectLibraryConfigurations)
-    find_library(Fontconfig_LIBRARY_DEBUG NAMES fontconfig fontconfigd NAMES_PER_DIR PATH_SUFFIXES lib PATHS "${_INSTALLED_DIR}/debug" NO_DEFAULT_PATH)
-    find_library(Fontconfig_LIBRARY_RELEASE NAMES fontconfig NAMES_PER_DIR PATH_SUFFIXES lib PATHS "${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}" NO_DEFAULT_PATH)
-    select_library_configurations(Fontconfig)
-    set_target_properties(Fontconfig::Fontconfig PROPERTIES
-        IMPORTED_CONFIGURATIONS "Release"
-        IMPORTED_LOCATION_RELEASE "${Fontconfig_LIBRARY_RELEASE}"
-    )
-    if(Fontconfig_LIBRARY_DEBUG)
-        set_property(TARGET Fontconfig::Fontconfig APPEND PROPERTY IMPORTED_CONFIGURATIONS "Debug")
-        set_target_properties(Fontconfig::Fontconfig PROPERTIES IMPORTED_LOCATION_DEBUG "${Fontconfig_LIBRARY_DEBUG}")
-    endif()
-    find_package(Freetype)
-    if(Freetype_FOUND)
-        list(APPEND Fontconfig_LIBRARIES "${FREETYPE_LIBRARIES}")
-        if(TARGET Freetype::Freetype)
-            set_property(TARGET Fontconfig::Fontconfig APPEND PROPERTY INTERFACE_LINK_LIBRARIES "\$<LINK_ONLY:Freetype::Freetype>")
-        else()
-            # TODO link FREETYPE_LIBRARIES transformed for $<CONFIG:...>.
-        endif()
-    endif()
-    find_package(EXPAT)
-    if(EXPAT_FOUND)
-        list(APPEND Fontconfig_LIBRARIES "${EXPAT_LIBRARIES}")
-        if(TARGET EXPAT::EXPAT)
-            set_property(TARGET Fontconfig::Fontconfig APPEND PROPERTY INTERFACE_LINK_LIBRARIES "\$<LINK_ONLY:EXPAT::EXPAT>")
-        else()
-            # TODO link EXPAT_LIBRARIES transformed for $<CONFIG:...>.
-        endif()
-    endif()
-    if("@VCPKG_TARGET_IS_LINUX@")
-        find_library(UUID_LIBRARY_DEBUG NAMES uuid uuidd uuid_d  NAMES_PER_DIR PATH_SUFFIXES lib PATHS "${_INSTALLED_DIR}/debug" NO_DEFAULT_PATH)
-        find_library(UUID_LIBRARY_RELEASE NAMES uuid NAMES_PER_DIR PATH_SUFFIXES lib PATHS "${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}" NO_DEFAULT_PATH)
-        select_library_configurations(UUID)
-        if(UUID_LIBRARIES)
-            list(APPEND Fontconfig_LIBRARIES "${UUID_LIBRARIES}")
-            if(UUID_LIBRARY_DEBUG)
-                set_property(TARGET Fontconfig::Fontconfig APPEND PROPERTY INTERFACE_LINK_LIBRARIES "$<$<NOT:$<CONFIG:DEBUG>>:${UUID_LIBRARY_RELEASE}>")
-                set_property(TARGET Fontconfig::Fontconfig APPEND PROPERTY INTERFACE_LINK_LIBRARIES "$<$<CONFIG:DEBUG>:${UUID_LIBRARY_DEBUG}>")
-            else()
-                set_property(TARGET Fontconfig::Fontconfig APPEND PROPERTY INTERFACE_LINK_LIBRARIES "${UUID_LIBRARY_RELEASE}")
-            endif()
-        endif()
-    endif()
-endif()

+ 0 - 60
Meta/CMake/vcpkg/overlay-ports/fontconfig/vcpkg.json

@@ -1,60 +0,0 @@
-{
-  "name": "fontconfig",
-  "version": "2.15.0",
-  "port-version": 2,
-  "description": "Library for configuring and customizing font access.",
-  "homepage": "https://www.freedesktop.org/wiki/Software/fontconfig",
-  "license": "MIT",
-  "supports": "!uwp",
-  "dependencies": [
-    "dirent",
-    "expat",
-    {
-      "name": "freetype",
-      "default-features": false
-    },
-    {
-      "name": "gperf",
-      "host": true
-    },
-    {
-      "name": "libiconv",
-      "platform": "!windows"
-    },
-    {
-      "name": "libuuid",
-      "platform": "!osx & !windows"
-    },
-    {
-      "name": "pthread",
-      "platform": "!emscripten & !windows"
-    },
-    {
-      "name": "vcpkg-tool-meson",
-      "host": true
-    }
-  ],
-  "features": {
-    "nls": {
-      "description": "Native languages support",
-      "dependencies": [
-        {
-          "name": "gettext",
-          "host": true,
-          "default-features": false,
-          "features": [
-            "tools"
-          ]
-        },
-        "gettext-libintl"
-      ]
-    },
-    "tools": {
-      "description": "Build tools",
-      "supports": "!emscripten",
-      "dependencies": [
-        "getopt"
-      ]
-    }
-  }
-}

+ 0 - 65
Meta/CMake/vcpkg/overlay-ports/freetype/0003-Fix-UWP.patch

@@ -1,65 +0,0 @@
-diff --git a/CMakeLists.txt b/CMakeLists.txt
-index db48e9f..5c35276 100644
---- a/CMakeLists.txt
-+++ b/CMakeLists.txt
-@@ -328,6 +328,10 @@ else ()
-   list(APPEND BASE_SRCS src/base/ftdebug.c)
- endif ()
- 
-+if(MSVC)
-+  add_definitions(-D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE -D_CRT_SECURE_NO_WARNINGS)
-+endif()
-+
- if (BUILD_FRAMEWORK)
-   list(APPEND BASE_SRCS builds/mac/freetype-Info.plist)
- endif ()
-diff --git a/include/freetype/freetype.h b/include/freetype/freetype.h
-index 4f2eaca..1e01fe4 100644
---- a/include/freetype/freetype.h
-+++ b/include/freetype/freetype.h
-@@ -1038,6 +1038,11 @@ FT_BEGIN_HEADER
-    *   Especially for TrueType fonts see also the documentation for
-    *   @FT_Size_Metrics.
-    */
-+   
-+#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY != WINAPI_FAMILY_DESKTOP_APP)
-+#define generic GenericFromFreeTypeLibrary
-+#endif
-+
-   typedef struct  FT_FaceRec_
-   {
-     FT_Long           num_faces;
-@@ -1910,6 +1915,9 @@ FT_BEGIN_HEADER
- 
-   } FT_GlyphSlotRec;
- 
-+#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY != WINAPI_FAMILY_DESKTOP_APP)
-+#undef generic
-+#endif
- 
-   /*************************************************************************/
-   /*************************************************************************/
-diff --git a/src/base/ftobjs.c b/src/base/ftobjs.c
-index 3f8619d..edf03b6 100644
---- a/src/base/ftobjs.c
-+++ b/src/base/ftobjs.c
-@@ -528,6 +528,9 @@
-     return error;
-   }
- 
-+#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY != WINAPI_FAMILY_DESKTOP_APP)
-+#define generic GenericFromFreeTypeLibrary
-+#endif
- 
-   static void
-   ft_glyphslot_clear( FT_GlyphSlot  slot )
-@@ -1195,6 +1198,9 @@
-     FT_FREE( face );
-   }
- 
-+#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY != WINAPI_FAMILY_DESKTOP_APP)
-+#undef generic
-+#endif
- 
-   static void
-   Destroy_Driver( FT_Driver  driver )

+ 0 - 21
Meta/CMake/vcpkg/overlay-ports/freetype/brotli-static.patch

@@ -1,21 +0,0 @@
-diff --git a/builds/cmake/FindBrotliDec.cmake b/builds/cmake/FindBrotliDec.cmake
-index 46356b1fd..ed4cc2409 100644
---- a/builds/cmake/FindBrotliDec.cmake
-+++ b/builds/cmake/FindBrotliDec.cmake
-@@ -35,10 +35,15 @@ find_path(BROTLIDEC_INCLUDE_DIRS
-   PATH_SUFFIXES brotli)
- 
- find_library(BROTLIDEC_LIBRARIES
--  NAMES brotlidec
-+  NAMES brotlidec brotlidec-static NAMES_PER_DIR
-   HINTS ${PC_BROTLIDEC_LIBDIR}
-         ${PC_BROTLIDEC_LIBRARY_DIRS})
- 
-+  find_library(BROTLICOMMON_LIBRARIES
-+    NAMES brotlicommon-static brotlicommon NAMES_PER_DIR
-+    HINTS ${PC_BROTLIDEC_LIBDIR}
-+          ${PC_BROTLIDEC_LIBRARY_DIRS})
-+  set(BROTLIDEC_LIBRARIES "${BROTLIDEC_LIBRARIES};${BROTLICOMMON_LIBRARIES}")
- 
- include(FindPackageHandleStandardArgs)
- find_package_handle_standard_args(

+ 0 - 13
Meta/CMake/vcpkg/overlay-ports/freetype/bzip2.patch

@@ -1,13 +0,0 @@
-diff --git a/CMakeLists.txt b/CMakeLists.txt
-index 469a141a2..eec19c7d0 100644
---- a/CMakeLists.txt	
-+++ b/CMakeLists.txt
-@@ -517,7 +517,7 @@ if (BZIP2_FOUND)
-   if (PC_BZIP2_FOUND)
-     list(APPEND PKGCONFIG_REQUIRES_PRIVATE "bzip2")
-   else ()
--    list(APPEND PKGCONFIG_LIBS_PRIVATE "-lbz2")
-+    list(APPEND PKGCONFIG_REQUIRES_PRIVATE "bzip2")
-   endif ()
- endif ()
- if (PNG_FOUND)

+ 0 - 40
Meta/CMake/vcpkg/overlay-ports/freetype/fix-exports.patch

@@ -1,40 +0,0 @@
-diff --git a/CMakeLists.txt b/CMakeLists.txt
-index cb1b9a0f2..edca5d579 100644
---- a/CMakeLists.txt
-+++ b/CMakeLists.txt
-@@ -508,7 +508,6 @@ set(PKG_CONFIG_REQUIRED_PRIVATE "")
- set(PKGCONFIG_LIBS_PRIVATE "")
- 
- if (ZLIB_FOUND)
--   target_link_libraries(freetype PRIVATE ${ZLIB_LIBRARIES})
-+   target_link_libraries(freetype PRIVATE ZLIB::ZLIB)
--   target_include_directories(freetype PRIVATE ${ZLIB_INCLUDE_DIRS})
-   list(APPEND PKGCONFIG_REQUIRES_PRIVATE "zlib")
- endif ()
-@@ -596,12 +596,25 @@ if (NOT SKIP_INSTALL_LIBRARIES AND NOT SKIP_INSTALL_ALL)
-   install(
-     EXPORT freetype-targets
-       DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/freetype
--      FILE freetype-config.cmake
-       COMPONENT headers)
-   install(
-     FILES ${PROJECT_BINARY_DIR}/freetype-config-version.cmake
-     DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/freetype
-     COMPONENT headers)
-+
-+  if(ZLIB_FOUND AND BUILD_SHARED_LIBS)
-+    file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/freetype-config.cmake"
-+[[include(CMakeFindDependencyMacro)
-+find_dependency(ZLIB)
-+include("${CMAKE_CURRENT_LIST_DIR}/freetype-targets.cmake")
-+]])
-+  else()
-+    file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/freetype-config.cmake"
-+[[include("${CMAKE_CURRENT_LIST_DIR}/freetype-targets.cmake")
-+]])
-+  endif()
-+
-+  install(FILES ${CMAKE_CURRENT_BINARY_DIR}/freetype-config.cmake DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/freetype)
- endif ()
- 
- 

+ 0 - 98
Meta/CMake/vcpkg/overlay-ports/freetype/portfile.cmake

@@ -1,98 +0,0 @@
-if("subpixel-rendering" IN_LIST FEATURES)
-    set(SUBPIXEL_RENDERING_PATCH "subpixel-rendering.patch")
-endif()
-
-string(REPLACE "." "-" VERSION_HYPHEN "${VERSION}")
-
-vcpkg_from_gitlab(
-    GITLAB_URL https://gitlab.com/
-    OUT_SOURCE_PATH SOURCE_PATH
-    REPO freetype/freetype
-    REF "VER-${VERSION_HYPHEN}"
-    SHA512  fccfaa15eb79a105981bf634df34ac9ddf1c53550ec0b334903a1b21f9f8bf5eb2b3f9476e554afa112a0fca58ec85ab212d674dfd853670efec876bacbe8a53
-    HEAD_REF master
-    PATCHES
-        0003-Fix-UWP.patch
-        brotli-static.patch
-        bzip2.patch
-        fix-exports.patch
-        ${SUBPIXEL_RENDERING_PATCH}
-)
-
-vcpkg_check_features(OUT_FEATURE_OPTIONS FEATURE_OPTIONS
-    FEATURES
-        zlib          FT_REQUIRE_ZLIB
-        bzip2         FT_REQUIRE_BZIP2
-        error-strings FT_ENABLE_ERROR_STRINGS
-        png           FT_REQUIRE_PNG
-        brotli        FT_REQUIRE_BROTLI
-    INVERTED_FEATURES
-        zlib          FT_DISABLE_ZLIB
-        bzip2         FT_DISABLE_BZIP2
-        png           FT_DISABLE_PNG
-        brotli        FT_DISABLE_BROTLI
-)
-
-vcpkg_cmake_configure(
-    SOURCE_PATH "${SOURCE_PATH}"
-    OPTIONS
-        -DFT_DISABLE_HARFBUZZ=ON
-        ${FEATURE_OPTIONS}
-)
-
-vcpkg_cmake_install()
-vcpkg_copy_pdbs()
-vcpkg_cmake_config_fixup(CONFIG_PATH lib/cmake/freetype)
-
-# Rename for easy usage (VS integration; CMake and autotools will not care)
-file(RENAME "${CURRENT_PACKAGES_DIR}/include/freetype2/freetype" "${CURRENT_PACKAGES_DIR}/include/freetype")
-file(RENAME "${CURRENT_PACKAGES_DIR}/include/freetype2/ft2build.h" "${CURRENT_PACKAGES_DIR}/include/ft2build.h")
-file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/include/freetype2")
-file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug/include")
-
-# Fix the include dir [freetype2 -> freetype]
-file(READ "${CURRENT_PACKAGES_DIR}/share/freetype/freetype-targets.cmake" CONFIG_MODULE)
-string(REPLACE "\${_IMPORT_PREFIX}/include/freetype2" "\${_IMPORT_PREFIX}/include" CONFIG_MODULE "${CONFIG_MODULE}")
-string(REPLACE "\${_IMPORT_PREFIX}/lib/brotlicommon-static.lib" [[\$<\$<NOT:\$<CONFIG:DEBUG>>:${_IMPORT_PREFIX}/lib/brotlicommon-static.lib>;\$<\$<CONFIG:DEBUG>:${_IMPORT_PREFIX}/debug/lib/brotlicommon-static.lib>]] CONFIG_MODULE "${CONFIG_MODULE}")
-string(REPLACE "\${_IMPORT_PREFIX}/lib/brotlidec-static.lib" [[\$<\$<NOT:\$<CONFIG:DEBUG>>:${_IMPORT_PREFIX}/lib/brotlidec-static.lib>;\$<\$<CONFIG:DEBUG>:${_IMPORT_PREFIX}/debug/lib/brotlidec-static.lib>]] CONFIG_MODULE "${CONFIG_MODULE}")
-string(REPLACE "\${_IMPORT_PREFIX}/lib/brotlidec.lib" [[\$<\$<NOT:\$<CONFIG:DEBUG>>:${_IMPORT_PREFIX}/lib/brotlidec.lib>;\$<\$<CONFIG:DEBUG>:${_IMPORT_PREFIX}/debug/lib/brotlidec.lib>]] CONFIG_MODULE "${CONFIG_MODULE}")
-string(REPLACE "\${_IMPORT_PREFIX}/lib/brotlidec.lib" [[\$<\$<NOT:\$<CONFIG:DEBUG>>:${_IMPORT_PREFIX}/lib/brotlidec.lib>;\$<\$<CONFIG:DEBUG>:${_IMPORT_PREFIX}/debug/lib/brotlidec.lib>]] CONFIG_MODULE "${CONFIG_MODULE}")
-file(WRITE ${CURRENT_PACKAGES_DIR}/share/freetype/freetype-targets.cmake "${CONFIG_MODULE}")
-
-find_library(FREETYPE_DEBUG NAMES freetyped PATHS "${CURRENT_PACKAGES_DIR}/debug/lib/" NO_DEFAULT_PATH)
-if(NOT VCPKG_BUILD_TYPE)
-    file(READ "${CURRENT_PACKAGES_DIR}/debug/lib/pkgconfig/freetype2.pc" _contents)
-    if(FREETYPE_DEBUG)
-        string(REPLACE "-lfreetype" "-lfreetyped" _contents "${_contents}")
-    endif()
-    string(REPLACE "-I\${includedir}/freetype2" "-I\${includedir}" _contents "${_contents}")
-    file(WRITE "${CURRENT_PACKAGES_DIR}/debug/lib/pkgconfig/freetype2.pc" "${_contents}")
-endif()
-
-file(READ "${CURRENT_PACKAGES_DIR}/lib/pkgconfig/freetype2.pc" _contents)
-string(REPLACE "-I\${includedir}/freetype2" "-I\${includedir}" _contents "${_contents}")
-file(WRITE "${CURRENT_PACKAGES_DIR}/lib/pkgconfig/freetype2.pc" "${_contents}")
-
-
-vcpkg_fixup_pkgconfig()
-
-file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug/include")
-file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug/share")
-
-if(VCPKG_TARGET_IS_WINDOWS)
-  set(dll_linkage 1)
-  if(VCPKG_LIBRARY_LINKAGE STREQUAL "static")
-    set(dll_linkage 0)
-  endif()
-  vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/include/freetype/config/public-macros.h" "#elif defined( DLL_IMPORT )" "#elif ${dll_linkage}")
-endif()
-
-configure_file("${CMAKE_CURRENT_LIST_DIR}/vcpkg-cmake-wrapper.cmake"
-    "${CURRENT_PACKAGES_DIR}/share/${PORT}/vcpkg-cmake-wrapper.cmake" @ONLY)
-file(INSTALL "${CMAKE_CURRENT_LIST_DIR}/usage" DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}")
-vcpkg_install_copyright(
-    FILE_LIST
-        "${SOURCE_PATH}/LICENSE.TXT"
-        "${SOURCE_PATH}/docs/FTL.TXT"
-        "${SOURCE_PATH}/docs/GPLv2.TXT"
-)

+ 0 - 13
Meta/CMake/vcpkg/overlay-ports/freetype/subpixel-rendering.patch

@@ -1,13 +0,0 @@
-diff --git a/include/freetype/config/ftoption.h b/include/freetype/config/ftoption.h
-index 1976b33af959..b3425e55feec 100644
---- a/include/freetype/config/ftoption.h
-+++ b/include/freetype/config/ftoption.h
-@@ -123,7 +123,7 @@ FT_BEGIN_HEADER
-    * When this macro is not defined, FreeType offers alternative LCD
-    * rendering technology that produces excellent output.
-    */
--/* #define FT_CONFIG_OPTION_SUBPIXEL_RENDERING */
-+#define FT_CONFIG_OPTION_SUBPIXEL_RENDERING
-
-
-   /**************************************************************************

+ 0 - 4
Meta/CMake/vcpkg/overlay-ports/freetype/usage

@@ -1,4 +0,0 @@
-freetype is compatible with built-in CMake targets:
-
-    find_package(Freetype REQUIRED)
-    target_link_libraries(main PRIVATE Freetype::Freetype) # since CMake 3.10

+ 0 - 95
Meta/CMake/vcpkg/overlay-ports/freetype/vcpkg-cmake-wrapper.cmake

@@ -1,95 +0,0 @@
-cmake_policy(PUSH)
-cmake_policy(SET CMP0012 NEW)
-cmake_policy(SET CMP0054 NEW)
-
-list(REMOVE_ITEM ARGS "NO_MODULE" "CONFIG" "MODULE")
-_find_package(${ARGS} CONFIG)
-
-if(Freetype_FOUND)
-    include("${CMAKE_ROOT}/Modules/SelectLibraryConfigurations.cmake")
-
-    get_target_property(_freetype_include_dirs freetype INTERFACE_INCLUDE_DIRECTORIES)
-
-    if (CMAKE_SYSTEM_NAME STREQUAL "Windows" OR CMAKE_SYSTEM_NAME STREQUAL "WindowsStore")
-        get_target_property(_freetype_location_debug freetype IMPORTED_IMPLIB_DEBUG)
-        get_target_property(_freetype_location_release freetype IMPORTED_IMPLIB_RELEASE)
-    endif()
-    if(NOT _freetype_location_debug AND NOT _freetype_location_release)
-        get_target_property(_freetype_location_debug freetype IMPORTED_LOCATION_DEBUG)
-        get_target_property(_freetype_location_release freetype IMPORTED_LOCATION_RELEASE)
-    endif()
-
-    set(FREETYPE_FOUND TRUE)
-
-    set(FREETYPE_INCLUDE_DIRS "${_freetype_include_dirs}")
-    set(FREETYPE_INCLUDE_DIR_ft2build "${_freetype_include_dirs}")
-    set(FREETYPE_INCLUDE_DIR_freetype2 "${_freetype_include_dirs}")
-    set(FREETYPE_LIBRARY_DEBUG "${_freetype_location_debug}" CACHE INTERNAL "vcpkg")
-    set(FREETYPE_LIBRARY_RELEASE "${_freetype_location_release}" CACHE INTERNAL "vcpkg")
-    select_library_configurations(FREETYPE)
-    set(FREETYPE_LIBRARIES ${FREETYPE_LIBRARY})
-    set(FREETYPE_VERSION_STRING "${Freetype_VERSION}")
-
-    unset(_freetype_include_dirs)
-    unset(_freetype_location_debug)
-    unset(_freetype_location_release)
-endif()
-
-if("@VCPKG_LIBRARY_LINKAGE@" STREQUAL "static")
-    if("@FT_REQUIRE_ZLIB@")
-        find_package(ZLIB)
-    endif()
-    if("@FT_REQUIRE_BZIP2@")
-        find_package(BZip2)
-    endif()
-    if("@FT_REQUIRE_PNG@")
-        find_package(PNG)
-    endif()
-    if("@FT_REQUIRE_BROTLI@")
-        find_library(BROTLIDEC_LIBRARY_RELEASE NAMES brotlidec brotlidec-static PATHS "${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}" PATH_SUFFIXES lib NO_DEFAULT_PATH)
-        find_library(BROTLIDEC_LIBRARY_DEBUG NAMES brotlidec brotlidec-static brotlidecd brotlidec-staticd PATHS "${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/debug" PATH_SUFFIXES lib NO_DEFAULT_PATH)
-        find_library(BROTLICOMMON_LIBRARY_RELEASE NAMES brotlicommon brotlicommon-static PATHS "${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}" PATH_SUFFIXES lib NO_DEFAULT_PATH)
-        find_library(BROTLICOMMON_LIBRARY_DEBUG NAMES brotlicommon brotlicommon-static brotlicommond brotlicommon-staticd PATHS "${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/debug" PATH_SUFFIXES lib NO_DEFAULT_PATH)
-        include(SelectLibraryConfigurations)
-        select_library_configurations(BROTLIDEC)
-        select_library_configurations(BROTLICOMMON)
-    endif("@FT_REQUIRE_BROTLI@")
-
-    if(TARGET Freetype::Freetype)
-        if("@FT_REQUIRE_ZLIB@")
-            set_property(TARGET Freetype::Freetype APPEND PROPERTY INTERFACE_LINK_LIBRARIES ZLIB::ZLIB)
-        endif()
-        if("@FT_REQUIRE_BZIP2@")
-            set_property(TARGET Freetype::Freetype APPEND PROPERTY INTERFACE_LINK_LIBRARIES BZip2::BZip2)
-        endif()
-        if("@FT_REQUIRE_PNG@")
-            set_property(TARGET Freetype::Freetype APPEND PROPERTY INTERFACE_LINK_LIBRARIES PNG::PNG)
-        endif()
-        if("@FT_REQUIRE_BROTLI@")
-            if(BROTLIDEC_LIBRARY_DEBUG)
-                set_property(TARGET Freetype::Freetype APPEND PROPERTY INTERFACE_LINK_LIBRARIES "\$<\$<CONFIG:DEBUG>:${BROTLIDEC_LIBRARY_DEBUG}>")
-                set_property(TARGET Freetype::Freetype APPEND PROPERTY INTERFACE_LINK_LIBRARIES "\$<\$<CONFIG:DEBUG>:${BROTLICOMMON_LIBRARY_DEBUG}>")
-            endif()
-            if(BROTLIDEC_LIBRARY_RELEASE)
-                set_property(TARGET Freetype::Freetype APPEND PROPERTY INTERFACE_LINK_LIBRARIES "\$<\$<NOT:$<CONFIG:DEBUG>>:${BROTLIDEC_LIBRARY_RELEASE}>")
-                set_property(TARGET Freetype::Freetype APPEND PROPERTY INTERFACE_LINK_LIBRARIES "\$<\$<NOT:$<CONFIG:DEBUG>>:${BROTLICOMMON_LIBRARY_RELEASE}>")
-            endif()
-        endif()
-    endif()
-
-    if(FREETYPE_LIBRARIES)
-        if("@FT_REQUIRE_ZLIB@")
-            list(APPEND FREETYPE_LIBRARIES ${ZLIB_LIBRARIES})
-        endif()
-        if("@FT_REQUIRE_BZIP2@")
-            list(APPEND FREETYPE_LIBRARIES ${BZIP2_LIBRARIES})
-        endif()
-        if("@FT_REQUIRE_PNG@")
-            list(APPEND FREETYPE_LIBRARIES ${PNG_LIBRARIES})
-        endif()
-        if("@FT_REQUIRE_BROTLI@")
-            list(APPEND FREETYPE_LIBRARIES ${BROTLIDEC_LIBRARIES} ${BROTLICOMMON_LIBRARIES})
-        endif()
-    endif()
-endif()
-cmake_policy(POP)

+ 0 - 55
Meta/CMake/vcpkg/overlay-ports/freetype/vcpkg.json

@@ -1,55 +0,0 @@
-{
-  "name": "freetype",
-  "version": "2.13.3",
-  "description": "A library to render fonts.",
-  "homepage": "https://www.freetype.org/",
-  "license": "FTL OR GPL-2.0-or-later",
-  "dependencies": [
-    {
-      "name": "vcpkg-cmake",
-      "host": true
-    },
-    {
-      "name": "vcpkg-cmake-config",
-      "host": true
-    }
-  ],
-  "default-features": [
-    "brotli",
-    "bzip2",
-    "png",
-    "zlib"
-  ],
-  "features": {
-    "brotli": {
-      "description": "Support decompression of WOFF2 streams",
-      "dependencies": [
-        "brotli"
-      ]
-    },
-    "bzip2": {
-      "description": "Support bzip2 compressed fonts.",
-      "dependencies": [
-        "bzip2"
-      ]
-    },
-    "error-strings": {
-      "description": "Enable support for meaningful error descriptions."
-    },
-    "png": {
-      "description": "Support PNG compressed OpenType embedded bitmaps.",
-      "dependencies": [
-        "libpng"
-      ]
-    },
-    "subpixel-rendering": {
-      "description": "Enables subpixel rendering."
-    },
-    "zlib": {
-      "description": "Use zlib instead of internal library for DEFLATE",
-      "dependencies": [
-        "zlib"
-      ]
-    }
-  }
-}

+ 2 - 1
Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/IDLGenerators.cpp

@@ -4249,7 +4249,8 @@ JS_DEFINE_NATIVE_FUNCTION(@class_name@::@attribute.setter_callback@)
     auto value = vm.argument(0);
 
     auto receiver = TRY(throw_dom_exception_if_needed(vm, [&]() { return impl->@attribute.cpp_name@(); }));
-    TRY(receiver->set(JS::PropertyKey { "@put_forwards_identifier@"_fly_string, JS::PropertyKey::StringMayBeNumber::No }, value, JS::Object::ShouldThrowExceptions::Yes));
+    if (receiver != JS::js_null())
+        TRY(receiver->set(JS::PropertyKey { "@put_forwards_identifier@"_fly_string, JS::PropertyKey::StringMayBeNumber::No }, value, JS::Object::ShouldThrowExceptions::Yes));
 
     return JS::js_undefined();
 }

+ 2 - 0
Meta/check-newlines-at-eof.py

@@ -18,6 +18,8 @@ def should_check_file(filename):
         return False
     if filename.startswith('Tests/LibWeb/Text/'):
         return False
+    if filename.startswith('Meta/CMake/vcpkg/overlay-ports/'):
+        return False
     if filename.endswith('.txt'):
         return 'CMake' in filename
     return True

+ 2 - 0
Meta/check-style.py

@@ -64,6 +64,8 @@ def should_check_file(filename):
         return False
     if filename.startswith('Base/'):
         return False
+    if filename.startswith('Meta/CMake/vcpkg/overlay-ports/'):
+        return False
     return True
 
 

+ 0 - 1
Meta/gn/secondary/Ladybird/BUILD.gn

@@ -39,7 +39,6 @@ link_qt("ladybird_qt_components") {
     "Core",
     "Gui",
     "Widgets",
-    "Network",
   ]
 }
 

+ 1 - 1
Services/RequestServer/ConnectionFromClient.cpp

@@ -13,7 +13,7 @@
 #include <LibCore/EventLoop.h>
 #include <LibCore/Proxy.h>
 #include <LibCore/Socket.h>
-#include <LibRequests/NetworkErrorEnum.h>
+#include <LibRequests/NetworkError.h>
 #include <LibRequests/RequestTimingInfo.h>
 #include <LibRequests/WebSocket.h>
 #include <LibTLS/TLSv12.h>

+ 1 - 1
Services/RequestServer/RequestClient.ipc

@@ -1,5 +1,5 @@
 #include <LibHTTP/HeaderMap.h>
-#include <LibRequests/NetworkErrorEnum.h>
+#include <LibRequests/NetworkError.h>
 #include <LibRequests/RequestTimingInfo.h>
 #include <LibURL/URL.h>
 

+ 32 - 0
Tests/LibWeb/Ref/input/wpt-import/css/css-cascade/import-conditional-001.html

@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>CSS Cascade: @import with basic media query</title>
+  <link rel="author" title="Elika J. Etemad" href="http://fantasai.inkedblade.net/contact">
+  <link rel="help" href="https://www.w3.org/TR/css-cascade-3/#conditional-import">
+  <link rel="help" href="https://www.w3.org/TR/css-cascade-4/#conditional-import">
+  <link rel="help" href="https://www.w3.org/TR/css3-mediaqueries/#syntax">
+  <link rel="match" href="../../../../expected/wpt-import/css/css-cascade/reference/ref-filled-green-100px-square.xht">
+  <meta name="assert" content="Test passes on visual UAs if @import can be combined with a media query.">
+  <style>
+  @import "support/test-red.css";
+  @import "support/test-green.css"
+    (min-width: 1px) and /* assuming screen < 1km */ (max-width: 40000in), nonsense;
+  @import "support/test-red.css"
+    (max-width: 1px), nonsense;
+  div {
+    box-sizing: border-box;
+    width: 100px;
+    height: 100px;
+    padding: 5px; /* Avoids text antialiasing issues */
+    background: red;
+  }
+  </style>
+</head>
+<body>
+  <p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+
+  <div class="test">FAIL</div>
+</body>
+</html>

+ 12 - 0
Tests/LibWeb/TestConfig.ini

@@ -312,3 +312,15 @@ Ref/input/wpt-import/css/css-contain/contain-paint-change-opacity.html
 
 ; Timing out; https://github.com/LadybirdBrowser/ladybird/issues/3912
 Text/input/wpt-import/html/rendering/replaced-elements/svg-inline-sizing/svg-inline.html
+
+; The number of subtests that pass is inconsistent, maybe a race condition?
+; https://github.com/LadybirdBrowser/ladybird/issues/4190
+Text/input/wpt-import/css/mediaqueries/media-query-matches-in-iframe.html
+
+; Inconsistently fails on CI.
+; https://github.com/LadybirdBrowser/ladybird/issues/4191
+Ref/input/scroll-iframe.html
+
+; Inconsistently times out because the echo server doesn't respond in time.
+; https://github.com/LadybirdBrowser/ladybird/issues/4192
+Text/input/WebSocket/echo.html

+ 18 - 3
Tests/LibWeb/Text/expected/wpt-import/css/css-fonts/parsing/font-stretch-computed.txt → Tests/LibWeb/Text/expected/wpt-import/css/css-fonts/parsing/font-width-computed.txt

@@ -1,9 +1,24 @@
 Harness status: OK
 
-Found 15 tests
+Found 30 tests
 
-4 Pass
-11 Fail
+8 Pass
+22 Fail
+Fail	Property font-width value 'ultra-condensed'
+Fail	Property font-width value 'extra-condensed'
+Fail	Property font-width value 'condensed'
+Fail	Property font-width value 'semi-condensed'
+Fail	Property font-width value 'normal'
+Fail	Property font-width value 'semi-expanded'
+Fail	Property font-width value 'expanded'
+Fail	Property font-width value 'extra-expanded'
+Fail	Property font-width value 'ultra-expanded'
+Pass	Property font-width value '234.5%'
+Pass	Property font-width value 'calc(100%)'
+Pass	Property font-width value 'calc(0%)'
+Fail	Property font-width value 'calc(-100%)'
+Pass	Property font-width value 'calc(100% + 100%)'
+Fail	Property font-width value 'calc(100% + (sign(20cqw - 10px) * 5%))'
 Fail	Property font-stretch value 'ultra-condensed'
 Fail	Property font-stretch value 'extra-condensed'
 Fail	Property font-stretch value 'condensed'

+ 6 - 2
Tests/LibWeb/Text/expected/wpt-import/css/css-fonts/parsing/font-stretch-invalid.txt → Tests/LibWeb/Text/expected/wpt-import/css/css-fonts/parsing/font-width-invalid.txt

@@ -1,8 +1,12 @@
 Harness status: OK
 
-Found 4 tests
+Found 8 tests
 
-4 Pass
+8 Pass
+Pass	e.style['font-width'] = "auto" should not set the property value
+Pass	e.style['font-width'] = "normal, ultra-condensed" should not set the property value
+Pass	e.style['font-width'] = "condensed expanded" should not set the property value
+Pass	e.style['font-width'] = "-50%" should not set the property value
 Pass	e.style['font-stretch'] = "auto" should not set the property value
 Pass	e.style['font-stretch'] = "normal, ultra-condensed" should not set the property value
 Pass	e.style['font-stretch'] = "condensed expanded" should not set the property value

+ 18 - 3
Tests/LibWeb/Text/expected/wpt-import/css/css-fonts/parsing/font-stretch-valid.txt → Tests/LibWeb/Text/expected/wpt-import/css/css-fonts/parsing/font-width-valid.txt

@@ -1,9 +1,24 @@
 Harness status: OK
 
-Found 15 tests
+Found 30 tests
 
-14 Pass
-1 Fail
+28 Pass
+2 Fail
+Pass	e.style['font-width'] = "normal" should set the property value
+Pass	e.style['font-width'] = "ultra-condensed" should set the property value
+Pass	e.style['font-width'] = "extra-condensed" should set the property value
+Pass	e.style['font-width'] = "condensed" should set the property value
+Pass	e.style['font-width'] = "semi-condensed" should set the property value
+Pass	e.style['font-width'] = "semi-expanded" should set the property value
+Pass	e.style['font-width'] = "expanded" should set the property value
+Pass	e.style['font-width'] = "extra-expanded" should set the property value
+Pass	e.style['font-width'] = "ultra-expanded" should set the property value
+Pass	e.style['font-width'] = "234.5%" should set the property value
+Pass	e.style['font-width'] = "calc(100%)" should set the property value
+Pass	e.style['font-width'] = "calc(0%)" should set the property value
+Pass	e.style['font-width'] = "calc(-100%)" should set the property value
+Pass	e.style['font-width'] = "calc(100% + 100%)" should set the property value
+Fail	e.style['font-width'] = "calc(100% + (sign(20cqw - 10px) * 5%))" should set the property value
 Pass	e.style['font-stretch'] = "normal" should set the property value
 Pass	e.style['font-stretch'] = "ultra-condensed" should set the property value
 Pass	e.style['font-stretch'] = "extra-condensed" should set the property value

+ 0 - 41
Tests/LibWeb/Text/input/wpt-import/css/css-fonts/parsing/font-stretch-computed.html

@@ -1,41 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<meta charset="utf-8">
-<title>CSS Fonts Module Level 4: getComputedStyle().fontStretch</title>
-<link rel="help" href="https://www.w3.org/TR/css-fonts-4/#font-stretch-prop">
-<meta name="assert" content="font-stretch computed value is a percentage.">
-<script src="../../../resources/testharness.js"></script>
-<script src="../../../resources/testharnessreport.js"></script>
-<script src="../../../css/support/computed-testcommon.js"></script>
-<style>
-  #container {
-    container-type: inline-size;
-    width: 10px;
-  }
-</style>
-</head>
-<body>
-<div id="container">
-  <div id="target"></div>
-</div>
-<script>
-test_computed_value('font-stretch', 'ultra-condensed', '50%');
-test_computed_value('font-stretch', 'extra-condensed', '62.5%');
-test_computed_value('font-stretch', 'condensed', '75%');
-test_computed_value('font-stretch', 'semi-condensed', '87.5%');
-test_computed_value('font-stretch', 'normal', '100%');
-test_computed_value('font-stretch', 'semi-expanded', '112.5%');
-test_computed_value('font-stretch', 'expanded', '125%');
-test_computed_value('font-stretch', 'extra-expanded', '150%');
-test_computed_value('font-stretch', 'ultra-expanded', '200%');
-
-test_computed_value('font-stretch', '234.5%');
-test_computed_value('font-stretch', 'calc(100%)', '100%');
-test_computed_value('font-stretch', 'calc(0%)', '0%');
-test_computed_value('font-stretch', 'calc(-100%)', '0%');
-test_computed_value('font-stretch', 'calc(100% + 100%)', '200%');
-test_computed_value('font-stretch', 'calc(100% + (sign(20cqw - 10px) * 5%))', '95%');
-</script>
-</body>
-</html>

+ 0 - 21
Tests/LibWeb/Text/input/wpt-import/css/css-fonts/parsing/font-stretch-invalid.html

@@ -1,21 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<meta charset="utf-8">
-<title>CSS Fonts Module Level 4: parsing font-stretch with invalid values</title>
-<link rel="help" href="https://www.w3.org/TR/css-fonts-4/#font-stretch-prop">
-<meta name="assert" content="font-stretch supports only the grammar 'normal | <percentage [0,∞]> | ultra-condensed | extra-condensed | condensed | semi-condensed | semi-expanded | expanded | extra-expanded | ultra-expanded'.">
-<meta name="assert" content="Values less than 0% are invalid.">
-<script src="../../../resources/testharness.js"></script>
-<script src="../../../resources/testharnessreport.js"></script>
-<script src="../../../css/support/parsing-testcommon.js"></script>
-</head>
-<body>
-<script>
-test_invalid_value('font-stretch', 'auto');
-test_invalid_value('font-stretch', 'normal, ultra-condensed');
-test_invalid_value('font-stretch', 'condensed expanded');
-test_invalid_value('font-stretch', '-50%');
-</script>
-</body>
-</html>

+ 0 - 32
Tests/LibWeb/Text/input/wpt-import/css/css-fonts/parsing/font-stretch-valid.html

@@ -1,32 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<meta charset="utf-8">
-<title>CSS Fonts Module Level 4: parsing font-stretch with valid values</title>
-<link rel="help" href="https://www.w3.org/TR/css-fonts-4/#font-stretch-prop">
-<meta name="assert" content="font-stretch supports the full grammar 'normal | <percentage [0,∞]> | ultra-condensed | extra-condensed | condensed | semi-condensed | semi-expanded | expanded | extra-expanded | ultra-expanded'.">
-<script src="../../../resources/testharness.js"></script>
-<script src="../../../resources/testharnessreport.js"></script>
-<script src="../../../css/support/parsing-testcommon.js"></script>
-</head>
-<body>
-<script>
-test_valid_value('font-stretch', 'normal');
-test_valid_value('font-stretch', 'ultra-condensed');
-test_valid_value('font-stretch', 'extra-condensed');
-test_valid_value('font-stretch', 'condensed');
-test_valid_value('font-stretch', 'semi-condensed');
-test_valid_value('font-stretch', 'semi-expanded');
-test_valid_value('font-stretch', 'expanded');
-test_valid_value('font-stretch', 'extra-expanded');
-test_valid_value('font-stretch', 'ultra-expanded');
-
-test_valid_value('font-stretch', '234.5%');
-test_valid_value('font-stretch', 'calc(100%)');
-test_valid_value('font-stretch', 'calc(0%)');
-test_valid_value('font-stretch', 'calc(-100%)');
-test_valid_value('font-stretch', 'calc(100% + 100%)', 'calc(200%)');
-test_valid_value('font-stretch', 'calc(100% + (sign(20cqw - 10px) * 5%))', 'calc(100% + (5% * sign(20cqw - 10px)))');
-</script>
-</body>
-</html>

+ 43 - 0
Tests/LibWeb/Text/input/wpt-import/css/css-fonts/parsing/font-width-computed.html

@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Fonts Module Level 4: getComputedStyle().fontWidth</title>
+<link rel="help" href="https://www.w3.org/TR/css-fonts-4/#font-width-prop">
+<meta name="assert" content="font-width computed value is a percentage.">
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script src="../../../css/support/computed-testcommon.js"></script>
+<style>
+  #container {
+    container-type: inline-size;
+    width: 10px;
+  }
+</style>
+</head>
+<body>
+<div id="container">
+  <div id="target"></div>
+</div>
+<script>
+for (const property of ['font-width','font-stretch']) {
+  test_computed_value(property, 'ultra-condensed', '50%');
+  test_computed_value(property, 'extra-condensed', '62.5%');
+  test_computed_value(property, 'condensed', '75%');
+  test_computed_value(property, 'semi-condensed', '87.5%');
+  test_computed_value(property, 'normal', '100%');
+  test_computed_value(property, 'semi-expanded', '112.5%');
+  test_computed_value(property, 'expanded', '125%');
+  test_computed_value(property, 'extra-expanded', '150%');
+  test_computed_value(property, 'ultra-expanded', '200%');
+
+  test_computed_value(property, '234.5%');
+  test_computed_value(property, 'calc(100%)', '100%');
+  test_computed_value(property, 'calc(0%)', '0%');
+  test_computed_value(property, 'calc(-100%)', '0%');
+  test_computed_value(property, 'calc(100% + 100%)', '200%');
+  test_computed_value(property, 'calc(100% + (sign(20cqw - 10px) * 5%))', '95%');
+}
+</script>
+</body>
+</html>

+ 23 - 0
Tests/LibWeb/Text/input/wpt-import/css/css-fonts/parsing/font-width-invalid.html

@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Fonts Module Level 4: parsing font-width with invalid values</title>
+<link rel="help" href="https://www.w3.org/TR/css-fonts-4/#font-width-prop">
+<meta name="assert" content="font-width supports only the grammar 'normal | <percentage [0,∞]> | ultra-condensed | extra-condensed | condensed | semi-condensed | semi-expanded | expanded | extra-expanded | ultra-expanded'.">
+<meta name="assert" content="Values less than 0% are invalid.">
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script src="../../../css/support/parsing-testcommon.js"></script>
+</head>
+<body>
+<script>
+for (const property of ['font-width','font-stretch']) {
+    test_invalid_value(property, 'auto');
+    test_invalid_value(property, 'normal, ultra-condensed');
+    test_invalid_value(property, 'condensed expanded');
+    test_invalid_value(property, '-50%');
+}
+</script>
+</body>
+</html>

+ 34 - 0
Tests/LibWeb/Text/input/wpt-import/css/css-fonts/parsing/font-width-valid.html

@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Fonts Module Level 4: parsing font-width with valid values</title>
+<link rel="help" href="https://www.w3.org/TR/css-fonts-4/#font-width-prop">
+<meta name="assert" content="font-width supports the full grammar 'normal | <percentage [0,∞]> | ultra-condensed | extra-condensed | condensed | semi-condensed | semi-expanded | expanded | extra-expanded | ultra-expanded'.">
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script src="../../../css/support/parsing-testcommon.js"></script>
+</head>
+<body>
+<script>
+for (const property of ['font-width','font-stretch']) {
+    test_valid_value(property, 'normal');
+    test_valid_value(property, 'ultra-condensed');
+    test_valid_value(property, 'extra-condensed');
+    test_valid_value(property, 'condensed');
+    test_valid_value(property, 'semi-condensed');
+    test_valid_value(property, 'semi-expanded');
+    test_valid_value(property, 'expanded');
+    test_valid_value(property, 'extra-expanded');
+    test_valid_value(property, 'ultra-expanded');
+
+    test_valid_value(property, '234.5%');
+    test_valid_value(property, 'calc(100%)');
+    test_valid_value(property, 'calc(0%)');
+    test_valid_value(property, 'calc(-100%)');
+    test_valid_value(property, 'calc(100% + 100%)', 'calc(200%)');
+    test_valid_value(property, 'calc(100% + (sign(20cqw - 10px) * 5%))', 'calc(100% + (5% * sign(20cqw - 10px)))');
+}
+</script>
+</body>
+</html>

+ 1 - 1
Toolchain/BuildVcpkg.py

@@ -10,7 +10,7 @@ def main() -> int:
     script_dir = pathlib.Path(__file__).parent.resolve()
 
     git_repo = "https://github.com/microsoft/vcpkg.git"
-    git_rev = "74ec888e385d189b42d6b398d0bbaa6f1b1d3b0e"  # 2025.02.07
+    git_rev = "ea2a964f9303270322cf3f2d51c265ba146c422d"  # main on 2025-04-01
 
     build_dir = script_dir.parent / "Build"
     build_dir.mkdir(parents=True, exist_ok=True)

+ 1 - 0
UI/AppKit/CMakeLists.txt

@@ -2,6 +2,7 @@ add_library(ladybird_impl STATIC
     ${LADYBIRD_SOURCES}
     Application/Application.mm
     Application/ApplicationDelegate.mm
+    Interface/Autocomplete.mm
     Interface/Event.mm
     Interface/InfoBar.mm
     Interface/LadybirdWebView.mm

+ 33 - 0
UI/AppKit/Interface/Autocomplete.h

@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2025, Tim Flynn <trflynn89@ladybird.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <AK/String.h>
+#include <AK/Vector.h>
+
+#import <Cocoa/Cocoa.h>
+
+@protocol AutocompleteObserver <NSObject>
+
+- (void)onSelectedSuggestion:(String)suggestion;
+
+@end
+
+@interface Autocomplete : NSPopover
+
+- (instancetype)init:(id<AutocompleteObserver>)observer
+     withToolbarItem:(NSToolbarItem*)toolbar_item;
+
+- (void)showWithSuggestions:(Vector<String>)suggestions;
+- (BOOL)close;
+
+- (Optional<String>)selectedSuggestion;
+
+- (BOOL)selectNextSuggestion;
+- (BOOL)selectPreviousSuggestion;
+
+@end

+ 203 - 0
UI/AppKit/Interface/Autocomplete.mm

@@ -0,0 +1,203 @@
+/*
+ * Copyright (c) 2025, Tim Flynn <trflynn89@ladybird.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#import <Interface/Autocomplete.h>
+#import <Utilities/Conversions.h>
+
+static NSString* const AUTOCOMPLETE_IDENTIFIER = @"Autocomplete";
+static constexpr auto MAX_NUMBER_OF_ROWS = 8uz;
+static constexpr auto POPOVER_PADDING = 6uz;
+
+@interface Autocomplete () <NSTableViewDataSource, NSTableViewDelegate>
+{
+    Vector<String> m_suggestions;
+}
+
+@property (nonatomic, weak) id<AutocompleteObserver> observer;
+@property (nonatomic, weak) NSToolbarItem* toolbar_item;
+
+@property (nonatomic, strong) NSTableView* table_view;
+
+@end
+
+@implementation Autocomplete
+
+- (instancetype)init:(id<AutocompleteObserver>)observer
+     withToolbarItem:(NSToolbarItem*)toolbar_item
+{
+    if (self = [super init]) {
+        self.observer = observer;
+        self.toolbar_item = toolbar_item;
+
+        auto* column = [[NSTableColumn alloc] init];
+        [column setEditable:NO];
+
+        self.table_view = [[NSTableView alloc] init];
+        [self.table_view setAction:@selector(selectSuggestion:)];
+        [self.table_view setBackgroundColor:[NSColor clearColor]];
+        [self.table_view setIntercellSpacing:NSMakeSize(0, 5)];
+        [self.table_view setHeaderView:nil];
+        [self.table_view setRefusesFirstResponder:YES];
+        [self.table_view setRowSizeStyle:NSTableViewRowSizeStyleDefault];
+        [self.table_view addTableColumn:column];
+        [self.table_view setDataSource:self];
+        [self.table_view setDelegate:self];
+        [self.table_view setTarget:self];
+
+        auto* scroll_view = [[NSScrollView alloc] init];
+        [scroll_view setHasVerticalScroller:YES];
+        [scroll_view setDocumentView:self.table_view];
+        [scroll_view setDrawsBackground:NO];
+
+        auto* content_view = [[NSView alloc] init];
+        [content_view addSubview:scroll_view];
+
+        auto* controller = [[NSViewController alloc] init];
+        [controller setView:content_view];
+
+        [self setAnimates:NO];
+        [self setBehavior:NSPopoverBehaviorTransient];
+        [self setContentViewController:controller];
+        [self setValue:[NSNumber numberWithBool:YES] forKeyPath:@"shouldHideAnchor"];
+    }
+
+    return self;
+}
+
+#pragma mark - Public methods
+
+- (void)showWithSuggestions:(Vector<String>)suggestions
+{
+    m_suggestions = move(suggestions);
+    [self.table_view reloadData];
+
+    if (m_suggestions.is_empty()) {
+        [self close];
+    } else {
+        [self show];
+    }
+}
+
+- (BOOL)close
+{
+    if (!self.isShown)
+        return NO;
+
+    [super close];
+    return YES;
+}
+
+- (Optional<String>)selectedSuggestion
+{
+    if (!self.isShown || self.table_view.numberOfRows == 0)
+        return {};
+
+    auto row = [self.table_view selectedRow];
+    if (row < 0)
+        return {};
+
+    return m_suggestions[row];
+}
+
+- (BOOL)selectNextSuggestion
+{
+    if (self.table_view.numberOfRows == 0)
+        return NO;
+
+    if (!self.isShown) {
+        [self show];
+        return YES;
+    }
+
+    [self selectRow:[self.table_view selectedRow] + 1];
+    return YES;
+}
+
+- (BOOL)selectPreviousSuggestion
+{
+    if (self.table_view.numberOfRows == 0)
+        return NO;
+
+    if (!self.isShown) {
+        [self show];
+        return YES;
+    }
+
+    [self selectRow:[self.table_view selectedRow] - 1];
+    return YES;
+}
+
+- (void)selectSuggestion:(id)sender
+{
+    if (auto suggestion = [self selectedSuggestion]; suggestion.has_value())
+        [self.observer onSelectedSuggestion:suggestion.release_value()];
+}
+
+#pragma mark - Private methods
+
+- (void)show
+{
+    auto height = (self.table_view.rowHeight + self.table_view.intercellSpacing.height) * min(self.table_view.numberOfRows, MAX_NUMBER_OF_ROWS);
+    auto frame = NSMakeRect(0, 0, [[self.toolbar_item view] frame].size.width, height);
+
+    [self.table_view.enclosingScrollView setFrame:NSInsetRect(frame, 0, POPOVER_PADDING)];
+    [self setContentSize:frame.size];
+
+    [self.table_view deselectAll:nil];
+    [self.table_view scrollRowToVisible:0];
+
+    [self showRelativeToToolbarItem:self.toolbar_item];
+
+    [self showRelativeToRect:self.toolbar_item.view.frame
+                      ofView:self.toolbar_item.view
+               preferredEdge:NSRectEdgeMaxY];
+}
+
+- (void)selectRow:(NSInteger)row
+{
+    if (row < 0)
+        row = self.table_view.numberOfRows - 1;
+    else if (row >= self.table_view.numberOfRows)
+        row = 0;
+
+    [self.table_view selectRowIndexes:[NSIndexSet indexSetWithIndex:row] byExtendingSelection:NO];
+    [self.table_view scrollRowToVisible:[self.table_view selectedRow]];
+}
+
+#pragma mark - NSTableViewDataSource
+
+- (NSInteger)numberOfRowsInTableView:(NSTableView*)tableView
+{
+    return static_cast<NSInteger>(m_suggestions.size());
+}
+
+#pragma mark - NSTableViewDelegate
+
+- (NSView*)tableView:(NSTableView*)table_view
+    viewForTableColumn:(NSTableColumn*)table_column
+                   row:(NSInteger)row
+{
+    NSTableCellView* view = [table_view makeViewWithIdentifier:AUTOCOMPLETE_IDENTIFIER owner:self];
+
+    if (view == nil) {
+        view = [[NSTableCellView alloc] initWithFrame:NSZeroRect];
+
+        NSTextField* text_field = [[NSTextField alloc] initWithFrame:NSZeroRect];
+        [text_field setBezeled:NO];
+        [text_field setDrawsBackground:NO];
+        [text_field setEditable:NO];
+        [text_field setSelectable:NO];
+
+        [view addSubview:text_field];
+        [view setTextField:text_field];
+        [view setIdentifier:AUTOCOMPLETE_IDENTIFIER];
+    }
+
+    [view.textField setStringValue:Ladybird::string_to_ns_string(m_suggestions[row])];
+    return view;
+}
+
+@end

+ 71 - 10
UI/AppKit/Interface/TabController.mm

@@ -6,12 +6,15 @@
 
 #include <LibWeb/Loader/UserAgent.h>
 #include <LibWebView/Application.h>
+#include <LibWebView/Autocomplete.h>
 #include <LibWebView/SearchEngine.h>
 #include <LibWebView/URL.h>
 #include <LibWebView/UserAgent.h>
 #include <LibWebView/ViewImplementation.h>
 
 #import <Application/ApplicationDelegate.h>
+#import <Interface/Autocomplete.h>
+#import <Interface/Event.h>
 #import <Interface/LadybirdWebView.h>
 #import <Interface/Tab.h>
 #import <Interface/TabController.h>
@@ -48,7 +51,7 @@ static NSString* const TOOLBAR_TAB_OVERVIEW_IDENTIFIER = @"ToolbarTabOverviewIde
 
 @end
 
-@interface TabController () <NSToolbarDelegate, NSSearchFieldDelegate>
+@interface TabController () <NSToolbarDelegate, NSSearchFieldDelegate, AutocompleteObserver>
 {
     u64 m_page_index;
 
@@ -56,6 +59,8 @@ static NSString* const TOOLBAR_TAB_OVERVIEW_IDENTIFIER = @"ToolbarTabOverviewIde
 
     TabSettings m_settings;
 
+    OwnPtr<WebView::Autocomplete> m_autocomplete;
+
     bool m_can_navigate_back;
     bool m_can_navigate_forward;
 }
@@ -73,6 +78,8 @@ static NSString* const TOOLBAR_TAB_OVERVIEW_IDENTIFIER = @"ToolbarTabOverviewIde
 @property (nonatomic, strong) NSToolbarItem* new_tab_toolbar_item;
 @property (nonatomic, strong) NSToolbarItem* tab_overview_toolbar_item;
 
+@property (nonatomic, strong) Autocomplete* autocomplete;
+
 @property (nonatomic, assign) NSLayoutConstraint* location_toolbar_item_width;
 
 @end
@@ -91,6 +98,8 @@ static NSString* const TOOLBAR_TAB_OVERVIEW_IDENTIFIER = @"ToolbarTabOverviewIde
 - (instancetype)init
 {
     if (self = [super init]) {
+        __weak TabController* weak_self = self;
+
         self.toolbar = [[NSToolbar alloc] initWithIdentifier:TOOLBAR_IDENTIFIER];
         [self.toolbar setDelegate:self];
         [self.toolbar setDisplayMode:NSToolbarDisplayModeIconOnly];
@@ -107,6 +116,18 @@ static NSString* const TOOLBAR_TAB_OVERVIEW_IDENTIFIER = @"ToolbarTabOverviewIde
         if (auto const& user_agent_preset = WebView::Application::web_content_options().user_agent_preset; user_agent_preset.has_value())
             m_settings.user_agent_name = *user_agent_preset;
 
+        self.autocomplete = [[Autocomplete alloc] init:self withToolbarItem:self.location_toolbar_item];
+        m_autocomplete = make<WebView::Autocomplete>();
+
+        m_autocomplete->on_autocomplete_query_complete = [weak_self](auto suggestions) {
+            TabController* self = weak_self;
+            if (self == nil) {
+                return;
+            }
+
+            [self.autocomplete showWithSuggestions:move(suggestions)];
+        };
+
         m_can_navigate_back = false;
         m_can_navigate_forward = false;
     }
@@ -278,6 +299,22 @@ static NSString* const TOOLBAR_TAB_OVERVIEW_IDENTIFIER = @"ToolbarTabOverviewIde
     [location_search_field setAttributedStringValue:attributed_url];
 }
 
+- (BOOL)navigateToLocation:(String)location
+{
+    Optional<StringView> search_engine_url;
+    if (auto const& search_engine = WebView::Application::settings().search_engine(); search_engine.has_value())
+        search_engine_url = search_engine->query_url;
+
+    if (auto url = WebView::sanitize_url(location, search_engine_url); url.has_value()) {
+        [self loadURL:*url];
+    }
+
+    [self.window makeFirstResponder:nil];
+    [self.autocomplete close];
+
+    return YES;
+}
+
 - (void)updateNavigationButtonStates
 {
     auto* navigate_back_button = (NSButton*)[[self navigate_back_toolbar_item] view];
@@ -685,21 +722,30 @@ static NSString* const TOOLBAR_TAB_OVERVIEW_IDENTIFIER = @"ToolbarTabOverviewIde
                textView:(NSTextView*)text_view
     doCommandBySelector:(SEL)selector
 {
-    if (selector != @selector(insertNewline:)) {
-        return NO;
+    if (selector == @selector(cancelOperation:)) {
+        if ([self.autocomplete close])
+            return YES;
     }
 
-    auto url_string = Ladybird::ns_string_to_string([[text_view textStorage] string]);
+    if (selector == @selector(moveDown:)) {
+        if ([self.autocomplete selectNextSuggestion])
+            return YES;
+    }
 
-    Optional<StringView> search_engine_url;
-    if (auto const& search_engine = WebView::Application::settings().search_engine(); search_engine.has_value())
-        search_engine_url = search_engine->query_url;
+    if (selector == @selector(moveUp:)) {
+        if ([self.autocomplete selectPreviousSuggestion])
+            return YES;
+    }
 
-    if (auto url = WebView::sanitize_url(url_string, search_engine_url); url.has_value()) {
-        [self loadURL:*url];
+    if (selector != @selector(insertNewline:)) {
+        return NO;
     }
 
-    [self.window makeFirstResponder:nil];
+    auto location = [self.autocomplete selectedSuggestion].value_or_lazy_evaluated([&]() {
+        return Ladybird::ns_string_to_string([[text_view textStorage] string]);
+    });
+
+    [self navigateToLocation:move(location)];
     return YES;
 }
 
@@ -711,4 +757,19 @@ static NSString* const TOOLBAR_TAB_OVERVIEW_IDENTIFIER = @"ToolbarTabOverviewIde
     [self setLocationFieldText:url_string];
 }
 
+- (void)controlTextDidChange:(NSNotification*)notification
+{
+    auto* location_search_field = (LocationSearchField*)[self.location_toolbar_item view];
+
+    auto url_string = Ladybird::ns_string_to_string([location_search_field stringValue]);
+    m_autocomplete->query_autocomplete_engine(move(url_string));
+}
+
+#pragma mark - AutocompleteObserver
+
+- (void)onSelectedSuggestion:(String)suggestion
+{
+    [self navigateToLocation:move(suggestion)];
+}
+
 @end

+ 0 - 172
UI/Qt/AutoComplete.cpp

@@ -1,172 +0,0 @@
-/*
- * Copyright (c) 2023, Cameron Youell <cameronyouell@gmail.com>
- *
- * SPDX-License-Identifier: BSD-2-Clause
- */
-
-#include <AK/JsonArray.h>
-#include <AK/JsonObject.h>
-#include <LibURL/URL.h>
-#include <UI/Qt/AutoComplete.h>
-#include <UI/Qt/Settings.h>
-
-namespace Ladybird {
-
-AutoComplete::AutoComplete(QWidget* parent)
-    : QCompleter(parent)
-{
-    m_tree_view = new QTreeView(parent);
-    m_manager = new QNetworkAccessManager(this);
-    m_auto_complete_model = new AutoCompleteModel(this);
-
-    setCompletionMode(QCompleter::UnfilteredPopupCompletion);
-    setModel(m_auto_complete_model);
-    setPopup(m_tree_view);
-
-    m_tree_view->setRootIsDecorated(false);
-    m_tree_view->setHeaderHidden(true);
-
-    connect(this, QOverload<QModelIndex const&>::of(&QCompleter::activated), this, [&](QModelIndex const& index) {
-        emit activated(index);
-    });
-
-    connect(m_manager, &QNetworkAccessManager::finished, this, [&](QNetworkReply* reply) {
-        auto result = got_network_response(reply);
-        if (result.is_error())
-            dbgln("AutoComplete::got_network_response: Error {}", result.error());
-    });
-}
-
-ErrorOr<Vector<String>> AutoComplete::parse_google_autocomplete(JsonValue const& json)
-{
-    if (!json.is_array())
-        return Error::from_string_literal("Expected Google autocomplete response to be a JSON array");
-
-    auto const& values = json.as_array();
-
-    if (values.size() != 5)
-        return Error::from_string_literal("Invalid Google autocomplete response, expected 5 elements in array");
-
-    if (!values[0].is_string())
-        return Error::from_string_literal("Invalid Google autocomplete response, expected first element to be a string");
-
-    auto const& query = values[0].as_string();
-    if (query != m_query)
-        return Error::from_string_literal("Invalid Google autocomplete response, query does not match");
-
-    if (!values[1].is_array())
-        return Error::from_string_literal("Invalid Google autocomplete response, expected second element to be an array");
-    auto const& suggestions_array = values[1].as_array().values();
-
-    Vector<String> results;
-    results.ensure_capacity(suggestions_array.size());
-    for (auto const& suggestion : suggestions_array)
-        results.unchecked_append(suggestion.as_string());
-
-    return results;
-}
-
-ErrorOr<Vector<String>> AutoComplete::parse_duckduckgo_autocomplete(JsonValue const& json)
-{
-    if (!json.is_array())
-        return Error::from_string_literal("Expected DuckDuckGo autocomplete response to be a JSON array");
-
-    Vector<String> results;
-    results.ensure_capacity(json.as_array().size());
-
-    for (auto const& suggestion : json.as_array().values()) {
-        if (!suggestion.is_object())
-            return Error::from_string_literal("Invalid DuckDuckGo autocomplete response, expected value to be an object");
-
-        if (auto value = suggestion.as_object().get_string("phrase"sv); value.has_value())
-            results.unchecked_append(*value);
-    }
-
-    return results;
-}
-
-ErrorOr<Vector<String>> AutoComplete::parse_yahoo_autocomplete(JsonValue const& json)
-{
-    if (!json.is_object())
-        return Error::from_string_literal("Expected Yahoo autocomplete response to be a JSON array");
-
-    auto query = json.as_object().get_string("q"sv);
-    if (!query.has_value())
-        return Error::from_string_literal("Invalid Yahoo autocomplete response, expected \"q\" to be a string");
-    if (query != m_query)
-        return Error::from_string_literal("Invalid Yahoo autocomplete response, query does not match");
-
-    auto suggestions = json.as_object().get_array("r"sv);
-    if (!suggestions.has_value())
-        return Error::from_string_literal("Invalid Yahoo autocomplete response, expected \"r\" to be an object");
-
-    Vector<String> results;
-    results.ensure_capacity(suggestions->size());
-
-    for (auto const& suggestion : suggestions->values()) {
-        if (!suggestion.is_object())
-            return Error::from_string_literal("Invalid Yahoo autocomplete response, expected value to be an object");
-
-        auto result = suggestion.as_object().get_string("k"sv);
-        if (!result.has_value())
-            return Error::from_string_literal("Invalid Yahoo autocomplete response, expected \"k\" to be a string");
-
-        results.unchecked_append(*result);
-    }
-
-    return results;
-}
-
-ErrorOr<void> AutoComplete::got_network_response(QNetworkReply* reply)
-{
-    if (reply->error() == QNetworkReply::NetworkError::OperationCanceledError)
-        return {};
-
-    auto reply_data = ak_string_from_qstring(reply->readAll());
-    auto json = TRY(JsonValue::from_string(reply_data));
-
-    auto const& engine_name = Settings::the()->autocomplete_engine().name;
-
-    Vector<String> results;
-    if (engine_name == "Google")
-        results = TRY(parse_google_autocomplete(json));
-    else if (engine_name == "DuckDuckGo")
-        results = TRY(parse_duckduckgo_autocomplete(json));
-    else if (engine_name == "Yahoo")
-        results = TRY(parse_yahoo_autocomplete(json));
-    else
-        return Error::from_string_literal("Invalid engine name");
-
-    constexpr size_t MAX_AUTOCOMPLETE_RESULTS = 6;
-    if (results.is_empty()) {
-        results.append(m_query);
-    } else if (results.size() > MAX_AUTOCOMPLETE_RESULTS) {
-        results.shrink(MAX_AUTOCOMPLETE_RESULTS);
-    }
-
-    m_auto_complete_model->replace_suggestions(move(results));
-    return {};
-}
-
-String AutoComplete::auto_complete_url_from_query(StringView query)
-{
-    auto autocomplete_engine = ak_string_from_qstring(Settings::the()->autocomplete_engine().url);
-    return MUST(autocomplete_engine.replace("{}"sv, URL::percent_encode(query), ReplaceMode::FirstOnly));
-}
-
-void AutoComplete::clear_suggestions()
-{
-    m_auto_complete_model->clear();
-}
-
-void AutoComplete::get_search_suggestions(String search_string)
-{
-    m_query = move(search_string);
-    if (m_reply)
-        m_reply->abort();
-
-    QNetworkRequest request { QUrl(qstring_from_ak_string(auto_complete_url_from_query(m_query))) };
-    m_reply = m_manager->get(request);
-}
-
-}

+ 0 - 94
UI/Qt/AutoComplete.h

@@ -1,94 +0,0 @@
-/*
- * Copyright (c) 2023, Cameron Youell <cameronyouell@gmail.com>
- *
- * SPDX-License-Identifier: BSD-2-Clause
- */
-
-#pragma once
-
-#include <AK/Forward.h>
-#include <AK/String.h>
-#include <UI/Qt/StringUtils.h>
-
-#include <QCompleter>
-#include <QNetworkReply>
-#include <QTreeView>
-
-namespace Ladybird {
-
-class AutoCompleteModel final : public QAbstractListModel {
-    Q_OBJECT
-public:
-    explicit AutoCompleteModel(QObject* parent)
-        : QAbstractListModel(parent)
-    {
-    }
-
-    virtual int rowCount(QModelIndex const& parent = QModelIndex()) const override { return parent.isValid() ? 0 : m_suggestions.size(); }
-    virtual QVariant data(QModelIndex const& index, int role = Qt::DisplayRole) const override
-    {
-        if (role == Qt::DisplayRole || role == Qt::EditRole)
-            return qstring_from_ak_string(m_suggestions[index.row()]);
-        return {};
-    }
-
-    void add(String const& result)
-    {
-        beginInsertRows({}, m_suggestions.size(), m_suggestions.size());
-        m_suggestions.append(result);
-        endInsertRows();
-    }
-
-    void clear()
-    {
-        beginResetModel();
-        m_suggestions.clear();
-        endResetModel();
-    }
-
-    void replace_suggestions(Vector<String> suggestions)
-    {
-        beginInsertRows({}, m_suggestions.size(), m_suggestions.size());
-        m_suggestions = suggestions;
-        endInsertRows();
-    }
-
-private:
-    AK::Vector<String> m_suggestions;
-};
-
-class AutoComplete final : public QCompleter {
-    Q_OBJECT
-
-public:
-    AutoComplete(QWidget* parent);
-
-    virtual QString pathFromIndex(QModelIndex const& index) const override
-    {
-        return index.data(Qt::DisplayRole).toString();
-    }
-
-    void get_search_suggestions(String);
-    void clear_suggestions();
-
-signals:
-    void activated(QModelIndex const&);
-
-private:
-    static String auto_complete_url_from_query(StringView query);
-
-    ErrorOr<void> got_network_response(QNetworkReply* reply);
-
-    ErrorOr<Vector<String>> parse_google_autocomplete(JsonValue const&);
-    ErrorOr<Vector<String>> parse_duckduckgo_autocomplete(JsonValue const&);
-    ErrorOr<Vector<String>> parse_yahoo_autocomplete(JsonValue const&);
-
-    QNetworkAccessManager* m_manager;
-    AutoCompleteModel* m_auto_complete_model;
-    QTreeView* m_tree_view;
-    QNetworkReply* m_reply { nullptr };
-
-    String m_query;
-};
-
-}

+ 43 - 0
UI/Qt/Autocomplete.cpp

@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2023, Cameron Youell <cameronyouell@gmail.com>
+ * Copyright (c) 2025, Tim Flynn <trflynn89@ladybird.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <LibWebView/Autocomplete.h>
+#include <UI/Qt/Autocomplete.h>
+#include <UI/Qt/StringUtils.h>
+
+namespace Ladybird {
+
+Autocomplete::Autocomplete(QWidget* parent)
+    : QCompleter(parent)
+    , m_autocomplete(make<WebView::Autocomplete>())
+    , m_model(new QStringListModel(this))
+    , m_popup(new QListView(parent))
+{
+    m_autocomplete->on_autocomplete_query_complete = [this](auto const& suggestions) {
+        if (suggestions.is_empty()) {
+            m_model->setStringList({});
+        } else {
+            QStringList list;
+            for (auto const& suggestion : suggestions)
+                list.append(qstring_from_ak_string(suggestion));
+
+            m_model->setStringList(list);
+            complete();
+        }
+    };
+
+    setCompletionMode(QCompleter::UnfilteredPopupCompletion);
+    setModel(m_model);
+    setPopup(m_popup);
+}
+
+void Autocomplete::query_autocomplete_engine(String search_string)
+{
+    m_autocomplete->query_autocomplete_engine(move(search_string));
+}
+
+}

+ 35 - 0
UI/Qt/Autocomplete.h

@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2023, Cameron Youell <cameronyouell@gmail.com>
+ * Copyright (c) 2025, Tim Flynn <trflynn89@ladybird.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <AK/NonnullOwnPtr.h>
+#include <AK/String.h>
+#include <LibWebView/Forward.h>
+
+#include <QCompleter>
+#include <QListView>
+#include <QStringListModel>
+
+namespace Ladybird {
+
+class Autocomplete final : public QCompleter {
+    Q_OBJECT
+
+public:
+    explicit Autocomplete(QWidget* parent);
+
+    void query_autocomplete_engine(String);
+
+private:
+    NonnullOwnPtr<WebView::Autocomplete> m_autocomplete;
+
+    QStringListModel* m_model { nullptr };
+    QListView* m_popup { nullptr };
+};
+
+}

+ 0 - 8
UI/Qt/BrowserWindow.cpp

@@ -35,7 +35,6 @@
 #include <QPlainTextEdit>
 #include <QShortcut>
 #include <QStatusBar>
-#include <QTabBar>
 #include <QWindow>
 
 namespace Ladybird {
@@ -98,12 +97,6 @@ BrowserWindow::BrowserWindow(Vector<URL::URL> const& initial_urls, IsPopupWindow
         });
     }
 
-    QObject::connect(Settings::the(), &Settings::enable_do_not_track_changed, this, [this](bool enable) {
-        for_each_tab([enable](auto& tab) {
-            tab.set_enable_do_not_track(enable);
-        });
-    });
-
     QObject::connect(Settings::the(), &Settings::preferred_languages_changed, this, [this](QStringList languages) {
         Vector<String> preferred_languages;
         preferred_languages.ensure_capacity(languages.length());
@@ -874,7 +867,6 @@ void BrowserWindow::initialize_tab(Tab* tab)
     tab->set_user_agent_string(user_agent_string());
     tab->set_preferred_languages(preferred_languages);
     tab->set_navigator_compatibility_mode(navigator_compatibility_mode());
-    tab->set_enable_do_not_track(Settings::the()->enable_do_not_track());
     tab->view().set_preferred_color_scheme(m_preferred_color_scheme);
 }
 

+ 1 - 0
UI/Qt/BrowserWindow.h

@@ -18,6 +18,7 @@
 #include <QLineEdit>
 #include <QMainWindow>
 #include <QMenuBar>
+#include <QTabBar>
 #include <QTabWidget>
 #include <QToolBar>
 

+ 2 - 2
UI/Qt/CMakeLists.txt

@@ -1,7 +1,7 @@
 qt_add_executable(ladybird ${LADYBIRD_SOURCES})
 target_sources(ladybird PRIVATE
     Application.cpp
-    AutoComplete.cpp
+    Autocomplete.cpp
     BrowserWindow.cpp
     FindInPageWidget.cpp
     Icon.cpp
@@ -16,5 +16,5 @@ target_sources(ladybird PRIVATE
     ladybird.qrc
     main.cpp
 )
-target_link_libraries(ladybird PRIVATE Qt::Core Qt::Gui Qt::Network Qt::Widgets)
+target_link_libraries(ladybird PRIVATE Qt::Core Qt::Gui Qt::Widgets)
 create_ladybird_bundle(ladybird)

+ 13 - 17
UI/Qt/LocationEdit.cpp

@@ -7,8 +7,8 @@
 #include <LibURL/URL.h>
 #include <LibWebView/Application.h>
 #include <LibWebView/URL.h>
+#include <UI/Qt/Autocomplete.h>
 #include <UI/Qt/LocationEdit.h>
-#include <UI/Qt/Settings.h>
 #include <UI/Qt/StringUtils.h>
 
 #include <QApplication>
@@ -20,13 +20,13 @@ namespace Ladybird {
 
 LocationEdit::LocationEdit(QWidget* parent)
     : QLineEdit(parent)
+    , m_autocomplete(new Autocomplete(this))
 {
     update_placeholder();
 
-    m_autocomplete = make<AutoComplete>(this);
-    this->setCompleter(m_autocomplete);
+    setCompleter(m_autocomplete);
 
-    connect(m_autocomplete, &AutoComplete::activated, [&](QModelIndex const&) {
+    connect(m_autocomplete, QOverload<QModelIndex const&>::of(&QCompleter::activated), [&](QModelIndex const&) {
         emit returnPressed();
     });
 
@@ -50,15 +50,7 @@ LocationEdit::LocationEdit(QWidget* parent)
     });
 
     connect(this, &QLineEdit::textEdited, [this] {
-        if (!Settings::the()->enable_autocomplete()) {
-            m_autocomplete->clear_suggestions();
-            return;
-        }
-
-        auto cursor_position = cursorPosition();
-
-        m_autocomplete->get_search_suggestions(ak_string_from_qstring(text()));
-        setCursorPosition(cursor_position);
+        m_autocomplete->query_autocomplete_engine(ak_string_from_qstring(text()));
     });
 
     connect(this, &QLineEdit::textChanged, this, &LocationEdit::highlight_location);
@@ -68,12 +60,15 @@ void LocationEdit::focusInEvent(QFocusEvent* event)
 {
     QLineEdit::focusInEvent(event);
     highlight_location();
-    QTimer::singleShot(0, this, &QLineEdit::selectAll);
+
+    if (event->reason() != Qt::PopupFocusReason)
+        QTimer::singleShot(0, this, &QLineEdit::selectAll);
 }
 
 void LocationEdit::focusOutEvent(QFocusEvent* event)
 {
     QLineEdit::focusOutEvent(event);
+
     if (m_url_is_hidden) {
         m_url_is_hidden = false;
         if (text().isEmpty())
@@ -142,13 +137,14 @@ void LocationEdit::highlight_location()
     QCoreApplication::sendEvent(this, &event);
 }
 
-void LocationEdit::set_url(URL::URL const& url)
+void LocationEdit::set_url(URL::URL url)
 {
-    m_url = url;
+    m_url = AK::move(url);
+
     if (m_url_is_hidden) {
         clear();
     } else {
-        setText(qstring_from_ak_string(url.serialize()));
+        setText(qstring_from_ak_string(m_url.serialize()));
         setCursorPosition(0);
     }
 }

+ 6 - 4
UI/Qt/LocationEdit.h

@@ -8,12 +8,13 @@
 
 #include <AK/OwnPtr.h>
 #include <LibWebView/Settings.h>
-#include <UI/Qt/AutoComplete.h>
 
 #include <QLineEdit>
 
 namespace Ladybird {
 
+class Autocomplete;
+
 class LocationEdit final
     : public QLineEdit
     , public WebView::SettingsObserver {
@@ -22,8 +23,8 @@ class LocationEdit final
 public:
     explicit LocationEdit(QWidget*);
 
-    URL::URL url() const { return m_url; }
-    void set_url(URL::URL const&);
+    URL::URL const& url() const { return m_url; }
+    void set_url(URL::URL);
 
     bool url_is_hidden() const { return m_url_is_hidden; }
     void set_url_is_hidden(bool url_is_hidden) { m_url_is_hidden = url_is_hidden; }
@@ -36,7 +37,8 @@ private:
 
     void update_placeholder();
     void highlight_location();
-    AK::OwnPtr<AutoComplete> m_autocomplete;
+
+    Autocomplete* m_autocomplete { nullptr };
 
     URL::URL m_url;
     bool m_url_is_hidden { false };

+ 0 - 35
UI/Qt/Settings.cpp

@@ -65,41 +65,6 @@ void Settings::set_preferred_languages(QStringList const& languages)
     emit preferred_languages_changed(languages);
 }
 
-Settings::EngineProvider Settings::autocomplete_engine()
-{
-    EngineProvider engine_provider;
-    engine_provider.name = m_qsettings->value("autocomplete_engine_name", "Google").toString();
-    engine_provider.url = m_qsettings->value("autocomplete_engine", "https://www.google.com/complete/search?client=chrome&q={}").toString();
-    return engine_provider;
-}
-
-void Settings::set_autocomplete_engine(EngineProvider const& engine_provider)
-{
-    m_qsettings->setValue("autocomplete_engine_name", engine_provider.name);
-    m_qsettings->setValue("autocomplete_engine", engine_provider.url);
-}
-
-bool Settings::enable_autocomplete()
-{
-    return m_qsettings->value("enable_autocomplete", false).toBool();
-}
-
-void Settings::set_enable_autocomplete(bool enable)
-{
-    m_qsettings->setValue("enable_autocomplete", enable);
-}
-
-bool Settings::enable_do_not_track()
-{
-    return m_qsettings->value("enable_do_not_track", false).toBool();
-}
-
-void Settings::set_enable_do_not_track(bool enable)
-{
-    m_qsettings->setValue("enable_do_not_track", enable);
-    emit enable_do_not_track_changed(enable);
-}
-
 bool Settings::show_menubar()
 {
     return m_qsettings->value("show_menubar", false).toBool();

+ 0 - 13
UI/Qt/Settings.h

@@ -44,19 +44,6 @@ public:
     QStringList preferred_languages();
     void set_preferred_languages(QStringList const& languages);
 
-    struct EngineProvider {
-        QString name;
-        QString url;
-    };
-    EngineProvider autocomplete_engine();
-    void set_autocomplete_engine(EngineProvider const& engine);
-
-    bool enable_autocomplete();
-    void set_enable_autocomplete(bool enable);
-
-    bool enable_do_not_track();
-    void set_enable_do_not_track(bool enable);
-
     bool show_menubar();
     void set_show_menubar(bool show_menubar);
 

+ 0 - 53
UI/Qt/SettingsDialog.cpp

@@ -32,64 +32,11 @@ SettingsDialog::SettingsDialog(QMainWindow* window)
         close();
     });
 
-    m_enable_autocomplete = new QCheckBox(this);
-    m_enable_autocomplete->setChecked(Settings::the()->enable_autocomplete());
-
-    m_autocomplete_engine_dropdown = new QPushButton(this);
-    m_autocomplete_engine_dropdown->setText(Settings::the()->autocomplete_engine().name);
-    m_autocomplete_engine_dropdown->setMaximumWidth(200);
-
-    m_enable_do_not_track = new QCheckBox(this);
-    m_enable_do_not_track->setChecked(Settings::the()->enable_do_not_track());
-#if (QT_VERSION > QT_VERSION_CHECK(6, 7, 0))
-    QObject::connect(m_enable_do_not_track, &QCheckBox::checkStateChanged, this, [&](int state) {
-#else
-    QObject::connect(m_enable_do_not_track, &QCheckBox::stateChanged, this, [&](int state) {
-#endif
-        Settings::the()->set_enable_do_not_track(state == Qt::Checked);
-    });
-
-    setup_autocomplete_engine();
-
     m_layout->addRow(new QLabel("Preferred Language(s)", this), m_preferred_languages);
-    m_layout->addRow(new QLabel("Enable Autocomplete", this), m_enable_autocomplete);
-    m_layout->addRow(new QLabel("Autocomplete Engine", this), m_autocomplete_engine_dropdown);
-    m_layout->addRow(new QLabel("Send web sites a \"Do Not Track\" request", this), m_enable_do_not_track);
 
     setWindowTitle("Settings");
     setLayout(m_layout);
     resize(600, 250);
 }
 
-void SettingsDialog::setup_autocomplete_engine()
-{
-    // FIXME: These should be centralized in LibWebView.
-    Vector<Settings::EngineProvider> autocomplete_engines = {
-        { "DuckDuckGo", "https://duckduckgo.com/ac/?q={}" },
-        { "Google", "https://www.google.com/complete/search?client=chrome&q={}" },
-        { "Yahoo", "https://search.yahoo.com/sugg/gossip/gossip-us-ura/?output=sd1&command={}" },
-    };
-
-    QMenu* autocomplete_engine_menu = new QMenu(this);
-    for (auto& autocomplete_engine : autocomplete_engines) {
-        QAction* action = new QAction(autocomplete_engine.name, this);
-        connect(action, &QAction::triggered, this, [&, autocomplete_engine] {
-            Settings::the()->set_autocomplete_engine(autocomplete_engine);
-            m_autocomplete_engine_dropdown->setText(autocomplete_engine.name);
-        });
-        autocomplete_engine_menu->addAction(action);
-    }
-    m_autocomplete_engine_dropdown->setMenu(autocomplete_engine_menu);
-    m_autocomplete_engine_dropdown->setEnabled(Settings::the()->enable_autocomplete());
-
-#if (QT_VERSION > QT_VERSION_CHECK(6, 7, 0))
-    connect(m_enable_autocomplete, &QCheckBox::checkStateChanged, this, [&](int state) {
-#else
-    connect(m_enable_autocomplete, &QCheckBox::stateChanged, this, [&](int state) {
-#endif
-        Settings::the()->set_enable_autocomplete(state == Qt::Checked);
-        m_autocomplete_engine_dropdown->setEnabled(state == Qt::Checked);
-    });
-}
-
 }

+ 0 - 5
UI/Qt/SettingsDialog.h

@@ -23,14 +23,9 @@ public:
     explicit SettingsDialog(QMainWindow* window);
 
 private:
-    void setup_autocomplete_engine();
-
     QFormLayout* m_layout;
     QMainWindow* m_window { nullptr };
     QLineEdit* m_preferred_languages { nullptr };
-    QCheckBox* m_enable_autocomplete { nullptr };
-    QPushButton* m_autocomplete_engine_dropdown { nullptr };
-    QCheckBox* m_enable_do_not_track { nullptr };
 };
 
 }

+ 0 - 5
UI/Qt/Tab.cpp

@@ -943,9 +943,4 @@ void Tab::set_preferred_languages(ReadonlySpan<String> preferred_languages)
     m_view->set_preferred_languages(preferred_languages);
 }
 
-void Tab::set_enable_do_not_track(bool enable)
-{
-    m_view->set_enable_do_not_track(enable);
-}
-
 }

+ 0 - 2
UI/Qt/Tab.h

@@ -90,8 +90,6 @@ public:
 
     void set_preferred_languages(ReadonlySpan<String> preferred_languages);
 
-    void set_enable_do_not_track(bool);
-
     bool url_is_hidden() const { return m_location_edit->url_is_hidden(); }
     void set_url_is_hidden(bool url_is_hidden) { m_location_edit->set_url_is_hidden(url_is_hidden); }
 

+ 1 - 0
UI/Qt/TabBar.cpp

@@ -14,6 +14,7 @@
 #include <QContextMenuEvent>
 #include <QEvent>
 #include <QPushButton>
+#include <QStyleOption>
 #include <QStylePainter>
 
 namespace Ladybird {

+ 7 - 1
vcpkg.json

@@ -1,5 +1,5 @@
 {
-  "builtin-baseline": "74ec888e385d189b42d6b398d0bbaa6f1b1d3b0e",
+  "builtin-baseline": "ea2a964f9303270322cf3f2d51c265ba146c422d",
   "dependencies": [
     {
       "name": "angle",
@@ -118,6 +118,12 @@
       "name": "vulkan",
       "platform": "!android"
     },
+    {
+      "name": "tiff",
+      "features": [
+        "zstd"
+      ]
+    }, 
     {
       "name": "vulkan-headers",
       "platform": "!android"