Title: [261921] trunk/Source
Revision
261921
Author
[email protected]
Date
2020-05-20 08:43:19 -0700 (Wed, 20 May 2020)

Log Message

[Mac] UI processes spin when creating the "Share" context menu item
https://bugs.webkit.org/show_bug.cgi?id=212137
<rdar://problem/54498394>

Reviewed by Wenson Hsieh.

Source/WebCore:

Ran update-webkit-localizable-strings.

* en.lproj/Localizable.strings:

Source/WebCore/PAL:

* pal/spi/mac/NSSharingServicePickerSPI.h: Declared -getMenuWithCompletion:.

Source/WebKit:

On Mac, WebKit has been using the +[NSMenuItem standardShareMenuItemForItems:] SPI to create
the "Share" context submenu and menu item. This call performs synchronous IPC and can result
in UI process spins.

Where available, switch to using the asynchronous
-[NSSharingServicePicker getMenuWithCompletion:] SPI instead. This method only creates the
submenu, not the menu item, so when using this new method we must create the "Share" menu
item ourselves.

* UIProcess/mac/WebContextMenuProxyMac.h:
* UIProcess/mac/WebContextMenuProxyMac.mm:
(WebKit::getStandardShareMenuItem):
(WebKit::WebContextMenuProxyMac::getShareMenuItem):
(WebKit::WebContextMenuProxyMac::getContextMenuFromItems):
(WebKit::WebContextMenuProxyMac::getContextMenuItem):
(WebKit::WebContextMenuProxyMac::showContextMenuWithItems):
(WebKit::WebContextMenuProxyMac::createShareMenuItem): Deleted.
(WebKit::WebContextMenuProxyMac::createContextMenuFromItems): Deleted.
(WebKit::WebContextMenuProxyMac::createContextMenuItem): Deleted.

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (261920 => 261921)


--- trunk/Source/WebCore/ChangeLog	2020-05-20 15:38:50 UTC (rev 261920)
+++ trunk/Source/WebCore/ChangeLog	2020-05-20 15:43:19 UTC (rev 261921)
@@ -1,3 +1,15 @@
+2020-05-20  Andy Estes  <[email protected]>
+
+        [Mac] UI processes spin when creating the "Share" context menu item
+        https://bugs.webkit.org/show_bug.cgi?id=212137
+        <rdar://problem/54498394>
+
+        Reviewed by Wenson Hsieh.
+
+        Ran update-webkit-localizable-strings.
+
+        * en.lproj/Localizable.strings:
+
 2020-05-20  Zalan Bujtas  <[email protected]>
 
         [LFC][TFC] Internal table boxes should take collapsed border into account

Modified: trunk/Source/WebCore/PAL/ChangeLog (261920 => 261921)


--- trunk/Source/WebCore/PAL/ChangeLog	2020-05-20 15:38:50 UTC (rev 261920)
+++ trunk/Source/WebCore/PAL/ChangeLog	2020-05-20 15:43:19 UTC (rev 261921)
@@ -1,3 +1,13 @@
+2020-05-20  Andy Estes  <[email protected]>
+
+        [Mac] UI processes spin when creating the "Share" context menu item
+        https://bugs.webkit.org/show_bug.cgi?id=212137
+        <rdar://problem/54498394>
+
+        Reviewed by Wenson Hsieh.
+
+        * pal/spi/mac/NSSharingServicePickerSPI.h: Declared -getMenuWithCompletion:.
+
 2020-05-18  Andy Estes  <[email protected]>
 
         http/tests/ssl/applepay/ApplePayInstallmentConfiguration.https.html fails in public SDK builds

Modified: trunk/Source/WebCore/PAL/pal/spi/mac/NSSharingServicePickerSPI.h (261920 => 261921)


--- trunk/Source/WebCore/PAL/pal/spi/mac/NSSharingServicePickerSPI.h	2020-05-20 15:38:50 UTC (rev 261920)
+++ trunk/Source/WebCore/PAL/pal/spi/mac/NSSharingServicePickerSPI.h	2020-05-20 15:43:19 UTC (rev 261921)
@@ -41,6 +41,7 @@
 @interface NSSharingServicePicker (Private)
 @property NSSharingServicePickerStyle style;
 - (NSMenu *)menu;
+- (void)getMenuWithCompletion:(void(^)(NSMenu *))completion;
 - (void)hide;
 @end
 

Modified: trunk/Source/WebCore/en.lproj/Localizable.strings (261920 => 261921)


--- trunk/Source/WebCore/en.lproj/Localizable.strings	2020-05-20 15:38:50 UTC (rev 261920)
+++ trunk/Source/WebCore/en.lproj/Localizable.strings	2020-05-20 15:43:19 UTC (rev 261921)
@@ -1,9 +1,3 @@
-/* Allow the specified bundle to use Touch ID to sign in to the specified website on this device */
-"“%@” would like to use Touch ID for “%@”." = "“%@” would like to use Touch ID for “%@”.";
-
-/* "Allow the specified bundle to sign in to the specified website */
-"“%@” would like to sign in to “%@”." = "“%@” would like to sign in to “%@”.";
-
 /* accessibility help text for media controller time value >= 1 day */
 "%1$d days %2$d hours %3$d minutes %4$d seconds" = "%1$d days %2$d hours %3$d minutes %4$d seconds";
 
@@ -229,7 +223,7 @@
 /* Continue */
 "Continue" = "Continue";
 
-/* Continue with Touch ID */
+/* Continue with Touch ID. */
 "Continue with Touch ID." = "Continue with Touch ID.";
 
 /* Media Controls context menu item */
@@ -646,6 +640,9 @@
 /* default label for Reset buttons in forms on web pages */
 "Reset" = "Reset";
 
+/* Reset button in date input context menu */
+"Reset Button Date/Time Context Menu" = "Reset";
+
 /* Right to Left context menu item */
 "Right to Left" = "Right to Left";
 
@@ -697,6 +694,9 @@
 /* Label for the set up with Apple Pay button. */
 "Set up with Apple Pay" = "Set up with Apple Pay";
 
+/* Title for Share context menu item. */
+"Share" = "Share";
+
 /* Title for Share action button */
 "Share…" = "Share…";
 
@@ -1324,9 +1324,6 @@
 /* HTTP result code string */
 "requested range not satisfiable" = "requested range not satisfiable";
 
-/* Reset button in date input popover */
-"Reset Button Date/Time Context Menu" = "Reset";
-
 /* HTTP result code string */
 "reset content" = "reset content";
 
@@ -1468,6 +1465,12 @@
 /* Message for requesting access to the device motion and orientation */
 "“%@” Would Like to Access Motion and Orientation" = "“%@” Would Like to Access Motion and Orientation";
 
+/* Allow the specified bundle to sign in to the specified website */
+"“%@” would like to sign in to “%@”." = "“%@” would like to sign in to “%@”.";
+
+/* Allow the specified bundle to use Touch ID to sign in to the specified website on this device */
+"“%@” would like to use Touch ID for “%@”." = "“%@” would like to use Touch ID for “%@”.";
+
 /* Option in segmented control for choosing list type in text editing */
 "•" = "•";
 

Modified: trunk/Source/WebKit/ChangeLog (261920 => 261921)


--- trunk/Source/WebKit/ChangeLog	2020-05-20 15:38:50 UTC (rev 261920)
+++ trunk/Source/WebKit/ChangeLog	2020-05-20 15:43:19 UTC (rev 261921)
@@ -1,3 +1,31 @@
+2020-05-20  Andy Estes  <[email protected]>
+
+        [Mac] UI processes spin when creating the "Share" context menu item
+        https://bugs.webkit.org/show_bug.cgi?id=212137
+        <rdar://problem/54498394>
+
+        Reviewed by Wenson Hsieh.
+
+        On Mac, WebKit has been using the +[NSMenuItem standardShareMenuItemForItems:] SPI to create
+        the "Share" context submenu and menu item. This call performs synchronous IPC and can result
+        in UI process spins.
+
+        Where available, switch to using the asynchronous
+        -[NSSharingServicePicker getMenuWithCompletion:] SPI instead. This method only creates the
+        submenu, not the menu item, so when using this new method we must create the "Share" menu
+        item ourselves.
+
+        * UIProcess/mac/WebContextMenuProxyMac.h:
+        * UIProcess/mac/WebContextMenuProxyMac.mm:
+        (WebKit::getStandardShareMenuItem):
+        (WebKit::WebContextMenuProxyMac::getShareMenuItem):
+        (WebKit::WebContextMenuProxyMac::getContextMenuFromItems):
+        (WebKit::WebContextMenuProxyMac::getContextMenuItem):
+        (WebKit::WebContextMenuProxyMac::showContextMenuWithItems):
+        (WebKit::WebContextMenuProxyMac::createShareMenuItem): Deleted.
+        (WebKit::WebContextMenuProxyMac::createContextMenuFromItems): Deleted.
+        (WebKit::WebContextMenuProxyMac::createContextMenuItem): Deleted.
+
 2020-05-20  Carlos Garcia Campos  <[email protected]>
 
         Unreviewed. Fix GTK4 build with GTK 3.98.4

Modified: trunk/Source/WebKit/UIProcess/mac/WebContextMenuProxyMac.h (261920 => 261921)


--- trunk/Source/WebKit/UIProcess/mac/WebContextMenuProxyMac.h	2020-05-20 15:38:50 UTC (rev 261920)
+++ trunk/Source/WebKit/UIProcess/mac/WebContextMenuProxyMac.h	2020-05-20 15:43:19 UTC (rev 261921)
@@ -68,12 +68,12 @@
     void show() override;
 
     RefPtr<WebContextMenuListenerProxy> m_contextMenuListener;
-    RetainPtr<NSMenuItem> createContextMenuItem(const WebContextMenuItemData&);
-    RetainPtr<NSMenu> createContextMenuFromItems(const Vector<WebContextMenuItemData>&);
+    void getContextMenuItem(const WebContextMenuItemData&, CompletionHandler<void(NSMenuItem *)>&&);
+    void getContextMenuFromItems(const Vector<WebContextMenuItemData>&, CompletionHandler<void(NSMenu *)>&&);
     void showContextMenu();
 
 #if ENABLE(SERVICE_CONTROLS)
-    RetainPtr<NSMenuItem> createShareMenuItem();
+    void getShareMenuItem(CompletionHandler<void(NSMenuItem *)>&&);
     void showServicesMenu();
     void setupServicesMenu();
 #endif

Modified: trunk/Source/WebKit/UIProcess/mac/WebContextMenuProxyMac.mm (261920 => 261921)


--- trunk/Source/WebKit/UIProcess/mac/WebContextMenuProxyMac.mm	2020-05-20 15:38:50 UTC (rev 261920)
+++ trunk/Source/WebKit/UIProcess/mac/WebContextMenuProxyMac.mm	2020-05-20 15:43:19 UTC (rev 261921)
@@ -44,6 +44,7 @@
 #import "WebProcessProxy.h"
 #import <WebCore/GraphicsContext.h>
 #import <WebCore/IntRect.h>
+#import <WebCore/LocalizedStrings.h>
 #import <pal/spi/mac/NSMenuSPI.h>
 #import <pal/spi/mac/NSSharingServicePickerSPI.h>
 #import <pal/spi/mac/NSSharingServiceSPI.h>
@@ -260,8 +261,27 @@
     m_menu = nullptr;
 }
 
-RetainPtr<NSMenuItem> WebContextMenuProxyMac::createShareMenuItem()
+static void getStandardShareMenuItem(NSArray *items, void (^completionHandler)(NSMenuItem *))
 {
+#if HAVE(NSSHARINGSERVICEPICKER_ASYNC_MENUS)
+    // FIXME (<rdar://problem/54551500>): Replace this with the async variant of +[NSMenuItem standardShareMenuItemForItems:] when it's available.
+    auto sharingServicePicker = adoptNS([[NSSharingServicePicker alloc] initWithItems:items]);
+    [sharingServicePicker setStyle:NSSharingServicePickerStyleMenu];
+    [sharingServicePicker getMenuWithCompletion:^(NSMenu *shareMenu) {
+        ASSERT(isMainThread());
+        shareMenu.delegate = (id <NSMenuDelegate>)sharingServicePicker.get();
+        auto shareMenuItem = adoptNS([[NSMenuItem alloc] initWithTitle:WEB_UI_STRING("Share", "Title for Share context menu item.") action:nil keyEquivalent:@""]);
+        [shareMenuItem setRepresentedObject:sharingServicePicker.get()];
+        [shareMenuItem setSubmenu:shareMenu];
+        completionHandler(shareMenuItem.get());
+    }];
+#else
+    completionHandler([NSMenuItem standardShareMenuItemForItems:items]);
+#endif
+}
+
+void WebContextMenuProxyMac::getShareMenuItem(CompletionHandler<void(NSMenuItem *)>&& completionHandler)
+{
     const WebHitTestResultData& hitTestData = m_context.webHitTestResultData();
 
     auto items = adoptNS([[NSMutableArray alloc] init]);
@@ -286,26 +306,32 @@
     if (!m_context.selectedText().isEmpty())
         [items addObject:(NSString *)m_context.selectedText()];
 
-    if (![items count])
-        return nil;
+    if (![items count]) {
+        completionHandler(nil);
+        return;
+    }
 
-    RetainPtr<NSMenuItem> item = [NSMenuItem standardShareMenuItemForItems:items.get()];
-    if (!item)
-        return nil;
+    getStandardShareMenuItem(items.get(), makeBlockPtr([completionHandler = WTFMove(completionHandler), protectedThis = makeRef(*this), this](NSMenuItem *item) mutable {
+        if (!item) {
+            completionHandler(nil);
+            return;
+        }
 
-    NSSharingServicePicker *sharingServicePicker = [item representedObject];
-    sharingServicePicker.delegate = [WKSharingServicePickerDelegate sharedSharingServicePickerDelegate];
+        NSSharingServicePicker *sharingServicePicker = item.representedObject;
+        WKSharingServicePickerDelegate *sharingServicePickerDelegate = WKSharingServicePickerDelegate.sharedSharingServicePickerDelegate;
+        sharingServicePicker.delegate = sharingServicePickerDelegate;
 
-    [[WKSharingServicePickerDelegate sharedSharingServicePickerDelegate] setFiltersEditingServices:NO];
-    [[WKSharingServicePickerDelegate sharedSharingServicePickerDelegate] setHandlesEditingReplacement:NO];
-    [[WKSharingServicePickerDelegate sharedSharingServicePickerDelegate] setMenuProxy:this];
+        sharingServicePickerDelegate.filtersEditingServices = NO;
+        sharingServicePickerDelegate.handlesEditingReplacement = NO;
+        sharingServicePickerDelegate.menuProxy = this;
 
-    // Setting the picker lets the delegate retain it to keep it alive, but this picker is kept alive by the menu item.
-    [[WKSharingServicePickerDelegate sharedSharingServicePickerDelegate] setPicker:nil];
+        // Setting the picker lets the delegate retain it to keep it alive, but this picker is kept alive by the menu item.
+        sharingServicePickerDelegate.picker = nil;
 
-    [item setIdentifier:_WKMenuItemIdentifierShareMenu];
+        item.identifier = _WKMenuItemIdentifierShareMenu;
 
-    return item;
+        completionHandler(item);
+    }).get());
 }
 #endif
 
@@ -323,17 +349,34 @@
     showContextMenu();
 }
 
-RetainPtr<NSMenu> WebContextMenuProxyMac::createContextMenuFromItems(const Vector<WebContextMenuItemData>& items)
+void WebContextMenuProxyMac::getContextMenuFromItems(const Vector<WebContextMenuItemData>& items, CompletionHandler<void(NSMenu *)>&& completionHandler)
 {
     auto menu = adoptNS([[NSMenu alloc] initWithTitle:@""]);
     [menu setAutoenablesItems:NO];
 
-    for (auto& item : items) {
-        if (auto menuItem = createContextMenuItem(item))
-            [menu addItem:menuItem.get()];
+    if (items.isEmpty()) {
+        completionHandler(menu.get());
+        return;
     }
 
-    return menu;
+    auto sparseMenuItems = retainPtr([NSPointerArray strongObjectsPointerArray]);
+    auto insertMenuItem = makeBlockPtr([completionHandler = WTFMove(completionHandler), itemsRemaining = items.size(), menu = WTFMove(menu), sparseMenuItems](NSMenuItem *item, NSUInteger index) mutable {
+        ASSERT(index < [sparseMenuItems count]);
+        ASSERT(![sparseMenuItems pointerAtIndex:index]);
+        [sparseMenuItems replacePointerAtIndex:index withPointer:item];
+        if (--itemsRemaining)
+            return;
+
+        [menu setItemArray:[sparseMenuItems allObjects]];
+        completionHandler(menu.get());
+    });
+
+    for (size_t i = 0; i < items.size(); ++i) {
+        [sparseMenuItems addPointer:nullptr];
+        getContextMenuItem(items[i], [insertMenuItem, i](NSMenuItem *menuItem) {
+            insertMenuItem(menuItem, i);
+        });
+    }
 }
 
 static NSString *menuItemIdentifier(const WebCore::ContextMenuAction action)
@@ -416,11 +459,13 @@
     }
 }
 
-RetainPtr<NSMenuItem> WebContextMenuProxyMac::createContextMenuItem(const WebContextMenuItemData& item)
+void WebContextMenuProxyMac::getContextMenuItem(const WebContextMenuItemData& item, CompletionHandler<void(NSMenuItem *)>&& completionHandler)
 {
 #if ENABLE(SERVICE_CONTROLS)
-    if (item.action() == ContextMenuItemTagShareMenu)
-        return createShareMenuItem();
+    if (item.action() == ContextMenuItemTagShareMenu) {
+        getShareMenuItem(WTFMove(completionHandler));
+        return;
+    }
 #endif
 
     switch (item.type()) {
@@ -439,19 +484,23 @@
             [menuItem setRepresentedObject:wrapper.get()];
         }
 
-        return menuItem;
+        completionHandler(menuItem.get());
+        return;
     }
 
     case WebCore::SeparatorType:
-        return [NSMenuItem separatorItem];
+        completionHandler(NSMenuItem.separatorItem);
+        return;
 
     case WebCore::SubmenuType: {
-        auto menuItem = adoptNS([[NSMenuItem alloc] initWithTitle:item.title() action:nullptr keyEquivalent:@""]);
-        [menuItem setEnabled:item.enabled()];
-        [menuItem setSubmenu:createContextMenuFromItems(item.submenu()).get()];
-        [menuItem setIdentifier:menuItemIdentifier(item.action())];
-
-        return menuItem;
+        getContextMenuFromItems(item.submenu(), [action = "" completionHandler = WTFMove(completionHandler), enabled = item.enabled(), title = item.title()](NSMenu *menu) mutable {
+            auto menuItem = adoptNS([[NSMenuItem alloc] initWithTitle:title action:nullptr keyEquivalent:@""]);
+            [menuItem setEnabled:enabled];
+            [menuItem setSubmenu:menu];
+            [menuItem setIdentifier:menuItemIdentifier(action)];
+            completionHandler(menuItem.get());
+        });
+        return;
     }
     }
 }
@@ -468,19 +517,20 @@
     data.reserveInitialCapacity(items.size());
     for (auto& item : items)
         data.uncheckedAppend(item->data());
-    
-    auto menu = createContextMenuFromItems(data);
-    [[WKMenuTarget sharedMenuTarget] setMenuProxy:this];
-    m_page.contextMenuClient().menuFromProposedMenu(m_page, menu.get(), m_context.webHitTestResultData(), m_userData.object(), [this, protectedThis = makeRef(*this)] (RetainPtr<NSMenu>&& menu) {
-        m_menu = WTFMove(menu);
-        NSPoint menuLocation = [m_webView convertPoint:m_context.menuLocation() toView:nil];
-        NSEvent *event = [NSEvent mouseEventWithType:NSEventTypeRightMouseUp location:menuLocation modifierFlags:0 timestamp:0 windowNumber:m_webView.window.windowNumber context:nil eventNumber:0 clickCount:0 pressure:0];
-        [NSMenu popUpContextMenu:m_menu.get() withEvent:event forView:m_webView];
-        
-        if (m_contextMenuListener) {
-            m_contextMenuListener->invalidate();
-            m_contextMenuListener = nullptr;
-        }
+
+    getContextMenuFromItems(data, [protectedThis = makeRef(*this), this](NSMenu *menu) mutable {
+        [[WKMenuTarget sharedMenuTarget] setMenuProxy:this];
+        m_page.contextMenuClient().menuFromProposedMenu(m_page, menu, m_context.webHitTestResultData(), m_userData.object(), [this, protectedThis = WTFMove(protectedThis)] (RetainPtr<NSMenu>&& menu) {
+            m_menu = WTFMove(menu);
+            NSPoint menuLocation = [m_webView convertPoint:m_context.menuLocation() toView:nil];
+            NSEvent *event = [NSEvent mouseEventWithType:NSEventTypeRightMouseUp location:menuLocation modifierFlags:0 timestamp:0 windowNumber:m_webView.window.windowNumber context:nil eventNumber:0 clickCount:0 pressure:0];
+            [NSMenu popUpContextMenu:m_menu.get() withEvent:event forView:m_webView];
+
+            if (m_contextMenuListener) {
+                m_contextMenuListener->invalidate();
+                m_contextMenuListener = nullptr;
+            }
+        });
     });
 }
 
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to