зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
00f87f386d
Коммит
0e48d4c3b4
|
@ -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: ":";
|
||||
}
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
|
@ -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',
|
||||
|
|
Загрузка…
Ссылка в новой задаче