Title: [175694] trunk
Revision
175694
Author
carlo...@webkit.org
Date
2014-11-06 07:08:07 -0800 (Thu, 06 Nov 2014)

Log Message

[GTK] Add context menu API to Web Process Extensions
https://bugs.webkit.org/show_bug.cgi?id=138311

Reviewed by Gustavo Noronha Silva.

Source/WebKit2:

Add WebKitWebPage::context-menu signal, similar to the
WebKitWebView one, but that receives a WebKitWebHitTestResult, a
class that extends WebKitTestResult to provide the WebKitDOMNode
from the Web Process Extensions API. This makes WebKitContextMenu,
WebKitContextMenuItem and WebKitTestResult classes shared between
UI and Web Extensions APIs. In addition to be able to customize
the context menu, it also provides API to set user data, as a
GVariant, in the Web Process that is sent to the UI Process.

* PlatformGTK.cmake: Add new files.
* UIProcess/API/gtk/WebKitContextMenu.cpp:
(webkit_context_menu_set_user_data): Add user data to the context
menu as a GVariant.
(webkit_context_menu_get_user_data): Get the user data previously
set with webkit_context_menu_set_user_data() either from the Web
or UI processes.
* UIProcess/API/gtk/WebKitContextMenu.h:
* UIProcess/API/gtk/WebKitContextMenuActions.h:
* UIProcess/API/gtk/WebKitContextMenuClient.cpp:
(getContextMenuFromProposedMenu): Convert the received user data
into a GVariant and pass it to webkitWebViewPopulateContextMenu().
* UIProcess/API/gtk/WebKitContextMenuItem.h:
* UIProcess/API/gtk/WebKitForwardDeclarations.h:
* UIProcess/API/gtk/WebKitHitTestResult.h:
* UIProcess/API/gtk/WebKitWebView.cpp:
(webkitWebViewPopulateContextMenu): Set the user data received
from the Web Process to the WebKitContextMenu before emitting
WebKitWebView::context-menu.
* UIProcess/API/gtk/WebKitWebViewPrivate.h:
* UIProcess/API/gtk/docs/webkit2gtk-docs.sgml: Add new section for WebKitWebHitTestResult.
* UIProcess/API/gtk/docs/webkit2gtk-sections.txt: Add new symbols.
* UIProcess/API/gtk/docs/webkit2gtk.types: Add webkit_web_hit_test_result_get_type.
* WebProcess/InjectedBundle/API/gtk/WebKitWebHitTestResult.cpp: Added.
(webkitWebHitTestResultGetProperty): Add getter for node property.
(webkitWebHitTestResultSetProperty): Add setter for node property.
(webkit_web_hit_test_result_class_init): Add node property.
(webkitWebHitTestResultCreate): Create a new
WebKitWebHitTestResult for the given InjectedBundleHitTestResult.
(webkit_web_hit_test_result_get_node): Return the WebKitDOMNode.
* WebProcess/InjectedBundle/API/gtk/WebKitWebHitTestResult.h: Added.
* WebProcess/InjectedBundle/API/gtk/WebKitWebHitTestResultPrivate.h: Added.
* WebProcess/InjectedBundle/API/gtk/WebKitWebPage.cpp:
(getContextMenuFromDefaultMenu): Build a WebKitContextMenu and
WebKitWebHitTestResult and emit WebKitWebPage::context-menu signal.
(webkit_web_page_class_init): Add WebKitWebPage::context-menu signal.
(webkitWebPageCreate): Add implementation for getContextMenuFromDefaultMenu.
* WebProcess/InjectedBundle/API/gtk/webkit-web-extension.h:

Tools:

Add tests cases for WebKitWebPage::context-menu signal.

* TestWebKitAPI/Tests/WebKit2Gtk/TestContextMenu.cpp:
(testContextMenuWebExtensionMenu):
(testContextMenuWebExtensionNode):
(beforeAll):
* TestWebKitAPI/Tests/WebKit2Gtk/WebExtensionTest.cpp:
(serializeContextMenu):
(serializeNode):
(contextMenuCallback):
(pageCreatedCallback):

Modified Paths

Added Paths

Diff

Modified: trunk/Source/WebKit2/ChangeLog (175693 => 175694)


--- trunk/Source/WebKit2/ChangeLog	2014-11-06 10:31:53 UTC (rev 175693)
+++ trunk/Source/WebKit2/ChangeLog	2014-11-06 15:08:07 UTC (rev 175694)
@@ -1,3 +1,58 @@
+2014-11-06  Carlos Garcia Campos  <cgar...@igalia.com>
+
+        [GTK] Add context menu API to Web Process Extensions
+        https://bugs.webkit.org/show_bug.cgi?id=138311
+
+        Reviewed by Gustavo Noronha Silva.
+
+        Add WebKitWebPage::context-menu signal, similar to the
+        WebKitWebView one, but that receives a WebKitWebHitTestResult, a
+        class that extends WebKitTestResult to provide the WebKitDOMNode
+        from the Web Process Extensions API. This makes WebKitContextMenu,
+        WebKitContextMenuItem and WebKitTestResult classes shared between
+        UI and Web Extensions APIs. In addition to be able to customize
+        the context menu, it also provides API to set user data, as a
+        GVariant, in the Web Process that is sent to the UI Process.
+
+        * PlatformGTK.cmake: Add new files.
+        * UIProcess/API/gtk/WebKitContextMenu.cpp:
+        (webkit_context_menu_set_user_data): Add user data to the context
+        menu as a GVariant.
+        (webkit_context_menu_get_user_data): Get the user data previously
+        set with webkit_context_menu_set_user_data() either from the Web
+        or UI processes.
+        * UIProcess/API/gtk/WebKitContextMenu.h:
+        * UIProcess/API/gtk/WebKitContextMenuActions.h:
+        * UIProcess/API/gtk/WebKitContextMenuClient.cpp:
+        (getContextMenuFromProposedMenu): Convert the received user data
+        into a GVariant and pass it to webkitWebViewPopulateContextMenu().
+        * UIProcess/API/gtk/WebKitContextMenuItem.h:
+        * UIProcess/API/gtk/WebKitForwardDeclarations.h:
+        * UIProcess/API/gtk/WebKitHitTestResult.h:
+        * UIProcess/API/gtk/WebKitWebView.cpp:
+        (webkitWebViewPopulateContextMenu): Set the user data received
+        from the Web Process to the WebKitContextMenu before emitting
+        WebKitWebView::context-menu.
+        * UIProcess/API/gtk/WebKitWebViewPrivate.h:
+        * UIProcess/API/gtk/docs/webkit2gtk-docs.sgml: Add new section for WebKitWebHitTestResult.
+        * UIProcess/API/gtk/docs/webkit2gtk-sections.txt: Add new symbols.
+        * UIProcess/API/gtk/docs/webkit2gtk.types: Add webkit_web_hit_test_result_get_type.
+        * WebProcess/InjectedBundle/API/gtk/WebKitWebHitTestResult.cpp: Added.
+        (webkitWebHitTestResultGetProperty): Add getter for node property.
+        (webkitWebHitTestResultSetProperty): Add setter for node property.
+        (webkit_web_hit_test_result_class_init): Add node property.
+        (webkitWebHitTestResultCreate): Create a new
+        WebKitWebHitTestResult for the given InjectedBundleHitTestResult.
+        (webkit_web_hit_test_result_get_node): Return the WebKitDOMNode.
+        * WebProcess/InjectedBundle/API/gtk/WebKitWebHitTestResult.h: Added.
+        * WebProcess/InjectedBundle/API/gtk/WebKitWebHitTestResultPrivate.h: Added.
+        * WebProcess/InjectedBundle/API/gtk/WebKitWebPage.cpp:
+        (getContextMenuFromDefaultMenu): Build a WebKitContextMenu and
+        WebKitWebHitTestResult and emit WebKitWebPage::context-menu signal.
+        (webkit_web_page_class_init): Add WebKitWebPage::context-menu signal.
+        (webkitWebPageCreate): Add implementation for getContextMenuFromDefaultMenu.
+        * WebProcess/InjectedBundle/API/gtk/webkit-web-extension.h:
+
 2014-11-06  Ryuan Choi  <ryuan.c...@gmail.com>
 
         [EFL] Remove m_scrollPosition from CoordinatedGraphicsScene

Modified: trunk/Source/WebKit2/PlatformGTK.cmake (175693 => 175694)


--- trunk/Source/WebKit2/PlatformGTK.cmake	2014-11-06 10:31:53 UTC (rev 175693)
+++ trunk/Source/WebKit2/PlatformGTK.cmake	2014-11-06 15:08:07 UTC (rev 175694)
@@ -274,6 +274,7 @@
     WebProcess/InjectedBundle/API/gtk/WebKitFrame.cpp
     WebProcess/InjectedBundle/API/gtk/WebKitScriptWorld.cpp
     WebProcess/InjectedBundle/API/gtk/WebKitWebExtension.cpp
+    WebProcess/InjectedBundle/API/gtk/WebKitWebHitTestResult.cpp
     WebProcess/InjectedBundle/API/gtk/WebKitWebPage.cpp
 
     WebProcess/InjectedBundle/gtk/InjectedBundleGtk.cpp
@@ -372,6 +373,7 @@
     ${WEBKIT2_DIR}/WebProcess/InjectedBundle/API/gtk/WebKitFrame.h
     ${WEBKIT2_DIR}/WebProcess/InjectedBundle/API/gtk/WebKitScriptWorld.h
     ${WEBKIT2_DIR}/WebProcess/InjectedBundle/API/gtk/WebKitWebExtension.h
+    ${WEBKIT2_DIR}/WebProcess/InjectedBundle/API/gtk/WebKitWebHitTestResult.h
     ${WEBKIT2_DIR}/WebProcess/InjectedBundle/API/gtk/WebKitWebPage.h
     ${WEBKIT2_DIR}/WebProcess/InjectedBundle/API/gtk/webkit-web-extension.h
 )
@@ -797,6 +799,10 @@
         -I${WEBKIT2_DIR}/WebProcess/InjectedBundle/API/gtk
         ${GObjectDOMBindings_GIR_HEADERS}
         ${WebKit2WebExtension_INSTALLED_HEADERS}
+        ${WEBKIT2_DIR}/UIProcess/API/gtk/WebKitContextMenu.h
+        ${WEBKIT2_DIR}/UIProcess/API/gtk/WebKitContextMenuActions.h
+        ${WEBKIT2_DIR}/UIProcess/API/gtk/WebKitContextMenuItem.h
+        ${WEBKIT2_DIR}/UIProcess/API/gtk/WebKitHitTestResult.h
         ${WEBKIT2_DIR}/UIProcess/API/gtk/WebKitURIRequest.h
         ${WEBKIT2_DIR}/UIProcess/API/gtk/WebKitURIResponse.h
         ${WEBKIT2_DIR}/WebProcess/InjectedBundle/API/gtk/*.cpp

Modified: trunk/Source/WebKit2/UIProcess/API/gtk/WebKitContextMenu.cpp (175693 => 175694)


--- trunk/Source/WebKit2/UIProcess/API/gtk/WebKitContextMenu.cpp	2014-11-06 10:31:53 UTC (rev 175693)
+++ trunk/Source/WebKit2/UIProcess/API/gtk/WebKitContextMenu.cpp	2014-11-06 15:08:07 UTC (rev 175694)
@@ -24,6 +24,7 @@
 #include "WebContextMenuItem.h"
 #include "WebKitContextMenuItemPrivate.h"
 #include "WebKitContextMenuPrivate.h"
+#include <wtf/gobject/GRefPtr.h>
 
 using namespace WebKit;
 using namespace WebCore;
@@ -50,6 +51,7 @@
 struct _WebKitContextMenuPrivate {
     GList* items;
     WebKitContextMenuItem* parentItem;
+    GRefPtr<GVariant> userData;
 };
 
 WEBKIT_DEFINE_TYPE(WebKitContextMenu, webkit_context_menu, G_TYPE_OBJECT)
@@ -316,3 +318,41 @@
     g_list_free_full(menu->priv->items, reinterpret_cast<GDestroyNotify>(g_object_unref));
     menu->priv->items = 0;
 }
+
+/**
+ * webkit_context_menu_set_user_data:
+ * @menu: a #WebKitContextMenu
+ * @user_data: a #GVariant
+ *
+ * Sets user data to @menu.
+ * This function can be used from a Web Process extension to set user data
+ * that can be retrieved from the UI Process using webkit_context_menu_get_user_data().
+ *
+ * Since: 2.8
+ */
+void webkit_context_menu_set_user_data(WebKitContextMenu* menu, GVariant* userData)
+{
+    g_return_if_fail(WEBKIT_IS_CONTEXT_MENU(menu));
+    g_return_if_fail(userData);
+
+    menu->priv->userData = userData;
+}
+
+/**
+ * webkit_context_menu_get_user_data:
+ * @menu: a #WebKitContextMenu
+ *
+ * Gets the user data of @menu.
+ * This function can be used from the UI Process to get user data previously set
+ * from the Web Process with webkit_context_menu_set_user_data().
+ *
+ * Returns: (transfer none): the user data of @menu, or %NULL if @menu doesn't have user data
+ *
+ * Since: 2.8
+ */
+GVariant* webkit_context_menu_get_user_data(WebKitContextMenu* menu)
+{
+    g_return_val_if_fail(WEBKIT_IS_CONTEXT_MENU(menu), nullptr);
+
+    return menu->priv->userData.get();
+}

Modified: trunk/Source/WebKit2/UIProcess/API/gtk/WebKitContextMenu.h (175693 => 175694)


--- trunk/Source/WebKit2/UIProcess/API/gtk/WebKitContextMenu.h	2014-11-06 10:31:53 UTC (rev 175693)
+++ trunk/Source/WebKit2/UIProcess/API/gtk/WebKitContextMenu.h	2014-11-06 15:08:07 UTC (rev 175694)
@@ -17,7 +17,7 @@
  * Boston, MA 02110-1301, USA.
  */
 
-#if !defined(__WEBKIT2_H_INSIDE__) && !defined(WEBKIT2_COMPILATION)
+#if !defined(__WEBKIT2_H_INSIDE__) && !defined(WEBKIT2_COMPILATION) && !defined(__WEBKIT_WEB_EXTENSION_H_INSIDE__)
 #error "Only <webkit2/webkit2.h> can be included directly."
 #endif
 
@@ -105,6 +105,13 @@
 WEBKIT_API void
 webkit_context_menu_remove_all           (WebKitContextMenu     *menu);
 
+WEBKIT_API void
+webkit_context_menu_set_user_data        (WebKitContextMenu     *menu,
+                                          GVariant              *user_data);
+
+WEBKIT_API GVariant *
+webkit_context_menu_get_user_data        (WebKitContextMenu     *menu);
+
 G_END_DECLS
 
 #endif

Modified: trunk/Source/WebKit2/UIProcess/API/gtk/WebKitContextMenuActions.h (175693 => 175694)


--- trunk/Source/WebKit2/UIProcess/API/gtk/WebKitContextMenuActions.h	2014-11-06 10:31:53 UTC (rev 175693)
+++ trunk/Source/WebKit2/UIProcess/API/gtk/WebKitContextMenuActions.h	2014-11-06 15:08:07 UTC (rev 175694)
@@ -17,7 +17,7 @@
  * Boston, MA 02110-1301, USA.
  */
 
-#if !defined(__WEBKIT2_H_INSIDE__) && !defined(WEBKIT2_COMPILATION)
+#if !defined(__WEBKIT2_H_INSIDE__) && !defined(WEBKIT2_COMPILATION) && !defined(__WEBKIT_WEB_EXTENSION_H_INSIDE__)
 #error "Only <webkit2/webkit2.h> can be included directly."
 #endif
 

Modified: trunk/Source/WebKit2/UIProcess/API/gtk/WebKitContextMenuClient.cpp (175693 => 175694)


--- trunk/Source/WebKit2/UIProcess/API/gtk/WebKitContextMenuClient.cpp	2014-11-06 10:31:53 UTC (rev 175693)
+++ trunk/Source/WebKit2/UIProcess/API/gtk/WebKitContextMenuClient.cpp	2014-11-06 15:08:07 UTC (rev 175694)
@@ -26,9 +26,15 @@
 
 using namespace WebKit;
 
-static void getContextMenuFromProposedMenu(WKPageRef, WKArrayRef proposedMenu, WKArrayRef*, WKHitTestResultRef hitTestResult, WKTypeRef /* userData */, const void* clientInfo)
+static void getContextMenuFromProposedMenu(WKPageRef, WKArrayRef proposedMenu, WKArrayRef*, WKHitTestResultRef hitTestResult, WKTypeRef userData, const void* clientInfo)
 {
-    webkitWebViewPopulateContextMenu(WEBKIT_WEB_VIEW(clientInfo), toImpl(proposedMenu), toImpl(hitTestResult));
+    GRefPtr<GVariant> variant;
+    if (userData) {
+        ASSERT(WKGetTypeID(userData) == WKStringGetTypeID());
+        CString userDataString = toImpl(static_cast<WKStringRef>(userData))->string().utf8();
+        variant = adoptGRef(g_variant_parse(nullptr, userDataString.data(), userDataString.data() + userDataString.length(), nullptr, nullptr));
+    }
+    webkitWebViewPopulateContextMenu(WEBKIT_WEB_VIEW(clientInfo), toImpl(proposedMenu), toImpl(hitTestResult), variant.get());
 }
 
 void attachContextMenuClientToView(WebKitWebView* webView)

Modified: trunk/Source/WebKit2/UIProcess/API/gtk/WebKitContextMenuItem.h (175693 => 175694)


--- trunk/Source/WebKit2/UIProcess/API/gtk/WebKitContextMenuItem.h	2014-11-06 10:31:53 UTC (rev 175693)
+++ trunk/Source/WebKit2/UIProcess/API/gtk/WebKitContextMenuItem.h	2014-11-06 15:08:07 UTC (rev 175694)
@@ -17,7 +17,7 @@
  * Boston, MA 02110-1301, USA.
  */
 
-#if !defined(__WEBKIT2_H_INSIDE__) && !defined(WEBKIT2_COMPILATION)
+#if !defined(__WEBKIT2_H_INSIDE__) && !defined(WEBKIT2_COMPILATION) && !defined(__WEBKIT_WEB_EXTENSION_H_INSIDE__)
 #error "Only <webkit2/webkit2.h> can be included directly."
 #endif
 

Modified: trunk/Source/WebKit2/UIProcess/API/gtk/WebKitForwardDeclarations.h (175693 => 175694)


--- trunk/Source/WebKit2/UIProcess/API/gtk/WebKitForwardDeclarations.h	2014-11-06 10:31:53 UTC (rev 175693)
+++ trunk/Source/WebKit2/UIProcess/API/gtk/WebKitForwardDeclarations.h	2014-11-06 15:08:07 UTC (rev 175694)
@@ -23,7 +23,7 @@
  * THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#if !defined(__WEBKIT2_H_INSIDE__) && !defined(WEBKIT2_COMPILATION)
+#if !defined(__WEBKIT2_H_INSIDE__) && !defined(WEBKIT2_COMPILATION) && !defined(__WEBKIT_WEB_EXTENSION_H_INSIDE__)
 #error "Only <webkit2/webkit2.h> can be included directly."
 #endif
 

Modified: trunk/Source/WebKit2/UIProcess/API/gtk/WebKitHitTestResult.h (175693 => 175694)


--- trunk/Source/WebKit2/UIProcess/API/gtk/WebKitHitTestResult.h	2014-11-06 10:31:53 UTC (rev 175693)
+++ trunk/Source/WebKit2/UIProcess/API/gtk/WebKitHitTestResult.h	2014-11-06 15:08:07 UTC (rev 175694)
@@ -17,7 +17,7 @@
  * Boston, MA 02110-1301, USA.
  */
 
-#if !defined(__WEBKIT2_H_INSIDE__) && !defined(WEBKIT2_COMPILATION)
+#if !defined(__WEBKIT2_H_INSIDE__) && !defined(WEBKIT2_COMPILATION) && !defined(__WEBKIT_WEB_EXTENSION_H_INSIDE__)
 #error "Only <webkit2/webkit2.h> can be included directly."
 #endif
 

Modified: trunk/Source/WebKit2/UIProcess/API/gtk/WebKitWebView.cpp (175693 => 175694)


--- trunk/Source/WebKit2/UIProcess/API/gtk/WebKitWebView.cpp	2014-11-06 10:31:53 UTC (rev 175693)
+++ trunk/Source/WebKit2/UIProcess/API/gtk/WebKitWebView.cpp	2014-11-06 15:08:07 UTC (rev 175694)
@@ -1891,7 +1891,7 @@
     g_signal_emit(webView, signals[CONTEXT_MENU_DISMISSED], 0, NULL);
 }
 
-void webkitWebViewPopulateContextMenu(WebKitWebView* webView, API::Array* proposedMenu, WebHitTestResult* webHitTestResult)
+void webkitWebViewPopulateContextMenu(WebKitWebView* webView, API::Array* proposedMenu, WebHitTestResult* webHitTestResult, GVariant* userData)
 {
     WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(webView);
     WebContextMenuProxyGtk* contextMenuProxy = webkitWebViewBaseGetActiveContextMenuProxy(webViewBase);
@@ -1917,6 +1917,9 @@
     GRefPtr<WebKitHitTestResult> hitTestResult = adoptGRef(webkitHitTestResultCreate(data));
     GUniquePtr<GdkEvent> contextMenuEvent(webkitWebViewBaseTakeContextMenuEvent(webViewBase));
 
+    if (userData)
+        webkit_context_menu_set_user_data(WEBKIT_CONTEXT_MENU(contextMenu.get()), userData);
+
     gboolean returnValue;
     g_signal_emit(webView, signals[CONTEXT_MENU], 0, contextMenu.get(), contextMenuEvent.get(), hitTestResult.get(), &returnValue);
     if (returnValue)

Modified: trunk/Source/WebKit2/UIProcess/API/gtk/WebKitWebViewPrivate.h (175693 => 175694)


--- trunk/Source/WebKit2/UIProcess/API/gtk/WebKitWebViewPrivate.h	2014-11-06 10:31:53 UTC (rev 175693)
+++ trunk/Source/WebKit2/UIProcess/API/gtk/WebKitWebViewPrivate.h	2014-11-06 15:08:07 UTC (rev 175694)
@@ -53,7 +53,7 @@
 void webkitWebViewRemoveLoadingWebResource(WebKitWebView*, uint64_t resourceIdentifier);
 bool webkitWebViewEnterFullScreen(WebKitWebView*);
 bool webkitWebViewLeaveFullScreen(WebKitWebView*);
-void webkitWebViewPopulateContextMenu(WebKitWebView*, API::Array* proposedMenu, WebKit::WebHitTestResult*);
+void webkitWebViewPopulateContextMenu(WebKitWebView*, API::Array* proposedMenu, WebKit::WebHitTestResult*, GVariant*);
 void webkitWebViewSubmitFormRequest(WebKitWebView*, WebKitFormSubmissionRequest*);
 void webkitWebViewHandleAuthenticationChallenge(WebKitWebView*, WebKit::AuthenticationChallengeProxy*);
 void webkitWebViewInsecureContentDetected(WebKitWebView*, WebKitInsecureContentEvent);

Modified: trunk/Source/WebKit2/UIProcess/API/gtk/docs/webkit2gtk-docs.sgml (175693 => 175694)


--- trunk/Source/WebKit2/UIProcess/API/gtk/docs/webkit2gtk-docs.sgml	2014-11-06 10:31:53 UTC (rev 175693)
+++ trunk/Source/WebKit2/UIProcess/API/gtk/docs/webkit2gtk-docs.sgml	2014-11-06 15:08:07 UTC (rev 175694)
@@ -53,6 +53,7 @@
     <xi:include href=""
     <xi:include href=""
     <xi:include href=""
+    <xi:include href=""
   </chapter>
 
   <index id="index-all">

Modified: trunk/Source/WebKit2/UIProcess/API/gtk/docs/webkit2gtk-sections.txt (175693 => 175694)


--- trunk/Source/WebKit2/UIProcess/API/gtk/docs/webkit2gtk-sections.txt	2014-11-06 10:31:53 UTC (rev 175693)
+++ trunk/Source/WebKit2/UIProcess/API/gtk/docs/webkit2gtk-sections.txt	2014-11-06 15:08:07 UTC (rev 175694)
@@ -982,6 +982,8 @@
 webkit_context_menu_get_item_at_position
 webkit_context_menu_remove
 webkit_context_menu_remove_all
+webkit_context_menu_set_user_data
+webkit_context_menu_get_user_data
 
 <SUBSECTION Standard>
 WebKitContextMenuClass
@@ -1160,3 +1162,22 @@
 WebKitScriptWorldPrivate
 webkit_script_world_get_type
 </SECTION>
+
+<SECTION>
+<FILE>WebKitWebHitTestResult</FILE>
+WebKitWebHitTestResult
+webkit_web_hit_test_result_get_node
+
+<SUBSECTION Standard>
+WebKitWebHitTestResultClass
+WEBKIT_TYPE_WEB_HIT_TEST_RESULT
+WEBKIT_WEB_HIT_TEST_RESULT
+WEBKIT_IS_WEB_HIT_TEST_RESULT
+WEBKIT_WEB_HIT_TEST_RESULT_CLASS
+WEBKIT_IS_WEB_HIT_TEST_RESULT_CLASS
+WEBKIT_WEB_HIT_TEST_RESULT_GET_CLASS
+
+<SUBSECTION Private>
+WebKitWebHitTestResultPrivate
+webkit_web_hit_test_result_get_type
+</SECTION>

Modified: trunk/Source/WebKit2/UIProcess/API/gtk/docs/webkit2gtk.types (175693 => 175694)


--- trunk/Source/WebKit2/UIProcess/API/gtk/docs/webkit2gtk.types	2014-11-06 10:31:53 UTC (rev 175693)
+++ trunk/Source/WebKit2/UIProcess/API/gtk/docs/webkit2gtk.types	2014-11-06 15:08:07 UTC (rev 175694)
@@ -28,3 +28,4 @@
 webkit_frame_get_type
 webkit_certificate_info_get_type
 webkit_user_content_manager_get_type
+webkit_web_hit_test_result_get_type

Added: trunk/Source/WebKit2/WebProcess/InjectedBundle/API/gtk/WebKitWebHitTestResult.cpp (0 => 175694)


--- trunk/Source/WebKit2/WebProcess/InjectedBundle/API/gtk/WebKitWebHitTestResult.cpp	                        (rev 0)
+++ trunk/Source/WebKit2/WebProcess/InjectedBundle/API/gtk/WebKitWebHitTestResult.cpp	2014-11-06 15:08:07 UTC (rev 175694)
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2014 Igalia S.L.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2,1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "WebKitWebHitTestResult.h"
+
+#include "InjectedBundleHitTestResult.h"
+#include "WebKitDOMNodePrivate.h"
+#include "WebKitPrivate.h"
+#include "WebKitWebHitTestResultPrivate.h"
+#include <glib/gi18n-lib.h>
+#include <wtf/gobject/GRefPtr.h>
+#include <wtf/text/CString.h>
+
+using namespace WebKit;
+using namespace WebCore;
+
+/**
+ * SECTION: WebKitWebHitTestResult
+ * @Short_description: Result of a Hit Test (Web Process Extensions)
+ * @Title: WebKitWebHitTestResult
+ * @See_also: #WebKitHitTestResult, #WebKitWebPage
+ *
+ * WebKitWebHitTestResult extends #WebKitHitTestResult to provide information
+ * about the #WebKitDOMNode in the coordinates of the Hit Test.
+ *
+ * Since: 2.8
+ */
+
+enum {
+    PROP_0,
+
+    PROP_NODE
+};
+
+struct _WebKitWebHitTestResultPrivate {
+    GRefPtr<WebKitDOMNode> node;
+};
+
+WEBKIT_DEFINE_TYPE(WebKitWebHitTestResult, webkit_web_hit_test_result, WEBKIT_TYPE_HIT_TEST_RESULT)
+
+static void webkitWebHitTestResultGetProperty(GObject* object, guint propId, GValue* value, GParamSpec* paramSpec)
+{
+    WebKitWebHitTestResult* webHitTestResult = WEBKIT_WEB_HIT_TEST_RESULT(object);
+
+    switch (propId) {
+    case PROP_NODE:
+        g_value_set_object(value, webkit_web_hit_test_result_get_node(webHitTestResult));
+        break;
+    default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propId, paramSpec);
+    }
+}
+
+static void webkitWebHitTestResultSetProperty(GObject* object, guint propId, const GValue* value, GParamSpec* paramSpec)
+{
+    WebKitWebHitTestResult* webHitTestResult = WEBKIT_WEB_HIT_TEST_RESULT(object);
+
+    switch (propId) {
+    case PROP_NODE: {
+        gpointer node = g_value_get_object(value);
+        webHitTestResult->priv->node = node ? WEBKIT_DOM_NODE(node) : nullptr;
+        break;
+    }
+    default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propId, paramSpec);
+    }
+}
+
+static void webkit_web_hit_test_result_class_init(WebKitWebHitTestResultClass* klass)
+{
+    GObjectClass* gObjectClass = G_OBJECT_CLASS(klass);
+
+    gObjectClass->get_property = webkitWebHitTestResultGetProperty;
+    gObjectClass->set_property = webkitWebHitTestResultSetProperty;
+
+    /**
+     * WebKitWebHitTestResult:node:
+     *
+     * The #WebKitDOMNode
+     */
+    g_object_class_install_property(
+        gObjectClass,
+        PROP_NODE,
+        g_param_spec_object(
+            "node",
+            _("Node"),
+            _("The WebKitDOMNode"),
+            WEBKIT_DOM_TYPE_NODE,
+            static_cast<GParamFlags>(WEBKIT_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)));
+}
+
+WebKitWebHitTestResult* webkitWebHitTestResultCreate(const InjectedBundleHitTestResult& hitTestResult)
+{
+    unsigned context = WEBKIT_HIT_TEST_RESULT_CONTEXT_DOCUMENT;
+    if (!hitTestResult.absoluteLinkURL().isEmpty())
+        context |= WEBKIT_HIT_TEST_RESULT_CONTEXT_LINK;
+    if (!hitTestResult.absoluteImageURL().isEmpty())
+        context |= WEBKIT_HIT_TEST_RESULT_CONTEXT_IMAGE;
+    if (!hitTestResult.absoluteMediaURL().isEmpty())
+        context |= WEBKIT_HIT_TEST_RESULT_CONTEXT_MEDIA;
+    if (hitTestResult.coreHitTestResult().isContentEditable())
+        context |= WEBKIT_HIT_TEST_RESULT_CONTEXT_EDITABLE;
+    if (hitTestResult.coreHitTestResult().scrollbar())
+        context |= WEBKIT_HIT_TEST_RESULT_CONTEXT_SCROLLBAR;
+    if (hitTestResult.isSelected())
+        context |= WEBKIT_HIT_TEST_RESULT_CONTEXT_SELECTION;
+
+    return WEBKIT_WEB_HIT_TEST_RESULT(g_object_new(WEBKIT_TYPE_WEB_HIT_TEST_RESULT,
+        "context", context,
+        "link-uri", context & WEBKIT_HIT_TEST_RESULT_CONTEXT_LINK ? hitTestResult.absoluteLinkURL().utf8().data() : nullptr,
+        "image-uri", context & WEBKIT_HIT_TEST_RESULT_CONTEXT_IMAGE ? hitTestResult.absoluteImageURL().utf8().data() : nullptr,
+        "media-uri", context & WEBKIT_HIT_TEST_RESULT_CONTEXT_MEDIA ? hitTestResult.absoluteMediaURL().utf8().data() : nullptr,
+        "link-title", !hitTestResult.linkTitle().isEmpty() ? hitTestResult.linkTitle().utf8().data() : nullptr,
+        "link-label", !hitTestResult.linkLabel().isEmpty() ? hitTestResult.linkLabel().utf8().data() : nullptr,
+        "node", kit(hitTestResult.coreHitTestResult().innerNonSharedNode()),
+        nullptr));
+}
+
+/**
+ * webkit_web_hit_test_result_get_node:
+ * @hit_test_result: a #WebKitWebHitTestResult
+ *
+ * Get the #WebKitDOMNode in the coordinates of the Hit Test.
+ *
+ * Returns: (transfer none): a #WebKitDOMNode
+ *
+ * Since: 2.8
+ */
+WebKitDOMNode* webkit_web_hit_test_result_get_node(WebKitWebHitTestResult* webHitTestResult)
+{
+    g_return_val_if_fail(WEBKIT_IS_WEB_HIT_TEST_RESULT(webHitTestResult), nullptr);
+
+    return webHitTestResult->priv->node.get();
+}

Added: trunk/Source/WebKit2/WebProcess/InjectedBundle/API/gtk/WebKitWebHitTestResult.h (0 => 175694)


--- trunk/Source/WebKit2/WebProcess/InjectedBundle/API/gtk/WebKitWebHitTestResult.h	                        (rev 0)
+++ trunk/Source/WebKit2/WebProcess/InjectedBundle/API/gtk/WebKitWebHitTestResult.h	2014-11-06 15:08:07 UTC (rev 175694)
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2014 Igalia S.L.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2,1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#if !defined(__WEBKIT_WEB_EXTENSION_H_INSIDE__) && !defined(WEBKIT2_COMPILATION)
+#error "Only <webkit2/webkit-web-extension.h> can be included directly."
+#endif
+
+#ifndef WebKitWebHitTestResult_h
+#define WebKitWebHitTestResult_h
+
+#include <glib-object.h>
+#include <webkit2/WebKitDefines.h>
+#include <webkit2/WebKitHitTestResult.h>
+#include <webkitdom/webkitdom.h>
+
+G_BEGIN_DECLS
+
+#define WEBKIT_TYPE_WEB_HIT_TEST_RESULT            (webkit_web_hit_test_result_get_type())
+#define WEBKIT_WEB_HIT_TEST_RESULT(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), WEBKIT_TYPE_WEB_HIT_TEST_RESULT, WebKitWebHitTestResult))
+#define WEBKIT_IS_WEB_HIT_TEST_RESULT(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), WEBKIT_TYPE_WEB_HIT_TEST_RESULT))
+#define WEBKIT_WEB_HIT_TEST_RESULT_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass),  WEBKIT_TYPE_WEB_HIT_TEST_RESULT, WebKitWebHitTestResultClass))
+#define WEBKIT_IS_WEB_HIT_TEST_RESULT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),  WEBKIT_TYPE_WEB_HIT_TEST_RESULT))
+#define WEBKIT_WEB_HIT_TEST_RESULT_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj),  WEBKIT_TYPE_WEB_HIT_TEST_RESULT, WebKitWebHitTestResultClass))
+
+typedef struct _WebKitWebHitTestResult        WebKitWebHitTestResult;
+typedef struct _WebKitWebHitTestResultClass   WebKitWebHitTestResultClass;
+typedef struct _WebKitWebHitTestResultPrivate WebKitWebHitTestResultPrivate;
+
+struct _WebKitWebHitTestResult {
+    WebKitHitTestResult parent;
+
+    WebKitWebHitTestResultPrivate *priv;
+};
+
+struct _WebKitWebHitTestResultClass {
+    WebKitHitTestResultClass parent_class;
+
+    void (*_webkit_reserved0) (void);
+    void (*_webkit_reserved1) (void);
+    void (*_webkit_reserved2) (void);
+    void (*_webkit_reserved3) (void);
+};
+
+WEBKIT_API GType
+webkit_web_hit_test_result_get_type (void);
+
+WEBKIT_API WebKitDOMNode *
+webkit_web_hit_test_result_get_node (WebKitWebHitTestResult *hit_test_result);
+
+G_END_DECLS
+
+#endif

Added: trunk/Source/WebKit2/WebProcess/InjectedBundle/API/gtk/WebKitWebHitTestResultPrivate.h (0 => 175694)


--- trunk/Source/WebKit2/WebProcess/InjectedBundle/API/gtk/WebKitWebHitTestResultPrivate.h	                        (rev 0)
+++ trunk/Source/WebKit2/WebProcess/InjectedBundle/API/gtk/WebKitWebHitTestResultPrivate.h	2014-11-06 15:08:07 UTC (rev 175694)
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2014 Igalia S.L.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef WebKitWebHitTestResultPrivate_h
+#define WebKitWebHitTestResultPrivate_h
+
+#include "InjectedBundleHitTestResult.h"
+#include "WebKitWebHitTestResult.h"
+
+WebKitWebHitTestResult* webkitWebHitTestResultCreate(const WebKit::InjectedBundleHitTestResult&);
+
+#endif // WebKitWebHitTestResultPrivate_h

Modified: trunk/Source/WebKit2/WebProcess/InjectedBundle/API/gtk/WebKitWebPage.cpp (175693 => 175694)


--- trunk/Source/WebKit2/WebProcess/InjectedBundle/API/gtk/WebKitWebPage.cpp	2014-11-06 10:31:53 UTC (rev 175693)
+++ trunk/Source/WebKit2/WebProcess/InjectedBundle/API/gtk/WebKitWebPage.cpp	2014-11-06 15:08:07 UTC (rev 175694)
@@ -20,12 +20,15 @@
 #include "config.h"
 #include "WebKitWebPage.h"
 
+#include "APIArray.h"
 #include "ImageOptions.h"
 #include "ImmutableDictionary.h"
 #include "InjectedBundle.h"
 #include "WKBundleAPICast.h"
 #include "WKBundleFrame.h"
+#include "WebContextMenuItem.h"
 #include "WebImage.h"
+#include "WebKitContextMenuPrivate.h"
 #include "WebKitDOMDocumentPrivate.h"
 #include "WebKitFramePrivate.h"
 #include "WebKitMarshal.h"
@@ -33,6 +36,7 @@
 #include "WebKitScriptWorldPrivate.h"
 #include "WebKitURIRequestPrivate.h"
 #include "WebKitURIResponsePrivate.h"
+#include "WebKitWebHitTestResultPrivate.h"
 #include "WebKitWebPagePrivate.h"
 #include "WebProcess.h"
 #include <WebCore/Document.h>
@@ -50,6 +54,7 @@
 enum {
     DOCUMENT_LOADED,
     SEND_REQUEST,
+    CONTEXT_MENU,
 
     LAST_SIGNAL
 };
@@ -223,6 +228,36 @@
     WebProcess::shared().injectedBundle()->postMessage(String::fromUTF8("WebPage.DidFailLoadForResource"), ImmutableDictionary::create(WTF::move(message)).get());
 }
 
+static void getContextMenuFromDefaultMenu(WKBundlePageRef, WKBundleHitTestResultRef wkHitTestResult, WKArrayRef wkDefaultMenu, WKArrayRef* wkNewMenu, WKTypeRef* wkUserData, const void* clientInfo)
+{
+    GRefPtr<WebKitContextMenu> contextMenu = adoptGRef(webkitContextMenuCreate(toImpl(wkDefaultMenu)));
+    GRefPtr<WebKitWebHitTestResult> webHitTestResult = adoptGRef(webkitWebHitTestResultCreate(*toImpl(wkHitTestResult)));
+    gboolean returnValue;
+    g_signal_emit(WEBKIT_WEB_PAGE(clientInfo), signals[CONTEXT_MENU], 0, contextMenu.get(), webHitTestResult.get(), &returnValue);
+    if (GVariant* userData = webkit_context_menu_get_user_data(contextMenu.get())) {
+        GUniquePtr<gchar> dataString(g_variant_print(userData, TRUE));
+        *wkUserData = static_cast<WKTypeRef>(WKStringCreateWithUTF8CString(dataString.get()));
+    }
+
+    if (!returnValue) {
+        WKRetain(wkDefaultMenu);
+        *wkNewMenu = wkDefaultMenu;
+        return;
+    }
+
+    Vector<ContextMenuItem> contextMenuItems;
+    webkitContextMenuPopulate(contextMenu.get(), contextMenuItems);
+
+    Vector<RefPtr<API::Object>> newMenuItems;
+    newMenuItems.reserveInitialCapacity(contextMenuItems.size());
+    for (const auto& item : contextMenuItems)
+        newMenuItems.uncheckedAppend(WebContextMenuItem::create(item));
+
+    RefPtr<API::Array> array = API::Array::create(WTF::move(newMenuItems));
+    *wkNewMenu = toAPI(array.get());
+    WKRetain(*wkNewMenu);
+}
+
 static void webkitWebPageGetProperty(GObject* object, guint propId, GValue* value, GParamSpec* paramSpec)
 {
     WebKitWebPage* webPage = WEBKIT_WEB_PAGE(object);
@@ -305,6 +340,36 @@
         G_TYPE_BOOLEAN, 2,
         WEBKIT_TYPE_URI_REQUEST,
         WEBKIT_TYPE_URI_RESPONSE);
+
+    /**
+     * WebKitWebPage::context-menu:
+     * @web_page: the #WebKitWebPage on which the signal is emitted
+     * @context_menu: the proposed #WebKitContextMenu
+     * @hit_test_result: a #WebKitWebHitTestResult
+     *
+     * Emmited before a context menu is displayed in the UI Process to
+     * give the application a chance to customize the proposed menu,
+     * build its own context menu or pass user data to the UI Process.
+     * This signal is useful when the information available in the UI Process
+     * is not enough to build or customize the context menu, for example, to
+     * add menu entries depending on the #WebKitDOMNode at the coordinates of the
+     * @hit_test_result. Otherwise, it's recommened to use #WebKitWebView::context-menu
+     * signal instead.
+     *
+     * Returns: %TRUE if the proposed @context_menu has been modified, or %FALSE otherwise.
+     *
+     * Since: 2.8
+     */
+    signals[CONTEXT_MENU] = g_signal_new(
+        "context-menu",
+        G_TYPE_FROM_CLASS(klass),
+        G_SIGNAL_RUN_LAST,
+        0,
+        g_signal_accumulator_true_handled, 0,
+        webkit_marshal_BOOLEAN__OBJECT_OBJECT,
+        G_TYPE_BOOLEAN, 2,
+        WEBKIT_TYPE_CONTEXT_MENU,
+        WEBKIT_TYPE_WEB_HIT_TEST_RESULT);
 }
 
 WebKitWebPage* webkitWebPageCreate(WebPage* webPage)
@@ -371,6 +436,15 @@
     };
     WKBundlePageSetResourceLoadClient(toAPI(webPage), &resourceLoadClient.base);
 
+    WKBundlePageContextMenuClientV0 contextMenuClient = {
+        {
+            0, // version
+            page, // clientInfo
+        },
+        getContextMenuFromDefaultMenu,
+    };
+    WKBundlePageSetContextMenuClient(toAPI(webPage), &contextMenuClient.base);
+
     return page;
 }
 

Modified: trunk/Source/WebKit2/WebProcess/InjectedBundle/API/gtk/webkit-web-extension.h (175693 => 175694)


--- trunk/Source/WebKit2/WebProcess/InjectedBundle/API/gtk/webkit-web-extension.h	2014-11-06 10:31:53 UTC (rev 175693)
+++ trunk/Source/WebKit2/WebProcess/InjectedBundle/API/gtk/webkit-web-extension.h	2014-11-06 15:08:07 UTC (rev 175694)
@@ -26,12 +26,16 @@
 
 #define __WEBKIT_WEB_EXTENSION_H_INSIDE__
 
+#include <webkit2/WebKitContextMenu.h>
+#include <webkit2/WebKitContextMenuActions.h>
+#include <webkit2/WebKitContextMenuItem.h>
 #include <webkit2/WebKitFrame.h>
 #include <webkit2/WebKitScriptWorld.h>
 #include <webkit2/WebKitURIRequest.h>
 #include <webkit2/WebKitURIResponse.h>
 #include <webkit2/WebKitVersion.h>
 #include <webkit2/WebKitWebExtension.h>
+#include <webkit2/WebKitWebHitTestResult.h>
 #include <webkit2/WebKitWebPage.h>
 
 #undef __WEBKIT_WEB_EXTENSION_H_INSIDE__

Modified: trunk/Tools/ChangeLog (175693 => 175694)


--- trunk/Tools/ChangeLog	2014-11-06 10:31:53 UTC (rev 175693)
+++ trunk/Tools/ChangeLog	2014-11-06 15:08:07 UTC (rev 175694)
@@ -1,3 +1,22 @@
+2014-11-06  Carlos Garcia Campos  <cgar...@igalia.com>
+
+        [GTK] Add context menu API to Web Process Extensions
+        https://bugs.webkit.org/show_bug.cgi?id=138311
+
+        Reviewed by Gustavo Noronha Silva.
+
+        Add tests cases for WebKitWebPage::context-menu signal.
+
+        * TestWebKitAPI/Tests/WebKit2Gtk/TestContextMenu.cpp:
+        (testContextMenuWebExtensionMenu):
+        (testContextMenuWebExtensionNode):
+        (beforeAll):
+        * TestWebKitAPI/Tests/WebKit2Gtk/WebExtensionTest.cpp:
+        (serializeContextMenu):
+        (serializeNode):
+        (contextMenuCallback):
+        (pageCreatedCallback):
+
 2014-11-06  Commit Queue  <commit-qu...@webkit.org>
 
         Unreviewed, rolling out r175690.

Modified: trunk/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestContextMenu.cpp (175693 => 175694)


--- trunk/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestContextMenu.cpp	2014-11-06 10:31:53 UTC (rev 175693)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestContextMenu.cpp	2014-11-06 15:08:07 UTC (rev 175694)
@@ -19,6 +19,7 @@
 
 #include "config.h"
 #include "WebViewTest.h"
+#include <wtf/Vector.h>
 #include <wtf/gobject/GRefPtr.h>
 
 class ContextMenuTest: public WebViewTest {
@@ -882,8 +883,164 @@
     g_assert(!GTK_IS_SEPARATOR_MENU_ITEM(item) && !gtk_widget_get_visible(item));
 }
 
+class ContextMenuWebExtensionTest: public ContextMenuTest {
+public:
+    MAKE_GLIB_TEST_FIXTURE(ContextMenuWebExtensionTest);
+
+    void deserializeContextMenuFromUserData(GVariant* userData)
+    {
+        m_actions.clear();
+        if (!userData)
+            return;
+
+        GVariantIter iter;
+        g_variant_iter_init(&iter, userData);
+        m_actions.reserveInitialCapacity(g_variant_iter_n_children(&iter));
+
+        uint32_t item;
+        while (g_variant_iter_next(&iter, "u", &item))
+            m_actions.uncheckedAppend(static_cast<WebKitContextMenuAction>(item));
+    }
+
+    bool contextMenu(WebKitContextMenu* menu, GdkEvent*, WebKitHitTestResult*)
+    {
+        deserializeContextMenuFromUserData(webkit_context_menu_get_user_data(menu));
+        GList* items = webkit_context_menu_get_items(menu);
+        g_assert_cmpuint(g_list_length(items), ==, m_actions.size());
+
+        unsigned actionIndex = 0;
+        for (GList* it = items; it; it = g_list_next(it)) {
+            WebKitContextMenuItem* item = WEBKIT_CONTEXT_MENU_ITEM(it->data);
+            g_assert_cmpuint(webkit_context_menu_item_get_stock_action(item), ==, m_actions[actionIndex++]);
+        }
+
+        quitMainLoop();
+
+        return true;
+    }
+
+    Vector<WebKitContextMenuAction> m_actions;
+};
+
+static void testContextMenuWebExtensionMenu(ContextMenuWebExtensionTest* test, gconstpointer)
+{
+    test->showInWindowAndWaitUntilMapped();
+    test->loadHtml("<html><body>WebKitGTK+ Context menu tests<br>"
+        "<a style='position:absolute; left:1; top:10' href=''>WebKitGTK+ Website</a></body></html>",
+        "ContextMenuTestDefault");
+    test->waitUntilLoadFinished();
+
+    // Default context menu.
+    test->showContextMenuAtPositionAndWaitUntilFinished(1, 1);
+    g_assert_cmpuint(test->m_actions.size(), ==, 4);
+    g_assert_cmpuint(test->m_actions[0], ==, WEBKIT_CONTEXT_MENU_ACTION_GO_BACK);
+    g_assert_cmpuint(test->m_actions[1], ==, WEBKIT_CONTEXT_MENU_ACTION_GO_FORWARD);
+    g_assert_cmpuint(test->m_actions[2], ==, WEBKIT_CONTEXT_MENU_ACTION_STOP);
+    g_assert_cmpuint(test->m_actions[3], ==, WEBKIT_CONTEXT_MENU_ACTION_RELOAD);
+
+    // Link menu.
+    test->showContextMenuAtPositionAndWaitUntilFinished(1, 11);
+    g_assert_cmpuint(test->m_actions.size(), ==, 4);
+    g_assert_cmpuint(test->m_actions[0], ==, WEBKIT_CONTEXT_MENU_ACTION_OPEN_LINK);
+    g_assert_cmpuint(test->m_actions[1], ==, WEBKIT_CONTEXT_MENU_ACTION_OPEN_LINK_IN_NEW_WINDOW);
+    g_assert_cmpuint(test->m_actions[2], ==, WEBKIT_CONTEXT_MENU_ACTION_DOWNLOAD_LINK_TO_DISK);
+    g_assert_cmpuint(test->m_actions[3], ==, WEBKIT_CONTEXT_MENU_ACTION_COPY_LINK_TO_CLIPBOARD);
+
+    // Custom menu.
+    test->loadHtml("<html><body></body></html>", "ContextMenuTestCustom");
+    test->showContextMenuAndWaitUntilFinished();
+    g_assert_cmpuint(test->m_actions.size(), ==, 4);
+    g_assert_cmpuint(test->m_actions[0], ==, WEBKIT_CONTEXT_MENU_ACTION_STOP);
+    g_assert_cmpuint(test->m_actions[1], ==, WEBKIT_CONTEXT_MENU_ACTION_RELOAD);
+    g_assert_cmpuint(test->m_actions[2], ==, WEBKIT_CONTEXT_MENU_ACTION_NO_ACTION);
+    g_assert_cmpuint(test->m_actions[3], ==, WEBKIT_CONTEXT_MENU_ACTION_INSPECT_ELEMENT);
+
+    // Menu cleared by the web process.
+    test->loadHtml("<html><body></body></html>", "ContextMenuTestClear");
+    test->showContextMenuAndWaitUntilFinished();
+    g_assert_cmpuint(test->m_actions.size(), ==, 0);
+}
+
+class ContextMenuWebExtensionNodeTest: public ContextMenuTest {
+public:
+    MAKE_GLIB_TEST_FIXTURE(ContextMenuWebExtensionNodeTest);
+
+    struct Node {
+        enum {
+            NodeUnknown = 0,
+            NodeElement = 1,
+            NodeText = 3
+        };
+        typedef unsigned Type;
+
+        CString name;
+        Type type;
+        CString contents;
+        CString parentName;
+    };
+
+    void deserializeNodeFromUserData(GVariant* userData)
+    {
+        GVariantIter iter;
+        g_variant_iter_init(&iter, userData);
+
+        const char* key;
+        GVariant* value;
+        while (g_variant_iter_next(&iter, "{&sv}", &key, &value)) {
+            if (!strcmp(key, "Name") && g_variant_classify(value) == G_VARIANT_CLASS_STRING)
+                m_node.name = g_variant_get_string(value, nullptr);
+            else if (!strcmp(key, "Type") && g_variant_classify(value) == G_VARIANT_CLASS_UINT32)
+                m_node.type = g_variant_get_uint32(value);
+            else if (!strcmp(key, "Contents") && g_variant_classify(value) == G_VARIANT_CLASS_STRING)
+                m_node.contents = g_variant_get_string(value, nullptr);
+            else if (!strcmp(key, "Parent") && g_variant_classify(value) == G_VARIANT_CLASS_STRING)
+                m_node.parentName = g_variant_get_string(value, nullptr);
+            g_variant_unref(value);
+        }
+    }
+
+    bool contextMenu(WebKitContextMenu* menu, GdkEvent*, WebKitHitTestResult*)
+    {
+        deserializeNodeFromUserData(webkit_context_menu_get_user_data(menu));
+        quitMainLoop();
+
+        return true;
+    }
+
+    Node m_node;
+};
+
+static void testContextMenuWebExtensionNode(ContextMenuWebExtensionNodeTest* test, gconstpointer)
+{
+    test->showInWindowAndWaitUntilMapped();
+    test->loadHtml("<html><body><p style='position:absolute; left:1; top:1'>WebKitGTK+ Context menu tests</p><br>"
+        "<a style='position:absolute; left:1; top:100' href=''>WebKitGTK+ Website</a></body></html>",
+        "ContextMenuTestNode");
+    test->waitUntilLoadFinished();
+
+    test->showContextMenuAtPositionAndWaitUntilFinished(0, 0);
+    g_assert_cmpstr(test->m_node.name.data(), ==, "HTML");
+    g_assert_cmpuint(test->m_node.type, ==, ContextMenuWebExtensionNodeTest::Node::NodeElement);
+    g_assert_cmpstr(test->m_node.contents.data(), ==, "WebKitGTK+ Context menu testsWebKitGTK+ Website");
+    g_assert_cmpstr(test->m_node.parentName.data(), ==, "#document");
+
+    test->showContextMenuAtPositionAndWaitUntilFinished(1, 20);
+    g_assert_cmpstr(test->m_node.name.data(), ==, "#text");
+    g_assert_cmpuint(test->m_node.type, ==, ContextMenuWebExtensionNodeTest::Node::NodeText);
+    g_assert_cmpstr(test->m_node.contents.data(), ==, "WebKitGTK+ Context menu tests");
+    g_assert_cmpstr(test->m_node.parentName.data(), ==, "P");
+
+    // Link menu.
+    test->showContextMenuAtPositionAndWaitUntilFinished(1, 101);
+    g_assert_cmpstr(test->m_node.name.data(), ==, "#text");
+    g_assert_cmpuint(test->m_node.type, ==, ContextMenuWebExtensionNodeTest::Node::NodeText);
+    g_assert_cmpstr(test->m_node.contents.data(), ==, "WebKitGTK+ Website");
+    g_assert_cmpstr(test->m_node.parentName.data(), ==, "A");
+}
+
 void beforeAll()
 {
+    webkit_web_context_set_web_extensions_directory(webkit_web_context_get_default(), WEBKIT_TEST_WEB_EXTENSIONS_DIR);
     ContextMenuDefaultTest::add("WebKitWebView", "default-menu", testContextMenuDefaultMenu);
     ContextMenuCustomTest::add("WebKitWebView", "populate-menu", testContextMenuPopulateMenu);
     ContextMenuCustomFullTest::add("WebKitWebView", "custom-menu", testContextMenuCustomMenu);
@@ -891,6 +1048,8 @@
     ContextMenuSubmenuTest::add("WebKitWebView", "submenu", testContextMenuSubMenu);
     ContextMenuDismissedTest::add("WebKitWebView", "menu-dismissed", testContextMenuDismissed);
     ContextMenuSmartSeparatorsTest::add("WebKitWebView", "smart-separators", testContextMenuSmartSeparators);
+    ContextMenuWebExtensionTest::add("WebKitWebPage", "context-menu", testContextMenuWebExtensionMenu);
+    ContextMenuWebExtensionNodeTest::add("WebKitWebPage", "context-menu-node", testContextMenuWebExtensionNode);
 }
 
 void afterAll()

Modified: trunk/Tools/TestWebKitAPI/Tests/WebKit2Gtk/WebExtensionTest.cpp (175693 => 175694)


--- trunk/Tools/TestWebKitAPI/Tests/WebKit2Gtk/WebExtensionTest.cpp	2014-11-06 10:31:53 UTC (rev 175693)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit2Gtk/WebExtensionTest.cpp	2014-11-06 15:08:07 UTC (rev 175694)
@@ -159,11 +159,67 @@
     return FALSE;
 }
 
+static GVariant* serializeContextMenu(WebKitContextMenu* menu)
+{
+    GVariantBuilder builder;
+    g_variant_builder_init(&builder, G_VARIANT_TYPE_ARRAY);
+    GList* items = webkit_context_menu_get_items(menu);
+    for (GList* it = items; it; it = g_list_next(it))
+        g_variant_builder_add(&builder, "u", webkit_context_menu_item_get_stock_action(WEBKIT_CONTEXT_MENU_ITEM(it->data)));
+    return g_variant_builder_end(&builder);
+}
+
+static GVariant* serializeNode(WebKitDOMNode* node)
+{
+    GVariantBuilder builder;
+    g_variant_builder_init(&builder, G_VARIANT_TYPE_ARRAY);
+    g_variant_builder_add(&builder, "{sv}", "Name", g_variant_new_take_string(webkit_dom_node_get_node_name(node)));
+    g_variant_builder_add(&builder, "{sv}", "Type", g_variant_new_uint32(webkit_dom_node_get_node_type(node)));
+    g_variant_builder_add(&builder, "{sv}", "Contents", g_variant_new_take_string(webkit_dom_node_get_text_content(node)));
+    WebKitDOMNode* parent = webkit_dom_node_get_parent_node(node);
+    g_variant_builder_add(&builder, "{sv}", "Parent", parent ? g_variant_new_take_string(webkit_dom_node_get_node_name(parent)) : g_variant_new_string("ROOT"));
+    return g_variant_builder_end(&builder);
+}
+
+static gboolean contextMenuCallback(WebKitWebPage* page, WebKitContextMenu* menu, WebKitWebHitTestResult* hitTestResult, gpointer)
+{
+    const char* pageURI = webkit_web_page_get_uri(page);
+    if (!g_strcmp0(pageURI, "ContextMenuTestDefault")) {
+        webkit_context_menu_set_user_data(menu, serializeContextMenu(menu));
+        return FALSE;
+    }
+
+    if (!g_strcmp0(pageURI, "ContextMenuTestCustom")) {
+        // Remove Back and Forward, and add Inspector action.
+        webkit_context_menu_remove(menu, webkit_context_menu_first(menu));
+        webkit_context_menu_remove(menu, webkit_context_menu_first(menu));
+        webkit_context_menu_append(menu, webkit_context_menu_item_new_separator());
+        webkit_context_menu_append(menu, webkit_context_menu_item_new_from_stock_action(WEBKIT_CONTEXT_MENU_ACTION_INSPECT_ELEMENT));
+        webkit_context_menu_set_user_data(menu, serializeContextMenu(menu));
+        return TRUE;
+    }
+
+    if (!g_strcmp0(pageURI, "ContextMenuTestClear")) {
+        webkit_context_menu_remove_all(menu);
+        return TRUE;
+    }
+
+    if (!g_strcmp0(pageURI, "ContextMenuTestNode")) {
+        WebKitDOMNode* node = webkit_web_hit_test_result_get_node(hitTestResult);
+        g_assert(WEBKIT_DOM_IS_NODE(node));
+        webkit_context_menu_set_user_data(menu, serializeNode(node));
+        return TRUE;
+    }
+
+    return FALSE;
+}
+
 static void pageCreatedCallback(WebKitWebExtension* extension, WebKitWebPage* webPage, gpointer)
 {
     g_signal_connect(webPage, "document-loaded", G_CALLBACK(documentLoadedCallback), extension);
     g_signal_connect(webPage, "notify::uri", G_CALLBACK(uriChangedCallback), extension);
-    g_signal_connect(webPage, "send-request", G_CALLBACK(sendRequestCallback), 0);
+    g_signal_connect(webPage, "send-request", G_CALLBACK(sendRequestCallback), nullptr);
+    g_signal_connect(webPage, "context-menu", G_CALLBACK(contextMenuCallback), nullptr);
 }
 
 static JSValueRef echoCallback(JSContextRef jsContext, JSObjectRef, JSObjectRef, size_t argumentCount, const JSValueRef arguments[], JSValueRef*)
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to