Web Inspector: Canvas Tab: no way to see backtrace of where a canvas context was...
authorwebkit@devinrousso.com <webkit@devinrousso.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 28 Oct 2017 01:58:52 +0000 (01:58 +0000)
committerwebkit@devinrousso.com <webkit@devinrousso.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 28 Oct 2017 01:58:52 +0000 (01:58 +0000)
https://bugs.webkit.org/show_bug.cgi?id=178799
<rdar://problem/35175805>

Reviewed by Brian Burg.

Source/JavaScriptCore:

* inspector/protocol/Canvas.json:
Add optional `backtrace` to Canvas type that is an array of Console.CallFrame.

Source/WebCore:

No new tests, updated existing tests.

* inspector/InspectorCanvas.h:
* inspector/InspectorCanvas.cpp:
(iterateCallFrames):
(WebCore::InspectorCanvas::buildObjectForCanvas):
(WebCore::InspectorCanvas::buildAction):

* inspector/InspectorCanvasAgent.cpp:
(WebCore::InspectorCanvasAgent::didCreateCanvasRenderingContext):
If the Canvas agent is enabled, generate a backtrace and send it to the frontend with the canvas.
We do not do this for canvases created before the agent is enabled for performance reasons.

Source/WebInspectorUI:

* Localizations/en.lproj/localizedStrings.js:

* UserInterface/Models/Canvas.js:
(WI.Canvas.fromPayload):
(WI.Canvas.prototype.get backtrace):

* UserInterface/Views/CanvasDetailsSidebarPanel.css:
(.sidebar > .panel.details.canvas .details-section.canvas-backtrace .call-frame):

* UserInterface/Views/CanvasDetailsSidebarPanel.js:
(WI.CanvasDetailsSidebarPanel.prototype.initialLayout):
(WI.CanvasDetailsSidebarPanel.prototype.layout):
(WI.CanvasDetailsSidebarPanel.prototype._refreshBacktraceSection):

* UserInterface/Views/ResourceIcons.css:
(.canvas > .icon):
(.canvas .icon): Deleted.

LayoutTests:

* inspector/canvas/create-context-2d-expected.txt:
* inspector/canvas/create-context-webgl-expected.txt:
* inspector/canvas/create-context-webgl2-expected.txt:
* inspector/canvas/create-context-webgpu-expected.txt:
* inspector/canvas/resources/create-context-utilities.js:
(TestPage.registerInitializer.sanitizeURL):
(TestPage.registerInitializer.awaitCanvasAdded):
Pretty-print backtrace when canvases are added to the page.

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

18 files changed:
LayoutTests/ChangeLog
LayoutTests/inspector/canvas/create-context-2d-expected.txt
LayoutTests/inspector/canvas/create-context-webgl-expected.txt
LayoutTests/inspector/canvas/create-context-webgl2-expected.txt
LayoutTests/inspector/canvas/create-context-webgpu-expected.txt
LayoutTests/inspector/canvas/resources/create-context-utilities.js
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/inspector/protocol/Canvas.json
Source/WebCore/ChangeLog
Source/WebCore/inspector/InspectorCanvas.cpp
Source/WebCore/inspector/InspectorCanvas.h
Source/WebCore/inspector/InspectorCanvasAgent.cpp
Source/WebInspectorUI/ChangeLog
Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js
Source/WebInspectorUI/UserInterface/Models/Canvas.js
Source/WebInspectorUI/UserInterface/Views/CanvasDetailsSidebarPanel.css
Source/WebInspectorUI/UserInterface/Views/CanvasDetailsSidebarPanel.js
Source/WebInspectorUI/UserInterface/Views/ResourceIcons.css

index b87460e..011c077 100644 (file)
@@ -1,3 +1,20 @@
+2017-10-27  Devin Rousso  <webkit@devinrousso.com>
+
+        Web Inspector: Canvas Tab: no way to see backtrace of where a canvas context was created
+        https://bugs.webkit.org/show_bug.cgi?id=178799
+        <rdar://problem/35175805>
+
+        Reviewed by Brian Burg.
+
+        * inspector/canvas/create-context-2d-expected.txt:
+        * inspector/canvas/create-context-webgl-expected.txt:
+        * inspector/canvas/create-context-webgl2-expected.txt:
+        * inspector/canvas/create-context-webgpu-expected.txt:
+        * inspector/canvas/resources/create-context-utilities.js:
+        (TestPage.registerInitializer.sanitizeURL):
+        (TestPage.registerInitializer.awaitCanvasAdded):
+        Pretty-print backtrace when canvases are added to the page.
+
 2017-10-27  Daniel Bates  <dabates@apple.com>
 
         Skip test http/tests/security/mixedContent/insecure-download-redirects-to-basic-auth-secure-download.https.html on OS X El Capitan
index 368cb39..b5b3acd 100644 (file)
@@ -7,14 +7,32 @@ PASS: CanvasManager should have no canvases.
 
 -- Running test case: Canvas.CreateContext2D.Attached
 PASS: Canvas context should be 2D.
+  0: createAttachedCanvas - inspector/canvas/resources/create-context-utilities.js:4:36
+  1: Global Code - [program code]
+  2: evaluateWithScopeExtension - [native code]
+  3: _evaluateOn - [native code]
+  4: _evaluateAndWrap - [native code]
+
 PASS: Removed canvas has expected ID.
 
 -- Running test case: Canvas.CreateContext2D.Detached
 PASS: Canvas context should be 2D.
+  0: createDetachedCanvas - inspector/canvas/resources/create-context-utilities.js:8:62
+  1: Global Code - [program code]
+  2: evaluateWithScopeExtension - [native code]
+  3: _evaluateOn - [native code]
+  4: _evaluateAndWrap - [native code]
+
 PASS: Removed canvas has expected ID.
 
 -- Running test case: Canvas.CreateContext2D.CSSCanvas
 Create CSS canvas from -webkit-canvas(css-canvas).
 PASS: Canvas context should be 2D.
+  0: createCSSCanvas - inspector/canvas/resources/create-context-utilities.js:12:47
+  1: Global Code - [program code]
+  2: evaluateWithScopeExtension - [native code]
+  3: _evaluateOn - [native code]
+  4: _evaluateAndWrap - [native code]
+
 PASS: Canvas name should equal the identifier passed to -webkit-canvas.
 
index b335617..89fc1ec 100644 (file)
@@ -7,14 +7,32 @@ PASS: CanvasManager should have no canvases.
 
 -- Running test case: Canvas.CreateContextWebGL.Attached
 PASS: Canvas context should be WebGL.
+  0: createAttachedCanvas - inspector/canvas/resources/create-context-utilities.js:4:36
+  1: Global Code - [program code]
+  2: evaluateWithScopeExtension - [native code]
+  3: _evaluateOn - [native code]
+  4: _evaluateAndWrap - [native code]
+
 PASS: Removed canvas has expected ID.
 
 -- Running test case: Canvas.CreateContextWebGL.Detached
 PASS: Canvas context should be WebGL.
+  0: createDetachedCanvas - inspector/canvas/resources/create-context-utilities.js:8:62
+  1: Global Code - [program code]
+  2: evaluateWithScopeExtension - [native code]
+  3: _evaluateOn - [native code]
+  4: _evaluateAndWrap - [native code]
+
 PASS: Removed canvas has expected ID.
 
 -- Running test case: Canvas.CreateContextWebGL.CSSCanvas
 Create CSS canvas from -webkit-canvas(css-canvas).
 PASS: Canvas context should be WebGL.
+  0: createCSSCanvas - inspector/canvas/resources/create-context-utilities.js:12:47
+  1: Global Code - [program code]
+  2: evaluateWithScopeExtension - [native code]
+  3: _evaluateOn - [native code]
+  4: _evaluateAndWrap - [native code]
+
 PASS: Canvas name should equal the identifier passed to -webkit-canvas.
 
index 561255f..3c1e139 100644 (file)
@@ -7,14 +7,32 @@ PASS: CanvasManager should have no canvases.
 
 -- Running test case: Canvas.CreateContextWebGL2.Attached
 PASS: Canvas context should be WebGL2.
+  0: createAttachedCanvas - inspector/canvas/resources/create-context-utilities.js:4:36
+  1: Global Code - [program code]
+  2: evaluateWithScopeExtension - [native code]
+  3: _evaluateOn - [native code]
+  4: _evaluateAndWrap - [native code]
+
 PASS: Removed canvas has expected ID.
 
 -- Running test case: Canvas.CreateContextWebGL2.Detached
 PASS: Canvas context should be WebGL2.
+  0: createDetachedCanvas - inspector/canvas/resources/create-context-utilities.js:8:62
+  1: Global Code - [program code]
+  2: evaluateWithScopeExtension - [native code]
+  3: _evaluateOn - [native code]
+  4: _evaluateAndWrap - [native code]
+
 PASS: Removed canvas has expected ID.
 
 -- Running test case: Canvas.CreateContextWebGL2.CSSCanvas
 Create CSS canvas from -webkit-canvas(css-canvas).
 PASS: Canvas context should be WebGL2.
+  0: createCSSCanvas - inspector/canvas/resources/create-context-utilities.js:12:47
+  1: Global Code - [program code]
+  2: evaluateWithScopeExtension - [native code]
+  3: _evaluateOn - [native code]
+  4: _evaluateAndWrap - [native code]
+
 PASS: Canvas name should equal the identifier passed to -webkit-canvas.
 
index 924be38..4f0d351 100644 (file)
@@ -7,14 +7,32 @@ PASS: CanvasManager should have no canvases.
 
 -- Running test case: Canvas.CreateContextWebGPU.Attached
 PASS: Canvas context should be WebGPU.
+  0: createAttachedCanvas - inspector/canvas/resources/create-context-utilities.js:4:36
+  1: Global Code - [program code]
+  2: evaluateWithScopeExtension - [native code]
+  3: _evaluateOn - [native code]
+  4: _evaluateAndWrap - [native code]
+
 PASS: Removed canvas has expected ID.
 
 -- Running test case: Canvas.CreateContextWebGPU.Detached
 PASS: Canvas context should be WebGPU.
+  0: createDetachedCanvas - inspector/canvas/resources/create-context-utilities.js:8:62
+  1: Global Code - [program code]
+  2: evaluateWithScopeExtension - [native code]
+  3: _evaluateOn - [native code]
+  4: _evaluateAndWrap - [native code]
+
 PASS: Removed canvas has expected ID.
 
 -- Running test case: Canvas.CreateContextWebGPU.CSSCanvas
 Create CSS canvas from -webkit-canvas(css-canvas).
 PASS: Canvas context should be WebGPU.
+  0: createCSSCanvas - inspector/canvas/resources/create-context-utilities.js:12:47
+  1: Global Code - [program code]
+  2: evaluateWithScopeExtension - [native code]
+  3: _evaluateOn - [native code]
+  4: _evaluateAndWrap - [native code]
+
 PASS: Canvas name should equal the identifier passed to -webkit-canvas.
 
index 44cc36d..7eb242e 100644 (file)
@@ -30,6 +30,10 @@ function destroyCanvases() {
 TestPage.registerInitializer(() => {
     let suite = null;
 
+    function sanitizeURL(url) {
+        return url.replace(/^.*?LayoutTests\//, "");
+    }
+
     function awaitCanvasAdded(contextType) {
         return WI.canvasManager.awaitEvent(WI.CanvasManager.Event.CanvasAdded)
         .then((event) => {
@@ -37,6 +41,25 @@ TestPage.registerInitializer(() => {
             let contextDisplayName = WI.Canvas.displayNameForContextType(contextType);
             InspectorTest.expectEqual(canvas.contextType, contextType, `Canvas context should be ${contextDisplayName}.`);
 
+            for (let i = 0; i < canvas.backtrace.length; ++i) {
+                let callFrame = canvas.backtrace[i];
+                let traceText = `  ${i}: `;
+                traceText += callFrame.functionName || "(anonymous function)";
+
+                if (callFrame.nativeCode)
+                    traceText += " - [native code]";
+                else if (callFrame.programCode)
+                    traceText += " - [program code]";
+                else if (callFrame.sourceCodeLocation) {
+                    let location = callFrame.sourceCodeLocation;
+                    traceText += " - " + sanitizeURL(location.sourceCode.url) + `:${location.lineNumber}:${location.columnNumber}`;
+                }
+
+                InspectorTest.log(traceText);
+            }
+
+            InspectorTest.log("");
+
             return canvas;
         });
     }
index cdef93c..700d125 100644 (file)
@@ -1,3 +1,14 @@
+2017-10-27  Devin Rousso  <webkit@devinrousso.com>
+
+        Web Inspector: Canvas Tab: no way to see backtrace of where a canvas context was created
+        https://bugs.webkit.org/show_bug.cgi?id=178799
+        <rdar://problem/35175805>
+
+        Reviewed by Brian Burg.
+
+        * inspector/protocol/Canvas.json:
+        Add optional `backtrace` to Canvas type that is an array of Console.CallFrame.
+
 2017-10-27  Yusuke Suzuki  <utatane.tea@gmail.com>
 
         [JSC] Tweak ES6 generator function to allow inlining
index c1bf08b..e6a92e9 100644 (file)
@@ -50,7 +50,8 @@
                 { "name": "nodeId", "$ref": "DOM.NodeId", "optional": true, "description": "The corresponding DOM node id." },
                 { "name": "cssCanvasName", "type": "string", "optional": true, "description": "The CSS canvas identifier, for canvases created with <code>document.getCSSCanvasContext</code>." },
                 { "name": "contextAttributes", "$ref": "ContextAttributes", "optional": true, "description": "Context attributes for WebGL rendering contexts." },
-                { "name": "memoryCost", "type": "number", "optional": true, "description": "Memory usage of the canvas in bytes." }
+                { "name": "memoryCost", "type": "number", "optional": true, "description": "Memory usage of the canvas in bytes." },
+                { "name": "backtrace", "type": "array", "items": { "$ref": "Console.CallFrame" }, "optional": true, "description": "Backtrace that was captured when this canvas context was created." }
             ]
         }
     ],
index 6e478df..c742561 100644 (file)
@@ -1,3 +1,24 @@
+2017-10-27  Devin Rousso  <webkit@devinrousso.com>
+
+        Web Inspector: Canvas Tab: no way to see backtrace of where a canvas context was created
+        https://bugs.webkit.org/show_bug.cgi?id=178799
+        <rdar://problem/35175805>
+
+        Reviewed by Brian Burg.
+
+        No new tests, updated existing tests.
+
+        * inspector/InspectorCanvas.h:
+        * inspector/InspectorCanvas.cpp:
+        (iterateCallFrames):
+        (WebCore::InspectorCanvas::buildObjectForCanvas):
+        (WebCore::InspectorCanvas::buildAction):
+
+        * inspector/InspectorCanvasAgent.cpp:
+        (WebCore::InspectorCanvasAgent::didCreateCanvasRenderingContext):
+        If the Canvas agent is enabled, generate a backtrace and send it to the frontend with the canvas.
+        We do not do this for canvases created before the agent is enabled for performance reasons.
+
 2017-10-27  Keith Miller  <keith_miller@apple.com>
 
         Add unified source list files and build scripts to Xcode project navigator
index c153b8d..494ca1f 100644 (file)
@@ -191,7 +191,31 @@ bool InspectorCanvas::hasBufferSpace() const
     return m_bufferUsed < m_bufferLimit;
 }
 
-Ref<Inspector::Protocol::Canvas::Canvas> InspectorCanvas::buildObjectForCanvas(InstrumentingAgents& instrumentingAgents)
+template <typename T, typename Functor>
+static RefPtr<Inspector::Protocol::Array<T>> iterateCallFrames(const Functor& functor)
+{
+    RefPtr<Inspector::Protocol::Array<T>> callFrames = Inspector::Protocol::Array<T>::create();
+    if (JSC::CallFrame* callFrame = JSMainThreadExecState::currentState()->vm().topCallFrame) {
+        callFrame->iterate([&] (JSC::StackVisitor& visitor) {
+            // Only skip Native frames if they are the first frame.
+            if (!callFrames->length() && visitor->isNativeFrame())
+                return JSC::StackVisitor::Continue;
+
+            unsigned line = 0;
+            unsigned column = 0;
+            visitor->computeLineAndColumn(line, column);
+
+            ScriptCallFrame scriptCallFrame(visitor->functionName(), visitor->sourceURL(), static_cast<JSC::SourceID>(visitor->sourceID()), line, column);
+            RefPtr<T> item = functor(scriptCallFrame);
+            callFrames->addItem(WTFMove(item));
+
+            return JSC::StackVisitor::Continue;
+        });
+    }
+    return callFrames;
+}
+
+Ref<Inspector::Protocol::Canvas::Canvas> InspectorCanvas::buildObjectForCanvas(InstrumentingAgents& instrumentingAgents, bool captureBacktrace)
 {
     Document& document = m_canvas.document();
     Frame* frame = document.frame();
@@ -258,6 +282,12 @@ Ref<Inspector::Protocol::Canvas::Canvas> InspectorCanvas::buildObjectForCanvas(I
     if (size_t memoryCost = m_canvas.memoryCost())
         canvas->setMemoryCost(memoryCost);
 
+    if (captureBacktrace) {
+        canvas->setBacktrace(iterateCallFrames<Inspector::Protocol::Console::CallFrame>([&] (const ScriptCallFrame& scriptCallFrame) {
+            return scriptCallFrame.buildInspectorObject();
+        }));
+    }
+
     return canvas;
 }
 
@@ -558,25 +588,9 @@ RefPtr<Inspector::Protocol::Array<Inspector::InspectorValue>> InspectorCanvas::b
 
     action->addItem(WTFMove(parametersData));
     action->addItem(WTFMove(swizzleTypes));
-
-    RefPtr<Inspector::Protocol::Array<double>> trace = Inspector::Protocol::Array<double>::create();
-    if (JSC::CallFrame* callFrame = JSMainThreadExecState::currentState()->vm().topCallFrame) {
-        callFrame->iterate([&] (JSC::StackVisitor& visitor) {
-            // Only skip Native frames if they are the first frame (e.g. CanvasRenderingContext2D.prototype.save).
-            if (!trace->length() && visitor->isNativeFrame())
-                return JSC::StackVisitor::Continue;
-
-            unsigned line = 0;
-            unsigned column = 0;
-            visitor->computeLineAndColumn(line, column);
-
-            ScriptCallFrame scriptCallFrame(visitor->functionName(), visitor->sourceURL(), static_cast<JSC::SourceID>(visitor->sourceID()), line, column);
-            trace->addItem(indexForData(scriptCallFrame));
-
-            return JSC::StackVisitor::Continue;
-        });
-    }
-    action->addItem(WTFMove(trace));
+    action->addItem(iterateCallFrames<InspectorValue>([&] (const ScriptCallFrame& scriptCallFrame) {
+        return InspectorValue::create(indexForData(scriptCallFrame));
+    }));
 
     return action;
 }
index a4fed0f..41c9efa 100644 (file)
@@ -74,7 +74,7 @@ public:
     bool singleFrame() const { return m_singleFrame; }
     void setSingleFrame(bool singleFrame) { m_singleFrame = singleFrame; }
 
-    Ref<Inspector::Protocol::Canvas::Canvas> buildObjectForCanvas(InstrumentingAgents&);
+    Ref<Inspector::Protocol::Canvas::Canvas> buildObjectForCanvas(InstrumentingAgents&, bool captureBacktrace);
 
     ~InspectorCanvas();
 
index 00a1a7b..c3d67d2 100644 (file)
@@ -94,8 +94,9 @@ void InspectorCanvasAgent::enable(ErrorString&)
 
     m_enabled = true;
 
+    const bool captureBacktrace = false;
     for (auto& inspectorCanvas : m_identifierToInspectorCanvas.values())
-        m_frontendDispatcher->canvasAdded(inspectorCanvas->buildObjectForCanvas(m_instrumentingAgents));
+        m_frontendDispatcher->canvasAdded(inspectorCanvas->buildObjectForCanvas(m_instrumentingAgents, captureBacktrace));
 
 #if ENABLE(WEBGL)
     for (auto& inspectorProgram : m_identifierToInspectorProgram.values()) {
@@ -391,8 +392,10 @@ void InspectorCanvasAgent::didCreateCanvasRenderingContext(HTMLCanvasElement& ca
     String cssCanvasName = m_canvasToCSSCanvasName.take(&canvasElement);
     auto inspectorCanvas = InspectorCanvas::create(canvasElement, cssCanvasName);
 
-    if (m_enabled)
-        m_frontendDispatcher->canvasAdded(inspectorCanvas->buildObjectForCanvas(m_instrumentingAgents));
+    if (m_enabled) {
+        const bool captureBacktrace = true;
+        m_frontendDispatcher->canvasAdded(inspectorCanvas->buildObjectForCanvas(m_instrumentingAgents, captureBacktrace));
+    }
 
     m_identifierToInspectorCanvas.set(inspectorCanvas->identifier(), WTFMove(inspectorCanvas));
 }
index 1250558..4f489c8 100644 (file)
@@ -1,3 +1,29 @@
+2017-10-27  Devin Rousso  <webkit@devinrousso.com>
+
+        Web Inspector: Canvas Tab: no way to see backtrace of where a canvas context was created
+        https://bugs.webkit.org/show_bug.cgi?id=178799
+        <rdar://problem/35175805>
+
+        Reviewed by Brian Burg.
+
+        * Localizations/en.lproj/localizedStrings.js:
+
+        * UserInterface/Models/Canvas.js:
+        (WI.Canvas.fromPayload):
+        (WI.Canvas.prototype.get backtrace):
+
+        * UserInterface/Views/CanvasDetailsSidebarPanel.css:
+        (.sidebar > .panel.details.canvas .details-section.canvas-backtrace .call-frame):
+
+        * UserInterface/Views/CanvasDetailsSidebarPanel.js:
+        (WI.CanvasDetailsSidebarPanel.prototype.initialLayout):
+        (WI.CanvasDetailsSidebarPanel.prototype.layout):
+        (WI.CanvasDetailsSidebarPanel.prototype._refreshBacktraceSection):
+
+        * UserInterface/Views/ResourceIcons.css:
+        (.canvas > .icon):
+        (.canvas .icon): Deleted.
+
 2017-10-26  Devin Rousso  <webkit@devinrousso.com>
 
         Web Inspector: Canvas Tab: canvas path components from old page stick around when page is reloaded
index 901486a..9c0ee07 100644 (file)
@@ -125,6 +125,7 @@ localizedStrings["Available Style Sheets"] = "Available Style Sheets";
 localizedStrings["Average Time"] = "Average Time";
 localizedStrings["Back (%s)"] = "Back (%s)";
 localizedStrings["Background"] = "Background";
+localizedStrings["Backtrace"] = "Backtrace";
 localizedStrings["Basis"] = "Basis";
 localizedStrings["Beacon"] = "Beacon";
 localizedStrings["Beacons"] = "Beacons";
index f797950..8676338 100644 (file)
@@ -25,7 +25,7 @@
 
 WI.Canvas = class Canvas extends WI.Object
 {
-    constructor(identifier, contextType, frame, {domNode, cssCanvasName, contextAttributes, memoryCost} = {})
+    constructor(identifier, contextType, frame, {domNode, cssCanvasName, contextAttributes, memoryCost, backtrace} = {})
     {
         super();
 
@@ -40,6 +40,7 @@ WI.Canvas = class Canvas extends WI.Object
         this._cssCanvasName = cssCanvasName || "";
         this._contextAttributes = contextAttributes || {};
         this._memoryCost = memoryCost || NaN;
+        this._backtrace = backtrace || [];
 
         this._cssCanvasClientNodes = null;
         this._shaderProgramCollection = new WI.ShaderProgramCollection;
@@ -78,6 +79,7 @@ WI.Canvas = class Canvas extends WI.Object
             cssCanvasName: payload.cssCanvasName,
             contextAttributes: payload.contextAttributes,
             memoryCost: payload.memoryCost,
+            backtrace: Array.isArray(payload.backtrace) ? payload.backtrace.map((item) => WI.CallFrame.fromPayload(WI.mainTarget, item)) : [],
         });
     }
 
@@ -109,6 +111,7 @@ WI.Canvas = class Canvas extends WI.Object
     get frame() { return this._frame; }
     get cssCanvasName() { return this._cssCanvasName; }
     get contextAttributes() { return this._contextAttributes; }
+    get backtrace() { return this._backtrace; }
     get shaderProgramCollection() { return this._shaderProgramCollection; }
     get recordingCollection() { return this._recordingCollection; }
 
index 1bc98a5..c7db484 100644 (file)
     display: block;
 }
 
+.sidebar > .panel.details.canvas .details-section.canvas-backtrace .call-frame {
+    margin: 3px;
+    font-size: 11px;
+}
+
 .sidebar > .panel.details.canvas > .content > .empty-content-placeholder {
     position: absolute;
     top: 0;
index f13b55c..7e39835 100644 (file)
@@ -128,6 +128,10 @@ WI.CanvasDetailsSidebarPanel = class CanvasDetailsSidebarPanel extends WI.Detail
         this._cssCanvasSection.element.hidden = true;
         this._sections.push(this._cssCanvasSection);
 
+        this._backtraceSection = new WI.DetailsSection("canvas-backtrace", WI.UIString("Backtrace"));
+        this._backtraceSection.element.hidden = true;
+        this._sections.push(this._backtraceSection);
+
         this._emptyContentPlaceholder = document.createElement("div");
         this._emptyContentPlaceholder.className = "empty-content-placeholder";
 
@@ -153,6 +157,7 @@ WI.CanvasDetailsSidebarPanel = class CanvasDetailsSidebarPanel extends WI.Detail
         this._refreshSourceSection();
         this._refreshAttributesSection();
         this._refreshCSSCanvasSection();
+        this._refreshBacktraceSection();
     }
 
     sizeDidChange()
@@ -289,6 +294,18 @@ WI.CanvasDetailsSidebarPanel = class CanvasDetailsSidebarPanel extends WI.Detail
         });
     }
 
+    _refreshBacktraceSection()
+    {
+        this._backtraceSection.element.hidden = !this._canvas.backtrace.length;
+
+        const showFunctionName = true;
+        this._backtraceSection.groups = this._canvas.backtrace.map((callFrame) => {
+            return {
+                element: new WI.CallFrameView(callFrame, showFunctionName),
+            };
+        });
+    }
+
     _formatMemoryRow()
     {
         if (!this.didInitialLayout)
index 9649cd4..4d0cbb1 100644 (file)
@@ -76,7 +76,7 @@
     content: url(../Images/Beacon.svg);
 }
 
-.canvas .icon {
+.canvas .icon {
     content: url(../Images/Canvas.svg);
 }