Skip to content

Commit

Permalink
[CSS Math Functions] De-duplicate `CSSCalcOperationNode::evaluateOper…
Browse files Browse the repository at this point in the history
…ator` & `CalcExpressionOperation::evaluate`

https://bugs.webkit.org/show_bug.cgi?id=259021
rdar://111962034

Reviewed by Darin Adler.

Use a common `evaluateCalcExpression` template function.

* Source/WebCore/css/calc/CSSCalcOperationNode.cpp:
(WebCore::CSSCalcOperationNode::evaluateOperator):
(WebCore::getNearestMultiples): Deleted.
* Source/WebCore/platform/calc/CalcExpressionOperation.cpp:
(WebCore::CalcExpressionOperation::evaluate const):
(WebCore::getNearestMultiples): Deleted.
* Source/WebCore/platform/calc/CalcOperator.h:
(WebCore::evaluateCalcExpression):

Canonical link: https://commits.webkit.org/265888@main
  • Loading branch information
nt1m committed Jul 9, 2023
1 parent 9047798 commit 4ea2d50
Show file tree
Hide file tree
Showing 3 changed files with 236 additions and 437 deletions.
227 changes: 4 additions & 223 deletions Source/WebCore/css/calc/CSSCalcOperationNode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@
#include "Logging.h"
#include <wtf/Algorithms.h>
#include <wtf/ListHashSet.h>
#include <wtf/MathExtras.h>
#include <wtf/text/TextStream.h>

namespace WebCore {
Expand Down Expand Up @@ -1273,229 +1272,11 @@ bool CSSCalcOperationNode::equals(const CSSCalcExpressionNode& exp) const
return true;
}

static std::pair<double, double> getNearestMultiples(double a, double b)
double CSSCalcOperationNode::evaluateOperator(CalcOperator calcOperator, const Vector<double>& children)
{
double lowerB = std::floor(a / std::abs(b))*std::abs(b);
double upperB = lowerB + std::abs(b);
return std::make_pair(lowerB, upperB);
}

double CSSCalcOperationNode::evaluateOperator(CalcOperator op, const Vector<double>& children)
{
switch (op) {
case CalcOperator::Add: {
double sum = 0;
for (auto& child : children)
sum += child;
return sum;
}
case CalcOperator::Subtract:
ASSERT(children.size() == 2);
return children[0] - children[1];
case CalcOperator::Multiply: {
double product = 1;
for (auto& child : children)
product *= child;
return product;
}
case CalcOperator::Divide:
ASSERT(children.size() == 1 || children.size() == 2);
if (children.size() == 1)
return std::numeric_limits<double>::quiet_NaN();
return children[0] / children[1];
case CalcOperator::Min: {
if (children.isEmpty())
return std::numeric_limits<double>::quiet_NaN();
double minimum = children[0];
for (auto child : children) {
if (std::isnan(child))
return child;
minimum = std::min(minimum, child);
}
return minimum;
}
case CalcOperator::Max: {
if (children.isEmpty())
return std::numeric_limits<double>::quiet_NaN();
double maximum = children[0];
for (auto child : children) {
if (std::isnan(child))
return child;
maximum = std::max(maximum, child);
}
return maximum;
}
case CalcOperator::Clamp: {
if (children.size() != 3)
return std::numeric_limits<double>::quiet_NaN();
double min = children[0];
double value = children[1];
double max = children[2];
if (std::isnan(min) || std::isnan(value) || std::isnan(max))
return std::numeric_limits<double>::quiet_NaN();
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) {
if (std::isnan(child))
return child;
sum += (child * child);
}
return std::sqrt(sum);
}
case CalcOperator::Sin: {
if (children.size() != 1)
return std::numeric_limits<double>::quiet_NaN();
return std::sin(children[0]);
}
case CalcOperator::Cos: {
if (children.size() != 1)
return std::numeric_limits<double>::quiet_NaN();
return std::cos(children[0]);
}
case CalcOperator::Tan: {
if (children.size() != 1)
return std::numeric_limits<double>::quiet_NaN();
double x = std::fmod(children[0], piDouble * 2);
// std::fmod can return negative values.
x = x < 0 ? piDouble * 2 + x : x;
ASSERT(!(x < 0));
ASSERT(!(x > piDouble * 2));
if (x == piOverTwoDouble)
return std::numeric_limits<double>::infinity();
if (x == 3 * piOverTwoDouble)
return -std::numeric_limits<double>::infinity();
return std::tan(x);
}
case CalcOperator::Log: {
if (children.size() != 1 && children.size() != 2)
return std::numeric_limits<double>::quiet_NaN();
if (children.size() == 1)
return std::log(children[0]);
return std::log(children[0]) / std::log(children[1]);
}
case CalcOperator::Exp: {
if (children.size() != 1)
return std::numeric_limits<double>::quiet_NaN();
return std::exp(children[0]);
}
case CalcOperator::Asin: {
if (children.size() != 1)
return std::numeric_limits<double>::quiet_NaN();
return rad2deg(std::asin(children[0]));
}
case CalcOperator::Acos: {
if (children.size() != 1)
return std::numeric_limits<double>::quiet_NaN();
return rad2deg(std::acos(children[0]));
}
case CalcOperator::Atan: {
if (children.size() != 1)
return std::numeric_limits<double>::quiet_NaN();
return rad2deg(std::atan(children[0]));
}
case CalcOperator::Atan2: {
if (children.size() != 2)
return std::numeric_limits<double>::quiet_NaN();
return rad2deg(atan2(children[0], children[1]));
}
case CalcOperator::Abs: {
if (children.size() != 1)
return std::numeric_limits<double>::quiet_NaN();
return std::abs(children[0]);
}
case CalcOperator::Sign: {
if (children.size() != 1)
return std::numeric_limits<double>::quiet_NaN();
if (children[0] > 0)
return 1;
if (children[0] < 0)
return -1;
return children[0];
}
case CalcOperator::Mod: {
if (children.size() != 2)
return std::numeric_limits<double>::quiet_NaN();
float left = children[0];
float right = children[1];
if (!right)
return std::numeric_limits<double>::quiet_NaN();
if ((left < 0) == (right < 0))
return std::fmod(left, right);
return std::remainder(left, right);
}
case CalcOperator::Rem: {
if (children.size() != 2)
return std::numeric_limits<double>::quiet_NaN();
float left = children[0];
float right = children[1];
if (!right)
return std::numeric_limits<double>::quiet_NaN();
return std::fmod(left, right);
}
case CalcOperator::Round:
return std::numeric_limits<double>::quiet_NaN();
case CalcOperator::Up: {
if (children.size() != 2)
return std::numeric_limits<double>::quiet_NaN();
if (!isinf(children[0]) && std::isinf(children[1])) {
if (!children[0])
return children[0];
return signbit(children[0]) ? -0.0 : std::numeric_limits<double>::infinity();
}
auto ret = getNearestMultiples(children[0], children[1]);
return ret.second;
}
case CalcOperator::Down: {
if (children.size() != 2)
return std::numeric_limits<double>::quiet_NaN();
if (!isinf(children[0]) && isinf(children[1])) {
if (!children[0])
return children[0];
return signbit(children[0]) ? -std::numeric_limits<double>::infinity() : +0.0;
}
auto ret = getNearestMultiples(children[0], children[1]);
return ret.first;
}
case CalcOperator::Nearest: {
if (children.size() != 2)
return std::numeric_limits<double>::quiet_NaN();
if (!isinf(children[0]) && isinf(children[1]))
return signbit(children[0]) ? -0.0 : +0.0;
auto ret = getNearestMultiples(children[0], children[1]);
auto upperB = ret.second;
auto lowerB = ret.first;
return std::abs(upperB - children[0]) <= std::abs(children[1]) / 2 ? upperB : lowerB;
}
case CalcOperator::ToZero: {
if (children.size() != 2)
return std::numeric_limits<double>::quiet_NaN();
if (!isinf(children[0]) && isinf(children[1]))
return signbit(children[0]) ? -0.0 : +0.0;
auto ret = getNearestMultiples(children[0], children[1]);
auto upperB = ret.second;
auto lowerB = ret.first;
return std::abs(upperB) < std::abs(lowerB) ? upperB : lowerB;
}
}
ASSERT_NOT_REACHED();
return 0;
return evaluateCalcExpression(calcOperator, children, [](double child) {
return child;
});
}



}

0 comments on commit 4ea2d50

Please sign in to comment.