Implement action menu support for videos
authorbdakin@apple.com <bdakin@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 8 Nov 2014 19:07:50 +0000 (19:07 +0000)
committerbdakin@apple.com <bdakin@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 8 Nov 2014 19:07:50 +0000 (19:07 +0000)
https://bugs.webkit.org/show_bug.cgi?id=138534
-and corresponding-
rdar://problem/18742164

Reviewed by Tim Horton.

Source/WebCore:

Export needed symbols and added not-yet-implemented
HitTestResult::isMediaThatCanBeDownloaded() so that action menus will work as
expected once it is implemented.
* WebCore.exp.in:
* rendering/HitTestResult.cpp:
(WebCore::HitTestResult::isMediaThatCanBeDownloaded):
* rendering/HitTestResult.h:

Source/WebKit2:

New menu type and items types.
* Shared/API/c/WKActionMenuItemTypes.h:
* Shared/API/c/WKActionMenuTypes.h:

Plumb isMediaThatCanBeDownloaded() up to WebHitTestResult.
* Shared/WebHitTestResult.cpp:
(WebKit::WebHitTestResult::Data::Data):
(WebKit::WebHitTestResult::Data::encode):
(WebKit::WebHitTestResult::Data::decode):
* Shared/WebHitTestResult.h:
(WebKit::WebHitTestResult::isMediaThatCanBeDownloaded):

Re-name _canAddImageToPhotos to _canAddMediaToPhotos, which is more accurate. We
might use this method for videos some day, so now it has an accurate name.
* UIProcess/mac/WKActionMenuController.mm:

Default items and their actions.
(-[WKActionMenuController _defaultMenuItemsForVideo]):
(-[WKActionMenuController _copyVideoURL:]):
(-[WKActionMenuController _saveVideoToDownloads:]):
(-[WKActionMenuController _defaultMenuItemsForImage]):
(-[WKActionMenuController _canAddMediaToPhotos]):
(-[WKActionMenuController _addImageToPhotos:]):
(-[WKActionMenuController _createActionMenuItemForTag:]):
(-[WKActionMenuController _defaultMenuItems:]):
(-[WKActionMenuController _canAddImageToPhotos]): Deleted.

We hit test including shadow content to get the desired result for editable text
regions. But for media, we want to re-set to the shadow root.
* WebProcess/WebPage/mac/WebPageMac.mm:
(WebKit::WebPage::performActionMenuHitTestAtLocation):

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

Source/WebCore/ChangeLog
Source/WebCore/WebCore.exp.in
Source/WebCore/rendering/HitTestResult.cpp
Source/WebCore/rendering/HitTestResult.h
Source/WebKit2/ChangeLog
Source/WebKit2/Shared/API/c/WKActionMenuItemTypes.h
Source/WebKit2/Shared/API/c/WKActionMenuTypes.h
Source/WebKit2/Shared/WebHitTestResult.cpp
Source/WebKit2/Shared/WebHitTestResult.h
Source/WebKit2/UIProcess/mac/WKActionMenuController.mm
Source/WebKit2/WebProcess/WebPage/mac/WebPageMac.mm

index 9cb5ba1..a77c85c 100644 (file)
@@ -1,3 +1,20 @@
+2014-11-08  Beth Dakin  <bdakin@apple.com>
+
+        Implement action menu support for videos
+        https://bugs.webkit.org/show_bug.cgi?id=138534
+        -and corresponding-
+        rdar://problem/18742164
+
+        Reviewed by Tim Horton.
+
+        Export needed symbols and added not-yet-implemented 
+        HitTestResult::isMediaThatCanBeDownloaded() so that action menus will work as 
+        expected once it is implemented.
+        * WebCore.exp.in:
+        * rendering/HitTestResult.cpp:
+        (WebCore::HitTestResult::isMediaThatCanBeDownloaded):
+        * rendering/HitTestResult.h:
+
 2014-11-08  Chris Dumez  <cdumez@apple.com>
 
         Speed up HTMLInputElement::isEmptyValue()
index 87b4ca8..add16c3 100644 (file)
@@ -311,6 +311,7 @@ __ZN7WebCore13HTTPHeaderMap3setERKN3WTF6StringES4_
 __ZN7WebCore13HTTPHeaderMap6removeENS_14HTTPHeaderNameE
 __ZN7WebCore13HTTPHeaderMapC1Ev
 __ZN7WebCore13HTTPHeaderMapD1Ev
+__ZN7WebCore13HitTestResult22setToNonShadowAncestorEv
 __ZN7WebCore13HitTestResultC1ERKNS_11LayoutPointE
 __ZN7WebCore13HitTestResultC1ERKNS_11LayoutPointEjjjj
 __ZN7WebCore13HitTestResultC1ERKNS_15HitTestLocationE
@@ -549,7 +550,6 @@ __ZN7WebCore15GraphicsContext9translateEff
 __ZN7WebCore15GraphicsContextC1EP9CGContext
 __ZN7WebCore15GraphicsContextD1Ev
 __ZN7WebCore15GraphicsLayerCA10initializeEv
-__ZN7WebCore15GraphicsLayerCA18setBackdropFiltersERKNS_16FilterOperationsE
 __ZN7WebCore15GraphicsLayerCA10setFiltersERKNS_16FilterOperationsE
 __ZN7WebCore15GraphicsLayerCA10setOpacityEf
 __ZN7WebCore15GraphicsLayerCA11setChildrenERKN3WTF6VectorIPNS_13GraphicsLayerELm0ENS1_15CrashOnOverflowEEE
@@ -579,6 +579,7 @@ __ZN7WebCore15GraphicsLayerCA16setMasksToBoundsEb
 __ZN7WebCore15GraphicsLayerCA17setContentsOpaqueEb
 __ZN7WebCore15GraphicsLayerCA17setCustomBehaviorENS_13GraphicsLayer14CustomBehaviorE
 __ZN7WebCore15GraphicsLayerCA17suspendAnimationsEd
+__ZN7WebCore15GraphicsLayerCA18setBackdropFiltersERKNS_16FilterOperationsE
 __ZN7WebCore15GraphicsLayerCA18setBackgroundColorERKNS_5ColorE
 __ZN7WebCore15GraphicsLayerCA18setContentsToImageEPNS_5ImageE
 __ZN7WebCore15GraphicsLayerCA18setContentsVisibleEb
@@ -1690,6 +1691,7 @@ __ZNK7WebCore13HitTestResult16absoluteMediaURLEv
 __ZNK7WebCore13HitTestResult16altDisplayStringEv
 __ZNK7WebCore13HitTestResult17isContentEditableEv
 __ZNK7WebCore13HitTestResult18titleDisplayStringEv
+__ZNK7WebCore13HitTestResult19isDownloadableMediaEv
 __ZNK7WebCore13HitTestResult19mediaIsInFullscreenEv
 __ZNK7WebCore13HitTestResult19rectBasedTestResultEv
 __ZNK7WebCore13HitTestResult21innerNonSharedElementEv
@@ -1931,6 +1933,7 @@ __ZNK7WebCore3URLcvP5NSURLEv
 __ZNK7WebCore4Font5widthERKNS_7TextRunEPN3WTF7HashSetIPKNS_14SimpleFontDataENS4_7PtrHashIS8_EENS4_10HashTraitsIS8_EEEEPNS_13GlyphOverflowE
 __ZNK7WebCore4Font8drawTextEPNS_15GraphicsContextERKNS_7TextRunERKNS_10FloatPointEiiNS0_24CustomFontNotReadyActionE
 __ZNK7WebCore4FonteqERKS0_
+__ZNK7WebCore4Node10shadowHostEv
 __ZNK7WebCore4Node11textContentEb
 __ZNK7WebCore4Node13ownerDocumentEv
 __ZNK7WebCore4Node14isDescendantOfEPKS0_
index 6ba08dd..6331ffb 100644 (file)
@@ -505,6 +505,13 @@ void HitTestResult::toggleMediaMuteState() const
 #endif
 }
 
+bool HitTestResult::isDownloadableMedia() const
+{
+    // FIXME: We should actually answer instead of always returning true for media elements.
+    // https://bugs.webkit.org/show_bug.cgi?id=138530
+    return mediaElement() ? true : false;
+}
+
 URL HitTestResult::absoluteLinkURL() const
 {
     if (m_innerURLElement)
index 72104ab..ab4ea10 100644 (file)
@@ -124,6 +124,7 @@ public:
     WEBCORE_EXPORT bool mediaIsVideo() const;
     bool mediaMuted() const;
     void toggleMediaMuteState() const;
+    bool isDownloadableMedia() const;
 
     // Returns true if it is rect-based hit test and needs to continue until the rect is fully
     // enclosed by the boundaries of a node.
index 3cf0971..a149de7 100644 (file)
@@ -1,3 +1,44 @@
+2014-11-08  Beth Dakin  <bdakin@apple.com>
+
+        Implement action menu support for videos
+        https://bugs.webkit.org/show_bug.cgi?id=138534
+        -and corresponding-
+        rdar://problem/18742164
+
+        Reviewed by Tim Horton.
+
+        New menu type and items types.
+        * Shared/API/c/WKActionMenuItemTypes.h:
+        * Shared/API/c/WKActionMenuTypes.h:
+
+        Plumb isMediaThatCanBeDownloaded() up to WebHitTestResult.
+        * Shared/WebHitTestResult.cpp:
+        (WebKit::WebHitTestResult::Data::Data):
+        (WebKit::WebHitTestResult::Data::encode):
+        (WebKit::WebHitTestResult::Data::decode):
+        * Shared/WebHitTestResult.h:
+        (WebKit::WebHitTestResult::isMediaThatCanBeDownloaded):
+
+        Re-name _canAddImageToPhotos to _canAddMediaToPhotos, which is more accurate. We 
+        might use this method for videos some day, so now it has an accurate name.
+        * UIProcess/mac/WKActionMenuController.mm:
+
+        Default items and their actions.
+        (-[WKActionMenuController _defaultMenuItemsForVideo]):
+        (-[WKActionMenuController _copyVideoURL:]):
+        (-[WKActionMenuController _saveVideoToDownloads:]):
+        (-[WKActionMenuController _defaultMenuItemsForImage]):
+        (-[WKActionMenuController _canAddMediaToPhotos]):
+        (-[WKActionMenuController _addImageToPhotos:]):
+        (-[WKActionMenuController _createActionMenuItemForTag:]):
+        (-[WKActionMenuController _defaultMenuItems:]):
+        (-[WKActionMenuController _canAddImageToPhotos]): Deleted.
+
+        We hit test including shadow content to get the desired result for editable text 
+        regions. But for media, we want to re-set to the shadow root.
+        * WebProcess/WebPage/mac/WebPageMac.mm:
+        (WebKit::WebPage::performActionMenuHitTestAtLocation):
+
 2014-11-08  Carlos Garcia Campos  <cgarcia@igalia.com>
 
         [GTK] Allow to create a view with a related page in WTR
index d9fde37..c28df52 100644 (file)
@@ -44,7 +44,10 @@ enum {
     kWKContextActionItemTagCopyText,
     kWKContextActionItemTagLookupText,
     kWKContextActionItemTagPaste,
-    kWKContextActionItemTagTextSuggestions
+    kWKContextActionItemTagTextSuggestions,
+    kWKContextActionItemTagCopyVideoURL,
+    kWKContextActionItemTagSaveVideoToDownloads,
+    kWKContextActionItemTagShareVideo
 };
 
 #ifdef __cplusplus
index 130f8ff..efdaad1 100644 (file)
@@ -40,7 +40,8 @@ enum {
     kWKActionMenuReadOnlyText,
     kWKActionMenuEditableText,
     kWKActionMenuEditableTextWithSuggestions,
-    kWKActionMenuWhitespaceInEditableArea
+    kWKActionMenuWhitespaceInEditableArea,
+    kWKActionMenuVideo
 };
 typedef uint32_t _WKActionMenuType;
 
index 49ae714..447d161 100644 (file)
@@ -54,6 +54,7 @@ WebHitTestResult::Data::Data(const HitTestResult& hitTestResult)
     , isScrollbar(hitTestResult.scrollbar())
     , isSelected(hitTestResult.isSelected())
     , isTextNode(hitTestResult.innerNode() && hitTestResult.innerNode()->isTextNode())
+    , isDownloadableMedia(hitTestResult.isDownloadableMedia())
 {
 }
 
@@ -74,6 +75,7 @@ void WebHitTestResult::Data::encode(IPC::ArgumentEncoder& encoder) const
     encoder << isScrollbar;
     encoder << isSelected;
     encoder << isTextNode;
+    encoder << isDownloadableMedia;
 }
 
 bool WebHitTestResult::Data::decode(IPC::ArgumentDecoder& decoder, WebHitTestResult::Data& hitTestResultData)
@@ -88,7 +90,8 @@ bool WebHitTestResult::Data::decode(IPC::ArgumentDecoder& decoder, WebHitTestRes
         || !decoder.decode(hitTestResultData.elementBoundingBox)
         || !decoder.decode(hitTestResultData.isScrollbar)
         || !decoder.decode(hitTestResultData.isSelected)
-        || !decoder.decode(hitTestResultData.isTextNode))
+        || !decoder.decode(hitTestResultData.isTextNode)
+        || !decoder.decode(hitTestResultData.isDownloadableMedia))
         return false;
 
     return true;
index 39a05eb..817dbfb 100644 (file)
@@ -54,6 +54,7 @@ public:
         bool isScrollbar;
         bool isSelected;
         bool isTextNode;
+        bool isDownloadableMedia;
 
         Data();
         explicit Data(const WebCore::HitTestResult&);
@@ -85,6 +86,8 @@ public:
 
     bool isTextNode() const { return m_data.isTextNode; }
 
+    bool isDownloadableMedia() const { return m_data.isDownloadableMedia; }
+
 private:
     explicit WebHitTestResult(const WebHitTestResult::Data& hitTestResultData)
         : m_data(hitTestResultData)
index 567f6d4..7e5a94f 100644 (file)
@@ -63,7 +63,7 @@ using namespace WebKit;
 
 @interface WKActionMenuController () <NSSharingServiceDelegate, NSSharingServicePickerDelegate, NSPopoverDelegate>
 - (void)_updateActionMenuItemsForStage:(MenuUpdateStage)stage;
-- (BOOL)_canAddImageToPhotos;
+- (BOOL)_canAddMediaToPhotos;
 - (void)_showTextIndicator;
 - (void)_hideTextIndicator;
 @end
@@ -391,13 +391,51 @@ static bool targetSizeFitsInAvailableSpace(NSSize targetSize, NSSize availableSp
     _previewPopover = nil;
 }
 
+#pragma mark Video actions
+
+- (NSArray *)_defaultMenuItemsForVideo
+{
+    RetainPtr<NSMenuItem> copyVideoURLItem = [self _createActionMenuItemForTag:kWKContextActionItemTagCopyVideoURL];
+
+    RetainPtr<NSMenuItem> saveToDownloadsItem;
+    RefPtr<WebHitTestResult> hitTestResult = WebHitTestResult::create(_hitTestResult.hitTestResult);
+    if (hitTestResult->isDownloadableMedia())
+        saveToDownloadsItem = [self _createActionMenuItemForTag:kWKContextActionItemTagSaveVideoToDownloads];
+    else
+        saveToDownloadsItem = [NSMenuItem separatorItem];
+
+    RetainPtr<NSMenuItem> shareItem = [self _createActionMenuItemForTag:kWKContextActionItemTagShareVideo];
+    String videoURL = hitTestResult->absoluteMediaURL();
+    if (!videoURL.isEmpty()) {
+        _sharingServicePicker = adoptNS([[NSSharingServicePicker alloc] initWithItems:@[ videoURL ]]);
+        [_sharingServicePicker setDelegate:self];
+        [shareItem setSubmenu:[_sharingServicePicker menu]];
+    }
+
+    return @[ copyVideoURLItem.get(), [NSMenuItem separatorItem], saveToDownloadsItem.get(), shareItem.get() ];
+}
+
+- (void)_copyVideoURL:(id)sender
+{
+    RefPtr<WebHitTestResult> hitTestResult = WebHitTestResult::create(_hitTestResult.hitTestResult);
+
+    [[NSPasteboard generalPasteboard] clearContents];
+    [[NSPasteboard generalPasteboard] writeObjects:@[ hitTestResult->absoluteMediaURL() ]];
+}
+
+- (void)_saveVideoToDownloads:(id)sender
+{
+    RefPtr<WebHitTestResult> hitTestResult = WebHitTestResult::create(_hitTestResult.hitTestResult);
+    _page->process().context().download(_page, hitTestResult->absoluteMediaURL());
+}
+
 #pragma mark Image actions
 
 - (NSArray *)_defaultMenuItemsForImage
 {
     RetainPtr<NSMenuItem> copyImageItem = [self _createActionMenuItemForTag:kWKContextActionItemTagCopyImage];
     RetainPtr<NSMenuItem> addToPhotosItem;
-    if ([self _canAddImageToPhotos])
+    if ([self _canAddMediaToPhotos])
         addToPhotosItem = [self _createActionMenuItemForTag:kWKContextActionItemTagAddImageToPhotos];
     else
         addToPhotosItem = [NSMenuItem separatorItem];
@@ -478,14 +516,14 @@ static NSString *pathToPhotoOnDisk(NSString *suggestedFilename)
     return path;
 }
 
-- (BOOL)_canAddImageToPhotos
+- (BOOL)_canAddMediaToPhotos
 {
     return [getIKSlideshowClass() canExportToApplication:@"com.apple.Photos"];
 }
 
 - (void)_addImageToPhotos:(id)sender
 {
-    if (![self _canAddImageToPhotos])
+    if (![self _canAddMediaToPhotos])
         return;
 
     RefPtr<ShareableBitmap> bitmap = _hitTestResult.image;
@@ -753,6 +791,23 @@ static NSString *pathToPhotoOnDisk(NSString *suggestedFilename)
         image = [NSImage imageNamed:@"NSActionMenuSpelling"];
         break;
 
+    case kWKContextActionItemTagCopyVideoURL:
+        selector = @selector(_copyVideoURL:);
+        title = @"Copy";
+        image = [NSImage imageNamed:@"NSActionMenuCopy"];
+        break;
+
+    case kWKContextActionItemTagSaveVideoToDownloads:
+        selector = @selector(_saveVideoToDownloads:);
+        title = @"Save to Downloads";
+        image = [NSImage imageNamed:@"NSActionMenuSaveToDownloads"];
+        break;
+
+    case kWKContextActionItemTagShareVideo:
+        title = @"Share";
+        image = [NSImage imageNamed:@"NSActionMenuShare"];
+        break;
+
     default:
         ASSERT_NOT_REACHED();
         return nil;
@@ -802,6 +857,11 @@ static NSImage *webKitBundleImageNamed(NSString *name)
         return [self _defaultMenuItemsForLink];
     }
 
+    if (!hitTestResult->absoluteMediaURL().isEmpty()) {
+        _type = kWKActionMenuVideo;
+        return [self _defaultMenuItemsForVideo];
+    }
+
     if (!hitTestResult->absoluteImageURL().isEmpty() && _hitTestResult.image) {
         _type = kWKActionMenuImage;
         return [self _defaultMenuItemsForImage];
index 637033d..4c1c5ab 100644 (file)
@@ -1181,6 +1181,15 @@ void WebPage::performActionMenuHitTestAtLocation(WebCore::FloatPoint locationInV
     HitTestResult hitTestResult(locationInContentCoordinates);
     mainRenderView.hitTest(request, hitTestResult);
 
+    // We hit test including shadow content to get the desired result for editable text regions.
+    // But for media, we want to re-set to the shadow root.
+    if (Node* node = hitTestResult.innerNode()) {
+        if (Element* shadowHost = node->shadowHost()) {
+            if (shadowHost->isMediaElement())
+                hitTestResult.setToNonShadowAncestor();
+        }
+    }
+
     ActionMenuHitTestResult actionMenuResult;
     actionMenuResult.hitTestLocationInViewCooordinates = locationInViewCooordinates;
     actionMenuResult.hitTestResult = WebHitTestResult::Data(hitTestResult);