<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[175315] branches/safari-600.3-branch/Source/WebKit2</title>
</head>
<body>
<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; }
#msg dl a { font-weight: bold}
#msg dl a:link { color:#fc3; }
#msg dl a:active { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/175315">175315</a></dd>
<dt>Author</dt> <dd>lforschler@apple.com</dd>
<dt>Date</dt> <dd>2014-10-29 01:30:49 -0700 (Wed, 29 Oct 2014)</dd>
</dl>
<h3>Log Message</h3>
<pre>Merged <a href="http://trac.webkit.org/projects/webkit/changeset/175178">r175178</a>. rdar://problem/18758758</pre>
<h3>Modified Paths</h3>
<ul>
<li><a href="#branchessafari6003branchSourceWebKit2ChangeLog">branches/safari-600.3-branch/Source/WebKit2/ChangeLog</a></li>
<li><a href="#branchessafari6003branchSourceWebKit2UIProcessAPImacWKViewmm">branches/safari-600.3-branch/Source/WebKit2/UIProcess/API/mac/WKView.mm</a></li>
<li><a href="#branchessafari6003branchSourceWebKit2WebKit2xcodeprojprojectpbxproj">branches/safari-600.3-branch/Source/WebKit2/WebKit2.xcodeproj/project.pbxproj</a></li>
</ul>
<h3>Added Paths</h3>
<ul>
<li><a href="#branchessafari6003branchSourceWebKit2UIProcessmacWKActionMenuControllerh">branches/safari-600.3-branch/Source/WebKit2/UIProcess/mac/WKActionMenuController.h</a></li>
<li><a href="#branchessafari6003branchSourceWebKit2UIProcessmacWKActionMenuControllermm">branches/safari-600.3-branch/Source/WebKit2/UIProcess/mac/WKActionMenuController.mm</a></li>
</ul>
</div>
<div id="patch">
<h3>Diff</h3>
<a id="branchessafari6003branchSourceWebKit2ChangeLog"></a>
<div class="modfile"><h4>Modified: branches/safari-600.3-branch/Source/WebKit2/ChangeLog (175314 => 175315)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-600.3-branch/Source/WebKit2/ChangeLog        2014-10-29 08:30:39 UTC (rev 175314)
+++ branches/safari-600.3-branch/Source/WebKit2/ChangeLog        2014-10-29 08:30:49 UTC (rev 175315)
</span><span class="lines">@@ -1,5 +1,67 @@
</span><span class="cx"> 2014-10-29 Lucas Forschler <lforschler@apple.com>
</span><span class="cx">
</span><ins>+ Merge r175178
+
+ 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-29 Lucas Forschler <lforschler@apple.com>
+
</ins><span class="cx"> Merge r175147
</span><span class="cx">
</span><span class="cx"> 2014-10-23 Tim Horton <timothy_horton@apple.com>
</span></span></pre></div>
<a id="branchessafari6003branchSourceWebKit2UIProcessAPImacWKViewmm"></a>
<div class="modfile"><h4>Modified: branches/safari-600.3-branch/Source/WebKit2/UIProcess/API/mac/WKView.mm (175314 => 175315)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-600.3-branch/Source/WebKit2/UIProcess/API/mac/WKView.mm        2014-10-29 08:30:39 UTC (rev 175314)
+++ branches/safari-600.3-branch/Source/WebKit2/UIProcess/API/mac/WKView.mm        2014-10-29 08:30:49 UTC (rev 175315)
</span><span class="lines">@@ -57,6 +57,7 @@
</span><span class="cx"> #import "ViewGestureController.h"
</span><span class="cx"> #import "ViewSnapshotStore.h"
</span><span class="cx"> #import "WKAPICast.h"
</span><ins>+#import "WKActionMenuController.h"
</ins><span class="cx"> #import "WKActionMenuItemTypes.h"
</span><span class="cx"> #import "WKFullScreenWindowController.h"
</span><span class="cx"> #import "WKPrintingView.h"
</span><span class="lines">@@ -76,8 +77,6 @@
</span><span class="cx"> #import "WebProcessProxy.h"
</span><span class="cx"> #import "WebSystemInterface.h"
</span><span class="cx"> #import "_WKThumbnailViewInternal.h"
</span><del>-#import <ImageIO/ImageIO.h>
-#import <ImageKit/ImageKit.h>
</del><span class="cx"> #import <QuartzCore/QuartzCore.h>
</span><span class="cx"> #import <WebCore/AXObjectCache.h>
</span><span class="cx"> #import <WebCore/ColorMac.h>
</span><span class="lines">@@ -89,7 +88,6 @@
</span><span class="cx"> #import <WebCore/FileSystem.h>
</span><span class="cx"> #import <WebCore/KeyboardEvent.h>
</span><span class="cx"> #import <WebCore/LocalizedStrings.h>
</span><del>-#import <WebCore/NSSharingServicePickerSPI.h>
</del><span class="cx"> #import <WebCore/NSViewSPI.h>
</span><span class="cx"> #import <WebCore/PlatformEventFactoryMac.h>
</span><span class="cx"> #import <WebCore/PlatformScreen.h>
</span><span class="lines">@@ -124,16 +122,6 @@
</span><span class="cx"> - (void)_maskRoundedBottomCorners:(NSRect)clipRect;
</span><span class="cx"> @end
</span><span class="cx">
</span><del>-@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
-
</del><span class="cx"> #if USE(ASYNC_NSTEXTINPUTCLIENT)
</span><span class="cx"> @interface NSTextInputContext (WKNSTextInputContextDetails)
</span><span class="cx"> - (void)handleEvent:(NSEvent *)theEvent completionHandler:(void(^)(BOOL handled))completionHandler;
</span><span class="lines">@@ -153,9 +141,6 @@
</span><span class="cx"> CGError CGSGetScreenRectForWindow(CGSConnectionID cid, CGSWindowID wid, CGRect *rect);
</span><span class="cx"> };
</span><span class="cx">
</span><del>-SOFT_LINK_FRAMEWORK_IN_UMBRELLA(Quartz, ImageKit)
-SOFT_LINK_CLASS(ImageKit, IKSlideshow)
-
</del><span class="cx"> using namespace WebKit;
</span><span class="cx"> using namespace WebCore;
</span><span class="cx">
</span><span class="lines">@@ -176,13 +161,6 @@
</span><span class="cx"> };
</span><span class="cx"> #endif
</span><span class="cx">
</span><del>-// FIXME: This and all action menu related code should move to its own file.
-enum class ActionMenuState {
- None = 0,
- Pending,
- Ready
-};
-
</del><span class="cx"> @interface WKViewData : NSObject {
</span><span class="cx"> @public
</span><span class="cx"> std::unique_ptr<PageClientImpl> _pageClient;
</span><span class="lines">@@ -279,9 +257,7 @@
</span><span class="cx"> _WKThumbnailView *_thumbnailView;
</span><span class="cx"> #endif
</span><span class="cx">
</span><del>- ActionMenuState _actionMenuState;
- ActionMenuHitTestResult _actionMenuHitTestResult;
- RetainPtr<NSSharingServicePicker> _actionMenuSharingServicePicker;
</del><ins>+ RetainPtr<WKActionMenuController> _actionMenuController;
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> @end
</span><span class="lines">@@ -328,6 +304,8 @@
</span><span class="cx">
</span><span class="cx"> - (void)dealloc
</span><span class="cx"> {
</span><ins>+ [_data->_actionMenuController willDestroyView:self];
+
</ins><span class="cx"> _data->_page->close();
</span><span class="cx">
</span><span class="cx"> #if WK_API_ENABLED
</span><span class="lines">@@ -3557,8 +3535,9 @@
</span><span class="cx"> [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_applicationWillTerminate:) name:NSApplicationWillTerminateNotification object:NSApp];
</span><span class="cx">
</span><span class="cx"> if ([self respondsToSelector:@selector(setActionMenu:)]) {
</span><del>- RetainPtr<NSMenu> actionMenu = adoptNS([[NSMenu alloc] init]);
- [self setActionMenu:actionMenu.get()];
</del><ins>+ RetainPtr<NSMenu> menu = adoptNS([[NSMenu alloc] init]);
+ self.actionMenu = menu.get();
+ _data->_actionMenuController = adoptNS([[WKActionMenuController alloc] initWithPage:*_data->_page view:self]);
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> return self;
</span><span class="lines">@@ -3658,324 +3637,26 @@
</span><span class="cx"> _data->_gestureController->removeSwipeSnapshot();
</span><span class="cx"> }
</span><span class="cx">
</span><del>-- (void)_openURLFromActionMenu:(id)sender
</del><ins>+- (void)prepareForMenu:(NSMenu *)menu withEvent:(NSEvent *)event
</ins><span class="cx"> {
</span><del>- WebHitTestResult* hitTestResult = _data->_page->activeActionMenuHitTestResult();
- if (!hitTestResult)
- return;
-
- NSURL *url = [NSURL URLWithString:hitTestResult->absoluteLinkURL()];
- [[NSWorkspace sharedWorkspace] openURL:url];
</del><ins>+ [_data->_actionMenuController prepareForMenu:menu withEvent:event];
</ins><span class="cx"> }
</span><span class="cx">
</span><del>-- (void)_addToReadingListFromActionMenu:(id)sender
</del><ins>+- (void)willOpenMenu:(NSMenu *)menu withEvent:(NSEvent *)event
</ins><span class="cx"> {
</span><del>- WebHitTestResult* hitTestResult = _data->_page->activeActionMenuHitTestResult();
- if (!hitTestResult)
- return;
-
- NSURL *url = [NSURL URLWithString:hitTestResult->absoluteLinkURL()];
- NSSharingService *service = [NSSharingService sharingServiceNamed:NSSharingServiceNameAddToSafariReadingList];
- [service performWithItems:@[ url ]];
</del><ins>+ [_data->_actionMenuController willOpenMenu:menu withEvent:event];
</ins><span class="cx"> }
</span><span class="cx">
</span><del>-- (void)_quickLookURLFromActionMenu:(id)sender
</del><ins>+- (void)didCloseMenu:(NSMenu *)menu withEvent:(NSEvent *)event
</ins><span class="cx"> {
</span><del>- 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];
</del><ins>+ [_data->_actionMenuController didCloseMenu:menu withEvent:event];
</ins><span class="cx"> }
</span><span class="cx">
</span><del>-- (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;
-}
-
</del><span class="cx"> - (void)_didPerformActionMenuHitTest:(const ActionMenuHitTestResult&)hitTestResult
</span><span class="cx"> {
</span><del>- // FIXME: This needs to use the WebKit2 callback mechanism to avoid out-of-order replies.
- _data->_actionMenuState = ActionMenuState::Ready;
- _data->_actionMenuHitTestResult = hitTestResult;
</del><ins>+ [_data->_actionMenuController didPerformActionMenuHitTest:hitTestResult];
</ins><span class="cx"> }
</span><span class="cx">
</span><del>-- (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];
-}
-
-- (void)didCloseMenu:(NSMenu *)menu withEvent:(NSEvent *)event
-{
- if (menu != self.actionMenu)
- return;
-
- _data->_actionMenuState = ActionMenuState::None;
- _data->_actionMenuHitTestResult = ActionMenuHitTestResult();
- _data->_actionMenuSharingServicePicker = nil;
-}
-
</del><span class="cx"> @end
</span><span class="cx">
</span><span class="cx"> @implementation WKView (Private)
</span></span></pre></div>
<a id="branchessafari6003branchSourceWebKit2UIProcessmacWKActionMenuControllerhfromrev175178trunkSourceWebKit2UIProcessmacWKActionMenuControllerh"></a>
<div class="copfile"><h4>Copied: branches/safari-600.3-branch/Source/WebKit2/UIProcess/mac/WKActionMenuController.h (from rev 175178, trunk/Source/WebKit2/UIProcess/mac/WKActionMenuController.h) (0 => 175315)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-600.3-branch/Source/WebKit2/UIProcess/mac/WKActionMenuController.h         (rev 0)
+++ branches/safari-600.3-branch/Source/WebKit2/UIProcess/mac/WKActionMenuController.h        2014-10-29 08:30:49 UTC (rev 175315)
</span><span class="lines">@@ -0,0 +1,49 @@
</span><ins>+/*
+ * 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
</ins></span></pre></div>
<a id="branchessafari6003branchSourceWebKit2UIProcessmacWKActionMenuControllermmfromrev175178trunkSourceWebKit2UIProcessmacWKActionMenuControllermm"></a>
<div class="copfile"><h4>Copied: branches/safari-600.3-branch/Source/WebKit2/UIProcess/mac/WKActionMenuController.mm (from rev 175178, trunk/Source/WebKit2/UIProcess/mac/WKActionMenuController.mm) (0 => 175315)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-600.3-branch/Source/WebKit2/UIProcess/mac/WKActionMenuController.mm         (rev 0)
+++ branches/safari-600.3-branch/Source/WebKit2/UIProcess/mac/WKActionMenuController.mm        2014-10-29 08:30:49 UTC (rev 175315)
</span><span class="lines">@@ -0,0 +1,401 @@
</span><ins>+/*
+ * 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)
</ins></span></pre></div>
<a id="branchessafari6003branchSourceWebKit2WebKit2xcodeprojprojectpbxproj"></a>
<div class="modfile"><h4>Modified: branches/safari-600.3-branch/Source/WebKit2/WebKit2.xcodeproj/project.pbxproj (175314 => 175315)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-600.3-branch/Source/WebKit2/WebKit2.xcodeproj/project.pbxproj        2014-10-29 08:30:39 UTC (rev 175314)
+++ branches/safari-600.3-branch/Source/WebKit2/WebKit2.xcodeproj/project.pbxproj        2014-10-29 08:30:49 UTC (rev 175315)
</span><span class="lines">@@ -562,6 +562,8 @@
</span><span class="cx">                 29CD55AB128E294F00133C85 /* WKAccessibilityWebPageObjectBase.mm in Sources */ = {isa = PBXBuildFile; fileRef = 29CD55A9128E294F00133C85 /* WKAccessibilityWebPageObjectBase.mm */; };
</span><span class="cx">                 29D55DF1161BF9F10031A2E3 /* WebPageGroupProxyMessageReceiver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 29D55DEF161BF9F10031A2E3 /* WebPageGroupProxyMessageReceiver.cpp */; };
</span><span class="cx">                 29D55DF2161BF9F10031A2E3 /* WebPageGroupProxyMessages.h in Headers */ = {isa = PBXBuildFile; fileRef = 29D55DF0161BF9F10031A2E3 /* WebPageGroupProxyMessages.h */; };
</span><ins>+                2D0730A219F9C7DA00E9D9C4 /* WKActionMenuController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 2D0730A019F9C7DA00E9D9C4 /* WKActionMenuController.mm */; };
+                2D0730A319F9C7DA00E9D9C4 /* WKActionMenuController.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D0730A119F9C7DA00E9D9C4 /* WKActionMenuController.h */; };
</ins><span class="cx">                 2D125C5E1857EA05003BA3CB /* ViewGestureController.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D125C5C1857EA05003BA3CB /* ViewGestureController.h */; };
</span><span class="cx">                 2D125C5F1857EA05003BA3CB /* ViewGestureControllerMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = 2D125C5D1857EA05003BA3CB /* ViewGestureControllerMac.mm */; };
</span><span class="cx">                 2D1B5D5D185869C8006C6596 /* ViewGestureControllerMessageReceiver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2D1B5D5B185869C8006C6596 /* ViewGestureControllerMessageReceiver.cpp */; };
</span><span class="lines">@@ -2564,6 +2566,8 @@
</span><span class="cx">                 29D55DEE161BF8780031A2E3 /* WebPageGroupProxy.messages.in */ = {isa = PBXFileReference; lastKnownFileType = text; path = WebPageGroupProxy.messages.in; sourceTree = "<group>"; };
</span><span class="cx">                 29D55DEF161BF9F10031A2E3 /* WebPageGroupProxyMessageReceiver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WebPageGroupProxyMessageReceiver.cpp; sourceTree = "<group>"; };
</span><span class="cx">                 29D55DF0161BF9F10031A2E3 /* WebPageGroupProxyMessages.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebPageGroupProxyMessages.h; sourceTree = "<group>"; };
</span><ins>+                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>"; };
</ins><span class="cx">                 2D125C5C1857EA05003BA3CB /* ViewGestureController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ViewGestureController.h; sourceTree = "<group>"; };
</span><span class="cx">                 2D125C5D1857EA05003BA3CB /* ViewGestureControllerMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ViewGestureControllerMac.mm; sourceTree = "<group>"; };
</span><span class="cx">                 2D1B5D5A18586599006C6596 /* ViewGestureController.messages.in */ = {isa = PBXFileReference; lastKnownFileType = text; path = ViewGestureController.messages.in; sourceTree = "<group>"; };
</span><span class="lines">@@ -6648,6 +6652,8 @@
</span><span class="cx">                                 51D130571382F10500351EDD /* WebProcessProxyMac.mm */,
</span><span class="cx">                                 868160CD18763D4B0021E79D /* WindowServerConnection.h */,
</span><span class="cx">                                 868160CF187645370021E79D /* WindowServerConnection.mm */,
</span><ins>+                                2D0730A019F9C7DA00E9D9C4 /* WKActionMenuController.mm */,
+                                2D0730A119F9C7DA00E9D9C4 /* WKActionMenuController.h */,
</ins><span class="cx">                                 E1AEA22D14687BDB00804569 /* WKFullKeyboardAccessWatcher.h */,
</span><span class="cx">                                 E1AEA22E14687BDB00804569 /* WKFullKeyboardAccessWatcher.mm */,
</span><span class="cx">                                 CDCA85C7132ABA4E00E961DF /* WKFullScreenWindowController.h */,
</span><span class="lines">@@ -7096,6 +7102,7 @@
</span><span class="cx">                                 E1513C67166EABB200149FCB /* ChildProcessProxy.h in Headers */,
</span><span class="cx">                                 7CA254EB182993CE00FC8A41 /* WKBrowsingContextPolicyDelegate.h in Headers */,
</span><span class="cx">                                 37C4C08718149C5B003688B9 /* WKBackForwardListItem.h in Headers */,
</span><ins>+                                2D0730A319F9C7DA00E9D9C4 /* WKActionMenuController.h in Headers */,
</ins><span class="cx">                                 1F335BC0185B84F0001A201A /* WKWebProcessPlugInLoadDelegate.h in Headers */,
</span><span class="cx">                                 1F7506B41859164C00EC0FF7 /* WKWebProcessPlugInScriptWorld.h in Headers */,
</span><span class="cx">                                 1A43E82A188F3CDC009E4D30 /* _WKProcessPoolConfiguration.h in Headers */,
</span><span class="lines">@@ -9119,6 +9126,7 @@
</span><span class="cx">                                 518D2CAD12D5153B003BB93B /* WebBackForwardListItem.cpp in Sources */,
</span><span class="cx">                                 BC72B9FA11E6476B001EB4EA /* WebBackForwardListProxy.cpp in Sources */,
</span><span class="cx">                                 BC111A5A112F4FBB00337BAB /* WebChromeClient.cpp in Sources */,
</span><ins>+                                2D0730A219F9C7DA00E9D9C4 /* WKActionMenuController.mm in Sources */,
</ins><span class="cx">                                 868160D0187645570021E79D /* WindowServerConnection.mm in Sources */,
</span><span class="cx">                                 3F87B9BD158940120090FF62 /* WebColorChooser.cpp in Sources */,
</span><span class="cx">                                 A58B6F0918FCA733008CBA53 /* WKFileUploadPanel.mm in Sources */,
</span></span></pre>
</div>
</div>
</body>
</html>