Title: [274148] trunk
Revision
274148
Author
[email protected]
Date
2021-03-09 08:21:29 -0800 (Tue, 09 Mar 2021)

Log Message

[macOS] Add a way to trigger webpage translation via the context menu
https://bugs.webkit.org/show_bug.cgi?id=222953
<rdar://problem/73901967>

Reviewed by Devin Rousso.

Source/WebCore:

Introduce a WebCore enum for the new context menu item. Additionally, update `Localizable.strings` by re-running
`Tools/Scripts/update-webkit-localizable-strings`.

* en.lproj/Localizable.strings:
* page/ContextMenuContext.h:
(WebCore::ContextMenuContext::setSelectionBounds):
(WebCore::ContextMenuContext::selectionBounds const):

Add a new member to represent the text selection bounds in root view coordinates.

* page/ContextMenuController.cpp:
(WebCore::ContextMenuController::contextMenuItemSelected):

Compute and set text selection bounds.

(WebCore::ContextMenuController::populate):
(WebCore::ContextMenuController::checkOrEnableIfNeeded const):
* platform/ContextMenuItem.cpp:
(WebCore::isValidContextMenuAction):
* platform/ContextMenuItem.h:

Add the new enum value.

* platform/LocalizedStrings.cpp:
(WebCore::truncatedStringForMenuItem):

Renamed this from `truncatedStringForLookupMenuItem`, since it's now used for this new translate menu item.

(WebCore::contextMenuItemTagLookUpInDictionary):
(WebCore::contextMenuItemTagTranslate):

Add a helper function to return the title for the new translate menu item, modeled after "Look Up".

(WebCore::truncatedStringForLookupMenuItem): Deleted.
* platform/LocalizedStrings.h:

Source/WebKit:

Add support for the new context menu item in WebKit2. See below for more details.

* Shared/API/c/WKContextMenuItemTypes.h:
* Shared/API/c/WKSharedAPICast.h:
(WebKit::toAPI):
(WebKit::toImpl):

Add a C API value for the new WebCore enum.

* Shared/ContextMenuContextData.cpp:
(WebKit::ContextMenuContextData::ContextMenuContextData):
(WebKit::ContextMenuContextData::encode const):
(WebKit::ContextMenuContextData::decode):
* Shared/ContextMenuContextData.h:
(WebKit::ContextMenuContextData::selectionBounds const):

Add a rect, `selectionBounds`, to `ContextMenuContextData` that represents the rect of the current text
selection in root view coordinates.

* UIProcess/API/Cocoa/WKMenuItemIdentifiers.mm:
* UIProcess/API/Cocoa/WKMenuItemIdentifiersPrivate.h:
* UIProcess/Cocoa/WebPageProxyCocoa.mm:
(WebKit::WebPageProxy::canHandleContextMenuTranslation const):
* UIProcess/Cocoa/WebViewImpl.h:
* UIProcess/Cocoa/WebViewImpl.mm:
(WebKit::WebViewImpl::canHandleContextMenuTranslation const):

Consult the class method to return whether or not the menu item should be present. If not, then we filter this
item out from the list of context menu items in `WebContextMenuProxyMac` below.

(WebKit::WebViewImpl::handleContextMenuTranslation):

Handle the translation action by using `NSPopover` to present an `LTUITranslationViewController`.

* UIProcess/PageClient.h:
* UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::contextMenuItemSelected):
* UIProcess/WebPageProxy.h:
* UIProcess/mac/PageClientImplMac.h:
* UIProcess/mac/PageClientImplMac.mm:
(WebKit::PageClientImpl::canHandleContextMenuTranslation const):
(WebKit::PageClientImpl::handleContextMenuTranslation):
* UIProcess/mac/WebContextMenuProxyMac.mm:
(WebKit::WebContextMenuProxyMac::getContextMenuFromItems):

Remove the translate menu item if we're already presented in the context of a popover, or if the system does not
support the feature (see `WebViewImpl::canHandleContextMenuTranslation`).

(WebKit::menuItemIdentifier):

Source/WebKitLegacy/mac:

Add (no-op) handling for the new enum value.

* WebView/WebHTMLView.mm:
(toTag):

Tools:

Adjust an API test. This new enum value is now the new last valid item value.

* TestWebKitAPI/Tests/WebCore/ContextMenuAction.cpp:
(TestWebKitAPI::TEST):

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (274147 => 274148)


--- trunk/Source/WebCore/ChangeLog	2021-03-09 15:51:48 UTC (rev 274147)
+++ trunk/Source/WebCore/ChangeLog	2021-03-09 16:21:29 UTC (rev 274148)
@@ -1,3 +1,47 @@
+2021-03-09  Wenson Hsieh  <[email protected]>
+
+        [macOS] Add a way to trigger webpage translation via the context menu
+        https://bugs.webkit.org/show_bug.cgi?id=222953
+        <rdar://problem/73901967>
+
+        Reviewed by Devin Rousso.
+
+        Introduce a WebCore enum for the new context menu item. Additionally, update `Localizable.strings` by re-running
+        `Tools/Scripts/update-webkit-localizable-strings`.
+
+        * en.lproj/Localizable.strings:
+        * page/ContextMenuContext.h:
+        (WebCore::ContextMenuContext::setSelectionBounds):
+        (WebCore::ContextMenuContext::selectionBounds const):
+
+        Add a new member to represent the text selection bounds in root view coordinates.
+
+        * page/ContextMenuController.cpp:
+        (WebCore::ContextMenuController::contextMenuItemSelected):
+
+        Compute and set text selection bounds.
+
+        (WebCore::ContextMenuController::populate):
+        (WebCore::ContextMenuController::checkOrEnableIfNeeded const):
+        * platform/ContextMenuItem.cpp:
+        (WebCore::isValidContextMenuAction):
+        * platform/ContextMenuItem.h:
+
+        Add the new enum value.
+
+        * platform/LocalizedStrings.cpp:
+        (WebCore::truncatedStringForMenuItem):
+
+        Renamed this from `truncatedStringForLookupMenuItem`, since it's now used for this new translate menu item.
+
+        (WebCore::contextMenuItemTagLookUpInDictionary):
+        (WebCore::contextMenuItemTagTranslate):
+
+        Add a helper function to return the title for the new translate menu item, modeled after "Look Up".
+
+        (WebCore::truncatedStringForLookupMenuItem): Deleted.
+        * platform/LocalizedStrings.h:
+
 2021-03-09  Antoine Quint  <[email protected]>
 
         Correctly blend column-width and column-count CSS properties

Modified: trunk/Source/WebCore/en.lproj/Localizable.strings (274147 => 274148)


--- trunk/Source/WebCore/en.lproj/Localizable.strings	2021-03-09 15:51:48 UTC (rev 274147)
+++ trunk/Source/WebCore/en.lproj/Localizable.strings	2021-03-09 16:21:29 UTC (rev 274148)
@@ -124,12 +124,21 @@
 /* Button title in Device Orientation Permission API prompt */
 "Allow (device motion and orientation access)" = "Allow";
 
+/* Allow button title in speech recognition prompt */
+"Allow (speechrecognition)" = "Allow";
+
+/* Allow button title in user media prompt */
+"Allow (usermedia)" = "Allow";
+
 /* Message for requesting cross-site cookie and website data access. */
+"Allow “%@” and “%@” to use cookies and website data while browsing “%@”?" = "Allow “%@” and “%@” to use cookies and website data while browsing “%@”?";
+
+/* Message for spechrecognition prompt */
+"Allow “%@” to capture your audio and use it for speech recognition?" = "Allow “%@” to capture your audio and use it for speech recognition?";
+
+/* Message for requesting cross-site cookie and website data access. */
 "Allow “%@” to use cookies and website data while browsing “%@”?" = "Allow “%@” to use cookies and website data while browsing “%@”?";
 
-/* Message for requesting cross-site cookie and website data access for multiple third party domains. */
-"Allow “%@” and “%@” to use cookies and website data while browsing “%@”?" = "Allow “%@” and “%@” to use cookies and website data while browsing “%@”?";
-
 /* Message for user media prompt */
 "Allow “%@” to use your camera and microphone?" = "Allow “%@” to use your camera and microphone?";
 
@@ -139,21 +148,6 @@
 /* Message for user microphone access prompt */
 "Allow “%@” to use your microphone?" = "Allow “%@” to use your microphone?";
 
-/* Allow button title in user media prompt */
-"Allow (usermedia)" = "Allow";
-
-/* Disallow button title in user media prompt */
-"Don’t Allow (usermedia)" = "Don’t Allow";
-
-/* Message for speech recognition prompt */
-"Allow “%@” to capture your audio and use it for speech recognition?" = "Allow “%@” to capture your audio and use it for speech recognition?";
-
-/* Allow button title in speech recognition prompt */
-"Allow (speechrecognition)" = "Allow";
-
-/* Disallow button title in speech recognition prompt */
-"Don’t Allow (speechrecognition)" = "Don’t Allow";
-
 /* WKErrorUnknown description */
 "An unknown error occurred" = "An unknown error occurred";
 
@@ -163,6 +157,9 @@
 /* Malware confirmation dialog title */
 "Are you sure you wish to go to this site?" = "Are you sure you wish to go to this site?";
 
+/* WKErrorNavigationAppBoundDomain description */
+"Attempted to navigate away from an app-bound domain or navigate after using restricted APIs" = "Attempted to navigate away from an app-bound domain or navigate after using restricted APIs";
+
 /* WKErrorAttributedStringContentFailedToLoad description */
 "Attributed string content failed to load" = "Attributed string content failed to load";
 
@@ -320,11 +317,11 @@
 "Dictation (Undo action name)" = "Dictation";
 
 /* Message for requesting cross-site cookie and website data access. */
+"Do you want to allow “%@” and “%@” to use cookies and website data while browsing “%@”?" = "Do you want to allow “%@” and “%@” to use cookies and website data while browsing “%@”?";
+
+/* Message for requesting cross-site cookie and website data access. */
 "Do you want to allow “%@” to use cookies and website data while browsing “%@”?" = "Do you want to allow “%@” to use cookies and website data while browsing “%@”?";
 
-/* Message for requesting cross-site cookie and website data access for multiple third party domains. */
-"Do you want to allow “%@” and “%@” to use cookies and website data while browsing “%@”?" = "Do you want to allow “%@” and “%@” to use cookies and website data while browsing “%@”?";
-
 /* Button title in Storage Access API prompt */
 "Don't Allow (cross-site cookie and website data access)" = "Don't Allow";
 
@@ -334,6 +331,12 @@
 /* Title of the Done button for zoomed form controls. */
 "Done" = "Done";
 
+/* Disallow button title in speech recognition prompt */
+"Don’t Allow (speechrecognition)" = "Don’t Allow";
+
+/* Disallow button title in user media prompt */
+"Don’t Allow (usermedia)" = "Don’t Allow";
+
 /* Download Audio To Disk context menu item */
 "Download Audio" = "Download Audio";
 
@@ -472,6 +475,12 @@
 /* WKErrorJavaScriptResultTypeIsUnsupported description */
 "_javascript_ execution returned a result of an unsupported type" = "_javascript_ execution returned a result of an unsupported type";
 
+/* WKErrorJavaScriptAppBoundDomain description */
+"_javascript_ execution targeted a frame that is not in an app-bound domain" = "_javascript_ execution targeted a frame that is not in an app-bound domain";
+
+/* WKErrorJavaScriptInvalidFrameTarget description */
+"_javascript_ execution targeted an invalid frame" = "_javascript_ execution targeted an invalid frame";
+
 /* Undo action name */
 "Justify (Undo action name)" = "Justify";
 
@@ -571,6 +580,9 @@
 /* Option in segmented control for inserting a numbered list in text editing */
 "Numbered list" = "Numbered list";
 
+/* Title of the OK button in date/time form controls. */
+"OK (OK button title in date/time picker)" = "OK";
+
 /* Title of the OK button for the number pad in zoomed form controls. */
 "OK (OK button title in extra zoomed number pad)" = "OK";
 
@@ -577,9 +589,6 @@
 /* OK button label in document password failure alert */
 "OK (document password failure alert)" = "OK";
 
-/* Title of the OK button in date/time form controls. */
-"OK (OK button title in date/time picker)" = "OK";
-
 /* Menu item label for the track that represents disabling closed captions */
 "Off" = "Off";
 
@@ -926,10 +935,10 @@
 "This website may try to trick you into installing software that harms your browsing experience, like changing your settings without your permission or showing you unwanted ads. Once installed, it may be difficult to remove." = "This website may try to trick you into installing software that harms your browsing experience, like changing your settings without your permission or showing you unwanted ads. Once installed, it may be difficult to remove.";
 
 /* Informative text for requesting cross-site cookie and website data access. */
-"This will allow “%@” to track your activity." = "This will allow “%@” to track your activity.";
+"This will allow “%@” and “%@” to track your activity." = "This will allow “%@” and “%@” to track your activity.";
 
 /* Informative text for requesting cross-site cookie and website data access. */
-"This will allow “%@” and “%@” to track your activity." = "This will allow “%@” and “%@” to track your activity.";
+"This will allow “%@” to track your activity." = "This will allow “%@” to track your activity.";
 
 /* Undo action name */
 "Tighten Kerning (Undo action name)" = "Tighten Kerning";
@@ -955,6 +964,9 @@
 /* Transformations context sub-menu item */
 "Transformations" = "Transformations";
 
+/* Translate context menu item with selected word */
+"Translate “%@”" = "Translate “%@”";
+
 /* Undo action name */
 "Turn Off Kerning (Undo action name)" = "Turn Off Kerning";
 

Modified: trunk/Source/WebCore/page/ContextMenuContext.h (274147 => 274148)


--- trunk/Source/WebCore/page/ContextMenuContext.h	2021-03-09 15:51:48 UTC (rev 274147)
+++ trunk/Source/WebCore/page/ContextMenuContext.h	2021-03-09 16:21:29 UTC (rev 274148)
@@ -43,6 +43,9 @@
     void setSelectedText(const String& selectedText) { m_selectedText = selectedText; }
     const String& selectedText() const { return m_selectedText; }
 
+    void setSelectionBounds(const IntRect& bounds) { m_selectionBounds = bounds; }
+    const IntRect& selectionBounds() const { return m_selectionBounds; }
+
 #if ENABLE(SERVICE_CONTROLS)
     void setControlledImage(Image* controlledImage) { m_controlledImage = controlledImage; }
     Image* controlledImage() const { return m_controlledImage.get(); }
@@ -51,6 +54,7 @@
 private:
     HitTestResult m_hitTestResult;
     String m_selectedText;
+    IntRect m_selectionBounds;
 
 #if ENABLE(SERVICE_CONTROLS)
     RefPtr<Image> m_controlledImage;

Modified: trunk/Source/WebCore/page/ContextMenuController.cpp (274147 => 274148)


--- trunk/Source/WebCore/page/ContextMenuController.cpp	2021-03-09 15:51:48 UTC (rev 274147)
+++ trunk/Source/WebCore/page/ContextMenuController.cpp	2021-03-09 16:21:29 UTC (rev 274148)
@@ -518,6 +518,7 @@
         frame->editor().applyDictationAlternative(title);
         break;
     case ContextMenuItemTagRevealImage:
+    case ContextMenuItemTagTranslate:
         // This should be handled at the client layer.
         ASSERT_NOT_REACHED();
         break;
@@ -831,7 +832,7 @@
     if (!m_context.hitTestResult().isContentEditable() && is<HTMLFormControlElement>(*node))
         return;
 #endif
-    Frame* frame = node->document().frame();
+    auto frame = makeRefPtr(node->document().frame());
     if (!frame)
         return;
 
@@ -842,9 +843,17 @@
 #endif
 
     if (!m_context.hitTestResult().isContentEditable()) {
-        String selectedString = m_context.hitTestResult().selectedText();
+        auto selectedString = m_context.hitTestResult().selectedText();
         m_context.setSelectedText(selectedString);
 
+        if (!selectedString.isEmpty()) {
+            if (auto view = makeRefPtr(frame->view())) {
+                auto selectionBoundsInContentCoordinates = enclosingIntRect(frame->selection().selectionBounds());
+                if (!selectionBoundsInContentCoordinates.isEmpty())
+                    m_context.setSelectionBounds(view->contentsToRootView(selectionBoundsInContentCoordinates));
+            }
+        }
+
         FrameLoader& loader = frame->loader();
         URL linkURL = m_context.hitTestResult().absoluteLinkURL();
         if (!linkURL.isEmpty()) {
@@ -908,6 +917,10 @@
 
                     appendItem(LookUpInDictionaryItem, m_contextMenu.get());
 #endif
+#if HAVE(TRANSLATION_UI_SERVICES)
+                    ContextMenuItem TranslateItem(ActionType, ContextMenuItemTagTranslate, contextMenuItemTagTranslate(selectedString));
+                    appendItem(TranslateItem, m_contextMenu.get());
+#endif
 
 #if !PLATFORM(GTK)
                     appendItem(SearchWebItem, m_contextMenu.get());
@@ -1463,6 +1476,7 @@
             shouldCheck = shouldEnable &&  m_context.hitTestResult().mediaMuted();
             break;
         case ContextMenuItemTagRevealImage:
+        case ContextMenuItemTagTranslate:
             break;
     }
 

Modified: trunk/Source/WebCore/platform/ContextMenuItem.cpp (274147 => 274148)


--- trunk/Source/WebCore/platform/ContextMenuItem.cpp	2021-03-09 15:51:48 UTC (rev 274147)
+++ trunk/Source/WebCore/platform/ContextMenuItem.cpp	2021-03-09 16:21:29 UTC (rev 274148)
@@ -247,6 +247,7 @@
     case ContextMenuAction::ContextMenuItemTagShareMenu:
     case ContextMenuAction::ContextMenuItemTagToggleVideoEnhancedFullscreen:
     case ContextMenuAction::ContextMenuItemTagRevealImage:
+    case ContextMenuAction::ContextMenuItemTagTranslate:
     case ContextMenuAction::ContextMenuItemBaseCustomTag:
     case ContextMenuAction::ContextMenuItemLastCustomTag:
     case ContextMenuAction::ContextMenuItemBaseApplicationTag:

Modified: trunk/Source/WebCore/platform/ContextMenuItem.h (274147 => 274148)


--- trunk/Source/WebCore/platform/ContextMenuItem.h	2021-03-09 15:51:48 UTC (rev 274147)
+++ trunk/Source/WebCore/platform/ContextMenuItem.h	2021-03-09 16:21:29 UTC (rev 274148)
@@ -150,6 +150,7 @@
     ContextMenuItemTagAddHighlightToNewGroup,
 #endif
     ContextMenuItemTagRevealImage,
+    ContextMenuItemTagTranslate,
     ContextMenuItemBaseCustomTag = 5000,
     ContextMenuItemLastCustomTag = 5999,
     ContextMenuItemBaseApplicationTag = 10000

Modified: trunk/Source/WebCore/platform/LocalizedStrings.cpp (274147 => 274148)


--- trunk/Source/WebCore/platform/LocalizedStrings.cpp	2021-03-09 15:51:48 UTC (rev 274147)
+++ trunk/Source/WebCore/platform/LocalizedStrings.cpp	2021-03-09 16:21:29 UTC (rev 274148)
@@ -80,7 +80,7 @@
 
 #if ENABLE(CONTEXT_MENUS)
 
-static String truncatedStringForLookupMenuItem(const String& original)
+static String truncatedStringForMenuItem(const String& original)
 {
     // Truncate the string if it's too long. This number is roughly the same as the one used by AppKit.
     unsigned maxNumberOfGraphemeClustersInLookupMenuItem = 24;
@@ -232,15 +232,25 @@
 String contextMenuItemTagLookUpInDictionary(const String& selectedString)
 {
 #if USE(CF)
-    auto selectedCFString = truncatedStringForLookupMenuItem(selectedString).createCFString();
+    auto selectedCFString = truncatedStringForMenuItem(selectedString).createCFString();
     return formatLocalizedString(WEB_UI_CFSTRING("Look Up “%@”", "Look Up context menu item with selected word"), selectedCFString.get());
 #elif USE(GLIB)
-    return formatLocalizedString(WEB_UI_STRING("Look Up “%s”", "Look Up context menu item with selected word"), truncatedStringForLookupMenuItem(selectedString).utf8().data());
+    return formatLocalizedString(WEB_UI_STRING("Look Up “%s”", "Look Up context menu item with selected word"), truncatedStringForMenuItem(selectedString).utf8().data());
 #else
-    return WEB_UI_STRING("Look Up “<selection>”", "Look Up context menu item with selected word").replace("<selection>", truncatedStringForLookupMenuItem(selectedString));
+    return WEB_UI_STRING("Look Up “<selection>”", "Look Up context menu item with selected word").replace("<selection>", truncatedStringForMenuItem(selectedString));
 #endif
 }
 
+#if HAVE(TRANSLATION_UI_SERVICES)
+
+String contextMenuItemTagTranslate(const String& selectedString)
+{
+    auto selectedCFString = truncatedStringForMenuItem(selectedString).createCFString();
+    return formatLocalizedString(WEB_UI_CFSTRING("Translate “%@”", "Translate context menu item with selected word"), selectedCFString.get());
+}
+
+#endif
+
 String contextMenuItemTagOpenLink()
 {
     return WEB_UI_STRING_WITH_MNEMONIC("Open Link", "_Open Link", "Open Link context menu item");

Modified: trunk/Source/WebCore/platform/LocalizedStrings.h (274147 => 274148)


--- trunk/Source/WebCore/platform/LocalizedStrings.h	2021-03-09 15:51:48 UTC (rev 274147)
+++ trunk/Source/WebCore/platform/LocalizedStrings.h	2021-03-09 16:21:29 UTC (rev 274148)
@@ -354,6 +354,10 @@
     WEBCORE_EXPORT String contextMenuItemTagRevealImage();
 #endif
 
+#if HAVE(TRANSLATION_UI_SERVICES)
+    String contextMenuItemTagTranslate(const String& selectedString);
+#endif
+
 #if USE(GLIB) && defined(GETTEXT_PACKAGE)
 #define WEB_UI_STRING(string, description) WebCore::localizedString(_(string))
 #define WEB_UI_STRING_KEY(string, key, description) WebCore::localizedString(C_(key, string))

Modified: trunk/Source/WebKit/ChangeLog (274147 => 274148)


--- trunk/Source/WebKit/ChangeLog	2021-03-09 15:51:48 UTC (rev 274147)
+++ trunk/Source/WebKit/ChangeLog	2021-03-09 16:21:29 UTC (rev 274148)
@@ -1,3 +1,61 @@
+2021-03-09  Wenson Hsieh  <[email protected]>
+
+        [macOS] Add a way to trigger webpage translation via the context menu
+        https://bugs.webkit.org/show_bug.cgi?id=222953
+        <rdar://problem/73901967>
+
+        Reviewed by Devin Rousso.
+
+        Add support for the new context menu item in WebKit2. See below for more details.
+
+        * Shared/API/c/WKContextMenuItemTypes.h:
+        * Shared/API/c/WKSharedAPICast.h:
+        (WebKit::toAPI):
+        (WebKit::toImpl):
+
+        Add a C API value for the new WebCore enum.
+
+        * Shared/ContextMenuContextData.cpp:
+        (WebKit::ContextMenuContextData::ContextMenuContextData):
+        (WebKit::ContextMenuContextData::encode const):
+        (WebKit::ContextMenuContextData::decode):
+        * Shared/ContextMenuContextData.h:
+        (WebKit::ContextMenuContextData::selectionBounds const):
+
+        Add a rect, `selectionBounds`, to `ContextMenuContextData` that represents the rect of the current text
+        selection in root view coordinates.
+
+        * UIProcess/API/Cocoa/WKMenuItemIdentifiers.mm:
+        * UIProcess/API/Cocoa/WKMenuItemIdentifiersPrivate.h:
+        * UIProcess/Cocoa/WebPageProxyCocoa.mm:
+        (WebKit::WebPageProxy::canHandleContextMenuTranslation const):
+        * UIProcess/Cocoa/WebViewImpl.h:
+        * UIProcess/Cocoa/WebViewImpl.mm:
+        (WebKit::WebViewImpl::canHandleContextMenuTranslation const):
+
+        Consult the class method to return whether or not the menu item should be present. If not, then we filter this
+        item out from the list of context menu items in `WebContextMenuProxyMac` below.
+
+        (WebKit::WebViewImpl::handleContextMenuTranslation):
+
+        Handle the translation action by using `NSPopover` to present an `LTUITranslationViewController`.
+
+        * UIProcess/PageClient.h:
+        * UIProcess/WebPageProxy.cpp:
+        (WebKit::WebPageProxy::contextMenuItemSelected):
+        * UIProcess/WebPageProxy.h:
+        * UIProcess/mac/PageClientImplMac.h:
+        * UIProcess/mac/PageClientImplMac.mm:
+        (WebKit::PageClientImpl::canHandleContextMenuTranslation const):
+        (WebKit::PageClientImpl::handleContextMenuTranslation):
+        * UIProcess/mac/WebContextMenuProxyMac.mm:
+        (WebKit::WebContextMenuProxyMac::getContextMenuFromItems):
+
+        Remove the translate menu item if we're already presented in the context of a popover, or if the system does not
+        support the feature (see `WebViewImpl::canHandleContextMenuTranslation`).
+
+        (WebKit::menuItemIdentifier):
+
 2021-03-08  Youenn Fablet  <[email protected]>
 
         Allow access to more cmio services from Web/GPU processes

Modified: trunk/Source/WebKit/Shared/API/c/WKContextMenuItemTypes.h (274147 => 274148)


--- trunk/Source/WebKit/Shared/API/c/WKContextMenuItemTypes.h	2021-03-09 15:51:48 UTC (rev 274147)
+++ trunk/Source/WebKit/Shared/API/c/WKContextMenuItemTypes.h	2021-03-09 16:21:29 UTC (rev 274148)
@@ -126,6 +126,7 @@
     kWKContextMenuItemTagAddHighlightToCurrentGroup,
     kWKContextMenuItemTagAddHighlightToNewGroup,
     kWKContextMenuItemTagRevealImage,
+    kWKContextMenuItemTagTranslate,
     kWKContextMenuItemBaseApplicationTag = 10000
 };
 typedef uint32_t WKContextMenuItemTag;

Modified: trunk/Source/WebKit/Shared/API/c/WKSharedAPICast.h (274147 => 274148)


--- trunk/Source/WebKit/Shared/API/c/WKSharedAPICast.h	2021-03-09 15:51:48 UTC (rev 274147)
+++ trunk/Source/WebKit/Shared/API/c/WKSharedAPICast.h	2021-03-09 16:21:29 UTC (rev 274148)
@@ -547,6 +547,8 @@
         return kWKContextMenuItemTagShareMenu;
     case WebCore::ContextMenuItemTagRevealImage:
         return kWKContextMenuItemTagRevealImage;
+    case WebCore::ContextMenuItemTagTranslate:
+        return kWKContextMenuItemTagTranslate;
     default:
         if (action < WebCore::ContextMenuItemBaseApplicationTag && !(action >= WebCore::ContextMenuItemBaseCustomTag && action <= WebCore::ContextMenuItemLastCustomTag))
             LOG_ERROR("ContextMenuAction %i is an unknown tag but is below the allowable custom tag value of %i", action, WebCore::ContextMenuItemBaseApplicationTag);
@@ -749,6 +751,8 @@
 #endif
     case kWKContextMenuItemTagRevealImage:
         return WebCore::ContextMenuItemTagRevealImage;
+    case kWKContextMenuItemTagTranslate:
+        return WebCore::ContextMenuItemTagTranslate;
     case kWKContextMenuItemTagOpenLinkInThisWindow:
     default:
         if (tag < kWKContextMenuItemBaseApplicationTag && !(tag >= WebCore::ContextMenuItemBaseCustomTag && tag <= WebCore::ContextMenuItemLastCustomTag))

Modified: trunk/Source/WebKit/Shared/ContextMenuContextData.cpp (274147 => 274148)


--- trunk/Source/WebKit/Shared/ContextMenuContextData.cpp	2021-03-09 15:51:48 UTC (rev 274147)
+++ trunk/Source/WebKit/Shared/ContextMenuContextData.cpp	2021-03-09 16:21:29 UTC (rev 274148)
@@ -54,6 +54,7 @@
     , m_menuItems(menuItems)
     , m_webHitTestResultData(context.hitTestResult(), true)
     , m_selectedText(context.selectedText())
+    , m_selectionBounds(context.selectionBounds())
 #if ENABLE(SERVICE_CONTROLS)
     , m_selectionIsEditable(false)
 #endif
@@ -79,6 +80,7 @@
     encoder << m_menuItems;
     encoder << m_webHitTestResultData;
     encoder << m_selectedText;
+    encoder << m_selectionBounds;
 
 #if ENABLE(SERVICE_CONTROLS)
     ShareableBitmap::Handle handle;
@@ -108,6 +110,9 @@
     if (!decoder.decode(result.m_selectedText))
         return false;
 
+    if (!decoder.decode(result.m_selectionBounds))
+        return false;
+
 #if ENABLE(SERVICE_CONTROLS)
     ShareableBitmap::Handle handle;
     if (!decoder.decode(handle))

Modified: trunk/Source/WebKit/Shared/ContextMenuContextData.h (274147 => 274148)


--- trunk/Source/WebKit/Shared/ContextMenuContextData.h	2021-03-09 15:51:48 UTC (rev 274147)
+++ trunk/Source/WebKit/Shared/ContextMenuContextData.h	2021-03-09 16:21:29 UTC (rev 274148)
@@ -61,6 +61,7 @@
     WebHitTestResultData& webHitTestResultData() { return m_webHitTestResultData; }
     const WebHitTestResultData& webHitTestResultData() const { return m_webHitTestResultData; }
     const String& selectedText() const { return m_selectedText; }
+    const WebCore::IntRect& selectionBounds() const { return m_selectionBounds; }
 
 #if ENABLE(SERVICE_CONTROLS)
     ContextMenuContextData(const WebCore::IntPoint& menuLocation, const Vector<uint8_t>& selectionData, const Vector<String>& selectedTelephoneNumbers, bool isEditable)
@@ -91,6 +92,7 @@
 
     WebHitTestResultData m_webHitTestResultData;
     String m_selectedText;
+    WebCore::IntRect m_selectionBounds;
 
 #if ENABLE(SERVICE_CONTROLS)
     RefPtr<ShareableBitmap> m_controlledImage;

Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/WKMenuItemIdentifiers.mm (274147 => 274148)


--- trunk/Source/WebKit/UIProcess/API/Cocoa/WKMenuItemIdentifiers.mm	2021-03-09 15:51:48 UTC (rev 274147)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/WKMenuItemIdentifiers.mm	2021-03-09 16:21:29 UTC (rev 274148)
@@ -55,3 +55,5 @@
 
 NSString * const _WKMenuItemIdentifierShareMenu = @"WKMenuItemIdentifierShareMenu";
 NSString * const _WKMenuItemIdentifierSpeechMenu = @"WKMenuItemIdentifierSpeechMenu";
+
+NSString * const _WKMenuItemIdentifierTranslate = @"WKMenuItemIdentifierTranslate";

Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/WKMenuItemIdentifiersPrivate.h (274147 => 274148)


--- trunk/Source/WebKit/UIProcess/API/Cocoa/WKMenuItemIdentifiersPrivate.h	2021-03-09 15:51:48 UTC (rev 274147)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/WKMenuItemIdentifiersPrivate.h	2021-03-09 16:21:29 UTC (rev 274148)
@@ -57,3 +57,5 @@
 
 WK_EXPORT extern NSString * const _WKMenuItemIdentifierAddHighlightToCurrentGroup WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
 WK_EXPORT extern NSString * const _WKMenuItemIdentifierAddHighlightToNewGroup WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
+
+WK_EXPORT extern NSString * const _WKMenuItemIdentifierTranslate WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));

Modified: trunk/Source/WebKit/UIProcess/Cocoa/WebPageProxyCocoa.mm (274147 => 274148)


--- trunk/Source/WebKit/UIProcess/Cocoa/WebPageProxyCocoa.mm	2021-03-09 15:51:48 UTC (rev 274147)
+++ trunk/Source/WebKit/UIProcess/Cocoa/WebPageProxyCocoa.mm	2021-03-09 16:21:29 UTC (rev 274148)
@@ -590,7 +590,8 @@
     return SandboxExtension::HandleArray();
 }
 
-#if ENABLE(IMAGE_EXTRACTION) && ENABLE(CONTEXT_MENUS)
+#if ENABLE(CONTEXT_MENUS)
+#if ENABLE(IMAGE_EXTRACTION)
 
 void WebPageProxy::handleContextMenuRevealImage()
 {
@@ -601,8 +602,18 @@
     revealExtractedImageInPreviewPanel(*result.imageBitmap, result.toolTipText);
 }
 
-#endif // ENABLE(IMAGE_EXTRACTION) && ENABLE(CONTEXT_MENUS)
+#endif // ENABLE(IMAGE_EXTRACTION)
 
+#if HAVE(TRANSLATION_UI_SERVICES)
+
+bool WebPageProxy::canHandleContextMenuTranslation() const
+{
+    return pageClient().canHandleContextMenuTranslation();
+}
+
+#endif // HAVE(TRANSLATION_UI_SERVICES)
+#endif // ENABLE(CONTEXT_MENUS)
+
 void WebPageProxy::requestActiveNowPlayingSessionInfo(CompletionHandler<void(bool, bool, const String&, double, double, uint64_t)>&& callback)
 {
     sendWithAsyncReply(Messages::WebPage::RequestActiveNowPlayingSessionInfo(), WTFMove(callback));

Modified: trunk/Source/WebKit/UIProcess/Cocoa/WebViewImpl.h (274147 => 274148)


--- trunk/Source/WebKit/UIProcess/Cocoa/WebViewImpl.h	2021-03-09 15:51:48 UTC (rev 274147)
+++ trunk/Source/WebKit/UIProcess/Cocoa/WebViewImpl.h	2021-03-09 16:21:29 UTC (rev 274148)
@@ -638,6 +638,11 @@
     void handleDOMPasteRequestWithResult(WebCore::DOMPasteAccessResponse);
     NSMenu *domPasteMenu() const { return m_domPasteMenu.get(); }
 
+#if HAVE(TRANSLATION_UI_SERVICES) && ENABLE(CONTEXT_MENUS)
+    bool canHandleContextMenuTranslation() const;
+    void handleContextMenuTranslation(const String& text, const WebCore::IntRect& boundsInView, const WebCore::IntPoint& menuLocation);
+#endif
+
 private:
 #if HAVE(TOUCH_BAR)
     void setUpTextTouchBar(NSTouchBar *);

Modified: trunk/Source/WebKit/UIProcess/Cocoa/WebViewImpl.mm (274147 => 274148)


--- trunk/Source/WebKit/UIProcess/Cocoa/WebViewImpl.mm	2021-03-09 15:51:48 UTC (rev 274147)
+++ trunk/Source/WebKit/UIProcess/Cocoa/WebViewImpl.mm	2021-03-09 16:21:29 UTC (rev 274148)
@@ -139,6 +139,13 @@
 #import <WebCore/ImageExtractionResult.h>
 #endif
 
+#if HAVE(TRANSLATION_UI_SERVICES)
+#import <TranslationUIServices/LTUITranslationViewController.h>
+
+SOFT_LINK_PRIVATE_FRAMEWORK_OPTIONAL(TranslationUIServices)
+SOFT_LINK_CLASS_OPTIONAL(TranslationUIServices, LTUITranslationViewController)
+#endif
+
 #if HAVE(TOUCH_BAR) && ENABLE(WEB_PLAYBACK_CONTROLS_MANAGER)
 SOFT_LINK_FRAMEWORK(AVKit)
 SOFT_LINK_CLASS(AVKit, AVTouchBarPlaybackControlsProvider)
@@ -5574,6 +5581,47 @@
     return false;
 }
 
+#if HAVE(TRANSLATION_UI_SERVICES) && ENABLE(CONTEXT_MENUS)
+
+bool WebViewImpl::canHandleContextMenuTranslation() const
+{
+    return TranslationUIServicesLibrary() && [getLTUITranslationViewControllerClass() isAvailable];
+}
+
+void WebViewImpl::handleContextMenuTranslation(const String& text, const IntRect& boundsInView, const IntPoint& menuLocation)
+{
+    if (!canHandleContextMenuTranslation()) {
+        ASSERT_NOT_REACHED();
+        return;
+    }
+
+    auto view = m_view.get();
+    auto translationViewController = adoptNS([allocLTUITranslationViewControllerInstance() init]);
+    auto textToTranslate = adoptNS([[NSAttributedString alloc] initWithString:text]);
+    [translationViewController setText:textToTranslate.get()];
+    if (NSEqualSizes([translationViewController preferredContentSize], NSZeroSize))
+        [translationViewController setPreferredContentSize:NSMakeSize(400, 400)];
+
+    auto popover = adoptNS([[NSPopover alloc] init]);
+    [popover setBehavior:NSPopoverBehaviorTransient];
+    [popover setAppearance:[view effectiveAppearance]];
+    [popover setAnimates:YES];
+    [popover setContentViewController:translationViewController.get()];
+    [popover setContentSize:[translationViewController preferredContentSize]];
+
+    NSRectEdge preferredEdge;
+    auto aim = menuLocation.x();
+    auto highlight = boundsInView.center().x();
+    if (aim == highlight)
+        preferredEdge = [view userInterfaceLayoutDirection] == NSUserInterfaceLayoutDirectionRightToLeft ? NSRectEdgeMinX : NSRectEdgeMaxX;
+    else
+        preferredEdge = aim > highlight ? NSRectEdgeMaxX : NSRectEdgeMinX;
+
+    [popover showRelativeToRect:boundsInView ofView:view.get() preferredEdge:preferredEdge];
+}
+
+#endif // HAVE(TRANSLATION_UI_SERVICES) && ENABLE(CONTEXT_MENUS)
+
 } // namespace WebKit
 
 #endif // PLATFORM(MAC)

Modified: trunk/Source/WebKit/UIProcess/PageClient.h (274147 => 274148)


--- trunk/Source/WebKit/UIProcess/PageClient.h	2021-03-09 15:51:48 UTC (rev 274147)
+++ trunk/Source/WebKit/UIProcess/PageClient.h	2021-03-09 16:21:29 UTC (rev 274148)
@@ -602,6 +602,11 @@
 #if PLATFORM(GTK)
     virtual String themeName() const = 0;
 #endif
+
+#if HAVE(TRANSLATION_UI_SERVICES) && ENABLE(CONTEXT_MENUS)
+    virtual bool canHandleContextMenuTranslation() const = 0;
+    virtual void handleContextMenuTranslation(const String& text, const WebCore::IntRect& boundsInView, const WebCore::IntPoint& menuLocation) = 0;
+#endif
 };
 
 } // namespace WebKit

Modified: trunk/Source/WebKit/UIProcess/WebPageProxy.cpp (274147 => 274148)


--- trunk/Source/WebKit/UIProcess/WebPageProxy.cpp	2021-03-09 15:51:48 UTC (rev 274147)
+++ trunk/Source/WebKit/UIProcess/WebPageProxy.cpp	2021-03-09 16:21:29 UTC (rev 274148)
@@ -6722,6 +6722,12 @@
 #endif
         return;
 
+    case ContextMenuItemTagTranslate:
+#if HAVE(TRANSLATION_UI_SERVICES)
+        pageClient().handleContextMenuTranslation(m_activeContextMenuContextData.selectedText(), m_activeContextMenuContextData.selectionBounds(), m_activeContextMenuContextData.menuLocation());
+#endif
+        return;
+
     default:
         break;
     }

Modified: trunk/Source/WebKit/UIProcess/WebPageProxy.h (274147 => 274148)


--- trunk/Source/WebKit/UIProcess/WebPageProxy.h	2021-03-09 15:51:48 UTC (rev 274147)
+++ trunk/Source/WebKit/UIProcess/WebPageProxy.h	2021-03-09 16:21:29 UTC (rev 274148)
@@ -1866,6 +1866,10 @@
     void resetImageExtractionPreview();
 #endif
 
+#if HAVE(TRANSLATION_UI_SERVICES)
+    bool canHandleContextMenuTranslation() const;
+#endif
+
 #if PLATFORM(COCOA)
     void setLastNavigationWasAppBound(WebCore::ResourceRequest&);
     void lastNavigationWasAppBound(CompletionHandler<void(bool)>&&);

Modified: trunk/Source/WebKit/UIProcess/mac/PageClientImplMac.h (274147 => 274148)


--- trunk/Source/WebKit/UIProcess/mac/PageClientImplMac.h	2021-03-09 15:51:48 UTC (rev 274147)
+++ trunk/Source/WebKit/UIProcess/mac/PageClientImplMac.h	2021-03-09 16:21:29 UTC (rev 274148)
@@ -276,6 +276,11 @@
     WebCore::Color accentColor() override;
 #endif
 
+#if HAVE(TRANSLATION_UI_SERVICES) && ENABLE(CONTEXT_MENUS)
+    bool canHandleContextMenuTranslation() const override;
+    void handleContextMenuTranslation(const String&, const WebCore::IntRect&, const WebCore::IntPoint&) override;
+#endif
+
     NSView *m_view;
     WeakPtr<WebViewImpl> m_impl;
 #if USE(AUTOCORRECTION_PANEL)

Modified: trunk/Source/WebKit/UIProcess/mac/PageClientImplMac.mm (274147 => 274148)


--- trunk/Source/WebKit/UIProcess/mac/PageClientImplMac.mm	2021-03-09 15:51:48 UTC (rev 274147)
+++ trunk/Source/WebKit/UIProcess/mac/PageClientImplMac.mm	2021-03-09 16:21:29 UTC (rev 274148)
@@ -992,6 +992,20 @@
 }
 #endif
 
+#if HAVE(TRANSLATION_UI_SERVICES) && ENABLE(CONTEXT_MENUS)
+
+bool PageClientImpl::canHandleContextMenuTranslation() const
+{
+    return m_impl->canHandleContextMenuTranslation();
+}
+
+void PageClientImpl::handleContextMenuTranslation(const String& text, const IntRect& boundsInView, const WebCore::IntPoint& menuLocation)
+{
+    m_impl->handleContextMenuTranslation(text, boundsInView, menuLocation);
+}
+
+#endif // HAVE(TRANSLATION_UI_SERVICES) && ENABLE(CONTEXT_MENUS)
+
 } // namespace WebKit
 
 #endif // PLATFORM(MAC)

Modified: trunk/Source/WebKit/UIProcess/mac/WebContextMenuProxyMac.mm (274147 => 274148)


--- trunk/Source/WebKit/UIProcess/mac/WebContextMenuProxyMac.mm	2021-03-09 15:51:48 UTC (rev 274147)
+++ trunk/Source/WebKit/UIProcess/mac/WebContextMenuProxyMac.mm	2021-03-09 16:21:29 UTC (rev 274148)
@@ -362,6 +362,14 @@
         });
     }
 
+#if HAVE(TRANSLATION_UI_SERVICES)
+    if (!page()->canHandleContextMenuTranslation() || isPopover) {
+        filteredItems.removeAllMatching([] (auto& item) {
+            return item.action() == ContextMenuItemTagTranslate;
+        });
+    }
+#endif
+
     auto sparseMenuItems = retainPtr([NSPointerArray strongObjectsPointerArray]);
     auto insertMenuItem = makeBlockPtr([completionHandler = WTFMove(completionHandler), itemsRemaining = filteredItems.size(), menu = WTFMove(menu), sparseMenuItems](NSMenuItem *item, NSUInteger index) mutable {
         ASSERT(index < [sparseMenuItems count]);
@@ -460,6 +468,9 @@
     case ContextMenuItemTagToggleVideoFullscreen:
         return _WKMenuItemIdentifierToggleFullScreen;
 
+    case ContextMenuItemTagTranslate:
+        return _WKMenuItemIdentifierTranslate;
+
     case ContextMenuItemTagShareMenu:
         return _WKMenuItemIdentifierShareMenu;
 

Modified: trunk/Source/WebKitLegacy/mac/ChangeLog (274147 => 274148)


--- trunk/Source/WebKitLegacy/mac/ChangeLog	2021-03-09 15:51:48 UTC (rev 274147)
+++ trunk/Source/WebKitLegacy/mac/ChangeLog	2021-03-09 16:21:29 UTC (rev 274148)
@@ -1,3 +1,16 @@
+2021-03-09  Wenson Hsieh  <[email protected]>
+
+        [macOS] Add a way to trigger webpage translation via the context menu
+        https://bugs.webkit.org/show_bug.cgi?id=222953
+        <rdar://problem/73901967>
+
+        Reviewed by Devin Rousso.
+
+        Add (no-op) handling for the new enum value.
+
+        * WebView/WebHTMLView.mm:
+        (toTag):
+
 2021-03-08  Sam Weinig  <[email protected]>
 
         Remove quirks for the no longer supported iAd Producer

Modified: trunk/Source/WebKitLegacy/mac/WebView/WebHTMLView.mm (274147 => 274148)


--- trunk/Source/WebKitLegacy/mac/WebView/WebHTMLView.mm	2021-03-09 15:51:48 UTC (rev 274147)
+++ trunk/Source/WebKitLegacy/mac/WebView/WebHTMLView.mm	2021-03-09 16:21:29 UTC (rev 274148)
@@ -615,6 +615,7 @@
     case ContextMenuItemTagToggleVideoEnhancedFullscreen:
         return WebMenuItemTagToggleVideoEnhancedFullscreen;
     case ContextMenuItemTagRevealImage:
+    case ContextMenuItemTagTranslate:
         return WTF::nullopt;
 
     case ContextMenuItemBaseCustomTag ... ContextMenuItemLastCustomTag:

Modified: trunk/Tools/ChangeLog (274147 => 274148)


--- trunk/Tools/ChangeLog	2021-03-09 15:51:48 UTC (rev 274147)
+++ trunk/Tools/ChangeLog	2021-03-09 16:21:29 UTC (rev 274148)
@@ -1,3 +1,16 @@
+2021-03-09  Wenson Hsieh  <[email protected]>
+
+        [macOS] Add a way to trigger webpage translation via the context menu
+        https://bugs.webkit.org/show_bug.cgi?id=222953
+        <rdar://problem/73901967>
+
+        Reviewed by Devin Rousso.
+
+        Adjust an API test. This new enum value is now the new last valid item value.
+
+        * TestWebKitAPI/Tests/WebCore/ContextMenuAction.cpp:
+        (TestWebKitAPI::TEST):
+
 2021-03-08  Stephan Szabo  <[email protected]>
 
         [PlayStation] Various small fixes for TestWTF/TestWebKit tests on PlayStation

Modified: trunk/Tools/TestWebKitAPI/Tests/WebCore/ContextMenuAction.cpp (274147 => 274148)


--- trunk/Tools/TestWebKitAPI/Tests/WebCore/ContextMenuAction.cpp	2021-03-09 15:51:48 UTC (rev 274147)
+++ trunk/Tools/TestWebKitAPI/Tests/WebCore/ContextMenuAction.cpp	2021-03-09 16:21:29 UTC (rev 274148)
@@ -37,9 +37,9 @@
     EXPECT_TRUE(WTF::isValidEnum<WebCore::ContextMenuAction>(WebCore::ContextMenuAction::ContextMenuItemTagNoAction));
     EXPECT_TRUE(WTF::isValidEnum<WebCore::ContextMenuAction>(WebCore::ContextMenuAction::ContextMenuItemTagNoAction + 1));
 
-    EXPECT_TRUE(WTF::isValidEnum<WebCore::ContextMenuAction>(WebCore::ContextMenuAction::ContextMenuItemTagRevealImage - 1));
-    EXPECT_TRUE(WTF::isValidEnum<WebCore::ContextMenuAction>(WebCore::ContextMenuAction::ContextMenuItemTagRevealImage));
-    EXPECT_FALSE(WTF::isValidEnum<WebCore::ContextMenuAction>(WebCore::ContextMenuAction::ContextMenuItemTagRevealImage + 1));
+    EXPECT_TRUE(WTF::isValidEnum<WebCore::ContextMenuAction>(WebCore::ContextMenuAction::ContextMenuItemTagTranslate - 1));
+    EXPECT_TRUE(WTF::isValidEnum<WebCore::ContextMenuAction>(WebCore::ContextMenuAction::ContextMenuItemTagTranslate));
+    EXPECT_FALSE(WTF::isValidEnum<WebCore::ContextMenuAction>(WebCore::ContextMenuAction::ContextMenuItemTagTranslate + 1));
 
     EXPECT_FALSE(WTF::isValidEnum<WebCore::ContextMenuAction>(WebCore::ContextMenuAction::ContextMenuItemBaseCustomTag - 1));
     EXPECT_TRUE(WTF::isValidEnum<WebCore::ContextMenuAction>(WebCore::ContextMenuAction::ContextMenuItemBaseCustomTag));
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to