Bug 1897361 - Share counter-style / list-style-type representation between Servo and Gecko. r=jwatt

It's not clear to me what is going on there or what caused it. I suspect
it might be:

  https://searchfox.org/mozilla-central/rev/1f46481d6c16f27c989e72b898fd1fddce9f445f/servo/components/style/gecko/values.rs#69

Which is the only potential from_raw_parts caller there. But hard to say
without a regression range.

However I've been wanting to get rid of that code for a while, and
this is a good opportunity for that.

The WithCounterStyleNameOrSymbols stuff isn't super pretty, but it has
only two callers, and something more complicated might require further
refactoring.

Differential Revision: https://phabricator.services.mozilla.com/D210814
This commit is contained in:
Emilio Cobos Álvarez 2024-05-19 19:42:38 +00:00
parent be925b90bf
commit f3519ac0d9
25 changed files with 426 additions and 679 deletions

View file

@ -99,7 +99,6 @@ function checkOverridableVirtualCall(entry, location, callee)
"Gecko_AddRefAtom", "Gecko_AddRefAtom",
"Gecko_ReleaseAtom", "Gecko_ReleaseAtom",
/nsPrincipal::Get/, /nsPrincipal::Get/,
/CounterStylePtr::Reset/,
]; ];
if (entry.matches(whitelist)) if (entry.matches(whitelist))
return; return;
@ -149,11 +148,6 @@ function treatAsSafeArgument(entry, varName, csuName)
// Various Servo binding out parameters. This is a mess and there needs // Various Servo binding out parameters. This is a mess and there needs
// to be a way to indicate which params are out parameters, either using // to be a way to indicate which params are out parameters, either using
// an attribute or a naming convention. // an attribute or a naming convention.
["Gecko_SetCounterStyleToName", "aPtr", null],
["Gecko_SetCounterStyleToSymbols", "aPtr", null],
["Gecko_SetCounterStyleToString", "aPtr", null],
["Gecko_CopyCounterStyle", "aDst", null],
["Gecko_SetMozBinding", "aDisplay", null],
[/ClassOrClassList/, /aClass/, null], [/ClassOrClassList/, /aClass/, null],
["Gecko_GetAtomAsUTF16", "aLength", null], ["Gecko_GetAtomAsUTF16", "aLength", null],
["Gecko_CopyMozBindingFrom", "aDest", null], ["Gecko_CopyMozBindingFrom", "aDest", null],
@ -223,8 +217,6 @@ function treatAsSafeArgument(entry, varName, csuName)
["Gecko_ClearAlternateValues", "aFont", null], ["Gecko_ClearAlternateValues", "aFont", null],
["Gecko_AppendAlternateValues", "aFont", null], ["Gecko_AppendAlternateValues", "aFont", null],
["Gecko_CopyAlternateValuesFrom", "aDest", null], ["Gecko_CopyAlternateValuesFrom", "aDest", null],
["Gecko_CounterStyle_GetName", "aResult", null],
["Gecko_CounterStyle_GetSingleString", "aResult", null],
["Gecko_nsTArray_FontFamilyName_AppendNamed", "aNames", null], ["Gecko_nsTArray_FontFamilyName_AppendNamed", "aNames", null],
["Gecko_nsTArray_FontFamilyName_AppendGeneric", "aNames", null], ["Gecko_nsTArray_FontFamilyName_AppendGeneric", "aNames", null],
]; ];
@ -345,12 +337,6 @@ function ignoreCallEdge(entry, callee)
return true; return true;
} }
// This function has an explicit test for being on the main thread if the
// style has non-threadsafe refcounts, but the analysis isn't smart enough
// to understand what the actual styles that can be involved are.
if (/nsStyleList::SetCounterStyle/.test(callee))
return true;
// CachedBorderImageData is exclusively owned by nsStyleImage, but the // CachedBorderImageData is exclusively owned by nsStyleImage, but the
// analysis is not smart enough to know this. // analysis is not smart enough to know this.
if (/CachedBorderImageData::PurgeCachedImages/.test(callee) && if (/CachedBorderImageData::PurgeCachedImages/.test(callee) &&

View file

@ -190,28 +190,39 @@ static bool GetFirstCounterValueForScopeAndFrame(ContainStyleScope* aScope,
void ContainStyleScopeManager::GetSpokenCounterText(nsIFrame* aFrame, void ContainStyleScopeManager::GetSpokenCounterText(nsIFrame* aFrame,
nsAString& aText) { nsAString& aText) {
using Tag = StyleCounterStyle::Tag;
const auto& listStyleType = aFrame->StyleList()->mListStyleType;
switch (listStyleType.tag) {
case Tag::None:
return;
case Tag::String:
listStyleType.AsString().AsAtom()->ToString(aText);
return;
case Tag::Symbols:
case Tag::Name:
break;
}
CounterValue ordinal = 1; CounterValue ordinal = 1;
GetFirstCounterValueForScopeAndFrame(&GetRootScope(), aFrame, ordinal); GetFirstCounterValueForScopeAndFrame(&GetRootScope(), aFrame, ordinal);
CounterStyle* counterStyle = aFrame->PresContext()->CounterStyleManager()->WithCounterStyleNameOrSymbols(
aFrame->PresContext()->CounterStyleManager()->ResolveCounterStyle( listStyleType, [&](CounterStyle* aStyle) {
aFrame->StyleList()->mCounterStyle); nsAutoString text;
nsAutoString text; bool isBullet;
bool isBullet; aStyle->GetSpokenCounterText(ordinal, aFrame->GetWritingMode(), text,
counterStyle->GetSpokenCounterText(ordinal, aFrame->GetWritingMode(), text,
isBullet); isBullet);
if (isBullet) { if (isBullet) {
aText = text; aText = text;
if (!counterStyle->IsNone()) { aText.Append(' ');
aText.Append(' '); } else {
} aStyle->GetPrefix(aText);
} else { aText += text;
counterStyle->GetPrefix(aText); nsAutoString suffix;
aText += text; aStyle->GetSuffix(suffix);
nsAutoString suffix; aText += suffix;
counterStyle->GetSuffix(suffix); }
aText += suffix; });
}
} }
#endif #endif

View file

@ -1584,23 +1584,23 @@ void nsCSSFrameConstructor::CreateGeneratedContent(
case Type::Counter: case Type::Counter:
case Type::Counters: { case Type::Counters: {
RefPtr<nsAtom> name; RefPtr<nsAtom> name;
CounterStylePtr ptr; const StyleCounterStyle* style;
nsString separator; nsString separator;
if (type == Type::Counter) { if (type == Type::Counter) {
auto& counter = aItem.AsCounter(); const auto& counter = aItem.AsCounter();
name = counter._0.AsAtom(); name = counter._0.AsAtom();
ptr = CounterStylePtr::FromStyle(counter._1); style = &counter._1;
} else { } else {
auto& counters = aItem.AsCounters(); const auto& counters = aItem.AsCounters();
name = counters._0.AsAtom(); name = counters._0.AsAtom();
CopyUTF8toUTF16(counters._1.AsString(), separator); CopyUTF8toUTF16(counters._1.AsString(), separator);
ptr = CounterStylePtr::FromStyle(counters._2); style = &counters._2;
} }
auto* counterList = mContainStyleScopeManager.GetOrCreateCounterList( auto* counterList = mContainStyleScopeManager.GetOrCreateCounterList(
aOriginatingElement, name); aOriginatingElement, name);
auto node = MakeUnique<nsCounterUseNode>( auto node = MakeUnique<nsCounterUseNode>(
std::move(ptr), std::move(separator), aContentIndex, *style, std::move(separator), aContentIndex,
/* aAllCounters = */ type == Type::Counters); /* aAllCounters = */ type == Type::Counters);
auto initializer = MakeUnique<nsGenConInitializer>( auto initializer = MakeUnique<nsGenConInitializer>(
@ -1747,8 +1747,6 @@ void nsCSSFrameConstructor::CreateGeneratedContent(
break; break;
} }
} }
return;
} }
void nsCSSFrameConstructor::CreateGeneratedContentFromListStyle( void nsCSSFrameConstructor::CreateGeneratedContentFromListStyle(
@ -1772,37 +1770,41 @@ void nsCSSFrameConstructor::CreateGeneratedContentFromListStyleType(
nsFrameConstructorState& aState, Element& aOriginatingElement, nsFrameConstructorState& aState, Element& aOriginatingElement,
const ComputedStyle& aPseudoStyle, const ComputedStyle& aPseudoStyle,
const FunctionRef<void(nsIContent*)> aAddChild) { const FunctionRef<void(nsIContent*)> aAddChild) {
const nsStyleList* styleList = aPseudoStyle.StyleList(); using Tag = StyleCounterStyle::Tag;
CounterStyle* counterStyle = const auto& styleType = aPseudoStyle.StyleList()->mListStyleType;
mPresShell->GetPresContext()->CounterStyleManager()->ResolveCounterStyle( switch (styleType.tag) {
styleList->mCounterStyle); case Tag::None:
bool needUseNode = false;
switch (counterStyle->GetStyle()) {
case ListStyle::None:
return; return;
case ListStyle::Disc: case Tag::String: {
case ListStyle::Circle: nsDependentAtomString string(styleType.AsString().AsAtom());
case ListStyle::Square: RefPtr<nsIContent> child = CreateGenConTextNode(aState, string, nullptr);
case ListStyle::DisclosureClosed: aAddChild(child);
case ListStyle::DisclosureOpen: return;
}
case Tag::Name:
case Tag::Symbols:
break; break;
default:
const auto* anonStyle = counterStyle->AsAnonymous();
if (!anonStyle || !anonStyle->IsSingleString()) {
needUseNode = true;
}
} }
auto node = MakeUnique<nsCounterUseNode>(nsCounterUseNode::ForLegacyBullet, auto node = MakeUnique<nsCounterUseNode>(nsCounterUseNode::ForLegacyBullet,
styleList->mCounterStyle); styleType);
if (!needUseNode) { if (styleType.IsName()) {
nsAutoString text; nsAtom* name = styleType.AsName().AsAtom();
node->GetText(WritingMode(&aPseudoStyle), counterStyle, text); if (name == nsGkAtoms::disc || name == nsGkAtoms::circle ||
// Note that we're done with 'node' in this case. It's not inserted into name == nsGkAtoms::square || name == nsGkAtoms::disclosure_closed ||
// any list so it's deleted when we return. name == nsGkAtoms::disclosure_open) {
RefPtr<nsIContent> child = CreateGenConTextNode(aState, text, nullptr); // We don't need a use node inserted for these.
aAddChild(child); CounterStyle* counterStyle = mPresShell->GetPresContext()
return; ->CounterStyleManager()
->ResolveCounterStyle(name);
nsAutoString text;
node->GetText(WritingMode(&aPseudoStyle), counterStyle, text);
// Note that we're done with 'node' in this case. It's not inserted into
// any list so it's deleted when we return.
RefPtr<nsIContent> child = CreateGenConTextNode(aState, text, nullptr);
aAddChild(child);
return;
}
} }
auto* counterList = mContainStyleScopeManager.GetOrCreateCounterList( auto* counterList = mContainStyleScopeManager.GetOrCreateCounterList(
@ -3404,18 +3406,18 @@ nsCSSFrameConstructor::FindDataByTag(const Element& aElement,
#define SUPPRESS_FCDATA() FrameConstructionData(nullptr, FCDATA_SUPPRESS_FRAME) #define SUPPRESS_FCDATA() FrameConstructionData(nullptr, FCDATA_SUPPRESS_FRAME)
#define SIMPLE_INT_CREATE(_int, _func) \ #define SIMPLE_INT_CREATE(_int, _func) \
{ int32_t(_int), FrameConstructionData(_func) } {int32_t(_int), FrameConstructionData(_func)}
#define SIMPLE_INT_CHAIN(_int, _func) \ #define SIMPLE_INT_CHAIN(_int, _func) \
{ int32_t(_int), FrameConstructionData(_func) } {int32_t(_int), FrameConstructionData(_func)}
#define COMPLEX_INT_CREATE(_int, _func) \ #define COMPLEX_INT_CREATE(_int, _func) \
{ int32_t(_int), FrameConstructionData(_func) } {int32_t(_int), FrameConstructionData(_func)}
#define SIMPLE_TAG_CREATE(_tag, _func) \ #define SIMPLE_TAG_CREATE(_tag, _func) \
{ nsGkAtoms::_tag, FrameConstructionData(_func) } {nsGkAtoms::_tag, FrameConstructionData(_func)}
#define SIMPLE_TAG_CHAIN(_tag, _func) \ #define SIMPLE_TAG_CHAIN(_tag, _func) \
{ nsGkAtoms::_tag, FrameConstructionData(_func) } {nsGkAtoms::_tag, FrameConstructionData(_func)}
#define COMPLEX_TAG_CREATE(_tag, _func) \ #define COMPLEX_TAG_CREATE(_tag, _func) \
{ nsGkAtoms::_tag, FrameConstructionData(_func) } {nsGkAtoms::_tag, FrameConstructionData(_func)}
static nsFieldSetFrame* GetFieldSetFrameFor(nsIFrame* aFrame) { static nsFieldSetFrame* GetFieldSetFrameFor(nsIFrame* aFrame) {
auto pseudo = aFrame->Style()->GetPseudoType(); auto pseudo = aFrame->Style()->GetPseudoType();
@ -4091,9 +4093,9 @@ nsresult nsCSSFrameConstructor::GetAnonymousContent(
_func, FCDATA_DISALLOW_OUT_OF_FLOW | FCDATA_MAY_NEED_SCROLLFRAME) _func, FCDATA_DISALLOW_OUT_OF_FLOW | FCDATA_MAY_NEED_SCROLLFRAME)
#define SIMPLE_XUL_CREATE(_tag, _func) \ #define SIMPLE_XUL_CREATE(_tag, _func) \
{ nsGkAtoms::_tag, SIMPLE_XUL_FCDATA(_func) } {nsGkAtoms::_tag, SIMPLE_XUL_FCDATA(_func)}
#define SCROLLABLE_XUL_CREATE(_tag, _func) \ #define SCROLLABLE_XUL_CREATE(_tag, _func) \
{ nsGkAtoms::_tag, SCROLLABLE_XUL_FCDATA(_func) } {nsGkAtoms::_tag, SCROLLABLE_XUL_FCDATA(_func)}
/* static */ /* static */
const nsCSSFrameConstructor::FrameConstructionData* const nsCSSFrameConstructor::FrameConstructionData*
@ -4727,7 +4729,7 @@ nsIFrame* nsCSSFrameConstructor::ConstructMarker(
FCDATA_SKIP_ABSPOS_PUSH | \ FCDATA_SKIP_ABSPOS_PUSH | \
FCDATA_DISALLOW_GENERATED_CONTENT) FCDATA_DISALLOW_GENERATED_CONTENT)
#define SIMPLE_SVG_CREATE(_tag, _func) \ #define SIMPLE_SVG_CREATE(_tag, _func) \
{ nsGkAtoms::_tag, SIMPLE_SVG_FCDATA(_func) } {nsGkAtoms::_tag, SIMPLE_SVG_FCDATA(_func)}
/* static */ /* static */
const nsCSSFrameConstructor::FrameConstructionData* const nsCSSFrameConstructor::FrameConstructionData*

View file

@ -80,10 +80,11 @@ void nsCounterChangeNode::Calc(nsCounterList* aList) {
} }
void nsCounterUseNode::GetText(nsString& aResult) { void nsCounterUseNode::GetText(nsString& aResult) {
CounterStyle* style = mPseudoFrame->PresContext()
mPseudoFrame->PresContext()->CounterStyleManager()->ResolveCounterStyle( ->CounterStyleManager()
mCounterStyle); ->WithCounterStyleNameOrSymbols(mCounterStyle, [&](CounterStyle* aStyle) {
GetText(mPseudoFrame->GetWritingMode(), style, aResult); GetText(mPseudoFrame->GetWritingMode(), aStyle, aResult);
});
} }
void nsCounterUseNode::GetText(WritingMode aWM, CounterStyle* aStyle, void nsCounterUseNode::GetText(WritingMode aWM, CounterStyle* aStyle,

View file

@ -94,7 +94,7 @@ struct nsCounterNode : public nsGenConNode {
}; };
struct nsCounterUseNode : public nsCounterNode { struct nsCounterUseNode : public nsCounterNode {
mozilla::CounterStylePtr mCounterStyle; mozilla::StyleCounterStyle mCounterStyle;
nsString mSeparator; nsString mSeparator;
// false for counter(), true for counters() // false for counter(), true for counters()
@ -103,16 +103,18 @@ struct nsCounterUseNode : public nsCounterNode {
bool mForLegacyBullet = false; bool mForLegacyBullet = false;
enum ForLegacyBullet { ForLegacyBullet }; enum ForLegacyBullet { ForLegacyBullet };
nsCounterUseNode(enum ForLegacyBullet, mozilla::CounterStylePtr aCounterStyle) nsCounterUseNode(enum ForLegacyBullet,
const mozilla::StyleCounterStyle& aCounterStyle)
: nsCounterNode(0, USE), : nsCounterNode(0, USE),
mCounterStyle(std::move(aCounterStyle)), mCounterStyle(aCounterStyle),
mForLegacyBullet(true) {} mForLegacyBullet(true) {}
// args go directly to member variables here and of nsGenConNode // args go directly to member variables here and of nsGenConNode
nsCounterUseNode(mozilla::CounterStylePtr aCounterStyle, nsString aSeparator, nsCounterUseNode(const mozilla::StyleCounterStyle& aCounterStyle,
uint32_t aContentIndex, bool aAllCounters) nsString aSeparator, uint32_t aContentIndex,
bool aAllCounters)
: nsCounterNode(aContentIndex, USE), : nsCounterNode(aContentIndex, USE),
mCounterStyle(std::move(aCounterStyle)), mCounterStyle(aCounterStyle),
mSeparator(std::move(aSeparator)), mSeparator(std::move(aSeparator)),
mAllCounters(aAllCounters) { mAllCounters(aAllCounters) {
NS_ASSERTION(aContentIndex <= INT32_MAX, "out of range"); NS_ASSERTION(aContentIndex <= INT32_MAX, "out of range");

View file

@ -70,22 +70,24 @@ static nscoord FontSizeInflationListMarginAdjustment(const nsIFrame* aFrame) {
return 0; return 0;
} }
const auto* list = aFrame->StyleList();
if (!list->mListStyleType.IsNone()) {
return 0;
}
// The HTML spec states that the default padding for ordered lists // The HTML spec states that the default padding for ordered lists
// begins at 40px, indicating that we have 40px of space to place a // begins at 40px, indicating that we have 40px of space to place a
// bullet. When performing font inflation calculations, we add space // bullet. When performing font inflation calculations, we add space
// equivalent to this, but simply inflated at the same amount as the // equivalent to this, but simply inflated at the same amount as the
// text, in app units. // text, in app units.
auto margin = nsPresContext::CSSPixelsToAppUnits(40) * (inflation - 1); auto margin = nsPresContext::CSSPixelsToAppUnits(40) * (inflation - 1);
if (!list->mListStyleType.IsName()) {
auto* list = aFrame->StyleList();
if (!list->mCounterStyle.IsAtom()) {
return margin; return margin;
} }
nsAtom* type = list->mCounterStyle.AsAtom(); nsAtom* type = list->mListStyleType.AsName().AsAtom();
if (type != nsGkAtoms::none && type != nsGkAtoms::disc && if (type != nsGkAtoms::disc && type != nsGkAtoms::circle &&
type != nsGkAtoms::circle && type != nsGkAtoms::square && type != nsGkAtoms::square && type != nsGkAtoms::disclosure_closed &&
type != nsGkAtoms::disclosure_closed &&
type != nsGkAtoms::disclosure_open) { type != nsGkAtoms::disclosure_open) {
return margin; return margin;
} }

View file

@ -7980,7 +7980,7 @@ bool nsBlockFrame::MarkerIsEmpty() const {
nsIFrame* marker = GetMarker(); nsIFrame* marker = GetMarker();
const nsStyleList* list = marker->StyleList(); const nsStyleList* list = marker->StyleList();
return marker->StyleContent()->mContent.IsNone() || return marker->StyleContent()->mContent.IsNone() ||
(list->mCounterStyle.IsNone() && list->mListStyleImage.IsNone() && (list->mListStyleType.IsNone() && list->mListStyleImage.IsNone() &&
marker->StyleContent()->NonAltContentItems().IsEmpty()); marker->StyleContent()->NonAltContentItems().IsEmpty());
} }
@ -8657,13 +8657,11 @@ void nsBlockFrame::VerifyOverflowSituation() {
} }
LineIterator line = flow->LinesBegin(); LineIterator line = flow->LinesBegin();
LineIterator line_end = flow->LinesEnd(); LineIterator line_end = flow->LinesEnd();
for (; line != line_end && line != cursor; ++line) for (; line != line_end && line != cursor; ++line);
;
if (line == line_end && overflowLines) { if (line == line_end && overflowLines) {
line = overflowLines->mLines.begin(); line = overflowLines->mLines.begin();
line_end = overflowLines->mLines.end(); line_end = overflowLines->mLines.end();
for (; line != line_end && line != cursor; ++line) for (; line != line_end && line != cursor; ++line);
;
} }
return line != line_end; return line != line_end;
}; };

View file

@ -47,29 +47,44 @@ struct PadType {
// points outside the BMP will need 2 16-bit units. // points outside the BMP will need 2 16-bit units.
#define LENGTH_LIMIT 150 #define LENGTH_LIMIT 150
static void SymbolToString(const StyleSymbol& aSymbol, nsAString& aResult) {
if (aSymbol.IsIdent()) {
return aSymbol.AsIdent().AsAtom()->ToString(aResult);
}
MOZ_ASSERT(aSymbol.IsString());
return CopyUTF8toUTF16(aSymbol.AsString().AsString(), aResult);
}
static size_t SymbolLength(const StyleSymbol& aSymbol) {
if (aSymbol.IsIdent()) {
return aSymbol.AsIdent().AsAtom()->GetLength();
}
MOZ_ASSERT(aSymbol.IsString());
return aSymbol.AsString().AsString().Length();
}
static bool GetCyclicCounterText(CounterValue aOrdinal, nsAString& aResult, static bool GetCyclicCounterText(CounterValue aOrdinal, nsAString& aResult,
Span<const nsString> aSymbols) { Span<const StyleSymbol> aSymbols) {
MOZ_ASSERT(aSymbols.Length() >= 1, "No symbol available for cyclic counter."); MOZ_ASSERT(aSymbols.Length() >= 1, "No symbol available for cyclic counter.");
auto n = CounterValue(aSymbols.Length()); auto n = CounterValue(aSymbols.Length());
CounterValue index = (aOrdinal - 1) % n; CounterValue index = (aOrdinal - 1) % n;
aResult = aSymbols[index >= 0 ? index : index + n]; SymbolToString(aSymbols[index >= 0 ? index : index + n], aResult);
return true; return true;
} }
static bool GetFixedCounterText(CounterValue aOrdinal, nsAString& aResult, static bool GetFixedCounterText(CounterValue aOrdinal, nsAString& aResult,
CounterValue aStart, CounterValue aStart,
Span<const nsString> aSymbols) { Span<const StyleSymbol> aSymbols) {
CounterValue index = aOrdinal - aStart; CounterValue index = aOrdinal - aStart;
if (index >= 0 && index < CounterValue(aSymbols.Length())) { if (index >= 0 && index < CounterValue(aSymbols.Length())) {
aResult = aSymbols[index]; SymbolToString(aSymbols[index], aResult);
return true; return true;
} else {
return false;
} }
return false;
} }
static bool GetSymbolicCounterText(CounterValue aOrdinal, nsAString& aResult, static bool GetSymbolicCounterText(CounterValue aOrdinal, nsAString& aResult,
Span<const nsString> aSymbols) { Span<const StyleSymbol> aSymbols) {
MOZ_ASSERT(aSymbols.Length() >= 1, MOZ_ASSERT(aSymbols.Length() >= 1,
"No symbol available for symbolic counter."); "No symbol available for symbolic counter.");
MOZ_ASSERT(aOrdinal >= 0, "Invalid ordinal."); MOZ_ASSERT(aOrdinal >= 0, "Invalid ordinal.");
@ -79,23 +94,25 @@ static bool GetSymbolicCounterText(CounterValue aOrdinal, nsAString& aResult,
aResult.Truncate(); aResult.Truncate();
auto n = aSymbols.Length(); auto n = aSymbols.Length();
const nsString& symbol = aSymbols[(aOrdinal - 1) % n]; const StyleSymbol& symbol = aSymbols[(aOrdinal - 1) % n];
size_t len = (aOrdinal + n - 1) / n; size_t len = (aOrdinal + n - 1) / n;
auto symbolLength = symbol.Length(); auto symbolLength = SymbolLength(symbol);
if (symbolLength > 0) { if (symbolLength > 0) {
if (len > LENGTH_LIMIT || symbolLength > LENGTH_LIMIT || if (len > LENGTH_LIMIT || symbolLength > LENGTH_LIMIT ||
len * symbolLength > LENGTH_LIMIT) { len * symbolLength > LENGTH_LIMIT) {
return false; return false;
} }
nsAutoString str;
SymbolToString(symbol, str);
for (size_t i = 0; i < len; ++i) { for (size_t i = 0; i < len; ++i) {
aResult.Append(symbol); aResult.Append(str);
} }
} }
return true; return true;
} }
static bool GetAlphabeticCounterText(CounterValue aOrdinal, nsAString& aResult, static bool GetAlphabeticCounterText(CounterValue aOrdinal, nsAString& aResult,
Span<const nsString> aSymbols) { Span<const StyleSymbol> aSymbols) {
MOZ_ASSERT(aSymbols.Length() >= 2, "Too few symbols for alphabetic counter."); MOZ_ASSERT(aSymbols.Length() >= 2, "Too few symbols for alphabetic counter.");
MOZ_ASSERT(aOrdinal >= 0, "Invalid ordinal."); MOZ_ASSERT(aOrdinal >= 0, "Invalid ordinal.");
if (aOrdinal == 0) { if (aOrdinal == 0) {
@ -115,18 +132,23 @@ static bool GetAlphabeticCounterText(CounterValue aOrdinal, nsAString& aResult,
aResult.Truncate(); aResult.Truncate();
for (auto i = indexes.Length(); i > 0; --i) { for (auto i = indexes.Length(); i > 0; --i) {
aResult.Append(aSymbols[indexes[i - 1]]); const auto& symbol = aSymbols[indexes[i - 1]];
if (symbol.IsIdent()) {
aResult.Append(nsDependentAtomString(symbol.AsIdent().AsAtom()));
} else {
AppendUTF8toUTF16(symbol.AsString().AsString(), aResult);
}
} }
return true; return true;
} }
static bool GetNumericCounterText(CounterValue aOrdinal, nsAString& aResult, static bool GetNumericCounterText(CounterValue aOrdinal, nsAString& aResult,
Span<const nsString> aSymbols) { Span<const StyleSymbol> aSymbols) {
MOZ_ASSERT(aSymbols.Length() >= 2, "Too few symbols for numeric counter."); MOZ_ASSERT(aSymbols.Length() >= 2, "Too few symbols for numeric counter.");
MOZ_ASSERT(aOrdinal >= 0, "Invalid ordinal."); MOZ_ASSERT(aOrdinal >= 0, "Invalid ordinal.");
if (aOrdinal == 0) { if (aOrdinal == 0) {
aResult = aSymbols[0]; SymbolToString(aSymbols[0], aResult);
return true; return true;
} }
@ -139,7 +161,12 @@ static bool GetNumericCounterText(CounterValue aOrdinal, nsAString& aResult,
aResult.Truncate(); aResult.Truncate();
for (auto i = indexes.Length(); i > 0; --i) { for (auto i = indexes.Length(); i > 0; --i) {
aResult.Append(aSymbols[indexes[i - 1]]); const auto& symbol = aSymbols[indexes[i - 1]];
if (symbol.IsIdent()) {
aResult.Append(nsDependentAtomString(symbol.AsIdent().AsAtom()));
} else {
AppendUTF8toUTF16(symbol.AsString().AsString(), aResult);
}
} }
return true; return true;
} }
@ -373,7 +400,7 @@ static bool HebrewToText(CounterValue aOrdinal, nsAString& aResult) {
} else { } else {
n1 -= 100; n1 -= 100;
} // if } // if
} // for } // for
// Process digit for 10 - 90 // Process digit for 10 - 90
int32_t n2; int32_t n2;
@ -515,25 +542,22 @@ class BuiltinCounterStyle : public CounterStyle {
nsStaticAtom* GetStyleName() const { return mName; } nsStaticAtom* GetStyleName() const { return mName; }
virtual void GetPrefix(nsAString& aResult) override; void GetPrefix(nsAString& aResult) override;
virtual void GetSuffix(nsAString& aResult) override; void GetSuffix(nsAString& aResult) override;
virtual void GetSpokenCounterText(CounterValue aOrdinal, void GetSpokenCounterText(CounterValue aOrdinal, WritingMode aWritingMode,
WritingMode aWritingMode, nsAString& aResult, bool& aIsBullet) override;
nsAString& aResult, bool IsBullet() override;
bool& aIsBullet) override;
virtual bool IsBullet() override;
virtual void GetNegative(NegativeType& aResult) override; void GetNegative(NegativeType& aResult) override;
virtual bool IsOrdinalInRange(CounterValue aOrdinal) override; bool IsOrdinalInRange(CounterValue aOrdinal) override;
virtual bool IsOrdinalInAutoRange(CounterValue aOrdinal) override; bool IsOrdinalInAutoRange(CounterValue aOrdinal) override;
virtual void GetPad(PadType& aResult) override; void GetPad(PadType& aResult) override;
virtual CounterStyle* GetFallback() override; CounterStyle* GetFallback() override;
virtual SpeakAs GetSpeakAs() override; SpeakAs GetSpeakAs() override;
virtual bool UseNegativeSign() override; bool UseNegativeSign() override;
virtual bool GetInitialCounterText(CounterValue aOrdinal, bool GetInitialCounterText(CounterValue aOrdinal, WritingMode aWritingMode,
WritingMode aWritingMode, nsAString& aResult, bool& aIsRTL) override;
nsAString& aResult, bool& aIsRTL) override;
protected: protected:
constexpr BuiltinCounterStyle(const BuiltinCounterStyle& aOther) constexpr BuiltinCounterStyle(const BuiltinCounterStyle& aOther)
@ -953,28 +977,24 @@ class CustomCounterStyle final : public CounterStyle {
const StyleLockedCounterStyleRule* GetRule() const { return mRule; } const StyleLockedCounterStyleRule* GetRule() const { return mRule; }
uint32_t GetRuleGeneration() const { return mRuleGeneration; } uint32_t GetRuleGeneration() const { return mRuleGeneration; }
virtual void GetPrefix(nsAString& aResult) override; void GetPrefix(nsAString& aResult) override;
virtual void GetSuffix(nsAString& aResult) override; void GetSuffix(nsAString& aResult) override;
virtual void GetSpokenCounterText(CounterValue aOrdinal, void GetSpokenCounterText(CounterValue aOrdinal, WritingMode aWritingMode,
WritingMode aWritingMode, nsAString& aResult, bool& aIsBullet) override;
nsAString& aResult, bool IsBullet() override;
bool& aIsBullet) override;
virtual bool IsBullet() override;
virtual void GetNegative(NegativeType& aResult) override; void GetNegative(NegativeType& aResult) override;
virtual bool IsOrdinalInRange(CounterValue aOrdinal) override; bool IsOrdinalInRange(CounterValue aOrdinal) override;
virtual bool IsOrdinalInAutoRange(CounterValue aOrdinal) override; bool IsOrdinalInAutoRange(CounterValue aOrdinal) override;
virtual void GetPad(PadType& aResult) override; void GetPad(PadType& aResult) override;
virtual CounterStyle* GetFallback() override; CounterStyle* GetFallback() override;
virtual SpeakAs GetSpeakAs() override; SpeakAs GetSpeakAs() override;
virtual bool UseNegativeSign() override; bool UseNegativeSign() override;
virtual void CallFallbackStyle(CounterValue aOrdinal, void CallFallbackStyle(CounterValue aOrdinal, WritingMode aWritingMode,
WritingMode aWritingMode, nsAString& aResult, nsAString& aResult, bool& aIsRTL) override;
bool& aIsRTL) override; bool GetInitialCounterText(CounterValue aOrdinal, WritingMode aWritingMode,
virtual bool GetInitialCounterText(CounterValue aOrdinal, nsAString& aResult, bool& aIsRTL) override;
WritingMode aWritingMode,
nsAString& aResult, bool& aIsRTL) override;
bool IsExtendsSystem() { return mSystem == StyleCounterSystem::Extends; } bool IsExtendsSystem() { return mSystem == StyleCounterSystem::Extends; }
@ -992,7 +1012,7 @@ class CustomCounterStyle final : public CounterStyle {
private: private:
~CustomCounterStyle() = default; ~CustomCounterStyle() = default;
Span<const nsString> GetSymbols(); Span<const StyleSymbol> GetSymbols();
Span<const AdditiveSymbol> GetAdditiveSymbols(); Span<const AdditiveSymbol> GetAdditiveSymbols();
// The speak-as values of counter styles may form a loop, and the // The speak-as values of counter styles may form a loop, and the
@ -1039,7 +1059,6 @@ class CustomCounterStyle final : public CounterStyle {
uint16_t mFlags; uint16_t mFlags;
// Fields below will be initialized when necessary. // Fields below will be initialized when necessary.
StyleOwnedSlice<nsString> mSymbols;
StyleOwnedSlice<AdditiveSymbol> mAdditiveSymbols; StyleOwnedSlice<AdditiveSymbol> mAdditiveSymbols;
NegativeType mNegative; NegativeType mNegative;
nsString mPrefix, mSuffix; nsString mPrefix, mSuffix;
@ -1068,7 +1087,6 @@ class CustomCounterStyle final : public CounterStyle {
}; };
void CustomCounterStyle::ResetCachedData() { void CustomCounterStyle::ResetCachedData() {
mSymbols.Clear();
mAdditiveSymbols.Clear(); mAdditiveSymbols.Clear();
mFlags &= ~(FLAG_NEGATIVE_INITED | FLAG_PREFIX_INITED | FLAG_SUFFIX_INITED | mFlags &= ~(FLAG_NEGATIVE_INITED | FLAG_PREFIX_INITED | FLAG_SUFFIX_INITED |
FLAG_PAD_INITED | FLAG_SPEAKAS_INITED); FLAG_PAD_INITED | FLAG_SPEAKAS_INITED);
@ -1296,11 +1314,10 @@ bool CustomCounterStyle::GetInitialCounterText(CounterValue aOrdinal,
} }
} }
Span<const nsString> CustomCounterStyle::GetSymbols() { Span<const StyleSymbol> CustomCounterStyle::GetSymbols() {
if (mSymbols.IsEmpty()) { size_t count = 0;
Servo_CounterStyleRule_GetSymbols(mRule, &mSymbols); const StyleSymbol* ptr = Servo_CounterStyleRule_GetSymbols(mRule, &count);
} return Span(ptr, count);
return mSymbols.AsSpan();
} }
Span<const AdditiveSymbol> CustomCounterStyle::GetAdditiveSymbols() { Span<const AdditiveSymbol> CustomCounterStyle::GetAdditiveSymbols() {
@ -1504,20 +1521,11 @@ CounterStyle* CustomCounterStyle::GetExtendsRoot() {
return mExtendsRoot; return mExtendsRoot;
} }
AnonymousCounterStyle::AnonymousCounterStyle(const nsAString& aContent)
: CounterStyle(ListStyle::Custom),
mSingleString(true),
mSymbolsType(StyleSymbolsType::Cyclic) {
mSymbols.SetCapacity(1);
mSymbols.AppendElement(aContent);
}
AnonymousCounterStyle::AnonymousCounterStyle(StyleSymbolsType aType, AnonymousCounterStyle::AnonymousCounterStyle(StyleSymbolsType aType,
nsTArray<nsString> aSymbols) Span<const StyleSymbol> aSymbols)
: CounterStyle(ListStyle::Custom), : CounterStyle(ListStyle::Custom),
mSingleString(false),
mSymbolsType(aType), mSymbolsType(aType),
mSymbols(std::move(aSymbols)) {} mSymbols(aSymbols) {}
/* virtual */ /* virtual */
void AnonymousCounterStyle::GetPrefix(nsAString& aResult) { void AnonymousCounterStyle::GetPrefix(nsAString& aResult) {
@ -1525,13 +1533,7 @@ void AnonymousCounterStyle::GetPrefix(nsAString& aResult) {
} }
/* virtual */ /* virtual */
void AnonymousCounterStyle::GetSuffix(nsAString& aResult) { void AnonymousCounterStyle::GetSuffix(nsAString& aResult) { aResult = ' '; }
if (IsSingleString()) {
aResult.Truncate();
} else {
aResult = ' ';
}
}
/* virtual */ /* virtual */
bool AnonymousCounterStyle::IsBullet() { bool AnonymousCounterStyle::IsBullet() {

View file

@ -97,195 +97,36 @@ class CounterStyle {
const ListStyle mStyle; const ListStyle mStyle;
}; };
class AnonymousCounterStyle final : public CounterStyle { class MOZ_STACK_CLASS AnonymousCounterStyle final : public CounterStyle {
public: public:
explicit AnonymousCounterStyle(const nsAString& aContent); explicit AnonymousCounterStyle(const nsAString& aContent);
AnonymousCounterStyle(StyleSymbolsType, nsTArray<nsString> aSymbols); AnonymousCounterStyle(StyleSymbolsType, Span<const StyleSymbol> aSymbols);
virtual void GetPrefix(nsAString& aResult) override; void GetPrefix(nsAString& aResult) override;
virtual void GetSuffix(nsAString& aResult) override; void GetSuffix(nsAString& aResult) override;
virtual bool IsBullet() override; bool IsBullet() override;
virtual void GetNegative(NegativeType& aResult) override; void GetNegative(NegativeType& aResult) override;
virtual bool IsOrdinalInRange(CounterValue aOrdinal) override; bool IsOrdinalInRange(CounterValue aOrdinal) override;
virtual bool IsOrdinalInAutoRange(CounterValue aOrdinal) override; bool IsOrdinalInAutoRange(CounterValue aOrdinal) override;
virtual void GetPad(PadType& aResult) override; void GetPad(PadType& aResult) override;
virtual CounterStyle* GetFallback() override; CounterStyle* GetFallback() override;
virtual SpeakAs GetSpeakAs() override; SpeakAs GetSpeakAs() override;
virtual bool UseNegativeSign() override; bool UseNegativeSign() override;
virtual bool GetInitialCounterText(CounterValue aOrdinal, bool GetInitialCounterText(CounterValue aOrdinal, WritingMode aWritingMode,
WritingMode aWritingMode, nsAString& aResult, bool& aIsRTL) override;
nsAString& aResult, bool& aIsRTL) override;
virtual AnonymousCounterStyle* AsAnonymous() override { return this; } AnonymousCounterStyle* AsAnonymous() override { return this; }
bool IsSingleString() const { return mSingleString; } auto GetSymbols() const { return mSymbols; }
auto GetSymbols() const { return Span<const nsString>{mSymbols}; }
StyleCounterSystem GetSystem() const; StyleCounterSystem GetSystem() const;
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AnonymousCounterStyle)
private:
~AnonymousCounterStyle() = default; ~AnonymousCounterStyle() = default;
bool mSingleString;
StyleSymbolsType mSymbolsType; StyleSymbolsType mSymbolsType;
nsTArray<nsString> mSymbols; Span<const StyleSymbol> mSymbols;
};
// A smart pointer to CounterStyle. It either owns a reference to an
// anonymous counter style, or weakly refers to a named counter style
// managed by counter style manager.
class CounterStylePtr {
public:
CounterStylePtr() : mRaw(0) {}
CounterStylePtr(const CounterStylePtr& aOther) : mRaw(aOther.mRaw) {
if (!mRaw) {
return;
}
switch (GetType()) {
case eAnonymousCounterStyle:
AsAnonymous()->AddRef();
break;
case eAtom:
AsAtom()->AddRef();
break;
default:
MOZ_ASSERT_UNREACHABLE("Unknown type");
break;
}
}
CounterStylePtr(CounterStylePtr&& aOther) : mRaw(aOther.mRaw) {
aOther.mRaw = 0;
}
~CounterStylePtr() { Reset(); }
CounterStylePtr& operator=(const CounterStylePtr& aOther) {
if (this != &aOther) {
Reset();
new (this) CounterStylePtr(aOther);
}
return *this;
}
CounterStylePtr& operator=(CounterStylePtr&& aOther) {
if (this != &aOther) {
Reset();
mRaw = aOther.mRaw;
aOther.mRaw = 0;
}
return *this;
}
CounterStylePtr& operator=(decltype(nullptr)) {
Reset();
return *this;
}
CounterStylePtr& operator=(nsStaticAtom* aStaticAtom) {
Reset();
mRaw = reinterpret_cast<uintptr_t>(aStaticAtom) | eAtom;
return *this;
}
CounterStylePtr& operator=(already_AddRefed<nsAtom> aAtom) {
Reset();
mRaw = reinterpret_cast<uintptr_t>(aAtom.take()) | eAtom;
return *this;
}
CounterStylePtr& operator=(AnonymousCounterStyle* aCounterStyle) {
Reset();
if (aCounterStyle) {
CounterStyle* raw = do_AddRef(aCounterStyle).take();
mRaw = reinterpret_cast<uintptr_t>(raw) | eAnonymousCounterStyle;
}
return *this;
}
// TODO(emilio): Make CounterStyle have a single representation, either by
// removing CounterStylePtr or by moving this representation to Rust.
static CounterStylePtr FromStyle(const StyleCounterStyle& aStyle) {
CounterStylePtr ret;
if (aStyle.IsName()) {
ret = do_AddRef(aStyle.AsName().AsAtom());
} else {
StyleSymbolsType type = aStyle.AsSymbols()._0;
Span<const StyleSymbol> symbols = aStyle.AsSymbols()._1._0.AsSpan();
nsTArray<nsString> transcoded(symbols.Length());
for (const auto& symbol : symbols) {
MOZ_ASSERT(symbol.IsString(), "Should not have <ident> in symbols()");
transcoded.AppendElement(
NS_ConvertUTF8toUTF16(symbol.AsString().AsString()));
}
ret = new AnonymousCounterStyle(type, std::move(transcoded));
}
return ret;
}
explicit operator bool() const { return !!mRaw; }
bool operator!() const { return !mRaw; }
bool operator==(const CounterStylePtr& aOther) const {
// FIXME(emilio): For atoms this is all right, but for symbols doesn't this
// cause us to compare as unequal all the time, even if the specified
// symbols didn't change?
return mRaw == aOther.mRaw;
}
bool operator!=(const CounterStylePtr& aOther) const {
return mRaw != aOther.mRaw;
}
nsAtom* AsAtom() const {
MOZ_ASSERT(IsAtom());
return reinterpret_cast<nsAtom*>(mRaw & ~eMask);
}
AnonymousCounterStyle* AsAnonymous() const {
MOZ_ASSERT(IsAnonymous());
return static_cast<AnonymousCounterStyle*>(
reinterpret_cast<CounterStyle*>(mRaw & ~eMask));
}
bool IsAtom() const { return GetType() == eAtom; }
bool IsAnonymous() const { return GetType() == eAnonymousCounterStyle; }
bool IsNone() const { return IsAtom() && AsAtom() == nsGkAtoms::none; }
private:
enum Type : uintptr_t {
eAnonymousCounterStyle = 0,
eAtom = 1,
eMask = 1,
};
static_assert(alignof(CounterStyle) >= 1 << eMask,
"We're gonna tag the pointer, so it better fit");
static_assert(alignof(nsAtom) >= 1 << eMask,
"We're gonna tag the pointer, so it better fit");
Type GetType() const { return static_cast<Type>(mRaw & eMask); }
void Reset() {
if (!mRaw) {
return;
}
switch (GetType()) {
case eAnonymousCounterStyle:
AsAnonymous()->Release();
break;
case eAtom:
AsAtom()->Release();
break;
default:
MOZ_ASSERT_UNREACHABLE("Unknown type");
break;
}
mRaw = 0;
}
// mRaw contains the pointer, and its last bit is used to store the type of
// the pointer.
// If the type is eAtom, the pointer owns a reference to an nsAtom
// (potentially null).
// If the type is eAnonymousCounterStyle, it owns a reference to an
// anonymous counter style (never null).
uintptr_t mRaw;
}; };
class CounterStyleManager final { class CounterStyleManager final {
@ -310,11 +151,23 @@ class CounterStyleManager final {
// Same as GetCounterStyle but try to build the counter style object // Same as GetCounterStyle but try to build the counter style object
// rather than returning nullptr if that hasn't been built. // rather than returning nullptr if that hasn't been built.
CounterStyle* ResolveCounterStyle(nsAtom* aName); CounterStyle* ResolveCounterStyle(nsAtom* aName);
CounterStyle* ResolveCounterStyle(const CounterStylePtr& aPtr) { template <typename F>
if (aPtr.IsAtom()) { void WithCounterStyleNameOrSymbols(const StyleCounterStyle& aStyle,
return ResolveCounterStyle(aPtr.AsAtom()); F&& aCallback) {
using Tag = StyleCounterStyle::Tag;
switch (aStyle.tag) {
case Tag::None:
case Tag::String:
MOZ_CRASH("Unexpected counter style");
case Tag::Symbols: {
AnonymousCounterStyle s(aStyle.AsSymbols().ty,
aStyle.AsSymbols().symbols._0.AsSpan());
return aCallback(&s);
}
case Tag::Name: {
return aCallback(ResolveCounterStyle(aStyle.AsName().AsAtom()));
}
} }
return aPtr.AsAnonymous();
} }
static CounterStyle* GetBuiltinStyle(ListStyle aStyle); static CounterStyle* GetBuiltinStyle(ListStyle aStyle);

View file

@ -960,34 +960,6 @@ void Gecko_SetFontPaletteOverride(
uint32_t(aIndex), gfx::sRGBColor::FromABGR(aColor->ToColor())}); uint32_t(aIndex), gfx::sRGBColor::FromABGR(aColor->ToColor())});
} }
void Gecko_CounterStyle_ToPtr(const StyleCounterStyle* aStyle,
CounterStylePtr* aPtr) {
*aPtr = CounterStylePtr::FromStyle(*aStyle);
}
void Gecko_SetCounterStyleToNone(CounterStylePtr* aPtr) {
*aPtr = nsGkAtoms::none;
}
void Gecko_SetCounterStyleToString(CounterStylePtr* aPtr,
const nsACString* aSymbol) {
*aPtr = new AnonymousCounterStyle(NS_ConvertUTF8toUTF16(*aSymbol));
}
void Gecko_CopyCounterStyle(CounterStylePtr* aDst,
const CounterStylePtr* aSrc) {
*aDst = *aSrc;
}
nsAtom* Gecko_CounterStyle_GetName(const CounterStylePtr* aPtr) {
return aPtr->IsAtom() ? aPtr->AsAtom() : nullptr;
}
const AnonymousCounterStyle* Gecko_CounterStyle_GetAnonymous(
const CounterStylePtr* aPtr) {
return aPtr->AsAnonymous();
}
void Gecko_EnsureImageLayersLength(nsStyleImageLayers* aLayers, size_t aLen, void Gecko_EnsureImageLayersLength(nsStyleImageLayers* aLayers, size_t aLen,
nsStyleImageLayers::LayerType aLayerType) { nsStyleImageLayers::LayerType aLayerType) {
size_t oldLength = aLayers->mLayers.Length(); size_t oldLength = aLayers->mLayers.Length();

View file

@ -315,23 +315,6 @@ void Gecko_SetImageOrientationAsFromImage(nsStyleVisibility* aVisibility);
void Gecko_CopyImageOrientationFrom(nsStyleVisibility* aDst, void Gecko_CopyImageOrientationFrom(nsStyleVisibility* aDst,
const nsStyleVisibility* aSrc); const nsStyleVisibility* aSrc);
// Counter style.
void Gecko_CounterStyle_ToPtr(const mozilla::StyleCounterStyle*,
mozilla::CounterStylePtr*);
void Gecko_SetCounterStyleToNone(mozilla::CounterStylePtr*);
void Gecko_SetCounterStyleToString(mozilla::CounterStylePtr* ptr,
const nsACString* symbol);
void Gecko_CopyCounterStyle(mozilla::CounterStylePtr* dst,
const mozilla::CounterStylePtr* src);
nsAtom* Gecko_CounterStyle_GetName(const mozilla::CounterStylePtr* ptr);
const mozilla::AnonymousCounterStyle* Gecko_CounterStyle_GetAnonymous(
const mozilla::CounterStylePtr* ptr);
// list-style-image style. // list-style-image style.
void Gecko_SetListStyleImageNone(nsStyleList* style_struct); void Gecko_SetListStyleImageNone(nsStyleList* style_struct);

View file

@ -206,7 +206,6 @@ allowlist-types = [
"mozilla::DeclarationBlockMutationClosure", "mozilla::DeclarationBlockMutationClosure",
"mozilla::AnimatedPropertyID", "mozilla::AnimatedPropertyID",
"mozilla::AnimationPropertySegment", "mozilla::AnimationPropertySegment",
"mozilla::AnonymousCounterStyle",
"mozilla::AtomArray", "mozilla::AtomArray",
"mozilla::ComputedTiming", "mozilla::ComputedTiming",
"mozilla::Matrix4x4Components", "mozilla::Matrix4x4Components",
@ -566,8 +565,8 @@ cbindgen-types = [
{ gecko = "StyleCounterSet", servo = "crate::values::computed::CounterSet" }, { gecko = "StyleCounterSet", servo = "crate::values::computed::CounterSet" },
{ gecko = "StyleCounterIncrement", servo = "crate::values::computed::CounterIncrement" }, { gecko = "StyleCounterIncrement", servo = "crate::values::computed::CounterIncrement" },
{ gecko = "StyleContent", servo = "crate::values::computed::counters::Content" }, { gecko = "StyleContent", servo = "crate::values::computed::counters::Content" },
{ gecko = "StyleSymbolsType", servo = "crate::values::generics::SymbolsType" }, { gecko = "StyleSymbolsType", servo = "crate::counter_style::SymbolsType" },
{ gecko = "StyleCounterStyle", servo = "crate::values::generics::CounterStyle" }, { gecko = "StyleCounterStyle", servo = "crate::counter_style::CounterStyle" },
{ gecko = "StyleComputedJustifyItems", servo = "crate::values::computed::align::ComputedJustifyItems" }, { gecko = "StyleComputedJustifyItems", servo = "crate::values::computed::align::ComputedJustifyItems" },
{ gecko = "StyleAlignItems", servo = "crate::values::computed::AlignItems" }, { gecko = "StyleAlignItems", servo = "crate::values::computed::AlignItems" },
{ gecko = "StyleJustifySelf", servo = "crate::values::computed::JustifySelf" }, { gecko = "StyleJustifySelf", servo = "crate::values::computed::JustifySelf" },
@ -619,6 +618,7 @@ cbindgen-types = [
{ gecko = "StyleLockedImportRule", servo = "crate::gecko::arc_types::LockedImportRule" }, { gecko = "StyleLockedImportRule", servo = "crate::gecko::arc_types::LockedImportRule" },
{ gecko = "StyleLockedFontFaceRule", servo = "crate::gecko::arc_types::LockedFontFaceRule" }, { gecko = "StyleLockedFontFaceRule", servo = "crate::gecko::arc_types::LockedFontFaceRule" },
{ gecko = "StyleBaselineSource", servo = "crate::values::computed::BaselineSource" }, { gecko = "StyleBaselineSource", servo = "crate::values::computed::BaselineSource" },
{ gecko = "StyleListStyleType", servo = "crate::values::computed::ListStyleType" },
{ gecko = "StyleAu", servo = "app_units::Au" }, { gecko = "StyleAu", servo = "app_units::Au" },
{ gecko = "StyleAnchorName", servo = "crate::values::computed::position::AnchorName" }, { gecko = "StyleAnchorName", servo = "crate::values::computed::position::AnchorName" },
{ gecko = "StyleAnchorScope", servo = "crate::values::computed::position::AnchorScope" }, { gecko = "StyleAnchorScope", servo = "crate::values::computed::position::AnchorScope" },

View file

@ -750,7 +750,7 @@ bool ServoStyleSet::GeneratedContentPseudoExists(
} }
// ::marker only exist if we have 'content' or at least one of // ::marker only exist if we have 'content' or at least one of
// 'list-style-type' or 'list-style-image'. // 'list-style-type' or 'list-style-image'.
if (aPseudoStyle.StyleList()->mCounterStyle.IsNone() && if (aPseudoStyle.StyleList()->mListStyleType.IsNone() &&
aPseudoStyle.StyleList()->mListStyleImage.IsNone() && aPseudoStyle.StyleList()->mListStyleImage.IsNone() &&
content.IsNormal()) { content.IsNormal()) {
return false; return false;

View file

@ -605,17 +605,16 @@ nsSize nsStyleOutline::EffectiveOffsetFor(const nsRect& aRect) const {
// //
nsStyleList::nsStyleList() nsStyleList::nsStyleList()
: mListStylePosition(StyleListStylePosition::Outside), : mListStylePosition(StyleListStylePosition::Outside),
mListStyleType(StyleCounterStyle::Name({StyleAtom(nsGkAtoms::disc)})),
mQuotes(StyleQuotes::Auto()), mQuotes(StyleQuotes::Auto()),
mListStyleImage(StyleImage::None()) { mListStyleImage(StyleImage::None()) {
MOZ_COUNT_CTOR(nsStyleList); MOZ_COUNT_CTOR(nsStyleList);
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
mCounterStyle = nsGkAtoms::disc;
} }
nsStyleList::nsStyleList(const nsStyleList& aSource) nsStyleList::nsStyleList(const nsStyleList& aSource)
: mListStylePosition(aSource.mListStylePosition), : mListStylePosition(aSource.mListStylePosition),
mCounterStyle(aSource.mCounterStyle), mListStyleType(aSource.mListStyleType),
mQuotes(aSource.mQuotes), mQuotes(aSource.mQuotes),
mListStyleImage(aSource.mListStyleImage) { mListStyleImage(aSource.mListStyleImage) {
MOZ_COUNT_CTOR(nsStyleList); MOZ_COUNT_CTOR(nsStyleList);
@ -641,7 +640,7 @@ nsChangeHint nsStyleList::CalcDifference(const nsStyleList& aNewData,
// value changes from something else to list-item, that change itself would // value changes from something else to list-item, that change itself would
// cause ReconstructFrame. // cause ReconstructFrame.
if (mListStylePosition != aNewData.mListStylePosition || if (mListStylePosition != aNewData.mListStylePosition ||
mCounterStyle != aNewData.mCounterStyle || mListStyleType != aNewData.mListStyleType ||
mListStyleImage != aNewData.mListStyleImage) { mListStyleImage != aNewData.mListStyleImage) {
if (aOldStyle.StyleDisplay()->IsListItem()) { if (aOldStyle.StyleDisplay()->IsListItem()) {
return nsChangeHint_ReconstructFrame; return nsChangeHint_ReconstructFrame;

View file

@ -642,7 +642,7 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleList {
mozilla::StyleListStylePosition mListStylePosition; mozilla::StyleListStylePosition mListStylePosition;
mozilla::CounterStylePtr mCounterStyle; mozilla::StyleListStyleType mListStyleType;
mozilla::StyleQuotes mQuotes; mozilla::StyleQuotes mQuotes;
mozilla::StyleImage mListStyleImage; mozilla::StyleImage mListStyleImage;
}; };

View file

@ -11,7 +11,7 @@ use crate::parser::{Parse, ParserContext};
use crate::shared_lock::{SharedRwLockReadGuard, ToCssWithGuard}; use crate::shared_lock::{SharedRwLockReadGuard, ToCssWithGuard};
use crate::str::CssStringWriter; use crate::str::CssStringWriter;
use crate::values::specified::Integer; use crate::values::specified::Integer;
use crate::values::CustomIdent; use crate::values::{AtomString, CustomIdent};
use crate::Atom; use crate::Atom;
use cssparser::{ use cssparser::{
AtRuleParser, DeclarationParser, QualifiedRuleParser, RuleBodyItemParser, RuleBodyParser, AtRuleParser, DeclarationParser, QualifiedRuleParser, RuleBodyItemParser, RuleBodyParser,
@ -21,14 +21,174 @@ use selectors::parser::SelectorParseErrorKind;
use std::fmt::{self, Write}; use std::fmt::{self, Write};
use std::mem; use std::mem;
use std::num::Wrapping; use std::num::Wrapping;
use style_traits::{Comma, CssWriter, OneOrMoreSeparated, ParseError}; use style_traits::{Comma, CssWriter, OneOrMoreSeparated, ParseError,
use style_traits::{StyleParseErrorKind, ToCss}; StyleParseErrorKind, ToCss,
KeywordsCollectFn, SpecifiedValueInfo};
/// Parse a counter style name reference. /// https://drafts.csswg.org/css-counter-styles/#typedef-symbols-type
#[allow(missing_docs)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[derive(
Clone,
Copy,
Debug,
Eq,
MallocSizeOf,
Parse,
PartialEq,
ToComputedValue,
ToCss,
ToResolvedValue,
ToShmem,
)]
#[repr(u8)]
pub enum SymbolsType {
Cyclic,
Numeric,
Alphabetic,
Symbolic,
Fixed,
}
/// <https://drafts.csswg.org/css-counter-styles/#typedef-counter-style>
/// ///
/// Note that 'none' is not a valid name, but we include this (along with String) for space
/// efficiency when storing list-style-type.
#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, ToComputedValue, ToCss, ToResolvedValue, ToShmem)]
#[repr(u8)]
pub enum CounterStyle {
/// The 'none' value.
None,
/// `<counter-style-name>`
Name(CustomIdent),
/// `symbols()`
#[css(function)]
Symbols {
/// The <symbols-type>, or symbolic if not specified.
#[css(skip_if = "is_symbolic")]
ty: SymbolsType,
/// The actual symbols.
symbols: Symbols,
},
/// A single string value, useful for `<list-style-type>`.
String(AtomString),
}
#[inline]
fn is_symbolic(symbols_type: &SymbolsType) -> bool {
*symbols_type == SymbolsType::Symbolic
}
impl CounterStyle {
/// disc value
pub fn disc() -> Self {
CounterStyle::Name(CustomIdent(atom!("disc")))
}
/// decimal value
pub fn decimal() -> Self {
CounterStyle::Name(CustomIdent(atom!("decimal")))
}
/// Is this a bullet? (i.e. `list-style-type: disc|circle|square|disclosure-closed|disclosure-open`)
#[inline]
pub fn is_bullet(&self) -> bool {
match self {
CounterStyle::Name(CustomIdent(ref name)) => {
name == &atom!("disc") ||
name == &atom!("circle") ||
name == &atom!("square") ||
name == &atom!("disclosure-closed") ||
name == &atom!("disclosure-open")
},
_ => false,
}
}
}
bitflags! {
#[derive(Clone, Copy)]
/// Flags to control parsing of counter styles.
pub struct CounterStyleParsingFlags: u8 {
/// Whether `none` is allowed.
const ALLOW_NONE = 1 << 0;
/// Whether a bare string is allowed.
const ALLOW_STRING = 1 << 1;
}
}
impl CounterStyle {
/// Parse a counter style, and optionally none|string (for list-style-type).
pub fn parse<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
flags: CounterStyleParsingFlags,
) -> Result<Self, ParseError<'i>> {
use self::CounterStyleParsingFlags as Flags;
let location = input.current_source_location();
match input.next()? {
Token::QuotedString(ref string) if flags.intersects(Flags::ALLOW_STRING) => {
Ok(Self::String(AtomString::from(string.as_ref())))
},
Token::Ident(ref ident) => {
if flags.intersects(Flags::ALLOW_NONE) && ident.eq_ignore_ascii_case("none") {
return Ok(Self::None);
}
Ok(Self::Name(counter_style_name_from_ident(ident, location)?))
},
Token::Function(ref name) if name.eq_ignore_ascii_case("symbols") => {
input.parse_nested_block(|input| {
let symbols_type = input
.try_parse(SymbolsType::parse)
.unwrap_or(SymbolsType::Symbolic);
let symbols = Symbols::parse(context, input)?;
// There must be at least two symbols for alphabetic or
// numeric system.
if (symbols_type == SymbolsType::Alphabetic || symbols_type == SymbolsType::Numeric) &&
symbols.0.len() < 2
{
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
}
// Identifier is not allowed in symbols() function.
if symbols.0.iter().any(|sym| !sym.is_allowed_in_symbols()) {
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
}
Ok(Self::Symbols { ty: symbols_type, symbols })
})
},
t => Err(location.new_unexpected_token_error(t.clone())),
}
}
}
impl SpecifiedValueInfo for CounterStyle {
fn collect_completion_keywords(f: KeywordsCollectFn) {
// XXX The best approach for implementing this is probably
// having a CounterStyleName type wrapping CustomIdent, and
// put the predefined list for that type in counter_style mod.
// But that's a non-trivial change itself, so we use a simpler
// approach here.
macro_rules! predefined {
($($name:expr,)+) => {
f(&["symbols", "none", $($name,)+])
}
}
include!("predefined.rs");
}
}
fn parse_counter_style_name<'i>(input: &mut Parser<'i, '_>) -> Result<CustomIdent, ParseError<'i>> {
let location = input.current_source_location();
let ident = input.expect_ident()?;
counter_style_name_from_ident(ident, location)
}
/// This allows the reserved counter style names "decimal" and "disc". /// This allows the reserved counter style names "decimal" and "disc".
pub fn parse_counter_style_name<'i, 't>( fn counter_style_name_from_ident<'i>(
input: &mut Parser<'i, 't>, ident: &CowRcStr<'i>,
location: SourceLocation,
) -> Result<CustomIdent, ParseError<'i>> { ) -> Result<CustomIdent, ParseError<'i>> {
macro_rules! predefined { macro_rules! predefined {
($($name: tt,)+) => {{ ($($name: tt,)+) => {{
@ -40,8 +200,6 @@ pub fn parse_counter_style_name<'i, 't>(
} }
} }
let location = input.current_source_location();
let ident = input.expect_ident()?;
// This effectively performs case normalization only on predefined names. // This effectively performs case normalization only on predefined names.
if let Some(lower_case) = predefined::get(&ident) { if let Some(lower_case) = predefined::get(&ident) {
Ok(CustomIdent(lower_case.clone())) Ok(CustomIdent(lower_case.clone()))
@ -583,21 +741,21 @@ impl Parse for Fallback {
Clone, Debug, Eq, MallocSizeOf, PartialEq, ToComputedValue, ToResolvedValue, ToCss, ToShmem, Clone, Debug, Eq, MallocSizeOf, PartialEq, ToComputedValue, ToResolvedValue, ToCss, ToShmem,
)] )]
#[repr(C)] #[repr(C)]
pub struct Symbols(#[css(iterable)] pub crate::OwnedSlice<Symbol>); pub struct Symbols(#[css(iterable)] #[ignore_malloc_size_of = "Arc"] pub crate::ArcSlice<Symbol>);
impl Parse for Symbols { impl Parse for Symbols {
fn parse<'i, 't>( fn parse<'i, 't>(
context: &ParserContext, context: &ParserContext,
input: &mut Parser<'i, 't>, input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> { ) -> Result<Self, ParseError<'i>> {
let mut symbols = Vec::new(); let mut symbols = smallvec::SmallVec::<[_; 5]>::new();
while let Ok(s) = input.try_parse(|input| Symbol::parse(context, input)) { while let Ok(s) = input.try_parse(|input| Symbol::parse(context, input)) {
symbols.push(s); symbols.push(s);
} }
if symbols.is_empty() { if symbols.is_empty() {
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)); return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
} }
Ok(Symbols(symbols.into())) Ok(Symbols(crate::ArcSlice::from_iter(symbols.drain(..))))
} }
} }

View file

@ -7,12 +7,6 @@
//! Different kind of helpers to interact with Gecko values. //! Different kind of helpers to interact with Gecko values.
use crate::color::{AbsoluteColor, ColorSpace}; use crate::color::{AbsoluteColor, ColorSpace};
use crate::counter_style::{Symbol, Symbols};
use crate::gecko_bindings::bindings;
use crate::gecko_bindings::structs::CounterStylePtr;
use crate::values::generics::CounterStyle;
use crate::values::Either;
use crate::Atom;
/// Convert a color value to `nscolor`. /// Convert a color value to `nscolor`.
pub fn convert_absolute_color_to_nscolor(color: &AbsoluteColor) -> u32 { pub fn convert_absolute_color_to_nscolor(color: &AbsoluteColor) -> u32 {
@ -40,38 +34,3 @@ fn convert_ns_color_to_absolute_color_should_be_in_legacy_syntax() {
assert!(result.is_legacy_syntax()); assert!(result.is_legacy_syntax());
} }
impl CounterStyle {
/// Convert this counter style to a Gecko CounterStylePtr.
#[inline]
pub fn to_gecko_value(&self, gecko_value: &mut CounterStylePtr) {
unsafe { bindings::Gecko_CounterStyle_ToPtr(self, gecko_value) }
}
/// Convert Gecko CounterStylePtr to CounterStyle or String.
pub fn from_gecko_value(gecko_value: &CounterStylePtr) -> Either<Self, String> {
use crate::values::CustomIdent;
let name = unsafe { bindings::Gecko_CounterStyle_GetName(gecko_value) };
if !name.is_null() {
let name = unsafe { Atom::from_raw(name) };
debug_assert_ne!(name, atom!("none"));
Either::First(CounterStyle::Name(CustomIdent(name)))
} else {
let anonymous =
unsafe { bindings::Gecko_CounterStyle_GetAnonymous(gecko_value).as_ref() }.unwrap();
let symbols = &anonymous.mSymbols;
if anonymous.mSingleString {
debug_assert_eq!(symbols.len(), 1);
Either::Second(symbols[0].to_string())
} else {
let symbol_type = anonymous.mSymbolsType;
let symbols = symbols
.iter()
.map(|gecko_symbol| Symbol::String(gecko_symbol.to_string().into()))
.collect();
Either::First(CounterStyle::Symbols(symbol_type, Symbols(symbols)))
}
}
}
}

View file

@ -20,7 +20,6 @@ use crate::gecko_bindings::bindings::Gecko_Construct_Default_${style_struct.geck
use crate::gecko_bindings::bindings::Gecko_CopyConstruct_${style_struct.gecko_ffi_name}; use crate::gecko_bindings::bindings::Gecko_CopyConstruct_${style_struct.gecko_ffi_name};
use crate::gecko_bindings::bindings::Gecko_Destroy_${style_struct.gecko_ffi_name}; use crate::gecko_bindings::bindings::Gecko_Destroy_${style_struct.gecko_ffi_name};
% endfor % endfor
use crate::gecko_bindings::bindings::Gecko_CopyCounterStyle;
use crate::gecko_bindings::bindings::Gecko_EnsureImageLayersLength; use crate::gecko_bindings::bindings::Gecko_EnsureImageLayersLength;
use crate::gecko_bindings::bindings::Gecko_nsStyleFont_SetLang; use crate::gecko_bindings::bindings::Gecko_nsStyleFont_SetLang;
use crate::gecko_bindings::bindings::Gecko_nsStyleFont_CopyLangFrom; use crate::gecko_bindings::bindings::Gecko_nsStyleFont_CopyLangFrom;
@ -1453,55 +1452,7 @@ fn static_assert() {
<% impl_simple_image_array_property("blend_mode", "background", "mImage", "mBlendMode", "Background") %> <% impl_simple_image_array_property("blend_mode", "background", "mImage", "mBlendMode", "Background") %>
</%self:impl_trait> </%self:impl_trait>
<%self:impl_trait style_struct_name="List" skip_longhands="list-style-type"> <%self:impl_trait style_struct_name="List">
pub fn set_list_style_type(&mut self, v: longhands::list_style_type::computed_value::T) {
use nsstring::{nsACString, nsCStr};
use self::longhands::list_style_type::computed_value::T;
match v {
T::None => unsafe {
bindings::Gecko_SetCounterStyleToNone(&mut self.mCounterStyle)
}
T::CounterStyle(s) => s.to_gecko_value(&mut self.mCounterStyle),
T::String(s) => unsafe {
bindings::Gecko_SetCounterStyleToString(
&mut self.mCounterStyle,
&nsCStr::from(&s) as &nsACString,
)
}
}
}
pub fn copy_list_style_type_from(&mut self, other: &Self) {
unsafe {
Gecko_CopyCounterStyle(&mut self.mCounterStyle, &other.mCounterStyle);
}
}
pub fn reset_list_style_type(&mut self, other: &Self) {
self.copy_list_style_type_from(other)
}
pub fn clone_list_style_type(&self) -> longhands::list_style_type::computed_value::T {
use self::longhands::list_style_type::computed_value::T;
use crate::values::Either;
use crate::values::generics::CounterStyle;
use crate::gecko_bindings::bindings;
let name = unsafe {
bindings::Gecko_CounterStyle_GetName(&self.mCounterStyle)
};
if !name.is_null() {
let name = unsafe { Atom::from_raw(name) };
if name == atom!("none") {
return T::None;
}
}
let result = CounterStyle::from_gecko_value(&self.mCounterStyle);
match result {
Either::First(counter_style) => T::CounterStyle(counter_style),
Either::Second(string) => T::String(string),
}
}
</%self:impl_trait> </%self:impl_trait>
<%self:impl_trait style_struct_name="Table"> <%self:impl_trait style_struct_name="Table">

View file

@ -46,7 +46,6 @@ ${helpers.single_keyword(
engines="gecko", engines="gecko",
initial_specified_value="specified::ListStyleType::disc()", initial_specified_value="specified::ListStyleType::disc()",
animation_value_type="discrete", animation_value_type="discrete",
boxed=True,
spec="https://drafts.csswg.org/css-lists/#propdef-list-style-type", spec="https://drafts.csswg.org/css-lists/#propdef-list-style-type",
servo_restyle_damage="rebuild_and_reflow", servo_restyle_damage="rebuild_and_reflow",
affects="layout", affects="layout",

View file

@ -69,14 +69,14 @@
Ok(expanded! { Ok(expanded! {
list_style_position: position, list_style_position: position,
list_style_image: Image::None, list_style_image: Image::None,
list_style_type: ListStyleType::None, list_style_type: ListStyleType::none(),
}) })
} }
(true, 1, None, Some(image)) => { (true, 1, None, Some(image)) => {
Ok(expanded! { Ok(expanded! {
list_style_position: position, list_style_position: position,
list_style_image: image, list_style_image: image,
list_style_type: ListStyleType::None, list_style_type: ListStyleType::none(),
}) })
} }
(true, 1, Some(list_style_type), None) => { (true, 1, Some(list_style_type), None) => {
@ -90,7 +90,7 @@
Ok(expanded! { Ok(expanded! {
list_style_position: position, list_style_position: position,
list_style_image: Image::None, list_style_image: Image::None,
list_style_type: ListStyleType::None, list_style_type: ListStyleType::none(),
}) })
} }
(true, 0, list_style_type, image) => { (true, 0, list_style_type, image) => {

View file

@ -7,7 +7,7 @@
#[cfg(feature = "servo")] #[cfg(feature = "servo")]
use crate::computed_values::list_style_type::T as ListStyleType; use crate::computed_values::list_style_type::T as ListStyleType;
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
use crate::values::generics::CounterStyle; use crate::counter_style::CounterStyle;
use crate::values::specified::Attr; use crate::values::specified::Attr;
use crate::values::CustomIdent; use crate::values::CustomIdent;
use std::fmt::{self, Write}; use std::fmt::{self, Write};

View file

@ -5,13 +5,8 @@
//! Generic types that share their serialization implementations //! Generic types that share their serialization implementations
//! for both specified and computed values. //! for both specified and computed values.
use super::CustomIdent;
use crate::counter_style::{parse_counter_style_name, Symbols};
use crate::parser::{Parse, ParserContext};
use crate::Zero; use crate::Zero;
use cssparser::Parser;
use std::ops::Add; use std::ops::Add;
use style_traits::{KeywordsCollectFn, ParseError, SpecifiedValueInfo, StyleParseErrorKind};
pub mod animation; pub mod animation;
pub mod background; pub mod background;
@ -42,123 +37,6 @@ pub mod transform;
pub mod ui; pub mod ui;
pub mod url; pub mod url;
/// https://drafts.csswg.org/css-counter-styles/#typedef-symbols-type
#[allow(missing_docs)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[derive(
Clone,
Copy,
Debug,
Eq,
MallocSizeOf,
Parse,
PartialEq,
ToComputedValue,
ToCss,
ToResolvedValue,
ToShmem,
)]
#[repr(u8)]
pub enum SymbolsType {
Cyclic,
Numeric,
Alphabetic,
Symbolic,
Fixed,
}
/// <https://drafts.csswg.org/css-counter-styles/#typedef-counter-style>
///
/// Note that 'none' is not a valid name.
#[cfg_attr(feature = "gecko", derive(MallocSizeOf))]
#[derive(Clone, Debug, Eq, PartialEq, ToComputedValue, ToCss, ToResolvedValue, ToShmem)]
#[repr(u8)]
pub enum CounterStyle {
/// `<counter-style-name>`
Name(CustomIdent),
/// `symbols()`
#[css(function)]
Symbols(#[css(skip_if = "is_symbolic")] SymbolsType, Symbols),
}
#[inline]
fn is_symbolic(symbols_type: &SymbolsType) -> bool {
*symbols_type == SymbolsType::Symbolic
}
impl CounterStyle {
/// disc value
pub fn disc() -> Self {
CounterStyle::Name(CustomIdent(atom!("disc")))
}
/// decimal value
pub fn decimal() -> Self {
CounterStyle::Name(CustomIdent(atom!("decimal")))
}
/// Is this a bullet? (i.e. `list-style-type: disc|circle|square|disclosure-closed|disclosure-open`)
#[inline]
pub fn is_bullet(&self) -> bool {
match self {
CounterStyle::Name(CustomIdent(ref name)) => {
name == &atom!("disc") ||
name == &atom!("circle") ||
name == &atom!("square") ||
name == &atom!("disclosure-closed") ||
name == &atom!("disclosure-open")
},
_ => false,
}
}
}
impl Parse for CounterStyle {
fn parse<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
if let Ok(name) = input.try_parse(|i| parse_counter_style_name(i)) {
return Ok(CounterStyle::Name(name));
}
input.expect_function_matching("symbols")?;
input.parse_nested_block(|input| {
let symbols_type = input
.try_parse(SymbolsType::parse)
.unwrap_or(SymbolsType::Symbolic);
let symbols = Symbols::parse(context, input)?;
// There must be at least two symbols for alphabetic or
// numeric system.
if (symbols_type == SymbolsType::Alphabetic || symbols_type == SymbolsType::Numeric) &&
symbols.0.len() < 2
{
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
}
// Identifier is not allowed in symbols() function.
if symbols.0.iter().any(|sym| !sym.is_allowed_in_symbols()) {
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
}
Ok(CounterStyle::Symbols(symbols_type, symbols))
})
}
}
impl SpecifiedValueInfo for CounterStyle {
fn collect_completion_keywords(f: KeywordsCollectFn) {
// XXX The best approach for implementing this is probably
// having a CounterStyleName type wrapping CustomIdent, and
// put the predefined list for that type in counter_style mod.
// But that's a non-trivial change itself, so we use a simpler
// approach here.
macro_rules! predefined {
($($name:expr,)+) => {
f(&["symbols", $($name,)+])
}
}
include!("../../counter_style/predefined.rs");
}
}
/// A wrapper of Non-negative values. /// A wrapper of Non-negative values.
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[derive( #[derive(

View file

@ -10,7 +10,7 @@ use crate::parser::{Parse, ParserContext};
use crate::values::generics::counters as generics; use crate::values::generics::counters as generics;
use crate::values::generics::counters::CounterPair; use crate::values::generics::counters::CounterPair;
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
use crate::values::generics::CounterStyle; use crate::counter_style::CounterStyle;
use crate::values::specified::image::Image; use crate::values::specified::image::Image;
use crate::values::specified::Attr; use crate::values::specified::Attr;
use crate::values::specified::Integer; use crate::values::specified::Integer;
@ -161,12 +161,13 @@ impl Content {
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
fn parse_counter_style(context: &ParserContext, input: &mut Parser) -> CounterStyle { fn parse_counter_style(context: &ParserContext, input: &mut Parser) -> CounterStyle {
use crate::counter_style::CounterStyleParsingFlags;
input input
.try_parse(|input| { .try_parse(|input| {
input.expect_comma()?; input.expect_comma()?;
CounterStyle::parse(context, input) CounterStyle::parse(context, input, CounterStyleParsingFlags::empty())
}) })
.unwrap_or(CounterStyle::decimal()) .unwrap_or_else(|_| CounterStyle::decimal())
} }
} }

View file

@ -6,9 +6,7 @@
use crate::parser::{Parse, ParserContext}; use crate::parser::{Parse, ParserContext};
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
use crate::values::generics::CounterStyle; use crate::counter_style::{CounterStyle, CounterStyleParsingFlags};
#[cfg(feature = "gecko")]
use crate::values::CustomIdent;
use cssparser::{Parser, Token}; use cssparser::{Parser, Token};
use style_traits::{ParseError, StyleParseErrorKind}; use style_traits::{ParseError, StyleParseErrorKind};
@ -26,37 +24,36 @@ use style_traits::{ParseError, StyleParseErrorKind};
ToResolvedValue, ToResolvedValue,
ToShmem, ToShmem,
)] )]
pub enum ListStyleType { #[repr(transparent)]
/// `none` pub struct ListStyleType(pub CounterStyle);
None,
/// <counter-style>
CounterStyle(CounterStyle),
/// <string>
String(String),
}
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
impl ListStyleType { impl ListStyleType {
/// Initial specified value for `list-style-type`. /// Initial specified value for `list-style-type`.
#[inline] #[inline]
pub fn disc() -> Self { pub fn disc() -> Self {
ListStyleType::CounterStyle(CounterStyle::disc()) Self(CounterStyle::disc())
}
/// none value.
#[inline]
pub fn none() -> Self {
Self(CounterStyle::None)
} }
/// Convert from gecko keyword to list-style-type. /// Convert from gecko keyword to list-style-type.
/// ///
/// This should only be used for mapping type attribute to /// This should only be used for mapping type attribute to list-style-type, and thus only
/// list-style-type, and thus only values possible in that /// values possible in that attribute is considered here.
/// attribute is considered here.
pub fn from_gecko_keyword(value: u32) -> Self { pub fn from_gecko_keyword(value: u32) -> Self {
use crate::gecko_bindings::structs; use crate::gecko_bindings::structs;
use crate::values::CustomIdent;
let v8 = value as u8; let v8 = value as u8;
if v8 == structs::ListStyle_None { if v8 == structs::ListStyle_None {
return ListStyleType::None; return Self::none();
} }
ListStyleType::CounterStyle(CounterStyle::Name(CustomIdent(match v8 { Self(CounterStyle::Name(CustomIdent(match v8 {
structs::ListStyle_Disc => atom!("disc"), structs::ListStyle_Disc => atom!("disc"),
structs::ListStyle_Circle => atom!("circle"), structs::ListStyle_Circle => atom!("circle"),
structs::ListStyle_Square => atom!("square"), structs::ListStyle_Square => atom!("square"),
@ -69,13 +66,11 @@ impl ListStyleType {
}))) })))
} }
/// Is this a bullet? (i.e. `list-style-type: disc|circle|square|disclosure-closed|disclosure-open`) /// Is this a bullet? (i.e. `list-style-type: disc|circle|square|disclosure-closed|disclosure-open`)
#[inline] #[inline]
pub fn is_bullet(&self) -> bool { pub fn is_bullet(&self) -> bool {
match self { self.0.is_bullet()
ListStyleType::CounterStyle(ref style) => style.is_bullet(),
_ => false,
}
} }
} }
@ -85,15 +80,8 @@ impl Parse for ListStyleType {
context: &ParserContext, context: &ParserContext,
input: &mut Parser<'i, 't>, input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> { ) -> Result<Self, ParseError<'i>> {
if let Ok(style) = input.try_parse(|i| CounterStyle::parse(context, i)) { let flags = CounterStyleParsingFlags::ALLOW_NONE | CounterStyleParsingFlags::ALLOW_STRING;
return Ok(ListStyleType::CounterStyle(style)); Ok(Self(CounterStyle::parse(context, input, flags)?))
}
if input.try_parse(|i| i.expect_ident_matching("none")).is_ok() {
return Ok(ListStyleType::None);
}
Ok(ListStyleType::String(
input.expect_string()?.as_ref().to_owned(),
))
} }
} }

View file

@ -3750,13 +3750,15 @@ pub unsafe extern "C" fn Servo_CounterStyleRule_IsInRange(
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn Servo_CounterStyleRule_GetSymbols( pub unsafe extern "C" fn Servo_CounterStyleRule_GetSymbols(
rule: &LockedCounterStyleRule, rule: &LockedCounterStyleRule,
symbols: &mut style::OwnedSlice<nsString>, count: &mut usize,
) { ) -> *const counter_style::Symbol {
read_locked_arc(rule, |rule: &CounterStyleRule| { read_locked_arc(rule, |rule: &CounterStyleRule| {
*symbols = match rule.symbols() { let symbols = match rule.symbols() {
Some(s) => s.0.iter().map(symbol_to_string).collect(), Some(s) => &*s.0,
None => style::OwnedSlice::default(), None => &[],
}; };
*count = symbols.len();
symbols.as_ptr()
}) })
} }
@ -5351,7 +5353,7 @@ pub extern "C" fn Servo_DeclarationBlock_SetKeywordValue(
}) })
}, },
FontWeight => longhands::font_weight::SpecifiedValue::from_gecko_keyword(value), FontWeight => longhands::font_weight::SpecifiedValue::from_gecko_keyword(value),
ListStyleType => Box::new(longhands::list_style_type::SpecifiedValue::from_gecko_keyword(value)), ListStyleType => longhands::list_style_type::SpecifiedValue::from_gecko_keyword(value),
MathStyle => longhands::math_style::SpecifiedValue::from_gecko_keyword(value), MathStyle => longhands::math_style::SpecifiedValue::from_gecko_keyword(value),
MozMathVariant => longhands::_moz_math_variant::SpecifiedValue::from_gecko_keyword(value), MozMathVariant => longhands::_moz_math_variant::SpecifiedValue::from_gecko_keyword(value),
WhiteSpaceCollapse => get_from_computed::<longhands::white_space_collapse::SpecifiedValue>(value), WhiteSpaceCollapse => get_from_computed::<longhands::white_space_collapse::SpecifiedValue>(value),