blob: 4a0f2fa8f404f0c7ee12a1e238a4451f8aa2b2e3 [file] [log] [blame]
/*
* Copyright (C) 2021 Tyler Wilcock <[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,
* 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 "CSSCounterStyleRule.h"
#include "CSSCounterStyleDescriptors.h"
#include "CSSPropertyParser.h"
#include "CSSPropertyParserConsumer+CounterStyles.h"
#include "CSSStyleSheet.h"
#include "CSSTokenizer.h"
#include "CSSValuePair.h"
#include "MutableStyleProperties.h"
#include "StyleProperties.h"
#include "StylePropertiesInlines.h"
#include <wtf/text/MakeString.h>
#include <wtf/text/StringBuilder.h>
namespace WebCore {
StyleRuleCounterStyle::StyleRuleCounterStyle(const AtomString& name, CSSCounterStyleDescriptors&& descriptors)
: StyleRuleBase(StyleRuleType::CounterStyle)
, m_name(name)
, m_descriptors(WTF::move(descriptors))
{
}
Ref<StyleRuleCounterStyle> StyleRuleCounterStyle::create(const AtomString& name, CSSCounterStyleDescriptors&& descriptors)
{
return adoptRef(*new StyleRuleCounterStyle(name, WTF::move(descriptors)));
}
CSSCounterStyleDescriptors::System toCounterStyleSystemEnum(const CSSValue* system)
{
if (!system)
return CSSCounterStyleDescriptors::System::Symbolic;
ASSERT(system->isValueID() || system->isPair());
CSSValueID systemKeyword = CSSValueInvalid;
if (system->isValueID())
systemKeyword = system->valueID();
else if (system->isPair()) {
// This value must be `fixed` or `extends`, both of which can or must have an additional component.
systemKeyword = system->first().valueID();
}
switch (systemKeyword) {
case CSSValueCyclic:
return CSSCounterStyleDescriptors::System::Cyclic;
case CSSValueFixed:
return CSSCounterStyleDescriptors::System::Fixed;
case CSSValueSymbolic:
return CSSCounterStyleDescriptors::System::Symbolic;
case CSSValueAlphabetic:
return CSSCounterStyleDescriptors::System::Alphabetic;
case CSSValueNumeric:
return CSSCounterStyleDescriptors::System::Numeric;
case CSSValueAdditive:
return CSSCounterStyleDescriptors::System::Additive;
case CSSValueInternalDisclosureClosed:
return CSSCounterStyleDescriptors::System::DisclosureClosed;
case CSSValueInternalDisclosureOpen:
return CSSCounterStyleDescriptors::System::DisclosureOpen;
case CSSValueInternalSimplifiedChineseInformal:
return CSSCounterStyleDescriptors::System::SimplifiedChineseInformal;
case CSSValueInternalSimplifiedChineseFormal:
return CSSCounterStyleDescriptors::System::SimplifiedChineseFormal;
case CSSValueInternalTraditionalChineseInformal:
return CSSCounterStyleDescriptors::System::TraditionalChineseInformal;
case CSSValueInternalTraditionalChineseFormal:
return CSSCounterStyleDescriptors::System::TraditionalChineseFormal;
case CSSValueInternalEthiopicNumeric:
return CSSCounterStyleDescriptors::System::EthiopicNumeric;
case CSSValueExtends:
return CSSCounterStyleDescriptors::System::Extends;
default:
ASSERT_NOT_REACHED();
return CSSCounterStyleDescriptors::System::Symbolic;
}
}
StyleRuleCounterStyle::~StyleRuleCounterStyle() = default;
Ref<CSSCounterStyleRule> CSSCounterStyleRule::create(StyleRuleCounterStyle& rule, CSSStyleSheet* sheet)
{
return adoptRef(*new CSSCounterStyleRule(rule, sheet));
}
CSSCounterStyleRule::CSSCounterStyleRule(StyleRuleCounterStyle& counterStyleRule, CSSStyleSheet* parent)
: CSSRule(parent)
, m_counterStyleRule(counterStyleRule)
{
}
CSSCounterStyleRule::~CSSCounterStyleRule() = default;
String CSSCounterStyleRule::cssText() const
{
String systemText = system();
const auto systemPrefix = systemText.isEmpty() ? ""_s : " system: "_s;
const auto systemSuffix = systemText.isEmpty() ? ""_s : ";"_s;
String symbolsText = symbols();
const auto symbolsPrefix = symbolsText.isEmpty() ? ""_s : " symbols: "_s;
const auto symbolsSuffix = symbolsText.isEmpty() ? ""_s : ";"_s;
String additiveSymbolsText = additiveSymbols();
const auto additiveSymbolsPrefix = additiveSymbolsText.isEmpty() ? ""_s : " additive-symbols: "_s;
const auto additiveSymbolsSuffix = additiveSymbolsText.isEmpty() ? ""_s : ";"_s;
String negativeText = negative();
const auto negativePrefix = negativeText.isEmpty() ? ""_s : " negative: "_s;
const auto negativeSuffix = negativeText.isEmpty() ? ""_s : ";"_s;
String prefixText = prefix();
const auto prefixTextPrefix = prefixText.isEmpty() ? ""_s : " prefix: "_s;
const auto prefixTextSuffix = prefixText.isEmpty() ? ""_s : ";"_s;
String suffixText = suffix();
const auto suffixTextPrefix = suffixText.isEmpty() ? ""_s : " suffix: "_s;
const auto suffixTextSuffix = suffixText.isEmpty() ? ""_s : ";"_s;
String padText = pad();
const auto padPrefix = padText.isEmpty() ? ""_s : " pad: "_s;
const auto padSuffix = padText.isEmpty() ? ""_s : ";"_s;
String rangeText = range();
const auto rangePrefix = rangeText.isEmpty() ? ""_s : " range: "_s;
const auto rangeSuffix = rangeText.isEmpty() ? ""_s : ";"_s;
String fallbackText = fallback();
const auto fallbackPrefix = fallbackText.isEmpty() ? ""_s : " fallback: "_s;
const auto fallbackSuffix = fallbackText.isEmpty() ? ""_s : ";"_s;
String speakAsText = speakAs();
const auto speakAsPrefix = speakAsText.isEmpty() ? ""_s : " speak-as: "_s;
const auto speakAsSuffix = speakAsText.isEmpty() ? ""_s : ";"_s;
return makeString("@counter-style "_s, name(), " {"_s,
systemPrefix, systemText, systemSuffix,
symbolsPrefix, symbolsText, symbolsSuffix,
additiveSymbolsPrefix, additiveSymbolsText, additiveSymbolsSuffix,
negativePrefix, negativeText, negativeSuffix,
prefixTextPrefix, prefixText, prefixTextSuffix,
suffixTextPrefix, suffixText, suffixTextSuffix,
padPrefix, padText, padSuffix,
rangePrefix, rangeText, rangeSuffix,
fallbackPrefix, fallbackText, fallbackSuffix,
speakAsPrefix, speakAsText, speakAsSuffix,
" }"_s);
}
void CSSCounterStyleRule::reattach(StyleRuleBase& rule)
{
m_counterStyleRule = downcast<StyleRuleCounterStyle>(rule);
}
RefPtr<CSSValue> CSSCounterStyleRule::cssValueFromText(CSSPropertyID propertyID, const String& string)
{
return CSSPropertyParser::parseCounterStyleDescriptor(propertyID, string, parserContext());
}
// https://drafts.csswg.org/css-counter-styles-3/#dom-csscounterstylerule-name
void CSSCounterStyleRule::setName(const String& text)
{
auto tokenizer = CSSTokenizer(text);
auto tokenRange = tokenizer.tokenRange();
auto name = CSSPropertyParserHelpers::consumeCounterStyleNameInPrelude(tokenRange);
if (!name)
return;
CSSStyleSheet::RuleMutationScope mutationScope(this);
mutableDescriptors().setName(WTF::move(name));
}
void CSSCounterStyleRule::setSystem(const String& text)
{
auto systemValue = cssValueFromText(CSSPropertySystem, text);
if (!systemValue)
return;
auto system = toCounterStyleSystemEnum(systemValue.get());
// If the attribute being set is `system`, and the new value would change the algorithm used, do nothing
// and abort these steps.
// (It's okay to change an aspect of the algorithm, like the first symbol value of a `fixed` system.)
// https://www.w3.org/TR/css-counter-styles-3/#the-csscounterstylerule-interface
auto systemData = extractSystemDataFromCSSValue(WTF::move(systemValue), system);
CSSStyleSheet::RuleMutationScope mutationScope(this);
mutableDescriptors().setSystemData(WTF::move(systemData));
}
void CSSCounterStyleRule::setNegative(const String& text)
{
auto newValue = cssValueFromText(CSSPropertyNegative, text);
if (!newValue)
return;
CSSStyleSheet::RuleMutationScope mutationScope(this);
mutableDescriptors().setNegative(negativeSymbolsFromCSSValue(newValue.releaseNonNull()));
}
void CSSCounterStyleRule::setPrefix(const String& text)
{
auto newValue = cssValueFromText(CSSPropertyPrefix, text);
if (!newValue)
return;
CSSStyleSheet::RuleMutationScope mutationScope(this);
mutableDescriptors().setPrefix(symbolFromCSSValue(WTF::move(newValue)));
}
void CSSCounterStyleRule::setSuffix(const String& text)
{
auto newValue = cssValueFromText(CSSPropertySuffix, text);
if (!newValue)
return;
CSSStyleSheet::RuleMutationScope mutationScope(this);
mutableDescriptors().setSuffix(symbolFromCSSValue(WTF::move(newValue)));
}
void CSSCounterStyleRule::setRange(const String& text)
{
auto newValue = cssValueFromText(CSSPropertyRange, text);
if (!newValue)
return;
CSSStyleSheet::RuleMutationScope mutationScope(this);
mutableDescriptors().setRanges(rangeFromCSSValue(newValue.releaseNonNull()));
}
void CSSCounterStyleRule::setPad(const String& text)
{
auto newValue = cssValueFromText(CSSPropertyPad, text);
if (!newValue)
return;
CSSStyleSheet::RuleMutationScope mutationScope(this);
mutableDescriptors().setPad(padFromCSSValue(newValue.releaseNonNull()));
}
void CSSCounterStyleRule::setFallback(const String& text)
{
auto newValue = cssValueFromText(CSSPropertyFallback, text);
if (!newValue)
return;
CSSStyleSheet::RuleMutationScope mutationScope(this);
mutableDescriptors().setFallbackName(fallbackNameFromCSSValue(newValue.releaseNonNull()));
}
void CSSCounterStyleRule::setSymbols(const String& text)
{
auto newValue = cssValueFromText(CSSPropertySymbols, text);
if (!newValue)
return;
CSSStyleSheet::RuleMutationScope mutationScope(this);
mutableDescriptors().setSymbols(symbolsFromCSSValue(newValue.releaseNonNull()));
}
void CSSCounterStyleRule::setAdditiveSymbols(const String& text)
{
auto newValue = cssValueFromText(CSSPropertyAdditiveSymbols, text);
if (!newValue)
return;
CSSStyleSheet::RuleMutationScope mutationScope(this);
mutableDescriptors().setAdditiveSymbols(additiveSymbolsFromCSSValue(newValue.releaseNonNull()));
}
void CSSCounterStyleRule::setSpeakAs(const String&)
{
// FIXME: @counter-style speak-as not supported (rdar://103019111).
}
} // namespace WebCore