Diff
Modified: trunk/LayoutTests/ChangeLog (237807 => 237808)
--- trunk/LayoutTests/ChangeLog 2018-11-05 17:33:54 UTC (rev 237807)
+++ trunk/LayoutTests/ChangeLog 2018-11-05 17:34:48 UTC (rev 237808)
@@ -1,3 +1,16 @@
+2018-11-05 Devin Rousso <[email protected]>
+
+ Web Inspector: show save/restore stack for recorded 2D Canvases
+ https://bugs.webkit.org/show_bug.cgi?id=175283
+ <rdar://problem/34040756>
+
+ Reviewed by Matt Baker.
+
+ * inspector/canvas/recording-2d.html:
+ * inspector/canvas/resources/recording-utilities.js:
+ (TestPage.registerInitializer.log):
+ (TestPage.registerInitializer.async logRecording):
+
2018-11-05 Thibault Saunier <[email protected]>
[GStreamer][WebRTC] Error out when simulcast is activated
Modified: trunk/LayoutTests/inspector/canvas/recording-2d.html (237807 => 237808)
--- trunk/LayoutTests/inspector/canvas/recording-2d.html 2018-11-05 17:33:54 UTC (rev 237807)
+++ trunk/LayoutTests/inspector/canvas/recording-2d.html 2018-11-05 17:34:48 UTC (rev 237808)
@@ -519,8 +519,8 @@
async function logStates(recording) {
async function compare(index, expected) {
- let swizzledState = await recording._swizzleState(recording.initialState.states[index]);
- InspectorTest.expectEqual(swizzledState["fillStyle"], expected, `State ${index} should match expected fillStyle value.`)
+ let state = await WI.RecordingState.swizzleInitialState(recording, recording.initialState.states[index]);
+ InspectorTest.expectEqual(state.get("fillStyle"), expected, `State ${index} should match expected fillStyle value.`)
}
await compare(0, "#000000");
Modified: trunk/LayoutTests/inspector/canvas/resources/recording-utilities.js (237807 => 237808)
--- trunk/LayoutTests/inspector/canvas/resources/recording-utilities.js 2018-11-05 17:33:54 UTC (rev 237807)
+++ trunk/LayoutTests/inspector/canvas/resources/recording-utilities.js 2018-11-05 17:34:48 UTC (rev 237808)
@@ -1,12 +1,11 @@
TestPage.registerInitializer(() => {
function log(object, indent) {
- for (let key of Object.keys(object)) {
- let value = object[key];
+ for (let [name, value] of object) {
if (typeof value === "string")
value = sanitizeURL(value);
else if (Array.isArray(value) && value[0] instanceof DOMMatrix)
value[0] = [value[0].a, value[0].b, value[0].c, value[0].d, value[0].e, value[0].f];
- InspectorTest.log(indent + key + ": " + JSON.stringify(value));
+ InspectorTest.log(indent + name + ": " + JSON.stringify(value));
}
}
@@ -14,17 +13,17 @@
InspectorTest.log("initialState:");
InspectorTest.log(" attributes:");
- log(recording.initialState.attributes, " ");
+ log(Object.entries(recording.initialState.attributes), " ");
let currentState = recording.initialState.states.lastValue;
if (currentState) {
InspectorTest.log(" current state:");
- let swizzledState = await recording._swizzleState(currentState);
- log(swizzledState, " ");
+ let state = await WI.RecordingState.swizzleInitialState(recording, currentState);
+ log(state, " ");
}
InspectorTest.log(" parameters:");
- log(recording.initialState.parameters, " ");
+ log(Object.entries(recording.initialState.parameters), " ");
InspectorTest.log(" content: " + JSON.stringify(recording.initialState.content));
Modified: trunk/Source/WebInspectorUI/ChangeLog (237807 => 237808)
--- trunk/Source/WebInspectorUI/ChangeLog 2018-11-05 17:33:54 UTC (rev 237807)
+++ trunk/Source/WebInspectorUI/ChangeLog 2018-11-05 17:34:48 UTC (rev 237808)
@@ -1,3 +1,60 @@
+2018-11-05 Devin Rousso <[email protected]>
+
+ Web Inspector: show save/restore stack for recorded 2D Canvases
+ https://bugs.webkit.org/show_bug.cgi?id=175283
+ <rdar://problem/34040756>
+
+ Reviewed by Matt Baker.
+
+ Instead of using plain objects for holding the `WI.Recording`'s state, use a model object
+ so that more data can be passed around. When visualizing the state, show any previously
+ saved states in a `WI.DetailsSection` underneath the current state. If there are no saved
+ states (meaning there is only the current state), don't use a `WI.DetailsSection`.
+
+ * UserInterface/Models/RecordingState.js: Added.
+ (WI.RecordingState):
+ (WI.RecordingState.fromContext):
+ (WI.RecordingState.async swizzleInitialState):
+ (WI.RecordingState.prototype.get source):
+ (WI.RecordingState.prototype.has):
+ (WI.RecordingState.prototype.get return):
+ (WI.RecordingState.prototype.toJSON):
+ (WI.RecordingState.prototype.[Symbol.iterator]):
+
+ * UserInterface/Models/Recording.js:
+ (WI.Recording.prototype.async _process):
+ (WI.Recording.prototype.async _swizzleState): Deleted.
+
+ * UserInterface/Models/RecordingAction.js:
+ (WI.RecordingAction.prototype.process):
+ (WI.RecordingAction.deriveCurrentState): Deleted.
+
+ * UserInterface/Views/RecordingContentView.js:
+ (WI.RecordingContentView.prototype._generateContentCanvas2D):
+
+ * UserInterface/Views/RecordingStateDetailsSidebarPanel.js:
+ (WI.RecordingStateDetailsSidebarPanel):
+ (WI.RecordingStateDetailsSidebarPanel.prototype.get scrollElement):
+ (WI.RecordingStateDetailsSidebarPanel.prototype.sizeDidChange): Added.
+ (WI.RecordingStateDetailsSidebarPanel.prototype._generateDetailsCanvas2D):
+ (WI.RecordingStateDetailsSidebarPanel.prototype._generateDetailsCanvas2D.isColorProperty): Deleted.
+ (WI.RecordingStateDetailsSidebarPanel.prototype._generateDetailsCanvas2D.createInlineSwatch): Deleted.
+ * UserInterface/Views/RecordingStateDetailsSidebarPanel.css:
+ (.sidebar > .panel.details.recording-state > .content .details-section > .header .source): Added.
+ (.sidebar > .panel.details.recording-state > .content .data-grid tr.modified): Added.
+ (.sidebar > .panel.details.recording-state > .content .data-grid tr:not(.selected).non-standard .name-column): Added.
+ (.sidebar > .panel.details.recording-state > .content .data-grid tr:not(.selected) .unavailable): Added.
+ (.sidebar > .panel.details.recording-state > .content .data-grid .inline-swatch): Added.
+ (.sidebar > .panel.details.recording-state > .content > .data-grid tr.modified): Deleted.
+ (.sidebar > .panel.details.recording-state > .content > .data-grid tr:not(.selected).non-standard): Deleted.
+ (.sidebar > .panel.details.recording-state > .content > .data-grid tr:not(.selected) .unavailable): Deleted.
+ (.sidebar > .panel.details.recording-state > .content > .data-grid .inline-swatch): Deleted.
+
+ * UserInterface/Main.html:
+ * UserInterface/Test.html:
+
+ * Localizations/en.lproj/localizedStrings.js:
+
2018-11-03 Devin Rousso <[email protected]>
Web Inspector: Canvas: capture changes to <canvas> that would affect the recorded context
Modified: trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js (237807 => 237808)
--- trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js 2018-11-05 17:33:54 UTC (rev 237807)
+++ trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js 2018-11-05 17:34:48 UTC (rev 237808)
@@ -54,6 +54,7 @@
localizedStrings["%s cannot be modified"] = "%s cannot be modified";
localizedStrings["%s delay"] = "%s delay";
localizedStrings["%s interval"] = "%s interval";
+localizedStrings["(Action %s)"] = "(Action %s)";
localizedStrings["(Disk)"] = "(Disk)";
localizedStrings["(Index)"] = "(Index)";
localizedStrings["(Memory)"] = "(Memory)";
@@ -252,6 +253,7 @@
localizedStrings["Create Breakpoint"] = "Create Breakpoint";
localizedStrings["Create a new tab"] = "Create a new tab";
localizedStrings["Current"] = "Current";
+localizedStrings["Current State"] = "Current State";
localizedStrings["Custom"] = "Custom";
localizedStrings["DNS"] = "DNS";
localizedStrings["DOM Content Loaded \u2014 %s"] = "DOM Content Loaded \u2014 %s";
@@ -745,9 +747,11 @@
localizedStrings["Run %d"] = "Run %d";
localizedStrings["Running the ā%sā audit"] = "Running the ā%sā audit";
localizedStrings["Samples"] = "Samples";
+localizedStrings["Save %d"] = "Save %d";
localizedStrings["Save File"] = "Save File";
localizedStrings["Save Selected"] = "Save Selected";
localizedStrings["Save configuration"] = "Save configuration";
+localizedStrings["Saved States"] = "Saved States";
localizedStrings["Scheduling:"] = "Scheduling:";
localizedStrings["Scheme"] = "Scheme";
localizedStrings["Scope"] = "Scope";
Modified: trunk/Source/WebInspectorUI/UserInterface/Main.html (237807 => 237808)
--- trunk/Source/WebInspectorUI/UserInterface/Main.html 2018-11-05 17:33:54 UTC (rev 237807)
+++ trunk/Source/WebInspectorUI/UserInterface/Main.html 2018-11-05 17:34:48 UTC (rev 237808)
@@ -413,6 +413,7 @@
<script src=""
<script src=""
<script src=""
+ <script src=""
<script src=""
<script src=""
<script src=""
Modified: trunk/Source/WebInspectorUI/UserInterface/Models/Recording.js (237807 => 237808)
--- trunk/Source/WebInspectorUI/UserInterface/Models/Recording.js 2018-11-05 17:33:54 UTC (rev 237807)
+++ trunk/Source/WebInspectorUI/UserInterface/Models/Recording.js 2018-11-05 17:34:48 UTC (rev 237808)
@@ -375,21 +375,14 @@
let initialContent = await WI.ImageUtilities.promisifyLoad(this._initialState.content);
this._processContext.drawImage(initialContent, 0, 0);
- for (let state of this._initialState.states) {
- let swizzledState = await this._swizzleState(state);
- for (let [key, value] of Object.entries(swizzledState)) {
- try {
- if (WI.RecordingAction.isFunctionForType(this._type, key))
- this._processContext[key](...value);
- else
- this._processContext[key] = value;
- } catch { }
- }
+ for (let initialState of this._initialState.states) {
+ let state = await WI.RecordingState.swizzleInitialState(this, initialState);
+ state.apply(this._type, this._processContext);
// The last state represents the current state, which should not be saved.
- if (state !== this._initialState.states.lastValue) {
+ if (initialState !== this._initialState.states.lastValue) {
this._processContext.save();
- this._processStates.push(WI.RecordingAction.deriveCurrentState(this._type, this._processContext));
+ this._processStates.push(WI.RecordingState.fromContext(this._type, this._processContext));
}
}
}
@@ -456,72 +449,6 @@
this._processContext = null;
this._processing = false;
}
-
- async _swizzleState(state)
- {
- let swizzledState = {};
-
- for (let [key, value] of Object.entries(state)) {
- // COMPATIBILITY (iOS 12.0): Recording.InitialState.states did not exist yet
- let keyIndex = parseInt(key);
- if (!isNaN(keyIndex))
- key = await this.swizzle(keyIndex, WI.Recording.Swizzle.String);
-
- switch (key) {
- case "setTransform":
- value = [await this.swizzle(value, WI.Recording.Swizzle.DOMMatrix)];
- break;
-
- case "fillStyle":
- case "strokeStyle":
- let [gradient, pattern, string] = await Promise.all([
- this.swizzle(value, WI.Recording.Swizzle.CanvasGradient),
- this.swizzle(value, WI.Recording.Swizzle.CanvasPattern),
- this.swizzle(value, WI.Recording.Swizzle.String),
- ]);
- if (gradient && !pattern)
- value = gradient;
- else if (pattern && !gradient)
- value = pattern;
- else
- value = string;
- break;
-
- case "direction":
- case "font":
- case "globalCompositeOperation":
- case "imageSmoothingQuality":
- case "lineCap":
- case "lineJoin":
- case "shadowColor":
- case "textAlign":
- case "textBaseline":
- value = await this.swizzle(value, WI.Recording.Swizzle.String);
- break;
-
- case "globalAlpha":
- case "lineWidth":
- case "miterLimit":
- case "shadowOffsetX":
- case "shadowOffsetY":
- case "shadowBlur":
- case "lineDashOffset":
- value = await this.swizzle(value, WI.Recording.Swizzle.Number);
- break;
-
- case "setPath":
- value = [await this.swizzle(value[0], WI.Recording.Swizzle.Path2D)];
- break;
- }
-
- if (value === undefined || (Array.isArray(value) && value.includes(undefined)))
- continue;
-
- swizzledState[key] = value;
- }
-
- return swizzledState;
- }
};
WI.Recording.Event = {
Modified: trunk/Source/WebInspectorUI/UserInterface/Models/RecordingAction.js (237807 => 237808)
--- trunk/Source/WebInspectorUI/UserInterface/Models/RecordingAction.js 2018-11-05 17:33:54 UTC (rev 237807)
+++ trunk/Source/WebInspectorUI/UserInterface/Models/RecordingAction.js 2018-11-05 17:34:48 UTC (rev 237808)
@@ -135,52 +135,6 @@
return null;
}
- static deriveCurrentState(type, context)
- {
- if (type === WI.Recording.Type.Canvas2D) {
- let matrix = context.getTransform();
-
- let state = {};
-
- if (WI.ImageUtilities.supportsCanvasPathDebugging()) {
- state.currentX = context.currentX;
- state.currentY = context.currentY;
- }
-
- state.direction = context.direction;
- state.fillStyle = context.fillStyle;
- state.font = context.font;
- state.globalAlpha = context.globalAlpha;
- state.globalCompositeOperation = context.globalCompositeOperation;
- state.imageSmoothingEnabled = context.imageSmoothingEnabled;
- state.imageSmoothingQuality = context.imageSmoothingQuality;
- state.lineCap = context.lineCap;
- state.lineDash = context.getLineDash();
- state.lineDashOffset = context.lineDashOffset;
- state.lineJoin = context.lineJoin;
- state.lineWidth = context.lineWidth;
- state.miterLimit = context.miterLimit;
- state.shadowBlur = context.shadowBlur;
- state.shadowColor = context.shadowColor;
- state.shadowOffsetX = context.shadowOffsetX;
- state.shadowOffsetY = context.shadowOffsetY;
- state.strokeStyle = context.strokeStyle;
- state.textAlign = context.textAlign;
- state.textBaseline = context.textBaseline;
- state.transform = [matrix.a, matrix.b, matrix.c, matrix.d, matrix.e, matrix.f];
- state.webkitImageSmoothingEnabled = context.webkitImageSmoothingEnabled;
- state.webkitLineDash = context.webkitLineDash;
- state.webkitLineDashOffset = context.webkitLineDashOffset;
-
- if (WI.ImageUtilities.supportsCanvasPathDebugging())
- state.setPath = [context.getPath()];
-
- return state;
- }
-
- return null;
- }
-
static _prototypeForType(type)
{
if (type === WI.Recording.Type.Canvas2D)
@@ -261,7 +215,7 @@
}
if (recording.type === WI.Recording.Type.Canvas2D) {
- let currentState = WI.RecordingAction.deriveCurrentState(recording.type, context);
+ let currentState = WI.RecordingState.fromContext(recording.type, context, {source: this});
console.assert(currentState);
if (this.name === "save")
@@ -274,10 +228,11 @@
let lastState = null;
if (lastAction) {
- lastState = lastAction.states.lastValue;
- for (let key in currentState) {
- if (!(key in lastState) || (currentState[key] !== lastState[key] && !Object.shallowEqual(currentState[key], lastState[key])))
- this._stateModifiers.add(key);
+ let previousState = lastAction.states.lastValue;
+ for (let [name, value] of currentState) {
+ let previousValue = previousState.get(name);
+ if (value !== previousValue && !Object.shallowEqual(value, previousValue))
+ this._stateModifiers.add(name);
}
}
Added: trunk/Source/WebInspectorUI/UserInterface/Models/RecordingState.js (0 => 237808)
--- trunk/Source/WebInspectorUI/UserInterface/Models/RecordingState.js (rev 0)
+++ trunk/Source/WebInspectorUI/UserInterface/Models/RecordingState.js 2018-11-05 17:34:48 UTC (rev 237808)
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2018 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+WI.RecordingState = class RecordingState
+{
+ constructor(data, {source} = {})
+ {
+ this._data = data;
+ this._source = source || null;
+ }
+
+ // Static
+
+ static fromContext(type, context, options = {})
+ {
+ if (type !== WI.Recording.Type.Canvas2D)
+ return null;
+
+ let matrix = context.getTransform();
+
+ let data = ""
+
+ if (WI.ImageUtilities.supportsCanvasPathDebugging()) {
+ data.currentX = context.currentX;
+ data.currentY = context.currentY;
+ }
+
+ data.direction = context.direction;
+ data.fillStyle = context.fillStyle;
+ data.font = context.font;
+ data.globalAlpha = context.globalAlpha;
+ data.globalCompositeOperation = context.globalCompositeOperation;
+ data.imageSmoothingEnabled = context.imageSmoothingEnabled;
+ data.imageSmoothingQuality = context.imageSmoothingQuality;
+ data.lineCap = context.lineCap;
+ data.lineDash = context.getLineDash();
+ data.lineDashOffset = context.lineDashOffset;
+ data.lineJoin = context.lineJoin;
+ data.lineWidth = context.lineWidth;
+ data.miterLimit = context.miterLimit;
+ data.shadowBlur = context.shadowBlur;
+ data.shadowColor = context.shadowColor;
+ data.shadowOffsetX = context.shadowOffsetX;
+ data.shadowOffsetY = context.shadowOffsetY;
+ data.strokeStyle = context.strokeStyle;
+ data.textAlign = context.textAlign;
+ data.textBaseline = context.textBaseline;
+ data.transform = [matrix.a, matrix.b, matrix.c, matrix.d, matrix.e, matrix.f];
+ data.webkitImageSmoothingEnabled = context.webkitImageSmoothingEnabled;
+ data.webkitLineDash = context.webkitLineDash;
+ data.webkitLineDashOffset = context.webkitLineDashOffset;
+
+ if (WI.ImageUtilities.supportsCanvasPathDebugging())
+ data.setPath = [context.getPath()];
+
+ return new WI.RecordingState(data, options);
+ }
+
+ static async swizzleInitialState(recording, initialState)
+ {
+ if (recording.type === WI.Recording.Type.Canvas2D) {
+ let swizzledState = {};
+
+ for (let [name, value] of Object.entries(initialState)) {
+ // COMPATIBILITY (iOS 12.0): Recording.InitialState.states did not exist yet
+ let nameIndex = parseInt(name);
+ if (!isNaN(nameIndex))
+ name = await recording.swizzle(nameIndex, WI.Recording.Swizzle.String);
+
+ switch (name) {
+ case "setTransform":
+ value = [await recording.swizzle(value, WI.Recording.Swizzle.DOMMatrix)];
+ break;
+
+ case "fillStyle":
+ case "strokeStyle":
+ var [gradient, pattern, string] = await Promise.all([
+ recording.swizzle(value, WI.Recording.Swizzle.CanvasGradient),
+ recording.swizzle(value, WI.Recording.Swizzle.CanvasPattern),
+ recording.swizzle(value, WI.Recording.Swizzle.String),
+ ]);
+ if (gradient && !pattern)
+ value = gradient;
+ else if (pattern && !gradient)
+ value = pattern;
+ else
+ value = string;
+ break;
+
+ case "direction":
+ case "font":
+ case "globalCompositeOperation":
+ case "imageSmoothingQuality":
+ case "lineCap":
+ case "lineJoin":
+ case "shadowColor":
+ case "textAlign":
+ case "textBaseline":
+ value = await recording.swizzle(value, WI.Recording.Swizzle.String);
+ break;
+
+ case "globalAlpha":
+ case "lineWidth":
+ case "miterLimit":
+ case "shadowOffsetX":
+ case "shadowOffsetY":
+ case "shadowBlur":
+ case "lineDashOffset":
+ value = await recording.swizzle(value, WI.Recording.Swizzle.Number);
+ break;
+
+ case "setPath":
+ value = [await recording.swizzle(value[0], WI.Recording.Swizzle.Path2D)];
+ break;
+ }
+
+ if (value === undefined || (Array.isArray(value) && value.includes(undefined)))
+ continue;
+
+ swizzledState[name] = value;
+ }
+
+ return new WI.RecordingState(swizzledState);
+ }
+
+ return null;
+ }
+
+ // Public
+
+ get source() { return this._source; }
+
+ has(name)
+ {
+ return name in this._data;
+ }
+
+ get(name)
+ {
+ return this._data[name];
+ }
+
+ apply(type, context)
+ {
+ for (let [name, value] of this) {
+ if (!(name in context))
+ continue;
+
+ // Skip internal state used for path debugging.
+ if (name === "currentX" || name === "currentY")
+ continue;
+
+ try {
+ if (WI.RecordingAction.isFunctionForType(type, name))
+ context[name](...value);
+ else
+ context[name] = value;
+ } catch { }
+ }
+ }
+
+ toJSON()
+ {
+ return this._data;
+ }
+
+ [Symbol.iterator]()
+ {
+ return Object.entries(this._data)[Symbol.iterator]();
+ }
+};
Modified: trunk/Source/WebInspectorUI/UserInterface/Test.html (237807 => 237808)
--- trunk/Source/WebInspectorUI/UserInterface/Test.html 2018-11-05 17:33:54 UTC (rev 237807)
+++ trunk/Source/WebInspectorUI/UserInterface/Test.html 2018-11-05 17:34:48 UTC (rev 237808)
@@ -174,6 +174,7 @@
<script src=""
<script src=""
<script src=""
+ <script src=""
<script src=""
<script src=""
<script src=""
Modified: trunk/Source/WebInspectorUI/UserInterface/Views/RecordingContentView.js (237807 => 237808)
--- trunk/Source/WebInspectorUI/UserInterface/Views/RecordingContentView.js 2018-11-05 17:33:54 UTC (rev 237807)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/RecordingContentView.js 2018-11-05 17:34:48 UTC (rev 237808)
@@ -229,24 +229,8 @@
}
for (let state of snapshot.states) {
- for (let name in state) {
- if (!(name in snapshot.context))
- continue;
+ state.apply(this.representedObject.type, snapshot.context);
- // Skip internal state used for path debugging.
- if (name === "currentX" || name === "currentY")
- continue;
-
- try {
- if (WI.RecordingAction.isFunctionForType(this.representedObject.type, name))
- snapshot.context[name](...state[name]);
- else
- snapshot.context[name] = state[name];
- } catch {
- delete state[name];
- }
- }
-
++saveCount;
snapshot.context.save();
}
Modified: trunk/Source/WebInspectorUI/UserInterface/Views/RecordingStateDetailsSidebarPanel.css (237807 => 237808)
--- trunk/Source/WebInspectorUI/UserInterface/Views/RecordingStateDetailsSidebarPanel.css 2018-11-05 17:33:54 UTC (rev 237807)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/RecordingStateDetailsSidebarPanel.css 2018-11-05 17:34:48 UTC (rev 237808)
@@ -27,24 +27,29 @@
min-height: 100%;
}
-.sidebar > .panel.details.recording-state > .content > .data-grid tr.modified {
+.sidebar > .panel.details.recording-state > .content .details-section > .header .source {
+ -webkit-margin-start: 4px;
+ color: var(--text-color-gray-medium);
+}
+
+.sidebar > .panel.details.recording-state > .content .data-grid tr.modified {
background-color: var(--value-changed-highlight);
}
-.sidebar > .panel.details.recording-state > .content > .data-grid tr:not(.selected).non-standard {
+.sidebar > .panel.details.recording-state > .content .data-grid tr:not(.selected).non-standard .name-column {
opacity: 0.5;
}
-.sidebar > .panel.details.recording-state > .content > .data-grid tr:not(.selected) .unavailable {
+.sidebar > .panel.details.recording-state > .content .data-grid tr:not(.selected) .unavailable {
color: grey;
}
-.sidebar > .panel.details.recording-state > .content > .data-grid .inline-swatch {
+.sidebar > .panel.details.recording-state > .content .data-grid .inline-swatch {
vertical-align: -1px;
}
@media (prefers-dark-interface) {
- .sidebar > .panel.details.recording-state > .content > .data-grid tr.modified {
+ .sidebar > .panel.details.recording-state > .content .data-grid tr.modified {
color: var(--green-highlight-text-color);
}
}
Modified: trunk/Source/WebInspectorUI/UserInterface/Views/RecordingStateDetailsSidebarPanel.js (237807 => 237808)
--- trunk/Source/WebInspectorUI/UserInterface/Views/RecordingStateDetailsSidebarPanel.js 2018-11-05 17:33:54 UTC (rev 237807)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/RecordingStateDetailsSidebarPanel.js 2018-11-05 17:34:48 UTC (rev 237808)
@@ -32,7 +32,7 @@
this._recording = null;
this._action = null;
- this._dataGrid = null;
+ this._dataGrids = [];
}
// Public
@@ -78,92 +78,149 @@
get scrollElement()
{
- return this._dataGrid.scrollContainer;
+ if (this._dataGrids.length === 1)
+ return this._dataGrids[0].scrollContainer;
+ return super.scrollElement;
}
+ sizeDidChange()
+ {
+ super.sizeDidChange();
+
+ if (this._dataGrids.length === 1)
+ return;
+
+ // FIXME: <https://webkit.org/b/152269> Web Inspector: Convert DetailsSection classes to use View
+ for (let dataGrid of this._dataGrids)
+ dataGrid.sizeDidChange();
+ }
+
// Private
_generateDetailsCanvas2D(action)
{
- if (!this._dataGrid) {
- this._dataGrid = new WI.DataGrid({
- name: {title: WI.UIString("Name")},
- value: {title: WI.UIString("Value")},
- });
- }
- if (!this._dataGrid.parentView)
- this.contentView.addSubview(this._dataGrid);
+ if (this._dataGrids.length === 1)
+ this.contentView.removeSubview(this._dataGrids[0]);
- this._dataGrid.removeChildren();
+ this.contentView.element.removeChildren();
+ this._dataGrids = [];
+
let currentState = action.states.lastValue;
console.assert(currentState);
if (!currentState)
return;
- function isColorProperty(name) {
- return name === "fillStyle" || name === "strokeStyle" || name === "shadowColor";
- }
+ let createStateDataGrid = (state) => {
+ let dataGrid = new WI.DataGrid({
+ name: {title: WI.UIString("Name")},
+ value: {title: WI.UIString("Value")},
+ });
+ this._dataGrids.push(dataGrid);
- function createInlineSwatch(value) {
- let color = WI.Color.fromString(value);
- if (!color)
- return null;
+ for (let [name, value] of state) {
+ // Skip internal state used for path debugging.
+ if (name === "setPath")
+ continue;
- const readOnly = true;
- return new WI.InlineSwatch(WI.InlineSwatch.Type.Color, color, readOnly);
- }
+ if (typeof value === "object") {
+ let isGradient = value instanceof CanvasGradient;
+ let isPattern = value instanceof CanvasPattern;
+ if (isGradient || isPattern) {
+ let textElement = document.createElement("span");
+ textElement.classList.add("unavailable");
- for (let name in currentState) {
- // Skip internal state used for path debugging.
- if (name === "setPath")
- continue;
+ let image = null;
+ if (isGradient) {
+ textElement.textContent = WI.unlocalizedString("CanvasGradient");
+ image = WI.ImageUtilities.imageFromCanvasGradient(value, 100, 100);
+ } else if (isPattern) {
+ textElement.textContent = WI.unlocalizedString("CanvasPattern");
+ image = value.__image;
+ }
- let value = currentState[name];
- if (typeof value === "object") {
- let isGradient = value instanceof CanvasGradient;
- let isPattern = value instanceof CanvasPattern;
- if (isGradient || isPattern) {
- let textElement = document.createElement("span");
- textElement.classList.add("unavailable");
+ let fragment = document.createDocumentFragment();
+ if (image) {
+ let swatch = new WI.InlineSwatch(WI.InlineSwatch.Type.Image, image);
+ fragment.appendChild(swatch.element);
+ }
+ fragment.appendChild(textElement);
+ value = fragment;
+ } else {
+ if (value instanceof DOMMatrix)
+ value = [value.a, value.b, value.c, value.d, value.e, value.f];
- let image = null;
- if (isGradient) {
- textElement.textContent = WI.unlocalizedString("CanvasGradient");
- image = WI.ImageUtilities.imageFromCanvasGradient(value, 100, 100);
- } else if (isPattern) {
- textElement.textContent = WI.unlocalizedString("CanvasPattern");
- image = value.__image;
+ value = JSON.stringify(value);
}
+ } else if (name === "fillStyle" || name === "strokeStyle" || name === "shadowColor") {
+ let color = WI.Color.fromString(value);
+ const readOnly = true;
+ let swatch = new WI.InlineSwatch(WI.InlineSwatch.Type.Color, color, readOnly);
+ value = document.createElement("span");
+ value.append(swatch.element, color.toString());
+ }
- let fragment = document.createDocumentFragment();
- if (image) {
- let swatch = new WI.InlineSwatch(WI.InlineSwatch.Type.Image, image);
- fragment.appendChild(swatch.element);
+ let classNames = [];
+ if (state === currentState && !action.isGetter && action.stateModifiers.has(name))
+ classNames.push("modified");
+ if (name.startsWith("webkit"))
+ classNames.push("non-standard");
+
+ const hasChildren = false;
+ dataGrid.appendChild(new WI.DataGridNode({name, value}, hasChildren, classNames));
+ }
+
+ dataGrid.updateLayoutIfNeeded();
+ return dataGrid;
+ };
+
+ let createStateSection = (state, index = NaN) => {
+ let isCurrentState = isNaN(index);
+
+ let dataGrid = createStateDataGrid(state);
+ let row = new WI.DetailsSectionDataGridRow(dataGrid);
+ let group = new WI.DetailsSectionGroup([row]);
+
+ let identifier = isCurrentState ? "recording-current-state" : `recording-saved-state-${index + 1}`;
+ const title = null;
+ const optionsElement = null;
+ let defaultCollapsedSettingValue = !isCurrentState;
+ let section = new WI.DetailsSection(identifier, title, [group], optionsElement, defaultCollapsedSettingValue);
+
+ if (isCurrentState)
+ section.title = WI.UIString("Current State");
+ else {
+ section.title = WI.UIString("Save %d").format(index + 1);
+
+ if (state.source) {
+ let sourceIndex = this._recording.actions.indexOf(state.source);
+ if (sourceIndex >= 0) {
+ let sourceElement = section.titleElement.appendChild(document.createElement("span"));
+ sourceElement.classList.add("source");
+ sourceElement.textContent = WI.UIString("(Action %s)").format(sourceIndex);
}
- fragment.appendChild(textElement);
- value = fragment;
- } else {
- if (value instanceof DOMMatrix)
- value = [value.a, value.b, value.c, value.d, value.e, value.f];
-
- value = JSON.stringify(value);
}
- } else if (isColorProperty(name)) {
- let swatch = createInlineSwatch(value);
- let label = swatch.value.toString();
- value = document.createElement("span");
- value.append(swatch.element, label);
}
- let classNames = [];
- if (!action.isGetter && action.stateModifiers.has(name))
- classNames.push("modified");
- if (name.startsWith("webkit"))
- classNames.push("non-standard");
+ return section;
+ };
- const hasChildren = false;
- this._dataGrid.appendChild(new WI.DataGridNode({name, value}, hasChildren, classNames));
+ if (action.states.length === 1) {
+ this.contentView.addSubview(createStateDataGrid(currentState));
+ return;
}
+
+ let currentStateSection = createStateSection(currentState);
+ this.contentView.element.appendChild(currentStateSection.element);
+
+ let savedStateSections = [];
+ for (let i = action.states.length - 2; i >= 0; --i) {
+ let savedStateSection = createStateSection(action.states[i], i);
+ savedStateSections.push(savedStateSection);
+ }
+
+ let savedStatesGroup = new WI.DetailsSectionGroup(savedStateSections);
+ let savedStatesSection = new WI.DetailsSection("recording-saved-states", WI.UIString("Saved States"), [savedStatesGroup]);
+ this.contentView.element.appendChild(savedStatesSection.element);
}
};