Skip to content

Commit

Permalink
Merge pull request #1443 from IBMa/dev-1202
Browse files Browse the repository at this point in the history
Sync dev branch dev-1202 to dev-1304
  • Loading branch information
shunguoy authored May 11, 2023
2 parents 0ee725c + 710ba30 commit bc7a65a
Show file tree
Hide file tree
Showing 21 changed files with 481 additions and 66 deletions.
23 changes: 17 additions & 6 deletions accessibility-checker-engine/src/v2/dom/ColorUtil.ts
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,7 @@ export class ColorUtil {
var retVal = {
"hasGradient": false,
"hasBGImage": false,
"textShadow": false,
"fg": null,
"bg": null
};
Expand Down Expand Up @@ -267,7 +268,7 @@ export class ColorUtil {
overallWorst = worstColor;
}
}
return overallWorst;
return overallWorst; // return the darkest color
} catch (e) {
console.log(e);
}
Expand All @@ -285,7 +286,7 @@ export class ColorUtil {
// cStyle is the computed style of this layer
var cStyle = win.getComputedStyle(procNext);
if (cStyle === null) continue;

// thisBgColor is the color of this layer or null if the layer is transparent
var thisBgColor = null;
if (cStyle.backgroundColor && cStyle.backgroundColor != "transparent" && cStyle.backgroundColor != "rgba(0, 0, 0, 0)") {
Expand All @@ -300,13 +301,19 @@ export class ColorUtil {
if (!gradColors[i].length) {
gradColors.splice(i--, 1);
} else {
gradColorComp.push(ColorUtil.Color(gradColors[i]));
let colorComp = ColorUtil.Color(gradColors[i]);
if (colorComp.alpha !== undefined && colorComp.alpha < 1) {
// mix the grdient bg color wit parent bg if alpha < 1
let compStackBg = thisStackBG || priorStackBG;
colorComp = colorComp.getOverlayColor(compStackBg);
}
gradColorComp.push(colorComp);
}
}
thisBgColor = guessGradColor(gradColorComp, thisStackBG || priorStackBG, fg);
}
}

// Handle non-solid opacity
if (thisStackOpacity === null || (cStyle.opacity && cStyle.opacity.length > 0 && parseFloat(cStyle.opacity) < 1)) {
// New stack, reset
Expand Down Expand Up @@ -370,6 +377,10 @@ export class ColorUtil {
}
retVal.fg = fg;
retVal.bg = priorStackBG;

if (cStyle.textShadow && cStyle.textShadow !== 'none')
retVal.textShadow = true;

return retVal;
} catch (err) {
// something happened, then...
Expand Down Expand Up @@ -413,10 +424,10 @@ export class ColorObj {

contrastRatio(bgColor : ColorObj) {
let fgColor: ColorObj = this;

if (typeof (this.alpha) != "undefined")
fgColor = this.getOverlayColor(bgColor);

let lum1 = fgColor.relativeLuminance();
if (!bgColor.relativeLuminance) {
let s = "";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { VisUtil } from "../../v2/dom/VisUtil";
import { ColorUtil } from "../../v2/dom/ColorUtil";
import { Rule, RuleResult, RuleFail, RuleContext, RulePotential, RulePass, RuleContextHierarchy } from "../api/IRule";
import { eRulePolicy, eToolkitLevel } from "../api/IRule";
import { setCache } from "../util/CacheUtil";
//import { setCache } from "../util/CacheUtil";
import { getWeightNumber, getFontInPixels } from "../util/CSSUtil";

export let text_contrast_sufficient: Rule = {
Expand All @@ -26,23 +26,31 @@ export let text_contrast_sufficient: Rule = {
"IBMA_Color_Contrast_WCAG2AA": {
"Pass_0": "Pass_0",
"Fail_1": "Fail_1",
"Potential_1": "Potential_1"
"Potential_1": "Potential_same_color"
},
"IBMA_Color_Contrast_WCAG2AA_PV": {
"Pass_0": "Pass_0",
"Potential_1": "Potential_graphic_background"
}
},
help: {
"en-US": {
"group": `text_contrast_sufficient.html`,
"Pass_0": `text_contrast_sufficient.html`,
"Fail_1": `text_contrast_sufficient.html`,
"Potential_1": `text_contrast_sufficient.html`
"Potential_same_color": `text_contrast_sufficient.html`,
"Potential_graphic_background": `text_contrast_sufficient.html`,
"Potential_text_shadow": `text_contrast_sufficient.html`
}
},
messages: {
"en-US": {
"group": "The contrast ratio of text with its background must meet WCAG 2.1 AA requirements",
"Pass_0": "Rule Passed",
"Fail_1": "Text contrast of {0} with its background is less than the WCAG AA minimum requirements for text of size {1}px and weight of {2}",
"Potential_1": "The foreground text and its background color are both detected as {3}. Verify the text meets the WCAG 2.1 AA requirements for minimum contrast"
"Potential_same_color": "The foreground text and its background color are both detected as {3}. Verify the text meets the WCAG 2.1 AA requirements for minimum contrast",
"Potential_graphic_background": "Verify the contrast ratio of the text against the lightest and the darkest colors of the background meets the WCAG 2.1 AA minimum requirements for text of size {1}px and weight of {2}",
"Potential_text_shadow": "Verify the contrast ratio of the text with shadow meets the WCAG 2.1 AA minimum requirements for text of size {1}px and weight of {2}"
}
},
rulesets: [{
Expand Down Expand Up @@ -85,9 +93,23 @@ export let text_contrast_sufficient: Rule = {
// Ensure that this element has children with actual text.
let childStr = RPTUtil.getNodeText(ruleContext);

if (childStr.trim().length == 0 && (!RPTUtil.isShadowHostElement(ruleContext) || (RPTUtil.isShadowHostElement(ruleContext) && RPTUtil.getNodeText(ruleContext.shadowRoot) === '')))
return null;

if (!RPTUtil.isShadowHostElement(ruleContext) || (RPTUtil.isShadowHostElement(ruleContext) && RPTUtil.getNodeText(ruleContext.shadowRoot) === '')) {
if (childStr.trim().length == 0 )
return null;

// ignore if the text does not convey anything in human language
/**
* (1) ignore non-alphanumeric or special characters in ASCI: ^(a-zA-Z\d\s)
* (2) ignore non-printable unicode characters: \u0000-\u0008\u000B-\u001F\u007F-\u009F\u2000-\u200F\u2028-\u202F\u205F-\u206F\u3000\uFEFF
* see https://stackoverflow.com/questions/3770117/what-is-the-range-of-unicode-printable-characters
* (3) for now not consider unicode special characters that are different in different languages
*/
let regex = /[^(a-zA-Z\d\s)\u0000-\u0008\u000B-\u001F\u007F-\u009F\u2000-\u200F\u2028-\u202F\u205F-\u206F\u3000\uFEFF]+/g;
const removed = childStr.trim().replace(regex, '');
if (removed.length === 0)
return null;
}

let elem = ruleContext;
// the child elements (rather than shadow root) of a shadow host is either re-assigned to the shadow slot if the slot exists
// or not displayed, so shouldn't be checked from the light DOM, rather it should be checked as reassginged slot element(s) in the shadow DOM.
Expand All @@ -104,7 +126,7 @@ export let text_contrast_sufficient: Rule = {
}
if (elem === null) return;
}

let style = win.getComputedStyle(elem);

// JCH clip INFO:
Expand Down Expand Up @@ -216,7 +238,7 @@ export let text_contrast_sufficient: Rule = {
// Corner case where item is hidden (accessibility hiding technique)
return null;
}

// First determine the color contrast ratio
let colorCombo = ColorUtil.ColorCombo(elem);
if (colorCombo === null) {
Expand All @@ -232,14 +254,15 @@ export let text_contrast_sufficient: Rule = {
let isLargeScale = size >= 24 || size >= 18.6 && weight >= 700;
let passed = ratio >= 4.5 || (ratio >= 3 && isLargeScale);
let hasBackground = colorCombo.hasBGImage || colorCombo.hasGradient;
let textShadow = colorCombo.textShadow;
let isDisabled = RPTUtil.isNodeDisabled(elem);
if (!isDisabled) {
let control = RPTUtil.getControlOfLabel(elem);
if (control) {
isDisabled = RPTUtil.isNodeDisabled(control);
}
}

if (!isDisabled && nodeName === 'label' && RPTUtil.isDisabledByFirstChildFormElement(elem)) {
isDisabled = true;
}
Expand All @@ -248,30 +271,33 @@ export let text_contrast_sufficient: Rule = {
isDisabled = true;
}

setCache(ruleContext, "EXT_Color_Contrast_WCAG2AA", {
/**setCache(ruleContext, "EXT_Color_Contrast_WCAG2AA", {
"ratio": ratio,
"isLargeScale": isLargeScale,
"weight": weight,
"size": size,
"hasBackground": hasBackground,
"isDisabled": isDisabled
});
if (hasBackground) {
// Allow other color rule to fire if we have a background
return null;
}

});*/

// If element or parent is disabled, this rule does not apply (but may be 3:1 in future)
if (!passed && isDisabled) {
passed = true;
}
//return new ValidationResult(passed, [ruleContext], '', '', [ratio.toFixed(2), size, weight, fg.toHex(), bg.toHex(), colorCombo.hasBGImage, colorCombo.hasGradient]);
if (!passed) {
if (fg.toHex() === bg.toHex()) {
return RulePotential("Potential_1", [ratio.toFixed(2), size, weight, fg.toHex(), bg.toHex(), colorCombo.hasBGImage, colorCombo.hasGradient]);
if (hasBackground) {
// fire potential since a text on an image or gradient may be still viewable, depending on the text location on the gradient or image
return RulePotential("Potential_graphic_background", [ratio.toFixed(2), size, weight]);;
} else if (textShadow) {
// fire potential since a text with shadow may be still viewable, depending on the shadow efffects
return RulePotential("Potential_text_shadow", [ratio.toFixed(2), size, weight]);;
} else {
return RuleFail("Fail_1", [ratio.toFixed(2), size, weight, fg.toHex(), bg.toHex(), colorCombo.hasBGImage, colorCombo.hasGradient]);
}
if (fg.toHex() === bg.toHex()) {
return RulePotential("Potential_same_color", [ratio.toFixed(2), size, weight, fg.toHex(), bg.toHex(), colorCombo.hasBGImage, colorCombo.hasGradient]);
} else {
return RuleFail("Fail_1", [ratio.toFixed(2), size, weight, fg.toHex(), bg.toHex(), colorCombo.hasBGImage, colorCombo.hasGradient]);
}
}
} else {
return RulePass("Pass_0", [ratio.toFixed(2), size, weight, fg.toHex(), bg.toHex(), colorCombo.hasBGImage, colorCombo.hasGradient]);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,7 @@ <h3>Color using Class Tests</h3>
passedXpaths: [
],
failedXpaths: [
"/html/body/div[1]",
/**"/html/body/div[1]",
"/html/body/div[2]",
"/html/body/div[3]",
"/html/body/div[4]",
Expand All @@ -348,7 +348,7 @@ <h3>Color using Class Tests</h3>
"/html/body/div[42]",
"/html/body/div[43]",
"/html/body/div[44]",
"/html/body/div[45]"
"/html/body/div[45]"*/
]
}
];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ <h3>Color using inline code Tests</h3>
passedXpaths: [
],
failedXpaths: [
"/html/body/div[1]",
/**"/html/body/div[1]",
"/html/body/div[2]",
"/html/body/div[3]",
"/html/body/div[4]",
Expand All @@ -133,7 +133,7 @@ <h3>Color using inline code Tests</h3>
"/html/body/div[42]",
"/html/body/div[43]",
"/html/body/div[44]",
"/html/body/div[45]"
"/html/body/div[45]"*/
]
}
];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ <h3>Color using Class Tests</h3>
passedXpaths: [
],
failedXpaths: [
"/html[1]/body[1]/div[1]"
]
}
];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ <h3>Color using inline code Tests</h3>
passedXpaths: [
],
failedXpaths: [
"/html[1]/body[1]/div[1]"
]
}
];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,8 @@ <h3>Color using Class Tests</h3>
<div class="alphaContrast11">This text is pass - div[52].</div>
<div class="alphaContrast12">This text is pass - div[53].</div>
<div class="alphaContrast13">This text is pass - div[54].</div>

<div aria-disabled="true" class="lowContrast1">This text is pass - div[55].</div>
<a name="navskip"></a>


Expand All @@ -325,6 +327,28 @@ <h3>Color using Class Tests</h3>
passedXpaths: [
],
failedXpaths: [
"/html/body/div[1]",
"/html/body/div[2]",
"/html/body/div[3]",
"/html/body/div[4]",
"/html/body/div[5]",
"/html/body/div[6]",
"/html/body/div[7]",
"/html/body/div[8]",
"/html/body/div[9]",
"/html/body/div[10]",
"/html/body/div[11]",
"/html/body/div[12]",
"/html/body/div[13]",
"/html/body/div[14]",
"/html/body/div[15]",
"/html/body/div[16]",
"/html/body/div[17]",
"/html/body/div[41]",
"/html/body/div[42]",
"/html/body/div[43]",
"/html/body/div[44]",
"/html/body/div[45]"
]
}
];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,28 @@ <h3>Color using inline code Tests</h3>
passedXpaths: [
],
failedXpaths: [
"/html/body/div[1]",
"/html/body/div[2]",
"/html/body/div[3]",
"/html/body/div[4]",
"/html/body/div[5]",
"/html/body/div[6]",
"/html/body/div[7]",
"/html/body/div[8]",
"/html/body/div[9]",
"/html/body/div[10]",
"/html/body/div[11]",
"/html/body/div[12]",
"/html/body/div[13]",
"/html/body/div[14]",
"/html/body/div[15]",
"/html/body/div[16]",
"/html/body/div[17]",
"/html/body/div[41]",
"/html/body/div[42]",
"/html/body/div[43]",
"/html/body/div[44]",
"/html/body/div[45]"
]
}
];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,26 @@
UnitTest = {
ruleIds: ["text_contrast_sufficient"],
results: [

{
"ruleId": "IBMA_Color_Contrast_WCAG2AA",
"value": [
"INFORMATION",
"POTENTIAL"
],
"path": {
"dom": "/html[1]/body[1]/p[1]",
"aria": "/document[1]/paragraph[1]"
},
"reasonId": "Potential_graphic_background",
"message": "Verify the contrast ratio of the text against the lightest and the darkest colors of the background meets the WCAG 2.1 AA minimum requirements for text of size 16px and weight of 400",
"messageArgs": [
"1.00",
16,
400
],
"apiArgs": [],
"category": "Accessibility"
}
]
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,26 @@
UnitTest = {
ruleIds: ["text_contrast_sufficient"],
results: [

{
"ruleId": "IBMA_Color_Contrast_WCAG2AA",
"value": [
"INFORMATION",
"POTENTIAL"
],
"path": {
"dom": "/html[1]/body[1]/p[1]",
"aria": "/document[1]/paragraph[1]"
},
"reasonId": "Potential_graphic_background",
"message": "Verify the contrast ratio of the text against the lightest and the darkest colors of the background meets the WCAG 2.1 AA minimum requirements for text of size 16px and weight of 400",
"messageArgs": [
"2.82",
16,
400
],
"apiArgs": [],
"category": "Accessibility"
}
]
}

Expand Down
Loading

0 comments on commit bc7a65a

Please sign in to comment.