Skip to content
Permalink
Browse files
Implement input validation for CSSRGB constructor and setters
https://bugs.webkit.org/show_bug.cgi?id=246972

Reviewed by Antti Koivisto.

Implement input validation for CSSRGB constructor and setters:
- https://drafts.css-houdini.org/css-typed-om-1/#dom-cssrgb-cssrgb-r-g-b-optional-alpha
- https://drafts.css-houdini.org/css-typed-om-1/#rectify-a-csscolorrgbcomp
- https://drafts.css-houdini.org/css-typed-om-1/#rectify-a-csscolorpercent

* LayoutTests/imported/w3c/web-platform-tests/css/css-typed-om/stylevalue-subclasses/cssRGB-expected.txt:

* LayoutTests/imported/w3c/web-platform-tests/css/css-typed-om/stylevalue-subclasses/cssRGB.html:
Made some fixes to the test, which I will export to WPT:
- Expect a Syntax error instead of a TypeError, as per the specification.
- The loop for iterating over invalid test cases for the setters was wrong. As a result, the setters kept
  getting called with the string "undefined" instead of the actual test value.

* Source/WebCore/Sources.txt:
* Source/WebCore/WebCore.xcodeproj/project.pbxproj:
* Source/WebCore/css/typedom/color/CSSColorValue.cpp: Added.
(WebCore::CSSColorValue::colorSpace):
(WebCore::CSSColorValue::to):
(WebCore::CSSColorValue::parse):
(WebCore::CSSColorValue::rectifyCSSColorPercent):
(WebCore::CSSColorValue::toCSSColorPercent):
* Source/WebCore/css/typedom/color/CSSColorValue.h:
(WebCore::CSSColorValue::colorSpace): Deleted.
(WebCore::CSSColorValue::to): Deleted.
(WebCore::CSSColorValue::parse): Deleted.
* Source/WebCore/css/typedom/color/CSSRGB.cpp:
(WebCore::toCSSColorRGBComp):
(WebCore::CSSRGB::create):
(WebCore::CSSRGB::CSSRGB):
(WebCore::CSSRGB::r const):
(WebCore::CSSRGB::setR):
(WebCore::CSSRGB::g const):
(WebCore::CSSRGB::setG):
(WebCore::CSSRGB::b const):
(WebCore::CSSRGB::setB):
(WebCore::CSSRGB::alpha const):
(WebCore::CSSRGB::setAlpha):
(WebCore::CSSRGB::rectifyCSSColorRGBComp):
* Source/WebCore/css/typedom/color/CSSRGB.h:
(WebCore::CSSRGB::create): Deleted.
(WebCore::CSSRGB::r const): Deleted.
(WebCore::CSSRGB::setR): Deleted.
(WebCore::CSSRGB::g const): Deleted.
(WebCore::CSSRGB::setG): Deleted.
(WebCore::CSSRGB::b const): Deleted.
(WebCore::CSSRGB::setB): Deleted.
(WebCore::CSSRGB::alpha const): Deleted.
(WebCore::CSSRGB::setAlpha): Deleted.

Canonical link: https://commits.webkit.org/256024@main
  • Loading branch information
cdumez committed Oct 26, 2022
1 parent e48a49d commit c4f1f9c6e5d1a6085ded4dfbc458a965024ed8a4
Show file tree
Hide file tree
Showing 8 changed files with 258 additions and 63 deletions.
@@ -1,50 +1,50 @@

FAIL Constructing a CSSRGB with an angle CSSUnitValue for the color channels throws a TypeError. assert_throws_js: function "() => new CSSRGB(color, 0, 0)" did not throw
FAIL Constructing a CSSRGB with a CSSMathValue that doesn"t match <number> for the color channels throws a TypeError. assert_throws_js: function "() => new CSSRGB(color, 0, 0)" did not throw
FAIL Constructing a CSSRGB with undefined for the color channels throws a TypeError. assert_throws_js: function "() => new CSSRGB(color, 0, 0)" did not throw
FAIL Constructing a CSSRGB with a CSS math calculation for the color channels throws a TypeError. assert_throws_js: function "() => new CSSRGB(color, 0, 0)" did not throw
FAIL Constructing a CSSRGB with a CSS number for the alpha channels throws a TypeError. assert_throws_js: function "() => new CSSRGB(0, 0, 0, CSS.number(1))" did not throw
FAIL Updating CSSRGB. r to an angle CSSUnitValue throws a TypeError. assert_throws_js: function "() => result[attr] = value" did not throw
FAIL Updating CSSRGB. r to a CSSMathValue that doesn"t match <number> throws a TypeError. assert_throws_js: function "() => result[attr] = value" did not throw
FAIL Updating CSSRGB. r to undefined throws a TypeError. assert_throws_js: function "() => result[attr] = value" did not throw
FAIL Updating CSSRGB. r to a CSS math calculation throws a TypeError. assert_throws_js: function "() => result[attr] = value" did not throw
FAIL Updating CSSRGB. g to an angle CSSUnitValue throws a TypeError. assert_throws_js: function "() => result[attr] = value" did not throw
FAIL Updating CSSRGB. g to a CSSMathValue that doesn"t match <number> throws a TypeError. assert_throws_js: function "() => result[attr] = value" did not throw
FAIL Updating CSSRGB. g to undefined throws a TypeError. assert_throws_js: function "() => result[attr] = value" did not throw
FAIL Updating CSSRGB. g to a CSS math calculation throws a TypeError. assert_throws_js: function "() => result[attr] = value" did not throw
FAIL Updating CSSRGB. b to an angle CSSUnitValue throws a TypeError. assert_throws_js: function "() => result[attr] = value" did not throw
FAIL Updating CSSRGB. b to a CSSMathValue that doesn"t match <number> throws a TypeError. assert_throws_js: function "() => result[attr] = value" did not throw
FAIL Updating CSSRGB. b to undefined throws a TypeError. assert_throws_js: function "() => result[attr] = value" did not throw
FAIL Updating CSSRGB. b to a CSS math calculation throws a TypeError. assert_throws_js: function "() => result[attr] = value" did not throw
FAIL Updating CSSRGB. alpha to an angle CSSUnitValue throws a TypeError. assert_throws_js: function "() => result[attr] = value" did not throw
FAIL Updating CSSRGB. alpha to a CSSMathValue that doesn"t match <number> throws a TypeError. assert_throws_js: function "() => result[attr] = value" did not throw
FAIL Updating CSSRGB. alpha to undefined throws a TypeError. assert_throws_js: function "() => result[attr] = value" did not throw
FAIL Updating CSSRGB. alpha to a CSS math calculation throws a TypeError. assert_throws_js: function "() => result[attr] = value" did not throw
FAIL Updating the alpha channel to a CSS number throws a TypeError. assert_throws_js: function "() => result.alpha = CSS.number(1)" did not throw
FAIL CSSRGB can be constructed from three numbers and will get an alpha of 100%. assert_equals: expected "CSSUnitValue" but got "Number"
FAIL CSSRGB can be constructed from four numbers. assert_equals: expected "CSSUnitValue" but got "Number"
FAIL CSSRGB.r can be updated with a number with the resulting value being a percentage. assert_equals: expected "CSSUnitValue" but got "Number"
PASS Constructing a CSSRGB with an angle CSSUnitValue for the color channels throws a SyntaxError.
PASS Constructing a CSSRGB with a CSSMathValue that doesn"t match <number> for the color channels throws a SyntaxError.
FAIL Constructing a CSSRGB with undefined for the color channels throws a SyntaxError. assert_throws_dom: function "() => new CSSRGB(color, 0, 0)" did not throw
FAIL Constructing a CSSRGB with a CSS math calculation for the color channels throws a SyntaxError. assert_throws_dom: function "() => new CSSRGB(color, 0, 0)" did not throw
PASS Constructing a CSSRGB with a CSS number for the alpha channels throws a SyntaxError.
PASS Updating CSSRGB. r to an angle CSSUnitValue throws a SyntaxError.
PASS Updating CSSRGB. r to a CSSMathValue that doesn"t match <number> throws a SyntaxError.
FAIL Updating CSSRGB. r to undefined throws a SyntaxError. assert_throws_dom: function "() => result[attr] = color" did not throw
FAIL Updating CSSRGB. r to a CSS math calculation throws a SyntaxError. assert_throws_dom: function "() => result[attr] = color" did not throw
PASS Updating CSSRGB. g to an angle CSSUnitValue throws a SyntaxError.
PASS Updating CSSRGB. g to a CSSMathValue that doesn"t match <number> throws a SyntaxError.
FAIL Updating CSSRGB. g to undefined throws a SyntaxError. assert_throws_dom: function "() => result[attr] = color" did not throw
FAIL Updating CSSRGB. g to a CSS math calculation throws a SyntaxError. assert_throws_dom: function "() => result[attr] = color" did not throw
PASS Updating CSSRGB. b to an angle CSSUnitValue throws a SyntaxError.
PASS Updating CSSRGB. b to a CSSMathValue that doesn"t match <number> throws a SyntaxError.
FAIL Updating CSSRGB. b to undefined throws a SyntaxError. assert_throws_dom: function "() => result[attr] = color" did not throw
FAIL Updating CSSRGB. b to a CSS math calculation throws a SyntaxError. assert_throws_dom: function "() => result[attr] = color" did not throw
PASS Updating CSSRGB. alpha to an angle CSSUnitValue throws a SyntaxError.
PASS Updating CSSRGB. alpha to a CSSMathValue that doesn"t match <number> throws a SyntaxError.
FAIL Updating CSSRGB. alpha to undefined throws a SyntaxError. assert_throws_dom: function "() => result[attr] = color" did not throw
FAIL Updating CSSRGB. alpha to a CSS math calculation throws a SyntaxError. assert_throws_dom: function "() => result[attr] = color" did not throw
PASS Updating the alpha channel to a CSS number throws a SyntaxError.
PASS CSSRGB can be constructed from three numbers and will get an alpha of 100%.
PASS CSSRGB can be constructed from four numbers.
PASS CSSRGB.r can be updated with a number with the resulting value being a percentage.
PASS CSSRGB.r can be updated with a CSS number.
PASS CSSRGB.r can be updated with CSS percent.
PASS CSSRGB.r can be updated with CSS math sum.
PASS CSSRGB.r can be updated with CSS math product.
PASS CSSRGB.r can be updated with CSS math max.
PASS CSSRGB.r can be updated with CSS math min.
FAIL CSSRGB.g can be updated with a number with the resulting value being a percentage. assert_equals: expected "CSSUnitValue" but got "Number"
PASS CSSRGB.g can be updated with a number with the resulting value being a percentage.
PASS CSSRGB.g can be updated with a CSS number.
PASS CSSRGB.g can be updated with CSS percent.
PASS CSSRGB.g can be updated with CSS math sum.
PASS CSSRGB.g can be updated with CSS math product.
PASS CSSRGB.g can be updated with CSS math max.
PASS CSSRGB.g can be updated with CSS math min.
FAIL CSSRGB.b can be updated with a number with the resulting value being a percentage. assert_equals: expected "CSSUnitValue" but got "Number"
PASS CSSRGB.b can be updated with a number with the resulting value being a percentage.
PASS CSSRGB.b can be updated with a CSS number.
PASS CSSRGB.b can be updated with CSS percent.
PASS CSSRGB.b can be updated with CSS math sum.
PASS CSSRGB.b can be updated with CSS math product.
PASS CSSRGB.b can be updated with CSS math max.
PASS CSSRGB.b can be updated with CSS math min.
FAIL CSSRGB.alpha can be updated with a number with the resulting value being a percentage. assert_equals: expected "CSSUnitValue" but got "Number"
PASS CSSRGB.alpha can be updated with a number with the resulting value being a percentage.
PASS CSSRGB.alpha can be updated with CSS percent.
PASS CSSRGB.alpha can be updated with CSS math sum.
PASS CSSRGB.alpha can be updated with CSS math product.
@@ -28,34 +28,34 @@

for (const {color, desc, skipAlpha} of gInvalidColorTestCases) {
test(() => {
assert_throws_js(TypeError, () => new CSSRGB(color, 0, 0));
assert_throws_js(TypeError, () => new CSSRGB(0, color, 0));
assert_throws_js(TypeError, () => new CSSRGB(0, 0, color));
assert_throws_js(TypeError, () => new CSSRGB(color, 0, 0, 0));
assert_throws_js(TypeError, () => new CSSRGB(0, color, 0, 0));
assert_throws_js(TypeError, () => new CSSRGB(0, 0, color, 0));
if (!skipAlpha) assert_throws_js(TypeError, () => new CSSRGB(0, 0, 0, color));
}, `Constructing a CSSRGB with ${desc} for the color channels throws a TypeError.`);
assert_throws_dom("SyntaxError", () => new CSSRGB(color, 0, 0));
assert_throws_dom("SyntaxError", () => new CSSRGB(0, color, 0));
assert_throws_dom("SyntaxError", () => new CSSRGB(0, 0, color));
assert_throws_dom("SyntaxError", () => new CSSRGB(color, 0, 0, 0));
assert_throws_dom("SyntaxError", () => new CSSRGB(0, color, 0, 0));
assert_throws_dom("SyntaxError", () => new CSSRGB(0, 0, color, 0));
if (!skipAlpha) assert_throws_dom("SyntaxError", () => new CSSRGB(0, 0, 0, color));
}, `Constructing a CSSRGB with ${desc} for the color channels throws a SyntaxError.`);
}

test(() => {
assert_throws_js(TypeError, () => new CSSRGB(0, 0, 0, CSS.number(1)));
}, `Constructing a CSSRGB with a CSS number for the alpha channels throws a TypeError.`);
assert_throws_dom("SyntaxError", () => new CSSRGB(0, 0, 0, CSS.number(1)));
}, `Constructing a CSSRGB with a CSS number for the alpha channels throws a SyntaxError.`);

for (const attr of ['r', 'g', 'b', 'alpha']) {
for (const {value, desc} of gInvalidColorTestCases) {
for (const {color, desc} of gInvalidColorTestCases) {
test(() => {
const result = new CSSRGB(0, 0, 0, 0);
assert_throws_js(TypeError, () => result[attr] = value);
assert_throws_dom("SyntaxError", () => result[attr] = color);
assert_style_value_equals(result[attr], CSS.percent(0));
}, `Updating CSSRGB. ${attr} to ${desc} throws a TypeError.`);
}, `Updating CSSRGB. ${attr} to ${desc} throws a SyntaxError.`);
}
}

test(() => {
const result = new CSSRGB(0, 0, 0);
assert_throws_js(TypeError, () => result.alpha = CSS.number(1));
}, "Updating the alpha channel to a CSS number throws a TypeError.");
assert_throws_dom("SyntaxError", () => result.alpha = CSS.number(1));
}, "Updating the alpha channel to a CSS number throws a SyntaxError.");

test(() => {
const result = new CSSRGB(0.5, CSS.number(73), CSS.percent(91));
@@ -113,4 +113,4 @@
assert_color_channel_approx_equals(result[attr], CSS.percent(70));
}
}, "toRGB() function works as expected and values can be updated.");
</script>
</script>
@@ -903,6 +903,7 @@ css/typedom/DeclaredStylePropertyMap.cpp
css/typedom/MainThreadStylePropertyMapReadOnly.cpp
css/typedom/StylePropertyMap.cpp
css/typedom/color/CSSColor.cpp
css/typedom/color/CSSColorValue.cpp
css/typedom/color/CSSHSL.cpp
css/typedom/color/CSSHWB.cpp
css/typedom/color/CSSLCH.cpp
@@ -9538,6 +9538,7 @@
460CBF331D4BCCFE0092E88E /* JSDOMWindowProperties.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSDOMWindowProperties.cpp; sourceTree = "<group>"; };
460CBF341D4BCCFE0092E88E /* JSDOMWindowProperties.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSDOMWindowProperties.h; sourceTree = "<group>"; };
460D19441FCE21DD00C3DB85 /* JSServiceWorkerGlobalScopeCustom.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSServiceWorkerGlobalScopeCustom.cpp; sourceTree = "<group>"; };
46186BDB2906F37000C09164 /* CSSColorValue.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CSSColorValue.cpp; sourceTree = "<group>"; };
4625239C28E5034A00082F84 /* ScreenOrientationLockType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScreenOrientationLockType.h; sourceTree = "<group>"; };
4625239D28E5034B00082F84 /* ScreenOrientationType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScreenOrientationType.h; sourceTree = "<group>"; };
462553D228DD0FB100D48FCC /* WakeLockType.idl */ = {isa = PBXFileReference; lastKnownFileType = text; path = WakeLockType.idl; sourceTree = "<group>"; };
@@ -24146,6 +24147,7 @@
5C26E86E27E999300084CAF5 /* CSSColor.cpp */,
5C26E87627E999330084CAF5 /* CSSColor.h */,
5C26E87A27E999340084CAF5 /* CSSColor.idl */,
46186BDB2906F37000C09164 /* CSSColorValue.cpp */,
5C26E87927E999340084CAF5 /* CSSColorValue.h */,
5C26E88827E999380084CAF5 /* CSSColorValue.idl */,
5C26E88227E999370084CAF5 /* CSSHSL.cpp */,
@@ -0,0 +1,81 @@
/*
* Copyright (C) 2022 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include "config.h"
#include "CSSColorValue.h"

#include "CSSKeywordValue.h"
#include "CSSUnitValue.h"
#include "CSSUnits.h"
#include "ExceptionOr.h"

namespace WebCore {

RefPtr<CSSKeywordValue> CSSColorValue::colorSpace()
{
// FIXME: implement this.
return nullptr;
}

RefPtr<CSSColorValue> CSSColorValue::to(CSSKeywordish)
{
// FIXME: implement this.
return nullptr;
}

std::variant<RefPtr<CSSColorValue>, RefPtr<CSSStyleValue>> CSSColorValue::parse(const String&)
{
// FIXME: implement this.
return RefPtr<CSSColorValue> { nullptr };
}

// https://drafts.css-houdini.org/css-typed-om-1/#rectify-a-csscolorpercent
ExceptionOr<RectifiedCSSColorPercent> CSSColorValue::rectifyCSSColorPercent(CSSColorPercent&& colorPercent)
{
return switchOn(WTFMove(colorPercent), [](double value) -> ExceptionOr<RectifiedCSSColorPercent> {
return { RefPtr<CSSNumericValue> { CSSUnitValue::create(value * 100, CSSUnitType::CSS_PERCENTAGE) } };
}, [](RefPtr<CSSNumericValue>&& numericValue) -> ExceptionOr<RectifiedCSSColorPercent> {
if (numericValue->type().matches<CSSNumericBaseType::Percent>())
return { WTFMove(numericValue) };
return Exception { SyntaxError, "Invalid CSSColorPercent"_s };
}, [](String&& string) -> ExceptionOr<RectifiedCSSColorPercent> {
return { RefPtr<CSSKeywordValue> { CSSKeywordValue::rectifyKeywordish(WTFMove(string)) } };
}, [](RefPtr<CSSKeywordValue>&& keywordValue) -> ExceptionOr<RectifiedCSSColorPercent> {
if (equalIgnoringASCIICase(keywordValue->value(), "none"_s))
return { WTFMove(keywordValue) };
return Exception { SyntaxError, "Invalid CSSColorPercent"_s };
});
}

CSSColorPercent CSSColorValue::toCSSColorPercent(const RectifiedCSSColorPercent& component)
{
return switchOn(component, [](const RefPtr<CSSKeywordValue>& keywordValue) -> CSSColorPercent {
return keywordValue;
}, [](const RefPtr<CSSNumericValue>& numericValue) -> CSSColorPercent {
return numericValue;
});
}

} // namespace WebCore
@@ -32,17 +32,21 @@
namespace WebCore {

class CSSKeywordValue;

using CSSKeywordish = std::variant<String, RefPtr<CSSKeywordValue>>;
using CSSColorPercent = std::variant<double, RefPtr<CSSNumericValue>, String, RefPtr<CSSKeywordValue>>;
using RectifiedCSSColorPercent = std::variant<RefPtr<CSSNumericValue>, RefPtr<CSSKeywordValue>>;
using CSSColorNumber = std::variant<double, RefPtr<CSSNumericValue>, String, RefPtr<CSSKeywordValue>>;
using CSSColorAngle = std::variant<double, RefPtr<CSSNumericValue>, String, RefPtr<CSSKeywordValue>>;

class CSSColorValue : public CSSStyleValue {
public:
// FIXME: Implement these.
RefPtr<CSSKeywordValue> colorSpace() { return nullptr; }
RefPtr<CSSColorValue> to(CSSKeywordish) { return nullptr; }
static std::variant<RefPtr<CSSColorValue>, RefPtr<CSSStyleValue>> parse(String) { return RefPtr<CSSColorValue> { nullptr }; }
RefPtr<CSSKeywordValue> colorSpace();
RefPtr<CSSColorValue> to(CSSKeywordish);
static std::variant<RefPtr<CSSColorValue>, RefPtr<CSSStyleValue>> parse(const String&);

static ExceptionOr<RectifiedCSSColorPercent> rectifyCSSColorPercent(CSSColorPercent&&);
static CSSColorPercent toCSSColorPercent(const RectifiedCSSColorPercent&);
};

} // namespace WebCore

0 comments on commit c4f1f9c

Please sign in to comment.