Commit 78dc603f authored by Alice Boxhall's avatar Alice Boxhall Committed by Commit Bot

[Devtools] Split Contrast.js into three separate files

Bug: 514674
Change-Id: Ia14ef320b9e6f9cfd25ee5f5114a5f71ba185559
Reviewed-on: https://chromium-review.googlesource.com/807751
Commit-Queue: Alice Boxhall <aboxhall@chromium.org>
Reviewed-by: default avatarPavel Feldman <pfeldman@chromium.org>
Cr-Commit-Position: refs/heads/master@{#522014}
parent db2008f2
...@@ -11959,7 +11959,7 @@ ...@@ -11959,7 +11959,7 @@
}, },
{ {
"name": "streamCompression", "name": "streamCompression",
"description": "Compression format to use. This only applies when using `ReturnAsStream` transfer mode (defaults to `none`)", "description": "Compression format to use. This only applies when using `ReturnAsStream`\ntransfer mode (defaults to `none`)",
"optional": true, "optional": true,
"$ref": "StreamCompression" "$ref": "StreamCompression"
}, },
......
...@@ -108,7 +108,9 @@ all_devtools_files = [ ...@@ -108,7 +108,9 @@ all_devtools_files = [
"front_end/cm_web_modes/htmlmixed.js", "front_end/cm_web_modes/htmlmixed.js",
"front_end/cm_web_modes/javascript.js", "front_end/cm_web_modes/javascript.js",
"front_end/cm_web_modes/xml.js", "front_end/cm_web_modes/xml.js",
"front_end/color_picker/Contrast.js", "front_end/color_picker/ContrastDetails.js",
"front_end/color_picker/ContrastInfo.js",
"front_end/color_picker/ContrastOverlay.js",
"front_end/color_picker/module.json", "front_end/color_picker/module.json",
"front_end/color_picker/spectrum.css", "front_end/color_picker/spectrum.css",
"front_end/color_picker/Spectrum.js", "front_end/color_picker/Spectrum.js",
......
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
ColorPicker.ContrastInfo = class extends Common.Object {
constructor() {
super();
/** @type {?Array<number>} */
this._hsva = null;
/** @type {?Common.Color} */
this._fgColor = null;
/** @type {?Common.Color} */
this._bgColor = null;
/** @type {?number} */
this._contrastRatio = null;
/** @type {?Object<string, number>} */
this._contrastRatioThresholds = null;
/** @type {string} */
this._colorString = '';
/** @type {boolean} */
this._isNull = true;
}
/**
* @param {?SDK.CSSModel.ContrastInfo} contrastInfo
*/
update(contrastInfo) {
this._isNull = true;
this._contrastRatio = null;
this._contrastRatioThresholds = null;
this._bgColor = null;
if (contrastInfo.computedFontSize && contrastInfo.computedFontWeight && contrastInfo.computedBodyFontSize) {
this._isNull = false;
var isLargeFont = ColorPicker.ContrastInfo.computeIsLargeFont(
contrastInfo.computedFontSize, contrastInfo.computedFontWeight, contrastInfo.computedBodyFontSize);
this._contrastRatioThresholds =
ColorPicker.ContrastInfo._ContrastThresholds[(isLargeFont ? 'largeFont' : 'normalFont')];
}
if (contrastInfo.backgroundColors && contrastInfo.backgroundColors.length === 1) {
var bgColorText = contrastInfo.backgroundColors[0];
var bgColor = Common.Color.parse(bgColorText);
if (bgColor)
this._setBgColorInternal(bgColor);
}
this.dispatchEventToListeners(ColorPicker.ContrastInfo.Events.ContrastInfoUpdated);
}
/**
* @return {boolean}
*/
isNull() {
return this._isNull;
}
/**
* @param {!Array<number>} hsva
* @param {string} colorString
*/
setColor(hsva, colorString) {
this._hsva = hsva;
this._fgColor = Common.Color.fromHSVA(hsva);
this._colorString = colorString;
this._updateContrastRatio();
this.dispatchEventToListeners(ColorPicker.ContrastInfo.Events.ContrastInfoUpdated);
}
/**
* @return {?number}
*/
contrastRatio() {
return this._contrastRatio;
}
/**
* @return {string}
*/
colorString() {
return this._colorString;
}
/**
* @return {?Array<number>}
*/
hsva() {
return this._hsva;
}
/**
* @param {!Common.Color} bgColor
*/
setBgColor(bgColor) {
this._setBgColorInternal(bgColor);
this.dispatchEventToListeners(ColorPicker.ContrastInfo.Events.ContrastInfoUpdated);
}
/**
* @param {!Common.Color} bgColor
*/
_setBgColorInternal(bgColor) {
this._bgColor = bgColor;
if (!this._fgColor)
return;
var fgRGBA = this._fgColor.rgba();
// If we have a semi-transparent background color over an unknown
// background, draw the line for the "worst case" scenario: where
// the unknown background is the same color as the text.
if (bgColor.hasAlpha) {
var blendedRGBA = [];
Common.Color.blendColors(bgColor.rgba(), fgRGBA, blendedRGBA);
this._bgColor = new Common.Color(blendedRGBA, Common.Color.Format.RGBA);
}
this._contrastRatio = Common.Color.calculateContrastRatio(fgRGBA, this._bgColor.rgba());
}
/**
* @return {?Common.Color}
*/
bgColor() {
return this._bgColor;
}
_updateContrastRatio() {
if (!this._bgColor || !this._fgColor)
return;
this._contrastRatio = Common.Color.calculateContrastRatio(this._fgColor.rgba(), this._bgColor.rgba());
}
/**
* @param {string} level
* @return {?number}
*/
contrastRatioThreshold(level) {
if (!this._contrastRatioThresholds)
return null;
return this._contrastRatioThresholds[level];
}
/**
* @param {string} fontSize
* @param {string} fontWeight
* @param {?string} bodyFontSize
* @return {boolean}
*/
static computeIsLargeFont(fontSize, fontWeight, bodyFontSize) {
const boldWeights = ['bold', 'bolder', '600', '700', '800', '900'];
var fontSizePx = parseFloat(fontSize.replace('px', ''));
var isBold = (boldWeights.indexOf(fontWeight) !== -1);
if (bodyFontSize) {
var bodyFontSizePx = parseFloat(bodyFontSize.replace('px', ''));
if (isBold) {
if (fontSizePx >= (bodyFontSizePx * 1.2))
return true;
} else if (fontSizePx >= (bodyFontSizePx * 1.5)) {
return true;
}
return false;
}
var fontSizePt = Math.ceil(fontSizePx * 72 / 96);
if (isBold)
return fontSizePt >= 14;
else
return fontSizePt >= 18;
}
};
/** @enum {symbol} */
ColorPicker.ContrastInfo.Events = {
ContrastInfoUpdated: Symbol('ContrastInfoUpdated')
};
ColorPicker.ContrastInfo._ContrastThresholds = {
largeFont: {aa: 3.0, aaa: 4.5},
normalFont: {aa: 4.5, aaa: 7.0}
};
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
ColorPicker.ContrastOverlay = class {
/**
* @param {!ColorPicker.ContrastInfo} contrastInfo
* @param {!Element} colorElement
*/
constructor(contrastInfo, colorElement) {
/** @type {!ColorPicker.ContrastInfo} */
this._contrastInfo = contrastInfo;
this._visible = false;
var contrastRatioSVG = colorElement.createSVGChild('svg', 'spectrum-contrast-container fill');
this._contrastRatioLine = contrastRatioSVG.createSVGChild('path', 'spectrum-contrast-line');
this._width = 0;
this._height = 0;
this._contrastRatioLineBuilder = new ColorPicker.ContrastRatioLineBuilder(this._contrastInfo);
this._contrastRatioLineThrottler = new Common.Throttler(0);
this._drawContrastRatioLineBound = this._drawContrastRatioLine.bind(this);
this._contrastInfo.addEventListener(ColorPicker.ContrastInfo.Events.ContrastInfoUpdated, this._update.bind(this));
}
_update() {
if (!this._visible || this._contrastInfo.isNull() || !this._contrastInfo.contrastRatio())
return;
this._contrastRatioLineThrottler.schedule(this._drawContrastRatioLineBound);
}
/**
* @param {number} width
* @param {number} height
*/
setDimensions(width, height) {
this._width = width;
this._height = height;
this._update();
}
/**
* @param {boolean} visible
*/
setVisible(visible) {
this._visible = visible;
this._contrastRatioLine.classList.toggle('hidden', !visible);
this._update();
}
/**
* @return {!Promise}
*/
_drawContrastRatioLine() {
var path = this._contrastRatioLineBuilder.drawContrastRatioLine(this._width, this._height);
if (path)
this._contrastRatioLine.setAttribute('d', path);
return Promise.resolve();
}
};
ColorPicker.ContrastRatioLineBuilder = class {
/**
* @param {!ColorPicker.ContrastInfo} contrastInfo
*/
constructor(contrastInfo) {
/** @type {!ColorPicker.ContrastInfo} */
this._contrastInfo = contrastInfo;
/** @type {?string} */
this._bgColorForPreviousLine = null;
this._hueForPreviousLine = 0;
this._alphaForPreviousLine = 0;
}
/**
* @param {number} width
* @param {number} height
* @return {?string}
*/
drawContrastRatioLine(width, height) {
var requiredContrast = this._contrastInfo.contrastRatioThreshold('aa');
if (!width || !height || !requiredContrast)
return null;
const dS = 0.02;
const epsilon = 0.0002;
const H = 0;
const S = 1;
const V = 2;
const A = 3;
var hsva = this._contrastInfo.hsva();
var bgColor = this._contrastInfo.bgColor();
if (!hsva || !bgColor)
return null;
var bgColorString = bgColor.asString(Common.Color.Format.RGBA);
// Don't compute a new line if it would be identical to the previous line.
if (hsva[H] === this._hueForPreviousLine && hsva[A] === this._alphaForPreviousLine &&
bgColorString === this._bgColorForPreviousLine)
return null;
var fgRGBA = [];
Common.Color.hsva2rgba(hsva, fgRGBA);
var bgRGBA = bgColor.rgba();
var bgLuminance = Common.Color.luminance(bgRGBA);
var blendedRGBA = [];
Common.Color.blendColors(fgRGBA, bgRGBA, blendedRGBA);
var fgLuminance = Common.Color.luminance(blendedRGBA);
var fgIsLighter = fgLuminance > bgLuminance;
var desiredLuminance = Common.Color.desiredLuminance(bgLuminance, requiredContrast, fgIsLighter);
var lastV = hsva[V];
var currentSlope = 0;
var candidateHSVA = [hsva[H], 0, 0, hsva[A]];
var pathBuilder = [];
var candidateRGBA = [];
Common.Color.hsva2rgba(candidateHSVA, candidateRGBA);
Common.Color.blendColors(candidateRGBA, bgRGBA, blendedRGBA);
/**
* @param {number} index
* @param {number} x
*/
function updateCandidateAndComputeDelta(index, x) {
candidateHSVA[index] = x;
Common.Color.hsva2rgba(candidateHSVA, candidateRGBA);
Common.Color.blendColors(candidateRGBA, bgRGBA, blendedRGBA);
return Common.Color.luminance(blendedRGBA) - desiredLuminance;
}
/**
* Approach a value of the given component of `candidateHSVA` such that the
* calculated luminance of `candidateHSVA` approximates `desiredLuminance`.
* @param {number} index The component of `candidateHSVA` to modify.
* @return {?number} The new value for the modified component, or `null` if
* no suitable value exists.
*/
function approach(index) {
var x = candidateHSVA[index];
var multiplier = 1;
var dLuminance = updateCandidateAndComputeDelta(index, x);
var previousSign = Math.sign(dLuminance);
for (var guard = 100; guard; guard--) {
if (Math.abs(dLuminance) < epsilon)
return x;
var sign = Math.sign(dLuminance);
if (sign !== previousSign) {
// If `x` overshoots the correct value, halve the step size.
multiplier /= 2;
previousSign = sign;
} else if (x < 0 || x > 1) {
// If there is no overshoot and `x` is out of bounds, there is no
// acceptable value for `x`.
return null;
}
// Adjust `x` by a multiple of `dLuminance` to decrease step size as
// the computed luminance converges on `desiredLuminance`.
x += multiplier * (index === V ? -dLuminance : dLuminance);
dLuminance = updateCandidateAndComputeDelta(index, x);
}
// The loop should always converge or go out of bounds on its own.
console.error('Loop exited unexpectedly');
return null;
}
// Plot V for values of S such that the computed luminance approximates
// `desiredLuminance`, until no suitable value for V can be found, or the
// current value of S goes of out bounds.
for (var s = 0; s < 1 + dS; s += dS) {
s = Math.min(1, s);
candidateHSVA[S] = s;
// Extrapolate the approximate next value for `v` using the approximate
// gradient of the curve.
candidateHSVA[V] = lastV + currentSlope * dS;
var v = approach(V);
if (v === null)
break;
// Approximate the current gradient of the curve.
currentSlope = s === 0 ? 0 : (v - lastV) / dS;
lastV = v;
pathBuilder.push(pathBuilder.length ? 'L' : 'M');
pathBuilder.push((s * width).toFixed(2));
pathBuilder.push(((1 - v) * height).toFixed(2));
}
// If no suitable V value for an in-bounds S value was found, find the value
// of S such that V === 1 and add that to the path.
if (s < 1 + dS) {
s -= dS;
candidateHSVA[V] = 1;
s = approach(S);
if (s !== null)
pathBuilder = pathBuilder.concat(['L', (s * width).toFixed(2), '-0.1']);
}
this._bgColorForPreviousLine = bgColorString;
this._hueForPreviousLine = hsva[H];
this._alphaForPreviousLine = hsva[A];
return pathBuilder.join(' ');
}
};
...@@ -4,7 +4,9 @@ ...@@ -4,7 +4,9 @@
"sdk" "sdk"
], ],
"scripts": [ "scripts": [
"Contrast.js", "ContrastInfo.js",
"ContrastOverlay.js",
"ContrastDetails.js",
"Spectrum.js" "Spectrum.js"
], ],
"resources": [ "resources": [
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment