Diff
Modified: trunk/LayoutTests/ChangeLog (242991 => 242992)
--- trunk/LayoutTests/ChangeLog 2019-03-15 05:56:24 UTC (rev 242991)
+++ trunk/LayoutTests/ChangeLog 2019-03-15 08:12:21 UTC (rev 242992)
@@ -1,3 +1,17 @@
+2019-03-15 Devin Rousso <[email protected]>
+
+ 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 Joseph Pecoraro.
+
+ * js/console.html:
+ * js/console-expected.txt:
+ * inspector/console/console-screenshot.html: Added.
+ * inspector/console/console-screenshot-expected.txt: Added.
+ * http/tests/inspector/dom/cross-domain-inspected-node-access-expected.txt:
+
2019-03-14 Sihui Liu <[email protected]>
IndexedDB: re-enable some leak tests
Modified: trunk/LayoutTests/http/tests/inspector/dom/cross-domain-inspected-node-access-expected.txt (242991 => 242992)
--- trunk/LayoutTests/http/tests/inspector/dom/cross-domain-inspected-node-access-expected.txt 2019-03-15 05:56:24 UTC (rev 242991)
+++ trunk/LayoutTests/http/tests/inspector/dom/cross-domain-inspected-node-access-expected.txt 2019-03-15 08:12:21 UTC (rev 242992)
@@ -1,5 +1,5 @@
-CONSOLE MESSAGE: line 43: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match.
-CONSOLE MESSAGE: line 43: Blocked a frame with origin "http://localhost:8000" from accessing a frame with origin "http://127.0.0.1:8000". Protocols, domains, and ports must match.
+CONSOLE MESSAGE: line 44: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match.
+CONSOLE MESSAGE: line 44: Blocked a frame with origin "http://localhost:8000" from accessing a frame with origin "http://127.0.0.1:8000". Protocols, domains, and ports must match.
Test that code evaluated in the main frame cannot access $0 that resolves to a node in a frame from a different domain. Bug 105423.
Added: trunk/LayoutTests/inspector/console/console-screenshot-expected.txt (0 => 242992)
--- trunk/LayoutTests/inspector/console/console-screenshot-expected.txt (rev 0)
+++ trunk/LayoutTests/inspector/console/console-screenshot-expected.txt 2019-03-15 08:12:21 UTC (rev 242992)
@@ -0,0 +1,23 @@
+CONSOLE MESSAGE: [object HTMLDivElement]
+CONSOLE MESSAGE: [object HTMLDivElement]
+CONSOLE MESSAGE: Could not capture screenshot
+Tests for the console.screenshot API.
+
+
+== Running test suite: console.screenshot
+-- Running test case: console.screenshot.SingleNode
+PASS: The added message should be an image.
+PASS: The image should be a 2x2 red square.
+
+-- Running test case: console.screenshot.MultipleNodes
+PASS: The added message should be an image.
+PASS: The image should be a 2x2 blue square.
+
+-- Running test case: console.screenshot.DetachedNode
+PASS: Could not capture screenshot
+
+-- Running test case: console.screenshot.NoArguments
+PASS: The added message should be an image.
+PASS: The image width should be greater than 2px.
+PASS: The image height should be greater than 2px.
+
Added: trunk/LayoutTests/inspector/console/console-screenshot.html (0 => 242992)
--- trunk/LayoutTests/inspector/console/console-screenshot.html (rev 0)
+++ trunk/LayoutTests/inspector/console/console-screenshot.html 2019-03-15 08:12:21 UTC (rev 242992)
@@ -0,0 +1,122 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src=""
+<script>
+
+function createDetachedTest3()
+{
+ let div = document.createElement("div");
+ div.id = "test3";
+ return div;
+}
+
+function test()
+{
+ InspectorTest.debug();
+
+ // 2x2 red square
+ const redSquareDataURL = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAYAAABytg0kAAAAAXNSR0IArs4c6QAAABNJREFUCB1j/M/AAEQMDEwgAgQAHxcCAmtAm/sAAAAASUVORK5CYII=";
+
+ // 2x2 blue square
+ const blueSquareDataURL = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAYAAABytg0kAAAAAXNSR0IArs4c6QAAABRJREFUCB1jZGD4/58BCJhABAgAAB0ZAgJSPDJ6AAAAAElFTkSuQmCC";
+
+ // 2x2 green square
+ const greenSquareDataURL = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAYAAABytg0kAAAAAXNSR0IArs4c6QAAABNJREFUCB1jZGhg+M8ABEwgAgQAFigBgxp1H6oAAAAASUVORK5CYII=";
+
+ let suite = InspectorTest.createAsyncSuite("console.screenshot");
+
+ function addTest({name, _expression_, imageMessageAddedCallback, shouldError}) {
+ suite.addTestCase({
+ name,
+ test(resolve, reject) {
+ let listener = WI.consoleManager.addEventListener(WI.ConsoleManager.Event.MessageAdded, async (event) => {
+ let {message} = event.data;
+
+ let isError = message.level === WI.ConsoleMessage.MessageLevel.Error;
+ if (isError || message.type === WI.ConsoleMessage.MessageType.Image) {
+ WI.consoleManager.removeEventListener(WI.ConsoleManager.Event.MessageAdded, listener);
+
+ if (isError)
+ InspectorTest.expectThat(shouldError, message.messageText);
+ else
+ InspectorTest.expectEqual(message.type, WI.ConsoleMessage.MessageType.Image, "The added message should be an image.");
+
+ if (imageMessageAddedCallback)
+ await imageMessageAddedCallback(message);
+
+ resolve();
+ return;
+ }
+ });
+
+ InspectorTest.evaluateInPage(_expression_)
+ .catch(reject);
+ },
+ });
+ }
+
+ addTest({
+ name: "console.screenshot.SingleNode",
+ _expression_: `console.screenshot(document.querySelector("#test1"))`,
+ imageMessageAddedCallback(message) {
+ InspectorTest.expectEqual(message.messageText, redSquareDataURL, "The image should be a 2x2 red square.");
+ },
+ });
+
+ addTest({
+ name: "console.screenshot.MultipleNodes",
+ _expression_: `console.screenshot(document.querySelector("#test2"), document.querySelector("#test1"))`,
+ imageMessageAddedCallback(message) {
+ InspectorTest.expectEqual(message.messageText, blueSquareDataURL, "The image should be a 2x2 blue square.");
+ },
+ });
+
+ addTest({
+ name: "console.screenshot.DetachedNode",
+ _expression_: `console.screenshot(createDetachedTest3())`,
+ shouldError: true,
+ });
+
+ addTest({
+ name: "console.screenshot.NoArguments",
+ _expression_: `console.screenshot()`,
+ async imageMessageAddedCallback(message) {
+ InspectorTest.assert(message.messageText !== redSquareDataURL, "The imag should not be a 2x2 red square.");
+ InspectorTest.assert(message.messageText !== blueSquareDataURL, "The imag should not be a 2x2 blue square.");
+ InspectorTest.assert(message.messageText !== greenSquareDataURL, "The imag should not be a 2x2 green square.");
+
+ let img = await WI.ImageUtilities.promisifyLoad(message.messageText);
+ InspectorTest.expectGreaterThan(img.width, 2, "The image width should be greater than 2px.");
+ InspectorTest.expectGreaterThan(img.height, 2, "The image height should be greater than 2px.");
+ },
+ });
+
+ suite.runTestCasesAndFinish();
+}
+</script>
+</head>
+<body _onload_="runTest()">
+ <p>Tests for the console.screenshot API.</p>
+ <div id="test1"></div>
+ <div id="test2"></div>
+ <div id="test3"></div>
+ <style>
+ #test1 {
+ width: 2px;
+ height: 2px;
+ background-color: red;
+ }
+ #test2 {
+ width: 2px;
+ height: 2px;
+ background-color: blue;
+ }
+ #test3 {
+ width: 2px;
+ height: 2px;
+ background-color: green;
+ }
+ </style>
+</body>
+</html>
Modified: trunk/LayoutTests/js/console-expected.txt (242991 => 242992)
--- trunk/LayoutTests/js/console-expected.txt 2019-03-15 05:56:24 UTC (rev 242991)
+++ trunk/LayoutTests/js/console-expected.txt 2019-03-15 08:12:21 UTC (rev 242992)
@@ -177,6 +177,13 @@
PASS descriptor.writable is true
PASS descriptor.enumerable is true
+console.screenshot
+PASS typeof console.screenshot is "function"
+PASS console.screenshot.length is 0
+PASS descriptor.configurable is true
+PASS descriptor.writable is true
+PASS descriptor.enumerable is true
+
PASS Object.getOwnPropertyNames(console).length is enumerablePropertyCount
fuzzing of target for console.record
@@ -218,6 +225,18 @@
PASS console.record(window.canvas) did not throw exception.
PASS console.record(window.canvas) did not throw exception.
PASS console.record(window.canvas) did not throw exception.
+
+fuzzing of target for console.screenshot
+PASS console.screenshot() did not throw exception.
+PASS console.screenshot(undefined) did not throw exception.
+PASS console.screenshot(null) did not throw exception.
+PASS console.screenshot(1) did not throw exception.
+PASS console.screenshot("test") did not throw exception.
+PASS console.screenshot([]) did not throw exception.
+PASS console.screenshot({}) did not throw exception.
+PASS console.screenshot(window) did not throw exception.
+PASS console.screenshot(console) did not throw exception.
+
PASS successfullyParsed is true
TEST COMPLETE
Modified: trunk/LayoutTests/js/console.html (242991 => 242992)
--- trunk/LayoutTests/js/console.html 2019-03-15 05:56:24 UTC (rev 242991)
+++ trunk/LayoutTests/js/console.html 2019-03-15 08:12:21 UTC (rev 242992)
@@ -47,7 +47,7 @@
debug("");
shouldBe("Object.getOwnPropertyNames(console).length", "enumerablePropertyCount");
-const consoleRecordArguments = [
+const fuzzingArguments = [
`undefined`,
`null`,
`1`,
@@ -61,18 +61,18 @@
debug("");
debug("fuzzing of target for console.record");
shouldNotThrow(`console.record()`);
-for (let argument of consoleRecordArguments)
+for (let argument of fuzzingArguments)
shouldNotThrow(`console.record(${argument})`);
debug("");
debug("fuzzing of options for console.record");
-for (let argument of consoleRecordArguments)
+for (let argument of fuzzingArguments)
shouldNotThrow(`console.record({}, ${argument})`);
debug("");
debug("fuzzing of target for console.recordEnd");
shouldNotThrow(`console.recordEnd()`);
-for (let argument of consoleRecordArguments)
+for (let argument of fuzzingArguments)
shouldNotThrow(`console.recordEnd(${argument})`);
debug("");
@@ -84,6 +84,14 @@
shouldNotThrow(`console.record(window.canvas)`);
shouldNotThrow(`console.record(window.canvas)`);
+debug("");
+debug("fuzzing of target for console.screenshot");
+shouldNotThrow(`console.screenshot()`);
+for (let argument of fuzzingArguments)
+ shouldNotThrow(`console.screenshot(${argument})`);
+
+debug("");
+
</script>
<script src=""
<canvas id="canvas"></canvas>
Modified: trunk/Source/_javascript_Core/ChangeLog (242991 => 242992)
--- trunk/Source/_javascript_Core/ChangeLog 2019-03-15 05:56:24 UTC (rev 242991)
+++ trunk/Source/_javascript_Core/ChangeLog 2019-03-15 08:12:21 UTC (rev 242992)
@@ -1,3 +1,34 @@
+2019-03-15 Devin Rousso <[email protected]>
+
+ 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 Joseph Pecoraro.
+
+ 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
+ - capture an image of a `Node` (if provided)
+ - capture an image of the viewport if nothing is provided
+
+ * inspector/protocol/Console.json:
+ Add `Image` enum value to `ConsoleMessage` type.
+ * runtime/ConsoleTypes.h:
+ * inspector/ConsoleMessage.h:
+ * inspector/ConsoleMessage.cpp:
+ (Inspector::messageTypeValue):
+
+ * runtime/ConsoleClient.h:
+ * runtime/ConsoleObject.cpp:
+ (JSC::ConsoleObject::finishCreation):
+ (JSC::consoleProtoFuncScreenshot): Added.
+
+ * inspector/JSGlobalObjectConsoleClient.h:
+ * inspector/JSGlobalObjectConsoleClient.cpp:
+ (Inspector::JSGlobalObjectConsoleClient::screenshot): Added.
+
2019-03-14 Yusuke Suzuki <[email protected]>
[JSC] Retain PrivateName of Symbol before passing it to operations potentially incurring GC
Modified: trunk/Source/_javascript_Core/inspector/ConsoleMessage.cpp (242991 => 242992)
--- trunk/Source/_javascript_Core/inspector/ConsoleMessage.cpp 2019-03-15 05:56:24 UTC (rev 242991)
+++ trunk/Source/_javascript_Core/inspector/ConsoleMessage.cpp 2019-03-15 08:12:21 UTC (rev 242992)
@@ -191,6 +191,7 @@
case MessageType::Timing: return Protocol::Console::ConsoleMessage::Type::Timing;
case MessageType::Profile: return Protocol::Console::ConsoleMessage::Type::Profile;
case MessageType::ProfileEnd: return Protocol::Console::ConsoleMessage::Type::ProfileEnd;
+ case MessageType::Image: return Protocol::Console::ConsoleMessage::Type::Image;
}
return Protocol::Console::ConsoleMessage::Type::Log;
}
Modified: trunk/Source/_javascript_Core/inspector/ConsoleMessage.h (242991 => 242992)
--- trunk/Source/_javascript_Core/inspector/ConsoleMessage.h 2019-03-15 05:56:24 UTC (rev 242991)
+++ trunk/Source/_javascript_Core/inspector/ConsoleMessage.h 2019-03-15 08:12:21 UTC (rev 242992)
@@ -55,7 +55,7 @@
ConsoleMessage(MessageSource, MessageType, MessageLevel, const String& message, unsigned long requestIdentifier = 0);
ConsoleMessage(MessageSource, MessageType, MessageLevel, const String& message, const String& url, unsigned line, unsigned column, JSC::ExecState* = nullptr, unsigned long requestIdentifier = 0);
ConsoleMessage(MessageSource, MessageType, MessageLevel, const String& message, Ref<ScriptCallStack>&&, unsigned long requestIdentifier = 0);
- ConsoleMessage(MessageSource, MessageType, MessageLevel, const String& message, Ref<ScriptArguments>&&, JSC::ExecState*, unsigned long requestIdentifier = 0);
+ ConsoleMessage(MessageSource, MessageType, MessageLevel, const String& message, Ref<ScriptArguments>&&, JSC::ExecState* = nullptr, unsigned long requestIdentifier = 0);
ConsoleMessage(MessageSource, MessageType, MessageLevel, Vector<JSONLogValue>&&, JSC::ExecState*, unsigned long requestIdentifier = 0);
~ConsoleMessage();
Modified: trunk/Source/_javascript_Core/inspector/JSGlobalObjectConsoleClient.cpp (242991 => 242992)
--- trunk/Source/_javascript_Core/inspector/JSGlobalObjectConsoleClient.cpp 2019-03-15 05:56:24 UTC (rev 242991)
+++ trunk/Source/_javascript_Core/inspector/JSGlobalObjectConsoleClient.cpp 2019-03-15 08:12:21 UTC (rev 242992)
@@ -168,6 +168,11 @@
void JSGlobalObjectConsoleClient::record(ExecState*, Ref<ScriptArguments>&&) { }
void JSGlobalObjectConsoleClient::recordEnd(ExecState*, Ref<ScriptArguments>&&) { }
+void JSGlobalObjectConsoleClient::screenshot(ExecState*, Ref<ScriptArguments>&&)
+{
+ warnUnimplemented("console.screenshot"_s);
+}
+
void JSGlobalObjectConsoleClient::warnUnimplemented(const String& method)
{
String message = method + " is currently ignored in _javascript_ context inspection.";
Modified: trunk/Source/_javascript_Core/inspector/JSGlobalObjectConsoleClient.h (242991 => 242992)
--- trunk/Source/_javascript_Core/inspector/JSGlobalObjectConsoleClient.h 2019-03-15 05:56:24 UTC (rev 242991)
+++ trunk/Source/_javascript_Core/inspector/JSGlobalObjectConsoleClient.h 2019-03-15 08:12:21 UTC (rev 242992)
@@ -55,6 +55,7 @@
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);
Modified: trunk/Source/_javascript_Core/inspector/protocol/Console.json (242991 => 242992)
--- trunk/Source/_javascript_Core/inspector/protocol/Console.json 2019-03-15 05:56:24 UTC (rev 242991)
+++ trunk/Source/_javascript_Core/inspector/protocol/Console.json 2019-03-15 08:12:21 UTC (rev 242992)
@@ -31,7 +31,7 @@
{ "name": "source", "$ref": "ChannelSource"},
{ "name": "level", "type": "string", "enum": ["log", "info", "warning", "error", "debug"], "description": "Message severity." },
{ "name": "text", "type": "string", "description": "Message text." },
- { "name": "type", "type": "string", "optional": true, "enum": ["log", "dir", "dirxml", "table", "trace", "clear", "startGroup", "startGroupCollapsed", "endGroup", "assert", "timing", "profile", "profileEnd"], "description": "Console message type." },
+ { "name": "type", "type": "string", "optional": true, "enum": ["log", "dir", "dirxml", "table", "trace", "clear", "startGroup", "startGroupCollapsed", "endGroup", "assert", "timing", "profile", "profileEnd", "image"], "description": "Console message type." },
{ "name": "url", "type": "string", "optional": true, "description": "URL of the message origin." },
{ "name": "line", "type": "integer", "optional": true, "description": "Line number in the resource that generated this message." },
{ "name": "column", "type": "integer", "optional": true, "description": "Column number on the line in the resource that generated this message." },
Modified: trunk/Source/_javascript_Core/runtime/ConsoleClient.h (242991 => 242992)
--- trunk/Source/_javascript_Core/runtime/ConsoleClient.h 2019-03-15 05:56:24 UTC (rev 242991)
+++ trunk/Source/_javascript_Core/runtime/ConsoleClient.h 2019-03-15 08:12:21 UTC (rev 242992)
@@ -64,6 +64,7 @@
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 };
Modified: trunk/Source/_javascript_Core/runtime/ConsoleObject.cpp (242991 => 242992)
--- trunk/Source/_javascript_Core/runtime/ConsoleObject.cpp 2019-03-15 05:56:24 UTC (rev 242991)
+++ trunk/Source/_javascript_Core/runtime/ConsoleObject.cpp 2019-03-15 08:12:21 UTC (rev 242992)
@@ -59,6 +59,7 @@
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 @@
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 @@
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
Modified: trunk/Source/_javascript_Core/runtime/ConsoleTypes.h (242991 => 242992)
--- trunk/Source/_javascript_Core/runtime/ConsoleTypes.h 2019-03-15 05:56:24 UTC (rev 242991)
+++ trunk/Source/_javascript_Core/runtime/ConsoleTypes.h 2019-03-15 08:12:21 UTC (rev 242992)
@@ -60,6 +60,7 @@
Timing,
Profile,
ProfileEnd,
+ Image,
};
enum class MessageLevel : uint8_t {
Modified: trunk/Source/WebCore/ChangeLog (242991 => 242992)
--- trunk/Source/WebCore/ChangeLog 2019-03-15 05:56:24 UTC (rev 242991)
+++ trunk/Source/WebCore/ChangeLog 2019-03-15 08:12:21 UTC (rev 242992)
@@ -1,3 +1,37 @@
+2019-03-15 Devin Rousso <[email protected]>
+
+ 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 Joseph Pecoraro.
+
+ 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
+ - capture an image of a `Node` (if provided)
+ - capture an image of the viewport if nothing is provided
+
+ * page/PageConsoleClient.h:
+ * page/PageConsoleClient.cpp:
+ (WebCore::PageConsoleClient::addMessage):
+ (WebCore::PageConsoleClient::screenshot): Added.
+
+ * workers/WorkerConsoleClient.h:
+ * workers/WorkerConsoleClient.cpp:
+ (WebCore::WorkerConsoleClient::screenshot): Added.
+ * worklets/WorkletConsoleClient.h:
+ * worklets/WorkletConsoleClient.cpp:
+ (WebCore::WorkletConsoleClient::screenshot): Added.
+
+ * inspector/CommandLineAPIModuleSource.js:
+ (CommandLineAPIImpl.prototype.screenshot): Added.
+
+ * inspector/InspectorInstrumentation.h:
+
2019-03-14 Yusuke Suzuki <[email protected]>
[JSC] Retain PrivateName of Symbol before passing it to operations potentially incurring GC
Modified: trunk/Source/WebCore/inspector/CommandLineAPIModuleSource.js (242991 => 242992)
--- trunk/Source/WebCore/inspector/CommandLineAPIModuleSource.js 2019-03-15 05:56:24 UTC (rev 242991)
+++ trunk/Source/WebCore/inspector/CommandLineAPIModuleSource.js 2019-03-15 08:12:21 UTC (rev 242992)
@@ -83,6 +83,7 @@
"profile",
"profileEnd",
"queryObjects",
+ "screenshot",
"table",
"unmonitorEvents",
"values",
@@ -200,6 +201,11 @@
return inspectedWindow.console.table.apply(inspectedWindow.console, arguments)
},
+ screenshot: function()
+ {
+ return inspectedWindow.console.screenshot.apply(inspectedWindow.console, arguments)
+ },
+
/**
* @param {Object} object
* @param {Array.<string>|string=} types
Modified: trunk/Source/WebCore/inspector/InspectorInstrumentation.h (242991 => 242992)
--- trunk/Source/WebCore/inspector/InspectorInstrumentation.h 2019-03-15 05:56:24 UTC (rev 242991)
+++ trunk/Source/WebCore/inspector/InspectorInstrumentation.h 2019-03-15 08:12:21 UTC (rev 242992)
@@ -98,7 +98,7 @@
struct WebSocketFrame;
-#define FAST_RETURN_IF_NO_FRONTENDS(value) if (LIKELY(!hasFrontends())) return value;
+#define FAST_RETURN_IF_NO_FRONTENDS(value) if (LIKELY(!InspectorInstrumentation::hasFrontends())) return value;
class InspectorInstrumentation {
public:
Modified: trunk/Source/WebCore/page/PageConsoleClient.cpp (242991 => 242992)
--- trunk/Source/WebCore/page/PageConsoleClient.cpp 2019-03-15 05:56:24 UTC (rev 242991)
+++ trunk/Source/WebCore/page/PageConsoleClient.cpp 2019-03-15 08:12:21 UTC (rev 242992)
@@ -34,15 +34,20 @@
#include "ChromeClient.h"
#include "Document.h"
#include "Frame.h"
+#include "FrameSnapshotting.h"
#include "HTMLCanvasElement.h"
#include "ImageBitmapRenderingContext.h"
+#include "ImageBuffer.h"
#include "InspectorController.h"
#include "InspectorInstrumentation.h"
+#include "IntRect.h"
#include "JSCanvasRenderingContext2D.h"
#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"
@@ -119,7 +124,7 @@
void PageConsoleClient::addMessage(std::unique_ptr<Inspector::ConsoleMessage>&& consoleMessage)
{
- if (consoleMessage->source() != MessageSource::CSS && !m_page.usesEphemeralSession()) {
+ if (consoleMessage->source() != MessageSource::CSS && consoleMessage->type() != MessageType::Image && !m_page.usesEphemeralSession()) {
m_page.chrome().client().addMessageToConsole(consoleMessage->source(), consoleMessage->level(), consoleMessage->message(), consoleMessage->line(), consoleMessage->column(), consoleMessage->url());
if (m_page.settings().logsPageMessagesToSystemConsoleEnabled() || shouldPrintExceptions())
@@ -258,4 +263,46 @@
InspectorInstrumentation::didFinishRecordingCanvasFrame(*context, true);
}
+void PageConsoleClient::screenshot(JSC::ExecState* state, Ref<ScriptArguments>&& arguments)
+{
+ FAST_RETURN_IF_NO_FRONTENDS(void());
+
+ Frame& frame = m_page.mainFrame();
+
+ std::unique_ptr<ImageBuffer> snapshot;
+
+ auto* target = objectArgumentAt(arguments, 0);
+ if (target) {
+ auto* node = JSNode::toWrapped(state->vm(), target);
+ if (!node)
+ return;
+
+ snapshot = WebCore::snapshotNode(frame, *node);
+ } else {
+ // If no target is provided, capture an image of the viewport.
+ IntRect imageRect(IntPoint::zero(), frame.view()->sizeForVisibleContent());
+ snapshot = WebCore::snapshotFrameRect(frame, imageRect, SnapshotOptionsInViewCoordinates);
+ }
+
+ if (!snapshot) {
+ addMessage(std::make_unique<Inspector::ConsoleMessage>(MessageSource::ConsoleAPI, MessageType::Log, MessageLevel::Error, "Could not capture screenshot"_s, arguments.copyRef()));
+ return;
+ }
+
+ String dataURL = snapshot->toDataURL("image/png"_s, WTF::nullopt, PreserveResolution::Yes);
+ if (dataURL.isEmpty()) {
+ addMessage(std::make_unique<Inspector::ConsoleMessage>(MessageSource::ConsoleAPI, MessageType::Log, MessageLevel::Error, "Could not capture screenshot"_s, arguments.copyRef()));
+ return;
+ }
+
+ if (target) {
+ // Log the argument before sending the image for it.
+ String messageText;
+ arguments->getFirstArgumentAsString(messageText);
+ addMessage(std::make_unique<Inspector::ConsoleMessage>(MessageSource::ConsoleAPI, MessageType::Log, MessageLevel::Log, messageText, arguments.copyRef()));
+ }
+
+ addMessage(std::make_unique<Inspector::ConsoleMessage>(MessageSource::ConsoleAPI, MessageType::Image, MessageLevel::Log, dataURL));
+}
+
} // namespace WebCore
Modified: trunk/Source/WebCore/page/PageConsoleClient.h (242991 => 242992)
--- trunk/Source/WebCore/page/PageConsoleClient.h 2019-03-15 05:56:24 UTC (rev 242991)
+++ trunk/Source/WebCore/page/PageConsoleClient.h 2019-03-15 08:12:21 UTC (rev 242992)
@@ -76,6 +76,7 @@
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;
Modified: trunk/Source/WebCore/workers/WorkerConsoleClient.cpp (242991 => 242992)
--- trunk/Source/WebCore/workers/WorkerConsoleClient.cpp 2019-03-15 05:56:24 UTC (rev 242991)
+++ trunk/Source/WebCore/workers/WorkerConsoleClient.cpp 2019-03-15 08:12:21 UTC (rev 242992)
@@ -76,4 +76,6 @@
void WorkerConsoleClient::record(JSC::ExecState*, Ref<ScriptArguments>&&) { }
void WorkerConsoleClient::recordEnd(JSC::ExecState*, Ref<ScriptArguments>&&) { }
+void WorkerConsoleClient::screenshot(JSC::ExecState*, Ref<ScriptArguments>&&) { }
+
} // namespace WebCore
Modified: trunk/Source/WebCore/workers/WorkerConsoleClient.h (242991 => 242992)
--- trunk/Source/WebCore/workers/WorkerConsoleClient.h 2019-03-15 05:56:24 UTC (rev 242991)
+++ trunk/Source/WebCore/workers/WorkerConsoleClient.h 2019-03-15 08:12:21 UTC (rev 242992)
@@ -52,6 +52,7 @@
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;
Modified: trunk/Source/WebCore/worklets/WorkletConsoleClient.cpp (242991 => 242992)
--- trunk/Source/WebCore/worklets/WorkletConsoleClient.cpp 2019-03-15 05:56:24 UTC (rev 242991)
+++ trunk/Source/WebCore/worklets/WorkletConsoleClient.cpp 2019-03-15 08:12:21 UTC (rev 242992)
@@ -66,5 +66,7 @@
void WorkletConsoleClient::record(JSC::ExecState*, Ref<ScriptArguments>&&) { }
void WorkletConsoleClient::recordEnd(JSC::ExecState*, Ref<ScriptArguments>&&) { }
+void WorkletConsoleClient::screenshot(JSC::ExecState*, Ref<ScriptArguments>&&) { }
+
} // namespace WebCore
#endif
Modified: trunk/Source/WebCore/worklets/WorkletConsoleClient.h (242991 => 242992)
--- trunk/Source/WebCore/worklets/WorkletConsoleClient.h 2019-03-15 05:56:24 UTC (rev 242991)
+++ trunk/Source/WebCore/worklets/WorkletConsoleClient.h 2019-03-15 08:12:21 UTC (rev 242992)
@@ -54,6 +54,7 @@
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;
};
Modified: trunk/Source/WebInspectorUI/ChangeLog (242991 => 242992)
--- trunk/Source/WebInspectorUI/ChangeLog 2019-03-15 05:56:24 UTC (rev 242991)
+++ trunk/Source/WebInspectorUI/ChangeLog 2019-03-15 08:12:21 UTC (rev 242992)
@@ -1,3 +1,77 @@
+2019-03-15 Devin Rousso <[email protected]>
+
+ 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 Joseph Pecoraro.
+
+ 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
+ - capture an image of a `Node` (if provided)
+ - capture an image of the viewport if nothing is provided
+
+ * UserInterface/Models/ConsoleMessage.js:
+ (WI.ConsoleMessage):
+ * UserInterface/Views/ConsoleCommandView.js:
+ (WI.ConsoleCommandView.prototype.render):
+ * UserInterface/Views/ConsoleMessageView.js:
+ (WI.ConsoleMessageView.prototype.render):
+ (WI.ConsoleMessageView.prototype.toClipboardString):
+ (WI.ConsoleMessageView.prototype._appendMessageTextAndArguments):
+ (WI.ConsoleMessageView.prototype._appendSavedResultIndex):
+ (WI.ConsoleMessageView.prototype._appendStackTrace):
+ (WI.ConsoleMessageView.prototype._makeExpandable):
+ (WI.ConsoleMessageView.prototype._handleContextMenu): Added.
+ * UserInterface/Views/ConsoleMessageView.css:
+ (.console-user-command.special-user-log > .console-message-body): Added.
+ (.console-message-body): Added.
+ (.console-message-body > span): Added.
+ (.console-message-body > span > :matches(.console-message-enclosed, .console-message-preview, .console-message-preview-divider)): Added.
+ (.console-message-body > .console-image): Added.
+ (.console-message-body > .show-grid): Added.
+ (.console-error-level .console-message-body): Added.
+ (.console-warning-level .console-message-body): Added.
+ (.console-log-level.console-image-container::before): Added.
+ (.console-user-command > .console-message-body): Added.
+ (.console-warning-level .console-message-body): Added.
+ (.console-error-level .console-message-body): Added.
+ (.console-user-command > .console-message-body): Added.
+ (.console-user-command.special-user-log > .console-message-text): Deleted.
+ (.console-message-text): Deleted.
+ (.console-message-text > span): Deleted.
+ (.console-message-text > span > :matches(.console-message-enclosed, .console-message-preview, .console-message-preview-divider)): Deleted.
+ (.console-error-level .console-message-text): Deleted.
+ (.console-warning-level .console-message-text): Deleted.
+ (.console-user-command > .console-message-text): Deleted.
+ (.console-warning-level .console-message-text): Deleted.
+ (.console-error-level .console-message-text): Deleted.
+ (.console-user-command > .console-message-text): Deleted.
+ * UserInterface/Views/LogContentView.css:
+ (.search-in-progress .console-item:not(.filtered-out-by-search).special-user-log .console-message-text .highlighted): Added.
+ (.search-in-progress .console-item:not(.filtered-out-by-search).special-user-log .console-message-body .highlighted): Deleted.
+ Renamed variables/classes to be more semantically correct when the content is an image.
+ - `_messageTextElement` to `_messageBodyElement` (JS)
+ - `.console-message-text` to `.console-message-body` (CSS)
+
+ * UserInterface/Controllers/_javascript_LogViewController.js:
+ (WI._javascript_LogViewController.prototype.renderPendingMessages):
+
+ * UserInterface/Views/Main.css:
+ (:matches(img, canvas).show-grid):
+ (@media (prefers-color-scheme: dark) :matches(img, canvas).show-grid):
+
+ * UserInterface/Base/FileUtilities.js:
+ (WI.FileUtilities.screenshotString): Added.
+
+ * UserInterface/Models/NativeFunctionParameters.js:
+ * UserInterface/Controllers/_javascript_RuntimeCompletionProvider.js:
+
+ * UserInterface/Images/ConsoleImage.svg: Copied from UserInterface/Images/Canvas.svg.
+ * Localizations/en.lproj/localizedStrings.js:
+
2019-03-14 Nikita Vasilyev <[email protected]>
Web Inspector: Styles: Jump to effective property button doesn't hide after overridden property become effective
Modified: trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js (242991 => 242992)
--- trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js 2019-03-15 05:56:24 UTC (rev 242991)
+++ trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js 2019-03-15 08:12:21 UTC (rev 242992)
@@ -864,6 +864,7 @@
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";
Modified: trunk/Source/WebInspectorUI/UserInterface/Base/FileUtilities.js (242991 => 242992)
--- trunk/Source/WebInspectorUI/UserInterface/Base/FileUtilities.js 2019-03-15 05:56:24 UTC (rev 242991)
+++ trunk/Source/WebInspectorUI/UserInterface/Base/FileUtilities.js 2019-03-15 08:12:21 UTC (rev 242992)
@@ -24,6 +24,20 @@
*/
WI.FileUtilities = class FileUtilities {
+ static screenshotString()
+ {
+ 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),
+ ];
+ return WI.UIString("Screen Shot %s-%s-%s at %s.%s.%s").format(...values);
+ }
+
static save(saveData, forceSaveAs)
{
console.assert(saveData);
Modified: trunk/Source/WebInspectorUI/UserInterface/Controllers/_javascript_LogViewController.js (242991 => 242992)
--- trunk/Source/WebInspectorUI/UserInterface/Controllers/_javascript_LogViewController.js 2019-03-15 05:56:24 UTC (rev 242991)
+++ trunk/Source/WebInspectorUI/UserInterface/Controllers/_javascript_LogViewController.js 2019-03-15 08:12:21 UTC (rev 242992)
@@ -323,7 +323,7 @@
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();
Modified: trunk/Source/WebInspectorUI/UserInterface/Controllers/_javascript_RuntimeCompletionProvider.js (242991 => 242992)
--- trunk/Source/WebInspectorUI/UserInterface/Controllers/_javascript_RuntimeCompletionProvider.js 2019-03-15 05:56:24 UTC (rev 242991)
+++ trunk/Source/WebInspectorUI/UserInterface/Controllers/_javascript_RuntimeCompletionProvider.js 2019-03-15 08:12:21 UTC (rev 242992)
@@ -319,6 +319,7 @@
"profile",
"profileEnd",
"queryObjects",
+ "screenshot",
"table",
"unmonitorEvents",
"values",
Added: trunk/Source/WebInspectorUI/UserInterface/Images/ConsoleImage.svg (0 => 242992)
--- trunk/Source/WebInspectorUI/UserInterface/Images/ConsoleImage.svg (rev 0)
+++ trunk/Source/WebInspectorUI/UserInterface/Images/ConsoleImage.svg 2019-03-15 08:12:21 UTC (rev 242992)
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright © 2017 Apple Inc. All rights reserved. -->
+<svg xmlns="http://www.w3.org/2000/svg" id="root" version="1.1" viewBox="0 0 16 16">
+ <rect x="1.5" y="2.5" width="13" height="11" fill="none" stroke="currentColor"/>
+ <polygon points="11 8 9 11 6 7 3 11 3 12 13 12 13 11 11 8"/>
+</svg>
Modified: trunk/Source/WebInspectorUI/UserInterface/Models/ConsoleMessage.js (242991 => 242992)
--- trunk/Source/WebInspectorUI/UserInterface/Models/ConsoleMessage.js 2019-03-15 05:56:24 UTC (rev 242991)
+++ trunk/Source/WebInspectorUI/UserInterface/Models/ConsoleMessage.js 2019-03-15 08:12:21 UTC (rev 242992)
@@ -27,10 +27,11 @@
{
constructor(target, source, level, message, type, url, line, column, repeatCount, parameters, callFrames, request)
{
+ console.assert(target instanceof WI.Target);
console.assert(typeof source === "string");
console.assert(typeof level === "string");
console.assert(typeof message === "string");
- console.assert(target instanceof WI.Target);
+ console.assert(!type || Object.values(WI.ConsoleMessage.MessageType).includes(type));
console.assert(!parameters || parameters.every((x) => x instanceof WI.RemoteObject));
this._target = target;
@@ -127,6 +128,7 @@
Timing: "timing",
Profile: "profile",
ProfileEnd: "profileEnd",
+ Image: "image",
Result: "result", // Frontend Only.
};
Modified: trunk/Source/WebInspectorUI/UserInterface/Models/NativeFunctionParameters.js (242991 => 242992)
--- trunk/Source/WebInspectorUI/UserInterface/Models/NativeFunctionParameters.js 2019-03-15 05:56:24 UTC (rev 242991)
+++ trunk/Source/WebInspectorUI/UserInterface/Models/NativeFunctionParameters.js 2019-03-15 08:12:21 UTC (rev 242992)
@@ -175,6 +175,7 @@
profileEnd: "name",
record: "object, [options]",
recordEnd: "object",
+ screenshot: "[node]",
table: "data, [columns]",
takeHeapSnapshot: "[label]",
time: "name = \"default\"",
Modified: trunk/Source/WebInspectorUI/UserInterface/Views/ConsoleCommandView.js (242991 => 242992)
--- trunk/Source/WebInspectorUI/UserInterface/Views/ConsoleCommandView.js 2019-03-15 05:56:24 UTC (rev 242991)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/ConsoleCommandView.js 2019-03-15 08:12:21 UTC (rev 242992)
@@ -49,7 +49,7 @@
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
Modified: trunk/Source/WebInspectorUI/UserInterface/Views/ConsoleMessageView.css (242991 => 242992)
--- trunk/Source/WebInspectorUI/UserInterface/Views/ConsoleMessageView.css 2019-03-15 05:56:24 UTC (rev 242991)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/ConsoleMessageView.css 2019-03-15 08:12:21 UTC (rev 242992)
@@ -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 > .console-image {
+ max-width: 500px;
+ max-height: 500px;
+ box-shadow: 1px 2px 6px hsla(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 @@
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 @@
border-color: hsl(40, 100%, 90%);
}
-.console-warning-level .console-message-text {
+.console-warning-level .console-message-body {
color: hsl(30, 90%, 35%);
}
@@ -182,6 +193,10 @@
content: url(../Images/Log.svg);
}
+.console-log-level.console-image-container::before {
+ content: url(../Images/ConsoleImage.svg);
+}
+
.console-info-level::before {
content: url(../Images/Info.svg);
}
@@ -212,7 +227,7 @@
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 +305,15 @@
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%);
}
Modified: trunk/Source/WebInspectorUI/UserInterface/Views/ConsoleMessageView.js (242991 => 242992)
--- trunk/Source/WebInspectorUI/UserInterface/Views/ConsoleMessageView.js 2019-03-15 05:56:24 UTC (rev 242991)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/ConsoleMessageView.js 2019-03-15 08:12:21 UTC (rev 242992)
@@ -88,10 +88,9 @@
// 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();
@@ -98,6 +97,11 @@
this._appendStackTrace();
this._renderRepeatCount();
+
+ if (this._message.type === WI.ConsoleMessage.MessageType.Image) {
+ this._element.classList.add("console-image-container");
+ this._element.addEventListener("contextmenu", this._handleContextMenu.bind(this));
+ }
}
get element()
@@ -197,7 +201,7 @@
toClipboardString(isPrefixOptional)
{
- let clipboardString = this._messageTextElement.innerText.removeWordBreakCharacters();
+ let clipboardString = this._messageBodyElement.innerText.removeWordBreakCharacters();
if (this._message.savedResultIndex)
clipboardString = clipboardString.replace(/\s*=\s*(\$\d+)$/, "");
@@ -284,6 +288,20 @@
this._extraParameters = null;
break;
+ case WI.ConsoleMessage.MessageType.Image: {
+ let img = element.appendChild(document.createElement("img"));
+ img.classList.add("console-image", "show-grid");
+ img.src = ""
+ img.setAttribute("filename", WI.FileUtilities.screenshotString() + ".png");
+ img.addEventListener("load", (event) => {
+ if (img.width >= img.height)
+ img.width = img.width / window.devicePixelRatio;
+ else
+ img.height = img.height / window.devicePixelRatio;
+ });
+ break;
+ }
+
default:
var args = this._message.parameters || [this._message.messageText];
this._appendFormattedArguments(element, args);
@@ -313,7 +331,7 @@
if (this._objectTree)
this._objectTree.appendTitleSuffix(savedVariableElement);
else
- this._messageTextElement.appendChild(savedVariableElement);
+ this._messageBodyElement.appendChild(savedVariableElement);
}
_appendLocationLink()
@@ -403,7 +421,7 @@
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 +938,26 @@
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 = event.target.closest(".console-image");
+ if (!image)
+ return;
+
+ 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.messageText).data,
+ base64Encoded: true,
+ }, forceSaveAs);
+ });
+
+ contextMenu.appendSeparator();
+ }
};
Modified: trunk/Source/WebInspectorUI/UserInterface/Views/ContextMenuUtilities.js (242991 => 242992)
--- trunk/Source/WebInspectorUI/UserInterface/Views/ContextMenuUtilities.js 2019-03-15 05:56:24 UTC (rev 242991)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/ContextMenuUtilities.js 2019-03-15 08:12:21 UTC (rev 242992)
@@ -250,18 +250,8 @@
return;
}
- 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);
WI.FileUtilities.save({
- url: encodeURI(`web-inspector:///${filename}.png`),
+ url: encodeURI(`web-inspector:///${WI.FileUtilities.screenshotString()}.png`),
content: parseDataURL(dataURL).data,
base64Encoded: true,
});
Modified: trunk/Source/WebInspectorUI/UserInterface/Views/LogContentView.css (242991 => 242992)
--- trunk/Source/WebInspectorUI/UserInterface/Views/LogContentView.css 2019-03-15 05:56:24 UTC (rev 242991)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/LogContentView.css 2019-03-15 08:12:21 UTC (rev 242992)
@@ -226,7 +226,7 @@
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);
Modified: trunk/Source/WebInspectorUI/UserInterface/Views/Main.css (242991 => 242992)
--- trunk/Source/WebInspectorUI/UserInterface/Views/Main.css 2019-03-15 05:56:24 UTC (rev 242991)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/Main.css 2019-03-15 08:12:21 UTC (rev 242992)
@@ -411,12 +411,16 @@
}
: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 {
@@ -479,8 +483,7 @@
}
: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%);
}
}