blob: 892b6e850f71a152b608b8526bc7ceb2213508b5 [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "core/css/cssom/CSSMathProduct.h"
#include "core/css/CSSCalculationValue.h"
namespace blink {
namespace {
CSSNumericSumValue::UnitMap MultiplyUnitMaps(
CSSNumericSumValue::UnitMap a,
const CSSNumericSumValue::UnitMap& b) {
for (const auto& unit_exponent : b) {
DCHECK_NE(unit_exponent.value, 0);
const auto old_value =
a.Contains(unit_exponent.key) ? a.at(unit_exponent.key) : 0;
// Remove any zero entries
if (old_value + unit_exponent.value == 0)
a.erase(unit_exponent.key);
else
a.Set(unit_exponent.key, old_value + unit_exponent.value);
}
return a;
}
} // namespace
CSSMathProduct* CSSMathProduct::Create(const HeapVector<CSSNumberish>& args,
ExceptionState& exception_state) {
if (args.IsEmpty()) {
exception_state.ThrowDOMException(kSyntaxError, "Arguments can't be empty");
return nullptr;
}
CSSMathProduct* result = Create(CSSNumberishesToNumericValues(args));
if (!result) {
exception_state.ThrowTypeError("Incompatible types");
return nullptr;
}
return result;
}
CSSMathProduct* CSSMathProduct::Create(CSSNumericValueVector values) {
bool error = false;
CSSNumericValueType final_type =
CSSMathVariadic::TypeCheck(values, CSSNumericValueType::Multiply, error);
return error ? nullptr
: new CSSMathProduct(CSSNumericArray::Create(std::move(values)),
final_type);
}
WTF::Optional<CSSNumericSumValue> CSSMathProduct::SumValue() const {
CSSNumericSumValue sum;
// Start with the number '1', which is the multiplicative identity.
sum.terms.push_back(CSSNumericSumValue::Term{1, {}});
for (const auto& value : NumericValues()) {
const auto child_sum = value->SumValue();
if (!child_sum)
return WTF::nullopt;
CSSNumericSumValue new_sum;
for (const auto& a : sum.terms) {
for (const auto& b : child_sum->terms) {
new_sum.terms.emplace_back(a.value * b.value,
MultiplyUnitMaps(a.units, b.units));
}
}
sum = new_sum;
}
return sum;
}
CSSCalcExpressionNode* CSSMathProduct::ToCalcExpressionNode() const {
// TODO(crbug.com/782103): Handle the single value case correctly.
if (NumericValues().size() == 1)
return NumericValues()[0]->ToCalcExpressionNode();
CSSCalcExpressionNode* node = CSSCalcValue::CreateExpressionNode(
NumericValues()[0]->ToCalcExpressionNode(),
NumericValues()[1]->ToCalcExpressionNode(), kCalcMultiply);
for (size_t i = 2; i < NumericValues().size(); i++) {
node = CSSCalcValue::CreateExpressionNode(
node, NumericValues()[i]->ToCalcExpressionNode(), kCalcMultiply);
}
return node;
}
} // namespace blink