blob: 182f27ac5a76ac0722104aa8c654ab1582c000e7 [file] [log] [blame]
/*
* Copyright (C) 2025 Samuel Weinig <[email protected]>
*
* 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,
* 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 "StyleCustomProperty.h"
#include "CSSCalcValue.h"
#include "CSSPrimitiveValue.h"
#include "CSSSerializationContext.h"
#include "CSSTokenizer.h"
#include "CSSValueList.h"
#include "CSSValuePool.h"
#include "CSSVariableReferenceValue.h"
#include "RenderStyle.h"
#include "StyleCalculationValue.h"
#include "StylePrimitiveNumericTypes+CSSValueCreation.h"
#include "StylePrimitiveNumericTypes+Serialization.h"
#include <wtf/TZoneMallocInlines.h>
#include <wtf/NeverDestroyed.h>
namespace WebCore {
namespace Style {
WTF_MAKE_TZONE_ALLOCATED_IMPL(CustomProperty);
bool CustomProperty::operator==(const CustomProperty& other) const
{
if (m_name != other.m_name || m_value.index() != other.m_value.index())
return false;
return WTF::switchOn(m_value,
[&](const GuaranteedInvalid&) {
return true;
},
[&](const Ref<CSSVariableData>& value) {
return arePointingToEqualData(value, std::get<Ref<CSSVariableData>>(other.m_value));
},
[&](const Value& value) {
return value == std::get<Value>(other.m_value);
},
[&](const ValueList& value) {
return value == std::get<ValueList>(other.m_value);
}
);
}
Ref<CSSValue> CustomProperty::propertyValue(CSSValuePool& pool, const RenderStyle& style) const
{
auto convertValue = [&](const Value& value) {
return WTF::switchOn(value,
[&](const auto& value) -> Ref<CSSValue> {
return createCSSValue(pool, style, value);
}
);
};
return WTF::switchOn(m_value,
[&](const GuaranteedInvalid&) -> Ref<CSSValue> {
return CSSPrimitiveValue::create(""_s);
},
[&](const Ref<CSSVariableData>& variableData) -> Ref<CSSValue> {
return CSSVariableReferenceValue::create(variableData.copyRef());
},
[&](const Value& value) -> Ref<CSSValue> {
return convertValue(value);
},
[&](const ValueList& valueList) -> Ref<CSSValue> {
CSSValueListBuilder builder;
for (auto& value : valueList.values)
builder.append(convertValue(value));
switch (valueList.separator) {
case CSSValue::SpaceSeparator:
return CSSValueList::createSpaceSeparated(WTF::move(builder));
case CSSValue::CommaSeparator:
return CSSValueList::createCommaSeparated(WTF::move(builder));
case CSSValue::SlashSeparator:
return CSSValueList::createSlashSeparated(WTF::move(builder));
}
RELEASE_ASSERT_NOT_REACHED();
}
);
}
String CustomProperty::propertyValueSerialization(const CSS::SerializationContext& context, const RenderStyle& style) const
{
StringBuilder builder;
propertyValueSerialization(builder, context, style);
return builder.toString();
}
void CustomProperty::propertyValueSerialization(StringBuilder& builder, const CSS::SerializationContext& context, const RenderStyle& style) const
{
auto serializeValue = [&](StringBuilder& builder, const Value& value) {
WTF::switchOn(value,
[&](const auto& value) {
Style::serializationForCSS(builder, context, style, value);
}
);
};
WTF::switchOn(m_value,
[&](const GuaranteedInvalid&) {
// "The guaranteed-invalid value serializes as the empty string".
// https://drafts.csswg.org/css-variables-2/#guaranteed-invalid
builder.append(emptyString());
},
[&](const Ref<CSSVariableData>& value) {
builder.append(value->serialize());
},
[&](const Value& value) {
serializeValue(builder, value);
},
[&](const ValueList& valueList) {
builder.append(interleave(valueList.values, [&](auto& builder, const auto& value) {
serializeValue(builder, value);
}, CSSValue::separatorCSSText(valueList.separator)));
}
);
}
String CustomProperty::propertyValueSerializationForTokenization(const CSS::SerializationContext& context, const RenderStyle& style) const
{
StringBuilder builder;
propertyValueSerializationForTokenization(builder, context, style);
return builder.toString();
}
void CustomProperty::propertyValueSerializationForTokenization(StringBuilder& builder, const CSS::SerializationContext& context, const RenderStyle& style) const
{
// `propertyValueSerializationForTokenization` differs from `propertyValueSerialization` only in how it handles custom `color`
// values:
//
// `propertyValueSerialization`: serializes the used/resolved value of `color` values (needed for getComputedStyle)
// `propertyValueSerializationForTokenization`: serializes the computed value of `color` values (needed for style building)
auto serializeValue = [&](StringBuilder& builder, const Value& value) {
WTF::switchOn(value,
[&](const Color& value) {
Style::serializationForCSSTokenization(builder, context, value);
},
[&](const auto& value) {
Style::serializationForCSS(builder, context, style, value);
}
);
};
WTF::switchOn(m_value,
[&](const GuaranteedInvalid&) {
// "The guaranteed-invalid value serializes as the empty string".
// https://drafts.csswg.org/css-variables-2/#guaranteed-invalid
builder.append(emptyString());
},
[&](const Ref<CSSVariableData>& value) {
builder.append(value->serialize());
},
[&](const Value& value) {
serializeValue(builder, value);
},
[&](const ValueList& valueList) {
builder.append(interleave(valueList.values, [&](auto& builder, const auto& value) {
serializeValue(builder, value);
}, CSSValue::separatorCSSText(valueList.separator)));
}
);
}
const Vector<CSSParserToken>& CustomProperty::tokens() const
{
static NeverDestroyed<Vector<CSSParserToken>> emptyTokens;
return WTF::switchOn(m_value,
[&](const Ref<CSSVariableData>& value) -> const Vector<CSSParserToken>& {
return value->tokens();
},
[&](auto&) -> const Vector<CSSParserToken>& {
if (!m_cachedTokens) {
CSSTokenizer tokenizer { propertyValueSerializationForTokenization(CSS::defaultSerializationContext(), RenderStyle::defaultStyleSingleton()) };
m_cachedTokens = CSSVariableData::create(tokenizer.tokenRange());
}
return m_cachedTokens->tokens();
}
);
}
} // namespace Style
} // namespace WebCore