Changeset 224367 in webkit
- Timestamp:
- Nov 2, 2017 5:54:35 PM (6 years ago)
- Location:
- trunk/Source/WebInspectorUI
- Files:
-
- 11 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebInspectorUI/ChangeLog
r224357 r224367 1 2017-11-02 Devin Rousso <webkit@devinrousso.com> 2 3 Web Inspector: Canvas: recording parameters that include an Image should show an InlineSwatch (2D canvas) 4 https://bugs.webkit.org/show_bug.cgi?id=177032 5 6 Reviewed by Brian Burg. 7 8 * Localizations/en.lproj/localizedStrings.js: 9 10 * UserInterface/Test.html: 11 * UserInterface/Base/ImageUtilities.js: 12 (WI.scratchCanvasContext2D): 13 Creates a static canvas that can be used for scratch purposes, such as converting ImageData 14 to an Image, or rendering the result of a CanvasGradient. The canvas is reset after each 15 call of the function so it can be reused by other callers. 16 17 (WI.imageFromImageData): 18 (WI.imageFromCanvasGradient): 19 Utility functions for getting a dataURL image of ImageData/CanvasGradient after drawing it 20 onto WI.scratchCanvasContext2D. 21 22 * UserInterface/Models/Recording.js: 23 (WI.Recording.prototype.async.swizzle): 24 Set the Image used to create a CanvasPattern as an expando property for later use. 25 26 * UserInterface/Models/RecordingAction.js: 27 (WI.RecordingAction.prototype.getImageParameters): 28 29 * UserInterface/Views/RecordingActionTreeElement.js: 30 (WI.RecordingActionTreeElement._generateDOM): 31 Add Image InlineSwatch elements for parameters that are viewable as an image. For ImageData 32 and CanvasGradient, WI.scratchCanvasContext2D is used to draw the ImageData/CanvasGradient 33 and get a dataURL to be used as the image. 34 35 (WI.RecordingActionTreeElement._createSwatchForColorParameters): 36 Drive-by: add checks that the parameter is not a CanvasGradient or CanvasPattern. 37 38 * UserInterface/Views/RecordingStateDetailsSidebarPanel.js: 39 (WI.RecordingStateDetailsSidebarPanel.prototype._generateDetailsCanvas2D): 40 Add Image InlineSwatch elements for fillStyle/strokeStyle when the value is a CanvasGradient 41 or a CanvasPattern. 42 43 * UserInterface/Views/InlineSwatch.js: 44 (WI.InlineSwatch): 45 (WI.InlineSwatch.prototype._updateSwatch): 46 (WI.InlineSwatch.prototype._swatchElementClicked): 47 * UserInterface/Views/InlineSwatch.css: 48 (.inline-swatch): 49 (.inline-swatch:matches(.color, .gradient)): 50 (.inline-swatch:matches(.bezier, .spring, .variable)): 51 (.inline-swatch:not(.read-only):matches(.bezier, .spring, .variable):hover): 52 (.inline-swatch:not(.read-only):matches(.bezier, .spring, .variable):active): 53 (.inline-swatch:not(.read-only):active > span): 54 (.inline-swatch:matches(.bezier, .spring, .variable) > span): 55 (.inline-swatch.image > span): 56 (.inline-swatch:matches(.bezier, .spring, .variable):hover): Deleted. 57 (.inline-swatch:matches(.bezier, .spring, .variable):active): Deleted. 58 (.inline-swatch:active > span): Deleted. 59 (.inline-swatch:matches(.bezier, .spring) > span): Deleted. 60 Add Image type for showing previews of images. 61 Drive-by: simplify some styles. 62 63 * UserInterface/Views/RecordingActionTreeElement.css: 64 (.item.action > .titles .parameters > .inline-swatch): 65 (.tree-outline:matches(:focus, .force-focus) .item.action > .titles .parameters > .inline-swatch): Deleted. 66 Drive-by: remove the :focus requirement, as it would cause the InlineSwatch to shift when 67 the user clicked out of the WebInspector window. 68 1 69 2017-11-02 Joseph Pecoraro <pecoraro@apple.com> 2 70 -
trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js
r224357 r224367 996 996 localizedStrings["Vertex Shader"] = "Vertex Shader"; 997 997 localizedStrings["Vertical"] = "Vertical"; 998 localizedStrings["View Image"] = "View Image"; 998 999 localizedStrings["View Recordings... (%d)"] = "View Recordings... (%d)"; 999 1000 localizedStrings["View variable value"] = "View variable value"; -
trunk/Source/WebInspectorUI/UserInterface/Base/ImageUtilities.js
r191740 r224367 52 52 return wrapper; 53 53 } 54 55 (function() { 56 let canvas = null; 57 let context = null; 58 59 WI.scratchCanvasContext2D = function(callback) { 60 if (!canvas) 61 canvas = document.createElement("canvas"); 62 63 if (!context) 64 context = canvas.getContext("2d"); 65 66 context.clearRect(0, 0, canvas.width, canvas.height); 67 context.save(); 68 callback(context); 69 context.restore(); 70 }; 71 })(); 72 73 WI.imageFromImageData = function(data) { 74 console.assert(data instanceof ImageData); 75 76 let image = null; 77 WI.scratchCanvasContext2D((context) => { 78 context.canvas.width = data.width; 79 context.canvas.height = data.height; 80 context.putImageData(data, 0, 0); 81 82 image = new Image; 83 image.src = context.canvas.toDataURL(); 84 }); 85 return image; 86 }; 87 88 WI.imageFromCanvasGradient = function(gradient, width, height) { 89 console.assert(gradient instanceof CanvasGradient); 90 91 let image = null; 92 WI.scratchCanvasContext2D((context) => { 93 context.canvas.width = width; 94 context.canvas.height = height; 95 context.fillStyle = gradient; 96 context.fillRect(0, 0, width, height); 97 98 image = new Image; 99 image.src = context.canvas.toDataURL(); 100 }); 101 return image; 102 }; -
trunk/Source/WebInspectorUI/UserInterface/Models/Recording.js
r223918 r224367 270 270 var gradientType = await this.swizzle(data[0], WI.Recording.Swizzle.String); 271 271 272 var context = document.createElement("canvas").getContext("2d"); 273 this._swizzle[index][type] = gradientType === "radial-gradient" ? context.createRadialGradient(...data[1]) : context.createLinearGradient(...data[1]); 272 WI.scratchCanvasContext2D((context) => { 273 this._swizzle[index][type] = gradientType === "radial-gradient" ? context.createRadialGradient(...data[1]) : context.createLinearGradient(...data[1]); 274 }); 274 275 275 276 for (let stop of data[2]) { … … 285 286 ]); 286 287 287 var context = document.createElement("canvas").getContext("2d"); 288 this._swizzle[index][type] = context.createPattern(image, repeat); 288 WI.scratchCanvasContext2D((context) => { 289 this._swizzle[index][type] = context.createPattern(image, repeat); 290 this._swizzle[index][type].__image = image; 291 }); 289 292 break; 290 293 } -
trunk/Source/WebInspectorUI/UserInterface/Models/RecordingAction.js
r223335 r224367 234 234 case "setShadow": 235 235 return this._parameters.slice(3); 236 } 237 238 return []; 239 } 240 241 getImageParameters() 242 { 243 switch (this._name) { 244 // 2D 245 case "createImageData": 246 case "createPattern": 247 case "drawImage": 248 case "fillStyle": 249 case "putImageData": 250 case "strokeStyle": 251 // 2D (non-standard) 252 case "drawImageFromRect": 253 case "webkitPutImageDataHD": 254 return this._parameters.slice(0, 1); 236 255 } 237 256 -
trunk/Source/WebInspectorUI/UserInterface/Test.html
r223952 r224367 53 53 <script src="Base/EventListener.js"></script> 54 54 <script src="Base/EventListenerSet.js"></script> 55 <script src="Base/ImageUtilities.js"></script> 55 56 <script src="Base/MIMETypeUtilities.js"></script> 56 57 <script src="Base/TextUtilities.js"></script> -
trunk/Source/WebInspectorUI/UserInterface/Views/InlineSwatch.css
r222102 r224367 32 32 margin-right: 3px; 33 33 vertical-align: -2px; 34 background-color: white; 35 border-radius: 2px; 36 overflow: hidden; 37 cursor: default; 38 } 39 40 .inline-swatch:matches(.color, .gradient) { 34 41 /* Make a checkered background for transparent colors to show against. */ 35 42 background-image: linear-gradient(to bottom, hsl(0, 0%, 80%), hsl(0, 0%, 80%)), 36 43 linear-gradient(to bottom, hsl(0, 0%, 80%), hsl(0, 0%, 80%)); 37 background-color: white;38 44 background-size: 50%; 39 45 background-position: top left, bottom right; 40 46 background-repeat: no-repeat; 41 border-radius: 2px;42 overflow: hidden;43 cursor: default;44 47 } 45 48 … … 54 57 .inline-swatch:matches(.bezier, .spring, .variable) { 55 58 margin-right: 2px; 56 background: none;57 59 } 58 60 59 .inline-swatch: matches(.bezier, .spring, .variable):hover {61 .inline-swatch:not(.read-only):matches(.bezier, .spring, .variable):hover { 60 62 filter: brightness(0.9); 61 63 } 62 64 63 .inline-swatch: matches(.bezier, .spring, .variable):active {65 .inline-swatch:not(.read-only):matches(.bezier, .spring, .variable):active { 64 66 filter: brightness(0.8); 65 67 } … … 89 91 } 90 92 91 .inline-swatch: active > span {93 .inline-swatch:not(.read-only):active > span { 92 94 border-color: hsl(0, 0%, 25%); 93 95 } 94 96 95 .inline-swatch:matches(.bezier, .spring ) > span {97 .inline-swatch:matches(.bezier, .spring, .variable) > span { 96 98 display: none; 99 } 100 101 .inline-swatch.image > span { 102 background-size: cover; 103 background-repeat: no-repeat; 97 104 } 98 105 -
trunk/Source/WebInspectorUI/UserInterface/Views/InlineSwatch.js
r222102 r224367 57 57 this._swatchElement.title = WI.UIString("View variable value"); 58 58 break; 59 case WI.InlineSwatch.Type.Image: 60 this._swatchElement.title = WI.UIString("View Image"); 61 break; 59 62 default: 60 63 WI.reportInternalError(`Unknown InlineSwatch type "${type}"`); … … 132 135 if (this._type === WI.InlineSwatch.Type.Color || this._type === WI.InlineSwatch.Type.Gradient) 133 136 this._swatchInnerElement.style.background = this._value ? this._value.toString() : null; 137 else if (this._type === WI.InlineSwatch.Type.Image) 138 this._swatchInnerElement.style.setProperty("background-image", `url(${this._value.src})`); 134 139 135 140 if (!dontFireEvents) … … 161 166 162 167 this._valueEditor = null; 163 if (this._type === WI.InlineSwatch.Type.Color) { 168 switch (this._type) { 169 case WI.InlineSwatch.Type.Color: 164 170 this._valueEditor = new WI.ColorPicker; 165 171 this._valueEditor.addEventListener(WI.ColorPicker.Event.ColorChanged, this._valueEditorValueDidChange, this); 166 172 this._valueEditor.addEventListener(WI.ColorPicker.Event.FormatChanged, (event) => popover.update()); 167 } else if (this._type === WI.InlineSwatch.Type.Gradient) { 173 break; 174 175 case WI.InlineSwatch.Type.Gradient: 168 176 this._valueEditor = new WI.GradientEditor; 169 177 this._valueEditor.addEventListener(WI.GradientEditor.Event.GradientChanged, this._valueEditorValueDidChange, this); 170 178 this._valueEditor.addEventListener(WI.GradientEditor.Event.ColorPickerToggled, (event) => popover.update()); 171 } else if (this._type === WI.InlineSwatch.Type.Bezier) { 179 break; 180 181 case WI.InlineSwatch.Type.Bezier: 172 182 this._valueEditor = new WI.BezierEditor; 173 183 this._valueEditor.addEventListener(WI.BezierEditor.Event.BezierChanged, this._valueEditorValueDidChange, this); 174 } else if (this._type === WI.InlineSwatch.Type.Spring) { 184 break; 185 186 case WI.InlineSwatch.Type.Spring: 175 187 this._valueEditor = new WI.SpringEditor; 176 188 this._valueEditor.addEventListener(WI.SpringEditor.Event.SpringChanged, this._valueEditorValueDidChange, this); 177 } else if (this._type === WI.InlineSwatch.Type.Variable) { 189 break; 190 191 case WI.InlineSwatch.Type.Variable: 178 192 this._valueEditor = {}; 179 193 … … 188 202 popover.update(); 189 203 }); 204 break; 205 206 case WI.InlineSwatch.Type.Image: 207 this._valueEditor = {}; 208 this._valueEditor.element = document.createElement("img"); 209 this._valueEditor.element.src = this._value.src; 210 this._valueEditor.element.classList.add("show-grid"); 211 this._valueEditor.element.style.setProperty("max-width", "50vw"); 212 this._valueEditor.element.style.setProperty("max-height", "50vh"); 213 break; 190 214 } 191 215 … … 202 226 203 227 let value = this._value || this._fallbackValue(); 204 if (this._type === WI.InlineSwatch.Type.Color) 228 switch (this._type) { 229 case WI.InlineSwatch.Type.Color: 205 230 this._valueEditor.color = value; 206 else if (this._type === WI.InlineSwatch.Type.Gradient) 231 break; 232 233 case WI.InlineSwatch.Type.Gradient: 207 234 this._valueEditor.gradient = value; 208 else if (this._type === WI.InlineSwatch.Type.Bezier) 235 break; 236 237 case WI.InlineSwatch.Type.Bezier: 209 238 this._valueEditor.bezier = value; 210 else if (this._type === WI.InlineSwatch.Type.Spring) 239 break; 240 241 case WI.InlineSwatch.Type.Spring: 211 242 this._valueEditor.spring = value; 212 else if (this._type === WI.InlineSwatch.Type.Variable) 243 break; 244 245 case WI.InlineSwatch.Type.Variable: 213 246 this._valueEditor.codeMirror.setValue(value); 247 break; 248 } 214 249 } 215 250 … … 334 369 Spring: "inline-swatch-type-spring", 335 370 Variable: "inline-swatch-type-variable", 371 Image: "inline-swatch-type-image", 336 372 }; 337 373 -
trunk/Source/WebInspectorUI/UserInterface/Views/RecordingActionTreeElement.css
r223918 r224367 71 71 } 72 72 73 .tree-outline:matches(:focus, .force-focus) .item.action > .titles .parameters > .inline-swatch {74 vertical-align: -1px;75 }76 77 73 .tree-outline[data-indent="1"] .item.action::before, 78 74 .tree-outline[data-indent="2"] .item.action::before { … … 130 126 .item.action:not(.selected) > .titles .parameter.swizzled { 131 127 color: var(--text-color-gray-medium); 128 } 129 130 .item.action > .titles .parameters > .inline-swatch { 131 vertical-align: -1px; 132 132 } 133 133 -
trunk/Source/WebInspectorUI/UserInterface/Views/RecordingActionTreeElement.js
r223335 r224367 132 132 if (colorParameters.length) { 133 133 let swatch = WI.RecordingActionTreeElement._createSwatchForColorParameters(colorParameters); 134 let insertionIndex = recordingAction.parameters.indexOf(colorParameters[0]); 135 let parameterElement = parametersContainer.children[insertionIndex]; 136 parametersContainer.insertBefore(swatch.element, parameterElement); 137 138 if (recordingAction.swizzleTypes[insertionIndex] === WI.Recording.Swizzle.String) { 139 parameterElement.textContent = swatch.value.toString(); 140 parameterElement.classList.add("color"); 134 if (swatch) { 135 let insertionIndex = recordingAction.parameters.indexOf(colorParameters[0]); 136 let parameterElement = parametersContainer.children[insertionIndex]; 137 parametersContainer.insertBefore(swatch.element, parameterElement); 138 139 if (recordingAction.swizzleTypes[insertionIndex] === WI.Recording.Swizzle.String) { 140 parameterElement.textContent = swatch.value.toString(); 141 parameterElement.classList.add("color"); 142 } 143 } 144 } 145 146 let imageParameters = recordingAction.getImageParameters(); 147 let isImage = imageParameters[0] instanceof HTMLImageElement; 148 let isImageData = imageParameters[0] instanceof ImageData; 149 let isCanvasGradient = imageParameters[0] instanceof CanvasGradient; 150 let isCanvasPattern = imageParameters[0] instanceof CanvasPattern; 151 if (imageParameters.length && (isImage || isImageData || isCanvasGradient || isCanvasPattern)) { 152 let image = imageParameters[0]; 153 154 if (isImageData) 155 image = WI.imageFromImageData(image); 156 else if (isCanvasGradient) 157 image = WI.imageFromCanvasGradient(image, 100, 100); 158 else if (isCanvasPattern) 159 image = image.__image; 160 161 if (image) { 162 let swatch = new WI.InlineSwatch(WI.InlineSwatch.Type.Image, image); 163 let insertionIndex = recordingAction.parameters.indexOf(imageParameters[0]); 164 let parameterElement = parametersContainer.children[insertionIndex]; 165 parametersContainer.insertBefore(swatch.element, parameterElement); 141 166 } 142 167 } … … 155 180 if (typeof parameters[0] === "string") 156 181 color = WI.Color.fromString(parameters[0]); 157 else 182 else if (!isNaN(parameters[0])) 158 183 rgb = WI.Color.normalized2rgb(parameters[0], parameters[0], parameters[0]); 159 184 break; … … 173 198 174 199 if (!color) { 200 if (rgb.length !== 3) 201 return null; 202 175 203 let alpha = parameters.length === 1 ? 1 : parameters.lastValue; 176 204 color = new WI.Color(WI.Color.Format.RGBA, [...rgb, alpha]); -
trunk/Source/WebInspectorUI/UserInterface/Views/RecordingStateDetailsSidebarPanel.js
r223991 r224367 142 142 let isPattern = value instanceof CanvasPattern; 143 143 if (isGradient || isPattern) { 144 value = document.createElement("span"); 145 value.classList.add("unavailable"); 146 if (isGradient) 147 value.textContent = WI.unlocalizedString("Gradient"); 148 else if (isPattern) 149 value.textContent = WI.unlocalizedString("Pattern"); 144 let textElement = document.createElement("span"); 145 textElement.classList.add("unavailable"); 146 147 let image = null; 148 if (isGradient) { 149 textElement.textContent = WI.unlocalizedString("CanvasGradient"); 150 image = WI.imageFromCanvasGradient(value, 100, 100); 151 } else if (isPattern) { 152 textElement.textContent = WI.unlocalizedString("CanvasPattern"); 153 image = value.__image; 154 } 155 156 let fragment = document.createDocumentFragment(); 157 if (image) { 158 let swatch = new WI.InlineSwatch(WI.InlineSwatch.Type.Image, image); 159 fragment.appendChild(swatch.element); 160 } 161 fragment.appendChild(textElement); 162 value = fragment; 150 163 } else { 151 164 if (value instanceof DOMMatrix)
Note: See TracChangeset
for help on using the changeset viewer.