Title: [148526] trunk/Source/WebKit2
Revision
148526
Author
[email protected]
Date
2013-04-16 11:29:43 -0700 (Tue, 16 Apr 2013)

Log Message

[GTK][WK2] Add API to retrieve a snapshot from a webview
https://bugs.webkit.org/show_bug.cgi?id=98270

Reviewed by Anders Carlsson.

This adds the GTK+ API necessary to retrieve a snapshot from a
webview asynchronously. The API uses the injected bundle
internally to get the snapshot from the WebProcess.

* UIProcess/API/gtk/WebKitError.cpp:
(webkit_snapshot_error_quark): Add snapshot API related error
quark.
* UIProcess/API/gtk/WebKitError.h: Add snapshot error handling.
* UIProcess/API/gtk/WebKitInjectedBundleClient.cpp:
(didReceiveWebViewMessageFromInjectedBundle): Handle the new
"DidGetSnapshot" message.
* UIProcess/API/gtk/WebKitPrivate.h: Add SnapshotRegion enum.
* UIProcess/API/gtk/WebKitWebView.cpp:
(_WebKitWebViewPrivate): Add a map for the snapshot results.
(GetSnapshotAsyncData):
(webKitWebViewDidReceiveSnapshot):
(webKitSnapshotRegionToSnapshotRegion): Helper method for casting
the region option enumeration.
(generateSnapshotCallbackID): Method to generate unique callback
ids.
(webkit_web_view_get_snapshot):
(webkit_web_view_get_snapshot_finish): New snapshotting API.
* UIProcess/API/gtk/WebKitWebView.h: Ditto.
* UIProcess/API/gtk/WebKitWebViewPrivate.h: Add the private method
to handle a received snapshot.
* UIProcess/API/gtk/docs/webkit2gtk-sections.txt: Add the new API
bits.
* UIProcess/API/gtk/tests/TestWebKitWebView.cpp:
(cairoSurfacesEqual): Add helper to compare cairo_surface_t
structs.
(testWebViewSnapshot): New test.
(beforeAll): Add the new test.
* UIProcess/API/gtk/tests/WebViewTest.cpp:
(WebViewTest::selectAll): Add method to help test snapshots
including selection.
* UIProcess/API/gtk/tests/WebViewTest.h: Ditto
* WebProcess/InjectedBundle/API/gtk/WebKitWebExtension.cpp:
(didReceiveMessageToPage): Ditto.
(webkitWebExtensionCreate): Register method above.
* WebProcess/InjectedBundle/API/gtk/WebKitWebPage.cpp:
(webkitWebPageDidReceiveMessage): Add this method. It
handles the new message "GetSnapshot".
* WebProcess/InjectedBundle/API/gtk/WebKitWebPagePrivate.h:
Add method above.

Modified Paths

Diff

Modified: trunk/Source/WebKit2/ChangeLog (148525 => 148526)


--- trunk/Source/WebKit2/ChangeLog	2013-04-16 18:25:38 UTC (rev 148525)
+++ trunk/Source/WebKit2/ChangeLog	2013-04-16 18:29:43 UTC (rev 148526)
@@ -1,3 +1,55 @@
+2013-04-16  Claudio Saavedra  <[email protected]>
+
+        [GTK][WK2] Add API to retrieve a snapshot from a webview
+        https://bugs.webkit.org/show_bug.cgi?id=98270
+
+        Reviewed by Anders Carlsson.
+
+        This adds the GTK+ API necessary to retrieve a snapshot from a
+        webview asynchronously. The API uses the injected bundle
+        internally to get the snapshot from the WebProcess.
+
+        * UIProcess/API/gtk/WebKitError.cpp:
+        (webkit_snapshot_error_quark): Add snapshot API related error
+        quark.
+        * UIProcess/API/gtk/WebKitError.h: Add snapshot error handling.
+        * UIProcess/API/gtk/WebKitInjectedBundleClient.cpp:
+        (didReceiveWebViewMessageFromInjectedBundle): Handle the new
+        "DidGetSnapshot" message.
+        * UIProcess/API/gtk/WebKitPrivate.h: Add SnapshotRegion enum.
+        * UIProcess/API/gtk/WebKitWebView.cpp:
+        (_WebKitWebViewPrivate): Add a map for the snapshot results.
+        (GetSnapshotAsyncData):
+        (webKitWebViewDidReceiveSnapshot):
+        (webKitSnapshotRegionToSnapshotRegion): Helper method for casting
+        the region option enumeration.
+        (generateSnapshotCallbackID): Method to generate unique callback
+        ids.
+        (webkit_web_view_get_snapshot):
+        (webkit_web_view_get_snapshot_finish): New snapshotting API.
+        * UIProcess/API/gtk/WebKitWebView.h: Ditto.
+        * UIProcess/API/gtk/WebKitWebViewPrivate.h: Add the private method
+        to handle a received snapshot.
+        * UIProcess/API/gtk/docs/webkit2gtk-sections.txt: Add the new API
+        bits.
+        * UIProcess/API/gtk/tests/TestWebKitWebView.cpp:
+        (cairoSurfacesEqual): Add helper to compare cairo_surface_t
+        structs.
+        (testWebViewSnapshot): New test.
+        (beforeAll): Add the new test.
+        * UIProcess/API/gtk/tests/WebViewTest.cpp:
+        (WebViewTest::selectAll): Add method to help test snapshots
+        including selection.
+        * UIProcess/API/gtk/tests/WebViewTest.h: Ditto
+        * WebProcess/InjectedBundle/API/gtk/WebKitWebExtension.cpp:
+        (didReceiveMessageToPage): Ditto.
+        (webkitWebExtensionCreate): Register method above.
+        * WebProcess/InjectedBundle/API/gtk/WebKitWebPage.cpp:
+        (webkitWebPageDidReceiveMessage): Add this method. It
+        handles the new message "GetSnapshot".
+        * WebProcess/InjectedBundle/API/gtk/WebKitWebPagePrivate.h:
+        Add method above.
+
 2013-04-16  Timothy Hatcher  <[email protected]>
 
         Create full rects for the inspector and inspected views when

Modified: trunk/Source/WebKit2/UIProcess/API/gtk/WebKitError.cpp (148525 => 148526)


--- trunk/Source/WebKit2/UIProcess/API/gtk/WebKitError.cpp	2013-04-16 18:25:38 UTC (rev 148525)
+++ trunk/Source/WebKit2/UIProcess/API/gtk/WebKitError.cpp	2013-04-16 18:29:43 UTC (rev 148526)
@@ -91,3 +91,8 @@
 {
     return g_quark_from_static_string("WebKitJavascriptError");
 }
+
+GQuark webkit_snapshot_error_quark()
+{
+    return g_quark_from_static_string("WebKitSnapshotError");
+}

Modified: trunk/Source/WebKit2/UIProcess/API/gtk/WebKitError.h (148525 => 148526)


--- trunk/Source/WebKit2/UIProcess/API/gtk/WebKitError.h	2013-04-16 18:25:38 UTC (rev 148525)
+++ trunk/Source/WebKit2/UIProcess/API/gtk/WebKitError.h	2013-04-16 18:29:43 UTC (rev 148526)
@@ -35,6 +35,7 @@
 #define WEBKIT_DOWNLOAD_ERROR   webkit_download_error_quark ()
 #define WEBKIT_PRINT_ERROR      webkit_print_error_quark ()
 #define WEBKIT_JAVASCRIPT_ERROR webkit_print_error_quark ()
+#define WEBKIT_SNAPSHOT_ERROR   webkit_snapshot_error_quark ()
 
 /**
  * WebKitNetworkError:
@@ -130,6 +131,16 @@
     WEBKIT_JAVASCRIPT_ERROR_SCRIPT_FAILED = 699
 } WebKitJavascriptError;
 
+/**
+ * WebKitSnapshotError:
+ * @WEBKIT_SNAPSHOT_ERROR_FAILED_TO_CREATE: An error occurred when creating a webpage snapshot.
+ *
+ * Enum values used to denote errors happending when creating snapshots of #WebKitWebView
+ */
+typedef enum {
+    WEBKIT_SNAPSHOT_ERROR_FAILED_TO_CREATE = 799
+} WebKitSnapshotError;
+
 WEBKIT_API GQuark
 webkit_network_error_quark    (void);
 
@@ -148,6 +159,9 @@
 WEBKIT_API GQuark
 webkit_javascript_error_quark (void);
 
+WEBKIT_API GQuark
+webkit_snapshot_error_quark   (void);
+
 G_END_DECLS
 
 #endif

Modified: trunk/Source/WebKit2/UIProcess/API/gtk/WebKitInjectedBundleClient.cpp (148525 => 148526)


--- trunk/Source/WebKit2/UIProcess/API/gtk/WebKitInjectedBundleClient.cpp	2013-04-16 18:25:38 UTC (rev 148525)
+++ trunk/Source/WebKit2/UIProcess/API/gtk/WebKitInjectedBundleClient.cpp	2013-04-16 18:29:43 UTC (rev 148526)
@@ -20,6 +20,7 @@
 #include "config.h"
 #include "WebKitInjectedBundleClient.h"
 
+#include "WebImage.h"
 #include "WebKitURIRequestPrivate.h"
 #include "WebKitURIResponsePrivate.h"
 #include "WebKitWebContextPrivate.h"
@@ -90,6 +91,10 @@
 
         webkitWebResourceFailed(resource.get(), resourceError.get());
         webkitWebViewRemoveLoadingWebResource(webView, resourceIdentifier->value());
+    } else if (g_str_equal(messageName, "DidGetSnapshot")) {
+        WebUInt64* callbackID = static_cast<WebUInt64*>(message.get("CallbackID"));
+        WebImage* image = static_cast<WebImage*>(message.get("Snapshot"));
+        webKitWebViewDidReceiveSnapshot(webView, callbackID->value(), image);
     } else
         ASSERT_NOT_REACHED();
 }

Modified: trunk/Source/WebKit2/UIProcess/API/gtk/WebKitPrivate.h (148525 => 148526)


--- trunk/Source/WebKit2/UIProcess/API/gtk/WebKitPrivate.h	2013-04-16 18:25:38 UTC (rev 148525)
+++ trunk/Source/WebKit2/UIProcess/API/gtk/WebKitPrivate.h	2013-04-16 18:29:43 UTC (rev 148526)
@@ -120,4 +120,9 @@
 unsigned wkEventModifiersToGdkModifiers(WKEventModifiers);
 unsigned wkEventMouseButtonToWebKitMouseButton(WKEventMouseButton);
 
+enum SnapshotRegion {
+    SnapshotRegionVisible,
+    SnapshotRegionFullDocument
+};
+
 #endif // WebKitPrivate_h

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


--- trunk/Source/WebKit2/UIProcess/API/gtk/WebKitWebView.cpp	2013-04-16 18:25:38 UTC (rev 148525)
+++ trunk/Source/WebKit2/UIProcess/API/gtk/WebKitWebView.cpp	2013-04-16 18:29:43 UTC (rev 148526)
@@ -21,6 +21,7 @@
 #include "config.h"
 #include "WebKitWebView.h"
 
+#include "ImageOptions.h"
 #include "PlatformCertificateInfo.h"
 #include "WebCertificateInfo.h"
 #include "WebContextMenuItem.h"
@@ -133,6 +134,7 @@
 };
 
 typedef HashMap<uint64_t, GRefPtr<WebKitWebResource> > LoadingResourcesMap;
+typedef HashMap<uint64_t, GRefPtr<GSimpleAsyncResult> > SnapshotResultsMap;
 
 struct _WebKitWebViewPrivate {
     ~_WebKitWebViewPrivate()
@@ -178,6 +180,8 @@
     GRefPtr<GCancellable> faviconCancellable;
     CString faviconURI;
     unsigned long faviconChangedHandlerID;
+
+    SnapshotResultsMap snapshotResultsMap;
 };
 
 static guint signals[LAST_SIGNAL] = { 0, };
@@ -2920,3 +2924,106 @@
 
     return !!certificateInfo.certificate();
 }
+
+struct GetSnapshotAsyncData {
+    GRefPtr<GCancellable> cancellable;
+    RefPtr<cairo_surface_t> snapshot;
+};
+WEBKIT_DEFINE_ASYNC_DATA_STRUCT(GetSnapshotAsyncData)
+
+void webKitWebViewDidReceiveSnapshot(WebKitWebView* webView, uint64_t callbackID, WebImage* webImage)
+{
+    GRefPtr<GSimpleAsyncResult> result = webView->priv->snapshotResultsMap.take(callbackID);
+    GetSnapshotAsyncData* data = ""
+    GError* error = 0;
+    if (g_cancellable_set_error_if_cancelled(data->cancellable.get(), &error))
+        g_simple_async_result_take_error(result.get(), error);
+    else if (webImage) {
+        if (RefPtr<ShareableBitmap> image = webImage->bitmap())
+            data->snapshot = image->createCairoSurface();
+    } else {
+        g_set_error_literal(&error, WEBKIT_SNAPSHOT_ERROR, WEBKIT_SNAPSHOT_ERROR_FAILED_TO_CREATE, _("There was an error creating the snapshot"));
+        g_simple_async_result_take_error(result.get(), error);
+    }
+
+    g_simple_async_result_complete(result.get());
+}
+
+COMPILE_ASSERT_MATCHING_ENUM(WEBKIT_SNAPSHOT_REGION_VISIBLE, SnapshotRegionVisible);
+COMPILE_ASSERT_MATCHING_ENUM(WEBKIT_SNAPSHOT_REGION_FULL_DOCUMENT, SnapshotRegionFullDocument);
+
+static inline unsigned webKitSnapshotOptionsToSnapshotOptions(WebKitSnapshotOptions options)
+{
+    SnapshotOptions snapshotOptions = 0;
+
+    if (!(options & WEBKIT_SNAPSHOT_OPTIONS_INCLUDE_SELECTION_HIGHLIGHTING))
+        snapshotOptions |= SnapshotOptionsExcludeSelectionHighlighting;
+
+    return snapshotOptions;
+}
+
+static inline uint64_t generateSnapshotCallbackID()
+{
+    static uint64_t uniqueCallbackID = 1;
+    return uniqueCallbackID++;
+}
+
+/**
+ * webkit_web_view_get_snapshot:
+ * @web_view: a #WebKitWebView
+ * @options: #WebKitSnapshotOptions for the snapshot
+ * @region: the #WebKitSnapshotRegion for this snapshot
+ * @cancellable: (allow-none): a #GCancellable
+ * @callback: (scope async): a #GAsyncReadyCallback
+ * @user_data: (closure): user data
+ *
+ * Asynchronously retrieves a snapshot of @web_view for @region.
+ * @options specifies how the snapshot should be rendered.
+ *
+ * When the operation is finished, @callback will be called. You must
+ * call webkit_web_view_get_snapshot_finish() to get the result of the
+ * operation.
+ */
+void webkit_web_view_get_snapshot(WebKitWebView* webView, WebKitSnapshotRegion region, WebKitSnapshotOptions options, GCancellable* cancellable, GAsyncReadyCallback callback, gpointer userData)
+{
+    g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
+
+    GRefPtr<GSimpleAsyncResult> result = adoptGRef(g_simple_async_result_new(G_OBJECT(webView), callback, userData,
+        reinterpret_cast<gpointer>(webkit_web_view_get_snapshot)));
+    GetSnapshotAsyncData* data = ""
+    data->cancellable = cancellable;
+    g_simple_async_result_set_op_res_gpointer(result.get(), data, reinterpret_cast<GDestroyNotify>(destroyGetSnapshotAsyncData));
+
+    ImmutableDictionary::MapType message;
+    uint64_t callbackID = generateSnapshotCallbackID();
+    message.set(String::fromUTF8("SnapshotOptions"), WebUInt64::create(static_cast<uint64_t>(webKitSnapshotOptionsToSnapshotOptions(options))));
+    message.set(String::fromUTF8("SnapshotRegion"), WebUInt64::create(static_cast<uint64_t>(region)));
+    message.set(String::fromUTF8("CallbackID"), WebUInt64::create(callbackID));
+
+    webView->priv->snapshotResultsMap.set(callbackID, result.get());
+    getPage(webView)->postMessageToInjectedBundle(String::fromUTF8("GetSnapshot"), ImmutableDictionary::adopt(message).get());
+}
+
+/**
+ * webkit_web_view_get_snapshot_finish:
+ * @web_view: a #WebKitWebView
+ * @result: a #GAsyncResult
+ * @error: return location for error or %NULL to ignore
+ *
+ * Finishes an asynchronous operation started with webkit_web_view_get_snapshot().
+ *
+ * Returns: (transfer full): a #cairo_surface_t with the retrieved snapshot or %NULL in error.
+ */
+cairo_surface_t* webkit_web_view_get_snapshot_finish(WebKitWebView* webView, GAsyncResult* result, GError** error)
+{
+    g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0);
+    g_return_val_if_fail(G_IS_ASYNC_RESULT(result), 0);
+
+    GSimpleAsyncResult* simple = G_SIMPLE_ASYNC_RESULT(result);
+    g_warn_if_fail(g_simple_async_result_get_source_tag(simple) == webkit_web_view_get_snapshot);
+
+    if (g_simple_async_result_propagate_error(simple, error))
+        return 0;
+
+    return cairo_surface_reference(static_cast<GetSnapshotAsyncData*>(g_simple_async_result_get_op_res_gpointer(simple))->snapshot.get());
+}

Modified: trunk/Source/WebKit2/UIProcess/API/gtk/WebKitWebView.h (148525 => 148526)


--- trunk/Source/WebKit2/UIProcess/API/gtk/WebKitWebView.h	2013-04-16 18:25:38 UTC (rev 148525)
+++ trunk/Source/WebKit2/UIProcess/API/gtk/WebKitWebView.h	2013-04-16 18:29:43 UTC (rev 148526)
@@ -159,6 +159,34 @@
     WEBKIT_VIEW_MODE_SOURCE
 } WebKitViewMode;
 
+/**
+ * WebKitSnapshotOptions:
+ * @WEBKIT_SNAPSHOT_OPTIONS_NONE: Do not include any special options.
+ * @WEBKIT_SNAPSHOT_OPTIONS_INCLUDE_SELECTION_HIGHLIGHTING: Whether to include in the
+ * snapshot the highlight of the selected content.
+ *
+ * Enum values used to specify options when taking a snapshot
+ * from a #WebKitWebView.
+ */
+typedef enum {
+  WEBKIT_SNAPSHOT_OPTIONS_NONE = 0,
+  WEBKIT_SNAPSHOT_OPTIONS_INCLUDE_SELECTION_HIGHLIGHTING = 1 << 0,
+} WebKitSnapshotOptions;
+
+/**
+ * WebKitSnapshotRegion:
+ * @WEBKIT_SNAPSHOT_REGION_VISIBLE: Specifies a snapshot only for the area that is
+ * visible in the webview
+ * @WEBKIT_SNAPSHOT_REGION_FULL_DOCUMENT: A snapshot of the entire document.
+ *
+ * Enum values used to specify the region from which to get a #WebKitWebView
+ * snapshot
+ */
+typedef enum {
+  WEBKIT_SNAPSHOT_REGION_VISIBLE = 0,
+  WEBKIT_SNAPSHOT_REGION_FULL_DOCUMENT,
+} WebKitSnapshotRegion;
+
 struct _WebKitWebView {
     WebKitWebViewBase parent;
 
@@ -418,7 +446,18 @@
 webkit_web_view_get_tls_info                         (WebKitWebView             *web_view,
                                                       GTlsCertificate          **certificate,
                                                       GTlsCertificateFlags      *errors);
+WEBKIT_API void
+webkit_web_view_get_snapshot                         (WebKitWebView             *web_view,
+                                                      WebKitSnapshotRegion       region,
+                                                      WebKitSnapshotOptions      options,
+                                                      GCancellable              *cancellable,
+                                                      GAsyncReadyCallback        callback,
+                                                      gpointer                   user_data);
 
+WEBKIT_API cairo_surface_t *
+webkit_web_view_get_snapshot_finish                  (WebKitWebView             *web_view,
+                                                      GAsyncResult              *result,
+                                                      GError                   **error);
 G_END_DECLS
 
 #endif

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


--- trunk/Source/WebKit2/UIProcess/API/gtk/WebKitWebViewPrivate.h	2013-04-16 18:25:38 UTC (rev 148525)
+++ trunk/Source/WebKit2/UIProcess/API/gtk/WebKitWebViewPrivate.h	2013-04-16 18:29:43 UTC (rev 148526)
@@ -27,6 +27,7 @@
 #ifndef WebKitWebViewPrivate_h
 #define WebKitWebViewPrivate_h
 
+#include "WebImage.h"
 #include "WebKitWebView.h"
 #include <wtf/text/CString.h>
 
@@ -50,6 +51,7 @@
 void webkitWebViewResourceLoadStarted(WebKitWebView*, WebKit::WebFrameProxy*, uint64_t resourceIdentifier, WebKitURIRequest*);
 void webkitWebViewRunFileChooserRequest(WebKitWebView*, WebKitFileChooserRequest*);
 WebKitWebResource* webkitWebViewGetLoadingWebResource(WebKitWebView*, uint64_t resourceIdentifier);
+void webKitWebViewDidReceiveSnapshot(WebKitWebView*, uint64_t callbackID, WebKit::WebImage*);
 void webkitWebViewRemoveLoadingWebResource(WebKitWebView*, uint64_t resourceIdentifier);
 bool webkitWebViewEnterFullScreen(WebKitWebView*);
 bool webkitWebViewLeaveFullScreen(WebKitWebView*);

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


--- trunk/Source/WebKit2/UIProcess/API/gtk/docs/webkit2gtk-sections.txt	2013-04-16 18:25:38 UTC (rev 148525)
+++ trunk/Source/WebKit2/UIProcess/API/gtk/docs/webkit2gtk-sections.txt	2013-04-16 18:29:43 UTC (rev 148526)
@@ -75,6 +75,8 @@
 WebKitSaveMode
 WebKitViewMode
 WebKitInsecureContentEvent
+WebKitSnapshotOptions
+WebKitSnapshotRegion
 
 <SUBSECTION Editing Commands>
 WEBKIT_EDITING_COMMAND_CUT
@@ -134,6 +136,8 @@
 webkit_web_view_set_view_mode
 webkit_web_view_get_view_mode
 webkit_web_view_get_tls_info
+webkit_web_view_get_snapshot
+webkit_web_view_get_snapshot_finish
 
 <SUBSECTION WebKitJavascriptResult>
 WebKitJavascriptResult
@@ -607,18 +611,21 @@
 WEBKIT_DOWNLOAD_ERROR
 WEBKIT_PRINT_ERROR
 WEBKIT_JAVASCRIPT_ERROR
+WEBKIT_SNAPSHOT_ERROR
 WebKitNetworkError
 WebKitPluginError
 WebKitPolicyError
 WebKitDownloadError
 WebKitPrintError
 WebKitJavascriptError
+WebKitSnapshotError
 webkit_network_error_quark
 webkit_plugin_error_quark
 webkit_policy_error_quark
 webkit_download_error_quark
 webkit_print_error_quark
 webkit_javascript_error_quark
+webkit_snapshot_error_quark
 </SECTION>
 
 <SECTION>

Modified: trunk/Source/WebKit2/UIProcess/API/gtk/tests/TestWebKitWebView.cpp (148525 => 148526)


--- trunk/Source/WebKit2/UIProcess/API/gtk/tests/TestWebKitWebView.cpp	2013-04-16 18:25:38 UTC (rev 148525)
+++ trunk/Source/WebKit2/UIProcess/API/gtk/tests/TestWebKitWebView.cpp	2013-04-16 18:29:43 UTC (rev 148526)
@@ -1146,6 +1146,135 @@
     g_assert(WebViewTest::_javascript_ResultToBoolean(_javascript_Result));
 }
 
+class SnapshotWebViewTest: public WebViewTest {
+public:
+    MAKE_GLIB_TEST_FIXTURE(SnapshotWebViewTest);
+
+    SnapshotWebViewTest()
+        : m_surface(0)
+    {
+    }
+
+    ~SnapshotWebViewTest()
+    {
+        cairo_surface_destroy(m_surface);
+    }
+
+    static void onSnapshotReady(WebKitWebView* web_view, GAsyncResult* res, SnapshotWebViewTest* test)
+    {
+        GOwnPtr<GError> error;
+        test->m_surface = webkit_web_view_get_snapshot_finish(web_view, res, &error.outPtr());
+        g_assert(!test->m_surface || !error.get());
+        if (error)
+            g_assert_error(error.get(), WEBKIT_SNAPSHOT_ERROR, WEBKIT_SNAPSHOT_ERROR_FAILED_TO_CREATE);
+        test->quitMainLoop();
+    }
+
+    cairo_surface_t* waitForSnapshot(WebKitSnapshotRegion region, WebKitSnapshotOptions options)
+    {
+        m_surface = 0;
+        webkit_web_view_get_snapshot(m_webView, region, options, 0, reinterpret_cast<GAsyncReadyCallback>(onSnapshotReady), this);
+        g_main_loop_run(m_mainLoop);
+        return cairo_surface_reference(m_surface);
+    }
+
+    static void onSnapshotCancelledReady(WebKitWebView* web_view, GAsyncResult* res, SnapshotWebViewTest* test)
+    {
+        GOwnPtr<GError> error;
+        test->m_surface = webkit_web_view_get_snapshot_finish(web_view, res, &error.outPtr());
+        g_assert(!test->m_surface);
+        g_assert_error(error.get(), G_IO_ERROR, G_IO_ERROR_CANCELLED);
+        test->quitMainLoop();
+    }
+
+    gboolean getSnapshotAndCancel()
+    {
+        m_surface = 0;
+        GRefPtr<GCancellable> cancellable = adoptGRef(g_cancellable_new());
+        webkit_web_view_get_snapshot(m_webView, WEBKIT_SNAPSHOT_REGION_VISIBLE, WEBKIT_SNAPSHOT_OPTIONS_NONE, cancellable.get(), reinterpret_cast<GAsyncReadyCallback>(onSnapshotCancelledReady), this);
+        g_cancellable_cancel(cancellable.get());
+        g_main_loop_run(m_mainLoop);
+
+        return true;
+    }
+
+    cairo_surface_t* m_surface;
+};
+
+static gboolean cairoSurfacesEqual(cairo_surface_t* s1, cairo_surface_t* s2)
+{
+    return (cairo_image_surface_get_format(s1) == cairo_image_surface_get_format(s2)
+        && cairo_image_surface_get_width(s1) == cairo_image_surface_get_width(s2)
+        && cairo_image_surface_get_height(s1) == cairo_image_surface_get_height(s2)
+        && cairo_image_surface_get_stride(s1) == cairo_image_surface_get_stride(s2)
+        && !memcmp(const_cast<const void*>(reinterpret_cast<void*>(cairo_image_surface_get_data(s1))),
+            const_cast<const void*>(reinterpret_cast<void*>(cairo_image_surface_get_data(s2))),
+            cairo_image_surface_get_height(s1)*cairo_image_surface_get_stride(s1)));
+}
+
+static void testWebViewSnapshot(SnapshotWebViewTest* test, gconstpointer)
+{
+    test->loadHtml("<html><body><p>Whatever</p></body></html>", 0);
+    test->waitUntilLoadFinished();
+
+    // WebView not visible.
+    cairo_surface_t* surface1 = test->waitForSnapshot(WEBKIT_SNAPSHOT_REGION_VISIBLE, WEBKIT_SNAPSHOT_OPTIONS_NONE);
+    g_assert(!surface1);
+
+    // Show surface, resize to 50x50, try again.
+    test->showInWindowAndWaitUntilMapped();
+    test->resizeView(50, 50);
+    surface1 = test->waitForSnapshot(WEBKIT_SNAPSHOT_REGION_VISIBLE, WEBKIT_SNAPSHOT_OPTIONS_NONE);
+    g_assert(surface1);
+
+    // obtained surface should be at the most 50x50. Store the size
+    // for comparison later.
+    int width = cairo_image_surface_get_width(surface1);
+    int height = cairo_image_surface_get_height(surface1);
+    g_assert_cmpint(width, <=, 50);
+    g_assert_cmpint(height, <=, 50);
+
+    cairo_surface_destroy(surface1);
+
+    // Select all text in the WebView, request a snapshot ignoring selection.
+    test->selectAll();
+    surface1 = test->waitForSnapshot(WEBKIT_SNAPSHOT_REGION_VISIBLE, WEBKIT_SNAPSHOT_OPTIONS_NONE);
+    g_assert(surface1);
+    g_assert_cmpint(cairo_image_surface_get_width(surface1), ==, width);
+    g_assert_cmpint(cairo_image_surface_get_height(surface1), ==, height);
+
+    // Create identical surface.
+    cairo_surface_t* surface2 = test->waitForSnapshot(WEBKIT_SNAPSHOT_REGION_VISIBLE, WEBKIT_SNAPSHOT_OPTIONS_NONE);
+    g_assert(surface2);
+
+    // Compare these two, they should be identical.
+    g_assert(cairoSurfacesEqual(surface1, surface2));
+    cairo_surface_destroy(surface2);
+
+    // Request a new snapshot, including the selection this time. The
+    // size should be the same but the result must be different to the
+    // one previously obtained.
+    surface2 = test->waitForSnapshot(WEBKIT_SNAPSHOT_REGION_VISIBLE, WEBKIT_SNAPSHOT_OPTIONS_INCLUDE_SELECTION_HIGHLIGHTING);
+    g_assert(surface2);
+    g_assert_cmpint(cairo_image_surface_get_width(surface2), ==, width);
+    g_assert_cmpint(cairo_image_surface_get_height(surface2), ==, height);
+    g_assert(!cairoSurfacesEqual(surface1, surface2));
+    cairo_surface_destroy(surface2);
+
+    // Request a snapshot of the whole document in the WebView. The
+    // result should be different from the size obtained previously.
+    surface2 = test->waitForSnapshot(WEBKIT_SNAPSHOT_REGION_FULL_DOCUMENT, WEBKIT_SNAPSHOT_OPTIONS_NONE);
+    g_assert(surface2);
+    g_assert_cmpint(cairo_image_surface_get_width(surface2),  >, width);
+    g_assert_cmpint(cairo_image_surface_get_height(surface2), >, height);
+    g_assert(!cairoSurfacesEqual(surface1, surface2));
+
+    cairo_surface_destroy(surface1);
+    cairo_surface_destroy(surface2);
+
+    g_assert(test->getSnapshotAndCancel());
+}
+
 void beforeAll()
 {
     WebViewTest::add("WebKitWebView", "default-context", testWebViewDefaultContext);
@@ -1166,6 +1295,7 @@
     FormClientTest::add("WebKitWebView", "submit-form", testWebViewSubmitForm);
     SaveWebViewTest::add("WebKitWebView", "save", testWebViewSave);
     WebViewTest::add("WebKitWebView", "view-mode", testWebViewMode);
+    SnapshotWebViewTest::add("WebKitWebView", "snapshot", testWebViewSnapshot);
     WebViewTest::add("WebKitWebView", "page-visibility", testWebViewPageVisibility);
 }
 

Modified: trunk/Source/WebKit2/UIProcess/API/gtk/tests/WebViewTest.cpp (148525 => 148526)


--- trunk/Source/WebKit2/UIProcess/API/gtk/tests/WebViewTest.cpp	2013-04-16 18:25:38 UTC (rev 148525)
+++ trunk/Source/WebKit2/UIProcess/API/gtk/tests/WebViewTest.cpp	2013-04-16 18:29:43 UTC (rev 148526)
@@ -207,6 +207,11 @@
     gtk_widget_size_allocate(GTK_WIDGET(m_webView), &allocation);
 }
 
+void WebViewTest::selectAll()
+{
+    webkit_web_view_execute_editing_command(m_webView, "SelectAll");
+}
+
 static void resourceGetDataCallback(GObject* object, GAsyncResult* result, gpointer userData)
 {
     size_t dataSize;

Modified: trunk/Source/WebKit2/UIProcess/API/gtk/tests/WebViewTest.h (148525 => 148526)


--- trunk/Source/WebKit2/UIProcess/API/gtk/tests/WebViewTest.h	2013-04-16 18:25:38 UTC (rev 148525)
+++ trunk/Source/WebKit2/UIProcess/API/gtk/tests/WebViewTest.h	2013-04-16 18:29:43 UTC (rev 148526)
@@ -49,6 +49,7 @@
     void showInWindow(GtkWindowType = GTK_WINDOW_POPUP);
     void showInWindowAndWaitUntilMapped(GtkWindowType = GTK_WINDOW_POPUP);
     void resizeView(int width, int height);
+    void selectAll();
     const char* mainResourceData(size_t& mainResourceDataSize);
 
     void mouseMoveTo(int x, int y, unsigned int mouseModifiers = 0);

Modified: trunk/Source/WebKit2/WebProcess/InjectedBundle/API/gtk/WebKitWebExtension.cpp (148525 => 148526)


--- trunk/Source/WebKit2/WebProcess/InjectedBundle/API/gtk/WebKitWebExtension.cpp	2013-04-16 18:25:38 UTC (rev 148525)
+++ trunk/Source/WebKit2/WebProcess/InjectedBundle/API/gtk/WebKitWebExtension.cpp	2013-04-16 18:29:43 UTC (rev 148526)
@@ -105,6 +105,13 @@
     webkitWebExtensionDidReceiveMessage(WEBKIT_WEB_EXTENSION(clientInfo), toImpl(name)->string(), *toImpl(static_cast<WKDictionaryRef>(messageBody)));
 }
 
+static void didReceiveMessageToPage(WKBundleRef bundle, WKBundlePageRef page, WKStringRef name, WKTypeRef messageBody, const void* clientInfo)
+{
+    ASSERT(WKGetTypeID(messageBody) == WKDictionaryGetTypeID());
+    if (WebKitWebPage* webPage = WEBKIT_WEB_EXTENSION(clientInfo)->priv->pages.get(toImpl(page)).get())
+        webkitWebPageDidReceiveMessage(webPage, toImpl(name)->string(), *toImpl(static_cast<WKDictionaryRef>(messageBody)));
+}
+
 WebKitWebExtension* webkitWebExtensionCreate(InjectedBundle* bundle)
 {
     WebKitWebExtension* extension = WEBKIT_WEB_EXTENSION(g_object_new(WEBKIT_TYPE_WEB_EXTENSION, NULL));
@@ -116,7 +123,7 @@
         willDestroyPage,
         0, // didInitializePageGroup
         didReceiveMessage,
-        0 // didReceiveMessageToPage
+        didReceiveMessageToPage
     };
     WKBundleSetClient(toAPI(bundle), &wkBundleClient);
 

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


--- trunk/Source/WebKit2/WebProcess/InjectedBundle/API/gtk/WebKitWebPage.cpp	2013-04-16 18:25:38 UTC (rev 148525)
+++ trunk/Source/WebKit2/WebProcess/InjectedBundle/API/gtk/WebKitWebPage.cpp	2013-04-16 18:29:43 UTC (rev 148526)
@@ -20,16 +20,19 @@
 #include "config.h"
 #include "WebKitWebPage.h"
 
+#include "ImageOptions.h"
 #include "ImmutableDictionary.h"
 #include "InjectedBundle.h"
 #include "WKBundleAPICast.h"
 #include "WKBundleFrame.h"
 #include "WebFrame.h"
+#include "WebImage.h"
 #include "WebKitDOMDocumentPrivate.h"
 #include "WebKitPrivate.h"
 #include "WebKitWebPagePrivate.h"
 #include "WebProcess.h"
 #include <WebCore/Frame.h>
+#include <WebCore/FrameView.h>
 
 using namespace WebKit;
 using namespace WebCore;
@@ -196,6 +199,40 @@
     return page;
 }
 
+void webkitWebPageDidReceiveMessage(WebKitWebPage* page, const String& messageName, ImmutableDictionary& message)
+{
+    if (messageName == String("GetSnapshot")) {
+        SnapshotOptions snapshotOptions = static_cast<SnapshotOptions>(static_cast<WebUInt64*>(message.get("SnapshotOptions"))->value());
+        uint64_t callbackID = static_cast<WebUInt64*>(message.get("CallbackID"))->value();
+        SnapshotRegion region = static_cast<SnapshotRegion>(static_cast<WebUInt64*>(message.get("SnapshotRegion"))->value());
+
+        RefPtr<WebImage> snapshotImage;
+        WebPage* webPage = page->priv->webPage;
+        if (WebCore::FrameView* frameView = webPage->mainFrameView()) {
+            WebCore::IntRect snapshotRect;
+            switch (region) {
+            case SnapshotRegionVisible:
+                snapshotRect = frameView->visibleContentRect(WebCore::ScrollableArea::ExcludeScrollbars);
+                break;
+            case SnapshotRegionFullDocument:
+                snapshotRect = WebCore::IntRect(WebCore::IntPoint(0, 0), frameView->contentsSize());
+                break;
+            default:
+                ASSERT_NOT_REACHED();
+            }
+            if (!snapshotRect.isEmpty())
+                snapshotImage = webPage->scaledSnapshotWithOptions(snapshotRect, 1, snapshotOptions | SnapshotOptionsShareable);
+        }
+
+        ImmutableDictionary::MapType messageReply;
+        messageReply.set("Page", webPage);
+        messageReply.set("CallbackID", WebUInt64::create(callbackID));
+        messageReply.set("Snapshot", snapshotImage);
+        WebProcess::shared().injectedBundle()->postMessage("WebPage.DidGetSnapshot", ImmutableDictionary::adopt(messageReply).get());
+    } else
+        ASSERT_NOT_REACHED();
+}
+
 /**
  * webkit_web_page_get_dom_document:
  * @web_page: a #WebKitWebPage

Modified: trunk/Source/WebKit2/WebProcess/InjectedBundle/API/gtk/WebKitWebPagePrivate.h (148525 => 148526)


--- trunk/Source/WebKit2/WebProcess/InjectedBundle/API/gtk/WebKitWebPagePrivate.h	2013-04-16 18:25:38 UTC (rev 148525)
+++ trunk/Source/WebKit2/WebProcess/InjectedBundle/API/gtk/WebKitWebPagePrivate.h	2013-04-16 18:29:43 UTC (rev 148526)
@@ -20,9 +20,11 @@
 #ifndef WebKitWebPagePrivate_h
 #define WebKitWebPagePrivate_h
 
+#include "ImmutableDictionary.h"
 #include "WebKitWebPage.h"
 #include "WebPage.h"
 
 WebKitWebPage* webkitWebPageCreate(WebKit::WebPage*);
+void webkitWebPageDidReceiveMessage(WebKitWebPage*, const String& messageName, WebKit::ImmutableDictionary& message);
 
 #endif // WebKitWebPagePrivate_h
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to