blob: 385fedf3fdd9b4de5862975a04256bc37fab74b7 [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,
* 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 "ContainerQuery.h"
#include "CSSMarkup.h"
#include "CSSValue.h"
#include <wtf/NeverDestroyed.h>
#include <wtf/text/StringBuilder.h>
namespace WebCore {
namespace CQ {
namespace FeatureNames {
const AtomString& width()
{
static MainThreadNeverDestroyed<AtomString> name { "width"_s };
return name;
}
const AtomString& height()
{
static MainThreadNeverDestroyed<AtomString> name { "height"_s };
return name;
}
const AtomString& inlineSize()
{
static MainThreadNeverDestroyed<AtomString> name { "inline-size"_s };
return name;
}
const AtomString& blockSize()
{
static MainThreadNeverDestroyed<AtomString> name { "block-size"_s };
return name;
}
const AtomString& aspectRatio()
{
static MainThreadNeverDestroyed<AtomString> name { "aspect-ratio"_s };
return name;
}
const AtomString& orientation()
{
static MainThreadNeverDestroyed<AtomString> name { "orientation"_s };
return name;
}
}
OptionSet<Axis> requiredAxesForFeature(const AtomString& featureName)
{
if (featureName == FeatureNames::width())
return { Axis::Width };
if (featureName == FeatureNames::height())
return { Axis::Height };
if (featureName == FeatureNames::inlineSize())
return { Axis::Inline };
if (featureName == FeatureNames::blockSize())
return { Axis::Block };
if (featureName == FeatureNames::aspectRatio() || featureName == FeatureNames::orientation())
return { Axis::Inline, Axis::Block };
return { };
}
void serialize(StringBuilder&, const SizeFeature&);
template<typename ConditionType> void serialize(StringBuilder&, const ConditionType&);
static void serialize(StringBuilder& builder, const ContainerQuery& containerQuery)
{
WTF::switchOn(containerQuery, [&](auto& node) {
builder.append('(');
serialize(builder, node);
builder.append(')');
}, [&](const CQ::UnknownQuery& unknownQuery) {
builder.append(unknownQuery.name);
builder.append('(');
builder.append(unknownQuery.text);
builder.append(')');
});
}
void serialize(StringBuilder& builder, const SizeFeature& sizeFeature)
{
auto serializeRangeComparisonOperator = [&](ComparisonOperator op) {
builder.append(' ');
switch (op) {
case ComparisonOperator::LessThan:
builder.append('<');
break;
case ComparisonOperator::LessThanOrEqual:
builder.append("<=");
break;
case ComparisonOperator::Equal:
builder.append('=');
break;
case ComparisonOperator::GreaterThan:
builder.append('>');
break;
case ComparisonOperator::GreaterThanOrEqual:
builder.append(">=");
break;
}
builder.append(' ');
};
switch (sizeFeature.syntax) {
case Syntax::Boolean:
serializeIdentifier(sizeFeature.name, builder);
break;
case Syntax::Colon:
switch (sizeFeature.rightComparison->op) {
case ComparisonOperator::LessThanOrEqual:
builder.append("max-");
break;
case ComparisonOperator::Equal:
break;
case ComparisonOperator::GreaterThanOrEqual:
builder.append("min-");
break;
case ComparisonOperator::LessThan:
case ComparisonOperator::GreaterThan:
ASSERT_NOT_REACHED();
break;
}
serializeIdentifier(sizeFeature.name, builder);
builder.append(": ");
builder.append(sizeFeature.rightComparison->value->cssText());
break;
case Syntax::Range:
if (sizeFeature.leftComparison) {
builder.append(sizeFeature.leftComparison->value->cssText());
serializeRangeComparisonOperator(sizeFeature.leftComparison->op);
}
serializeIdentifier(sizeFeature.name, builder);
if (sizeFeature.rightComparison) {
serializeRangeComparisonOperator(sizeFeature.rightComparison->op);
builder.append(sizeFeature.rightComparison->value->cssText());
}
break;
}
}
template<typename ConditionType>
void serialize(StringBuilder& builder, const ConditionType& condition)
{
if (condition.queries.size() == 1 && condition.logicalOperator == LogicalOperator::Not) {
builder.append("not ");
serialize(builder, condition.queries.first());
return;
}
for (auto& query : condition.queries) {
if (&query != &condition.queries.first())
builder.append(condition.logicalOperator == LogicalOperator::And ? " and " : " or ");
serialize(builder, query);
}
}
}
void serialize(StringBuilder& builder, const ContainerQuery& query)
{
CQ::serialize(builder, query);
}
}