blob: e1037a9150930b7c575d14c94a3a2ae6bda29a00 [file] [log] [blame]
/*
* 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 "CSSNumericType.h"
#include "CSSNumericValue.h"
#include "CSSUnits.h"
#if ENABLE(CSS_TYPED_OM)
namespace WebCore {
std::optional<CSSNumericType> CSSNumericType::create(CSSUnitType unit, int exponent)
{
// https://drafts.css-houdini.org/css-typed-om/#cssnumericvalue-create-a-type
CSSNumericType type;
switch (unitCategory(unit)) {
case CSSUnitCategory::Number:
return { WTFMove(type) };
case CSSUnitCategory::Percent:
type.percent = exponent;
return { WTFMove(type) };
case CSSUnitCategory::Length:
type.length = exponent;
return { WTFMove(type) };
case CSSUnitCategory::Angle:
type.angle = exponent;
return { WTFMove(type) };
case CSSUnitCategory::Time:
type.time = exponent;
return { WTFMove(type) };
case CSSUnitCategory::Frequency:
type.frequency = exponent;
return { WTFMove(type) };
case CSSUnitCategory::Resolution:
type.resolution = exponent;
return { WTFMove(type) };
case CSSUnitCategory::Other:
if (unit == CSSUnitType::CSS_FR) {
type.flex = exponent;
return { WTFMove(type) };
}
break;
}
return std::nullopt;
}
std::optional<CSSNumericType> CSSNumericType::addTypes(CSSNumericType a, CSSNumericType b)
{
// https://drafts.css-houdini.org/css-typed-om/#cssnumericvalue-add-two-types
if (a.percentHint && b.percentHint && *a.percentHint != *b.percentHint)
return std::nullopt;
if (a.percentHint)
b.applyPercentHint(*a.percentHint);
if (b.percentHint)
a.applyPercentHint(*b.percentHint);
if (a == b)
return { WTFMove(a) };
for (auto type : eachBaseType()) {
if (type == CSSNumericBaseType::Percent)
continue;
if (!a.valueForType(type) && !b.valueForType(type))
continue;
a.applyPercentHint(type);
b.applyPercentHint(type);
if (a.valueForType(type) != b.valueForType(type))
return std::nullopt;
}
return { WTFMove(a) };
}
template<typename Argument> std::optional<CSSNumericType> typeFromVector(const Vector<Ref<CSSNumericValue>>& values, std::optional<CSSNumericType>(*function)(Argument, Argument))
{
if (values.isEmpty())
return std::nullopt;
std::optional<CSSNumericType> type = values[0]->type();
for (size_t i = 1; i < values.size(); ++i) {
type = function(*type, values[i]->type());
if (!type)
return std::nullopt;
}
return type;
}
std::optional<CSSNumericType> CSSNumericType::addTypes(const Vector<Ref<CSSNumericValue>>& values)
{
return typeFromVector(values, addTypes);
}
std::optional<CSSNumericType> CSSNumericType::multiplyTypes(const CSSNumericType& a, const CSSNumericType& b)
{
// https://drafts.css-houdini.org/css-typed-om/#cssnumericvalue-multiply-two-types
if (a.percentHint && b.percentHint && *a.percentHint != *b.percentHint)
return std::nullopt;
auto add = [] (auto left, auto right) -> CSSNumericType::BaseTypeStorage {
if (!left)
return right;
if (!right)
return left;
return *left + *right;
};
return { {
add(a.length, b.length),
add(a.angle, b.angle),
add(a.time, b.time),
add(a.frequency, b.frequency),
add(a.resolution, b.resolution),
add(a.flex, b.flex),
add(a.percent, b.percent),
a.percentHint ? a.percentHint : b.percentHint
} };
}
std::optional<CSSNumericType> CSSNumericType::multiplyTypes(const Vector<Ref<CSSNumericValue>>& values)
{
return typeFromVector(values, multiplyTypes);
}
String CSSNumericType::debugString() const
{
return makeString("{",
length ? makeString(" length:", *length) : String(),
angle ? makeString(" angle:", *angle) : String(),
time ? makeString(" time:", *time) : String(),
frequency ? makeString(" frequency:", *frequency) : String(),
resolution ? makeString(" resolution:", *resolution) : String(),
flex ? makeString(" flex:", *flex) : String(),
percent ? makeString(" percent:", *percent) : String(),
percentHint ? makeString(" percentHint:", WebCore::debugString(*percentHint)) : String(),
" }");
}
auto CSSNumericType::valueForType(CSSNumericBaseType type) -> BaseTypeStorage&
{
switch (type) {
case CSSNumericBaseType::Length:
return length;
case CSSNumericBaseType::Angle:
return angle;
case CSSNumericBaseType::Time:
return time;
case CSSNumericBaseType::Frequency:
return frequency;
case CSSNumericBaseType::Resolution:
return resolution;
case CSSNumericBaseType::Flex:
return flex;
case CSSNumericBaseType::Percent:
return percent;
}
RELEASE_ASSERT_NOT_REACHED();
}
bool CSSNumericType::operator==(const CSSNumericType& other) const
{
return length == other.length
&& angle == other.angle
&& time == other.time
&& frequency == other.frequency
&& resolution == other.resolution
&& flex == other.flex
&& percent == other.percent
&& percentHint == other.percentHint;
}
void CSSNumericType::applyPercentHint(CSSNumericBaseType hint)
{
// https://drafts.css-houdini.org/css-typed-om/#apply-the-percent-hint
auto& optional = valueForType(hint);
if (!optional)
optional = 0;
if (percent)
*optional += *std::exchange(percent, 0);
percentHint = hint;
}
size_t CSSNumericType::nonZeroEntryCount() const
{
size_t count { 0 };
count += length && *length;
count += angle && *angle;
count += time && *time;
count += frequency && *frequency;
count += resolution && *resolution;
count += flex && *flex;
count += percent && *percent;
return count;
}
} // namespace WebCore
#endif