Diff
Modified: trunk/LayoutTests/ChangeLog (283358 => 283359)
--- trunk/LayoutTests/ChangeLog 2021-10-01 04:18:17 UTC (rev 283358)
+++ trunk/LayoutTests/ChangeLog 2021-10-01 07:58:12 UTC (rev 283359)
@@ -1,3 +1,14 @@
+2021-10-01 Kevin Turner <[email protected]>
+
+ Add support for pow(), sqrt() and hypot() per https://drafts.csswg.org/css-values-4/#exponent-funcs.
+ https://bugs.webkit.org/show_bug.cgi?id=203312
+
+ Reviewed by Simon Fraser.
+
+ Tests performing CSS calculations with pow(), sqrt(), and hypot() with a range of inputs.
+ * fast/css/calc-parsing-expected.txt:
+ * fast/css/calc-parsing.html:
+
2021-09-30 Lauro Moura <[email protected]>
[GLIB] Gardening some mediastream consistent failures
Modified: trunk/LayoutTests/fast/css/calc-parsing-expected.txt (283358 => 283359)
--- trunk/LayoutTests/fast/css/calc-parsing-expected.txt 2021-10-01 04:18:17 UTC (rev 283358)
+++ trunk/LayoutTests/fast/css/calc-parsing-expected.txt 2021-10-01 07:58:12 UTC (rev 283359)
@@ -52,6 +52,58 @@
PASS element.style['width'] is "clamp(100px, 0%, 1%)"
PASS getComputedStyle(element).getPropertyValue('width') is "100px"
+element.style["width"] = "calc(100px * pow(2, pow(2, 2)))"
+PASS element.style['width'] is "calc(1600px)"
+PASS getComputedStyle(element).getPropertyValue('width') is "1600px"
+
+element.style["width"] = "calc(1px * pow(2, 3))"
+PASS element.style['width'] is "calc(8px)"
+PASS getComputedStyle(element).getPropertyValue('width') is "8px"
+
+element.style["width"] = "calc(100px * sqrt(100))"
+PASS element.style['width'] is "calc(1000px)"
+PASS getComputedStyle(element).getPropertyValue('width') is "1000px"
+
+element.style["width"] = "calc(1px * sqrt(999))"
+PASS element.style['width'] is "calc(31.606961258558215px)"
+PASS getComputedStyle(element).getPropertyValue('width') is "31.59375px"
+
+element.style["width"] = "calc(1px * pow(2, sqrt(100))"
+PASS element.style['width'] is "calc(1024px)"
+PASS getComputedStyle(element).getPropertyValue('width') is "1024px"
+
+element.style["width"] = "hypot(4px, 5px, 7px, 9px)"
+PASS element.style['width'] is "hypot(13.076696830622021px)"
+PASS getComputedStyle(element).getPropertyValue('width') is "13.0625px"
+
+element.style["width"] = "hypot(3px, 4px)"
+PASS element.style['width'] is "hypot(5px)"
+PASS getComputedStyle(element).getPropertyValue('width') is "5px"
+
+element.style["width"] = "calc(100px * hypot(3, 4))"
+PASS element.style['width'] is "calc(500px)"
+PASS getComputedStyle(element).getPropertyValue('width') is "500px"
+
+element.style["width"] = "hypot(-5px)"
+PASS element.style['width'] is "hypot(5px)"
+PASS getComputedStyle(element).getPropertyValue('width') is "5px"
+
+element.style["width"] = "calc(1px * hypot(-5))"
+PASS element.style['width'] is "calc(5px)"
+PASS getComputedStyle(element).getPropertyValue('width') is "5px"
+
+element.style["width"] = "calc(1px * hypot(10000))"
+PASS element.style['width'] is "calc(10000px)"
+PASS getComputedStyle(element).getPropertyValue('width') is "10000px"
+
+element.style["width"] = "calc(2px * sqrt(100000000))"
+PASS element.style['width'] is "calc(20000px)"
+PASS getComputedStyle(element).getPropertyValue('width') is "20000px"
+
+element.style["width"] = "calc(3px * pow(200, 4))"
+PASS element.style['width'] is "calc(4800000000px)"
+PASS getComputedStyle(element).getPropertyValue('width') is "33554428px"
+
element.style["width"] = "calc(sin(90deg) * 100px)"
PASS 100 is 100
@@ -128,6 +180,54 @@
PASS element.style['width'] is "999px"
PASS getComputedStyle(element).getPropertyValue('width') is "999px"
+element.style["width"] = "calc(1px * pow(1))"
+PASS element.style['width'] is "999px"
+PASS getComputedStyle(element).getPropertyValue('width') is "999px"
+
+element.style["width"] = "calc(1px * pow(2px, 3px))"
+PASS element.style['width'] is "999px"
+PASS getComputedStyle(element).getPropertyValue('width') is "999px"
+
+element.style["width"] = "calc(sqrt(100px)"
+PASS element.style['width'] is "999px"
+PASS getComputedStyle(element).getPropertyValue('width') is "999px"
+
+element.style["width"] = "hypot(2px, 40%)"
+PASS element.style['width'] is "999px"
+PASS getComputedStyle(element).getPropertyValue('width') is "999px"
+
+element.style["width"] = "hypot(2px, 3)"
+PASS element.style['width'] is "999px"
+PASS getComputedStyle(element).getPropertyValue('width') is "999px"
+
+element.style["width"] = "hypot(3, ,4)"
+PASS element.style['width'] is "999px"
+PASS getComputedStyle(element).getPropertyValue('width') is "999px"
+
+element.style["width"] = "calc(1px * pow(2 3))"
+PASS element.style['width'] is "999px"
+PASS getComputedStyle(element).getPropertyValue('width') is "999px"
+
+element.style["width"] = "hypot()"
+PASS element.style['width'] is "999px"
+PASS getComputedStyle(element).getPropertyValue('width') is "999px"
+
+element.style["width"] = "calc(pow(2))"
+PASS element.style['width'] is "999px"
+PASS getComputedStyle(element).getPropertyValue('width') is "999px"
+
+element.style["width"] = "pow())"
+PASS element.style['width'] is "999px"
+PASS getComputedStyle(element).getPropertyValue('width') is "999px"
+
+element.style["width"] = "calc(sqrt())"
+PASS element.style['width'] is "999px"
+PASS getComputedStyle(element).getPropertyValue('width') is "999px"
+
+element.style["width"] = "calc(sqrt(100, 200))"
+PASS element.style['width'] is "999px"
+PASS getComputedStyle(element).getPropertyValue('width') is "999px"
+
element.style["width"] = "calc(sin(90px) * 100px)"
PASS element.style['width'] is "999px"
PASS getComputedStyle(element).getPropertyValue('width') is "999px"
@@ -212,6 +312,58 @@
PASS element.style['min-width'] is "clamp(100px, 0%, 1%)"
PASS getComputedStyle(element).getPropertyValue('min-width') is "clamp(100px, 0%, 1%)"
+element.style["min-width"] = "calc(100px * pow(2, pow(2, 2)))"
+PASS element.style['min-width'] is "calc(1600px)"
+PASS getComputedStyle(element).getPropertyValue('min-width') is "1600px"
+
+element.style["min-width"] = "calc(1px * pow(2, 3))"
+PASS element.style['min-width'] is "calc(8px)"
+PASS getComputedStyle(element).getPropertyValue('min-width') is "8px"
+
+element.style["min-width"] = "calc(100px * sqrt(100))"
+PASS element.style['min-width'] is "calc(1000px)"
+PASS getComputedStyle(element).getPropertyValue('min-width') is "1000px"
+
+element.style["min-width"] = "calc(1px * sqrt(999))"
+PASS element.style['min-width'] is "calc(31.606961258558215px)"
+PASS getComputedStyle(element).getPropertyValue('min-width') is "31.606962203979492px"
+
+element.style["min-width"] = "calc(1px * pow(2, sqrt(100))"
+PASS element.style['min-width'] is "calc(1024px)"
+PASS getComputedStyle(element).getPropertyValue('min-width') is "1024px"
+
+element.style["min-width"] = "hypot(4px, 5px, 7px, 9px)"
+PASS element.style['min-width'] is "hypot(13.076696830622021px)"
+PASS getComputedStyle(element).getPropertyValue('min-width') is "13.076696395874023px"
+
+element.style["min-width"] = "hypot(3px, 4px)"
+PASS element.style['min-width'] is "hypot(5px)"
+PASS getComputedStyle(element).getPropertyValue('min-width') is "5px"
+
+element.style["min-width"] = "calc(100px * hypot(3, 4))"
+PASS element.style['min-width'] is "calc(500px)"
+PASS getComputedStyle(element).getPropertyValue('min-width') is "500px"
+
+element.style["min-width"] = "hypot(-5px)"
+PASS element.style['min-width'] is "hypot(5px)"
+PASS getComputedStyle(element).getPropertyValue('min-width') is "5px"
+
+element.style["min-width"] = "calc(1px * hypot(-5))"
+PASS element.style['min-width'] is "calc(5px)"
+PASS getComputedStyle(element).getPropertyValue('min-width') is "5px"
+
+element.style["min-width"] = "calc(1px * hypot(10000))"
+PASS element.style['min-width'] is "calc(10000px)"
+PASS getComputedStyle(element).getPropertyValue('min-width') is "10000px"
+
+element.style["min-width"] = "calc(2px * sqrt(100000000))"
+PASS element.style['min-width'] is "calc(20000px)"
+PASS getComputedStyle(element).getPropertyValue('min-width') is "20000px"
+
+element.style["min-width"] = "calc(3px * pow(200, 4))"
+PASS element.style['min-width'] is "calc(4800000000px)"
+PASS getComputedStyle(element).getPropertyValue('min-width') is "33554428px"
+
element.style["min-width"] = "calc(sin(90deg) * 100px)"
PASS 100 is 100
@@ -288,6 +440,54 @@
PASS element.style['min-width'] is "999px"
PASS getComputedStyle(element).getPropertyValue('min-width') is "999px"
+element.style["min-width"] = "calc(1px * pow(1))"
+PASS element.style['min-width'] is "999px"
+PASS getComputedStyle(element).getPropertyValue('min-width') is "999px"
+
+element.style["min-width"] = "calc(1px * pow(2px, 3px))"
+PASS element.style['min-width'] is "999px"
+PASS getComputedStyle(element).getPropertyValue('min-width') is "999px"
+
+element.style["min-width"] = "calc(sqrt(100px)"
+PASS element.style['min-width'] is "999px"
+PASS getComputedStyle(element).getPropertyValue('min-width') is "999px"
+
+element.style["min-width"] = "hypot(2px, 40%)"
+PASS element.style['min-width'] is "999px"
+PASS getComputedStyle(element).getPropertyValue('min-width') is "999px"
+
+element.style["min-width"] = "hypot(2px, 3)"
+PASS element.style['min-width'] is "999px"
+PASS getComputedStyle(element).getPropertyValue('min-width') is "999px"
+
+element.style["min-width"] = "hypot(3, ,4)"
+PASS element.style['min-width'] is "999px"
+PASS getComputedStyle(element).getPropertyValue('min-width') is "999px"
+
+element.style["min-width"] = "calc(1px * pow(2 3))"
+PASS element.style['min-width'] is "999px"
+PASS getComputedStyle(element).getPropertyValue('min-width') is "999px"
+
+element.style["min-width"] = "hypot()"
+PASS element.style['min-width'] is "999px"
+PASS getComputedStyle(element).getPropertyValue('min-width') is "999px"
+
+element.style["min-width"] = "calc(pow(2))"
+PASS element.style['min-width'] is "999px"
+PASS getComputedStyle(element).getPropertyValue('min-width') is "999px"
+
+element.style["min-width"] = "pow())"
+PASS element.style['min-width'] is "999px"
+PASS getComputedStyle(element).getPropertyValue('min-width') is "999px"
+
+element.style["min-width"] = "calc(sqrt())"
+PASS element.style['min-width'] is "999px"
+PASS getComputedStyle(element).getPropertyValue('min-width') is "999px"
+
+element.style["min-width"] = "calc(sqrt(100, 200))"
+PASS element.style['min-width'] is "999px"
+PASS getComputedStyle(element).getPropertyValue('min-width') is "999px"
+
element.style["min-width"] = "calc(sin(90px) * 100px)"
PASS element.style['min-width'] is "999px"
PASS getComputedStyle(element).getPropertyValue('min-width') is "999px"
Modified: trunk/LayoutTests/fast/css/calc-parsing.html (283358 => 283359)
--- trunk/LayoutTests/fast/css/calc-parsing.html 2021-10-01 04:18:17 UTC (rev 283358)
+++ trunk/LayoutTests/fast/css/calc-parsing.html 2021-10-01 07:58:12 UTC (rev 283359)
@@ -42,6 +42,19 @@
testExpression('min(100px,0%)', 'min(100px, 0%)', propertyName == 'width' ? '0px' : "min(100px, 0%)");
testExpression('max(100px,0%)', 'max(100px, 0%)', propertyName == 'width' ? '100px' : "max(100px, 0%)");
testExpression('clamp(100px,0%,1%)', 'clamp(100px, 0%, 1%)', propertyName == 'width' ? '100px' : "clamp(100px, 0%, 1%)");
+ testExpression('calc(100px * pow(2, pow(2, 2)))', 'calc(1600px)', '1600px');
+ testExpression('calc(1px * pow(2, 3))', 'calc(8px)', '8px')
+ testExpression('calc(100px * sqrt(100))', 'calc(1000px)', '1000px');
+ testExpression('calc(1px * sqrt(999))', 'calc(31.606961258558215px)', propertyName == 'width' ? '31.59375px' : '31.606962203979492px');
+ testExpression('calc(1px * pow(2, sqrt(100))', 'calc(1024px)', '1024px');
+ testExpression('hypot(4px, 5px, 7px, 9px)', 'hypot(13.076696830622021px)', propertyName == 'width' ? '13.0625px' : '13.076696395874023px');
+ testExpression('hypot(3px, 4px)', 'hypot(5px)', '5px');
+ testExpression('calc(100px * hypot(3, 4))', 'calc(500px)', '500px');
+ testExpression('hypot(-5px)', 'hypot(5px)', '5px');
+ testExpression('calc(1px * hypot(-5))', 'calc(5px)', '5px');
+ testExpression('calc(1px * hypot(10000))', 'calc(10000px)', '10000px');
+ testExpression('calc(2px * sqrt(100000000))', 'calc(20000px)', '20000px');
+ testExpression('calc(3px * pow(200, 4))', 'calc(4800000000px)', '33554428px');
testValue('calc(sin(90deg) * 100px)', '100');
testValue('calc(sin(45deg + 45deg ) * 100px)', '100');
testValue('calc(cos( 0 ) * 100px)', '100');
@@ -65,6 +78,18 @@
testExpression('clamp(200px,,300px)', '999px', '999px');
testExpression('clamp((),,300px)', '999px', '999px');
testExpression('clamp(1px,2px,2px,4px)', '999px', '999px');
+ testExpression('calc(1px * pow(1))', '999px', '999px');
+ testExpression('calc(1px * pow(2px, 3px))', '999px', '999px');
+ testExpression('calc(sqrt(100px)', '999px', '999px');
+ testExpression('hypot(2px, 40%)', '999px', '999px');
+ testExpression('hypot(2px, 3)', '999px', '999px');
+ testExpression('hypot(3, ,4)', '999px', '999px');
+ testExpression('calc(1px * pow(2 3))', '999px', '999px');
+ testExpression('hypot()', '999px', '999px');
+ testExpression('calc(pow(2))', '999px', '999px');
+ testExpression('pow())', '999px', '999px', '999px');
+ testExpression('calc(sqrt())', '999px', '999px');
+ testExpression('calc(sqrt(100, 200))', '999px', '999px');
testExpression('calc(sin(90px) * 100px)', '999px', '999px');
testExpression('calc(sin(30deg + 1.0471967rad, 0) * 100px)', '999px', '999px');
testExpression('calc(cos( 0 ,) * 100px)', '999px', '999px');
Modified: trunk/Source/WebCore/ChangeLog (283358 => 283359)
--- trunk/Source/WebCore/ChangeLog 2021-10-01 04:18:17 UTC (rev 283358)
+++ trunk/Source/WebCore/ChangeLog 2021-10-01 07:58:12 UTC (rev 283359)
@@ -1,3 +1,38 @@
+2021-10-01 Kevin Turner <[email protected]>
+
+ Add support for pow(), sqrt() and hypot()
+ https://bugs.webkit.org/show_bug.cgi?id=203312
+ <rdar://82640883>
+
+ Reviewed by Simon Fraser.
+
+ Implements pow(), sqrt() and hypot() functions as specified by https://drafts.csswg.org/css-values-4/#exponent-funcs.
+
+ Test: fast/css/calc-parsing.html
+
+ * css/CSSValueKeywords.in: Adds pow, sqrt, and hypot keywords.
+ * css/calc/CSSCalcExpressionNodeParser.cpp:
+ (WebCore::CSSCalcExpressionNodeParser::parseCalcFunction):
+ * css/calc/CSSCalcOperationNode.cpp:
+ (WebCore::determineCategory):
+ (WebCore::functionFromOperator):
+ (WebCore::CSSCalcOperationNode::createPowOrSqrt):
+ (WebCore::CSSCalcOperationNode::createHypot):
+ (WebCore::CSSCalcOperationNode::canCombineAllChildren const): Ensures nodes that are identity functions cannot have their children combined.
+ (WebCore::CSSCalcOperationNode::combineChildren): Early exit if node behaves as an identity function. Performs combine of children if node is an exponential function.
+ (WebCore::CSSCalcOperationNode::simplifyNode): Avoid simplifying if node does not behave as an identify function. Calls combineChildren() if node is an exponential function.
+ (WebCore::functionPrefixForOperator):
+ (WebCore::CSSCalcOperationNode::evaluateOperator):
+ * css/calc/CSSCalcOperationNode.h: Adds isExponentialFunction() and isIdentity() methods. Exponential functions include hypot, sqrt, and pow. Identity functions are min and max when they contain one child.
+ * css/calc/CSSCalcValue.cpp:
+ (WebCore::createCSS):
+ (WebCore::CSSCalcValue::isCalcFunction):
+ * platform/calc/CalcExpressionOperation.cpp:
+ (WebCore::CalcExpressionOperation::evaluate const):
+ * platform/calc/CalcOperator.cpp:
+ (WebCore::operator<<):
+ * platform/calc/CalcOperator.h:
+
2021-09-30 Simon Fraser <[email protected]>
Rename snapRubberBand() to have a clearer name
Modified: trunk/Source/WebCore/css/CSSValueKeywords.in (283358 => 283359)
--- trunk/Source/WebCore/css/CSSValueKeywords.in 2021-10-01 04:18:17 UTC (rev 283358)
+++ trunk/Source/WebCore/css/CSSValueKeywords.in 2021-10-01 07:58:12 UTC (rev 283359)
@@ -1347,6 +1347,9 @@
min
max
clamp
+pow
+sqrt
+hypot
sin
cos
e
Modified: trunk/Source/WebCore/css/calc/CSSCalcExpressionNodeParser.cpp (283358 => 283359)
--- trunk/Source/WebCore/css/calc/CSSCalcExpressionNodeParser.cpp 2021-10-01 04:18:17 UTC (rev 283358)
+++ trunk/Source/WebCore/css/calc/CSSCalcExpressionNodeParser.cpp 2021-10-01 07:58:12 UTC (rev 283359)
@@ -123,6 +123,7 @@
switch (functionID) {
case CSSValueMin:
case CSSValueMax:
+ case CSSValueHypot:
maxArgumentCount = std::nullopt;
break;
case CSSValueClamp:
@@ -156,7 +157,13 @@
case CSSValueAtan2:
maxArgumentCount = 2;
break;
- // TODO: pow, sqrt, hypot.
+ case CSSValuePow:
+ minArgumentCount = 2;
+ maxArgumentCount = 2;
+ break;
+ case CSSValueSqrt:
+ maxArgumentCount = 1;
+ break;
default:
break;
}
@@ -241,7 +248,15 @@
case CSSValueSign:
result = CSSCalcOperationNode::createSign(CalcOperator::Sign, WTFMove(nodes));
break;
- // TODO: pow, sqrt, hypot
+ case CSSValuePow:
+ result = CSSCalcOperationNode::createPowOrSqrt(CalcOperator::Pow, WTFMove(nodes));
+ break;
+ case CSSValueSqrt:
+ result = CSSCalcOperationNode::createPowOrSqrt(CalcOperator::Sqrt, WTFMove(nodes));
+ break;
+ case CSSValueHypot:
+ result = CSSCalcOperationNode::createHypot(WTFMove(nodes));
+ break;
default:
break;
}
Modified: trunk/Source/WebCore/css/calc/CSSCalcOperationNode.cpp (283358 => 283359)
--- trunk/Source/WebCore/css/calc/CSSCalcOperationNode.cpp 2021-10-01 04:18:17 UTC (rev 283358)
+++ trunk/Source/WebCore/css/calc/CSSCalcOperationNode.cpp 2021-10-01 07:58:12 UTC (rev 283359)
@@ -94,6 +94,9 @@
case CalcOperator::Down:
case CalcOperator::Nearest:
case CalcOperator::ToZero:
+ case CalcOperator::Pow:
+ case CalcOperator::Sqrt:
+ case CalcOperator::Hypot:
ASSERT_NOT_REACHED();
return CalculationCategory::Other;
}
@@ -180,8 +183,12 @@
case CalcOperator::Down:
case CalcOperator::Nearest:
case CalcOperator::ToZero:
- // The type of a min(), max(), or clamp() _expression_ is the result of adding the types of its comma-separated calculations
+ case CalcOperator::Hypot:
return CalculationCategory::Other;
+ case CalcOperator::Pow:
+ case CalcOperator::Sqrt:
+ // The type of pow() and sqrt() functions must evaluate to a number.
+ return CalculationCategory::Number;
}
}
@@ -276,7 +283,6 @@
return CSSCalcPrimitiveValueNode::UnitConversion::Invalid;
}
-
static CSSValueID functionFromOperator(CalcOperator op)
{
switch (op) {
@@ -291,6 +297,12 @@
return CSSValueMax;
case CalcOperator::Clamp:
return CSSValueClamp;
+ case CalcOperator::Pow:
+ return CSSValuePow;
+ case CalcOperator::Sqrt:
+ return CSSValueSqrt;
+ case CalcOperator::Hypot:
+ return CSSValueHypot;
case CalcOperator::Sin:
return CSSValueSin;
case CalcOperator::Cos:
@@ -331,6 +343,20 @@
return CSSValueCalc;
}
+static std::optional<CalculationCategory> commonCategory(const Vector<Ref<CSSCalcExpressionNode>>& values)
+{
+ if (values.isEmpty())
+ return std::nullopt;
+
+ auto expectedCategory = values[0]->category();
+ for (size_t i = 1; i < values.size(); ++i) {
+ if (values[i]->category() != expectedCategory)
+ return std::nullopt;
+ }
+
+ return expectedCategory;
+}
+
RefPtr<CSSCalcOperationNode> CSSCalcOperationNode::create(CalcOperator op, RefPtr<CSSCalcExpressionNode>&& leftSide, RefPtr<CSSCalcExpressionNode>&& rightSide)
{
if (!leftSide || !rightSide)
@@ -441,6 +467,34 @@
return adoptRef(new CSSCalcOperationNode(CalculationCategory::Number, CalcOperator::Exp, WTFMove(values)));
}
+RefPtr<CSSCalcOperationNode> CSSCalcOperationNode::createPowOrSqrt(CalcOperator op, Vector<Ref<CSSCalcExpressionNode>>&& values)
+{
+ if (op == CalcOperator::Pow && values.size() != 2)
+ return nullptr;
+
+ if (op == CalcOperator::Sqrt && values.size() != 1)
+ return nullptr;
+
+ if (commonCategory(values) != CalculationCategory::Number) {
+ LOG_WITH_STREAM(Calc, stream << "Failed to create " << op << "node because unable to determine category from " << prettyPrintNodes(values));
+ return nullptr;
+ }
+
+ return adoptRef(new CSSCalcOperationNode(CalculationCategory::Number, op, WTFMove(values)));
+}
+
+RefPtr<CSSCalcOperationNode> CSSCalcOperationNode::createHypot(Vector<Ref<CSSCalcExpressionNode>>&& values)
+{
+ auto expectedCategory = commonCategory(values);
+
+ if (expectedCategory == CalculationCategory::Other) {
+ LOG_WITH_STREAM(Calc, stream << "Failed to create hypot node because unable to determine category from " << prettyPrintNodes(values));
+ return nullptr;
+ }
+
+ return adoptRef(new CSSCalcOperationNode(*expectedCategory, CalcOperator::Hypot, WTFMove(values)));
+}
+
RefPtr<CSSCalcOperationNode> CSSCalcOperationNode::createMinOrMaxOrClamp(CalcOperator op, Vector<Ref<CSSCalcExpressionNode>>&& values, CalculationCategory destinationCategory)
{
ASSERT(op == CalcOperator::Min || op == CalcOperator::Max || op == CalcOperator::Clamp);
@@ -597,7 +651,7 @@
bool CSSCalcOperationNode::canCombineAllChildren() const
{
- if (m_children.size() < 2)
+ if (isIdentity() || !m_children.size())
return false;
if (!is<CSSCalcPrimitiveValueNode>(m_children[0]))
@@ -630,6 +684,9 @@
void CSSCalcOperationNode::combineChildren()
{
+ if (isIdentity() || !m_children.size())
+ return;
+
if (m_children.size() < 2) {
if (m_children.size() == 1 && isTrigNode()) {
double resolvedValue = doubleValue(m_children[0]->primitiveType());
@@ -644,7 +701,6 @@
m_children.clear();
m_children.append(WTFMove(newChild));
}
-
if (m_children.size() == 1 && isInverseTrigNode()) {
double resolvedValue = doubleValue(m_children[0]->primitiveType());
auto newChild = CSSCalcPrimitiveValueNode::create(CSSPrimitiveValue::create(resolvedValue, CSSUnitType::CSS_DEG));
@@ -651,7 +707,7 @@
m_children.clear();
m_children.append(WTFMove(newChild));
}
- if (isSignNode()) {
+ if (isSignNode() || isHypotNode()) {
auto combinedUnitType = m_children[0]->primitiveType();
if (calcOperator() == CalcOperator::Sign)
combinedUnitType = CSSUnitType::CSS_NUMBER;
@@ -660,9 +716,15 @@
m_children.clear();
m_children.append(WTFMove(newChild));
}
+ if (calcOperator() == CalcOperator::Sqrt) {
+ double resolvedValue = doubleValue(m_children[0]->primitiveType());
+ auto newChild = CSSCalcPrimitiveValueNode::create(CSSPrimitiveValue::create(resolvedValue, CSSUnitType::CSS_NUMBER));
+ m_children.clear();
+ m_children.append(WTFMove(newChild));
+ }
return;
}
-
+
if (shouldSortChildren()) {
// <https://drafts.csswg.org/css-values-4/#sort-a-calculations-children>
std::stable_sort(m_children.begin(), m_children.end(), [](const auto& first, const auto& second) {
@@ -781,7 +843,7 @@
m_children = WTFMove(newChildren);
}
- if (isMinOrMaxNode() && canCombineAllChildren()) {
+ if ((isMinOrMaxNode() || isHypotNode()) && canCombineAllChildren()) {
auto combinedUnitType = m_children[0]->primitiveType();
auto category = calculationCategoryForCombination(combinedUnitType);
if (category != CalculationCategory::Other)
@@ -793,7 +855,14 @@
m_children.clear();
m_children.append(WTFMove(newChild));
}
-
+
+ if (calcOperator() == CalcOperator::Pow) {
+ auto resolvedValue = doubleValue(m_children[0]->primitiveType());
+ auto newChild = CSSCalcPrimitiveValueNode::create(CSSPrimitiveValue::create(resolvedValue, CSSUnitType::CSS_NUMBER));
+ m_children.clear();
+ m_children.append(WTFMove(newChild));
+ }
+
if (calcOperator() == CalcOperator::Atan2) {
double resolvedValue = doubleValue(m_children[0]->primitiveType());
auto newChild = CSSCalcPrimitiveValueNode::create(CSSPrimitiveValue::create(resolvedValue, CSSUnitType::CSS_DEG));
@@ -871,8 +940,8 @@
// using its children, expressed in the result’s canonical unit.
if (is<CSSCalcOperationNode>(rootNode)) {
auto& calcOperationNode = downcast<CSSCalcOperationNode>(rootNode.get());
- // Simplify operations with only one child node (other than root and operations that only need one node).
- if (calcOperationNode.children().size() == 1 && depth && !calcOperationNode.isTrigNode() && !calcOperationNode.isExpNode() && !calcOperationNode.isInverseTrigNode() && !calcOperationNode.isSignNode())
+ // Identity nodes have only one child and perform no operation on their child.
+ if (calcOperationNode.isIdentity() && depth)
return WTFMove(calcOperationNode.children()[0]);
if (calcOperationNode.isCalcSumNode()) {
@@ -907,6 +976,13 @@
if (calcOperationNode.isRoundOperation() && depth)
calcOperationNode.combineChildren();
+
+ if (calcOperationNode.isHypotNode())
+ calcOperationNode.combineChildren();
+
+ if (calcOperationNode.isPowOrSqrtNode() && depth)
+ calcOperationNode.combineChildren();
+
// If only one child remains, return the child (except at the root).
auto shouldCombineParentWithOnlyChild = [](const CSSCalcOperationNode& parent, int depth)
{
@@ -1119,6 +1195,9 @@
case CalcOperator::Down: return "round(down, ";
case CalcOperator::Nearest: return "round(nearest, ";
case CalcOperator::ToZero: return "round(to-zero, ";
+ case CalcOperator::Pow: return "pow(";
+ case CalcOperator::Sqrt: return "sqrt(";
+ case CalcOperator::Hypot: return "hypot(";
}
return "";
@@ -1327,6 +1406,25 @@
double max = children[2];
return std::max(min, std::min(value, max));
}
+ case CalcOperator::Pow:
+ if (children.size() != 2)
+ return std::numeric_limits<double>::quiet_NaN();
+ return std::pow(children[0], children[1]);
+ case CalcOperator::Sqrt: {
+ if (children.size() != 1)
+ return std::numeric_limits<double>::quiet_NaN();
+ return std::sqrt(children[0]);
+ }
+ case CalcOperator::Hypot: {
+ if (children.isEmpty())
+ return std::numeric_limits<double>::quiet_NaN();
+ if (children.size() == 1)
+ return std::abs(children[0]);
+ double sum = 0;
+ for (auto child : children)
+ sum += (child * child);
+ return std::sqrt(sum);
+ }
case CalcOperator::Sin: {
if (children.size() != 1)
return std::numeric_limits<double>::quiet_NaN();
Modified: trunk/Source/WebCore/css/calc/CSSCalcOperationNode.h (283358 => 283359)
--- trunk/Source/WebCore/css/calc/CSSCalcOperationNode.h 2021-10-01 04:18:17 UTC (rev 283358)
+++ trunk/Source/WebCore/css/calc/CSSCalcOperationNode.h 2021-10-01 07:58:12 UTC (rev 283359)
@@ -37,6 +37,8 @@
static RefPtr<CSSCalcOperationNode> createSum(Vector<Ref<CSSCalcExpressionNode>>&& values);
static RefPtr<CSSCalcOperationNode> createProduct(Vector<Ref<CSSCalcExpressionNode>>&& values);
static RefPtr<CSSCalcOperationNode> createMinOrMaxOrClamp(CalcOperator, Vector<Ref<CSSCalcExpressionNode>>&& values, CalculationCategory destinationCategory);
+ static RefPtr<CSSCalcOperationNode> createPowOrSqrt(CalcOperator, Vector<Ref<CSSCalcExpressionNode>>&& values);
+ static RefPtr<CSSCalcOperationNode> createHypot(Vector<Ref<CSSCalcExpressionNode>>&& values);
static RefPtr<CSSCalcOperationNode> createTrig(CalcOperator, Vector<Ref<CSSCalcExpressionNode>>&& values);
static RefPtr<CSSCalcOperationNode> createLog(Vector<Ref<CSSCalcExpressionNode>>&& values);
static RefPtr<CSSCalcOperationNode> createExp(Vector<Ref<CSSCalcExpressionNode>>&& values);
@@ -63,6 +65,8 @@
bool isSteppedNode() const { return m_operator == CalcOperator::Mod || m_operator == CalcOperator::Rem || m_operator == CalcOperator::Round; }
bool isRoundOperation() const { return m_operator == CalcOperator::Down || m_operator == CalcOperator::Up || m_operator == CalcOperator::ToZero || m_operator == CalcOperator::Nearest; }
bool isRoundConstant() const { return (isRoundOperation()) && !m_children.size(); }
+ bool isHypotNode() const { return m_operator == CalcOperator::Hypot; }
+ bool isPowOrSqrtNode() const { return m_operator == CalcOperator::Pow || m_operator == CalcOperator::Sqrt; }
void hoistChildrenWithOperator(CalcOperator);
void combineChildren();
@@ -69,6 +73,8 @@
bool canCombineAllChildren() const;
+ bool isIdentity() const { return m_children.size() == 1 && (m_operator == CalcOperator::Min || m_operator == CalcOperator::Max || m_operator == CalcOperator::Add || m_operator == CalcOperator::Multiply); }
+
const Vector<Ref<CSSCalcExpressionNode>>& children() const { return m_children; }
Vector<Ref<CSSCalcExpressionNode>>& children() { return m_children; }
Modified: trunk/Source/WebCore/css/calc/CSSCalcValue.cpp (283358 => 283359)
--- trunk/Source/WebCore/css/calc/CSSCalcValue.cpp 2021-10-01 04:18:17 UTC (rev 283358)
+++ trunk/Source/WebCore/css/calc/CSSCalcValue.cpp 2021-10-01 07:58:12 UTC (rev 283359)
@@ -213,6 +213,19 @@
return nullptr;
return CSSCalcOperationNode::createSign(op, WTFMove(children));
}
+ case CalcOperator::Sqrt:
+ case CalcOperator::Pow: {
+ auto children = createCSS(operationChildren, style);
+ if (children.isEmpty())
+ return nullptr;
+ return CSSCalcOperationNode::createPowOrSqrt(op, WTFMove(children));
+ }
+ case CalcOperator::Hypot: {
+ auto children = createCSS(operationChildren, style);
+ if (children.isEmpty())
+ return nullptr;
+ return CSSCalcOperationNode::createHypot(WTFMove(children));
+ }
case CalcOperator::Mod:
case CalcOperator::Rem:
case CalcOperator::Round: {
@@ -338,6 +351,9 @@
case CSSValueMin:
case CSSValueMax:
case CSSValueClamp:
+ case CSSValuePow:
+ case CSSValueSqrt:
+ case CSSValueHypot:
case CSSValueSin:
case CSSValueCos:
case CSSValueTan:
Modified: trunk/Source/WebCore/platform/calc/CalcExpressionOperation.cpp (283358 => 283359)
--- trunk/Source/WebCore/platform/calc/CalcExpressionOperation.cpp 2021-10-01 04:18:17 UTC (rev 283358)
+++ trunk/Source/WebCore/platform/calc/CalcExpressionOperation.cpp 2021-10-01 07:58:12 UTC (rev 283359)
@@ -95,6 +95,30 @@
float max = m_children[2]->evaluate(maxValue);
return std::max(min, std::min(value, max));
}
+ case CalcOperator::Pow: {
+ if (m_children.size() != 2)
+ return std::numeric_limits<float>::quiet_NaN();
+ float base = m_children[0]->evaluate(maxValue);
+ float power = m_children[1]->evaluate(maxValue);
+ return std::pow(base, power);
+ }
+ case CalcOperator::Sqrt: {
+ if (m_children.size() != 1)
+ return std::numeric_limits<float>::quiet_NaN();
+ return std::sqrt(m_children[0]->evaluate(maxValue));
+ }
+ case CalcOperator::Hypot: {
+ if (m_children.isEmpty())
+ return std::numeric_limits<float>::quiet_NaN();
+ if (m_children.size() == 1)
+ return std::abs(m_children[0]->evaluate(maxValue));
+ float sum = 0;
+ for (auto& child : m_children) {
+ float value = child->evaluate(maxValue);
+ sum += (value * value);
+ }
+ return sum;
+ }
case CalcOperator::Sin: {
if (m_children.size() != 1)
return std::numeric_limits<double>::quiet_NaN();
Modified: trunk/Source/WebCore/platform/calc/CalcOperator.cpp (283358 => 283359)
--- trunk/Source/WebCore/platform/calc/CalcOperator.cpp 2021-10-01 04:18:17 UTC (rev 283358)
+++ trunk/Source/WebCore/platform/calc/CalcOperator.cpp 2021-10-01 07:58:12 UTC (rev 283359)
@@ -40,6 +40,9 @@
case CalcOperator::Min: ts << "min"; break;
case CalcOperator::Max: ts << "max"; break;
case CalcOperator::Clamp: ts << "clamp"; break;
+ case CalcOperator::Pow: ts << "pow"; break;
+ case CalcOperator::Sqrt: ts << "sqrt"; break;
+ case CalcOperator::Hypot: ts << "hypot"; break;
case CalcOperator::Sin: ts << "sin"; break;
case CalcOperator::Cos: ts << "cos"; break;
case CalcOperator::Tan: ts << "tan"; break;
Modified: trunk/Source/WebCore/platform/calc/CalcOperator.h (283358 => 283359)
--- trunk/Source/WebCore/platform/calc/CalcOperator.h 2021-10-01 04:18:17 UTC (rev 283358)
+++ trunk/Source/WebCore/platform/calc/CalcOperator.h 2021-10-01 07:58:12 UTC (rev 283359)
@@ -38,6 +38,9 @@
Min = 0,
Max,
Clamp,
+ Pow,
+ Sqrt,
+ Hypot,
Sin,
Cos,
Tan,