Skip to content

WKWebView.URL should not need not parse the URL string every time it is called#62522

Merged
webkit-commit-queue merged 1 commit into
WebKit:mainfrom
cdumez:312009_WKWebView_URL
Apr 12, 2026
Merged

WKWebView.URL should not need not parse the URL string every time it is called#62522
webkit-commit-queue merged 1 commit into
WebKit:mainfrom
cdumez:312009_WKWebView_URL

Conversation

@cdumez
Copy link
Copy Markdown
Contributor

@cdumez cdumez commented Apr 11, 2026

56d2552

WKWebView.URL should not need not parse the URL string every time it is called
https://bugs.webkit.org/show_bug.cgi?id=312009
rdar://174434204

Reviewed by Darin Adler.

Update PageLoadState to store urls as URL, not String. Otherwise, APIs
like WKWebView.URL have to keep re-parsing the URL string every thing
they're called.

* Source/WTF/wtf/URL.cpp:
(WTF::aboutBlankURL):
(WTF::aboutSrcDocURL):
* Source/WTF/wtf/URL.h:
* Source/WebKit/UIProcess/API/C/WKPage.cpp:
(WKPageSetPageUIClient):
(WKPageCopyPendingAPIRequestURL):
* Source/WebKit/UIProcess/API/C/mac/WKPagePrivateMac.mm:
(-[WKObservablePageState URL]):
(-[WKObservablePageState unreachableURL]):
* Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm:
(-[WKWebView URL]):
(-[WKWebView _unreachableURL]):
(-[WKWebView _committedURL]):
* Source/WebKit/UIProcess/API/Cocoa/WKWebViewInternal.h:
* Source/WebKit/UIProcess/API/glib/WebKitWebView.cpp:
(PageLoadStateObserver::didChangeActiveURL):
(webkitWebViewWillStartLoad):
(webkitWebViewLoadChanged):
(webkitWebViewGetLoadDecisionForIcons):
(webkitWebViewUpdatePageIcons):
(webkitWebViewSetIcon):
* Source/WebKit/UIProcess/API/gtk/WebKitRemoteInspectorProtocolHandler.cpp:
* Source/WebKit/UIProcess/API/gtk/WebKitWebViewGtk.cpp:
(webkitWebViewScriptDialog):
* Source/WebKit/UIProcess/Automation/WebAutomationSession.cpp:
(WebKit::WebAutomationSession::buildBrowsingContextForPage):
(WebKit::WebAutomationSession::addSingleCookie):
(WebKit::WebAutomationSession::deleteAllCookies):
* Source/WebKit/UIProcess/Cocoa/SOAuthorization/NavigationSOAuthorizationSession.h:
* Source/WebKit/UIProcess/Cocoa/UIDelegate.mm:
(WebKit::UIDelegate::UIClient::decidePolicyForGeolocationPermissionRequest):
(WebKit::UIDelegate::UIClient::shouldAllowDeviceOrientationAndMotionAccess):
* Source/WebKit/UIProcess/Cocoa/WebPageProxyCocoa.mm:
(WebKit::WebPageProxy::shouldAllowAutoFillForCellularIdentifiers const):
* Source/WebKit/UIProcess/Inspector/socket/RemoteInspectorProtocolHandler.cpp:
* Source/WebKit/UIProcess/Network/NetworkProcessProxy.cpp:
(WebKit::NetworkProcessProxy::deleteWebsiteDataInWebProcessesForOrigin):
* Source/WebKit/UIProcess/PageLoadState.cpp:
(WebKit::PageLoadState::reset):
(WebKit::PageLoadState::activeURL):
(WebKit::PageLoadState::hasOnlySecureContent):
(WebKit::PageLoadState::didExplicitOpen):
(WebKit::PageLoadState::didStartProvisionalLoad):
(WebKit::PageLoadState::didReceiveServerRedirectForProvisionalLoad):
(WebKit::PageLoadState::didFailProvisionalLoad):
(WebKit::PageLoadState::didCommitLoad):
(WebKit::PageLoadState::didSameDocumentNavigation):
(WebKit::PageLoadState::setUnreachableURL):
* Source/WebKit/UIProcess/PageLoadState.h:
(WebKit::PageLoadState::activeURL const):
* Source/WebKit/UIProcess/RemotePageProxy.cpp:
(WebKit::RemotePageProxy::injectPageIntoNewProcess):
(WebKit::RemotePageProxy::setDrawingArea):
* Source/WebKit/UIProcess/UserMediaPermissionRequestManagerProxy.cpp:
(WebKit::UserMediaPermissionRequestManagerProxy::decidePolicyForUserMediaPermissionRequest):
(WebKit::UserMediaPermissionRequestManagerProxy::checkUserMediaPermissionForSpeechRecognition):
(WebKit::UserMediaPermissionRequestManagerProxy::shouldChangeDeniedToPromptForCamera const):
(WebKit::UserMediaPermissionRequestManagerProxy::shouldChangeDeniedToPromptForMicrophone const):
(WebKit::UserMediaPermissionRequestManagerProxy::getUserMediaPermissionInfo):
* Source/WebKit/UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::launchProcessForReload):
(WebKit::WebPageProxy::loadRequestWithNavigationShared):
(WebKit::WebPageProxy::loadFile):
(WebKit::WebPageProxy::loadDataWithNavigationShared):
(WebKit::WebPageProxy::loadSimulatedRequest):
(WebKit::WebPageProxy::loadAlternateHTML):
(WebKit::WebPageProxy::reload):
(WebKit::WebPageProxy::goToBackForwardItem):
(WebKit::WebPageProxy::receivedNavigationActionPolicyDecision):
(WebKit::WebPageProxy::continueNavigationInNewProcess):
(WebKit::WebPageProxy::sessionState const):
(WebKit::WebPageProxy::didStartProvisionalLoadForFrameShared):
(WebKit::WebPageProxy::didExplicitOpenForFrame):
(WebKit::WebPageProxy::didReceiveServerRedirectForProvisionalLoadForFrameShared):
(WebKit::WebPageProxy::didChangeProvisionalURLForFrameShared):
(WebKit::WebPageProxy::didSameDocumentNavigationForFrame):
(WebKit::WebPageProxy::didSameDocumentNavigationForFrameViaJS):
(WebKit::WebPageProxy::decidePolicyForNavigationAction):
(WebKit::WebPageProxy::decidePolicyForResponseShared):
(WebKit::WebPageProxy::currentURL const):
(WebKit::WebPageProxy::tryReloadAfterProcessTermination):
* Source/WebKit/UIProcess/WebProcessPool.cpp:
(WebKit::WebProcessPool::processForNavigationInternal):
* Source/WebKit/UIProcess/WebsiteData/WebDeviceOrientationAndMotionAccessController.cpp:
(WebKit::WebDeviceOrientationAndMotionAccessController::shouldAllowAccess):
* Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.cpp:
(WebKit::WebsiteDataStore::download):
* Tools/TestWebKitAPI/Tests/WebKit/WKWebView/WKBackForwardListTests.mm:
(TEST(WKBackForwardList, InteractionStateRestoration)):
(TEST(WKBackForwardList, InteractionStateRestorationNil)):
(TEST(WKBackForwardList, InteractionStateRestorationInvalid)):
(TEST(WKBackForwardList, InteractionStateRestorationMultipleItems)):
(TEST(WKBackForwardList, BackSwipeNavigationSkipsItemsWithoutUserGesture)):
(TEST(WKBackForwardList, BackSwipeNavigationDoesNotSkipItemsWithUserGesture)):
(runBackForwardNavigationSkipsItemsWithoutUserGestureTest):
(runBackForwardNavigationDoesNotSkipItemsWithUserGestureTest):
(TEST(WKBackForwardList, BackForwardNavigationDoesNotSkipUpdatedItemWithRecentUserGesture)):
(TEST(WKBackForwardList, BackNavigationHijacking)):
* Tools/TestWebKitAPI/glib/WebKitGLib/WebViewTest.cpp:
(WebViewTest::loadURI):
(WebViewTest::loadHtml):
(WebViewTest::loadBytes):
(WebViewTest::loadRequest):
(WebViewTest::loadAlternateHTML):

Canonical link: https://commits.webkit.org/311033@main

c17138e

Misc iOS, visionOS, tvOS & watchOS macOS Linux Windows Apple Internal
✅ 🧪 style ✅ 🛠 ios ✅ 🛠 mac ✅ 🛠 wpe 🛠 win ⏳ 🛠 ios-apple
✅ 🧪 bindings ✅ 🛠 ios-sim ✅ 🛠 mac-AS-debug ✅ 🧪 wpe-wk2 🧪 win-tests ⏳ 🛠 mac-apple
✅ 🧪 webkitperl ✅ 🧪 ios-wk2 ✅ 🧪 api-mac ✅ 🧪 api-wpe ⏳ 🛠 vision-apple
✅ 🧪 ios-wk2-wpt ✅ 🧪 api-mac-debug ✅ 🛠 gtk3-libwebrtc
✅ 🛠 🧪 jsc ✅ 🧪 api-ios ✅ 🧪 mac-wk1 ✅ 🛠 gtk
✅ 🛠 🧪 jsc-debug-arm64 ✅ 🛠 ios-safer-cpp ✅ 🧪 mac-wk2 ✅ 🧪 gtk-wk2
✅ 🛠 vision ✅ 🧪 mac-AS-debug-wk2 ✅ 🧪 api-gtk
✅ 🛠 🧪 merge ✅ 🛠 vision-sim ✅ 🧪 mac-wk2-stress ✅ 🛠 playstation
✅ 🧪 vision-wk2 ✅ 🧪 mac-intel-wk2 ✅ 🛠 jsc-armv7
✅ 🛠 tv ✅ 🛠 mac-safer-cpp ✅ 🧪 jsc-armv7-tests
✅ 🛠 tv-sim
✅ 🛠 watch
✅ 🛠 watch-sim

@cdumez cdumez self-assigned this Apr 11, 2026
@cdumez cdumez added the WebKit2 Bugs relating to the WebKit2 API layer label Apr 11, 2026
@webkit-ews-buildbot
Copy link
Copy Markdown
Collaborator

macOS Safer C++ Build #92237 (150f7ed)

❌ Found 8 failing files with 19 issues. Please address these issues before landing. See WebKit Guidelines for Safer C++ Programming.
(cc @rniwa)

@webkit-ews-buildbot webkit-ews-buildbot added the merging-blocked Applied to prevent a change from being merged label Apr 11, 2026
@cdumez cdumez removed the merging-blocked Applied to prevent a change from being merged label Apr 11, 2026
@cdumez cdumez force-pushed the 312009_WKWebView_URL branch from 150f7ed to 72eddd1 Compare April 11, 2026 07:17
@webkit-ews-buildbot
Copy link
Copy Markdown
Collaborator

macOS Safer C++ Build #92245 (72eddd1)

❌ Found 1 failing file with 1 issue. Please address these issues before landing. See WebKit Guidelines for Safer C++ Programming.
(cc @rniwa)

@webkit-ews-buildbot webkit-ews-buildbot added the merging-blocked Applied to prevent a change from being merged label Apr 11, 2026
@cdumez cdumez removed the merging-blocked Applied to prevent a change from being merged label Apr 11, 2026
@cdumez cdumez force-pushed the 312009_WKWebView_URL branch from 72eddd1 to aa25b31 Compare April 11, 2026 12:02
@cdumez cdumez marked this pull request as ready for review April 11, 2026 12:02
@cdumez cdumez requested review from basuke, beidson and darinadler April 11, 2026 12:03
@@ -86,7 +86,7 @@ - (NSString *)title

- (NSURL *)URL
{
return [NSURL _web_URLWithWTFString:protect(protect(*_page)->pageLoadState())->activeURL()];
return protect(protect(*_page)->pageLoadState())->activeURL().createNSURL().autorelease();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need protect() here? Other places doesn't use it.

@@ -86,7 +86,7 @@ - (NSString *)title

- (NSURL *)URL
{
return [NSURL _web_URLWithWTFString:protect(protect(*_page)->pageLoadState())->activeURL()];
return protect(protect(*_page)->pageLoadState())->activeURL().createNSURL().autorelease();
Copy link
Copy Markdown
Member

@darinadler darinadler Apr 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The premise of this change is that these methods are called repeatedly, and if so we still will do repetitive unnecessary work, creating a new NSURL every time. I could imagine storing a String/NSURL pair and returning that same NSURL unless the string has changed. This should be even more effective than the change here at speeding up this method.

We could do either or both improvements.

A separate decision is whether to autorelease the NSURL each time. In theory that would no longer be needed but there is a small risk that callers accidentally rely on the NSURL lifetime continuing past the lifetime of the owning object or past a future call to the same method returning a different URL.

We could create a C++ object implementing this idiom for reuse, and do this for all the NSURL-returning functions.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm fixing a radar where we're spinning in the URLParser when calling WKWebView.URL so it made sense for me to focus on avoiding calling the URLParser. That said, it is true that we also recreate a NSURL every time and this can be avoided too. I'll take a look.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some things to consider: Maybe this is obvious but memoizing the NSURL would also avoid calling the parser. Creating an NSURL from a WebKit URL also involves URL parsing, although perhaps it's more efficient than WebKit's parsing or maybe it's got a laziness mechanism.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not calling autorelease() caused some crashes in the tests so I'm going to keep autoreleasing for now, especially considering that this is likely going to get cherry-picked to a branch.

@cdumez cdumez force-pushed the 312009_WKWebView_URL branch from aa25b31 to fbab551 Compare April 12, 2026 06:43
@cdumez cdumez force-pushed the 312009_WKWebView_URL branch from fbab551 to c17138e Compare April 12, 2026 10:59
@cdumez cdumez added the merge-queue Applied to send a pull request to merge-queue label Apr 12, 2026
…is called

https://bugs.webkit.org/show_bug.cgi?id=312009
rdar://174434204

Reviewed by Darin Adler.

Update PageLoadState to store urls as URL, not String. Otherwise, APIs
like WKWebView.URL have to keep re-parsing the URL string every thing
they're called.

* Source/WTF/wtf/URL.cpp:
(WTF::aboutBlankURL):
(WTF::aboutSrcDocURL):
* Source/WTF/wtf/URL.h:
* Source/WebKit/UIProcess/API/C/WKPage.cpp:
(WKPageSetPageUIClient):
(WKPageCopyPendingAPIRequestURL):
* Source/WebKit/UIProcess/API/C/mac/WKPagePrivateMac.mm:
(-[WKObservablePageState URL]):
(-[WKObservablePageState unreachableURL]):
* Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm:
(-[WKWebView URL]):
(-[WKWebView _unreachableURL]):
(-[WKWebView _committedURL]):
* Source/WebKit/UIProcess/API/Cocoa/WKWebViewInternal.h:
* Source/WebKit/UIProcess/API/glib/WebKitWebView.cpp:
(PageLoadStateObserver::didChangeActiveURL):
(webkitWebViewWillStartLoad):
(webkitWebViewLoadChanged):
(webkitWebViewGetLoadDecisionForIcons):
(webkitWebViewUpdatePageIcons):
(webkitWebViewSetIcon):
* Source/WebKit/UIProcess/API/gtk/WebKitRemoteInspectorProtocolHandler.cpp:
* Source/WebKit/UIProcess/API/gtk/WebKitWebViewGtk.cpp:
(webkitWebViewScriptDialog):
* Source/WebKit/UIProcess/Automation/WebAutomationSession.cpp:
(WebKit::WebAutomationSession::buildBrowsingContextForPage):
(WebKit::WebAutomationSession::addSingleCookie):
(WebKit::WebAutomationSession::deleteAllCookies):
* Source/WebKit/UIProcess/Cocoa/SOAuthorization/NavigationSOAuthorizationSession.h:
* Source/WebKit/UIProcess/Cocoa/UIDelegate.mm:
(WebKit::UIDelegate::UIClient::decidePolicyForGeolocationPermissionRequest):
(WebKit::UIDelegate::UIClient::shouldAllowDeviceOrientationAndMotionAccess):
* Source/WebKit/UIProcess/Cocoa/WebPageProxyCocoa.mm:
(WebKit::WebPageProxy::shouldAllowAutoFillForCellularIdentifiers const):
* Source/WebKit/UIProcess/Inspector/socket/RemoteInspectorProtocolHandler.cpp:
* Source/WebKit/UIProcess/Network/NetworkProcessProxy.cpp:
(WebKit::NetworkProcessProxy::deleteWebsiteDataInWebProcessesForOrigin):
* Source/WebKit/UIProcess/PageLoadState.cpp:
(WebKit::PageLoadState::reset):
(WebKit::PageLoadState::activeURL):
(WebKit::PageLoadState::hasOnlySecureContent):
(WebKit::PageLoadState::didExplicitOpen):
(WebKit::PageLoadState::didStartProvisionalLoad):
(WebKit::PageLoadState::didReceiveServerRedirectForProvisionalLoad):
(WebKit::PageLoadState::didFailProvisionalLoad):
(WebKit::PageLoadState::didCommitLoad):
(WebKit::PageLoadState::didSameDocumentNavigation):
(WebKit::PageLoadState::setUnreachableURL):
* Source/WebKit/UIProcess/PageLoadState.h:
(WebKit::PageLoadState::activeURL const):
* Source/WebKit/UIProcess/RemotePageProxy.cpp:
(WebKit::RemotePageProxy::injectPageIntoNewProcess):
(WebKit::RemotePageProxy::setDrawingArea):
* Source/WebKit/UIProcess/UserMediaPermissionRequestManagerProxy.cpp:
(WebKit::UserMediaPermissionRequestManagerProxy::decidePolicyForUserMediaPermissionRequest):
(WebKit::UserMediaPermissionRequestManagerProxy::checkUserMediaPermissionForSpeechRecognition):
(WebKit::UserMediaPermissionRequestManagerProxy::shouldChangeDeniedToPromptForCamera const):
(WebKit::UserMediaPermissionRequestManagerProxy::shouldChangeDeniedToPromptForMicrophone const):
(WebKit::UserMediaPermissionRequestManagerProxy::getUserMediaPermissionInfo):
* Source/WebKit/UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::launchProcessForReload):
(WebKit::WebPageProxy::loadRequestWithNavigationShared):
(WebKit::WebPageProxy::loadFile):
(WebKit::WebPageProxy::loadDataWithNavigationShared):
(WebKit::WebPageProxy::loadSimulatedRequest):
(WebKit::WebPageProxy::loadAlternateHTML):
(WebKit::WebPageProxy::reload):
(WebKit::WebPageProxy::goToBackForwardItem):
(WebKit::WebPageProxy::receivedNavigationActionPolicyDecision):
(WebKit::WebPageProxy::continueNavigationInNewProcess):
(WebKit::WebPageProxy::sessionState const):
(WebKit::WebPageProxy::didStartProvisionalLoadForFrameShared):
(WebKit::WebPageProxy::didExplicitOpenForFrame):
(WebKit::WebPageProxy::didReceiveServerRedirectForProvisionalLoadForFrameShared):
(WebKit::WebPageProxy::didChangeProvisionalURLForFrameShared):
(WebKit::WebPageProxy::didSameDocumentNavigationForFrame):
(WebKit::WebPageProxy::didSameDocumentNavigationForFrameViaJS):
(WebKit::WebPageProxy::decidePolicyForNavigationAction):
(WebKit::WebPageProxy::decidePolicyForResponseShared):
(WebKit::WebPageProxy::currentURL const):
(WebKit::WebPageProxy::tryReloadAfterProcessTermination):
* Source/WebKit/UIProcess/WebProcessPool.cpp:
(WebKit::WebProcessPool::processForNavigationInternal):
* Source/WebKit/UIProcess/WebsiteData/WebDeviceOrientationAndMotionAccessController.cpp:
(WebKit::WebDeviceOrientationAndMotionAccessController::shouldAllowAccess):
* Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.cpp:
(WebKit::WebsiteDataStore::download):
* Tools/TestWebKitAPI/Tests/WebKit/WKWebView/WKBackForwardListTests.mm:
(TEST(WKBackForwardList, InteractionStateRestoration)):
(TEST(WKBackForwardList, InteractionStateRestorationNil)):
(TEST(WKBackForwardList, InteractionStateRestorationInvalid)):
(TEST(WKBackForwardList, InteractionStateRestorationMultipleItems)):
(TEST(WKBackForwardList, BackSwipeNavigationSkipsItemsWithoutUserGesture)):
(TEST(WKBackForwardList, BackSwipeNavigationDoesNotSkipItemsWithUserGesture)):
(runBackForwardNavigationSkipsItemsWithoutUserGestureTest):
(runBackForwardNavigationDoesNotSkipItemsWithUserGestureTest):
(TEST(WKBackForwardList, BackForwardNavigationDoesNotSkipUpdatedItemWithRecentUserGesture)):
(TEST(WKBackForwardList, BackNavigationHijacking)):
* Tools/TestWebKitAPI/glib/WebKitGLib/WebViewTest.cpp:
(WebViewTest::loadURI):
(WebViewTest::loadHtml):
(WebViewTest::loadBytes):
(WebViewTest::loadRequest):
(WebViewTest::loadAlternateHTML):

Canonical link: https://commits.webkit.org/311033@main
@webkit-commit-queue
Copy link
Copy Markdown
Collaborator

Committed 311033@main (56d2552): https://commits.webkit.org/311033@main

Reviewed commits have been landed. Closing PR #62522 and removing active labels.

@webkit-commit-queue webkit-commit-queue merged commit 56d2552 into WebKit:main Apr 12, 2026
@webkit-commit-queue webkit-commit-queue removed the merge-queue Applied to send a pull request to merge-queue label Apr 12, 2026

RetainPtr<WKScrollGeometry> _currentScrollGeometry;

std::pair<URL, RetainPtr<NSURL>> _cachedActiveNSURL;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don’t need to store the URL. Since all we do is compare the URL with a new URL can just store the URL’s string and compare the URL’s string with the new URL’s string.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok. I was trying to move away from storing URLs as Strings but it doesn't hurt here since we don't need to ever re-parse it and would save some memory. I'll follow-up.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

WebKit2 Bugs relating to the WebKit2 API layer

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants