Web Inspector: introduce Page.captureScreenshot
authorpfeldman@chromium.org <pfeldman@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 20 Dec 2012 09:39:32 +0000 (09:39 +0000)
committerpfeldman@chromium.org <pfeldman@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 20 Dec 2012 09:39:32 +0000 (09:39 +0000)
https://bugs.webkit.org/show_bug.cgi?id=105315

Reviewed by Yury Semikhatsky.

Source/WebCore:

It will be primarily used by the automation clients, but maybe we find a good place
for it in the front-end as well.

* inspector/Inspector.json:
* inspector/InspectorClient.h:
(WebCore::InspectorClient::captureScreenshot):
(InspectorClient):
* inspector/InspectorPageAgent.cpp:
(WebCore::InspectorPageAgent::captureScreenshot):
(WebCore):
* inspector/InspectorPageAgent.h:

Source/WebKit/chromium:

Introduces a way for browser to handle protocol commands:
embedder will ask WebKit whether it should override the command
result and will get a hint value. Based on that hint, browser
will prepare the data and ask WebKit again to patch this data in.

* public/WebDevToolsAgent.h:
(WebDevToolsAgent):
* src/InspectorClientImpl.cpp:
(WebKit::InspectorClientImpl::captureScreenshot):
(WebKit):
* src/InspectorClientImpl.h:
(InspectorClientImpl):
* src/WebDevToolsAgentImpl.cpp:
(BrowserDataHintStringValues):
(WebKit):
(WebKit::WebDevToolsAgentImpl::WebDevToolsAgentImpl):
(WebKit::WebDevToolsAgentImpl::captureScreenshot):
(WebKit::browserHintToString):
(WebKit::browserHintFromString):
(WebKit::WebDevToolsAgentImpl::sendMessageToFrontend):
(WebKit::WebDevToolsAgent::shouldPatchWithBrowserData):
(WebKit::WebDevToolsAgent::patchWithBrowserData):
* src/WebDevToolsAgentImpl.h:
(WebDevToolsAgentImpl):

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

Source/WebCore/ChangeLog
Source/WebCore/inspector/Inspector.json
Source/WebCore/inspector/InspectorClient.h
Source/WebCore/inspector/InspectorPageAgent.cpp
Source/WebCore/inspector/InspectorPageAgent.h
Source/WebKit/chromium/ChangeLog
Source/WebKit/chromium/public/WebDevToolsAgent.h
Source/WebKit/chromium/src/InspectorClientImpl.cpp
Source/WebKit/chromium/src/InspectorClientImpl.h
Source/WebKit/chromium/src/WebDevToolsAgentImpl.cpp
Source/WebKit/chromium/src/WebDevToolsAgentImpl.h

index 6a5196f..ffa2321 100644 (file)
@@ -1,3 +1,22 @@
+2012-12-19  Pavel Feldman  <pfeldman@chromium.org>
+
+        Web Inspector: introduce Page.captureScreenshot
+        https://bugs.webkit.org/show_bug.cgi?id=105315
+
+        Reviewed by Yury Semikhatsky.
+
+        It will be primarily used by the automation clients, but maybe we find a good place
+        for it in the front-end as well.
+
+        * inspector/Inspector.json:
+        * inspector/InspectorClient.h:
+        (WebCore::InspectorClient::captureScreenshot):
+        (InspectorClient):
+        * inspector/InspectorPageAgent.cpp:
+        (WebCore::InspectorPageAgent::captureScreenshot):
+        (WebCore):
+        * inspector/InspectorPageAgent.h:
+
 2012-12-19  Carlos Garcia Campos  <cgarcia@igalia.com>
 
         Make order iterator member stack allocated in RenderFlexibleBox
index 6525ad8..37a24f1 100644 (file)
                     { "name": "visible", "type": "boolean", "description": "True for showing compositing borders." }
                 ],
                 "hidden": true
+            },
+            {
+                "name": "captureScreenshot",
+                "description": "Capture page screenshot.",
+                "returns": [
+                    { "name": "data", "type": "string", "description": "Base64-encoded image data (PNG)." }
+                ],
+                "hidden": true
             }
         ],
         "events": [
index d0c7531..948df02 100644 (file)
@@ -81,6 +81,8 @@ public:
     virtual void getAllocatedObjects(HashSet<const void*>&) { }
     virtual void dumpUncountedAllocatedObjects(const HashMap<const void*, size_t>&) { }
 
+    virtual bool captureScreenshot(String*) { return false; }
+
     static bool doDispatchMessageOnFrontendPage(Page* frontendPage, const String& message);
 };
 
index 5a3582a..f752a56 100644 (file)
@@ -1048,7 +1048,7 @@ void InspectorPageAgent::setGeolocationOverride(ErrorString* error, const double
     GeolocationController* controller = GeolocationController::from(m_page);
     GeolocationPosition* position = 0;
     if (!controller) {
-        *error = "Internal error: unable to override geolocation.";
+        *error = "Internal error: unable to override geolocation";
         return;
     }
     position = controller->lastPosition();
@@ -1063,7 +1063,7 @@ void InspectorPageAgent::setGeolocationOverride(ErrorString* error, const double
 
     controller->positionChanged(0); // Kick location update.
 #else
-    *error = "Geolocation is not available.";
+    *error = "Geolocation is not available";
     UNUSED_PARAM(latitude);
     UNUSED_PARAM(longitude);
     UNUSED_PARAM(accuracy);
@@ -1083,7 +1083,7 @@ void InspectorPageAgent::clearGeolocationOverride(ErrorString* error)
     if (controller && m_platformGeolocationPosition.get())
         controller->positionChanged(m_platformGeolocationPosition.get());
 #else
-    *error = "Geolocation is not available.";
+    *error = "Geolocation is not available";
 #endif
 }
 
@@ -1110,7 +1110,7 @@ void InspectorPageAgent::setDeviceOrientationOverride(ErrorString* error, double
 {
     DeviceOrientationController* controller = DeviceOrientationController::from(m_page);
     if (!controller) {
-        *error = "Internal error: unable to override device orientation.";
+        *error = "Internal error: unable to override device orientation";
         return;
     }
 
@@ -1182,7 +1182,7 @@ void InspectorPageAgent::getCompositingBordersVisible(ErrorString* error, bool*
 {
     Settings* settings = m_page->settings();
     if (!settings) {
-        *error = "Internal error: unable to read settings.";
+        *error = "Internal error: unable to read settings";
         return;
     }
 
@@ -1199,6 +1199,12 @@ void InspectorPageAgent::setCompositingBordersVisible(ErrorString*, bool visible
     settings->setShowRepaintCounter(visible);
 }
 
+void InspectorPageAgent::captureScreenshot(ErrorString* errorString, String* data)
+{
+    if (!m_client->captureScreenshot(data))
+        *errorString = "Could not capture screenshot";
+}
+
 } // namespace WebCore
 
 #endif // ENABLE(INSPECTOR)
index 93fed0e..a97c191 100644 (file)
@@ -123,6 +123,7 @@ public:
     virtual void setEmulatedMedia(ErrorString*, const String&);
     virtual void getCompositingBordersVisible(ErrorString*, bool* out_param);
     virtual void setCompositingBordersVisible(ErrorString*, bool);
+    virtual void captureScreenshot(ErrorString*, String* data);
 
     // Geolocation override helpers.
     GeolocationPosition* overrideGeolocationPosition(GeolocationPosition*);
index 1b029b5..950da67 100644 (file)
@@ -1,3 +1,35 @@
+2012-12-19  Pavel Feldman  <pfeldman@chromium.org>
+
+        Web Inspector: introduce Page.captureScreenshot
+        https://bugs.webkit.org/show_bug.cgi?id=105315
+
+        Reviewed by Yury Semikhatsky.
+
+        Introduces a way for browser to handle protocol commands:
+        embedder will ask WebKit whether it should override the command
+        result and will get a hint value. Based on that hint, browser
+        will prepare the data and ask WebKit again to patch this data in.
+
+        * public/WebDevToolsAgent.h:
+        (WebDevToolsAgent):
+        * src/InspectorClientImpl.cpp:
+        (WebKit::InspectorClientImpl::captureScreenshot):
+        (WebKit):
+        * src/InspectorClientImpl.h:
+        (InspectorClientImpl):
+        * src/WebDevToolsAgentImpl.cpp:
+        (BrowserDataHintStringValues):
+        (WebKit):
+        (WebKit::WebDevToolsAgentImpl::WebDevToolsAgentImpl):
+        (WebKit::WebDevToolsAgentImpl::captureScreenshot):
+        (WebKit::browserHintToString):
+        (WebKit::browserHintFromString):
+        (WebKit::WebDevToolsAgentImpl::sendMessageToFrontend):
+        (WebKit::WebDevToolsAgent::shouldPatchWithBrowserData):
+        (WebKit::WebDevToolsAgent::patchWithBrowserData):
+        * src/WebDevToolsAgentImpl.h:
+        (WebDevToolsAgentImpl):
+
 2012-12-20  Sheriff Bot  <webkit.review.bot@gmail.com>
 
         Unreviewed, rolling out r138215.
index b61105d..e97b902 100644 (file)
@@ -47,6 +47,12 @@ struct WebURLError;
 
 class WebDevToolsAgent {
 public:
+    // Hint for the browser on the data it should prepare for message patching.
+    enum BrowserDataHint {
+        BrowserDataHintNone = 0,
+        BrowserDataHintScreenshot = 1,
+    };
+
     virtual ~WebDevToolsAgent() {}
 
     // Returns WebKit WebInspector protocol version.
@@ -87,8 +93,12 @@ public:
     // in order to let it know that it has disconnected from the agent.
     WEBKIT_EXPORT static WebString workerDisconnectedFromWorkerEvent();
 
-    // FIXME: remove once migrated to workerDisconnectedFromWorkerEvent().
-    WEBKIT_EXPORT static WebString disconnectEventAsText();
+    // Determines whether given message response should be patch with the data calculatd in browser.
+    // Returns the hint on the data browser should prepare for patching.
+    WEBKIT_EXPORT static BrowserDataHint shouldPatchWithBrowserData(const char* message, size_t messageLength);
+
+    // Patches message response with the data calculated in browser.
+    WEBKIT_EXPORT static WebString patchWithBrowserData(const WebString& message, BrowserDataHint, const WebString& hintData);
 };
 
 } // namespace WebKit
index ea0d14d..bab5816 100644 (file)
@@ -189,6 +189,13 @@ void InspectorClientImpl::dumpUncountedAllocatedObjects(const HashMap<const void
         agent->dumpUncountedAllocatedObjects(map);
 }
 
+bool InspectorClientImpl::captureScreenshot(String* data)
+{
+    if (WebDevToolsAgentImpl* agent = devToolsAgent())
+        return agent->captureScreenshot(data);
+    return false;
+}
+
 WebDevToolsAgentImpl* InspectorClientImpl::devToolsAgent()
 {
     return static_cast<WebDevToolsAgentImpl*>(m_inspectedWebView->devToolsAgent());
index 25d8597..2033e3f 100644 (file)
@@ -84,6 +84,8 @@ public:
     virtual void getAllocatedObjects(HashSet<const void*>&);
     virtual void dumpUncountedAllocatedObjects(const HashMap<const void*, size_t>&);
 
+    virtual bool captureScreenshot(WTF::String* data);
+
 private:
     WebDevToolsAgentImpl* devToolsAgent();
 
index 71754e2..b58cf61 100644 (file)
@@ -40,6 +40,7 @@
 #include "InspectorController.h"
 #include "InspectorFrontend.h"
 #include "InspectorProtocolVersion.h"
+#include "InspectorValues.h"
 #include "MemoryCache.h"
 #include "Page.h"
 #include "PageGroup.h"
@@ -79,6 +80,10 @@ static const int highlight = 99;
 
 namespace WebKit {
 
+namespace BrowserDataHintStringValues {
+static const char screenshot[] = "screenshot";
+}
+
 class ClientMessageLoopAdapter : public PageScriptDebugServer::ClientMessageLoop {
 public:
     static void ensureClientMessageLoopCreated(WebDevToolsAgentClient* client)
@@ -366,6 +371,7 @@ WebDevToolsAgentImpl::WebDevToolsAgentImpl(
     , m_client(client)
     , m_webViewImpl(webViewImpl)
     , m_attached(false)
+    , m_sendWithBrowserDataHint(BrowserDataHintNone)
 {
     ASSERT(m_hostId > 0);
 }
@@ -566,6 +572,14 @@ void WebDevToolsAgentImpl::dumpUncountedAllocatedObjects(const HashMap<const voi
     m_client->dumpUncountedAllocatedObjects(&provider);
 }
 
+bool WebDevToolsAgentImpl::captureScreenshot(WTF::String* data)
+{
+    // Value is going to be substituted with the actual data on the browser level.
+    *data = "{screenshot-placeholder}";
+    m_sendWithBrowserDataHint = BrowserDataHintScreenshot;
+    return true;
+}
+
 void WebDevToolsAgentImpl::dispatchOnInspectorBackend(const WebString& message)
 {
     inspectorController()->dispatchMessageFromFrontend(message);
@@ -630,13 +644,39 @@ void WebDevToolsAgentImpl::hideHighlight()
     m_webViewImpl->removePageOverlay(this);
 }
 
+static String browserHintToString(WebDevToolsAgent::BrowserDataHint dataHint)
+{
+    switch (dataHint) {
+    case WebDevToolsAgent::BrowserDataHintScreenshot:
+        return BrowserDataHintStringValues::screenshot;
+    case WebDevToolsAgent::BrowserDataHintNone:
+    default:
+        ASSERT_NOT_REACHED();
+    }
+    return String();
+}
+
+static WebDevToolsAgent::BrowserDataHint browserHintFromString(const String& value)
+{
+    if (value == BrowserDataHintStringValues::screenshot)
+        return WebDevToolsAgent::BrowserDataHintScreenshot;
+    ASSERT_NOT_REACHED();
+    return WebDevToolsAgent::BrowserDataHintNone;
+}
+
 bool WebDevToolsAgentImpl::sendMessageToFrontend(const String& message)
 {
     WebDevToolsAgentImpl* devToolsAgent = static_cast<WebDevToolsAgentImpl*>(m_webViewImpl->devToolsAgent());
     if (!devToolsAgent)
         return false;
 
-    m_client->sendMessageToInspectorFrontend(message);
+    if (m_sendWithBrowserDataHint != BrowserDataHintNone) {
+        String prefix = browserHintToString(m_sendWithBrowserDataHint);
+        m_client->sendMessageToInspectorFrontend(makeString("<", prefix, ">", message));
+    } else
+        m_client->sendMessageToInspectorFrontend(message);
+
+    m_sendWithBrowserDataHint = BrowserDataHintNone;
     return true;
 }
 
@@ -734,10 +774,51 @@ WebString WebDevToolsAgent::workerDisconnectedFromWorkerEvent()
     return channel.m_message;
 }
 
-// FIXME: remove this once migrated to workerDisconnectedFromWorkerEvent().
-WebString WebDevToolsAgent::disconnectEventAsText()
+WebDevToolsAgent::BrowserDataHint WebDevToolsAgent::shouldPatchWithBrowserData(const char* message, size_t messageLength)
+{
+    if (!messageLength || message[0] != '<')
+        return BrowserDataHintNone;
+
+    String messageString(message, messageLength);
+    size_t hintEnd = messageString.find(">", 1);
+    if (hintEnd == notFound)
+        return BrowserDataHintNone;
+    messageString = messageString.substring(1, hintEnd - 1);
+    return browserHintFromString(messageString);
+}
+
+WebString WebDevToolsAgent::patchWithBrowserData(const WebString& message, BrowserDataHint dataHint, const WebString& hintData)
 {
-    return WebDevToolsAgent::workerDisconnectedFromWorkerEvent();
+    String messageString = message;
+    size_t hintEnd = messageString.find(">");
+    if (hintEnd == notFound) {
+        ASSERT_NOT_REACHED();
+        return message;
+    }
+
+    messageString = messageString.substring(hintEnd + 1);
+    RefPtr<InspectorValue> messageObject = InspectorValue::parseJSON(messageString);
+    if (!messageObject || messageObject->type() != InspectorValue::TypeObject) {
+        ASSERT_NOT_REACHED();
+        return messageString;
+    }
+
+    RefPtr<InspectorObject> resultObject = messageObject->asObject()->getObject("result");
+    if (!resultObject) {
+        ASSERT_NOT_REACHED();
+        return messageString;
+    }
+
+    // Patch message below.
+    switch (dataHint) {
+    case BrowserDataHintScreenshot:
+        resultObject->setString("data", hintData);
+        break;
+    case BrowserDataHintNone:
+    default:
+        ASSERT_NOT_REACHED();
+    }
+    return messageObject->toJSONString();
 }
 
 } // namespace WebKit
index 73256cf..e0f2b14 100644 (file)
@@ -110,6 +110,8 @@ public:
     virtual void getAllocatedObjects(HashSet<const void*>&);
     virtual void dumpUncountedAllocatedObjects(const HashMap<const void*, size_t>&);
 
+    virtual bool captureScreenshot(WTF::String* data);
+
     int hostId() { return m_hostId; }
 
     // WebPageOverlay
@@ -128,6 +130,7 @@ private:
     WebViewImpl* m_webViewImpl;
     bool m_attached;
     OwnPtr<DeviceMetricsSupport> m_metricsSupport;
+    BrowserDataHint m_sendWithBrowserDataHint;
 };
 
 } // namespace WebKit