Bug 1478156 - Move shared code to be used by color contrast feature, r=yzen,gl

Differential Revision: https://phabricator.services.mozilla.com/D32490

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Maliha Islam 2019-07-15 11:01:03 +00:00
parent 43f3f62186
commit a94e63b533
7 changed files with 197 additions and 144 deletions

View File

@ -20,12 +20,6 @@
--accessibility-link-color: var(--blue-60);
--accessibility-link-color-active: var(--blue-70);
--accessibility-body-background-a90: rgba(255, 255, 255, 0.9);
--badge-active-background-color: var(--blue-50);
--badge-active-border-color: #FFFFFFB3;
--badge-interactive-background-color: var(--grey-20);
--accessible-label-background-color: white;
--accessible-label-border-color: #CACAD1;
--accessible-label-color: var(--grey-60);
/* Similarly to webconsole, add more padding before the toolbar group. */
--separator-inline-margin: 5px;
--accessibility-code-background: var(--grey-20);
@ -37,12 +31,6 @@
--accessibility-link-color: var(--theme-highlight-blue);
--accessibility-link-color-active: var(--blue-40);
--accessibility-body-background-a90: rgba(42, 42, 46, 0.9);
--badge-active-background-color: var(--blue-60);
--badge-active-border-color: #FFF6;
--badge-interactive-background-color: var(--grey-70);
--accessible-label-background-color: var(--grey-80);
--accessible-label-border-color: var(--grey-50);
--accessible-label-color: var(--grey-40);
--accessibility-code-background: var(--grey-70);
}
@ -382,9 +370,9 @@ body {
border-radius: 3px;
padding: 0px 3px;
margin-inline-start: 5px;
color: var(--accessible-label-color);
background-color: var(--accessible-label-background-color);
border: 1px solid var(--accessible-label-border-color);
color: var(--badge-color);
background-color: var(--badge-background-color);
border: 1px solid var(--badge-border-color);
}
.badge.audit-badge::before {
@ -427,7 +415,7 @@ body {
}
.treeTable:not(:focus):not(:focus-within) .treeRow.selected .badges .badge {
color: var(--accessible-label-color);
color: var(--badge-color);
}
.badge.toggle-button.checked {
@ -580,9 +568,9 @@ body {
}
.accessible .tree .objectBox-accessible .accessible-role {
background-color: var(--accessible-label-background-color);
color: var(--accessible-label-color);
border: 1px solid var(--accessible-label-border-color);
background-color: var(--badge-background-color);
color: var(--badge-color);
border: 1px solid var(--badge-border-color);
border-radius: 3px;
padding: 0px 2px;
margin-inline-start: 5px;
@ -700,10 +688,6 @@ body {
line-height: 20px;
}
.accessibility-color-contrast {
align-items: baseline;
}
.accessibility-check-header {
margin: 0;
font-weight: bold;
@ -715,7 +699,7 @@ body {
display: inline;
margin: 0;
white-space: normal;
color: var(--accessible-label-color);
color: var(--badge-color);
}
.accessibility-check-annotation .link {
@ -740,16 +724,6 @@ body {
text-decoration: underline;
}
.accessibility-color-contrast-large-text {
background-color: var(--accessible-label-background-color);
color: var(--accessible-label-color);
outline: 1px solid var(--accessible-label-border-color);
-moz-outline-radius: 3px;
padding: 0px 2px;
margin-inline-start: 6px;
line-height: initial;
}
.accessibility-color-contrast .accessibility-contrast-value:not(:empty) {
margin-block-end: 4px;
}
@ -772,28 +746,6 @@ body {
margin-inline-start: 4px;
}
.accessibility-color-contrast .accessibility-contrast-value:not(:empty):after {
margin-inline-start: 4px;
}
.accessibility-color-contrast .accessibility-contrast-value:not(:empty).AA:after,
.accessibility-color-contrast .accessibility-contrast-value:not(:empty).AAA:after {
color: var(--theme-highlight-green);
}
.accessibility-color-contrast .accessibility-contrast-value:not(:empty).fail:after {
color: #E57180;
content: "⚠️";
}
.accessibility-color-contrast .accessibility-contrast-value:not(:empty).AA:after {
content: "AA\2713";
}
.accessibility-color-contrast .accessibility-contrast-value:not(:empty).AAA:after {
content: "AAA\2713";
}
.accessibility-color-contrast .accessibility-color-contrast-label:after {
content: ":";
}

View File

@ -7,6 +7,8 @@
<head>
<meta charset="utf-8"/>
<link href="chrome://devtools/skin/badge.css" rel="stylesheet" />
<link href="chrome://devtools/skin/accessibility-color-contrast.css" rel="stylesheet" />
<link href="resource://devtools/client/accessibility/accessibility.css" rel="stylesheet"/>
<link href="resource://devtools/client/shared/components/splitter/SplitBox.css" rel="stylesheet" />
<link href="resource://devtools/client/shared/components/Accordion.css" rel="stylesheet" />

View File

@ -165,6 +165,7 @@ devtools.jar:
skin/images/dock-side-right.svg (themes/images/dock-side-right.svg)
skin/images/dock-undock.svg (themes/images/dock-undock.svg)
skin/floating-scrollbars-responsive-design.css (themes/floating-scrollbars-responsive-design.css)
skin/accessibility-color-contrast.css (themes/accessibility-color-contrast.css)
skin/badge.css (themes/badge.css)
skin/inspector.css (themes/inspector.css)
skin/images/profiler-stopwatch.svg (themes/images/profiler-stopwatch.svg)

View File

@ -0,0 +1,52 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* Classes used to style the color contrast section in the Accessibility
* Checks panel and color picker tooltip across the Inspector panel.
*
* The section consists of:
* - contrast ratio value (numeric + score badge (AA/AAA/fail)):
* Only shows up if contrast ratio can be calculated.
* - large text indicator badge:
* Only shows up if the selected text node contains large text.
*/
.accessibility-color-contrast {
position: relative;
display: flex;
cursor: default;
height: inherit;
align-items: baseline;
}
.accessibility-color-contrast .accessibility-contrast-value:not(:empty):after {
margin-inline-start: 4px;
}
.accessibility-color-contrast .accessibility-contrast-value:not(:empty).AA:after,
.accessibility-color-contrast .accessibility-contrast-value:not(:empty).AAA:after {
color: var(--theme-highlight-green);
}
.accessibility-color-contrast .accessibility-contrast-value:not(:empty).fail:after {
color: #E57180;
content: "⚠️";
}
.accessibility-color-contrast .accessibility-contrast-value:not(:empty).AA:after {
content: "AA\2713";
}
.accessibility-color-contrast .accessibility-contrast-value:not(:empty).AAA:after {
content: "AAA\2713";
}
.accessibility-color-contrast-large-text {
background-color: var(--badge-background-color);
color: var(--badge-color);
outline: 1px solid var(--badge-border-color);
-moz-outline-radius: 3px;
padding: 0px 2px;
margin-inline-start: 6px;
line-height: initial;
}

View File

@ -37,14 +37,20 @@ loader.lazyRequireGetter(
);
loader.lazyRequireGetter(
this,
"DevToolsWorker",
"devtools/shared/worker/worker",
"getContrastRatioScore",
"devtools/shared/accessibility",
true
);
loader.lazyRequireGetter(
this,
"accessibility",
"devtools/shared/constants",
"getTextProperties",
"devtools/shared/accessibility",
true
);
loader.lazyRequireGetter(
this,
"DevToolsWorker",
"devtools/shared/worker/worker",
true
);
loader.lazyRequireGetter(
@ -55,67 +61,12 @@ loader.lazyRequireGetter(
const WORKER_URL = "resource://devtools/server/actors/accessibility/worker.js";
const HIGHLIGHTED_PSEUDO_CLASS = ":-moz-devtools-highlighted";
// CSS pixel value (constant) that corresponds to 14 point text size which defines large
// text when font text is bold (font weight is greater than or equal to 600).
const BOLD_LARGE_TEXT_MIN_PIXELS = 18.66;
// CSS pixel value (constant) that corresponds to 18 point text size which defines large
// text for normal text (e.g. not bold).
const LARGE_TEXT_MIN_PIXELS = 24;
const {
LARGE_TEXT: { BOLD_LARGE_TEXT_MIN_PIXELS, LARGE_TEXT_MIN_PIXELS },
} = require("devtools/shared/accessibility");
loader.lazyGetter(this, "worker", () => new DevToolsWorker(WORKER_URL));
/**
* Get text style properties for a given node, if possible.
* @param {DOMNode} node
* DOM node for which text styling information is to be calculated.
* @return {Object}
* Color and text size information for a given DOM node.
*/
function getTextProperties(node) {
const computedStyles = CssLogic.getComputedStyle(node);
if (!computedStyles) {
return null;
}
const {
color,
"font-size": fontSize,
"font-weight": fontWeight,
} = computedStyles;
const opacity = parseFloat(computedStyles.opacity);
let { r, g, b, a } = colorUtils.colorToRGBA(color, true);
// If the element has opacity in addition to background alpha value, take it
// into account. TODO: this does not handle opacity set on ancestor elements
// (see bug https://bugzilla.mozilla.org/show_bug.cgi?id=1544721).
a = opacity * a;
const textRgbaColor = new colorUtils.CssColor(
`rgba(${r}, ${g}, ${b}, ${a})`,
true
);
// TODO: For cases where text color is transparent, it likely comes from the color of
// the background that is underneath it (commonly from background-clip: text
// property). With some additional investigation it might be possible to calculate the
// color contrast where the color of the background is used as text color and the
// color of the ancestor's background is used as its background.
if (textRgbaColor.isTransparent()) {
return null;
}
const isBoldText = parseInt(fontWeight, 10) >= 600;
const size = parseFloat(fontSize);
const isLargeText =
size >= (isBoldText ? BOLD_LARGE_TEXT_MIN_PIXELS : LARGE_TEXT_MIN_PIXELS);
return {
color: [r, g, b, a],
isLargeText,
isBoldText,
size,
opacity,
};
}
/**
* Get canvas rendering context for the current target window bound by the bounds of the
* accessible objects.
@ -167,31 +118,6 @@ function getImageCtx(win, bounds, zoom, scale, node) {
return ctx;
}
/**
* Get contrast ratio score based on WCAG criteria.
* @param {Number} ratio
* Value of the contrast ratio for a given accessible object.
* @param {Boolean} isLargeText
* True if the accessible object contains large text.
* @return {String}
* Value that represents calculated contrast ratio score.
*/
function getContrastRatioScore(ratio, isLargeText) {
const {
SCORES: { FAIL, AA, AAA },
} = accessibility;
const levels = isLargeText ? { AA: 3, AAA: 4.5 } : { AA: 4.5, AAA: 7 };
let score = FAIL;
if (ratio >= levels.AAA) {
score = AAA;
} else if (ratio >= levels.AA) {
score = AA;
}
return score;
}
/**
* Calculates the contrast ratio of the referenced DOM node.
*
@ -208,7 +134,9 @@ function getContrastRatioScore(ratio, isLargeText) {
* isLargeText, value, min, max values for contrast.
*/
async function getContrastRatioFor(node, options = {}) {
const props = getTextProperties(node);
const computedStyle = CssLogic.getComputedStyle(node);
const props = computedStyle ? getTextProperties(computedStyle) : null;
if (!props) {
return {
error: true,

View File

@ -0,0 +1,117 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
loader.lazyRequireGetter(this, "colorUtils", "devtools/shared/css/color", true);
const {
accessibility: {
SCORES: { FAIL, AA, AAA },
},
} = require("devtools/shared/constants");
/**
* Mapping of text size to contrast ratio score levels
*/
const LEVELS = {
LARGE_TEXT: { AA: 3, AAA: 4.5 },
REGULAR_TEXT: { AA: 4.5, AAA: 7 },
};
/**
* Mapping of large text size to CSS pixel value
*/
const LARGE_TEXT = {
// CSS pixel value (constant) that corresponds to 14 point text size which defines large
// text when font text is bold (font weight is greater than or equal to 600).
BOLD_LARGE_TEXT_MIN_PIXELS: 18.66,
// CSS pixel value (constant) that corresponds to 18 point text size which defines large
// text for normal text (e.g. not bold).
LARGE_TEXT_MIN_PIXELS: 24,
};
/**
* Get contrast ratio score based on WCAG criteria.
* @param {Number} ratio
* Value of the contrast ratio for a given accessible object.
* @param {Boolean} isLargeText
* True if the accessible object contains large text.
* @return {String}
* Value that represents calculated contrast ratio score.
*/
function getContrastRatioScore(ratio, isLargeText) {
const levels = isLargeText ? LEVELS.LARGE_TEXT : LEVELS.REGULAR_TEXT;
let score = FAIL;
if (ratio >= levels.AAA) {
score = AAA;
} else if (ratio >= levels.AA) {
score = AA;
}
return score;
}
/**
* Get calculated text style properties from a node's computed style, if possible.
* @param {Object} computedStyle
* Computed style using which text styling information is to be calculated.
* - fontSize {String}
* Font size of the text
* - fontWeight {String}
* Font weight of the text
* - color {String}
* Rgb color of the text
* - opacity {String} Optional
* Opacity of the text
* @return {Object}
* Color and text size information for a given DOM node.
*/
function getTextProperties(computedStyle) {
const { color, fontSize, fontWeight } = computedStyle;
let { r, g, b, a } = colorUtils.colorToRGBA(color, true);
// If the element has opacity in addition to background alpha value, take it
// into account. TODO: this does not handle opacity set on ancestor elements
// (see bug https://bugzilla.mozilla.org/show_bug.cgi?id=1544721).
const opacity = computedStyle.opacity
? parseFloat(computedStyle.opacity)
: null;
if (opacity) {
a = opacity * a;
}
const textRgbaColor = new colorUtils.CssColor(
`rgba(${r}, ${g}, ${b}, ${a})`,
true
);
// TODO: For cases where text color is transparent, it likely comes from the color of
// the background that is underneath it (commonly from background-clip: text
// property). With some additional investigation it might be possible to calculate the
// color contrast where the color of the background is used as text color and the
// color of the ancestor's background is used as its background.
if (textRgbaColor.isTransparent()) {
return null;
}
const isBoldText = parseInt(fontWeight, 10) >= 600;
const size = parseFloat(fontSize);
const isLargeText =
size >=
(isBoldText
? LARGE_TEXT.BOLD_LARGE_TEXT_MIN_PIXELS
: LARGE_TEXT.LARGE_TEXT_MIN_PIXELS);
return {
color: [r, g, b, a],
isLargeText,
isBoldText,
size,
opacity,
};
}
exports.getContrastRatioScore = getContrastRatioScore;
exports.getTextProperties = getTextProperties;
exports.LARGE_TEXT = LARGE_TEXT;

View File

@ -43,6 +43,7 @@ XPCSHELL_TESTS_MANIFESTS += ['tests/unit/xpcshell.ini']
JAR_MANIFESTS += ['jar.mn']
DevToolsModules(
'accessibility.js',
'async-storage.js',
'async-utils.js',
'base-loader.js',