зеркало из https://github.com/mozilla/gecko-dev.git
457 строки
13 KiB
C++
457 строки
13 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
/* a Gecko @counter-style rule */
|
|
|
|
#include "nsCSSCounterStyleRule.h"
|
|
|
|
#include "mozAutoDocUpdate.h"
|
|
#include "mozilla/ArrayUtils.h"
|
|
#include "mozilla/dom/CSSCounterStyleRuleBinding.h"
|
|
#include "mozilla/ServoCSSParser.h"
|
|
#include "nsCSSParser.h"
|
|
#include "nsStyleUtil.h"
|
|
|
|
using namespace mozilla;
|
|
using namespace mozilla::dom;
|
|
|
|
nsCSSCounterStyleRule::nsCSSCounterStyleRule(const nsCSSCounterStyleRule& aCopy)
|
|
: Rule(aCopy)
|
|
, mName(aCopy.mName)
|
|
, mGeneration(aCopy.mGeneration)
|
|
{
|
|
for (size_t i = 0; i < ArrayLength(mValues); ++i) {
|
|
mValues[i] = aCopy.mValues[i];
|
|
}
|
|
}
|
|
|
|
nsCSSCounterStyleRule::~nsCSSCounterStyleRule()
|
|
{
|
|
}
|
|
|
|
/* virtual */ already_AddRefed<css::Rule>
|
|
nsCSSCounterStyleRule::Clone() const
|
|
{
|
|
RefPtr<css::Rule> clone = new nsCSSCounterStyleRule(*this);
|
|
return clone.forget();
|
|
}
|
|
|
|
nsCSSCounterStyleRule::Getter const
|
|
nsCSSCounterStyleRule::kGetters[] = {
|
|
#define CSS_COUNTER_DESC(name_, method_) &nsCSSCounterStyleRule::Get##method_,
|
|
#include "nsCSSCounterDescList.h"
|
|
#undef CSS_COUNTER_DESC
|
|
};
|
|
|
|
// If this class gets its own cycle-collection bits, reevaluate our IsCCLeaf
|
|
// implementation.
|
|
|
|
bool
|
|
nsCSSCounterStyleRule::IsCCLeaf() const
|
|
{
|
|
return Rule::IsCCLeaf();
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
void
|
|
nsCSSCounterStyleRule::List(FILE* out, int32_t aIndent) const
|
|
{
|
|
nsCString baseInd, descInd;
|
|
for (int32_t indent = aIndent; --indent >= 0; ) {
|
|
baseInd.AppendLiteral(" ");
|
|
}
|
|
descInd = baseInd;
|
|
descInd.AppendLiteral(" ");
|
|
|
|
nsDependentAtomString name(mName);
|
|
fprintf_stderr(out, "%s@counter-style %s (rev.%u) {\n",
|
|
baseInd.get(), NS_ConvertUTF16toUTF8(name).get(),
|
|
mGeneration);
|
|
// TODO
|
|
fprintf_stderr(out, "%s}\n", baseInd.get());
|
|
}
|
|
#endif
|
|
|
|
/* virtual */ int32_t
|
|
nsCSSCounterStyleRule::GetType() const
|
|
{
|
|
return Rule::COUNTER_STYLE_RULE;
|
|
}
|
|
|
|
uint16_t
|
|
nsCSSCounterStyleRule::Type() const
|
|
{
|
|
return CSSRuleBinding::COUNTER_STYLE_RULE;
|
|
}
|
|
|
|
void
|
|
nsCSSCounterStyleRule::GetCssTextImpl(nsAString& aCssText) const
|
|
{
|
|
aCssText.AssignLiteral(u"@counter-style ");
|
|
nsDependentAtomString name(mName);
|
|
nsStyleUtil::AppendEscapedCSSIdent(name, aCssText);
|
|
aCssText.AppendLiteral(u" {\n");
|
|
for (nsCSSCounterDesc id = nsCSSCounterDesc(0);
|
|
id < eCSSCounterDesc_COUNT;
|
|
id = nsCSSCounterDesc(id + 1)) {
|
|
if (mValues[id].GetUnit() != eCSSUnit_Null) {
|
|
nsAutoString tmp;
|
|
// This is annoying. We want to be a const method, but kGetters stores
|
|
// XPCOM method pointers, which aren't const methods. The thing is,
|
|
// none of those mutate "this". So it's OK to cast away const here.
|
|
(const_cast<nsCSSCounterStyleRule*>(this)->*kGetters[id])(tmp);
|
|
aCssText.AppendLiteral(u" ");
|
|
AppendASCIItoUTF16(nsCSSProps::GetStringValue(id), aCssText);
|
|
aCssText.AppendLiteral(u": ");
|
|
aCssText.Append(tmp);
|
|
aCssText.AppendLiteral(u";\n");
|
|
}
|
|
}
|
|
aCssText.AppendLiteral(u"}");
|
|
}
|
|
|
|
void
|
|
nsCSSCounterStyleRule::GetName(nsAString& aName)
|
|
{
|
|
aName.Truncate();
|
|
nsDependentAtomString name(mName);
|
|
nsStyleUtil::AppendEscapedCSSIdent(name, aName);
|
|
}
|
|
|
|
void
|
|
nsCSSCounterStyleRule::SetName(const nsAString& aName)
|
|
{
|
|
RefPtr<nsAtom> name;
|
|
|
|
nsIDocument* doc = GetDocument();
|
|
if (!doc || doc->IsStyledByServo()) {
|
|
name = ServoCSSParser::ParseCounterStyleName(aName);
|
|
} else {
|
|
nsCSSParser parser;
|
|
name = parser.ParseCounterStyleName(aName, nullptr);
|
|
}
|
|
|
|
if (name) {
|
|
MOZ_AUTO_DOC_UPDATE(doc, UPDATE_STYLE, true);
|
|
|
|
mName = name;
|
|
|
|
if (StyleSheet* sheet = GetStyleSheet()) {
|
|
sheet->RuleChanged(this);
|
|
}
|
|
}
|
|
}
|
|
|
|
int32_t
|
|
nsCSSCounterStyleRule::GetSystem() const
|
|
{
|
|
const nsCSSValue& system = GetDesc(eCSSCounterDesc_System);
|
|
switch (system.GetUnit()) {
|
|
case eCSSUnit_Enumerated:
|
|
return system.GetIntValue();
|
|
case eCSSUnit_Pair:
|
|
return system.GetPairValue().mXValue.GetIntValue();
|
|
default:
|
|
return NS_STYLE_COUNTER_SYSTEM_SYMBOLIC;
|
|
}
|
|
}
|
|
|
|
const nsCSSValue&
|
|
nsCSSCounterStyleRule::GetSystemArgument() const
|
|
{
|
|
const nsCSSValue& system = GetDesc(eCSSCounterDesc_System);
|
|
MOZ_ASSERT(system.GetUnit() == eCSSUnit_Pair,
|
|
"Invalid system value");
|
|
return system.GetPairValue().mYValue;
|
|
}
|
|
|
|
void
|
|
nsCSSCounterStyleRule::SetDesc(nsCSSCounterDesc aDescID, const nsCSSValue& aValue)
|
|
{
|
|
MOZ_ASSERT(aDescID >= 0 && aDescID < eCSSCounterDesc_COUNT,
|
|
"descriptor ID out of range");
|
|
|
|
nsIDocument* doc = GetDocument();
|
|
MOZ_AUTO_DOC_UPDATE(doc, UPDATE_STYLE, true);
|
|
|
|
mValues[aDescID] = aValue;
|
|
mGeneration++;
|
|
|
|
if (StyleSheet* sheet = GetStyleSheet()) {
|
|
sheet->RuleChanged(this);
|
|
}
|
|
}
|
|
|
|
void
|
|
nsCSSCounterStyleRule::GetSystem(nsAString& aSystem)
|
|
{
|
|
const nsCSSValue& value = GetDesc(eCSSCounterDesc_System);
|
|
if (value.GetUnit() == eCSSUnit_Null) {
|
|
aSystem.Truncate();
|
|
return;
|
|
}
|
|
|
|
aSystem = NS_ConvertASCIItoUTF16(nsCSSProps::ValueToKeyword(
|
|
GetSystem(), nsCSSProps::kCounterSystemKTable));
|
|
if (value.GetUnit() == eCSSUnit_Pair) {
|
|
aSystem.Append(' ');
|
|
GetSystemArgument().AppendToString(eCSSProperty_UNKNOWN, aSystem);
|
|
}
|
|
}
|
|
|
|
void
|
|
nsCSSCounterStyleRule::GetSymbols(nsAString& aSymbols)
|
|
{
|
|
const nsCSSValue& value = GetDesc(eCSSCounterDesc_Symbols);
|
|
|
|
aSymbols.Truncate();
|
|
if (value.GetUnit() == eCSSUnit_List) {
|
|
for (const nsCSSValueList* item = value.GetListValue();
|
|
item; item = item->mNext) {
|
|
item->mValue.AppendToString(eCSSProperty_UNKNOWN, aSymbols);
|
|
if (item->mNext) {
|
|
aSymbols.Append(' ');
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
nsCSSCounterStyleRule::GetAdditiveSymbols(nsAString& aSymbols)
|
|
{
|
|
const nsCSSValue& value = GetDesc(eCSSCounterDesc_AdditiveSymbols);
|
|
|
|
aSymbols.Truncate();
|
|
if (value.GetUnit() == eCSSUnit_PairList) {
|
|
for (const nsCSSValuePairList* item = value.GetPairListValue();
|
|
item; item = item->mNext) {
|
|
item->mXValue.AppendToString(eCSSProperty_UNKNOWN, aSymbols);
|
|
aSymbols.Append(' ');
|
|
item->mYValue.AppendToString(eCSSProperty_UNKNOWN, aSymbols);
|
|
if (item->mNext) {
|
|
aSymbols.AppendLiteral(", ");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
nsCSSCounterStyleRule::GetRange(nsAString& aRange)
|
|
{
|
|
const nsCSSValue& value = GetDesc(eCSSCounterDesc_Range);
|
|
|
|
switch (value.GetUnit()) {
|
|
case eCSSUnit_Auto:
|
|
aRange.AssignLiteral(u"auto");
|
|
break;
|
|
|
|
case eCSSUnit_PairList:
|
|
aRange.Truncate();
|
|
for (const nsCSSValuePairList* item = value.GetPairListValue();
|
|
item; item = item->mNext) {
|
|
const nsCSSValue& lower = item->mXValue;
|
|
const nsCSSValue& upper = item->mYValue;
|
|
if (lower.GetUnit() == eCSSUnit_Enumerated) {
|
|
NS_ASSERTION(lower.GetIntValue() ==
|
|
NS_STYLE_COUNTER_RANGE_INFINITE,
|
|
"Unrecognized keyword");
|
|
aRange.AppendLiteral("infinite");
|
|
} else {
|
|
aRange.AppendInt(lower.GetIntValue());
|
|
}
|
|
aRange.Append(' ');
|
|
if (upper.GetUnit() == eCSSUnit_Enumerated) {
|
|
NS_ASSERTION(upper.GetIntValue() ==
|
|
NS_STYLE_COUNTER_RANGE_INFINITE,
|
|
"Unrecognized keyword");
|
|
aRange.AppendLiteral("infinite");
|
|
} else {
|
|
aRange.AppendInt(upper.GetIntValue());
|
|
}
|
|
if (item->mNext) {
|
|
aRange.AppendLiteral(", ");
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
aRange.Truncate();
|
|
}
|
|
}
|
|
|
|
void
|
|
nsCSSCounterStyleRule::GetSpeakAs(nsAString& aSpeakAs)
|
|
{
|
|
const nsCSSValue& value = GetDesc(eCSSCounterDesc_SpeakAs);
|
|
|
|
switch (value.GetUnit()) {
|
|
case eCSSUnit_Enumerated:
|
|
switch (value.GetIntValue()) {
|
|
case NS_STYLE_COUNTER_SPEAKAS_BULLETS:
|
|
aSpeakAs.AssignLiteral(u"bullets");
|
|
break;
|
|
case NS_STYLE_COUNTER_SPEAKAS_NUMBERS:
|
|
aSpeakAs.AssignLiteral(u"numbers");
|
|
break;
|
|
case NS_STYLE_COUNTER_SPEAKAS_WORDS:
|
|
aSpeakAs.AssignLiteral(u"words");
|
|
break;
|
|
case NS_STYLE_COUNTER_SPEAKAS_SPELL_OUT:
|
|
aSpeakAs.AssignLiteral(u"spell-out");
|
|
break;
|
|
default:
|
|
NS_NOTREACHED("Unknown speech synthesis");
|
|
}
|
|
break;
|
|
|
|
case eCSSUnit_Auto:
|
|
case eCSSUnit_AtomIdent:
|
|
aSpeakAs.Truncate();
|
|
value.AppendToString(eCSSProperty_UNKNOWN, aSpeakAs);
|
|
break;
|
|
|
|
case eCSSUnit_Null:
|
|
aSpeakAs.Truncate();
|
|
break;
|
|
|
|
default:
|
|
NS_NOTREACHED("Unknown speech synthesis");
|
|
aSpeakAs.Truncate();
|
|
}
|
|
}
|
|
|
|
void
|
|
nsCSSCounterStyleRule::GetDescriptor(nsCSSCounterDesc aDescID,
|
|
nsAString& aValue)
|
|
{
|
|
NS_ASSERTION(aDescID == eCSSCounterDesc_Negative ||
|
|
aDescID == eCSSCounterDesc_Prefix ||
|
|
aDescID == eCSSCounterDesc_Suffix ||
|
|
aDescID == eCSSCounterDesc_Pad ||
|
|
aDescID == eCSSCounterDesc_Fallback,
|
|
"Unexpected descriptor");
|
|
const nsCSSValue& value = GetDesc(aDescID);
|
|
aValue.Truncate();
|
|
if (value.GetUnit() != eCSSUnit_Null) {
|
|
value.AppendToString(eCSSProperty_UNKNOWN, aValue);
|
|
}
|
|
}
|
|
|
|
#define CSS_COUNTER_DESC_GETTER(name_) \
|
|
void \
|
|
nsCSSCounterStyleRule::Get##name_(nsAString& a##name_) \
|
|
{ \
|
|
GetDescriptor(eCSSCounterDesc_##name_, a##name_); \
|
|
}
|
|
CSS_COUNTER_DESC_GETTER(Negative)
|
|
CSS_COUNTER_DESC_GETTER(Prefix)
|
|
CSS_COUNTER_DESC_GETTER(Suffix)
|
|
CSS_COUNTER_DESC_GETTER(Pad)
|
|
CSS_COUNTER_DESC_GETTER(Fallback)
|
|
#undef CSS_COUNTER_DESC_GETTER
|
|
|
|
/* static */ bool
|
|
nsCSSCounterStyleRule::CheckDescValue(int32_t aSystem,
|
|
nsCSSCounterDesc aDescID,
|
|
const nsCSSValue& aValue)
|
|
{
|
|
switch (aDescID) {
|
|
case eCSSCounterDesc_System:
|
|
if (aValue.GetUnit() != eCSSUnit_Pair) {
|
|
return aValue.GetIntValue() == aSystem;
|
|
} else {
|
|
return aValue.GetPairValue().mXValue.GetIntValue() == aSystem;
|
|
}
|
|
|
|
case eCSSCounterDesc_Symbols:
|
|
switch (aSystem) {
|
|
case NS_STYLE_COUNTER_SYSTEM_NUMERIC:
|
|
case NS_STYLE_COUNTER_SYSTEM_ALPHABETIC:
|
|
// for these two system, the list must contain at least 2 elements
|
|
return aValue.GetListValue()->mNext;
|
|
case NS_STYLE_COUNTER_SYSTEM_EXTENDS:
|
|
// for extends system, no symbols should be set
|
|
return false;
|
|
default:
|
|
return true;
|
|
}
|
|
|
|
case eCSSCounterDesc_AdditiveSymbols:
|
|
switch (aSystem) {
|
|
case NS_STYLE_COUNTER_SYSTEM_EXTENDS:
|
|
return false;
|
|
default:
|
|
return true;
|
|
}
|
|
|
|
default:
|
|
return true;
|
|
}
|
|
}
|
|
|
|
void
|
|
nsCSSCounterStyleRule::SetDescriptor(nsCSSCounterDesc aDescID,
|
|
const nsAString& aValue)
|
|
{
|
|
nsCSSValue value;
|
|
bool ok;
|
|
|
|
StyleSheet* sheet = GetStyleSheet();
|
|
|
|
#ifdef MOZ_STYLO
|
|
bool useServo = !sheet || sheet->IsServo();
|
|
#else
|
|
bool useServo = false;
|
|
#endif
|
|
|
|
if (useServo) {
|
|
URLExtraData* data = sheet ? sheet->AsServo()->URLData() : nullptr;
|
|
ok = ServoCSSParser::ParseCounterStyleDescriptor(aDescID, aValue, data,
|
|
value);
|
|
} else {
|
|
nsCSSParser parser;
|
|
nsIURI* baseURL = sheet ? sheet->GetBaseURI() : nullptr;
|
|
nsIPrincipal* principal = sheet ? sheet->Principal() : nullptr;
|
|
ok = parser.ParseCounterDescriptor(aDescID, aValue, nullptr,
|
|
baseURL, principal, value);
|
|
}
|
|
|
|
if (ok && CheckDescValue(GetSystem(), aDescID, value)) {
|
|
SetDesc(aDescID, value);
|
|
}
|
|
}
|
|
|
|
#define CSS_COUNTER_DESC_SETTER(name_) \
|
|
void \
|
|
nsCSSCounterStyleRule::Set##name_(const nsAString& a##name_) \
|
|
{ \
|
|
SetDescriptor(eCSSCounterDesc_##name_, a##name_); \
|
|
}
|
|
CSS_COUNTER_DESC_SETTER(System)
|
|
CSS_COUNTER_DESC_SETTER(Symbols)
|
|
CSS_COUNTER_DESC_SETTER(AdditiveSymbols)
|
|
CSS_COUNTER_DESC_SETTER(Negative)
|
|
CSS_COUNTER_DESC_SETTER(Prefix)
|
|
CSS_COUNTER_DESC_SETTER(Suffix)
|
|
CSS_COUNTER_DESC_SETTER(Range)
|
|
CSS_COUNTER_DESC_SETTER(Pad)
|
|
CSS_COUNTER_DESC_SETTER(Fallback)
|
|
CSS_COUNTER_DESC_SETTER(SpeakAs)
|
|
#undef CSS_COUNTER_DESC_SETTER
|
|
|
|
/* virtual */ size_t
|
|
nsCSSCounterStyleRule::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
|
|
{
|
|
return aMallocSizeOf(this);
|
|
}
|
|
|
|
/* virtual */ JSObject*
|
|
nsCSSCounterStyleRule::WrapObject(JSContext* aCx,
|
|
JS::Handle<JSObject*> aGivenProto)
|
|
{
|
|
return CSSCounterStyleRuleBinding::Wrap(aCx, this, aGivenProto);
|
|
}
|