1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 loader.lazyRequireGetter(
10 "resource://devtools/shared/css/color.js",
15 SCORES: { FAIL, AA, AAA },
17 } = require("resource://devtools/shared/constants.js");
20 * Mapping of text size to contrast ratio score levels
23 LARGE_TEXT: { AA: 3, AAA: 4.5 },
24 REGULAR_TEXT: { AA: 4.5, AAA: 7 },
28 * Mapping of large text size to CSS pixel value
31 // CSS pixel value (constant) that corresponds to 14 point text size which defines large
32 // text when font text is bold (font weight is greater than or equal to 600).
33 BOLD_LARGE_TEXT_MIN_PIXELS: 18.66,
34 // CSS pixel value (constant) that corresponds to 18 point text size which defines large
35 // text for normal text (e.g. not bold).
36 LARGE_TEXT_MIN_PIXELS: 24,
40 * Get contrast ratio score based on WCAG criteria.
41 * @param {Number} ratio
42 * Value of the contrast ratio for a given accessible object.
43 * @param {Boolean} isLargeText
44 * True if the accessible object contains large text.
46 * Value that represents calculated contrast ratio score.
48 function getContrastRatioScore(ratio, isLargeText) {
49 const levels = isLargeText ? LEVELS.LARGE_TEXT : LEVELS.REGULAR_TEXT;
52 if (ratio >= levels.AAA) {
54 } else if (ratio >= levels.AA) {
62 * Get calculated text style properties from a node's computed style, if possible.
63 * @param {Object} computedStyle
64 * Computed style using which text styling information is to be calculated.
66 * Font size of the text
67 * - fontWeight {String}
68 * Font weight of the text
70 * Rgb color of the text
71 * - opacity {String} Optional
74 * Color and text size information for a given DOM node.
76 function getTextProperties(computedStyle) {
77 const { color, fontSize, fontWeight } = computedStyle;
78 let { r, g, b, a } = InspectorUtils.colorToRGBA(color);
80 // If the element has opacity in addition to background alpha value, take it
81 // into account. TODO: this does not handle opacity set on ancestor elements
82 // (see bug https://bugzilla.mozilla.org/show_bug.cgi?id=1544721).
83 const opacity = computedStyle.opacity
84 ? parseFloat(computedStyle.opacity)
90 const textRgbaColor = new colorUtils.CssColor(
91 `rgba(${r}, ${g}, ${b}, ${a})`,
94 // TODO: For cases where text color is transparent, it likely comes from the color of
95 // the background that is underneath it (commonly from background-clip: text
96 // property). With some additional investigation it might be possible to calculate the
97 // color contrast where the color of the background is used as text color and the
98 // color of the ancestor's background is used as its background.
99 if (textRgbaColor.isTransparent()) {
103 const isBoldText = parseInt(fontWeight, 10) >= 600;
104 const size = parseFloat(fontSize);
108 ? LARGE_TEXT.BOLD_LARGE_TEXT_MIN_PIXELS
109 : LARGE_TEXT.LARGE_TEXT_MIN_PIXELS);
121 * Calculates contrast ratio or range of contrast ratios of the referenced DOM node
122 * against the given background color data. If background is multi-colored, return a
123 * range, otherwise a single contrast ratio.
125 * @param {Object} backgroundColorData
126 * Object with one or more of the following properties:
128 * rgba array for single color background
130 * min luminance rgba array for multi color background
132 * max luminance rgba array for multi color background
133 * @param {Object} textData
135 * rgba array for text of referenced DOM node
136 * - isLargeText {Boolean}
137 * True if text of referenced DOM node is large
139 * An object that may contain one or more of the following fields: error,
140 * isLargeText, value, min, max values for contrast.
142 function getContrastRatioAgainstBackground(
144 { color, isLargeText }
146 if (backgroundColorData.value) {
147 const value = colorUtils.calculateContrastRatio(
148 backgroundColorData.value,
154 backgroundColor: backgroundColorData.value,
156 score: getContrastRatioScore(value, isLargeText),
160 let { min: backgroundColorMin, max: backgroundColorMax } =
162 let min = colorUtils.calculateContrastRatio(backgroundColorMin, color);
163 let max = colorUtils.calculateContrastRatio(backgroundColorMax, color);
165 // Flip minimum and maximum contrast ratios if necessary.
167 [min, max] = [max, min];
168 [backgroundColorMin, backgroundColorMax] = [
174 const score = getContrastRatioScore(min, isLargeText);
185 scoreMax: getContrastRatioScore(max, isLargeText),
189 exports.getContrastRatioScore = getContrastRatioScore;
190 exports.getTextProperties = getTextProperties;
191 exports.getContrastRatioAgainstBackground = getContrastRatioAgainstBackground;
192 exports.LARGE_TEXT = LARGE_TEXT;