Changeset 275491 in webkit


Ignore:
Timestamp:
Apr 5, 2021 9:31:13 PM (3 years ago)
Author:
Wenson Hsieh
Message:

[macOS] Image preview context menu action should be shown conditionally
https://bugs.webkit.org/show_bug.cgi?id=224126
<rdar://problem/76162272>

Reviewed by Devin Rousso.

Add a page client hook to return whether or not the "reveal image" context menu item should be enabled, given
the image URL and decoded image bitmap; we then use this method to conditionally insert a context menu item for
revealing the image in context menu data.

  • UIProcess/Cocoa/WebViewImpl.h:
  • UIProcess/PageClient.h:

(WebKit::PageClient::computeCanRevealImage):

  • UIProcess/WebPageProxy.cpp:

(WebKit::WebPageProxy::computeCanRevealImage):

  • UIProcess/WebPageProxy.h:
  • UIProcess/mac/PageClientImplMac.h:
  • UIProcess/mac/PageClientImplMac.mm:

(WebKit::PageClientImpl::computeCanRevealImage):

  • UIProcess/mac/WebContextMenuProxyMac.mm:

(WebKit::createMenuActionItem):

Pull logic for mapping a WebContextMenuItemData of type ActionType or CheckableActionType to a platform
NSMenuItem out into a separate helper function. Use this helper in getContextMenuItem, as well as the
completion handler for the call to computeCanRevealImage. Note that this also requires moving the
menuItemIdentifier function up above getContextMenuFromItems.

(WebKit::WebContextMenuProxyMac::getContextMenuFromItems):

Special case the ContextMenuItemTagRevealImage item; instead of adding this item to the context menu right
away, we hide it by default, and only reinsert it if the page client indicates that we require the item (via
computeCanRevealImage).

(WebKit::WebContextMenuProxyMac::getContextMenuItem):

Location:
trunk/Source/WebKit
Files:
8 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebKit/ChangeLog

    r275487 r275491  
     12021-04-05  Wenson Hsieh  <wenson_hsieh@apple.com>
     2
     3        [macOS] Image preview context menu action should be shown conditionally
     4        https://bugs.webkit.org/show_bug.cgi?id=224126
     5        <rdar://problem/76162272>
     6
     7        Reviewed by Devin Rousso.
     8
     9        Add a page client hook to return whether or not the "reveal image" context menu item should be enabled, given
     10        the image URL and decoded image bitmap; we then use this method to conditionally insert a context menu item for
     11        revealing the image in context menu data.
     12
     13        * UIProcess/Cocoa/WebViewImpl.h:
     14        * UIProcess/PageClient.h:
     15        (WebKit::PageClient::computeCanRevealImage):
     16        * UIProcess/WebPageProxy.cpp:
     17        (WebKit::WebPageProxy::computeCanRevealImage):
     18        * UIProcess/WebPageProxy.h:
     19        * UIProcess/mac/PageClientImplMac.h:
     20        * UIProcess/mac/PageClientImplMac.mm:
     21        (WebKit::PageClientImpl::computeCanRevealImage):
     22        * UIProcess/mac/WebContextMenuProxyMac.mm:
     23        (WebKit::createMenuActionItem):
     24
     25        Pull logic for mapping a `WebContextMenuItemData` of type `ActionType` or `CheckableActionType` to a platform
     26        `NSMenuItem` out into a separate helper function. Use this helper in `getContextMenuItem`, as well as the
     27        completion handler for the call to `computeCanRevealImage`. Note that this also requires moving the
     28        `menuItemIdentifier` function up above `getContextMenuFromItems`.
     29
     30        (WebKit::WebContextMenuProxyMac::getContextMenuFromItems):
     31
     32        Special case the `ContextMenuItemTagRevealImage` item; instead of adding this item to the context menu right
     33        away, we hide it by default, and only reinsert it if the page client indicates that we require the item (via
     34        `computeCanRevealImage`).
     35
     36        (WebKit::WebContextMenuProxyMac::getContextMenuItem):
     37
    1382021-04-05  Alex Christensen  <achristensen@webkit.org>
    239
  • trunk/Source/WebKit/UIProcess/Cocoa/WebViewImpl.h

    r274148 r275491  
    4545#include <wtf/WeakObjCPtr.h>
    4646#include <wtf/WeakPtr.h>
     47#include <wtf/WorkQueue.h>
    4748#include <wtf/text/WTFString.h>
    4849
     
    586587#if ENABLE(IMAGE_EXTRACTION)
    587588    void requestImageExtraction(const URL& imageURL, const ShareableBitmap::Handle& imageData, CompletionHandler<void(WebCore::ImageExtractionResult&&)>&&);
     589    void computeCanRevealImage(const URL& imageURL, ShareableBitmap& imageBitmap, CompletionHandler<void(bool)>&&);
    588590#endif
    589591
  • trunk/Source/WebKit/UIProcess/PageClient.h

    r275485 r275491  
    528528#if ENABLE(IMAGE_EXTRACTION)
    529529    virtual void requestImageExtraction(const URL& imageURL, const ShareableBitmap::Handle& imageData, CompletionHandler<void(WebCore::ImageExtractionResult&&)>&& completion) { completion({ }); }
     530    virtual void computeCanRevealImage(const URL&, ShareableBitmap&, CompletionHandler<void(bool)>&& completion) { completion(false); }
    530531#endif
    531532
  • trunk/Source/WebKit/UIProcess/WebPageProxy.cpp

    r275485 r275491  
    82598259}
    82608260
     8261void WebPageProxy::computeCanRevealImage(const URL& imageURL, ShareableBitmap& imageBitmap, CompletionHandler<void(bool)>&& completion)
     8262{
     8263    pageClient().computeCanRevealImage(imageURL, imageBitmap, WTFMove(completion));
     8264}
     8265
    82618266void WebPageProxy::updateWithImageExtractionResult(ImageExtractionResult&& results, const ElementContext& context, const FloatPoint& location, CompletionHandler<void(bool textExistsAtLocation)>&& completionHandler)
    82628267{
  • trunk/Source/WebKit/UIProcess/WebPageProxy.h

    r275485 r275491  
    16401640    void requestImageExtraction(const URL& imageURL, const ShareableBitmap::Handle& imageData, CompletionHandler<void(WebCore::ImageExtractionResult&&)>&&);
    16411641    void updateWithImageExtractionResult(WebCore::ImageExtractionResult&&, const WebCore::ElementContext&, const WebCore::FloatPoint& location, CompletionHandler<void(bool textExistsAtLocation)>&&);
     1642    void computeCanRevealImage(const URL& imageURL, ShareableBitmap& imageBitmap, CompletionHandler<void(bool)>&&);
    16421643#endif
    16431644
  • trunk/Source/WebKit/UIProcess/mac/PageClientImplMac.h

    r275485 r275491  
    133133#if ENABLE(IMAGE_EXTRACTION)
    134134    void requestImageExtraction(const URL& imageURL, const ShareableBitmap::Handle& imageData, CompletionHandler<void(WebCore::ImageExtractionResult&&)>&&) override;
     135    void computeCanRevealImage(const URL&, ShareableBitmap&, CompletionHandler<void(bool)>&&) override;
    135136#endif
    136137
  • trunk/Source/WebKit/UIProcess/mac/PageClientImplMac.mm

    r275485 r275491  
    489489}
    490490
     491void PageClientImpl::computeCanRevealImage(const URL& imageURL, ShareableBitmap& imageBitmap, CompletionHandler<void(bool)>&& completion)
     492{
     493    m_impl->computeCanRevealImage(imageURL, imageBitmap, WTFMove(completion));
     494}
     495
    491496#endif
    492497
  • trunk/Source/WebKit/UIProcess/mac/WebContextMenuProxyMac.mm

    r274521 r275491  
    3535#import "ShareableBitmap.h"
    3636#import "WKMenuItemIdentifiersPrivate.h"
     37#import "WKNSURLExtras.h"
    3738#import "WKSharingServicePickerDelegate.h"
    3839#import "WebContextMenuItem.h"
     
    374375}
    375376
    376 void WebContextMenuProxyMac::getContextMenuFromItems(const Vector<WebContextMenuItemData>& items, CompletionHandler<void(NSMenu *)>&& completionHandler)
    377 {
    378     auto menu = adoptNS([[NSMenu alloc] initWithTitle:@""]);
    379     [menu setAutoenablesItems:NO];
    380 
    381     if (items.isEmpty()) {
    382         completionHandler(menu.get());
    383         return;
    384     }
    385    
    386     auto filteredItems = items;
    387     auto webView = m_webView.get();
    388    
    389     bool isPopover = webView.get().window._childWindowOrderingPriority == NSWindowChildOrderingPriorityPopover;
    390     bool isLookupDisabled = [NSUserDefaults.standardUserDefaults boolForKey:@"LULookupDisabled"];
    391    
    392     if (isLookupDisabled || isPopover) {
    393         filteredItems.removeAllMatching([] (auto& item) {
    394             return item.action() == WebCore::ContextMenuItemTagLookUpInDictionary;
    395         });
    396     }
    397 
    398 #if HAVE(TRANSLATION_UI_SERVICES)
    399     if (!page()->canHandleContextMenuTranslation() || isPopover) {
    400         filteredItems.removeAllMatching([] (auto& item) {
    401             return item.action() == ContextMenuItemTagTranslate;
    402         });
    403     }
    404 #endif
    405 
    406     auto sparseMenuItems = retainPtr([NSPointerArray strongObjectsPointerArray]);
    407     auto insertMenuItem = makeBlockPtr([completionHandler = WTFMove(completionHandler), itemsRemaining = filteredItems.size(), menu = WTFMove(menu), sparseMenuItems](NSMenuItem *item, NSUInteger index) mutable {
    408         ASSERT(index < [sparseMenuItems count]);
    409         ASSERT(![sparseMenuItems pointerAtIndex:index]);
    410         [sparseMenuItems replacePointerAtIndex:index withPointer:item];
    411         if (--itemsRemaining)
    412             return;
    413 
    414         [menu setItemArray:[sparseMenuItems allObjects]];
    415         completionHandler(menu.get());
    416     });
    417 
    418     for (size_t i = 0; i < filteredItems.size(); ++i) {
    419         [sparseMenuItems addPointer:nullptr];
    420         getContextMenuItem(filteredItems[i], [insertMenuItem, i](NSMenuItem *menuItem) {
    421             insertMenuItem(menuItem, i);
    422         });
    423     }
    424 }
    425 
    426377static NSString *menuItemIdentifier(const WebCore::ContextMenuAction action)
    427378{
     
    516467}
    517468
     469static RetainPtr<NSMenuItem> createMenuActionItem(const WebContextMenuItemData& item)
     470{
     471    auto type = item.type();
     472    ASSERT_UNUSED(type, type == WebCore::ActionType || type == WebCore::CheckableActionType);
     473
     474    auto menuItem = adoptNS([[NSMenuItem alloc] initWithTitle:item.title() action:@selector(forwardContextMenuAction:) keyEquivalent:@""]);
     475
     476    [menuItem setTag:item.action()];
     477    [menuItem setEnabled:item.enabled()];
     478    [menuItem setState:item.checked() ? NSControlStateValueOn : NSControlStateValueOff];
     479    [menuItem setIndentationLevel:item.indentationLevel()];
     480    [menuItem setTarget:[WKMenuTarget sharedMenuTarget]];
     481    [menuItem setIdentifier:menuItemIdentifier(item.action())];
     482
     483    if (item.userData()) {
     484        auto wrapper = adoptNS([[WKUserDataWrapper alloc] initWithUserData:item.userData()]);
     485        [menuItem setRepresentedObject:wrapper.get()];
     486    }
     487
     488    return menuItem;
     489}
     490
     491void WebContextMenuProxyMac::getContextMenuFromItems(const Vector<WebContextMenuItemData>& items, CompletionHandler<void(NSMenu *)>&& completionHandler)
     492{
     493    auto menu = adoptNS([[NSMenu alloc] initWithTitle:@""]);
     494    [menu setAutoenablesItems:NO];
     495
     496    if (items.isEmpty()) {
     497        completionHandler(menu.get());
     498        return;
     499    }
     500
     501    auto filteredItems = items;
     502    auto webView = m_webView.get();
     503
     504    bool isPopover = webView.get().window._childWindowOrderingPriority == NSWindowChildOrderingPriorityPopover;
     505    bool isLookupDisabled = [NSUserDefaults.standardUserDefaults boolForKey:@"LULookupDisabled"];
     506
     507    if (isLookupDisabled || isPopover) {
     508        filteredItems.removeAllMatching([] (auto& item) {
     509            return item.action() == WebCore::ContextMenuItemTagLookUpInDictionary;
     510        });
     511    }
     512
     513    Optional<WebContextMenuItemData> revealImageItem;
     514
     515#if ENABLE(IMAGE_EXTRACTION)
     516    filteredItems.removeFirstMatching([&] (auto& item) {
     517        if (item.action() != WebCore::ContextMenuItemTagRevealImage)
     518            return false;
     519
     520        revealImageItem = { item };
     521        return true;
     522    });
     523#endif
     524
     525#if HAVE(TRANSLATION_UI_SERVICES)
     526    if (!page()->canHandleContextMenuTranslation() || isPopover) {
     527        filteredItems.removeAllMatching([] (auto& item) {
     528            return item.action() == ContextMenuItemTagTranslate;
     529        });
     530    }
     531#endif
     532
     533    auto imageURL = URL([NSURL _web_URLWithWTFString:m_context.webHitTestResultData().absoluteImageURL]);
     534    auto imageBitmap = m_context.webHitTestResultData().imageBitmap;
     535
     536    auto sparseMenuItems = retainPtr([NSPointerArray strongObjectsPointerArray]);
     537    auto insertMenuItem = makeBlockPtr([protectedThis = makeRef(*this), weakPage = makeWeakPtr(page()), imageURL = WTFMove(imageURL), imageBitmap = WTFMove(imageBitmap), revealImageItem = WTFMove(revealImageItem), completionHandler = WTFMove(completionHandler), itemsRemaining = filteredItems.size(), menu = WTFMove(menu), sparseMenuItems](NSMenuItem *item, NSUInteger index) mutable {
     538        ASSERT(index < [sparseMenuItems count]);
     539        ASSERT(![sparseMenuItems pointerAtIndex:index]);
     540        [sparseMenuItems replacePointerAtIndex:index withPointer:item];
     541        if (--itemsRemaining)
     542            return;
     543
     544        [menu setItemArray:[sparseMenuItems allObjects]];
     545
     546        auto page = makeRefPtr(weakPage.get());
     547        if (revealImageItem && page && imageBitmap) {
     548#if ENABLE(IMAGE_EXTRACTION)
     549            page->computeCanRevealImage(imageURL, *imageBitmap, [protectedThis = WTFMove(protectedThis), revealImageItem = WTFMove(*revealImageItem)] (bool canRevealImage) mutable {
     550                if (!canRevealImage)
     551                    return;
     552
     553                auto nsMenuItem = createMenuActionItem(revealImageItem);
     554                [protectedThis->m_menu addItem:nsMenuItem.get()];
     555            });
     556#else
     557            UNUSED_PARAM(imageURL);
     558#endif
     559        }
     560
     561        completionHandler(menu.get());
     562    });
     563
     564    for (size_t i = 0; i < filteredItems.size(); ++i) {
     565        [sparseMenuItems addPointer:nullptr];
     566        getContextMenuItem(filteredItems[i], [insertMenuItem, i](NSMenuItem *menuItem) {
     567            insertMenuItem(menuItem, i);
     568        });
     569    }
     570}
     571
    518572void WebContextMenuProxyMac::getContextMenuItem(const WebContextMenuItemData& item, CompletionHandler<void(NSMenuItem *)>&& completionHandler)
    519573{
     
    528582    case WebCore::ActionType:
    529583    case WebCore::CheckableActionType: {
    530         auto menuItem = adoptNS([[NSMenuItem alloc] initWithTitle:item.title() action:@selector(forwardContextMenuAction:) keyEquivalent:@""]);
    531 
    532         [menuItem setTag:item.action()];
    533         [menuItem setEnabled:item.enabled()];
    534         [menuItem setState:item.checked() ? NSControlStateValueOn : NSControlStateValueOff];
    535         [menuItem setIndentationLevel:item.indentationLevel()];
    536         [menuItem setTarget:[WKMenuTarget sharedMenuTarget]];
    537         [menuItem setIdentifier:menuItemIdentifier(item.action())];
    538 
    539         if (item.userData()) {
    540             auto wrapper = adoptNS([[WKUserDataWrapper alloc] initWithUserData:item.userData()]);
    541             [menuItem setRepresentedObject:wrapper.get()];
    542         }
    543 
    544         completionHandler(menuItem.get());
     584        auto nsMenuItem = createMenuActionItem(item);
     585        completionHandler(nsMenuItem.get());
    545586        return;
    546587    }
Note: See TracChangeset for help on using the changeset viewer.