Diff
Modified: trunk/LayoutTests/ChangeLog (275825 => 275826)
--- trunk/LayoutTests/ChangeLog 2021-04-12 16:49:52 UTC (rev 275825)
+++ trunk/LayoutTests/ChangeLog 2021-04-12 16:53:16 UTC (rev 275826)
@@ -1,3 +1,15 @@
+2021-04-12 Sam Weinig <wei...@apple.com>
+
+ Update color-contrast() to support a target contrast ratio
+ https://bugs.webkit.org/show_bug.cgi?id=224411
+
+ Reviewed by Antti Koivisto.
+
+ Add tests and update results for target contrast ratios in color-contrast().
+
+ * fast/css/parsing-color-contrast-expected.txt:
+ * fast/css/parsing-color-contrast.html:
+
2021-04-12 Antti Koivisto <an...@apple.com>
Descendant style relations are sometimes reset when they shouldn't
Modified: trunk/LayoutTests/fast/css/parsing-color-contrast-expected.txt (275825 => 275826)
--- trunk/LayoutTests/fast/css/parsing-color-contrast-expected.txt 2021-04-12 16:49:52 UTC (rev 275825)
+++ trunk/LayoutTests/fast/css/parsing-color-contrast-expected.txt 2021-04-12 16:53:16 UTC (rev 275826)
@@ -3,7 +3,9 @@
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-color-contrast(... vs ..., ...)
+color-contrast(... vs ..., ... [to ...])
+
+Test with no specified target contrast
PASS computedStyle("background-color", "color-contrast(white vs red, blue)") is "rgb(0, 0, 255)"
PASS computedStyle("background-color", "color-contrast(white vs blue, red)") is "rgb(0, 0, 255)"
PASS computedStyle("background-color", "color-contrast(white vs red, blue, green)") is "rgb(0, 0, 255)"
@@ -15,6 +17,15 @@
PASS computedStyle("background-color", "color-contrast(black vs white, white)") is "rgb(255, 255, 255)"
PASS computedStyle("background-color", "color-contrast(red vs blue, rgb(255, 255, 255, .5))") is "rgba(255, 255, 255, 0.5)"
+Test with specified target contrast
+PASS computedStyle("background-color", "color-contrast(wheat vs bisque, darkgoldenrod, olive, sienna, darkgreen, maroon to AA)") is "rgb(0, 100, 0)"
+PASS computedStyle("background-color", "color-contrast(wheat vs bisque, darkgoldenrod, olive, sienna, darkgreen, maroon to AA-large)") is "rgb(128, 128, 0)"
+PASS computedStyle("background-color", "color-contrast(wheat vs bisque, darkgoldenrod, olive, sienna, darkgreen, maroon to 5.8)") is "rgb(128, 0, 0)"
+
+Test with specified target contrast that none meet
+PASS computedStyle("background-color", "color-contrast(wheat vs bisque, darkgoldenrod, olive to 100)") is "rgb(0, 0, 0)"
+PASS computedStyle("background-color", "color-contrast(green vs bisque, darkgoldenrod, olive to 100)") is "rgb(255, 255, 255)"
+
Test non-sRGB colors
PASS computedStyle("background-color", "color-contrast(green vs color(display-p3 0 1 0), color(display-p3 0 0 1))") is "color(display-p3 0 1 0)"
PASS computedStyle("background-color", "color-contrast(color(display-p3 1 1 0) vs color(display-p3 0 1 0), color(display-p3 0 0 1))") is "color(display-p3 0 0 1)"
@@ -27,6 +38,9 @@
PASS computedStyle("background-color", "color-contrast(white vs )") is "rgba(0, 0, 0, 0)"
PASS computedStyle("background-color", "color-contrast(white)") is "rgba(0, 0, 0, 0)"
PASS computedStyle("background-color", "color-contrast(white vs red green)") is "rgba(0, 0, 0, 0)"
+PASS computedStyle("background-color", "color-contrast(white vs red, green to)") is "rgba(0, 0, 0, 0)"
+PASS computedStyle("background-color", "color-contrast(white vs red, green to invalid)") is "rgba(0, 0, 0, 0)"
+PASS computedStyle("background-color", "color-contrast(white vs red to AA)") is "rgba(0, 0, 0, 0)"
PASS successfullyParsed is true
TEST COMPLETE
Modified: trunk/LayoutTests/fast/css/parsing-color-contrast.html (275825 => 275826)
--- trunk/LayoutTests/fast/css/parsing-color-contrast.html 2021-04-12 16:49:52 UTC (rev 275825)
+++ trunk/LayoutTests/fast/css/parsing-color-contrast.html 2021-04-12 16:53:16 UTC (rev 275826)
@@ -26,8 +26,11 @@
testComputedProperty("background-color", value, expected);
}
- debug('color-contrast(... vs ..., ...)');
+ debug('color-contrast(... vs ..., ... [to ...])');
+ debug('');
+ debug('Test with no specified target contrast')
+
testComputed(`color-contrast(white vs red, blue)`, `rgb(0, 0, 255)`);
testComputed(`color-contrast(white vs blue, red)`, `rgb(0, 0, 255)`);
testComputed(`color-contrast(white vs red, blue, green)`, `rgb(0, 0, 255)`);
@@ -40,6 +43,19 @@
testComputed(`color-contrast(red vs blue, rgb(255, 255, 255, .5))`, `rgba(255, 255, 255, 0.5)`);
debug('');
+ debug('Test with specified target contrast')
+
+ testComputed(`color-contrast(wheat vs bisque, darkgoldenrod, olive, sienna, darkgreen, maroon to AA)`, `rgb(0, 100, 0)`); // darkgreen
+ testComputed(`color-contrast(wheat vs bisque, darkgoldenrod, olive, sienna, darkgreen, maroon to AA-large)`, `rgb(128, 128, 0)`); // olive
+ testComputed(`color-contrast(wheat vs bisque, darkgoldenrod, olive, sienna, darkgreen, maroon to 5.8)`, `rgb(128, 0, 0)`); // olive maroon
+
+ debug('');
+ debug('Test with specified target contrast that none meet')
+ testComputed(`color-contrast(wheat vs bisque, darkgoldenrod, olive to 100)`, `rgb(0, 0, 0)`); // black
+ testComputed(`color-contrast(green vs bisque, darkgoldenrod, olive to 100)`, `rgb(255, 255, 255)`); // white
+
+
+ debug('');
debug('Test non-sRGB colors');
testComputed(`color-contrast(green vs color(display-p3 0 1 0), color(display-p3 0 0 1))`, `color(display-p3 0 1 0)`);
@@ -55,6 +71,9 @@
testComputed(`color-contrast(white vs )`, `rgba(0, 0, 0, 0)`);
testComputed(`color-contrast(white)`, `rgba(0, 0, 0, 0)`);
testComputed(`color-contrast(white vs red green)`, `rgba(0, 0, 0, 0)`);
+ testComputed(`color-contrast(white vs red, green to)`, `rgba(0, 0, 0, 0)`);
+ testComputed(`color-contrast(white vs red, green to invalid)`, `rgba(0, 0, 0, 0)`);
+ testComputed(`color-contrast(white vs red to AA)`, `rgba(0, 0, 0, 0)`);
</script>
Modified: trunk/Source/WebCore/ChangeLog (275825 => 275826)
--- trunk/Source/WebCore/ChangeLog 2021-04-12 16:49:52 UTC (rev 275825)
+++ trunk/Source/WebCore/ChangeLog 2021-04-12 16:53:16 UTC (rev 275826)
@@ -1,3 +1,27 @@
+2021-04-12 Sam Weinig <wei...@apple.com>
+
+ Update color-contrast() to support a target contrast ratio
+ https://bugs.webkit.org/show_bug.cgi?id=224411
+
+ Reviewed by Antti Koivisto.
+
+ Updated fast/css/parsing-color-contrast.html with new test cases.
+
+ * css/CSSValueKeywords.in:
+ Add new keywords, AA and AA-large which are constants for contrast ratios of 4.5
+ and 3.0 respectively.
+
+ * css/parser/CSSPropertyParserHelpers.cpp:
+ (WebCore::CSSPropertyParserHelpers::parseColorFunctionParameters):
+ Remove now incorrect comment about adding support for fallback as fallback
+ has been removed from the spec.
+
+ (WebCore::CSSPropertyParserHelpers::selectFirstColorThatMeetsOrExceedsTargetContrast):
+ (WebCore::CSSPropertyParserHelpers::selectFirstColorWithHighestContrast):
+ (WebCore::CSSPropertyParserHelpers::parseColorContrastFunctionParameters):
+ Add support for the new optional target contrast ratio in color-contrast() that was
+ recently added to CSS Color 5.
+
2021-04-12 Antti Koivisto <an...@apple.com>
Descendant style relations are sometimes reset when they shouldn't
Modified: trunk/Source/WebCore/css/CSSValueKeywords.in (275825 => 275826)
--- trunk/Source/WebCore/css/CSSValueKeywords.in 2021-04-12 16:49:52 UTC (rev 275825)
+++ trunk/Source/WebCore/css/CSSValueKeywords.in 2021-04-12 16:53:16 UTC (rev 275826)
@@ -1438,6 +1438,8 @@
// color-contast()
color-contrast
vs
+AA
+AA-large
// color-mix()
color-mix
Modified: trunk/Source/WebCore/css/parser/CSSPropertyParserHelpers.cpp (275825 => 275826)
--- trunk/Source/WebCore/css/parser/CSSPropertyParserHelpers.cpp 2021-04-12 16:49:52 UTC (rev 275825)
+++ trunk/Source/WebCore/css/parser/CSSPropertyParserHelpers.cpp 2021-04-12 16:53:16 UTC (rev 275826)
@@ -1502,8 +1502,6 @@
if (!color.isValid())
return { };
- // FIXME: Support the comma-separated list of fallback color values.
-
if (!args.atEnd())
return { };
@@ -1511,6 +1509,40 @@
return color;
}
+static Color selectFirstColorThatMeetsOrExceedsTargetContrast(const Color& originBackgroundColor, const Vector<Color>& colorsToCompareAgainst, double targetContrast)
+{
+ auto originBackgroundColorLuminance = originBackgroundColor.luminance();
+
+ for (auto& color : colorsToCompareAgainst) {
+ auto contrastRatio = WebCore::contrastRatio(originBackgroundColorLuminance, color.luminance());
+ if (contrastRatio >= targetContrast)
+ return color;
+ }
+
+ // If there is a target contrast, and the end of the list is reached without meeting that target,
+ // either white or black is returned, whichever has the higher contrast.
+ auto contrastRatioWithWhite = WebCore::contrastRatio(originBackgroundColorLuminance, 1.0f);
+ auto contrastRatioWithBlack = WebCore::contrastRatio(originBackgroundColorLuminance, 0.0f);
+ return contrastRatioWithWhite > contrastRatioWithBlack ? Color::white : Color::black;
+}
+
+static Color selectFirstColorWithHighestContrast(const Color& originBackgroundColor, const Vector<Color>& colorsToCompareAgainst)
+{
+ auto originBackgroundColorLuminance = originBackgroundColor.luminance();
+
+ size_t indexOfColorWithHigestContrastRatio = 0;
+ float highestContrastRatioSoFar = 0;
+ for (size_t i = 0; i < colorsToCompareAgainst.size(); ++i) {
+ auto contrastRatio = WebCore::contrastRatio(originBackgroundColorLuminance, colorsToCompareAgainst[i].luminance());
+ if (contrastRatio > highestContrastRatioSoFar) {
+ highestContrastRatioSoFar = contrastRatio;
+ indexOfColorWithHigestContrastRatio = i;
+ }
+ }
+
+ return colorsToCompareAgainst[indexOfColorWithHigestContrastRatio];
+}
+
static Color parseColorContrastFunctionParameters(CSSParserTokenRange& range, const CSSParserContext& context)
{
ASSERT(range.peek().functionId() == CSSValueColorContrast);
@@ -1528,6 +1560,7 @@
return { };
Vector<Color> colorsToCompareAgainst;
+ bool consumedTo = false;
do {
auto colorToCompareAgainst = consumeOriginColor(args, context);
if (!colorToCompareAgainst.isValid())
@@ -1534,24 +1567,34 @@
return { };
colorsToCompareAgainst.append(WTFMove(colorToCompareAgainst));
+
+ if (consumeIdentRaw<CSSValueTo>(args)) {
+ consumedTo = true;
+ break;
+ }
} while (consumeCommaIncludingWhitespace(args));
if (colorsToCompareAgainst.size() == 1)
return { };
- auto originBackgroundColorLuminance = originBackgroundColor.luminance();
+ if (consumedTo) {
+ auto targetContrast = [&] () -> Optional<double> {
+ if (consumeIdentRaw<CSSValueAA>(args))
+ return 4.5;
+ if (consumeIdentRaw<CSSValueAALarge>(args))
+ return 3.0;
+ return consumeNumberRaw(args);
+ }();
- size_t indexOfColorWithHigestContrastRatio = 0;
- float highestContrastRatioSoFar = 0;
- for (size_t i = 0; i < colorsToCompareAgainst.size(); ++i) {
- auto contrastRatio = WebCore::contrastRatio(originBackgroundColorLuminance, colorsToCompareAgainst[i].luminance());
- if (contrastRatio > highestContrastRatioSoFar) {
- highestContrastRatioSoFar = contrastRatio;
- indexOfColorWithHigestContrastRatio = i;
- }
+ if (!targetContrast)
+ return { };
+
+ // When a target constast is specified, we select "the first color color to meet or exceed the target contrast."
+ return selectFirstColorThatMeetsOrExceedsTargetContrast(originBackgroundColor, colorsToCompareAgainst, *targetContrast);
}
- return colorsToCompareAgainst[indexOfColorWithHigestContrastRatio];
+ // When a target constast is NOT specified, we select "the first color with the highest contrast to the single color."
+ return selectFirstColorWithHighestContrast(originBackgroundColor, colorsToCompareAgainst);
}
enum class ColorMixColorSpace {