Backed out changeset dffe004546c6 (bug 1897361) for causing reftest failures in /list-1.html CLOSED TREE

This commit is contained in:
Cristian Tuns 2024-05-19 17:09:47 -04:00
parent f3519ac0d9
commit e65d93ace2
25 changed files with 680 additions and 427 deletions

View file

@ -99,6 +99,7 @@ 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;
@ -148,6 +149,11 @@ 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],
@ -217,6 +223,8 @@ 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],
]; ];
@ -337,6 +345,12 @@ 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,39 +190,28 @@ 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);
aFrame->PresContext()->CounterStyleManager()->WithCounterStyleNameOrSymbols( CounterStyle* counterStyle =
listStyleType, [&](CounterStyle* aStyle) { aFrame->PresContext()->CounterStyleManager()->ResolveCounterStyle(
nsAutoString text; aFrame->StyleList()->mCounterStyle);
bool isBullet; nsAutoString text;
aStyle->GetSpokenCounterText(ordinal, aFrame->GetWritingMode(), text, bool isBullet;
counterStyle->GetSpokenCounterText(ordinal, aFrame->GetWritingMode(), text,
isBullet); isBullet);
if (isBullet) { if (isBullet) {
aText = text; aText = text;
aText.Append(' '); if (!counterStyle->IsNone()) {
} else { aText.Append(' ');
aStyle->GetPrefix(aText); }
aText += text; } else {
nsAutoString suffix; counterStyle->GetPrefix(aText);
aStyle->GetSuffix(suffix); aText += text;
aText += suffix; nsAutoString 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;
const StyleCounterStyle* style; CounterStylePtr ptr;
nsString separator; nsString separator;
if (type == Type::Counter) { if (type == Type::Counter) {
const auto& counter = aItem.AsCounter(); auto& counter = aItem.AsCounter();
name = counter._0.AsAtom(); name = counter._0.AsAtom();
style = &counter._1; ptr = CounterStylePtr::FromStyle(counter._1);
} else { } else {
const auto& counters = aItem.AsCounters(); auto& counters = aItem.AsCounters();
name = counters._0.AsAtom(); name = counters._0.AsAtom();
CopyUTF8toUTF16(counters._1.AsString(), separator); CopyUTF8toUTF16(counters._1.AsString(), separator);
style = &counters._2; ptr = CounterStylePtr::FromStyle(counters._2);
} }
auto* counterList = mContainStyleScopeManager.GetOrCreateCounterList( auto* counterList = mContainStyleScopeManager.GetOrCreateCounterList(
aOriginatingElement, name); aOriginatingElement, name);
auto node = MakeUnique<nsCounterUseNode>( auto node = MakeUnique<nsCounterUseNode>(
*style, std::move(separator), aContentIndex, std::move(ptr), std::move(separator), aContentIndex,
/* aAllCounters = */ type == Type::Counters); /* aAllCounters = */ type == Type::Counters);
auto initializer = MakeUnique<nsGenConInitializer>( auto initializer = MakeUnique<nsGenConInitializer>(
@ -1747,6 +1747,8 @@ void nsCSSFrameConstructor::CreateGeneratedContent(
break; break;
} }
} }
return;
} }
void nsCSSFrameConstructor::CreateGeneratedContentFromListStyle( void nsCSSFrameConstructor::CreateGeneratedContentFromListStyle(
@ -1770,41 +1772,37 @@ 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) {
using Tag = StyleCounterStyle::Tag; const nsStyleList* styleList = aPseudoStyle.StyleList();
const auto& styleType = aPseudoStyle.StyleList()->mListStyleType; CounterStyle* counterStyle =
switch (styleType.tag) { mPresShell->GetPresContext()->CounterStyleManager()->ResolveCounterStyle(
case Tag::None: styleList->mCounterStyle);
bool needUseNode = false;
switch (counterStyle->GetStyle()) {
case ListStyle::None:
return; return;
case Tag::String: { case ListStyle::Disc:
nsDependentAtomString string(styleType.AsString().AsAtom()); case ListStyle::Circle:
RefPtr<nsIContent> child = CreateGenConTextNode(aState, string, nullptr); case ListStyle::Square:
aAddChild(child); case ListStyle::DisclosureClosed:
return; case ListStyle::DisclosureOpen:
}
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,
styleType); styleList->mCounterStyle);
if (styleType.IsName()) { if (!needUseNode) {
nsAtom* name = styleType.AsName().AsAtom(); nsAutoString text;
if (name == nsGkAtoms::disc || name == nsGkAtoms::circle || node->GetText(WritingMode(&aPseudoStyle), counterStyle, text);
name == nsGkAtoms::square || name == nsGkAtoms::disclosure_closed || // Note that we're done with 'node' in this case. It's not inserted into
name == nsGkAtoms::disclosure_open) { // any list so it's deleted when we return.
// We don't need a use node inserted for these. RefPtr<nsIContent> child = CreateGenConTextNode(aState, text, nullptr);
CounterStyle* counterStyle = mPresShell->GetPresContext() aAddChild(child);
->CounterStyleManager() return;
->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(
@ -3406,18 +3404,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();
@ -4093,9 +4091,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*
@ -4729,7 +4727,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,11 +80,10 @@ void nsCounterChangeNode::Calc(nsCounterList* aList) {
} }
void nsCounterUseNode::GetText(nsString& aResult) { void nsCounterUseNode::GetText(nsString& aResult) {
mPseudoFrame->PresContext() CounterStyle* style =
->CounterStyleManager() mPseudoFrame->PresContext()->CounterStyleManager()->ResolveCounterStyle(
->WithCounterStyleNameOrSymbols(mCounterStyle, [&](CounterStyle* aStyle) { mCounterStyle);
GetText(mPseudoFrame->GetWritingMode(), aStyle, aResult); GetText(mPseudoFrame->GetWritingMode(), style, 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::StyleCounterStyle mCounterStyle; mozilla::CounterStylePtr mCounterStyle;
nsString mSeparator; nsString mSeparator;
// false for counter(), true for counters() // false for counter(), true for counters()
@ -103,18 +103,16 @@ struct nsCounterUseNode : public nsCounterNode {
bool mForLegacyBullet = false; bool mForLegacyBullet = false;
enum ForLegacyBullet { ForLegacyBullet }; enum ForLegacyBullet { ForLegacyBullet };
nsCounterUseNode(enum ForLegacyBullet, nsCounterUseNode(enum ForLegacyBullet, mozilla::CounterStylePtr aCounterStyle)
const mozilla::StyleCounterStyle& aCounterStyle)
: nsCounterNode(0, USE), : nsCounterNode(0, USE),
mCounterStyle(aCounterStyle), mCounterStyle(std::move(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(const mozilla::StyleCounterStyle& aCounterStyle, nsCounterUseNode(mozilla::CounterStylePtr aCounterStyle, nsString aSeparator,
nsString aSeparator, uint32_t aContentIndex, uint32_t aContentIndex, bool aAllCounters)
bool aAllCounters)
: nsCounterNode(aContentIndex, USE), : nsCounterNode(aContentIndex, USE),
mCounterStyle(aCounterStyle), mCounterStyle(std::move(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,24 +70,22 @@ 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->mListStyleType.AsName().AsAtom(); nsAtom* type = list->mCounterStyle.AsAtom();
if (type != nsGkAtoms::disc && type != nsGkAtoms::circle && if (type != nsGkAtoms::none && type != nsGkAtoms::disc &&
type != nsGkAtoms::square && type != nsGkAtoms::disclosure_closed && type != nsGkAtoms::circle && type != nsGkAtoms::square &&
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->mListStyleType.IsNone() && list->mListStyleImage.IsNone() && (list->mCounterStyle.IsNone() && list->mListStyleImage.IsNone() &&
marker->StyleContent()->NonAltContentItems().IsEmpty()); marker->StyleContent()->NonAltContentItems().IsEmpty());
} }
@ -8657,11 +8657,13 @@ 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,44 +47,29 @@ 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 StyleSymbol> aSymbols) { Span<const nsString> 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;
SymbolToString(aSymbols[index >= 0 ? index : index + n], aResult); aResult = aSymbols[index >= 0 ? index : index + n];
return true; return true;
} }
static bool GetFixedCounterText(CounterValue aOrdinal, nsAString& aResult, static bool GetFixedCounterText(CounterValue aOrdinal, nsAString& aResult,
CounterValue aStart, CounterValue aStart,
Span<const StyleSymbol> aSymbols) { Span<const nsString> aSymbols) {
CounterValue index = aOrdinal - aStart; CounterValue index = aOrdinal - aStart;
if (index >= 0 && index < CounterValue(aSymbols.Length())) { if (index >= 0 && index < CounterValue(aSymbols.Length())) {
SymbolToString(aSymbols[index], aResult); aResult = aSymbols[index];
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 StyleSymbol> aSymbols) { Span<const nsString> 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.");
@ -94,25 +79,23 @@ static bool GetSymbolicCounterText(CounterValue aOrdinal, nsAString& aResult,
aResult.Truncate(); aResult.Truncate();
auto n = aSymbols.Length(); auto n = aSymbols.Length();
const StyleSymbol& symbol = aSymbols[(aOrdinal - 1) % n]; const nsString& symbol = aSymbols[(aOrdinal - 1) % n];
size_t len = (aOrdinal + n - 1) / n; size_t len = (aOrdinal + n - 1) / n;
auto symbolLength = SymbolLength(symbol); auto symbolLength = symbol.Length();
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(str); aResult.Append(symbol);
} }
} }
return true; return true;
} }
static bool GetAlphabeticCounterText(CounterValue aOrdinal, nsAString& aResult, static bool GetAlphabeticCounterText(CounterValue aOrdinal, nsAString& aResult,
Span<const StyleSymbol> aSymbols) { Span<const nsString> 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) {
@ -132,23 +115,18 @@ 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) {
const auto& symbol = aSymbols[indexes[i - 1]]; aResult.Append(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 StyleSymbol> aSymbols) { Span<const nsString> 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) {
SymbolToString(aSymbols[0], aResult); aResult = aSymbols[0];
return true; return true;
} }
@ -161,12 +139,7 @@ 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) {
const auto& symbol = aSymbols[indexes[i - 1]]; aResult.Append(aSymbols[indexes[i - 1]]);
if (symbol.IsIdent()) {
aResult.Append(nsDependentAtomString(symbol.AsIdent().AsAtom()));
} else {
AppendUTF8toUTF16(symbol.AsString().AsString(), aResult);
}
} }
return true; return true;
} }
@ -400,7 +373,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;
@ -542,22 +515,25 @@ class BuiltinCounterStyle : public CounterStyle {
nsStaticAtom* GetStyleName() const { return mName; } nsStaticAtom* GetStyleName() const { return mName; }
void GetPrefix(nsAString& aResult) override; virtual void GetPrefix(nsAString& aResult) override;
void GetSuffix(nsAString& aResult) override; virtual void GetSuffix(nsAString& aResult) override;
void GetSpokenCounterText(CounterValue aOrdinal, WritingMode aWritingMode, virtual void GetSpokenCounterText(CounterValue aOrdinal,
nsAString& aResult, bool& aIsBullet) override; WritingMode aWritingMode,
bool IsBullet() override; nsAString& aResult,
bool& aIsBullet) override;
virtual bool IsBullet() override;
void GetNegative(NegativeType& aResult) override; virtual void GetNegative(NegativeType& aResult) override;
bool IsOrdinalInRange(CounterValue aOrdinal) override; virtual bool IsOrdinalInRange(CounterValue aOrdinal) override;
bool IsOrdinalInAutoRange(CounterValue aOrdinal) override; virtual bool IsOrdinalInAutoRange(CounterValue aOrdinal) override;
void GetPad(PadType& aResult) override; virtual void GetPad(PadType& aResult) override;
CounterStyle* GetFallback() override; virtual CounterStyle* GetFallback() override;
SpeakAs GetSpeakAs() override; virtual SpeakAs GetSpeakAs() override;
bool UseNegativeSign() override; virtual bool UseNegativeSign() override;
bool GetInitialCounterText(CounterValue aOrdinal, WritingMode aWritingMode, virtual bool GetInitialCounterText(CounterValue aOrdinal,
nsAString& aResult, bool& aIsRTL) override; WritingMode aWritingMode,
nsAString& aResult, bool& aIsRTL) override;
protected: protected:
constexpr BuiltinCounterStyle(const BuiltinCounterStyle& aOther) constexpr BuiltinCounterStyle(const BuiltinCounterStyle& aOther)
@ -977,24 +953,28 @@ 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; }
void GetPrefix(nsAString& aResult) override; virtual void GetPrefix(nsAString& aResult) override;
void GetSuffix(nsAString& aResult) override; virtual void GetSuffix(nsAString& aResult) override;
void GetSpokenCounterText(CounterValue aOrdinal, WritingMode aWritingMode, virtual void GetSpokenCounterText(CounterValue aOrdinal,
nsAString& aResult, bool& aIsBullet) override; WritingMode aWritingMode,
bool IsBullet() override; nsAString& aResult,
bool& aIsBullet) override;
virtual bool IsBullet() override;
void GetNegative(NegativeType& aResult) override; virtual void GetNegative(NegativeType& aResult) override;
bool IsOrdinalInRange(CounterValue aOrdinal) override; virtual bool IsOrdinalInRange(CounterValue aOrdinal) override;
bool IsOrdinalInAutoRange(CounterValue aOrdinal) override; virtual bool IsOrdinalInAutoRange(CounterValue aOrdinal) override;
void GetPad(PadType& aResult) override; virtual void GetPad(PadType& aResult) override;
CounterStyle* GetFallback() override; virtual CounterStyle* GetFallback() override;
SpeakAs GetSpeakAs() override; virtual SpeakAs GetSpeakAs() override;
bool UseNegativeSign() override; virtual bool UseNegativeSign() override;
void CallFallbackStyle(CounterValue aOrdinal, WritingMode aWritingMode, virtual void CallFallbackStyle(CounterValue aOrdinal,
nsAString& aResult, bool& aIsRTL) override; WritingMode aWritingMode, nsAString& aResult,
bool GetInitialCounterText(CounterValue aOrdinal, WritingMode aWritingMode, bool& aIsRTL) override;
nsAString& aResult, bool& aIsRTL) override; virtual bool GetInitialCounterText(CounterValue aOrdinal,
WritingMode aWritingMode,
nsAString& aResult, bool& aIsRTL) override;
bool IsExtendsSystem() { return mSystem == StyleCounterSystem::Extends; } bool IsExtendsSystem() { return mSystem == StyleCounterSystem::Extends; }
@ -1012,7 +992,7 @@ class CustomCounterStyle final : public CounterStyle {
private: private:
~CustomCounterStyle() = default; ~CustomCounterStyle() = default;
Span<const StyleSymbol> GetSymbols(); Span<const nsString> 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
@ -1059,6 +1039,7 @@ 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;
@ -1087,6 +1068,7 @@ 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);
@ -1314,10 +1296,11 @@ bool CustomCounterStyle::GetInitialCounterText(CounterValue aOrdinal,
} }
} }
Span<const StyleSymbol> CustomCounterStyle::GetSymbols() { Span<const nsString> CustomCounterStyle::GetSymbols() {
size_t count = 0; if (mSymbols.IsEmpty()) {
const StyleSymbol* ptr = Servo_CounterStyleRule_GetSymbols(mRule, &count); Servo_CounterStyleRule_GetSymbols(mRule, &mSymbols);
return Span(ptr, count); }
return mSymbols.AsSpan();
} }
Span<const AdditiveSymbol> CustomCounterStyle::GetAdditiveSymbols() { Span<const AdditiveSymbol> CustomCounterStyle::GetAdditiveSymbols() {
@ -1521,11 +1504,20 @@ CounterStyle* CustomCounterStyle::GetExtendsRoot() {
return mExtendsRoot; return mExtendsRoot;
} }
AnonymousCounterStyle::AnonymousCounterStyle(StyleSymbolsType aType, AnonymousCounterStyle::AnonymousCounterStyle(const nsAString& aContent)
Span<const StyleSymbol> aSymbols)
: CounterStyle(ListStyle::Custom), : CounterStyle(ListStyle::Custom),
mSingleString(true),
mSymbolsType(StyleSymbolsType::Cyclic) {
mSymbols.SetCapacity(1);
mSymbols.AppendElement(aContent);
}
AnonymousCounterStyle::AnonymousCounterStyle(StyleSymbolsType aType,
nsTArray<nsString> aSymbols)
: CounterStyle(ListStyle::Custom),
mSingleString(false),
mSymbolsType(aType), mSymbolsType(aType),
mSymbols(aSymbols) {} mSymbols(std::move(aSymbols)) {}
/* virtual */ /* virtual */
void AnonymousCounterStyle::GetPrefix(nsAString& aResult) { void AnonymousCounterStyle::GetPrefix(nsAString& aResult) {
@ -1533,7 +1525,13 @@ void AnonymousCounterStyle::GetPrefix(nsAString& aResult) {
} }
/* virtual */ /* virtual */
void AnonymousCounterStyle::GetSuffix(nsAString& aResult) { aResult = ' '; } void AnonymousCounterStyle::GetSuffix(nsAString& aResult) {
if (IsSingleString()) {
aResult.Truncate();
} else {
aResult = ' ';
}
}
/* virtual */ /* virtual */
bool AnonymousCounterStyle::IsBullet() { bool AnonymousCounterStyle::IsBullet() {

View file

@ -97,36 +97,195 @@ class CounterStyle {
const ListStyle mStyle; const ListStyle mStyle;
}; };
class MOZ_STACK_CLASS AnonymousCounterStyle final : public CounterStyle { class AnonymousCounterStyle final : public CounterStyle {
public: public:
explicit AnonymousCounterStyle(const nsAString& aContent); explicit AnonymousCounterStyle(const nsAString& aContent);
AnonymousCounterStyle(StyleSymbolsType, Span<const StyleSymbol> aSymbols); AnonymousCounterStyle(StyleSymbolsType, nsTArray<nsString> aSymbols);
void GetPrefix(nsAString& aResult) override; virtual void GetPrefix(nsAString& aResult) override;
void GetSuffix(nsAString& aResult) override; virtual void GetSuffix(nsAString& aResult) override;
bool IsBullet() override; virtual bool IsBullet() override;
void GetNegative(NegativeType& aResult) override; virtual void GetNegative(NegativeType& aResult) override;
bool IsOrdinalInRange(CounterValue aOrdinal) override; virtual bool IsOrdinalInRange(CounterValue aOrdinal) override;
bool IsOrdinalInAutoRange(CounterValue aOrdinal) override; virtual bool IsOrdinalInAutoRange(CounterValue aOrdinal) override;
void GetPad(PadType& aResult) override; virtual void GetPad(PadType& aResult) override;
CounterStyle* GetFallback() override; virtual CounterStyle* GetFallback() override;
SpeakAs GetSpeakAs() override; virtual SpeakAs GetSpeakAs() override;
bool UseNegativeSign() override; virtual bool UseNegativeSign() override;
bool GetInitialCounterText(CounterValue aOrdinal, WritingMode aWritingMode, virtual bool GetInitialCounterText(CounterValue aOrdinal,
nsAString& aResult, bool& aIsRTL) override; WritingMode aWritingMode,
nsAString& aResult, bool& aIsRTL) override;
AnonymousCounterStyle* AsAnonymous() override { return this; } virtual AnonymousCounterStyle* AsAnonymous() override { return this; }
auto GetSymbols() const { return mSymbols; } bool IsSingleString() const { return mSingleString; }
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;
Span<const StyleSymbol> mSymbols; nsTArray<nsString> 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 {
@ -151,23 +310,11 @@ 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);
template <typename F> CounterStyle* ResolveCounterStyle(const CounterStylePtr& aPtr) {
void WithCounterStyleNameOrSymbols(const StyleCounterStyle& aStyle, if (aPtr.IsAtom()) {
F&& aCallback) { return ResolveCounterStyle(aPtr.AsAtom());
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,6 +960,34 @@ 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,6 +315,23 @@ 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,6 +206,7 @@ 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",
@ -565,8 +566,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::counter_style::SymbolsType" }, { gecko = "StyleSymbolsType", servo = "crate::values::generics::SymbolsType" },
{ gecko = "StyleCounterStyle", servo = "crate::counter_style::CounterStyle" }, { gecko = "StyleCounterStyle", servo = "crate::values::generics::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" },
@ -618,7 +619,6 @@ 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()->mListStyleType.IsNone() && if (aPseudoStyle.StyleList()->mCounterStyle.IsNone() &&
aPseudoStyle.StyleList()->mListStyleImage.IsNone() && aPseudoStyle.StyleList()->mListStyleImage.IsNone() &&
content.IsNormal()) { content.IsNormal()) {
return false; return false;

View file

@ -605,16 +605,17 @@ 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),
mListStyleType(aSource.mListStyleType), mCounterStyle(aSource.mCounterStyle),
mQuotes(aSource.mQuotes), mQuotes(aSource.mQuotes),
mListStyleImage(aSource.mListStyleImage) { mListStyleImage(aSource.mListStyleImage) {
MOZ_COUNT_CTOR(nsStyleList); MOZ_COUNT_CTOR(nsStyleList);
@ -640,7 +641,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 ||
mListStyleType != aNewData.mListStyleType || mCounterStyle != aNewData.mCounterStyle ||
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::StyleListStyleType mListStyleType; mozilla::CounterStylePtr mCounterStyle;
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::{AtomString, CustomIdent}; use crate::values::CustomIdent;
use crate::Atom; use crate::Atom;
use cssparser::{ use cssparser::{
AtRuleParser, DeclarationParser, QualifiedRuleParser, RuleBodyItemParser, RuleBodyParser, AtRuleParser, DeclarationParser, QualifiedRuleParser, RuleBodyItemParser, RuleBodyParser,
@ -21,174 +21,14 @@ 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};
StyleParseErrorKind, ToCss, use style_traits::{StyleParseErrorKind, ToCss};
KeywordsCollectFn, SpecifiedValueInfo};
/// https://drafts.csswg.org/css-counter-styles/#typedef-symbols-type /// Parse a counter style name reference.
#[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".
fn counter_style_name_from_ident<'i>( pub fn parse_counter_style_name<'i, 't>(
ident: &CowRcStr<'i>, input: &mut Parser<'i, 't>,
location: SourceLocation,
) -> Result<CustomIdent, ParseError<'i>> { ) -> Result<CustomIdent, ParseError<'i>> {
macro_rules! predefined { macro_rules! predefined {
($($name: tt,)+) => {{ ($($name: tt,)+) => {{
@ -200,6 +40,8 @@ fn counter_style_name_from_ident<'i>(
} }
} }
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()))
@ -741,21 +583,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)] #[ignore_malloc_size_of = "Arc"] pub crate::ArcSlice<Symbol>); pub struct Symbols(#[css(iterable)] pub crate::OwnedSlice<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 = smallvec::SmallVec::<[_; 5]>::new(); let mut symbols = Vec::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(crate::ArcSlice::from_iter(symbols.drain(..)))) Ok(Symbols(symbols.into()))
} }
} }

View file

@ -7,6 +7,12 @@
//! 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 {
@ -34,3 +40,38 @@ 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,6 +20,7 @@ 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;
@ -1452,7 +1453,55 @@ 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"> <%self:impl_trait style_struct_name="List" skip_longhands="list-style-type">
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,6 +46,7 @@ ${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::counter_style::CounterStyle; use crate::values::generics::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,8 +5,13 @@
//! 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;
@ -37,6 +42,123 @@ 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::counter_style::CounterStyle; use crate::values::generics::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,13 +161,12 @@ 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, CounterStyleParsingFlags::empty()) CounterStyle::parse(context, input)
}) })
.unwrap_or_else(|_| CounterStyle::decimal()) .unwrap_or(CounterStyle::decimal())
} }
} }

View file

@ -6,7 +6,9 @@
use crate::parser::{Parse, ParserContext}; use crate::parser::{Parse, ParserContext};
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
use crate::counter_style::{CounterStyle, CounterStyleParsingFlags}; use crate::values::generics::CounterStyle;
#[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};
@ -24,36 +26,37 @@ use style_traits::{ParseError, StyleParseErrorKind};
ToResolvedValue, ToResolvedValue,
ToShmem, ToShmem,
)] )]
#[repr(transparent)] pub enum ListStyleType {
pub struct ListStyleType(pub CounterStyle); /// `none`
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 {
Self(CounterStyle::disc()) ListStyleType::CounterStyle(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 list-style-type, and thus only /// This should only be used for mapping type attribute to
/// values possible in that attribute is considered here. /// list-style-type, and thus only values possible in that
/// 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 Self::none(); return ListStyleType::None;
} }
Self(CounterStyle::Name(CustomIdent(match v8 { ListStyleType::CounterStyle(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"),
@ -66,11 +69,13 @@ 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 {
self.0.is_bullet() match self {
ListStyleType::CounterStyle(ref style) => style.is_bullet(),
_ => false,
}
} }
} }
@ -80,8 +85,15 @@ 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>> {
let flags = CounterStyleParsingFlags::ALLOW_NONE | CounterStyleParsingFlags::ALLOW_STRING; if let Ok(style) = input.try_parse(|i| CounterStyle::parse(context, i)) {
Ok(Self(CounterStyle::parse(context, input, flags)?)) return Ok(ListStyleType::CounterStyle(style));
}
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,15 +3750,13 @@ 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,
count: &mut usize, symbols: &mut style::OwnedSlice<nsString>,
) -> *const counter_style::Symbol { ) {
read_locked_arc(rule, |rule: &CounterStyleRule| { read_locked_arc(rule, |rule: &CounterStyleRule| {
let symbols = match rule.symbols() { *symbols = match rule.symbols() {
Some(s) => &*s.0, Some(s) => s.0.iter().map(symbol_to_string).collect(),
None => &[], None => style::OwnedSlice::default(),
}; };
*count = symbols.len();
symbols.as_ptr()
}) })
} }
@ -5353,7 +5351,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 => longhands::list_style_type::SpecifiedValue::from_gecko_keyword(value), ListStyleType => Box::new(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),