[Mac][WebKit2] Move action menu code into its own file
authortimothy_horton@apple.com <timothy_horton@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 24 Oct 2014 21:08:20 +0000 (21:08 +0000)
committertimothy_horton@apple.com <timothy_horton@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 24 Oct 2014 21:08:20 +0000 (21:08 +0000)
https://bugs.webkit.org/show_bug.cgi?id=138034
<rdar://problem/18758758>

Reviewed by Dan Bernstein.

* UIProcess/API/mac/WKView.mm:
(-[WKView initWithFrame:context:configuration:webView:]):
Make a WKActionMenuController if needed.

(-[WKView prepareForMenu:withEvent:]):
(-[WKView willOpenMenu:withEvent:]):
(-[WKView didCloseMenu:withEvent:]):
(-[WKView _didPerformActionMenuHitTest:]):
Forward these to WKActionMenuController.

(-[WKView _openURLFromActionMenu:]): Deleted.
(-[WKView _addToReadingListFromActionMenu:]): Deleted.
(-[WKView _quickLookURLFromActionMenu:]): Deleted.
(-[WKView _createActionMenuItemForTag:]): Deleted.
(webKitBundleImageNamed): Deleted.
(-[WKView _copyImage:]): Deleted.
(-[WKView _saveImageToDownloads:]): Deleted.
(temporaryPhotosDirectoryPath): Deleted.
(pathToPhotoOnDisk): Deleted.
(-[WKView _addImageToPhotos:]): Deleted.
(-[WKView _defaultMenuItemsForImage]): Deleted.
(-[WKView _defaultMenuItems]): Deleted.
(-[WKView _updateActionMenu]): Deleted.
Moved to WKActionMenuController.

* UIProcess/mac/WKActionMenuController.h: Added.
* UIProcess/mac/WKActionMenuController.mm: Added.
(-[WKActionMenuController initWithPage:view:]):
(-[WKActionMenuController prepareForMenu:withEvent:]):
(-[WKActionMenuController willOpenMenu:withEvent:]):
(-[WKActionMenuController didCloseMenu:withEvent:]):
(-[WKActionMenuController didPerformActionMenuHitTest:]):
(-[WKActionMenuController _defaultMenuItemsForLink]):
(-[WKActionMenuController _openURLFromActionMenu:]):
(-[WKActionMenuController _addToReadingListFromActionMenu:]):
(-[WKActionMenuController _quickLookURLFromActionMenu:]):
(-[WKActionMenuController _defaultMenuItemsForImage]):
(-[WKActionMenuController _copyImage:]):
(-[WKActionMenuController _saveImageToDownloads:]):
(temporaryPhotosDirectoryPath):
(pathToPhotoOnDisk):
(-[WKActionMenuController _addImageToPhotos:]):
(-[WKActionMenuController _createActionMenuItemForTag:]):
(webKitBundleImageNamed):
(imageForResource:name::if):
(-[WKActionMenuController _updateActionMenuItems]):
Moved from WKView.

* WebKit2.xcodeproj/project.pbxproj:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@175178 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebKit2/ChangeLog
Source/WebKit2/UIProcess/API/mac/WKView.mm
Source/WebKit2/UIProcess/mac/WKActionMenuController.h [new file with mode: 0644]
Source/WebKit2/UIProcess/mac/WKActionMenuController.mm [new file with mode: 0644]
Source/WebKit2/WebKit2.xcodeproj/project.pbxproj

index aa5aa595217c0446d61058f5b5df20f0712ea26d..6552de281cb0b92927a1e97bc5089cd5a0d957a5 100644 (file)
@@ -1,3 +1,61 @@
+2014-10-24  Tim Horton  <timothy_horton@apple.com>
+
+        [Mac][WebKit2] Move action menu code into its own file
+        https://bugs.webkit.org/show_bug.cgi?id=138034
+        <rdar://problem/18758758>
+
+        Reviewed by Dan Bernstein.
+
+        * UIProcess/API/mac/WKView.mm:
+        (-[WKView initWithFrame:context:configuration:webView:]):
+        Make a WKActionMenuController if needed.
+
+        (-[WKView prepareForMenu:withEvent:]):
+        (-[WKView willOpenMenu:withEvent:]):
+        (-[WKView didCloseMenu:withEvent:]):
+        (-[WKView _didPerformActionMenuHitTest:]):
+        Forward these to WKActionMenuController.
+
+        (-[WKView _openURLFromActionMenu:]): Deleted.
+        (-[WKView _addToReadingListFromActionMenu:]): Deleted.
+        (-[WKView _quickLookURLFromActionMenu:]): Deleted.
+        (-[WKView _createActionMenuItemForTag:]): Deleted.
+        (webKitBundleImageNamed): Deleted.
+        (-[WKView _copyImage:]): Deleted.
+        (-[WKView _saveImageToDownloads:]): Deleted.
+        (temporaryPhotosDirectoryPath): Deleted.
+        (pathToPhotoOnDisk): Deleted.
+        (-[WKView _addImageToPhotos:]): Deleted.
+        (-[WKView _defaultMenuItemsForImage]): Deleted.
+        (-[WKView _defaultMenuItems]): Deleted.
+        (-[WKView _updateActionMenu]): Deleted.
+        Moved to WKActionMenuController.
+
+        * UIProcess/mac/WKActionMenuController.h: Added.
+        * UIProcess/mac/WKActionMenuController.mm: Added.
+        (-[WKActionMenuController initWithPage:view:]):
+        (-[WKActionMenuController prepareForMenu:withEvent:]):
+        (-[WKActionMenuController willOpenMenu:withEvent:]):
+        (-[WKActionMenuController didCloseMenu:withEvent:]):
+        (-[WKActionMenuController didPerformActionMenuHitTest:]):
+        (-[WKActionMenuController _defaultMenuItemsForLink]):
+        (-[WKActionMenuController _openURLFromActionMenu:]):
+        (-[WKActionMenuController _addToReadingListFromActionMenu:]):
+        (-[WKActionMenuController _quickLookURLFromActionMenu:]):
+        (-[WKActionMenuController _defaultMenuItemsForImage]):
+        (-[WKActionMenuController _copyImage:]):
+        (-[WKActionMenuController _saveImageToDownloads:]):
+        (temporaryPhotosDirectoryPath):
+        (pathToPhotoOnDisk):
+        (-[WKActionMenuController _addImageToPhotos:]):
+        (-[WKActionMenuController _createActionMenuItemForTag:]):
+        (webKitBundleImageNamed):
+        (imageForResource:name::if):
+        (-[WKActionMenuController _updateActionMenuItems]):
+        Moved from WKView.
+
+        * WebKit2.xcodeproj/project.pbxproj:
+
 2014-10-24  Marcos Chavarría Teijeiro  <chavarria1991@gmail.com>
 
         [GTK] Implement is_selected method on WebKitHitTestResult
index 141a31c43cc56a444b6df8c60f5fa8fd6e90251b..4a6ce4f96cb08029bd8c059b3e9ec80af6a7b724 100644 (file)
@@ -57,6 +57,7 @@
 #import "ViewGestureController.h"
 #import "ViewSnapshotStore.h"
 #import "WKAPICast.h"
+#import "WKActionMenuController.h"
 #import "WKActionMenuItemTypes.h"
 #import "WKFullScreenWindowController.h"
 #import "WKPrintingView.h"
@@ -76,8 +77,6 @@
 #import "WebProcessProxy.h"
 #import "WebSystemInterface.h"
 #import "_WKThumbnailViewInternal.h"
-#import <ImageIO/ImageIO.h>
-#import <ImageKit/ImageKit.h>
 #import <QuartzCore/QuartzCore.h>
 #import <WebCore/AXObjectCache.h>
 #import <WebCore/ColorMac.h>
@@ -89,7 +88,6 @@
 #import <WebCore/FileSystem.h>
 #import <WebCore/KeyboardEvent.h>
 #import <WebCore/LocalizedStrings.h>
-#import <WebCore/NSSharingServicePickerSPI.h>
 #import <WebCore/NSViewSPI.h>
 #import <WebCore/PlatformEventFactoryMac.h>
 #import <WebCore/PlatformScreen.h>
 - (void)_maskRoundedBottomCorners:(NSRect)clipRect;
 @end
 
-@class QLPreviewBubble;
-@interface NSObject (WKQLPreviewBubbleDetails)
-@property (copy) NSArray * controls;
-@property NSSize maximumSize;
-@property NSRectEdge preferredEdge;
-@property (retain) IBOutlet NSWindow* parentWindow;
-- (void)showPreviewItem:(id)previewItem itemFrame:(NSRect)frame;
-- (void)setAutomaticallyCloseWithMask:(NSEventMask)autocloseMask filterMask:(NSEventMask)filterMask block:(void (^)(void))block;
-@end
-
 #if USE(ASYNC_NSTEXTINPUTCLIENT)
 @interface NSTextInputContext (WKNSTextInputContextDetails)
 - (void)handleEvent:(NSEvent *)theEvent completionHandler:(void(^)(BOOL handled))completionHandler;
@@ -153,9 +141,6 @@ CGSConnectionID CGSMainConnectionID(void);
 CGError CGSGetScreenRectForWindow(CGSConnectionID cid, CGSWindowID wid, CGRect *rect);
 };
 
-SOFT_LINK_FRAMEWORK_IN_UMBRELLA(Quartz, ImageKit)
-SOFT_LINK_CLASS(ImageKit, IKSlideshow)
-
 using namespace WebKit;
 using namespace WebCore;
 
@@ -176,13 +161,6 @@ struct WKViewInterpretKeyEventsParameters {
 };
 #endif
 
-// FIXME: This and all action menu related code should move to its own file.
-enum class ActionMenuState {
-    None = 0,
-    Pending,
-    Ready
-};
-
 @interface WKViewData : NSObject {
 @public
     std::unique_ptr<PageClientImpl> _pageClient;
@@ -279,9 +257,7 @@ enum class ActionMenuState {
     _WKThumbnailView *_thumbnailView;
 #endif
 
-    ActionMenuState _actionMenuState;
-    ActionMenuHitTestResult _actionMenuHitTestResult;
-    RetainPtr<NSSharingServicePicker> _actionMenuSharingServicePicker;
+    RetainPtr<WKActionMenuController> _actionMenuController;
 }
 
 @end
@@ -328,6 +304,8 @@ enum class ActionMenuState {
 
 - (void)dealloc
 {
+    [_data->_actionMenuController willDestroyView:self];
+
     _data->_page->close();
 
 #if WK_API_ENABLED
@@ -3557,8 +3535,9 @@ static NSString *pathWithUniqueFilenameForPath(NSString *path)
     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_applicationWillTerminate:) name:NSApplicationWillTerminateNotification object:NSApp];
 
     if ([self respondsToSelector:@selector(setActionMenu:)]) {
-        RetainPtr<NSMenu> actionMenu = adoptNS([[NSMenu alloc] init]);
-        [self setActionMenu:actionMenu.get()];
+        RetainPtr<NSMenu> menu = adoptNS([[NSMenu alloc] init]);
+        self.actionMenu = menu.get();
+        _data->_actionMenuController = adoptNS([[WKActionMenuController alloc] initWithPage:*_data->_page view:self]);
     }
 
     return self;
@@ -3658,322 +3637,24 @@ static NSString *pathWithUniqueFilenameForPath(NSString *path)
         _data->_gestureController->removeSwipeSnapshot();
 }
 
-- (void)_openURLFromActionMenu:(id)sender
-{
-    WebHitTestResult* hitTestResult = _data->_page->activeActionMenuHitTestResult();
-    if (!hitTestResult)
-        return;
-
-    NSURL *url = [NSURL URLWithString:hitTestResult->absoluteLinkURL()];
-    [[NSWorkspace sharedWorkspace] openURL:url];
-}
-
-- (void)_addToReadingListFromActionMenu:(id)sender
-{
-    WebHitTestResult* hitTestResult = _data->_page->activeActionMenuHitTestResult();
-    if (!hitTestResult)
-        return;
-
-    NSURL *url = [NSURL URLWithString:hitTestResult->absoluteLinkURL()];
-    NSSharingService *service = [NSSharingService sharingServiceNamed:NSSharingServiceNameAddToSafariReadingList];
-    [service performWithItems:@[ url ]];
-}
-
-- (void)_quickLookURLFromActionMenu:(id)sender
-{
-    WebHitTestResult* hitTestResult = _data->_page->activeActionMenuHitTestResult();
-    if (!hitTestResult)
-        return;
-
-    NSRect itemFrame = [self convertRect:hitTestResult->elementBoundingBox() toView:nil];
-    NSSize maximumPreviewSize = NSMakeSize(self.bounds.size.width * 0.75, self.bounds.size.height * 0.75);
-
-    RetainPtr<QLPreviewBubble> bubble = adoptNS([[NSClassFromString(@"QLPreviewBubble") alloc] init]);
-    [bubble setParentWindow:self.window];
-    [bubble setMaximumSize:maximumPreviewSize];
-    [bubble setPreferredEdge:NSMaxYEdge];
-    [bubble setControls:@[ ]];
-    NSEventMask filterMask = NSAnyEventMask & ~(NSAppKitDefinedMask | NSSystemDefinedMask | NSApplicationDefinedMask | NSMouseEnteredMask | NSMouseExitedMask);
-    NSEventMask autocloseMask = NSLeftMouseDownMask | NSRightMouseDownMask | NSKeyDownMask;
-    [bubble setAutomaticallyCloseWithMask:autocloseMask filterMask:filterMask block:[bubble] {
-        [bubble close];
-    }];
-    [bubble showPreviewItem:[NSURL URLWithString:hitTestResult->absoluteLinkURL()] itemFrame:itemFrame];
-}
-
-- (RetainPtr<NSMenuItem>)_createActionMenuItemForTag:(uint32_t)tag
-{
-    SEL selector = nil;
-    NSString *title = nil;
-    NSImage *image = nil;
-
-    switch (tag) {
-    case kWKContextActionItemTagOpenLinkInDefaultBrowser:
-        selector = @selector(_openURLFromActionMenu:);
-        title = @"Open";
-        image = webKitBundleImageNamed(@"OpenInNewWindowTemplate");
-        break;
-
-    case kWKContextActionItemTagPreviewLink:
-        selector = @selector(_quickLookURLFromActionMenu:);
-        title = @"Preview";
-        image = [NSImage imageNamed:NSImageNameQuickLookTemplate];
-        break;
-
-    case kWKContextActionItemTagAddLinkToSafariReadingList:
-        selector = @selector(_addToReadingListFromActionMenu:);
-        title = @"Add to Safari Reading List";
-        image = [NSImage imageNamed:NSImageNameBookmarksTemplate];
-        break;
-
-    case kWKContextActionItemTagCopyImage:
-        selector = @selector(_copyImage:);
-        title = @"Copy";
-        image = webKitBundleImageNamed(@"CopyImageTemplate");
-        break;
-
-    case kWKContextActionItemTagAddImageToPhotos:
-        selector = @selector(_addImageToPhotos:);
-        title = @"Add to Photos";
-        image = webKitBundleImageNamed(@"AddImageToPhotosTemplate");
-        break;
-
-    case kWKContextActionItemTagSaveImageToDownloads:
-        selector = @selector(_saveImageToDownloads:);
-        title = @"Save to Downloads";
-        image = webKitBundleImageNamed(@"SaveImageToDownloadsTemplate");
-        break;
-
-    case kWKContextActionItemTagShareImage:
-        title = @"Share";
-        image = webKitBundleImageNamed(@"ShareImageTemplate");
-        break;
-
-    default:
-        ASSERT_NOT_REACHED();
-        return nil;
-    }
-
-    RetainPtr<NSMenuItem> item = adoptNS([[NSMenuItem alloc] initWithTitle:title action:selector keyEquivalent:@""]);
-    [item setImage:image];
-    [item setTarget:self];
-    [item setTag:tag];
-    return item;
-}
-
-static NSImage *webKitBundleImageNamed(NSString *name)
-{
-    return [[NSBundle bundleForClass:[WKView class]] imageForResource:name];
-}
-
-- (NSArray *)_defaultMenuItemsForLink
-{
-    WebHitTestResult* hitTestResult = _data->_page->activeActionMenuHitTestResult();
-    if (!hitTestResult)
-        return @[ ];
-
-    if (!WebCore::protocolIsInHTTPFamily(hitTestResult->absoluteLinkURL()))
-        return @[ ];
-
-    RetainPtr<NSMenuItem> openLinkItem = [self _createActionMenuItemForTag:kWKContextActionItemTagOpenLinkInDefaultBrowser];
-    RetainPtr<NSMenuItem> previewLinkItem = [self _createActionMenuItemForTag:kWKContextActionItemTagPreviewLink];
-    RetainPtr<NSMenuItem> readingListItem = [self _createActionMenuItemForTag:kWKContextActionItemTagAddLinkToSafariReadingList];
-
-    // FIXME: The separator item is required to work around <rdar://18684207>.
-    return @[openLinkItem.get(), previewLinkItem.get(), [NSMenuItem separatorItem], readingListItem.get()];
-}
-
-- (void)_copyImage:(id)sender
-{
-    WebHitTestResult* hitTestResult = _data->_page->activeActionMenuHitTestResult();
-    if (!hitTestResult)
-        return;
-
-    RefPtr<ShareableBitmap> bitmap = _data->_actionMenuHitTestResult.image;
-    if (!bitmap)
-        return;
-
-    RetainPtr<CGImageRef> image = bitmap->makeCGImage();
-    RetainPtr<NSImage> nsImage = adoptNS([[NSImage alloc] initWithCGImage:image.get() size:NSZeroSize]);
-    [[NSPasteboard generalPasteboard] clearContents];
-    [[NSPasteboard generalPasteboard] writeObjects:@[ nsImage.get() ]];
-}
-
-- (void)_saveImageToDownloads:(id)sender
-{
-    WebHitTestResult* hitTestResult = _data->_page->activeActionMenuHitTestResult();
-    if (!hitTestResult)
-        return;
-
-    _data->_page->process().context().download(_data->_page.get(), URL(URL(), hitTestResult->absoluteImageURL()));
-}
-
-static NSString *temporaryPhotosDirectoryPath()
-{
-    static NSString *temporaryPhotosDirectoryPath;
-
-    if (!temporaryPhotosDirectoryPath) {
-        NSString *temporaryDirectoryTemplate = [NSTemporaryDirectory() stringByAppendingPathComponent:@"WebKitPhotos-XXXXXX"];
-        CString templateRepresentation = [temporaryDirectoryTemplate fileSystemRepresentation];
-
-        if (mkdtemp(templateRepresentation.mutableData()))
-            temporaryPhotosDirectoryPath = [[[NSFileManager defaultManager] stringWithFileSystemRepresentation:templateRepresentation.data() length:templateRepresentation.length()] copy];
-    }
-
-    return temporaryPhotosDirectoryPath;
-}
-
-static NSString *pathToPhotoOnDisk(NSString *suggestedFilename)
-{
-    NSString *photoDirectoryPath = temporaryPhotosDirectoryPath();
-    if (!photoDirectoryPath) {
-        WTFLogAlways("Cannot create temporary photo download directory.");
-        return nil;
-    }
-
-    NSString *path = [photoDirectoryPath stringByAppendingPathComponent:suggestedFilename];
-
-    NSFileManager *fileManager = [NSFileManager defaultManager];
-    if ([fileManager fileExistsAtPath:path]) {
-        NSString *pathTemplatePrefix = [photoDirectoryPath stringByAppendingPathComponent:@"XXXXXX-"];
-        NSString *pathTemplate = [pathTemplatePrefix stringByAppendingString:suggestedFilename];
-        CString pathTemplateRepresentation = [pathTemplate fileSystemRepresentation];
-
-        int fd = mkstemps(pathTemplateRepresentation.mutableData(), pathTemplateRepresentation.length() - strlen([pathTemplatePrefix fileSystemRepresentation]) + 1);
-        if (fd < 0) {
-            WTFLogAlways("Cannot create photo file in the temporary directory (%@).", suggestedFilename);
-            return nil;
-        }
-
-        close(fd);
-        path = [fileManager stringWithFileSystemRepresentation:pathTemplateRepresentation.data() length:pathTemplateRepresentation.length()];
-    }
-
-    return path;
-}
-
-- (void)_addImageToPhotos:(id)sender
-{
-    // FIXME: We shouldn't even add the button if this is the case, for now.
-    if (![getIKSlideshowClass() canExportToApplication:(@"com.apple.Photos")])
-        return;
-
-    WebHitTestResult* hitTestResult = _data->_page->activeActionMenuHitTestResult();
-    if (!hitTestResult)
-        return;
-
-    RefPtr<ShareableBitmap> bitmap = _data->_actionMenuHitTestResult.image;
-    if (!bitmap)
-        return;
-    RetainPtr<CGImageRef> image = bitmap->makeCGImage();
-
-    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
-        NSString * const suggestedFilename = @"image.jpg";
-
-        NSString *filePath = pathToPhotoOnDisk(suggestedFilename);
-        if (!filePath)
-            return;
-
-        NSURL *fileURL = [NSURL fileURLWithPath:filePath];
-        auto dest = adoptCF(CGImageDestinationCreateWithURL((CFURLRef)fileURL, kUTTypeJPEG, 1, nullptr));
-        CGImageDestinationAddImage(dest.get(), image.get(), nullptr);
-        CGImageDestinationFinalize(dest.get());
-
-        dispatch_async(dispatch_get_main_queue(), ^{
-            // This API provides no way to report failure, but if 18420778 is fixed so that it does, we should handle this.
-            [getIKSlideshowClass() exportSlideshowItem:filePath toApplication:(@"com.apple.Photos")];
-        });
-    });
-}
-
-- (NSArray *)_defaultMenuItemsForImage
-{
-    WebHitTestResult* hitTestResult = _data->_page->activeActionMenuHitTestResult();
-    if (!hitTestResult)
-        return @[ ];
-
-    RetainPtr<NSMenuItem> copyImageItem = [self _createActionMenuItemForTag:kWKContextActionItemTagCopyImage];
-    RetainPtr<NSMenuItem> addToPhotosItem = [self _createActionMenuItemForTag:kWKContextActionItemTagAddImageToPhotos];
-    RetainPtr<NSMenuItem> saveToDownloadsItem = [self _createActionMenuItemForTag:kWKContextActionItemTagSaveImageToDownloads];
-    RetainPtr<NSMenuItem> shareItem = [self _createActionMenuItemForTag:kWKContextActionItemTagShareImage];
-
-    if (RefPtr<ShareableBitmap> bitmap = _data->_actionMenuHitTestResult.image) {
-        RetainPtr<CGImageRef> image = bitmap->makeCGImage();
-        RetainPtr<NSImage> nsImage = adoptNS([[NSImage alloc] initWithCGImage:image.get() size:NSZeroSize]);
-        _data->_actionMenuSharingServicePicker = adoptNS([[NSSharingServicePicker alloc] initWithItems:@[ nsImage.get() ]]);
-        [shareItem setSubmenu:[_data->_actionMenuSharingServicePicker menu]];
-     }
-
-    return @[copyImageItem.get(), addToPhotosItem.get(), saveToDownloadsItem.get(), shareItem.get()];
-}
-
-- (NSArray *)_defaultMenuItems
-{
-    if (WebHitTestResult* hitTestResult = _data->_page->activeActionMenuHitTestResult()) {
-        if (!hitTestResult->absoluteImageURL().isEmpty())
-            return [self _defaultMenuItemsForImage];
-        if (!hitTestResult->absoluteLinkURL().isEmpty())
-            return [self _defaultMenuItemsForLink];
-    }
-
-    return @[ ];
-}
-
-- (void)_updateActionMenu
-{
-    [[self actionMenu] removeAllItems];
-
-    NSArray *menuItems = [self _actionMenuItemsForHitTestResult:toAPI(_data->_page->activeActionMenuHitTestResult()) defaultActionMenuItems:[self _defaultMenuItems]];
-
-    for (NSMenuItem *item in menuItems)
-        [[self actionMenu] addItem:item];
-}
-
 - (void)prepareForMenu:(NSMenu *)menu withEvent:(NSEvent *)event
 {
-    if (menu != self.actionMenu)
-        return;
-
-    [self _updateActionMenu];
-
-    _data->_page->performActionMenuHitTestAtLocation([self convertPoint:[event locationInWindow] fromView:nil]);
-
-    _data->_actionMenuState = ActionMenuState::Pending;
-}
-
-- (void)_didPerformActionMenuHitTest:(const ActionMenuHitTestResult&)hitTestResult
-{
-    // FIXME: This needs to use the WebKit2 callback mechanism to avoid out-of-order replies.
-    _data->_actionMenuState = ActionMenuState::Ready;
-    _data->_actionMenuHitTestResult = hitTestResult;
+    [_data->_actionMenuController prepareForMenu:menu withEvent:event];
 }
 
 - (void)willOpenMenu:(NSMenu *)menu withEvent:(NSEvent *)event
 {
-    if (menu != self.actionMenu)
-        return;
-
-    ASSERT(_data->_actionMenuState != ActionMenuState::None);
-
-    // FIXME: We need to be able to cancel this if the menu goes away.
-    // FIXME: Connection can be null if the process is closed; we should clean up better in that case.
-    if (_data->_actionMenuState == ActionMenuState::Pending) {
-        if (auto* connection = _data->_page->process().connection())
-            connection->waitForAndDispatchImmediately<Messages::WebPageProxy::DidPerformActionMenuHitTest>(_data->_page->pageID(), std::chrono::milliseconds(500));
-    }
-
-    if (_data->_actionMenuState == ActionMenuState::Ready)
-        [self _updateActionMenu];
+    [_data->_actionMenuController willOpenMenu:menu withEvent:event];
 }
 
 - (void)didCloseMenu:(NSMenu *)menu withEvent:(NSEvent *)event
 {
-    if (menu != self.actionMenu)
-        return;
+    [_data->_actionMenuController didCloseMenu:menu withEvent:event];
+}
 
-    _data->_actionMenuState = ActionMenuState::None;
-    _data->_actionMenuHitTestResult = ActionMenuHitTestResult();
-    _data->_actionMenuSharingServicePicker = nil;
+- (void)_didPerformActionMenuHitTest:(const ActionMenuHitTestResult&)hitTestResult
+{
+    [_data->_actionMenuController didPerformActionMenuHitTest:hitTestResult];
 }
 
 @end
diff --git a/Source/WebKit2/UIProcess/mac/WKActionMenuController.h b/Source/WebKit2/UIProcess/mac/WKActionMenuController.h
new file mode 100644 (file)
index 0000000..3311543
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef WKActionMenuController_h
+#define WKActionMenuController_h
+
+namespace WebKit {
+class WebPageProxy;
+struct ActionMenuHitTestResult;
+}
+
+@class WKView;
+
+@interface WKActionMenuController : NSObject
+
+- (instancetype)initWithPage:(WebKit::WebPageProxy&)page view:(WKView *)wkView;
+- (void)willDestroyView:(WKView *)view;
+
+- (void)prepareForMenu:(NSMenu *)menu withEvent:(NSEvent *)event;
+- (void)willOpenMenu:(NSMenu *)menu withEvent:(NSEvent *)event;
+- (void)didCloseMenu:(NSMenu *)menu withEvent:(NSEvent *)event;
+
+- (void)didPerformActionMenuHitTest:(const WebKit::ActionMenuHitTestResult&)hitTestResult;
+
+@end
+
+#endif // WKActionMenuController_h
diff --git a/Source/WebKit2/UIProcess/mac/WKActionMenuController.mm b/Source/WebKit2/UIProcess/mac/WKActionMenuController.mm
new file mode 100644 (file)
index 0000000..a31f971
--- /dev/null
@@ -0,0 +1,401 @@
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import "config.h"
+#import "WKActionMenuController.h"
+
+#if PLATFORM(MAC)
+
+#import "ActionMenuHitTestResult.h"
+#import "WKActionMenuItemTypes.h"
+#import "WKNSURLExtras.h"
+#import "WKViewInternal.h"
+#import "WebContext.h"
+#import "WebPageMessages.h"
+#import "WebPageProxy.h"
+#import "WebPageProxyMessages.h"
+#import "WebProcessProxy.h"
+#import <ImageIO/ImageIO.h>
+#import <ImageKit/ImageKit.h>
+#import <WebCore/NSSharingServicePickerSPI.h>
+#import <WebCore/NSViewSPI.h>
+#import <WebCore/SoftLinking.h>
+#import <WebCore/URL.h>
+
+// FIXME: This should move into an SPI header if it stays.
+@class QLPreviewBubble;
+@interface NSObject (WKQLPreviewBubbleDetails)
+@property (copy) NSArray * controls;
+@property NSSize maximumSize;
+@property NSRectEdge preferredEdge;
+@property (retain) IBOutlet NSWindow* parentWindow;
+- (void)showPreviewItem:(id)previewItem itemFrame:(NSRect)frame;
+- (void)setAutomaticallyCloseWithMask:(NSEventMask)autocloseMask filterMask:(NSEventMask)filterMask block:(void (^)(void))block;
+@end
+
+SOFT_LINK_FRAMEWORK_IN_UMBRELLA(Quartz, ImageKit)
+SOFT_LINK_CLASS(ImageKit, IKSlideshow)
+
+using namespace WebCore;
+using namespace WebKit;
+
+enum class ActionMenuState {
+    None = 0,
+    Pending,
+    Ready
+};
+
+@interface WKActionMenuController ()
+- (void)_updateActionMenuItems;
+@end
+
+@implementation WKActionMenuController {
+    WebPageProxy *_page;
+    WKView *_wkView;
+
+    ActionMenuState _state;
+    ActionMenuHitTestResult _hitTestResult;
+    RetainPtr<NSSharingServicePicker> _sharingServicePicker;
+}
+
+- (instancetype)initWithPage:(WebPageProxy&)page view:(WKView *)wkView
+{
+    self = [super init];
+
+    if (!self)
+        return nil;
+
+    _page = &page;
+    _wkView = wkView;
+
+    return self;
+}
+
+- (void)willDestroyView:(WKView *)view
+{
+    _page = nullptr;
+    _wkView = nullptr;
+}
+
+- (void)prepareForMenu:(NSMenu *)menu withEvent:(NSEvent *)event
+{
+    if (menu != _wkView.actionMenu)
+        return;
+
+    [self _updateActionMenuItems];
+
+    _page->performActionMenuHitTestAtLocation([_wkView convertPoint:[event locationInWindow] fromView:nil]);
+
+    _state = ActionMenuState::Pending;
+}
+
+- (void)willOpenMenu:(NSMenu *)menu withEvent:(NSEvent *)event
+{
+    if (menu != _wkView.actionMenu)
+        return;
+
+    ASSERT(_state != ActionMenuState::None);
+
+    // FIXME: We need to be able to cancel this if the menu goes away.
+    // FIXME: Connection can be null if the process is closed; we should clean up better in that case.
+    if (_state == ActionMenuState::Pending) {
+        if (auto* connection = _page->process().connection())
+            connection->waitForAndDispatchImmediately<Messages::WebPageProxy::DidPerformActionMenuHitTest>(_page->pageID(), std::chrono::milliseconds(500));
+    }
+
+    if (_state == ActionMenuState::Ready)
+        [self _updateActionMenuItems];
+}
+
+- (void)didCloseMenu:(NSMenu *)menu withEvent:(NSEvent *)event
+{
+    if (menu != _wkView.actionMenu)
+        return;
+    
+    _state = ActionMenuState::None;
+    _hitTestResult = ActionMenuHitTestResult();
+    _sharingServicePicker = nil;
+}
+
+- (void)didPerformActionMenuHitTest:(const ActionMenuHitTestResult&)hitTestResult
+{
+    // FIXME: This needs to use the WebKit2 callback mechanism to avoid out-of-order replies.
+    _state = ActionMenuState::Ready;
+    _hitTestResult = hitTestResult;
+}
+
+#pragma mark Link actions
+
+- (NSArray *)_defaultMenuItemsForLink
+{
+    WebHitTestResult* hitTestResult = _page->activeActionMenuHitTestResult();
+    if (!WebCore::protocolIsInHTTPFamily(hitTestResult->absoluteLinkURL()))
+        return @[ ];
+
+    RetainPtr<NSMenuItem> openLinkItem = [self _createActionMenuItemForTag:kWKContextActionItemTagOpenLinkInDefaultBrowser];
+    RetainPtr<NSMenuItem> previewLinkItem = [self _createActionMenuItemForTag:kWKContextActionItemTagPreviewLink];
+    RetainPtr<NSMenuItem> readingListItem = [self _createActionMenuItemForTag:kWKContextActionItemTagAddLinkToSafariReadingList];
+
+    // FIXME: The separator item is required to work around <rdar://18684207>.
+    return @[ openLinkItem.get(), previewLinkItem.get(), [NSMenuItem separatorItem], readingListItem.get() ];
+}
+
+- (void)_openURLFromActionMenu:(id)sender
+{
+    WebHitTestResult* hitTestResult = _page->activeActionMenuHitTestResult();
+    [[NSWorkspace sharedWorkspace] openURL:[NSURL _web_URLWithWTFString:hitTestResult->absoluteLinkURL()]];
+}
+
+- (void)_addToReadingListFromActionMenu:(id)sender
+{
+    WebHitTestResult* hitTestResult = _page->activeActionMenuHitTestResult();
+    NSSharingService *service = [NSSharingService sharingServiceNamed:NSSharingServiceNameAddToSafariReadingList];
+    [service performWithItems:@[ [NSURL _web_URLWithWTFString:hitTestResult->absoluteLinkURL()] ]];
+}
+
+- (void)_quickLookURLFromActionMenu:(id)sender
+{
+    WebHitTestResult* hitTestResult = _page->activeActionMenuHitTestResult();
+    NSRect itemFrame = [_wkView convertRect:hitTestResult->elementBoundingBox() toView:nil];
+    NSSize maximumPreviewSize = NSMakeSize(_wkView.bounds.size.width * 0.75, _wkView.bounds.size.height * 0.75);
+
+    RetainPtr<QLPreviewBubble> bubble = adoptNS([[NSClassFromString(@"QLPreviewBubble") alloc] init]);
+    [bubble setParentWindow:_wkView.window];
+    [bubble setMaximumSize:maximumPreviewSize];
+    [bubble setPreferredEdge:NSMaxYEdge];
+    [bubble setControls:@[ ]];
+    NSEventMask filterMask = NSAnyEventMask & ~(NSAppKitDefinedMask | NSSystemDefinedMask | NSApplicationDefinedMask | NSMouseEnteredMask | NSMouseExitedMask);
+    NSEventMask autocloseMask = NSLeftMouseDownMask | NSRightMouseDownMask | NSKeyDownMask;
+    [bubble setAutomaticallyCloseWithMask:autocloseMask filterMask:filterMask block:[bubble] {
+        [bubble close];
+    }];
+    [bubble showPreviewItem:[NSURL _web_URLWithWTFString:hitTestResult->absoluteLinkURL()] itemFrame:itemFrame];
+}
+
+#pragma mark Image actions
+
+- (NSArray *)_defaultMenuItemsForImage
+{
+    RetainPtr<NSMenuItem> copyImageItem = [self _createActionMenuItemForTag:kWKContextActionItemTagCopyImage];
+    RetainPtr<NSMenuItem> addToPhotosItem = [self _createActionMenuItemForTag:kWKContextActionItemTagAddImageToPhotos];
+    RetainPtr<NSMenuItem> saveToDownloadsItem = [self _createActionMenuItemForTag:kWKContextActionItemTagSaveImageToDownloads];
+    RetainPtr<NSMenuItem> shareItem = [self _createActionMenuItemForTag:kWKContextActionItemTagShareImage];
+
+    if (RefPtr<ShareableBitmap> bitmap = _hitTestResult.image) {
+        RetainPtr<CGImageRef> image = bitmap->makeCGImage();
+        RetainPtr<NSImage> nsImage = adoptNS([[NSImage alloc] initWithCGImage:image.get() size:NSZeroSize]);
+        _sharingServicePicker = adoptNS([[NSSharingServicePicker alloc] initWithItems:@[ nsImage.get() ]]);
+        [shareItem setSubmenu:[_sharingServicePicker menu]];
+    }
+
+    return @[ copyImageItem.get(), addToPhotosItem.get(), saveToDownloadsItem.get(), shareItem.get() ];
+}
+
+- (void)_copyImage:(id)sender
+{
+    RefPtr<ShareableBitmap> bitmap = _hitTestResult.image;
+    if (!bitmap)
+        return;
+
+    RetainPtr<CGImageRef> image = bitmap->makeCGImage();
+    RetainPtr<NSImage> nsImage = adoptNS([[NSImage alloc] initWithCGImage:image.get() size:NSZeroSize]);
+    [[NSPasteboard generalPasteboard] clearContents];
+    [[NSPasteboard generalPasteboard] writeObjects:@[ nsImage.get() ]];
+}
+
+- (void)_saveImageToDownloads:(id)sender
+{
+    WebHitTestResult* hitTestResult = _page->activeActionMenuHitTestResult();
+    _page->process().context().download(_page, hitTestResult->absoluteImageURL());
+}
+
+// FIXME: We should try to share this with WebPageProxyMac's similar PDF functions.
+static NSString *temporaryPhotosDirectoryPath()
+{
+    static NSString *temporaryPhotosDirectoryPath;
+
+    if (!temporaryPhotosDirectoryPath) {
+        NSString *temporaryDirectoryTemplate = [NSTemporaryDirectory() stringByAppendingPathComponent:@"WebKitPhotos-XXXXXX"];
+        CString templateRepresentation = [temporaryDirectoryTemplate fileSystemRepresentation];
+
+        if (mkdtemp(templateRepresentation.mutableData()))
+            temporaryPhotosDirectoryPath = [[[NSFileManager defaultManager] stringWithFileSystemRepresentation:templateRepresentation.data() length:templateRepresentation.length()] copy];
+    }
+
+    return temporaryPhotosDirectoryPath;
+}
+
+static NSString *pathToPhotoOnDisk(NSString *suggestedFilename)
+{
+    NSString *photoDirectoryPath = temporaryPhotosDirectoryPath();
+    if (!photoDirectoryPath) {
+        WTFLogAlways("Cannot create temporary photo download directory.");
+        return nil;
+    }
+
+    NSString *path = [photoDirectoryPath stringByAppendingPathComponent:suggestedFilename];
+
+    NSFileManager *fileManager = [NSFileManager defaultManager];
+    if ([fileManager fileExistsAtPath:path]) {
+        NSString *pathTemplatePrefix = [photoDirectoryPath stringByAppendingPathComponent:@"XXXXXX-"];
+        NSString *pathTemplate = [pathTemplatePrefix stringByAppendingString:suggestedFilename];
+        CString pathTemplateRepresentation = [pathTemplate fileSystemRepresentation];
+
+        int fd = mkstemps(pathTemplateRepresentation.mutableData(), pathTemplateRepresentation.length() - strlen([pathTemplatePrefix fileSystemRepresentation]) + 1);
+        if (fd < 0) {
+            WTFLogAlways("Cannot create photo file in the temporary directory (%@).", suggestedFilename);
+            return nil;
+        }
+
+        close(fd);
+        path = [fileManager stringWithFileSystemRepresentation:pathTemplateRepresentation.data() length:pathTemplateRepresentation.length()];
+    }
+
+    return path;
+}
+
+- (void)_addImageToPhotos:(id)sender
+{
+    // FIXME: We shouldn't even add the button if this is the case, for now.
+    if (![getIKSlideshowClass() canExportToApplication:@"com.apple.Photos"])
+        return;
+
+    RefPtr<ShareableBitmap> bitmap = _hitTestResult.image;
+    if (!bitmap)
+        return;
+    RetainPtr<CGImageRef> image = bitmap->makeCGImage();
+
+    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
+        NSString * const suggestedFilename = @"image.jpg";
+
+        NSString *filePath = pathToPhotoOnDisk(suggestedFilename);
+        if (!filePath)
+            return;
+
+        NSURL *fileURL = [NSURL fileURLWithPath:filePath];
+        auto dest = adoptCF(CGImageDestinationCreateWithURL((CFURLRef)fileURL, kUTTypeJPEG, 1, nullptr));
+        CGImageDestinationAddImage(dest.get(), image.get(), nullptr);
+        CGImageDestinationFinalize(dest.get());
+
+        dispatch_async(dispatch_get_main_queue(), ^{
+            // This API provides no way to report failure, but if 18420778 is fixed so that it does, we should handle this.
+            [getIKSlideshowClass() exportSlideshowItem:filePath toApplication:@"com.apple.Photos"];
+        });
+    });
+}
+
+#pragma mark Menu Items
+
+- (RetainPtr<NSMenuItem>)_createActionMenuItemForTag:(uint32_t)tag
+{
+    SEL selector = nullptr;
+    NSString *title = nil;
+    NSImage *image = nil;
+
+    // FIXME: These titles need to be localized.
+    switch (tag) {
+    case kWKContextActionItemTagOpenLinkInDefaultBrowser:
+        selector = @selector(_openURLFromActionMenu:);
+        title = @"Open";
+        image = webKitBundleImageNamed(@"OpenInNewWindowTemplate");
+        break;
+
+    case kWKContextActionItemTagPreviewLink:
+        selector = @selector(_quickLookURLFromActionMenu:);
+        title = @"Preview";
+        image = [NSImage imageNamed:NSImageNameQuickLookTemplate];
+        break;
+
+    case kWKContextActionItemTagAddLinkToSafariReadingList:
+        selector = @selector(_addToReadingListFromActionMenu:);
+        title = @"Add to Safari Reading List";
+        image = [NSImage imageNamed:NSImageNameBookmarksTemplate];
+        break;
+
+    case kWKContextActionItemTagCopyImage:
+        selector = @selector(_copyImage:);
+        title = @"Copy";
+        image = webKitBundleImageNamed(@"CopyImageTemplate");
+        break;
+
+    case kWKContextActionItemTagAddImageToPhotos:
+        selector = @selector(_addImageToPhotos:);
+        title = @"Add to Photos";
+        image = webKitBundleImageNamed(@"AddImageToPhotosTemplate");
+        break;
+
+    case kWKContextActionItemTagSaveImageToDownloads:
+        selector = @selector(_saveImageToDownloads:);
+        title = @"Save to Downloads";
+        image = webKitBundleImageNamed(@"SaveImageToDownloadsTemplate");
+        break;
+
+    case kWKContextActionItemTagShareImage:
+        title = @"Share";
+        image = webKitBundleImageNamed(@"ShareImageTemplate");
+        break;
+
+    default:
+        ASSERT_NOT_REACHED();
+        return nil;
+    }
+
+    RetainPtr<NSMenuItem> item = adoptNS([[NSMenuItem alloc] initWithTitle:title action:selector keyEquivalent:@""]);
+    [item setImage:image];
+    [item setTarget:self];
+    [item setTag:tag];
+    return item;
+}
+
+static NSImage *webKitBundleImageNamed(NSString *name)
+{
+    return [[NSBundle bundleForClass:[WKView class]] imageForResource:name];
+}
+
+- (NSArray *)_defaultMenuItems
+{
+    if (WebHitTestResult* hitTestResult = _page->activeActionMenuHitTestResult()) {
+        if (!hitTestResult->absoluteImageURL().isEmpty())
+            return [self _defaultMenuItemsForImage];
+        if (!hitTestResult->absoluteLinkURL().isEmpty())
+            return [self _defaultMenuItemsForLink];
+    }
+
+    return @[ ];
+}
+
+- (void)_updateActionMenuItems
+{
+    [_wkView.actionMenu removeAllItems];
+
+    NSArray *menuItems = [_wkView _actionMenuItemsForHitTestResult:toAPI(_page->activeActionMenuHitTestResult()) defaultActionMenuItems:[self _defaultMenuItems]];
+    
+    for (NSMenuItem *item in menuItems)
+        [_wkView.actionMenu addItem:item];
+}
+
+@end
+
+#endif // PLATFORM(MAC)
index 9ce93e9cf01bf8ab472c987fda98f999ecdabb88..a6b649e317cd386774e2e90d443478fe4c45b19a 100644 (file)
                29CD55AB128E294F00133C85 /* WKAccessibilityWebPageObjectBase.mm in Sources */ = {isa = PBXBuildFile; fileRef = 29CD55A9128E294F00133C85 /* WKAccessibilityWebPageObjectBase.mm */; };
                29D55DF1161BF9F10031A2E3 /* WebPageGroupProxyMessageReceiver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 29D55DEF161BF9F10031A2E3 /* WebPageGroupProxyMessageReceiver.cpp */; };
                29D55DF2161BF9F10031A2E3 /* WebPageGroupProxyMessages.h in Headers */ = {isa = PBXBuildFile; fileRef = 29D55DF0161BF9F10031A2E3 /* WebPageGroupProxyMessages.h */; };
+               2D0730A219F9C7DA00E9D9C4 /* WKActionMenuController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 2D0730A019F9C7DA00E9D9C4 /* WKActionMenuController.mm */; };
+               2D0730A319F9C7DA00E9D9C4 /* WKActionMenuController.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D0730A119F9C7DA00E9D9C4 /* WKActionMenuController.h */; };
                2D125C5E1857EA05003BA3CB /* ViewGestureController.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D125C5C1857EA05003BA3CB /* ViewGestureController.h */; };
                2D125C5F1857EA05003BA3CB /* ViewGestureControllerMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = 2D125C5D1857EA05003BA3CB /* ViewGestureControllerMac.mm */; };
                2D1B5D5D185869C8006C6596 /* ViewGestureControllerMessageReceiver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2D1B5D5B185869C8006C6596 /* ViewGestureControllerMessageReceiver.cpp */; };
                29D55DEE161BF8780031A2E3 /* WebPageGroupProxy.messages.in */ = {isa = PBXFileReference; lastKnownFileType = text; path = WebPageGroupProxy.messages.in; sourceTree = "<group>"; };
                29D55DEF161BF9F10031A2E3 /* WebPageGroupProxyMessageReceiver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WebPageGroupProxyMessageReceiver.cpp; sourceTree = "<group>"; };
                29D55DF0161BF9F10031A2E3 /* WebPageGroupProxyMessages.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebPageGroupProxyMessages.h; sourceTree = "<group>"; };
+               2D0730A019F9C7DA00E9D9C4 /* WKActionMenuController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WKActionMenuController.mm; sourceTree = "<group>"; };
+               2D0730A119F9C7DA00E9D9C4 /* WKActionMenuController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKActionMenuController.h; sourceTree = "<group>"; };
                2D125C5C1857EA05003BA3CB /* ViewGestureController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ViewGestureController.h; sourceTree = "<group>"; };
                2D125C5D1857EA05003BA3CB /* ViewGestureControllerMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ViewGestureControllerMac.mm; sourceTree = "<group>"; };
                2D1B5D5A18586599006C6596 /* ViewGestureController.messages.in */ = {isa = PBXFileReference; lastKnownFileType = text; path = ViewGestureController.messages.in; sourceTree = "<group>"; };
                                51D130571382F10500351EDD /* WebProcessProxyMac.mm */,
                                868160CD18763D4B0021E79D /* WindowServerConnection.h */,
                                868160CF187645370021E79D /* WindowServerConnection.mm */,
+                               2D0730A019F9C7DA00E9D9C4 /* WKActionMenuController.mm */,
+                               2D0730A119F9C7DA00E9D9C4 /* WKActionMenuController.h */,
                                E1AEA22D14687BDB00804569 /* WKFullKeyboardAccessWatcher.h */,
                                E1AEA22E14687BDB00804569 /* WKFullKeyboardAccessWatcher.mm */,
                                CDCA85C7132ABA4E00E961DF /* WKFullScreenWindowController.h */,
                                E1513C67166EABB200149FCB /* ChildProcessProxy.h in Headers */,
                                7CA254EB182993CE00FC8A41 /* WKBrowsingContextPolicyDelegate.h in Headers */,
                                37C4C08718149C5B003688B9 /* WKBackForwardListItem.h in Headers */,
+                               2D0730A319F9C7DA00E9D9C4 /* WKActionMenuController.h in Headers */,
                                1F335BC0185B84F0001A201A /* WKWebProcessPlugInLoadDelegate.h in Headers */,
                                1F7506B41859164C00EC0FF7 /* WKWebProcessPlugInScriptWorld.h in Headers */,
                                1A43E82A188F3CDC009E4D30 /* _WKProcessPoolConfiguration.h in Headers */,
                                518D2CAD12D5153B003BB93B /* WebBackForwardListItem.cpp in Sources */,
                                BC72B9FA11E6476B001EB4EA /* WebBackForwardListProxy.cpp in Sources */,
                                BC111A5A112F4FBB00337BAB /* WebChromeClient.cpp in Sources */,
+                               2D0730A219F9C7DA00E9D9C4 /* WKActionMenuController.mm in Sources */,
                                868160D0187645570021E79D /* WindowServerConnection.mm in Sources */,
                                3F87B9BD158940120090FF62 /* WebColorChooser.cpp in Sources */,
                                A58B6F0918FCA733008CBA53 /* WKFileUploadPanel.mm in Sources */,