Changeset 222102 in webkit
- Timestamp:
- Sep 15, 2017 12:50:40 PM (7 years ago)
- Location:
- trunk
- Files:
-
- 12 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r222101 r222102 1 2017-09-15 Matt Baker <mattbaker@apple.com> 2 3 Web Inspector: Canvas: recording parameters that include colors should show an InlineSwatch (2D canvas) 4 https://bugs.webkit.org/show_bug.cgi?id=176822 5 <rdar://problem/34402170> 6 7 Reviewed by Devin Rousso. 8 9 Add tests for color space conversions. 10 11 * inspector/model/color-expected.txt: 12 * inspector/model/color.html: 13 1 14 2017-09-15 Brent Fulgham <bfulgham@apple.com> 2 15 -
trunk/LayoutTests/inspector/model/color-expected.txt
r222055 r222102 154 154 PASS: Color as 'HSLA' should be 'hsla(201, 100%, 70%, 0.5)' 155 155 156 -- Running test case: WI.Color.rgb2hsv 157 PASS: Should convert [0,0,0] to [0,0,0]. 158 PASS: Should convert [255,255,255] to [0,0,1]. 159 PASS: Should convert [255,0,0] to [0,1,1]. 160 PASS: Should convert [0,255,0] to [120,1,1]. 161 PASS: Should convert [0,0,255] to [240,1,1]. 162 PASS: Should convert [-1,-1,-1] to [0,0,0]. 163 PASS: Should convert [256,256,256] to [0,0,1]. 164 PASS: Should convert [254.9,0,0] to [0,1,1]. 165 166 -- Running test case: WI.Color.cmyk2rgb 167 PASS: Should convert [0,0,0,1] to [0,0,0]. 168 PASS: Should convert [1,0,0,0] to [0,255,255]. 169 PASS: Should convert [0,1,0,0] to [255,0,255]. 170 PASS: Should convert [0,0,1,0] to [255,255,0]. 171 PASS: Should convert [0,0,0,0] to [255,255,255]. 172 PASS: Should convert [2,0,0,0] to [0,255,255]. 173 PASS: Should convert [-1,0,0,0] to [255,255,255]. 174 175 -- Running test case: WI.Color.normalized2rgb 176 PASS: Should convert [0,0,0] to [0,0,0]. 177 PASS: Should convert [1,1,1] to [255,255,255]. 178 PASS: Should convert [0.24,0.25,0.26] to [61,64,66]. 179 PASS: Should convert [2,0,0] to [255,0,0]. 180 PASS: Should convert [-1,0,0] to [0,0,0]. 181 -
trunk/LayoutTests/inspector/model/color.html
r222055 r222102 299 299 }); 300 300 301 function testColorConversion(func, value, expected) { 302 let actual = func(...value); 303 InspectorTest.expectShallowEqual(actual, expected, `Should convert ${JSON.stringify(value)} to ${JSON.stringify(expected)}.`); 304 } 305 306 suite.addTestCase({ 307 name: "WI.Color.rgb2hsv", 308 description: "Test conversion from RGB to HSV.", 309 test(resolve, reject) { 310 testColorConversion(WI.Color.rgb2hsv, [0, 0, 0], [0, 0, 0]); 311 testColorConversion(WI.Color.rgb2hsv, [255, 255, 255], [0, 0, 1]); 312 testColorConversion(WI.Color.rgb2hsv, [255, 0, 0], [0, 1, 1]); 313 testColorConversion(WI.Color.rgb2hsv, [0, 255, 0], [120, 1, 1]); 314 testColorConversion(WI.Color.rgb2hsv, [0, 0, 255], [240, 1, 1]); 315 316 // Out-of-bounds and floating point inputs. 317 testColorConversion(WI.Color.rgb2hsv, [-1, -1, -1], [0, 0, 0]); 318 testColorConversion(WI.Color.rgb2hsv, [256, 256, 256], [0, 0, 1]); 319 testColorConversion(WI.Color.rgb2hsv, [254.9, 0, 0], [0, 1, 1]); 320 321 resolve(); 322 } 323 }); 324 325 suite.addTestCase({ 326 name: "WI.Color.cmyk2rgb", 327 description: "Test conversion from CMYK to RGB.", 328 test(resolve, reject) { 329 testColorConversion(WI.Color.cmyk2rgb, [0, 0, 0, 1], [0, 0, 0]); 330 testColorConversion(WI.Color.cmyk2rgb, [1, 0, 0, 0], [0, 255, 255]); 331 testColorConversion(WI.Color.cmyk2rgb, [0, 1, 0, 0], [255, 0, 255]); 332 testColorConversion(WI.Color.cmyk2rgb, [0, 0, 1, 0], [255, 255, 0]); 333 testColorConversion(WI.Color.cmyk2rgb, [0, 0, 0, 0], [255, 255, 255]); 334 335 // Out-of-bounds inputs. 336 testColorConversion(WI.Color.cmyk2rgb, [2, 0, 0, 0], [0, 255, 255]); 337 testColorConversion(WI.Color.cmyk2rgb, [-1, 0, 0, 0], [255, 255, 255]); 338 339 resolve(); 340 } 341 }); 342 343 suite.addTestCase({ 344 name: "WI.Color.normalized2rgb", 345 description: "Test conversion from normalized RGB to RGB.", 346 test(resolve, reject) { 347 testColorConversion(WI.Color.normalized2rgb, [0, 0, 0], [0, 0, 0]); 348 testColorConversion(WI.Color.normalized2rgb, [1, 1, 1], [255, 255, 255]); 349 testColorConversion(WI.Color.normalized2rgb, [0.24, 0.25, 0.26], [61, 64, 66]); // Values chosen to test round up/down behavior. 350 351 // Out-of-bounds inputs. 352 testColorConversion(WI.Color.normalized2rgb, [2, 0, 0], [255, 0, 0]); 353 testColorConversion(WI.Color.normalized2rgb, [-1, 0, 0], [0, 0, 0]); 354 355 resolve(); 356 } 357 }); 358 301 359 suite.runTestCasesAndFinish(); 302 360 } -
trunk/Source/WebInspectorUI/ChangeLog
r222064 r222102 1 2017-09-15 Matt Baker <mattbaker@apple.com> 2 3 Web Inspector: Canvas: recording parameters that include colors should show an InlineSwatch (2D canvas) 4 https://bugs.webkit.org/show_bug.cgi?id=176822 5 <rdar://problem/34402170> 6 7 Reviewed by Devin Rousso. 8 9 Show inline swatches in the canvas recording action and state sidebars. 10 11 * UserInterface/Models/Color.js: 12 Added helpers for dealing with CMYK and normalized RGB. The latter is 13 for RGB components scaled to the range [0, 1]. Also improved handling 14 for 8-bit channel values. 15 (WI.Color.rgb2hsv): 16 (WI.Color.cmyk2rgb): 17 (WI.Color.normalized2rgb): 18 (WI.Color._eightBitChannel): 19 (WI.Color.prototype._toRGBString): 20 (WI.Color.prototype._toRGBAString): 21 (WI.Color.prototype._componentToHexValue): 22 (WI.Color.prototype._rgbToHSL): 23 (WI.Color.prototype._componentToNumber): Deleted. 24 Replaced by _eightBitChannel. 25 26 * UserInterface/Models/RecordingAction.js: 27 (WI.RecordingAction): 28 (WI.RecordingAction.prototype.getColorParameters): 29 Get a subset of parameters that describe a color. This can be an array 30 containing one value (e.g. fillStyle), or multiple values, as is the 31 case with non-standard API functions that describe color using multiple 32 parameters (e.g. setFillColor). 33 34 * UserInterface/Views/InlineSwatch.css: 35 (.inline-swatch:not(.read-only):hover > span): 36 (.inline-swatch:hover > span): Deleted. 37 * UserInterface/Views/InlineSwatch.js: 38 (WI.InlineSwatch): 39 Read-only colors shouldn't show a context menu or hover effects. 40 41 * UserInterface/Views/RecordingActionTreeElement.css: 42 (.tree-outline:matches(:focus, .force-focus) .item.action > .titles .parameters > .inline-swatch): 43 44 * UserInterface/Views/RecordingActionTreeElement.js: 45 (WI.RecordingActionTreeElement._generateDOM.createParameterElement): 46 (WI.RecordingActionTreeElement._generateDOM): 47 (WI.RecordingActionTreeElement._createSwatchForColorParameters): 48 49 * UserInterface/Views/RecordingStateDetailsSidebarPanel.css: 50 (.sidebar > .panel.details.recording-state > .content > .data-grid .inline-swatch): 51 52 * UserInterface/Views/RecordingStateDetailsSidebarPanel.js: 53 (WI.RecordingStateDetailsSidebarPanel.prototype._generateDetailsCanvas2D.isColorProperty): 54 (WI.RecordingStateDetailsSidebarPanel.prototype._generateDetailsCanvas2D.createInlineSwatch): 55 (WI.RecordingStateDetailsSidebarPanel.prototype._generateDetailsCanvas2D): 56 (WI.RecordingStateDetailsSidebarPanel): 57 1 58 2017-09-14 Joseph Pecoraro <pecoraro@apple.com> 2 59 -
trunk/Source/WebInspectorUI/UserInterface/Models/Color.js
r222055 r222102 158 158 static rgb2hsv(r, g, b) 159 159 { 160 r /=255;161 g /=255;162 b /=255;160 r = WI.Color._eightBitChannel(r) / 255; 161 g = WI.Color._eightBitChannel(g) / 255; 162 b = WI.Color._eightBitChannel(b) / 255; 163 163 164 164 let min = Math.min(Math.min(r, g), b); … … 229 229 } 230 230 231 static cmyk2rgb(c, m, y, k) 232 { 233 c = Number.constrain(c, 0, 1); 234 m = Number.constrain(m, 0, 1); 235 y = Number.constrain(y, 0, 1); 236 k = Number.constrain(k, 0, 1); 237 238 let r = 255 - ((Math.min(1, c * (1 - k) + k)) * 255); 239 let g = 255 - ((Math.min(1, m * (1 - k) + k)) * 255); 240 let b = 255 - ((Math.min(1, y * (1 - k) + k)) * 255); 241 return [r, g, b]; 242 } 243 244 static normalized2rgb(r, g, b) 245 { 246 return [ 247 WI.Color._eightBitChannel(r * 255), 248 WI.Color._eightBitChannel(g * 255), 249 WI.Color._eightBitChannel(b * 255) 250 ]; 251 } 252 253 static _eightBitChannel(value) 254 { 255 return Number.constrain(Math.round(value), 0, 255); 256 } 231 257 232 258 // Public … … 485 511 return this._toRGBAString(); 486 512 487 let rgba = this.rgba.slice(0, -1); 488 rgba = rgba.map((value) => value.maxDecimals(2)); 489 return "rgb(" + rgba.join(", ") + ")"; 513 let r = WI.Color._eightBitChannel(this.rgb[0]); 514 let g = WI.Color._eightBitChannel(this.rgb[1]); 515 let b = WI.Color._eightBitChannel(this.rgb[2]); 516 return `rgb(${r}, ${g}, ${b})`; 490 517 } 491 518 492 519 _toRGBAString() 493 520 { 494 let rgba = this.rgba; 495 rgba = rgba.map((value) => value.maxDecimals(2)); 496 return "rgba(" + rgba.join(", ") + ")"; 521 let r = WI.Color._eightBitChannel(this.rgb[0]); 522 let g = WI.Color._eightBitChannel(this.rgb[1]); 523 let b = WI.Color._eightBitChannel(this.rgb[2]); 524 return `rgba(${r}, ${g}, ${b}, ${this.alpha})`; 497 525 } 498 526 … … 514 542 } 515 543 516 _componentToNumber(value)517 {518 return Number.constrain(value, 0, 255);519 }520 521 544 _componentToHexValue(value) 522 545 { 523 let hex = this._componentToNumber(value).toString(16);546 let hex = WI.Color._eightBitChannel(value).toString(16); 524 547 if (hex.length === 1) 525 548 hex = "0" + hex; … … 529 552 _rgbToHSL(rgb) 530 553 { 531 let r = this._componentToNumber(rgb[0]) / 255;532 let g = this._componentToNumber(rgb[1]) / 255;533 let b = this._componentToNumber(rgb[2]) / 255;554 let r = WI.Color._eightBitChannel(rgb[0]) / 255; 555 let g = WI.Color._eightBitChannel(rgb[1]) / 255; 556 let b = WI.Color._eightBitChannel(rgb[2]) / 255; 534 557 let max = Math.max(r, g, b); 535 558 let min = Math.min(r, g, b); -
trunk/Source/WebInspectorUI/UserInterface/Models/RecordingAction.js
r222057 r222102 167 167 this._stateModifiers.add(item); 168 168 } 169 } 170 171 getColorParameters() 172 { 173 switch (this._name) { 174 // 2D 175 case "fillStyle": 176 case "strokeStyle": 177 case "shadowColor": 178 // 2D (non-standard, legacy) 179 case "setFillColor": 180 case "setStrokeColor": 181 // WebGL 182 case "blendColor": 183 case "clearColor": 184 return this._parameters; 185 186 // 2D (non-standard, legacy) 187 case "setShadow": 188 return this._parameters.slice(3); 189 } 190 191 return []; 169 192 } 170 193 }; -
trunk/Source/WebInspectorUI/UserInterface/Views/InlineSwatch.css
r221748 r222102 85 85 } 86 86 87 .inline-swatch: hover > span {87 .inline-swatch:not(.read-only):hover > span { 88 88 border-color: hsla(0, 0%, 25%, 0.8); 89 89 } -
trunk/Source/WebInspectorUI/UserInterface/Views/InlineSwatch.js
r221748 r222102 36 36 this._swatchElement.classList.add("inline-swatch", this._type.split("-").lastValue); 37 37 38 switch (this._type) {39 case WI.InlineSwatch.Type.Color:40 this._swatchElement.title = WI.UIString("Click to select a color. Shift-click to switch color formats.");41 break;42 case WI.InlineSwatch.Type.Gradient:43 this._swatchElement.title = WI.UIString("Edit custom gradient");44 break;45 case WI.InlineSwatch.Type.Bezier:46 this._swatchElement.title = WI.UIString("Edit “cubic-bezier“ function");47 break;48 case WI.InlineSwatch.Type.Spring:49 this._swatchElement.title = WI.UIString("Edit “spring“ function");50 break;51 case WI.InlineSwatch.Type.Variable:52 this._swatchElement.title = WI.UIString("View variable value");53 break;54 default:55 WI.reportInternalError(`Unknown InlineSwatch type "${type}"`);56 break;57 }58 59 38 this._boundSwatchElementClicked = null; 60 if (!readOnly) { 39 40 if (readOnly) 41 this._swatchElement.classList.add("read-only"); 42 else { 43 switch (this._type) { 44 case WI.InlineSwatch.Type.Color: 45 this._swatchElement.title = WI.UIString("Click to select a color. Shift-click to switch color formats."); 46 break; 47 case WI.InlineSwatch.Type.Gradient: 48 this._swatchElement.title = WI.UIString("Edit custom gradient"); 49 break; 50 case WI.InlineSwatch.Type.Bezier: 51 this._swatchElement.title = WI.UIString("Edit “cubic-bezier“ function"); 52 break; 53 case WI.InlineSwatch.Type.Spring: 54 this._swatchElement.title = WI.UIString("Edit “spring“ function"); 55 break; 56 case WI.InlineSwatch.Type.Variable: 57 this._swatchElement.title = WI.UIString("View variable value"); 58 break; 59 default: 60 WI.reportInternalError(`Unknown InlineSwatch type "${type}"`); 61 break; 62 } 63 61 64 this._boundSwatchElementClicked = this._swatchElementClicked.bind(this); 62 65 this._swatchElement.addEventListener("click", this._boundSwatchElementClicked); -
trunk/Source/WebInspectorUI/UserInterface/Views/RecordingActionTreeElement.css
r221844 r222102 62 62 } 63 63 64 body:not(.window-inactive, .window-docked-inactive) .item.action > .titles .parameter.swizzled { 65 color: var(--text-color-gray-medium); 66 } 67 64 68 body:not(.window-inactive, .window-docked-inactive) :matches(:focus, .force-focus) .item.action.selected > .titles .parameter.swizzled, 65 69 body:not(.window-inactive, .window-docked-inactive) :matches(:focus, .force-focus) .item.action.selected::before { 66 color: var(--selected-secondary-text-color); 70 color: var(--console-secondary-text-color); 71 } 72 73 .tree-outline:matches(:focus, .force-focus) .item.action > .titles .parameters > .inline-swatch { 74 vertical-align: -1px; 67 75 } 68 76 -
trunk/Source/WebInspectorUI/UserInterface/Views/RecordingActionTreeElement.js
r221844 r222102 126 126 copyText += ")"; 127 127 128 let colorParameters = recordingAction.getColorParameters(); 129 if (colorParameters.length) { 130 let swatch = WI.RecordingActionTreeElement._createSwatchForColorParameters(colorParameters); 131 let insertionIndex = recordingAction.parameters.indexOf(colorParameters[0]); 132 let parameterElement = parametersContainer.children[insertionIndex]; 133 parametersContainer.insertBefore(swatch.element, parameterElement); 134 135 if (recordingAction.swizzleTypes[insertionIndex] === WI.Recording.Swizzle.String) { 136 parameterElement.textContent = swatch.value.toString(); 137 parameterElement.classList.add("color"); 138 } 139 } 140 128 141 return {titleFragment, copyText}; 142 } 143 144 static _createSwatchForColorParameters(parameters) 145 { 146 let rgb = []; 147 let color = null; 148 149 switch (parameters.length) { 150 case 1: 151 case 2: 152 if (typeof parameters[0] === "string") 153 color = WI.Color.fromString(parameters[0]); 154 else 155 rgb = WI.Color.normalized2rgb(parameters[0], parameters[0], parameters[0]); 156 break; 157 158 case 4: 159 rgb = WI.Color.normalized2rgb(parameters[0], parameters[1], parameters[2]); 160 break; 161 162 case 5: 163 rgb = WI.Color.cmyk2rgb(...parameters); 164 break; 165 166 default: 167 console.error("Unexpected number of color parameters."); 168 return null; 169 } 170 171 if (!color) { 172 let alpha = parameters.length === 1 ? 1 : parameters.lastValue; 173 color = new WI.Color(WI.Color.Format.RGBA, [...rgb, alpha]); 174 if (!color) 175 return null; 176 } 177 178 const readOnly = true; 179 return new WI.InlineSwatch(WI.InlineSwatch.Type.Color, color, readOnly); 129 180 } 130 181 -
trunk/Source/WebInspectorUI/UserInterface/Views/RecordingStateDetailsSidebarPanel.css
r220114 r222102 39 39 color: grey; 40 40 } 41 42 .sidebar > .panel.details.recording-state > .content > .data-grid .inline-swatch { 43 vertical-align: -1px; 44 } -
trunk/Source/WebInspectorUI/UserInterface/Views/RecordingStateDetailsSidebarPanel.js
r222057 r222102 136 136 state.webkitLineDashOffset = context.webkitLineDashOffset; 137 137 138 function isColorProperty(name) { 139 return name === "fillStyle" || name === "strokeStyle" || name === "shadowColor"; 140 } 141 142 function createInlineSwatch(value) { 143 let color = WI.Color.fromString(value); 144 if (!color) 145 return null; 146 147 const readOnly = true; 148 return new WI.InlineSwatch(WI.InlineSwatch.Type.Color, color, readOnly); 149 } 150 138 151 let action = actions[this._index]; 139 152 for (let name in state) { … … 155 168 value = JSON.stringify(value); 156 169 } 170 } else if (isColorProperty(name)) { 171 let swatch = createInlineSwatch(value); 172 let label = swatch.value.toString(); 173 value = document.createElement("span"); 174 value.append(swatch.element, label); 157 175 } 158 176
Note: See TracChangeset
for help on using the changeset viewer.