WebKit Bugzilla
Attachment 361160 Details for
Bug 194279
: Web Inspector: provide a way to capture a screenshot of a node from within the page
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Patch
bug-194279-20190204230704.patch (text/plain), 43.13 KB, created by
Devin Rousso
on 2019-02-04 23:07:04 PST
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
Devin Rousso
Created:
2019-02-04 23:07:04 PST
Size:
43.13 KB
patch
obsolete
>diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog >index 4d70226ac5b3db1084dff51990d64fae9d9b21b9..3a87a42ad8a82fffc7d15431fd61c541a52b3d16 100644 >--- a/Source/JavaScriptCore/ChangeLog >+++ b/Source/JavaScriptCore/ChangeLog >@@ -1,3 +1,28 @@ >+2019-02-04 Devin Rousso <drousso@apple.com> >+ >+ Web Inspector: provide a way to capture a screenshot of a node from within the page >+ https://bugs.webkit.org/show_bug.cgi?id=194279 >+ <rdar://problem/10731573> >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Add `console.screenshot` functionality, which displays a screenshot of a given object (if >+ able) within Web Inspector's Console tab. From there, it can be viewed and saved. >+ >+ Currently, `console.screenshot` will only have an effect if given a `Node`. >+ >+ * inspector/protocol/Page.json: >+ Add `consoleScreenshotted` event. >+ >+ * runtime/ConsoleClient.h: >+ * runtime/ConsoleObject.cpp: >+ (JSC::ConsoleObject::finishCreation): >+ (JSC::consoleProtoFuncScreenshot): Added. >+ >+ * inspector/JSGlobalObjectConsoleClient.h: >+ * inspector/JSGlobalObjectConsoleClient.cpp: >+ (Inspector::JSGlobalObjectConsoleClient::screenshot): Added. >+ > 2019-02-04 Robin Morisset <rmorisset@apple.com> > > when lowering AssertNotEmpty, create the value before creating the patchpoint >diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog >index f6fb51c05f13f20c7b913ce85939db4dd1f6f86a..c627650a203cde578d9ad98f1511bb2855288311 100644 >--- a/Source/WebCore/ChangeLog >+++ b/Source/WebCore/ChangeLog >@@ -1,3 +1,38 @@ >+2019-02-04 Devin Rousso <drousso@apple.com> >+ >+ Web Inspector: provide a way to capture a screenshot of a node from within the page >+ https://bugs.webkit.org/show_bug.cgi?id=194279 >+ <rdar://problem/10731573> >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Test: inspector/console/console-screenshot.html >+ >+ Add `console.screenshot` functionality, which displays a screenshot of a given object (if >+ able) within Web Inspector's Console tab. From there, it can be viewed and saved. >+ >+ Currently, `console.screenshot` will only have an effect if given a `Node`. >+ >+ * inspector/agents/InspectorPageAgent.h: >+ * inspector/agents/InspectorPageAgent.cpp: >+ (WebCore::InspectorPageAgent::consoleScreenshot): Added. >+ >+ * inspector/InspectorInstrumentation.h: >+ (WebCore::InspectorInstrumentation::consoleScreenshot): Added. >+ * inspector/InspectorInstrumentation.cpp: >+ (WebCore::InspectorInstrumentation::consoleScreenshotImpl): Added. >+ >+ * page/PageConsoleClient.h: >+ * page/PageConsoleClient.cpp: >+ (WebCore::PageConsoleClient::screenshot): Added. >+ >+ * workers/WorkerConsoleClient.h: >+ * workers/WorkerConsoleClient.cpp: >+ (WebCore::WorkerConsoleClient::screenshot): Added. >+ * worklets/WorkletConsoleClient.h: >+ * worklets/WorkletConsoleClient.cpp: >+ (WebCore::WorkletConsoleClient::screenshot): Added. >+ > 2019-02-04 Fujii Hironori <Hironori.Fujii@sony.com> > > [curl] ASSERTION FAILED: !m_didNotifyResponse || m_multipartHandle >diff --git a/Source/WebInspectorUI/ChangeLog b/Source/WebInspectorUI/ChangeLog >index 630bec4dfb6c1eba5909bffb509c133e6ba5b701..5e86045ec4e6105b9f7f00a3402df2a4bf9ff14a 100644 >--- a/Source/WebInspectorUI/ChangeLog >+++ b/Source/WebInspectorUI/ChangeLog >@@ -1,3 +1,48 @@ >+2019-02-04 Devin Rousso <drousso@apple.com> >+ >+ Web Inspector: provide a way to capture a screenshot of a node from within the page >+ https://bugs.webkit.org/show_bug.cgi?id=194279 >+ <rdar://problem/10731573> >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Add `console.screenshot` functionality, which displays a screenshot of a given object (if >+ able) within Web Inspector's Console tab. From there, it can be viewed and saved. >+ >+ Currently, `console.screenshot` will only have an effect if given a `Node`. >+ >+ * UserInterface/Protocol/PageObserver.js: >+ (WI.PageObserver.prototype.consoleScreenshotted): Added. >+ * UserInterface/Controllers/ConsoleManager.js: >+ (WI.ConsoleManager.prototype.consoleScreenshotted): Added. >+ >+ * UserInterface/Models/ConsoleMessage.js: >+ * UserInterface/Models/IssueMessage.js: >+ * UserInterface/Views/ConsoleCommandView.js: >+ * UserInterface/Views/LogContentView.css: >+ * UserInterface/Views/ConsoleMessageView.js: >+ (WI.ConsoleMessageView.prototype.render): >+ (WI.ConsoleMessageView.prototype._appendMessageTextAndArguments): >+ (WI.ConsoleMessageView.prototype._handleContextMenu): Added. >+ * UserInterface/Views/ConsoleMessageView.css: >+ (.console-message-body > img): Added. >+ (.console-message-body > .show-grid): Added. >+ Renamed (removed ChangeLog entries for simplicity/clarity) >+ - `messageText` to `data` (JS) >+ - `_messageTextElement` to `_messageBodyElement` (JS) >+ - `.console-message-text` to `.console-message-body` (CSS) >+ to be more semantically correct when the content is an image. >+ >+ * UserInterface/Controllers/JavaScriptLogViewController.js: >+ (WI.JavaScriptLogViewController.prototype.renderPendingMessages): >+ >+ * UserInterface/Views/Main.css: >+ (:matches(img, canvas).show-grid): >+ (@media (prefers-color-scheme: dark) :matches(img, canvas).show-grid): >+ >+ * UserInterface/Models/NativeFunctionParameters.js: >+ * Localizations/en.lproj/localizedStrings.js: >+ > 2019-02-04 Devin Rousso <drousso@apple.com> > > Web Inspector: Resources: missing resource data for document on reload >diff --git a/Source/JavaScriptCore/inspector/JSGlobalObjectConsoleClient.cpp b/Source/JavaScriptCore/inspector/JSGlobalObjectConsoleClient.cpp >index 096b9b7b7f0edccbec279bf161b53cfdb3a1c2fa..1318339ef67601ffcefcc5eb357d1bcfd10b9f7d 100644 >--- a/Source/JavaScriptCore/inspector/JSGlobalObjectConsoleClient.cpp >+++ b/Source/JavaScriptCore/inspector/JSGlobalObjectConsoleClient.cpp >@@ -168,6 +168,8 @@ void JSGlobalObjectConsoleClient::timeStamp(ExecState*, Ref<ScriptArguments>&&) > void JSGlobalObjectConsoleClient::record(ExecState*, Ref<ScriptArguments>&&) { } > void JSGlobalObjectConsoleClient::recordEnd(ExecState*, Ref<ScriptArguments>&&) { } > >+void JSGlobalObjectConsoleClient::screenshot(ExecState*, Ref<ScriptArguments>&&) { } >+ > void JSGlobalObjectConsoleClient::warnUnimplemented(const String& method) > { > String message = method + " is currently ignored in JavaScript context inspection."; >diff --git a/Source/JavaScriptCore/inspector/JSGlobalObjectConsoleClient.h b/Source/JavaScriptCore/inspector/JSGlobalObjectConsoleClient.h >index 448917ebfa32e8ac17be6439f7200655bda47996..2e169c25c60d589896160faaff1b1592e726e324 100644 >--- a/Source/JavaScriptCore/inspector/JSGlobalObjectConsoleClient.h >+++ b/Source/JavaScriptCore/inspector/JSGlobalObjectConsoleClient.h >@@ -55,6 +55,7 @@ protected: > void timeStamp(JSC::ExecState*, Ref<ScriptArguments>&&) override; > void record(JSC::ExecState*, Ref<ScriptArguments>&&) override; > void recordEnd(JSC::ExecState*, Ref<ScriptArguments>&&) override; >+ void screenshot(JSC::ExecState*, Ref<ScriptArguments>&&) override; > > private: > void warnUnimplemented(const String& method); >diff --git a/Source/JavaScriptCore/inspector/protocol/Page.json b/Source/JavaScriptCore/inspector/protocol/Page.json >index 769bf4b3b8f98e6c4ed39f5506955727e72f0815..39f6ff3f92fe499b0342f9bf50fe07a2179037c2 100644 >--- a/Source/JavaScriptCore/inspector/protocol/Page.json >+++ b/Source/JavaScriptCore/inspector/protocol/Page.json >@@ -344,6 +344,13 @@ > "parameters": [ > { "name": "appearance", "$ref": "Appearance", "description": "Name of the appearance that is active (not considering any forced appearance.)" } > ] >+ }, >+ { >+ "name": "consoleScreenshotted", >+ "description": "Fired when a node is passed into console.screenshot.", >+ "parameters": [ >+ { "name": "dataURL", "type": "string", "description": "Base64 encoded image data (PNG)." } >+ ] > } > ] > } >diff --git a/Source/JavaScriptCore/runtime/ConsoleClient.h b/Source/JavaScriptCore/runtime/ConsoleClient.h >index 852c193fa3bc72bc3451f406389a59ebb52f9a37..53abb50e9fc48db1cec080e9202768cec5ff915d 100644 >--- a/Source/JavaScriptCore/runtime/ConsoleClient.h >+++ b/Source/JavaScriptCore/runtime/ConsoleClient.h >@@ -64,6 +64,7 @@ public: > virtual void timeStamp(ExecState*, Ref<Inspector::ScriptArguments>&&) = 0; > virtual void record(ExecState*, Ref<Inspector::ScriptArguments>&&) = 0; > virtual void recordEnd(ExecState*, Ref<Inspector::ScriptArguments>&&) = 0; >+ virtual void screenshot(ExecState*, Ref<Inspector::ScriptArguments>&&) = 0; > > private: > enum ArgumentRequirement { ArgumentRequired, ArgumentNotRequired }; >diff --git a/Source/JavaScriptCore/runtime/ConsoleObject.cpp b/Source/JavaScriptCore/runtime/ConsoleObject.cpp >index 417d6404fa81f814a7f779ce72048bb5f85ccf76..37c40d3ab7d3acfa2af6e125bd4052c4779c0ff7 100644 >--- a/Source/JavaScriptCore/runtime/ConsoleObject.cpp >+++ b/Source/JavaScriptCore/runtime/ConsoleObject.cpp >@@ -59,6 +59,7 @@ static EncodedJSValue JSC_HOST_CALL consoleProtoFuncGroupCollapsed(ExecState*); > static EncodedJSValue JSC_HOST_CALL consoleProtoFuncGroupEnd(ExecState*); > static EncodedJSValue JSC_HOST_CALL consoleProtoFuncRecord(ExecState*); > static EncodedJSValue JSC_HOST_CALL consoleProtoFuncRecordEnd(ExecState*); >+static EncodedJSValue JSC_HOST_CALL consoleProtoFuncScreenshot(ExecState*); > > const ClassInfo ConsoleObject::s_info = { "Console", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(ConsoleObject) }; > >@@ -99,6 +100,7 @@ void ConsoleObject::finishCreation(VM& vm, JSGlobalObject* globalObject) > JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("groupEnd", consoleProtoFuncGroupEnd, static_cast<unsigned>(PropertyAttribute::None), 0); > JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("record", consoleProtoFuncRecord, static_cast<unsigned>(PropertyAttribute::None), 0); > JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("recordEnd", consoleProtoFuncRecordEnd, static_cast<unsigned>(PropertyAttribute::None), 0); >+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("screenshot", consoleProtoFuncScreenshot, static_cast<unsigned>(PropertyAttribute::None), 0); > } > > static String valueToStringWithUndefinedOrNullCheck(ExecState* exec, JSValue value) >@@ -391,4 +393,14 @@ static EncodedJSValue JSC_HOST_CALL consoleProtoFuncRecordEnd(ExecState* exec) > return JSValue::encode(jsUndefined()); > } > >+static EncodedJSValue JSC_HOST_CALL consoleProtoFuncScreenshot(ExecState* exec) >+{ >+ ConsoleClient* client = exec->lexicalGlobalObject()->consoleClient(); >+ if (!client) >+ return JSValue::encode(jsUndefined()); >+ >+ client->screenshot(exec, Inspector::createScriptArguments(exec, 0)); >+ return JSValue::encode(jsUndefined()); >+} >+ > } // namespace JSC >diff --git a/Source/WebCore/inspector/InspectorInstrumentation.cpp b/Source/WebCore/inspector/InspectorInstrumentation.cpp >index 2b430629b8633da0a191e6943fc7bad536107e9b..c1dcaebd1a4eabd4eb8fd579fdda5636540d67da 100644 >--- a/Source/WebCore/inspector/InspectorInstrumentation.cpp >+++ b/Source/WebCore/inspector/InspectorInstrumentation.cpp >@@ -899,6 +899,12 @@ void InspectorInstrumentation::consoleStartRecordingCanvasImpl(InstrumentingAgen > canvasAgent->consoleStartRecordingCanvas(context, exec, options); > } > >+void InspectorInstrumentation::consoleScreenshotImpl(InstrumentingAgents& instrumentingAgents, Node& node) >+{ >+ if (auto* pageAgent = instrumentingAgents.inspectorPageAgent()) >+ pageAgent->consoleScreenshot(node); >+} >+ > void InspectorInstrumentation::didOpenDatabaseImpl(InstrumentingAgents& instrumentingAgents, RefPtr<Database>&& database, const String& domain, const String& name, const String& version) > { > if (!instrumentingAgents.inspectorEnvironment().developerExtrasEnabled()) >diff --git a/Source/WebCore/inspector/InspectorInstrumentation.h b/Source/WebCore/inspector/InspectorInstrumentation.h >index efe265a4e070f12b5499ebd82dd2fb39b66b834d..2580c7b5e8716c4151a0798692422921b329efa0 100644 >--- a/Source/WebCore/inspector/InspectorInstrumentation.h >+++ b/Source/WebCore/inspector/InspectorInstrumentation.h >@@ -231,6 +231,7 @@ public: > static void startProfiling(Page&, JSC::ExecState*, const String& title); > static void stopProfiling(Page&, JSC::ExecState*, const String& title); > static void consoleStartRecordingCanvas(CanvasRenderingContext&, JSC::ExecState&, JSC::JSObject* options); >+ static void consoleScreenshot(Node&); > > static void didRequestAnimationFrame(Document&, int callbackId); > static void didCancelAnimationFrame(Document&, int callbackId); >@@ -408,6 +409,7 @@ private: > static void startProfilingImpl(InstrumentingAgents&, JSC::ExecState*, const String& title); > static void stopProfilingImpl(InstrumentingAgents&, JSC::ExecState*, const String& title); > static void consoleStartRecordingCanvasImpl(InstrumentingAgents&, CanvasRenderingContext&, JSC::ExecState&, JSC::JSObject* options); >+ static void consoleScreenshotImpl(InstrumentingAgents&, Node&); > > static void didRequestAnimationFrameImpl(InstrumentingAgents&, int callbackId, Document&); > static void didCancelAnimationFrameImpl(InstrumentingAgents&, int callbackId, Document&); >@@ -1420,6 +1422,13 @@ inline void InspectorInstrumentation::consoleStartRecordingCanvas(CanvasRenderin > consoleStartRecordingCanvasImpl(*instrumentingAgents, context, exec, options); > } > >+inline void InspectorInstrumentation::consoleScreenshot(Node& node) >+{ >+ FAST_RETURN_IF_NO_FRONTENDS(void()); >+ if (auto* instrumentingAgents = instrumentingAgentsForDocument(node.document())) >+ consoleScreenshotImpl(*instrumentingAgents, node); >+} >+ > inline void InspectorInstrumentation::didRequestAnimationFrame(Document& document, int callbackId) > { > if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForDocument(document)) >diff --git a/Source/WebCore/inspector/agents/InspectorPageAgent.cpp b/Source/WebCore/inspector/agents/InspectorPageAgent.cpp >index 1333aa937d4070cbbb77315ec9d76ce3f5323fee..a5bbe5380fd2bcd8fca7d4ac22ebf9c5a4aada0c 100644 >--- a/Source/WebCore/inspector/agents/InspectorPageAgent.cpp >+++ b/Source/WebCore/inspector/agents/InspectorPageAgent.cpp >@@ -34,6 +34,7 @@ > > #include "CachedResource.h" > #include "CachedResourceLoader.h" >+#include "CanvasRenderingContext.h" > #include "Cookie.h" > #include "CookieJar.h" > #include "Document.h" >@@ -45,7 +46,9 @@ > #include "FrameView.h" > #include "HTMLFrameOwnerElement.h" > #include "HTMLNames.h" >+#include "ImageBitmap.h" > #include "ImageBuffer.h" >+#include "ImageData.h" > #include "InspectorClient.h" > #include "InspectorDOMAgent.h" > #include "InspectorNetworkAgent.h" >@@ -798,6 +801,15 @@ void InspectorPageAgent::didRecalculateStyle() > m_overlay->update(); > } > >+void InspectorPageAgent::consoleScreenshot(Node& node) >+{ >+ std::unique_ptr<ImageBuffer> snapshot = WebCore::snapshotNode(mainFrame(), node); >+ if (!snapshot) >+ return; >+ >+ m_frontendDispatcher->consoleScreenshotted(snapshot->toDataURL("image/png"_s, WTF::nullopt, PreserveResolution::Yes)); >+} >+ > Ref<Inspector::Protocol::Page::Frame> InspectorPageAgent::buildObjectForFrame(Frame* frame) > { > ASSERT_ARG(frame, frame); >diff --git a/Source/WebCore/inspector/agents/InspectorPageAgent.h b/Source/WebCore/inspector/agents/InspectorPageAgent.h >index 9bfa2bb966259add54fd5433f92ef4c76da00d58..1fc3483d96d9da57dcf3e2ffbb27282bcf2f0c8a 100644 >--- a/Source/WebCore/inspector/agents/InspectorPageAgent.h >+++ b/Source/WebCore/inspector/agents/InspectorPageAgent.h >@@ -125,6 +125,7 @@ public: > void didLayout(); > void didScroll(); > void didRecalculateStyle(); >+ void consoleScreenshot(Node&); > > // Inspector Controller API > void didCreateFrontendAndBackend(Inspector::FrontendRouter*, Inspector::BackendDispatcher*) final; >diff --git a/Source/WebCore/page/PageConsoleClient.cpp b/Source/WebCore/page/PageConsoleClient.cpp >index 9f65531480c5cbcf4d33cf2caa33577b4d92a2d6..689486c469d1e55674c4135079490c1e7a8c2635 100644 >--- a/Source/WebCore/page/PageConsoleClient.cpp >+++ b/Source/WebCore/page/PageConsoleClient.cpp >@@ -42,7 +42,9 @@ > #include "JSExecState.h" > #include "JSHTMLCanvasElement.h" > #include "JSImageBitmapRenderingContext.h" >+#include "JSNode.h" > #include "JSOffscreenCanvas.h" >+#include "Node.h" > #include "OffscreenCanvas.h" > #include "Page.h" > #include "ScriptableDocumentParser.h" >@@ -258,4 +260,14 @@ void PageConsoleClient::recordEnd(JSC::ExecState* state, Ref<ScriptArguments>&& > InspectorInstrumentation::didFinishRecordingCanvasFrame(*context, true); > } > >+void PageConsoleClient::screenshot(JSC::ExecState* state, Ref<ScriptArguments>&& arguments) >+{ >+ auto* target = objectArgumentAt(arguments, 0); >+ if (!target) >+ return; >+ >+ if (auto* node = JSNode::toWrapped(state->vm(), target)) >+ InspectorInstrumentation::consoleScreenshot(*node); >+} >+ > } // namespace WebCore >diff --git a/Source/WebCore/page/PageConsoleClient.h b/Source/WebCore/page/PageConsoleClient.h >index ba6140d1404de79260f741f6b0fe4ba1a04bfa6e..52c2fdc9ac83e0f46253ad9dc9b1303ca79dd9d6 100644 >--- a/Source/WebCore/page/PageConsoleClient.h >+++ b/Source/WebCore/page/PageConsoleClient.h >@@ -76,6 +76,7 @@ protected: > void timeStamp(JSC::ExecState*, Ref<Inspector::ScriptArguments>&&) override; > void record(JSC::ExecState*, Ref<Inspector::ScriptArguments>&&) override; > void recordEnd(JSC::ExecState*, Ref<Inspector::ScriptArguments>&&) override; >+ void screenshot(JSC::ExecState*, Ref<Inspector::ScriptArguments>&&) override; > > private: > Page& m_page; >diff --git a/Source/WebCore/workers/WorkerConsoleClient.cpp b/Source/WebCore/workers/WorkerConsoleClient.cpp >index c354a5631b0a2678f04d638b69723710b120d6d5..bab2da66329cfaeeca2ae25c54ad54a281d8617b 100644 >--- a/Source/WebCore/workers/WorkerConsoleClient.cpp >+++ b/Source/WebCore/workers/WorkerConsoleClient.cpp >@@ -76,4 +76,6 @@ void WorkerConsoleClient::timeStamp(JSC::ExecState*, Ref<ScriptArguments>&&) { } > void WorkerConsoleClient::record(JSC::ExecState*, Ref<ScriptArguments>&&) { } > void WorkerConsoleClient::recordEnd(JSC::ExecState*, Ref<ScriptArguments>&&) { } > >+void WorkerConsoleClient::screenshot(JSC::ExecState*, Ref<ScriptArguments>&&) { } >+ > } // namespace WebCore >diff --git a/Source/WebCore/workers/WorkerConsoleClient.h b/Source/WebCore/workers/WorkerConsoleClient.h >index 1f79bf94a977d0bb923c2794cc28511d9f333e2e..ef38587471bbab24cf94c4a25d53e61d2c7c7e92 100644 >--- a/Source/WebCore/workers/WorkerConsoleClient.h >+++ b/Source/WebCore/workers/WorkerConsoleClient.h >@@ -52,6 +52,7 @@ protected: > void timeStamp(JSC::ExecState*, Ref<Inspector::ScriptArguments>&&) override; > void record(JSC::ExecState*, Ref<Inspector::ScriptArguments>&&) override; > void recordEnd(JSC::ExecState*, Ref<Inspector::ScriptArguments>&&) override; >+ void screenshot(JSC::ExecState*, Ref<Inspector::ScriptArguments>&&) override; > > private: > WorkerGlobalScope& m_workerGlobalScope; >diff --git a/Source/WebCore/worklets/WorkletConsoleClient.cpp b/Source/WebCore/worklets/WorkletConsoleClient.cpp >index 89506b9e393134cec33636ca66f1c5dc24b88182..5dcb68e07b243cacaf7ddbcb4d9c493beb835534 100644 >--- a/Source/WebCore/worklets/WorkletConsoleClient.cpp >+++ b/Source/WebCore/worklets/WorkletConsoleClient.cpp >@@ -66,5 +66,7 @@ void WorkletConsoleClient::timeStamp(JSC::ExecState*, Ref<ScriptArguments>&&) { > void WorkletConsoleClient::record(JSC::ExecState*, Ref<ScriptArguments>&&) { } > void WorkletConsoleClient::recordEnd(JSC::ExecState*, Ref<ScriptArguments>&&) { } > >+void WorkletConsoleClient::screenshot(JSC::ExecState*, Ref<ScriptArguments>&&) { } >+ > } // namespace WebCore > #endif >diff --git a/Source/WebCore/worklets/WorkletConsoleClient.h b/Source/WebCore/worklets/WorkletConsoleClient.h >index 520f75960ff8b768e1c6c40f5d1929eb0864239b..7a581c804e039c2f3123aa01ff969b1f802fe578 100644 >--- a/Source/WebCore/worklets/WorkletConsoleClient.h >+++ b/Source/WebCore/worklets/WorkletConsoleClient.h >@@ -54,6 +54,7 @@ private: > void timeStamp(JSC::ExecState*, Ref<Inspector::ScriptArguments>&&) final; > void record(JSC::ExecState*, Ref<Inspector::ScriptArguments>&&) final; > void recordEnd(JSC::ExecState*, Ref<Inspector::ScriptArguments>&&) final; >+ void screenshot(JSC::ExecState*, Ref<Inspector::ScriptArguments>&&) final; > > WorkletGlobalScope& m_workletGlobalScope; > }; >diff --git a/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js b/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js >index d8c79558caadaefbeb25f954bdbfb8499d5091ad..9f3b376c246798ee1955c9fcda250b39f9a7b397 100644 >--- a/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js >+++ b/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js >@@ -807,6 +807,7 @@ localizedStrings["Running the \u201C%s\u201D audit"] = "Running the \u201C%s\u20 > localizedStrings["Samples"] = "Samples"; > localizedStrings["Save %d"] = "Save %d"; > localizedStrings["Save File"] = "Save File"; >+localizedStrings["Save Image"] = "Save Image"; > localizedStrings["Save Selected"] = "Save Selected"; > localizedStrings["Save configuration"] = "Save configuration"; > localizedStrings["Saved States"] = "Saved States"; >diff --git a/Source/WebInspectorUI/UserInterface/Controllers/ConsoleManager.js b/Source/WebInspectorUI/UserInterface/Controllers/ConsoleManager.js >index bc56eb1c98edc1bfb8d2727ca289f8dda6165194..01ade55e71618a6c03466114e8666db37bf361de 100644 >--- a/Source/WebInspectorUI/UserInterface/Controllers/ConsoleManager.js >+++ b/Source/WebInspectorUI/UserInterface/Controllers/ConsoleManager.js >@@ -120,6 +120,15 @@ WI.ConsoleManager = class ConsoleManager extends WI.Object > } > } > >+ consoleScreenshotted(dataURL) >+ { >+ // Called from WI.PageObserver. >+ >+ let message = new WI.ConsoleMessage(WI.mainTarget, WI.ConsoleMessage.MessageSource.ConsoleAPI, WI.ConsoleMessage.MessageLevel.Log, dataURL, WI.ConsoleMessage.MessageType.Image); >+ >+ this.dispatchEventToListeners(WI.ConsoleManager.Event.MessageAdded, {message}); >+ } >+ > _delayedMessagesCleared() > { > if (this._isNewPageOrReload) { >diff --git a/Source/WebInspectorUI/UserInterface/Controllers/JavaScriptLogViewController.js b/Source/WebInspectorUI/UserInterface/Controllers/JavaScriptLogViewController.js >index d293c14a2f830497125b8656be9635b81e40ff59..71245b568e7e7ea27def7dc1456d97f121ff2bd6 100644 >--- a/Source/WebInspectorUI/UserInterface/Controllers/JavaScriptLogViewController.js >+++ b/Source/WebInspectorUI/UserInterface/Controllers/JavaScriptLogViewController.js >@@ -322,7 +322,7 @@ WI.JavaScriptLogViewController = class JavaScriptLogViewController extends WI.Ob > > this._currentSessionOrGroup = savedCurrentConsoleGroup; > >- if (wasScrolledToBottom || lastMessageView instanceof WI.ConsoleCommandView || lastMessageView.message.type === WI.ConsoleMessage.MessageType.Result) >+ if (wasScrolledToBottom || lastMessageView instanceof WI.ConsoleCommandView || lastMessageView.message.type === WI.ConsoleMessage.MessageType.Result || lastMessageView.message.type === WI.ConsoleMessage.MessageType.Image) > this.scrollToBottom(); > > WI.quickConsole.needsLayout(); >diff --git a/Source/WebInspectorUI/UserInterface/Models/ConsoleMessage.js b/Source/WebInspectorUI/UserInterface/Models/ConsoleMessage.js >index d061d52fd55171419e87b77ff844148dbb20c18c..65b575791a6d5bb6b3fc60119745b73f1e1ec2a0 100644 >--- a/Source/WebInspectorUI/UserInterface/Models/ConsoleMessage.js >+++ b/Source/WebInspectorUI/UserInterface/Models/ConsoleMessage.js >@@ -25,18 +25,18 @@ > > WI.ConsoleMessage = class ConsoleMessage > { >- constructor(target, source, level, message, type, url, line, column, repeatCount, parameters, callFrames, request) >+ constructor(target, source, level, data, type, url, line, column, repeatCount, parameters, callFrames, request) > { > console.assert(typeof source === "string"); > console.assert(typeof level === "string"); >- console.assert(typeof message === "string"); >+ console.assert(typeof data === "string"); > console.assert(target instanceof WI.Target); > console.assert(!parameters || parameters.every((x) => x instanceof WI.RemoteObject)); > > this._target = target; > this._source = source; > this._level = level; >- this._messageText = message; >+ this._data = data; > this._type = type || WI.ConsoleMessage.MessageType.Log; > > this._url = url || null; >@@ -58,7 +58,7 @@ WI.ConsoleMessage = class ConsoleMessage > get target() { return this._target; } > get source() { return this._source; } > get level() { return this._level; } >- get messageText() { return this._messageText; } >+ get data() { return this._data; } > get type() { return this._type; } > get url() { return this._url; } > get line() { return this._line; } >@@ -127,6 +127,7 @@ WI.ConsoleMessage.MessageType = { > Profile: "profile", > ProfileEnd: "profileEnd", > Result: "result", // Frontend Only. >+ Image: "image", // Frontend only. > }; > > WI.ConsoleMessage.MessageLevel = { >diff --git a/Source/WebInspectorUI/UserInterface/Models/IssueMessage.js b/Source/WebInspectorUI/UserInterface/Models/IssueMessage.js >index ad3d248bbfbfb4c370b1f4e754167afb4df07207..ad762d8822664b937b7b4c32b32e7079b69374af 100644 >--- a/Source/WebInspectorUI/UserInterface/Models/IssueMessage.js >+++ b/Source/WebInspectorUI/UserInterface/Models/IssueMessage.js >@@ -132,10 +132,10 @@ WI.IssueMessage = class IssueMessage extends WI.Object > { > let parameters = this._consoleMessage.parameters; > if (!parameters) >- return this._consoleMessage.messageText; >+ return this._consoleMessage.data; > > if (parameters[0].type !== "string") >- return this._consoleMessage.messageText; >+ return this._consoleMessage.data; > > function valueFormatter(obj) > { >diff --git a/Source/WebInspectorUI/UserInterface/Models/NativeFunctionParameters.js b/Source/WebInspectorUI/UserInterface/Models/NativeFunctionParameters.js >index d885b0ca1d77f47acec358f20ba95f83c58f9e58..795e09527919f11d7e4c8387ec09552d7b70719a 100644 >--- a/Source/WebInspectorUI/UserInterface/Models/NativeFunctionParameters.js >+++ b/Source/WebInspectorUI/UserInterface/Models/NativeFunctionParameters.js >@@ -175,6 +175,7 @@ WI.NativeConstructorFunctionParameters = { > profileEnd: "name", > record: "object, [options]", > recordEnd: "object", >+ screenshot: "object", > table: "data, [columns]", > takeHeapSnapshot: "[label]", > time: "name = \"default\"", >diff --git a/Source/WebInspectorUI/UserInterface/Protocol/PageObserver.js b/Source/WebInspectorUI/UserInterface/Protocol/PageObserver.js >index 6b7af6f9cebace1abddce55dd23e17c263015dea..8b52be4fd2b0b0ba86cad1c8c192629a874af65e 100644 >--- a/Source/WebInspectorUI/UserInterface/Protocol/PageObserver.js >+++ b/Source/WebInspectorUI/UserInterface/Protocol/PageObserver.js >@@ -52,6 +52,11 @@ WI.PageObserver = class PageObserver > WI.cssManager.defaultAppearanceDidChange(appearance); > } > >+ consoleScreenshotted(dataURL) >+ { >+ WI.consoleManager.consoleScreenshotted(dataURL); >+ } >+ > frameStartedLoading(frameId) > { > // Not handled yet. >diff --git a/Source/WebInspectorUI/UserInterface/Views/ConsoleCommandView.js b/Source/WebInspectorUI/UserInterface/Views/ConsoleCommandView.js >index 434c6aaee9cf306ef6ff9d1fa4498962a7b60364..8326a5534751d5edc3024a0cd901315434a95778 100644 >--- a/Source/WebInspectorUI/UserInterface/Views/ConsoleCommandView.js >+++ b/Source/WebInspectorUI/UserInterface/Views/ConsoleCommandView.js >@@ -49,7 +49,7 @@ WI.ConsoleCommandView = class ConsoleCommandView extends WI.Object > this._element.classList.add(this._className); > > this._formattedCommandElement = this._element.appendChild(document.createElement("span")); >- this._formattedCommandElement.classList.add("console-message-text"); >+ this._formattedCommandElement.classList.add("console-message-body"); > this._formattedCommandElement.textContent = this._commandText; > > // FIXME: <https://webkit.org/b/143545> Web Inspector: LogContentView should use higher level objects >diff --git a/Source/WebInspectorUI/UserInterface/Views/ConsoleMessageView.css b/Source/WebInspectorUI/UserInterface/Views/ConsoleMessageView.css >index 3a2909f73a32fef700dfe8e2c3ff47c6ef72aeb4..f5af79bc6e026e483916b421458b2e7af3ccc99e 100644 >--- a/Source/WebInspectorUI/UserInterface/Views/ConsoleMessageView.css >+++ b/Source/WebInspectorUI/UserInterface/Views/ConsoleMessageView.css >@@ -29,7 +29,7 @@ > min-height: 21px; > } > >-.console-user-command.special-user-log > .console-message-text { >+.console-user-command.special-user-log > .console-message-body { > padding: 0 6px 1px; > border-radius: 3px; > border: 1px solid transparent; >@@ -59,18 +59,29 @@ > border-radius: 7px; > } > >-.console-message-text { >+.console-message-body { > white-space: pre-wrap; > } > >-.console-message-text > span { >+.console-message-body > span { > -webkit-user-select: text; > } > >-.console-message-text > span > :matches(.console-message-enclosed, .console-message-preview, .console-message-preview-divider) { >+.console-message-body > span > :matches(.console-message-enclosed, .console-message-preview, .console-message-preview-divider) { > -webkit-user-select: none; > } > >+.console-message-body > img { >+ max-width: 500px; >+ max-height: 500px; >+ box-shadow: 1px 2px 6px rgba(0, 0, 0, 0.58); >+} >+ >+.console-message-body > .show-grid { >+ /* Prevents the light blue highlight from being visible in the checkerboard. */ >+ --checkerboard-light-square: white; >+} >+ > .console-message.expandable .console-top-level-message::before { > display: inline-block; > >@@ -160,7 +171,7 @@ body[dir=rtl] .console-message.expandable .console-top-level-message::before { > border-color: hsl(0, 100%, 92%); > } > >-.console-error-level .console-message-text { >+.console-error-level .console-message-body { > color: hsl(0, 75%, 45%); > } > >@@ -169,7 +180,7 @@ body[dir=rtl] .console-message.expandable .console-top-level-message::before { > border-color: hsl(40, 100%, 90%); > } > >-.console-warning-level .console-message-text { >+.console-warning-level .console-message-body { > color: hsl(30, 90%, 35%); > } > >@@ -212,7 +223,7 @@ body[dir=rtl] .console-message.expandable .console-top-level-message::before { > padding-top: 1px; > } > >-.console-user-command > .console-message-text { >+.console-user-command > .console-message-body { > color: hsl(209, 100%, 50%); > -webkit-user-select: text; > } >@@ -290,15 +301,15 @@ body[dir=rtl] .console-message.expandable .console-top-level-message::before { > background-color: unset; > } > >- .console-warning-level .console-message-text { >+ .console-warning-level .console-message-body { > color: hsl(53, 80%, 55%); > } > >- .console-error-level .console-message-text { >+ .console-error-level .console-message-body { > color: hsl(10, 100%, 70%); > } > >- .console-user-command > .console-message-text { >+ .console-user-command > .console-message-body { > color: hsl(209, 100%, 70%); > } > >diff --git a/Source/WebInspectorUI/UserInterface/Views/ConsoleMessageView.js b/Source/WebInspectorUI/UserInterface/Views/ConsoleMessageView.js >index de6ec24e9911444115e0877812b80ede5e009f3a..9efed9e2af68f8cfdc70cdb9d02ae203acae2199 100644 >--- a/Source/WebInspectorUI/UserInterface/Views/ConsoleMessageView.js >+++ b/Source/WebInspectorUI/UserInterface/Views/ConsoleMessageView.js >@@ -88,16 +88,18 @@ WI.ConsoleMessageView = class ConsoleMessageView extends WI.Object > // FIXME: The location link should include stack trace information. > this._appendLocationLink(); > >- this._messageTextElement = this._element.appendChild(document.createElement("span")); >- this._messageTextElement.classList.add("console-top-level-message"); >- this._messageTextElement.classList.add("console-message-text"); >- this._appendMessageTextAndArguments(this._messageTextElement); >+ this._messageBodyElement = this._element.appendChild(document.createElement("span")); >+ this._messageBodyElement.classList.add("console-top-level-message", "console-message-body"); >+ this._appendMessageTextAndArguments(this._messageBodyElement); > this._appendSavedResultIndex(); > > this._appendExtraParameters(); > this._appendStackTrace(); > > this._renderRepeatCount(); >+ >+ if (this._message.type === WI.ConsoleMessage.MessageType.Image) >+ this._element.addEventListener("contextmenu", this._handleContextMenu.bind(this)); > } > > get element() >@@ -197,7 +199,7 @@ WI.ConsoleMessageView = class ConsoleMessageView extends WI.Object > > toClipboardString(isPrefixOptional) > { >- let clipboardString = this._messageTextElement.innerText.removeWordBreakCharacters(); >+ let clipboardString = this._messageBodyElement.innerText.removeWordBreakCharacters(); > if (this._message.savedResultIndex) > clipboardString = clipboardString.replace(/\s*=\s*(\$\d+)$/, ""); > >@@ -279,13 +281,40 @@ WI.ConsoleMessageView = class ConsoleMessageView extends WI.Object > > case WI.ConsoleMessage.MessageType.StartGroup: > case WI.ConsoleMessage.MessageType.StartGroupCollapsed: >- var args = this._message.parameters || [this._message.messageText || WI.UIString("Group")]; >+ var args = this._message.parameters || [this._message.data || WI.UIString("Group")]; > this._formatWithSubstitutionString(args, element); > this._extraParameters = null; > break; > >+ case WI.ConsoleMessage.MessageType.Image: { >+ let image = element.appendChild(document.createElement("img")); >+ image.classList.add("show-grid"); >+ image.src = this._message.data; >+ >+ let date = new Date; >+ let values = [ >+ date.getFullYear(), >+ Number.zeroPad(date.getMonth() + 1, 2), >+ Number.zeroPad(date.getDate(), 2), >+ Number.zeroPad(date.getHours(), 2), >+ Number.zeroPad(date.getMinutes(), 2), >+ Number.zeroPad(date.getSeconds(), 2), >+ ]; >+ let filename = WI.UIString("Screen Shot %s-%s-%s at %s.%s.%s").format(...values); >+ image.title = filename; >+ image.setAttribute("filename", filename + ".png"); >+ >+ image.addEventListener("load", (event) => { >+ if (image.width >= image.height) >+ image.width = image.width / window.devicePixelRatio; >+ else >+ image.height = image.height / window.devicePixelRatio; >+ }); >+ break; >+ } >+ > default: >- var args = this._message.parameters || [this._message.messageText]; >+ var args = this._message.parameters || [this._message.data]; > this._appendFormattedArguments(element, args); > break; > } >@@ -294,7 +323,7 @@ WI.ConsoleMessageView = class ConsoleMessageView extends WI.Object > > // FIXME: Better handle WI.ConsoleMessage.MessageSource.Network once it has request info. > >- var args = this._message.parameters || [this._message.messageText]; >+ var args = this._message.parameters || [this._message.data]; > this._appendFormattedArguments(element, args); > } > >@@ -313,7 +342,7 @@ WI.ConsoleMessageView = class ConsoleMessageView extends WI.Object > if (this._objectTree) > this._objectTree.appendTitleSuffix(savedVariableElement); > else >- this._messageTextElement.appendChild(savedVariableElement); >+ this._messageBodyElement.appendChild(savedVariableElement); > } > > _appendLocationLink() >@@ -403,7 +432,7 @@ WI.ConsoleMessageView = class ConsoleMessageView extends WI.Object > this.expand(); > > this._stackTraceElement = this._element.appendChild(document.createElement("div")); >- this._stackTraceElement.classList.add("console-message-text", "console-message-stack-trace-container"); >+ this._stackTraceElement.classList.add("console-message-body", "console-message-stack-trace-container"); > > var callFramesElement = new WI.StackTraceView(this._message.stackTrace).element; > this._stackTraceElement.appendChild(callFramesElement); >@@ -920,6 +949,24 @@ WI.ConsoleMessageView = class ConsoleMessageView extends WI.Object > this._element.classList.add("expandable"); > > this._boundClickHandler = this.toggle.bind(this); >- this._messageTextElement.addEventListener("click", this._boundClickHandler); >+ this._messageBodyElement.addEventListener("click", this._boundClickHandler); >+ } >+ >+ _handleContextMenu(event) >+ { >+ let image = this._messageBodyElement.querySelector("img"); >+ >+ let contextMenu = WI.ContextMenu.createFromEvent(event); >+ >+ contextMenu.appendItem(WI.UIString("Save Image"), () => { >+ const forceSaveAs = true; >+ WI.FileUtilities.save({ >+ url: encodeURI("web-inspector:///" + image.getAttribute("filename")), >+ content: parseDataURL(this._message.data).data, >+ base64Encoded: true, >+ }, forceSaveAs); >+ }); >+ >+ contextMenu.appendSeparator(); > } > }; >diff --git a/Source/WebInspectorUI/UserInterface/Views/LogContentView.css b/Source/WebInspectorUI/UserInterface/Views/LogContentView.css >index ad96a3d5f744b3c79b65206df242d6716a675165..14637f8ef33d00d271bdbcfd93cc4480c19739e5 100644 >--- a/Source/WebInspectorUI/UserInterface/Views/LogContentView.css >+++ b/Source/WebInspectorUI/UserInterface/Views/LogContentView.css >@@ -238,7 +238,7 @@ body[dir=rtl] .console-group-title::before { > background-color: hsla(53, 83%, 53%, 0.75); > } > >-.search-in-progress .console-item:not(.filtered-out-by-search).special-user-log .console-message-text .highlighted { >+.search-in-progress .console-item:not(.filtered-out-by-search).special-user-log .console-message-body .highlighted { > color: var(--selected-foreground-color); > background-color: var(--selected-background-color-highlight); > >diff --git a/Source/WebInspectorUI/UserInterface/Views/Main.css b/Source/WebInspectorUI/UserInterface/Views/Main.css >index 31a70cb19f5676ca3f12741cc3a1f38ad663c63c..9aee116ecaf9fe1c70cb78a24fca3f115ab81172 100644 >--- a/Source/WebInspectorUI/UserInterface/Views/Main.css >+++ b/Source/WebInspectorUI/UserInterface/Views/Main.css >@@ -379,12 +379,16 @@ body[dir=rtl] .go-to-arrow { > } > > :matches(img, canvas).show-grid { >- background-image: linear-gradient(315deg, transparent 75%, hsl(0, 0%, 95%) 75%), >- linear-gradient(45deg, transparent 75%, hsl(0, 0%, 95%) 75%), >- linear-gradient(315deg, hsl(0, 0%, 95%) 25%, transparent 25%), >- linear-gradient(45deg, hsl(0, 0%, 95%) 25%, transparent 25%); >+ background-color: var(--checkerboard-light-square); >+ background-image: linear-gradient(315deg, transparent 75%, var(--checkerboard-dark-square) 75%), >+ linear-gradient(45deg, transparent 75%, var(--checkerboard-dark-square) 75%), >+ linear-gradient(315deg, var(--checkerboard-dark-square) 25%, transparent 25%), >+ linear-gradient(45deg, var(--checkerboard-dark-square) 25%, transparent 25%); > background-size: 20px 20px; > background-position: 10px 10px, 10px 0px, 0 0, 0 10px; >+ >+ --checkerboard-light-square: transparent; >+ --checkerboard-dark-square: hsl(0, 0%, 95%); > } > > .device-settings-content { >@@ -452,8 +456,7 @@ body[dir=rtl] .go-to-arrow { > } > > :matches(img, canvas).show-grid { >- background-color: white; >+ --checkerboard-light-square: white; > --checkerboard-dark-square: hsl(0, 0%, 80%); >- background-image: linear-gradient(315deg, transparent 75%, var(--checkerboard-dark-square) 75%), linear-gradient(45deg, transparent 75%, var(--checkerboard-dark-square) 75%), linear-gradient(315deg, var(--checkerboard-dark-square) 25%, transparent 25%), linear-gradient(45deg, var(--checkerboard-dark-square) 25%, transparent 25%); > } > } >diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog >index 2f3e2064c23a189c8725fbe577b2192169fbe272..5a980ef5eb5b2d826963ab0f8f46b34ee6dc0cf8 100644 >--- a/LayoutTests/ChangeLog >+++ b/LayoutTests/ChangeLog >@@ -1,3 +1,14 @@ >+2019-02-04 Devin Rousso <drousso@apple.com> >+ >+ Web Inspector: provide a way to capture a screenshot of a node from within the page >+ https://bugs.webkit.org/show_bug.cgi?id=194279 >+ <rdar://problem/10731573> >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ * inspector/console/console-screenshot.html: Added. >+ * inspector/console/console-screenshot-expected.txt: Added. >+ > 2019-02-04 Shawn Roberts <sroberts@apple.com> > > [iOS Simulator] pageoverlay/overlay tests are flaky failures >diff --git a/LayoutTests/inspector/console/console-screenshot-expected.txt b/LayoutTests/inspector/console/console-screenshot-expected.txt >new file mode 100644 >index 0000000000000000000000000000000000000000..e54e17e001c9200490073e917c8d721a89b6fc03 >--- /dev/null >+++ b/LayoutTests/inspector/console/console-screenshot-expected.txt >@@ -0,0 +1,8 @@ >+Tests for the console.screenshot API. >+ >+ >+== Running test suite: console.screenshot >+-- Running test case: console.screenshot.Node >+PASS: The added message should be an image. >+PASS: The image should be a 2x2 red square. >+ >diff --git a/LayoutTests/inspector/console/console-screenshot.html b/LayoutTests/inspector/console/console-screenshot.html >new file mode 100644 >index 0000000000000000000000000000000000000000..990ae53dc7cbbeee0be2d815d4b6192033aa4c82 >--- /dev/null >+++ b/LayoutTests/inspector/console/console-screenshot.html >@@ -0,0 +1,44 @@ >+<!DOCTYPE html> >+<html> >+<head> >+<script src="../../http/tests/inspector/resources/inspector-test.js"></script> >+<script> >+function test() >+{ >+ // 2x2 red square >+ const redSquareDataURL = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAYAAABytg0kAAAAAXNSR0IArs4c6QAAABNJREFUCB1j/M/AAEQMDEwgAgQAHxcCAmtAm/sAAAAASUVORK5CYII="; >+ >+ let suite = InspectorTest.createAsyncSuite("console.screenshot"); >+ >+ suite.addTestCase({ >+ name: "console.screenshot.Node", >+ description: "Test that console.screenshot is works with nodes.", >+ async test() { >+ let [messageAddedEvent, _] = await Promise.all([ >+ WI.consoleManager.awaitEvent(WI.ConsoleManager.Event.MessageAdded), >+ InspectorTest.evaluateInPage(`console.screenshot(document.querySelector("#test1"))`), >+ ]); >+ >+ let {message} = messageAddedEvent.data; >+ >+ InspectorTest.expectEqual(message.type, WI.ConsoleMessage.MessageType.Image, "The added message should be an image."); >+ InspectorTest.expectEqual(message.data, redSquareDataURL, "The image should be a 2x2 red square."); >+ }, >+ }); >+ >+ suite.runTestCasesAndFinish(); >+} >+</script> >+</head> >+<body onload="runTest()"> >+ <p>Tests for the console.screenshot API.</p> >+ <div id="test1"></div> >+ <style> >+ #test1 { >+ width: 2px; >+ height: 2px; >+ background-color: red; >+ } >+ </style> >+</body> >+</html>
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 194279
:
361160
|
361161
|
361164
|
361165
|
361170
|
361172
|
361176
|
361326
|
361334
|
361337
|
361339
|
361340
|
361345
|
361358
|
364646
|
364647
|
364653
|
364776