Skip to content

Commit

Permalink
Implement input validation for CSSRGB constructor and setters
Browse files Browse the repository at this point in the history
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 c4f1f9c
Show file tree
Hide file tree
Showing 8 changed files with 258 additions and 63 deletions.
Original file line number Diff line number Diff line change
@@ -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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down Expand Up @@ -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>
1 change: 1 addition & 0 deletions Source/WebCore/Sources.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions Source/WebCore/WebCore.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -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>"; };
Expand Down Expand Up @@ -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 */,
Expand Down
81 changes: 81 additions & 0 deletions Source/WebCore/css/typedom/color/CSSColorValue.cpp
Original file line number Diff line number Diff line change
@@ -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
12 changes: 8 additions & 4 deletions Source/WebCore/css/typedom/color/CSSColorValue.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Loading

0 comments on commit c4f1f9c

Please sign in to comment.