Bug 1605803 - Use cbindgen for content property. r=xidorn

This cleans up and also allows us to keep the distinction between content: none
and content: normal, which allows us to fix the computed style we return from
getComputedStyle().

Do this last bit from the resolved value instead of StyleAdjuster, because
otherwise we need to tweak every initial struct for ::before / ::after.

Differential Revision: https://phabricator.services.mozilla.com/D58276

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Emilio Cobos Álvarez 2020-01-05 13:10:39 +00:00
parent 08310b0e31
commit ab672d9f29
31 changed files with 332 additions and 796 deletions

View File

@ -164,7 +164,7 @@ test_newtab({
);
is(
content.getComputedStyle(hr).content,
"none",
"normal",
"filtered out attempted @media query"
);
},

View File

@ -1363,13 +1363,12 @@ static bool ShouldCreateImageFrameForContent(const Element& aElement,
if (aElement.IsRootOfNativeAnonymousSubtree()) {
return false;
}
auto& content = *aStyle.StyleContent();
if (content.ContentCount() != 1) {
auto& content = aStyle.StyleContent()->mContent;
if (!content.IsItems()) {
return false;
}
return content.ContentAt(0).GetType() == StyleContentType::Image;
Span<const StyleContentItem> items = content.AsItems().AsSpan();
return items.Length() == 1 && items[0].IsUrl();
}
//----------------------------------------------------------------------
@ -1485,24 +1484,25 @@ already_AddRefed<nsIContent> nsCSSFrameConstructor::CreateGenConTextNode(
already_AddRefed<nsIContent> nsCSSFrameConstructor::CreateGeneratedContent(
nsFrameConstructorState& aState, const Element& aOriginatingElement,
ComputedStyle& aPseudoStyle, uint32_t aContentIndex) {
using Type = StyleContentItem::Tag;
// Get the content value
const nsStyleContentData& data =
aPseudoStyle.StyleContent()->ContentAt(aContentIndex);
const StyleContentType type = data.GetType();
const auto& item = aPseudoStyle.StyleContent()->ContentAt(aContentIndex);
const Type type = item.tag;
switch (type) {
case StyleContentType::Image:
case Type::Url:
return GeneratedImageContent::Create(*mDocument, aContentIndex);
case StyleContentType::String:
return CreateGenConTextNode(aState, nsDependentString(data.GetString()),
nullptr);
case Type::String:
return CreateGenConTextNode(
aState, NS_ConvertUTF8toUTF16(item.AsString().AsString()), nullptr);
case StyleContentType::Attr: {
const nsStyleContentAttr* attr = data.GetAttr();
RefPtr<nsAtom> attrName = attr->mName;
case Type::Attr: {
const auto& attr = item.AsAttr();
RefPtr<nsAtom> attrName = attr.attribute.AsAtom();
int32_t attrNameSpace = kNameSpaceID_None;
if (RefPtr<nsAtom> ns = attr->mNamespaceURL) {
RefPtr<nsAtom> ns = attr.namespace_url.AsAtom();
if (!ns->IsEmpty()) {
nsresult rv = nsContentUtils::NameSpaceManager()->RegisterNameSpace(
ns.forget(), attrNameSpace);
NS_ENSURE_SUCCESS(rv, nullptr);
@ -1518,25 +1518,36 @@ already_AddRefed<nsIContent> nsCSSFrameConstructor::CreateGeneratedContent(
return content.forget();
}
case StyleContentType::Counter:
case StyleContentType::Counters: {
nsStyleContentData::CounterFunction* counters = data.GetCounters();
nsCounterList* counterList =
mCounterManager.CounterListFor(counters->mIdent);
case Type::Counter:
case Type::Counters: {
RefPtr<nsAtom> name;
CounterStylePtr ptr;
nsString separator;
if (type == Type::Counter) {
auto& counter = item.AsCounter();
name = counter._0.AsAtom();
ptr = CounterStylePtr::FromStyle(counter._1);
} else {
auto& counters = item.AsCounters();
name = counters._0.AsAtom();
separator = NS_ConvertUTF8toUTF16(counters._1.AsString());
ptr = CounterStylePtr::FromStyle(counters._2);
}
nsCounterList* counterList = mCounterManager.CounterListFor(name);
auto node = MakeUnique<nsCounterUseNode>(
counters, aContentIndex, type == StyleContentType::Counters);
std::move(ptr), std::move(separator), aContentIndex,
/* aAllCounters = */ type == Type::Counters);
auto initializer = MakeUnique<nsGenConInitializer>(
std::move(node), counterList, &nsCSSFrameConstructor::CountersDirty);
return CreateGenConTextNode(aState, EmptyString(),
std::move(initializer));
}
case StyleContentType::OpenQuote:
case StyleContentType::CloseQuote:
case StyleContentType::NoOpenQuote:
case StyleContentType::NoCloseQuote: {
case Type::OpenQuote:
case Type::CloseQuote:
case Type::NoOpenQuote:
case Type::NoCloseQuote: {
auto node = MakeUnique<nsQuoteNode>(type, aContentIndex);
auto initializer = MakeUnique<nsGenConInitializer>(
std::move(node), &mQuoteList, &nsCSSFrameConstructor::QuotesDirty);
@ -1544,7 +1555,7 @@ already_AddRefed<nsIContent> nsCSSFrameConstructor::CreateGeneratedContent(
std::move(initializer));
}
case StyleContentType::AltContent: {
case Type::MozAltContent: {
// Use the "alt" attribute; if that fails and the node is an HTML
// <input>, try the value attribute and then fall back to some default
// localized text we have.
@ -1574,10 +1585,6 @@ already_AddRefed<nsIContent> nsCSSFrameConstructor::CreateGeneratedContent(
break;
}
case StyleContentType::Uninitialized:
MOZ_ASSERT_UNREACHABLE("uninitialized content type");
return nullptr;
}
return nullptr;

View File

@ -89,11 +89,12 @@ struct nsCounterUseNode : public nsCounterNode {
}
// args go directly to member variables here and of nsGenConNode
nsCounterUseNode(nsStyleContentData::CounterFunction* aCounterFunction,
uint32_t aContentIndex, bool aAllCounters)
nsCounterUseNode(mozilla::CounterStylePtr aCounterStyle,
nsString aSeparator, uint32_t aContentIndex,
bool aAllCounters)
: nsCounterNode(aContentIndex, USE),
mCounterStyle(aCounterFunction->mCounterStyle),
mSeparator(aCounterFunction->mSeparator),
mCounterStyle(std::move(aCounterStyle)),
mSeparator(std::move(aSeparator)),
mAllCounters(aAllCounters) {
NS_ASSERTION(aContentIndex <= INT32_MAX, "out of range");
}

View File

@ -18,7 +18,7 @@
class nsGenConList;
struct nsGenConNode : public mozilla::LinkedListElement<nsGenConNode> {
using StyleContentType = mozilla::StyleContentType;
using StyleContentType = mozilla::StyleContentItem::Tag;
// The wrapper frame for all of the pseudo-element's content. This
// frame generally has useful style data and has the

View File

@ -106,6 +106,8 @@ void nsQuoteList::RecalcAll() {
#ifdef DEBUG
void nsQuoteList::PrintChain() {
using StyleContentType = nsQuoteNode::StyleContentType;
printf("Chain: \n");
for (nsQuoteNode* node = FirstNode(); node; node = Next(node)) {
printf(" %p %d - ", static_cast<void*>(node), node->mDepthBefore);

View File

@ -17,6 +17,7 @@
#include "mozilla/Encoding.h"
#include "mozilla/EventStates.h"
#include "mozilla/HTMLEditor.h"
#include "mozilla/dom/ImageTracker.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/gfx/Helpers.h"
#include "mozilla/gfx/PathHelpers.h"
@ -270,12 +271,11 @@ void nsImageFrame::DestroyFrom(nsIFrame* aDestructRoot,
// deregister with our refresh driver.
imageLoader->FrameDestroyed(this);
imageLoader->RemoveNativeObserver(mListener);
} else {
if (mContentURLRequest) {
nsLayoutUtils::DeregisterImageRequest(PresContext(), mContentURLRequest,
&mContentURLRequestRegistered);
mContentURLRequest->Cancel(NS_BINDING_ABORTED);
}
} else if (mContentURLRequest) {
PresContext()->Document()->ImageTracker()->Remove(mContentURLRequest);
nsLayoutUtils::DeregisterImageRequest(PresContext(), mContentURLRequest,
&mContentURLRequestRegistered);
mContentURLRequest->Cancel(NS_BINDING_ABORTED);
}
// set the frame to null so we don't send messages to a dead object.
@ -333,7 +333,9 @@ void nsImageFrame::Init(nsIContent* aContent, nsContainerFrame* aParent,
mListener = new nsImageListener(this);
if (!gIconLoad) LoadIcons(PresContext());
if (!gIconLoad) {
LoadIcons(PresContext());
}
if (mKind == Kind::ImageElement) {
nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(aContent);
@ -362,11 +364,12 @@ void nsImageFrame::Init(nsIContent* aContent, nsContainerFrame* aParent,
contentIndex = static_cast<GeneratedImageContent*>(aContent)->Index();
}
MOZ_RELEASE_ASSERT(contentIndex < styleContent->ContentCount());
MOZ_RELEASE_ASSERT(styleContent->ContentAt(contentIndex).GetType() ==
StyleContentType::Image);
if (auto* proxy = styleContent->ContentAt(contentIndex).GetImage()) {
proxy->Clone(mListener, mContent->OwnerDoc(),
getter_AddRefs(mContentURLRequest));
MOZ_RELEASE_ASSERT(styleContent->ContentAt(contentIndex).IsUrl());
auto& url = const_cast<StyleComputedUrl&>(
styleContent->ContentAt(contentIndex).AsUrl());
Document* doc = PresContext()->Document();
if (RefPtr<imgRequestProxy> proxy = url.LoadImage(*doc)) {
proxy->Clone(mListener, doc, getter_AddRefs(mContentURLRequest));
SetupForContentURLRequest();
}
}
@ -391,6 +394,9 @@ void nsImageFrame::SetupForContentURLRequest() {
return;
}
// We're not using nsStyleImageRequest, so manually track the image.
PresContext()->Document()->ImageTracker()->Add(mContentURLRequest);
uint32_t status = 0;
nsresult rv = mContentURLRequest->GetImageStatus(&status);
if (NS_FAILED(rv)) {

View File

@ -1504,16 +1504,16 @@ CounterStyle* CustomCounterStyle::GetExtendsRoot() {
AnonymousCounterStyle::AnonymousCounterStyle(const nsAString& aContent)
: CounterStyle(NS_STYLE_LIST_STYLE_CUSTOM),
mSingleString(true),
mSystem(NS_STYLE_COUNTER_SYSTEM_CYCLIC) {
mSymbolsType(StyleSymbolsType::Cyclic) {
mSymbols.SetCapacity(1);
mSymbols.AppendElement(aContent);
}
AnonymousCounterStyle::AnonymousCounterStyle(uint8_t aSystem,
AnonymousCounterStyle::AnonymousCounterStyle(StyleSymbolsType aType,
nsTArray<nsString> aSymbols)
: CounterStyle(NS_STYLE_LIST_STYLE_CUSTOM),
mSingleString(false),
mSystem(aSystem),
mSymbolsType(aType),
mSymbols(std::move(aSymbols)) {}
/* virtual */
@ -1532,13 +1532,8 @@ void AnonymousCounterStyle::GetSuffix(nsAString& aResult) {
/* virtual */
bool AnonymousCounterStyle::IsBullet() {
switch (mSystem) {
case NS_STYLE_COUNTER_SYSTEM_CYCLIC:
// Only use ::-moz-list-bullet for cyclic system
return true;
default:
return false;
}
// Only use ::-moz-list-bullet for cyclic system
return mSymbolsType == StyleSymbolsType::Cyclic;
}
/* virtual */
@ -1549,13 +1544,13 @@ void AnonymousCounterStyle::GetNegative(NegativeType& aResult) {
/* virtual */
bool AnonymousCounterStyle::IsOrdinalInRange(CounterValue aOrdinal) {
switch (mSystem) {
case NS_STYLE_COUNTER_SYSTEM_CYCLIC:
case NS_STYLE_COUNTER_SYSTEM_NUMERIC:
case NS_STYLE_COUNTER_SYSTEM_FIXED:
switch (mSymbolsType) {
case StyleSymbolsType::Cyclic:
case StyleSymbolsType::Numeric:
case StyleSymbolsType::Fixed:
return true;
case NS_STYLE_COUNTER_SYSTEM_ALPHABETIC:
case NS_STYLE_COUNTER_SYSTEM_SYMBOLIC:
case StyleSymbolsType::Alphabetic:
case StyleSymbolsType::Symbolic:
return aOrdinal >= 1;
default:
MOZ_ASSERT_UNREACHABLE("Invalid system.");
@ -1579,14 +1574,31 @@ CounterStyle* AnonymousCounterStyle::GetFallback() {
return CounterStyleManager::GetDecimalStyle();
}
uint8_t AnonymousCounterStyle::GetSystem() const {
switch (mSymbolsType) {
case StyleSymbolsType::Cyclic:
return NS_STYLE_COUNTER_SYSTEM_CYCLIC;
case StyleSymbolsType::Numeric:
return NS_STYLE_COUNTER_SYSTEM_NUMERIC;
case StyleSymbolsType::Fixed:
return NS_STYLE_COUNTER_SYSTEM_FIXED;
case StyleSymbolsType::Alphabetic:
return NS_STYLE_COUNTER_SYSTEM_ALPHABETIC;
case StyleSymbolsType::Symbolic:
return NS_STYLE_COUNTER_SYSTEM_SYMBOLIC;
}
MOZ_ASSERT_UNREACHABLE("Unknown symbols() type");
return NS_STYLE_COUNTER_SYSTEM_CYCLIC;
}
/* virtual */
uint8_t AnonymousCounterStyle::GetSpeakAs() {
return GetDefaultSpeakAsForSystem(mSystem);
return GetDefaultSpeakAsForSystem(GetSystem());
}
/* virtual */
bool AnonymousCounterStyle::UseNegativeSign() {
return SystemUsesNegativeSign(mSystem);
return SystemUsesNegativeSign(GetSystem());
}
/* virtual */
@ -1594,21 +1606,20 @@ bool AnonymousCounterStyle::GetInitialCounterText(CounterValue aOrdinal,
WritingMode aWritingMode,
nsAString& aResult,
bool& aIsRTL) {
switch (mSystem) {
case NS_STYLE_COUNTER_SYSTEM_CYCLIC:
switch (mSymbolsType) {
case StyleSymbolsType::Cyclic:
return GetCyclicCounterText(aOrdinal, aResult, mSymbols);
case NS_STYLE_COUNTER_SYSTEM_FIXED:
return GetFixedCounterText(aOrdinal, aResult, 1, mSymbols);
case NS_STYLE_COUNTER_SYSTEM_SYMBOLIC:
return GetSymbolicCounterText(aOrdinal, aResult, mSymbols);
case NS_STYLE_COUNTER_SYSTEM_ALPHABETIC:
return GetAlphabeticCounterText(aOrdinal, aResult, mSymbols);
case NS_STYLE_COUNTER_SYSTEM_NUMERIC:
case StyleSymbolsType::Numeric:
return GetNumericCounterText(aOrdinal, aResult, mSymbols);
default:
MOZ_ASSERT_UNREACHABLE("Invalid system.");
return false;
case StyleSymbolsType::Fixed:
return GetFixedCounterText(aOrdinal, aResult, 1, mSymbols);
case StyleSymbolsType::Alphabetic:
return GetAlphabeticCounterText(aOrdinal, aResult, mSymbols);
case StyleSymbolsType::Symbolic:
return GetSymbolicCounterText(aOrdinal, aResult, mSymbols);
}
MOZ_ASSERT_UNREACHABLE("Invalid system.");
return false;
}
bool CounterStyle::IsDependentStyle() const {

View File

@ -93,7 +93,7 @@ class CounterStyle {
class AnonymousCounterStyle final : public CounterStyle {
public:
explicit AnonymousCounterStyle(const nsAString& aContent);
AnonymousCounterStyle(uint8_t aSystem, nsTArray<nsString> aSymbols);
AnonymousCounterStyle(StyleSymbolsType, nsTArray<nsString> aSymbols);
virtual void GetPrefix(nsAString& aResult) override;
virtual void GetSuffix(nsAString& aResult) override;
@ -114,16 +114,17 @@ class AnonymousCounterStyle final : public CounterStyle {
virtual AnonymousCounterStyle* AsAnonymous() override { return this; }
bool IsSingleString() const { return mSingleString; }
uint8_t GetSystem() const { return mSystem; }
Span<const nsString> GetSymbols() const { return MakeSpan(mSymbols); }
uint8_t GetSystem() const;
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AnonymousCounterStyle)
private:
~AnonymousCounterStyle() {}
bool mSingleString;
uint8_t mSystem;
StyleSymbolsType mSymbolsType;
nsTArray<nsString> mSymbols;
};
@ -192,6 +193,26 @@ class CounterStylePtr {
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 {

View File

@ -1076,19 +1076,13 @@ void Gecko_FontWeight_SetFloat(FontWeight* aWeight, float aFloat) {
*aWeight = FontWeight(aFloat);
}
void Gecko_SetCounterStyleToName(CounterStylePtr* aPtr, nsAtom* aName) {
RefPtr<nsAtom> name = already_AddRefed<nsAtom>(aName);
*aPtr = name.forget();
void Gecko_CounterStyle_ToPtr(const StyleCounterStyle* aStyle,
CounterStylePtr* aPtr) {
*aPtr = CounterStylePtr::FromStyle(*aStyle);
}
void Gecko_SetCounterStyleToSymbols(CounterStylePtr* aPtr, uint8_t aSymbolsType,
nsACString const* const* aSymbols,
uint32_t aSymbolsCount) {
nsTArray<nsString> symbols(aSymbolsCount);
for (uint32_t i = 0; i < aSymbolsCount; i++) {
symbols.AppendElement(NS_ConvertUTF8toUTF16(*aSymbols[i]));
}
*aPtr = new AnonymousCounterStyle(aSymbolsType, std::move(symbols));
void Gecko_SetCounterStyleToNone(CounterStylePtr* aPtr) {
*aPtr = nsGkAtoms::none;
}
void Gecko_SetCounterStyleToString(CounterStylePtr* aPtr,
@ -1173,23 +1167,6 @@ void Gecko_CopyCursorArrayFrom(nsStyleUI* aDest, const nsStyleUI* aSrc) {
aDest->mCursorImages = aSrc->mCursorImages;
}
void Gecko_SetContentDataImageValue(nsStyleContentData* aContent,
const StyleComputedImageUrl* aUrl) {
MOZ_ASSERT(aContent && aUrl);
RefPtr<nsStyleImageRequest> req =
CreateStyleImageRequest(nsStyleImageRequest::Mode::Track, aUrl);
aContent->SetImageRequest(req.forget());
}
nsStyleContentData::CounterFunction* Gecko_SetCounterFunction(
nsStyleContentData* aContent, StyleContentType aType) {
auto counterFunc = MakeRefPtr<nsStyleContentData::CounterFunction>();
auto* ptr = counterFunc.get();
aContent->SetCounters(aType, counterFunc.forget());
return ptr;
}
const nsStyleImageRequest* Gecko_GetImageRequest(const nsStyleImage* aImage) {
MOZ_ASSERT(aImage);
return aImage->ImageRequest();
@ -1245,22 +1222,6 @@ void Gecko_ResizeAtomArray(nsTArray<RefPtr<nsAtom>>* aArray, uint32_t aLength) {
aArray->SetLength(aLength);
}
void Gecko_ClearAndResizeStyleContents(nsStyleContent* aContent,
uint32_t aHowMany) {
aContent->AllocateContents(aHowMany);
}
void Gecko_CopyStyleContentsFrom(nsStyleContent* aContent,
const nsStyleContent* aOther) {
uint32_t count = aOther->ContentCount();
aContent->AllocateContents(count);
for (uint32_t i = 0; i < count; ++i) {
aContent->ContentAt(i) = aOther->ContentAt(i);
}
}
void Gecko_EnsureImageLayersLength(nsStyleImageLayers* aLayers, size_t aLen,
nsStyleImageLayers::LayerType aLayerType) {
size_t oldLength = aLayers->mLayers.Length();

View File

@ -320,13 +320,10 @@ void Gecko_CopyImageOrientationFrom(nsStyleVisibility* aDst,
const nsStyleVisibility* aSrc);
// Counter style.
// This function takes an already addrefed nsAtom
void Gecko_SetCounterStyleToName(mozilla::CounterStylePtr* ptr, nsAtom* name);
void Gecko_CounterStyle_ToPtr(const mozilla::StyleCounterStyle*,
mozilla::CounterStylePtr*);
void Gecko_SetCounterStyleToSymbols(mozilla::CounterStylePtr* ptr,
uint8_t symbols_type,
nsACString const* const* symbols,
uint32_t symbols_count);
void Gecko_SetCounterStyleToNone(mozilla::CounterStylePtr*);
void Gecko_SetCounterStyleToString(mozilla::CounterStylePtr* ptr,
const nsACString* symbol);
@ -371,12 +368,6 @@ void Gecko_SetCursorImageValue(nsCursorImage* aCursor,
void Gecko_CopyCursorArrayFrom(nsStyleUI* dest, const nsStyleUI* src);
void Gecko_SetContentDataImageValue(nsStyleContentData* aList,
const mozilla::StyleComputedImageUrl* url);
nsStyleContentData::CounterFunction* Gecko_SetCounterFunction(
nsStyleContentData* content_data, mozilla::StyleContentType);
// Dirtiness tracking.
void Gecko_SetNodeFlags(const nsINode* node, uint32_t flags);
void Gecko_UnsetNodeFlags(const nsINode* node, uint32_t flags);
@ -421,14 +412,6 @@ void Gecko_ClearPODTArray(void* array, size_t elem_size, size_t elem_align);
void Gecko_ResizeTArrayForStrings(nsTArray<nsString>* array, uint32_t length);
void Gecko_ResizeAtomArray(nsTArray<RefPtr<nsAtom>>* array, uint32_t length);
// Clear the mContents, mCounterIncrements, mCounterResets, or mCounterSets
// field in nsStyleContent. This is needed to run the destructors, otherwise
// we'd leak the images, strings, and whatnot.
void Gecko_ClearAndResizeStyleContents(nsStyleContent* content,
uint32_t how_many);
void Gecko_CopyStyleContentsFrom(nsStyleContent* content,
const nsStyleContent* other);
void Gecko_EnsureImageLayersLength(nsStyleImageLayers* layers, size_t len,
nsStyleImageLayers::LayerType layer_type);

View File

@ -68,7 +68,6 @@ rusty-enums = [
"mozilla::InheritTarget",
"mozilla::css::DocumentMatchingFunction",
"mozilla::css::SheetParsingMode",
"mozilla::StyleContentType",
"nsStyleSVGOpacitySource",
"nsCSSKeyword",
"mozilla::dom::Document_DocumentTheme",
@ -543,6 +542,9 @@ cbindgen-types = [
{ gecko = "StyleClipRectOrAuto", servo = "values::computed::ClipRectOrAuto" },
{ gecko = "StyleCounterSetOrReset", servo = "values::computed::CounterSetOrReset" },
{ gecko = "StyleCounterIncrement", servo = "values::computed::CounterIncrement" },
{ gecko = "StyleContent", servo = "values::computed::counters::Content" },
{ gecko = "StyleSymbolsType", servo = "values::generics::SymbolsType" },
{ gecko = "StyleCounterStyle", servo = "values::generics::CounterStyle" },
]
mapped-generic-types = [

View File

@ -87,7 +87,6 @@ class SharedFontList;
class StyleSheet;
class WritingMode;
class ServoElementSnapshotTable;
enum class StyleContentType : uint8_t;
template <typename T>
struct StyleForgottenArcSlicePtr;

View File

@ -186,21 +186,6 @@ enum class StyleColumnSpan : uint8_t {
All,
};
// Counters and generated content.
enum class StyleContentType : uint8_t {
String = 1,
Image = 10,
Attr = 20,
Counter = 30,
Counters = 31,
OpenQuote = 40,
CloseQuote = 41,
NoOpenQuote = 42,
NoCloseQuote = 43,
AltContent = 50,
Uninitialized,
};
// Define geometry box for clip-path's reference-box, background-clip,
// background-origin, mask-clip, mask-origin, shape-box and transform-box.
enum class StyleGeometryBox : uint8_t {
@ -348,15 +333,6 @@ enum class StyleBorderCollapse : uint8_t { Collapse, Separate };
// border-image-repeat
enum class StyleBorderImageRepeat : uint8_t { Stretch, Repeat, Round, Space };
// See nsStyleContent
enum class StyleContent : uint8_t {
OpenQuote,
CloseQuote,
NoOpenQuote,
NoCloseQuote,
AltContent
};
// See nsStyleVisibility
#define NS_STYLE_DIRECTION_LTR 0
#define NS_STYLE_DIRECTION_RTL 1

View File

@ -122,9 +122,25 @@ already_AddRefed<nsIURI> StyleComputedUrl::ResolveLocalRef(
return ResolveLocalRef(aContent->GetBaseURI());
}
imgRequestProxy* StyleComputedUrl::LoadImage(Document& aDocument) {
already_AddRefed<imgRequestProxy> StyleComputedUrl::LoadImage(
Document& aDocument) {
MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread());
nsIURI* docURI = aDocument.GetDocumentURI();
if (HasRef()) {
bool isEqualExceptRef = false;
nsIURI* imageURI = GetURI();
if (!imageURI) {
return nullptr;
}
if (NS_SUCCEEDED(imageURI->EqualsExceptRef(docURI, &isEqualExceptRef)) &&
isEqualExceptRef) {
// Prevent loading an internal resource.
return nullptr;
}
}
static uint64_t sNextLoadID = 1;
StyleLoadData& data = LoadData();
@ -136,6 +152,7 @@ imgRequestProxy* StyleComputedUrl::LoadImage(Document& aDocument) {
// images from aDocument. Instead we do the image load from the original doc
// and clone it to aDocument.
Document* loadingDoc = aDocument.GetOriginalDocument();
const bool isPrint = !!loadingDoc;
if (!loadingDoc) {
loadingDoc = &aDocument;
}
@ -144,7 +161,17 @@ imgRequestProxy* StyleComputedUrl::LoadImage(Document& aDocument) {
css::ImageLoader::LoadImage(*this, *loadingDoc);
// Register the image in the document that's using it.
return aDocument.StyleImageLoader()->RegisterCSSImage(data);
imgRequestProxy* request =
aDocument.StyleImageLoader()->RegisterCSSImage(data);
if (!request) {
return nullptr;
}
if (!isPrint) {
return do_AddRef(request);
}
RefPtr<imgRequestProxy> ret;
request->GetStaticRequest(&aDocument, getter_AddRefs(ret));
return ret.forget();
}
// --------------------
@ -1577,28 +1604,13 @@ nsStyleImageRequest::~nsStyleImageRequest() {
MOZ_ASSERT(!mImageTracker);
}
bool nsStyleImageRequest::Resolve(Document& aDocument,
void nsStyleImageRequest::Resolve(Document& aDocument,
const nsStyleImageRequest* aOldImageRequest) {
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!IsResolved(), "already resolved");
mResolved = true;
nsIURI* docURI = aDocument.GetDocumentURI();
if (GetImageValue().HasRef()) {
bool isEqualExceptRef = false;
RefPtr<nsIURI> imageURI = GetImageURI();
if (!imageURI) {
return false;
}
if (NS_SUCCEEDED(imageURI->EqualsExceptRef(docURI, &isEqualExceptRef)) &&
isEqualExceptRef) {
// Prevent loading an internal resource.
return true;
}
}
// TODO(emilio, bug 1440442): This is a hackaround to avoid flickering due the
// lack of non-http image caching in imagelib (bug 1406134), which causes
// stuff like bug 1439285. Cleanest fix if that doesn't get fixed is bug
@ -1617,18 +1629,12 @@ bool nsStyleImageRequest::Resolve(Document& aDocument,
mRequestProxy = aOldImageRequest->mRequestProxy;
} else {
mDocGroup = aDocument.GetDocGroup();
imgRequestProxy* request = mImageURL.LoadImage(aDocument);
bool isPrint = !!aDocument.GetOriginalDocument();
if (!isPrint) {
mRequestProxy = request;
} else if (request) {
request->GetStaticRequest(&aDocument, getter_AddRefs(mRequestProxy));
}
mRequestProxy = mImageURL.LoadImage(aDocument);
}
if (!mRequestProxy) {
// The URL resolution or image load failed.
return false;
return;
}
// Boost priority now that we know the image is present in the ComputedStyle
@ -1640,7 +1646,6 @@ bool nsStyleImageRequest::Resolve(Document& aDocument,
}
MaybeTrackAndLock();
return true;
}
void nsStyleImageRequest::MaybeTrackAndLock() {
@ -3185,126 +3190,19 @@ nsChangeHint nsStyleVisibility::CalcDifference(
return hint;
}
nsStyleContentData::~nsStyleContentData() {
MOZ_COUNT_DTOR(nsStyleContentData);
if (mType == StyleContentType::Image) {
// FIXME(emilio): Is this needed now that URLs are not main thread only?
NS_ReleaseOnMainThreadSystemGroup("nsStyleContentData::mContent.mImage",
dont_AddRef(mContent.mImage));
mContent.mImage = nullptr;
} else if (mType == StyleContentType::Counter ||
mType == StyleContentType::Counters) {
mContent.mCounters->Release();
} else if (mType == StyleContentType::String) {
free(mContent.mString);
} else if (mType == StyleContentType::Attr) {
delete mContent.mAttr;
} else {
MOZ_ASSERT(mContent.mString == nullptr, "Leaking due to missing case");
}
}
nsStyleContentData::nsStyleContentData(const nsStyleContentData& aOther)
: mType(aOther.mType) {
MOZ_COUNT_CTOR(nsStyleContentData);
switch (mType) {
case StyleContentType::Image:
mContent.mImage = aOther.mContent.mImage;
mContent.mImage->AddRef();
break;
case StyleContentType::Counter:
case StyleContentType::Counters:
mContent.mCounters = aOther.mContent.mCounters;
mContent.mCounters->AddRef();
break;
case StyleContentType::Attr:
mContent.mAttr = new nsStyleContentAttr(*aOther.mContent.mAttr);
break;
case StyleContentType::String:
mContent.mString = NS_xstrdup(aOther.mContent.mString);
break;
default:
MOZ_ASSERT(!aOther.mContent.mString);
mContent.mString = nullptr;
}
}
bool nsStyleContentData::CounterFunction::operator==(
const CounterFunction& aOther) const {
return mIdent == aOther.mIdent && mSeparator == aOther.mSeparator &&
mCounterStyle == aOther.mCounterStyle;
}
nsStyleContentData& nsStyleContentData::operator=(
const nsStyleContentData& aOther) {
if (this == &aOther) {
return *this;
}
this->~nsStyleContentData();
new (this) nsStyleContentData(aOther);
return *this;
}
bool nsStyleContentData::operator==(const nsStyleContentData& aOther) const {
if (mType != aOther.mType) {
return false;
}
if (mType == StyleContentType::Image) {
return DefinitelyEqualImages(mContent.mImage, aOther.mContent.mImage);
}
if (mType == StyleContentType::Attr) {
return *mContent.mAttr == *aOther.mContent.mAttr;
}
if (mType == StyleContentType::Counter ||
mType == StyleContentType::Counters) {
return *mContent.mCounters == *aOther.mContent.mCounters;
}
if (mType == StyleContentType::String) {
return NS_strcmp(mContent.mString, aOther.mContent.mString) == 0;
}
MOZ_ASSERT(!mContent.mString && !aOther.mContent.mString);
return true;
}
void nsStyleContentData::Resolve(Document& aDocument,
const nsStyleContentData* aOldStyle) {
if (mType != StyleContentType::Image) {
return;
}
if (!mContent.mImage->IsResolved()) {
const nsStyleImageRequest* oldRequest =
(aOldStyle && aOldStyle->mType == StyleContentType::Image)
? aOldStyle->mContent.mImage
: nullptr;
mContent.mImage->Resolve(aDocument, oldRequest);
}
}
//-----------------------
// nsStyleContent
//
nsStyleContent::nsStyleContent(const Document& aDocument) {
nsStyleContent::nsStyleContent(const Document& aDocument)
: mContent(StyleContent::Normal()) {
MOZ_COUNT_CTOR(nsStyleContent);
}
nsStyleContent::~nsStyleContent() { MOZ_COUNT_DTOR(nsStyleContent); }
void nsStyleContent::TriggerImageLoads(Document& aDocument,
const nsStyleContent* aOldStyle) {
for (size_t i = 0; i < mContents.Length(); ++i) {
const nsStyleContentData* oldData =
(aOldStyle && aOldStyle->mContents.Length() > i)
? &aOldStyle->mContents[i]
: nullptr;
mContents[i].Resolve(aDocument, oldData);
}
}
nsStyleContent::nsStyleContent(const nsStyleContent& aSource)
: mContents(aSource.mContents),
: mContent(aSource.mContent),
mCounterIncrement(aSource.mCounterIncrement),
mCounterReset(aSource.mCounterReset),
mCounterSet(aSource.mCounterSet) {
@ -3316,7 +3214,7 @@ nsChangeHint nsStyleContent::CalcDifference(
// Unfortunately we need to reframe even if the content lengths are the same;
// a simple reflow will not pick up different text or different image URLs,
// since we set all that up in the CSSFrameConstructor
if (mContents != aNewData.mContents ||
if (mContent != aNewData.mContent ||
mCounterIncrement != aNewData.mCounterIncrement ||
mCounterReset != aNewData.mCounterReset ||
mCounterSet != aNewData.mCounterSet) {

View File

@ -181,7 +181,7 @@ class nsStyleImageRequest {
// on the main thread before get() can be used.
nsStyleImageRequest(Mode aModeFlags, const mozilla::StyleComputedImageUrl&);
bool Resolve(mozilla::dom::Document&,
void Resolve(mozilla::dom::Document&,
const nsStyleImageRequest* aOldImageRequest);
bool IsResolved() const { return mResolved; }
@ -1923,154 +1923,27 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleTableBorder {
uint8_t mEmptyCells;
};
struct nsStyleContentAttr {
RefPtr<nsAtom> mName; // Non-null.
RefPtr<nsAtom> mNamespaceURL; // May be null.
bool operator==(const nsStyleContentAttr& aOther) const {
return mName == aOther.mName && mNamespaceURL == aOther.mNamespaceURL;
}
};
class nsStyleContentData {
using StyleContentType = mozilla::StyleContentType;
public:
nsStyleContentData() : mType(StyleContentType::Uninitialized) {
MOZ_COUNT_CTOR(nsStyleContentData);
mContent.mString = nullptr;
}
nsStyleContentData(const nsStyleContentData&);
~nsStyleContentData();
nsStyleContentData& operator=(const nsStyleContentData& aOther);
bool operator==(const nsStyleContentData& aOther) const;
bool operator!=(const nsStyleContentData& aOther) const {
return !(*this == aOther);
}
StyleContentType GetType() const { return mType; }
char16_t* GetString() const {
MOZ_ASSERT(mType == StyleContentType::String);
return mContent.mString;
}
const nsStyleContentAttr* GetAttr() const {
MOZ_ASSERT(mType == StyleContentType::Attr);
MOZ_ASSERT(mContent.mAttr);
return mContent.mAttr;
}
struct CounterFunction {
RefPtr<nsAtom> mIdent;
// This is only used when it is a counters() function.
nsString mSeparator;
mozilla::CounterStylePtr mCounterStyle;
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CounterFunction)
bool operator==(const CounterFunction& aOther) const;
bool operator!=(const CounterFunction& aOther) const {
return !(*this == aOther);
}
private:
~CounterFunction() {}
};
CounterFunction* GetCounters() const {
MOZ_ASSERT(mType == StyleContentType::Counter ||
mType == StyleContentType::Counters);
return mContent.mCounters;
}
nsStyleImageRequest* ImageRequest() const {
MOZ_ASSERT(mType == StyleContentType::Image);
MOZ_ASSERT(mContent.mImage);
return mContent.mImage;
}
imgRequestProxy* GetImage() const { return ImageRequest()->get(); }
void SetCounters(StyleContentType aType,
already_AddRefed<CounterFunction> aCounterFunction) {
MOZ_ASSERT(aType == StyleContentType::Counter ||
aType == StyleContentType::Counters);
MOZ_ASSERT(mType == StyleContentType::Uninitialized,
"should only initialize nsStyleContentData once");
mType = aType;
mContent.mCounters = aCounterFunction.take();
MOZ_ASSERT(mContent.mCounters);
}
void SetImageRequest(already_AddRefed<nsStyleImageRequest> aRequest) {
MOZ_ASSERT(mType == StyleContentType::Uninitialized,
"should only initialize nsStyleContentData once");
mType = StyleContentType::Image;
mContent.mImage = aRequest.take();
MOZ_ASSERT(mContent.mImage);
}
void Resolve(mozilla::dom::Document&, const nsStyleContentData*);
private:
StyleContentType mType;
union {
char16_t* mString;
nsStyleContentAttr* mAttr;
nsStyleImageRequest* mImage;
CounterFunction* mCounters;
} mContent;
};
struct nsStyleCounterData {
RefPtr<nsAtom> mCounter;
int32_t mValue;
bool operator==(const nsStyleCounterData& aOther) const {
return mValue == aOther.mValue && mCounter == aOther.mCounter;
}
bool operator!=(const nsStyleCounterData& aOther) const {
return !(*this == aOther);
}
};
struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleContent {
using CounterPair = mozilla::StyleGenericCounterPair<int32_t>;
explicit nsStyleContent(const mozilla::dom::Document&);
nsStyleContent(const nsStyleContent& aContent);
~nsStyleContent();
void TriggerImageLoads(mozilla::dom::Document&, const nsStyleContent*);
const static bool kHasTriggerImageLoads = true;
void TriggerImageLoads(mozilla::dom::Document&, const nsStyleContent*) {}
const static bool kHasTriggerImageLoads = false;
size_t ContentCount() const {
return mContent.IsItems() ? mContent.AsItems().Length() : 0;
}
const mozilla::StyleContentItem& ContentAt(size_t aIndex) const {
return mContent.AsItems().AsSpan()[aIndex];
}
nsChangeHint CalcDifference(const nsStyleContent& aNewData) const;
uint32_t ContentCount() const { return mContents.Length(); }
const nsStyleContentData& ContentAt(uint32_t aIndex) const {
return mContents[aIndex];
}
nsStyleContentData& ContentAt(uint32_t aIndex) { return mContents[aIndex]; }
void AllocateContents(uint32_t aCount) {
// We need to run the destructors of the elements of mContents, so we
// delete and reallocate even if aCount == mContentCount. (If
// nsStyleContentData had its members private and managed their
// ownership on setting, we wouldn't need this, but that seems
// unnecessary at this point.)
mContents.Clear();
mContents.SetLength(aCount);
}
protected:
nsTArray<nsStyleContentData> mContents;
public:
mozilla::StyleContent mContent;
mozilla::StyleCounterIncrement mCounterIncrement;
mozilla::StyleCounterSetOrReset mCounterReset;
mozilla::StyleCounterSetOrReset mCounterSet;

View File

@ -5285,7 +5285,7 @@ var gCSSProperties = {
inherited: false,
type: CSS_TYPE_LONGHAND,
applies_to_marker: true,
/* XXX needs to be on pseudo-elements */
// XXX This really depends on pseudo-element-ness.
initial_values: ["normal", "none"],
other_values: [
'""',

View File

@ -409,6 +409,7 @@ impl ToCss for System {
/// <https://drafts.csswg.org/css-counter-styles/#typedef-symbol>
#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, ToComputedValue, ToCss, ToShmem)]
#[repr(u8)]
pub enum Symbol {
/// <string>
String(crate::OwnedStr),
@ -554,6 +555,7 @@ impl Parse for Fallback {
/// <https://drafts.csswg.org/css-counter-styles/#descdef-counter-style-symbols>
#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, ToComputedValue, ToCss, ToShmem)]
#[repr(C)]
pub struct Symbols(#[css(iterable)] pub crate::OwnedSlice<Symbol>);
impl Parse for Symbols {

View File

@ -7,13 +7,13 @@
//! Different kind of helpers to interact with Gecko values.
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;
use app_units::Au;
use cssparser::RGBA;
use nsstring::{nsACString, nsCStr};
use std::cmp::max;
/// Convert a given RGBA value to `nscolor`.
@ -51,43 +51,13 @@ pub fn round_border_to_device_pixels(width: Au, au_per_device_px: Au) -> Au {
impl CounterStyle {
/// Convert this counter style to a Gecko CounterStylePtr.
pub fn to_gecko_value(self, gecko_value: &mut CounterStylePtr) {
use crate::gecko_bindings::bindings::Gecko_SetCounterStyleToName as set_name;
use crate::gecko_bindings::bindings::Gecko_SetCounterStyleToSymbols as set_symbols;
match self {
CounterStyle::Name(name) => unsafe {
debug_assert_ne!(name.0, atom!("none"));
set_name(gecko_value, name.0.into_addrefed());
},
CounterStyle::Symbols(symbols_type, symbols) => {
let symbols: Vec<_> = symbols
.0
.iter()
.map(|symbol| match *symbol {
Symbol::String(ref s) => nsCStr::from(&**s),
Symbol::Ident(_) => unreachable!("Should not have identifier in symbols()"),
})
.collect();
let symbols: Vec<_> = symbols
.iter()
.map(|symbol| symbol as &nsACString as *const _)
.collect();
unsafe {
set_symbols(
gecko_value,
symbols_type.to_gecko_keyword(),
symbols.as_ptr(),
symbols.len() as u32,
)
};
},
}
#[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::gecko_bindings::bindings;
use crate::values::generics::SymbolsType;
use crate::values::CustomIdent;
let name = unsafe { bindings::Gecko_CounterStyle_GetName(gecko_value) };
@ -103,7 +73,7 @@ impl CounterStyle {
debug_assert_eq!(symbols.len(), 1);
Either::Second(symbols[0].to_string())
} else {
let symbol_type = SymbolsType::from_gecko_keyword(anonymous.mSystem as u32);
let symbol_type = anonymous.mSymbolsType;
let symbols = symbols
.iter()
.map(|gecko_symbol| Symbol::String(gecko_symbol.to_string().into()))

View File

@ -25,6 +25,7 @@ macro_rules! ns {
/// A Gecko namespace is just a wrapped atom.
#[derive(Clone, Debug, Default, Eq, Hash, MallocSizeOf, PartialEq, ToShmem)]
#[repr(transparent)]
pub struct Namespace(pub Atom);
impl PrecomputedHash for Namespace {

View File

@ -173,10 +173,12 @@ pub mod values;
pub use crate::gecko_string_cache as string_cache;
#[cfg(feature = "gecko")]
pub use crate::gecko_string_cache::Atom;
/// The namespace prefix type for Gecko, which is just an atom.
#[cfg(feature = "gecko")]
pub use crate::gecko_string_cache::Atom as Prefix;
pub type Prefix = crate::gecko_string_cache::Atom;
/// The local name of an element for Gecko, which is just an atom.
#[cfg(feature = "gecko")]
pub use crate::gecko_string_cache::Atom as LocalName;
pub type LocalName = crate::gecko_string_cache::Atom;
#[cfg(feature = "gecko")]
pub use crate::gecko_string_cache::Namespace;

View File

@ -36,7 +36,6 @@ use crate::gecko_bindings::bindings::Gecko_SetNullImageValue;
use crate::gecko_bindings::structs;
use crate::gecko_bindings::structs::nsCSSPropertyID;
use crate::gecko_bindings::structs::mozilla::PseudoStyleType;
use crate::gecko_bindings::sugar::refptr::RefPtr;
use crate::gecko::values::round_border_to_device_pixels;
use crate::logical_geometry::WritingMode;
use crate::media_queries::Device;
@ -45,7 +44,6 @@ use crate::properties::longhands;
use crate::rule_tree::StrongRuleNode;
use crate::selector_parser::PseudoElement;
use servo_arc::{Arc, RawOffsetArc, UniqueArc};
use std::marker::PhantomData;
use std::mem::{forget, MaybeUninit};
use std::{cmp, ops, ptr};
use crate::values::{self, CustomIdent, Either, KeyframesName, None_};
@ -2200,19 +2198,18 @@ fn static_assert() {
}
pub fn set_list_style_type(&mut self, v: longhands::list_style_type::computed_value::T) {
use crate::gecko_bindings::bindings::Gecko_SetCounterStyleToName;
use crate::gecko_bindings::bindings::Gecko_SetCounterStyleToString;
use nsstring::{nsACString, nsCStr};
use self::longhands::list_style_type::computed_value::T;
match v {
T::None => unsafe {
Gecko_SetCounterStyleToName(&mut self.gecko.mCounterStyle,
atom!("none").into_addrefed());
bindings::Gecko_SetCounterStyleToNone(&mut self.gecko.mCounterStyle)
}
T::CounterStyle(s) => s.to_gecko_value(&mut self.gecko.mCounterStyle),
T::String(s) => unsafe {
Gecko_SetCounterStyleToString(&mut self.gecko.mCounterStyle,
&nsCStr::from(&s) as &nsACString)
bindings::Gecko_SetCounterStyleToString(
&mut self.gecko.mCounterStyle,
&nsCStr::from(&s) as &nsACString,
)
}
}
}
@ -2580,236 +2577,9 @@ clip-path
${impl_simple('column_rule_style', 'mColumnRuleStyle')}
</%self:impl_trait>
<%self:impl_trait style_struct_name="Counters" skip_longhands="content">
<%self:impl_trait style_struct_name="Counters">
pub fn ineffective_content_property(&self) -> bool {
self.gecko.mContents.is_empty()
}
pub fn set_content(&mut self, v: longhands::content::computed_value::T) {
use crate::values::CustomIdent;
use crate::values::generics::counters::{Content, ContentItem};
use crate::values::generics::CounterStyle;
use crate::gecko_bindings::structs::nsStyleContentData;
use crate::gecko_bindings::structs::nsStyleContentAttr;
use crate::gecko_bindings::structs::StyleContentType;
use crate::gecko_bindings::bindings::Gecko_ClearAndResizeStyleContents;
// Converts a string as utf16, and returns an owned, zero-terminated raw buffer.
fn as_utf16_and_forget(s: &str) -> *mut u16 {
use std::mem;
let mut vec = s.encode_utf16().collect::<Vec<_>>();
vec.push(0u16);
let ptr = vec.as_mut_ptr();
mem::forget(vec);
ptr
}
fn set_counter_function(
data: &mut nsStyleContentData,
content_type: StyleContentType,
name: CustomIdent,
sep: &str,
style: CounterStyle,
) {
debug_assert!(content_type == StyleContentType::Counter ||
content_type == StyleContentType::Counters);
let counter_func = unsafe {
bindings::Gecko_SetCounterFunction(data, content_type).as_mut().unwrap()
};
counter_func.mIdent.set_move(unsafe {
RefPtr::from_addrefed(name.0.into_addrefed())
});
if content_type == StyleContentType::Counters {
counter_func.mSeparator.assign_str(sep);
}
style.to_gecko_value(&mut counter_func.mCounterStyle);
}
match v {
Content::None |
Content::Normal => {
// Ensure destructors run, otherwise we could leak.
if !self.gecko.mContents.is_empty() {
unsafe {
Gecko_ClearAndResizeStyleContents(&mut *self.gecko, 0);
}
}
},
Content::MozAltContent => {
unsafe {
Gecko_ClearAndResizeStyleContents(&mut *self.gecko, 1);
*self.gecko.mContents[0].mContent.mString.as_mut() = ptr::null_mut();
}
self.gecko.mContents[0].mType = StyleContentType::AltContent;
},
Content::Items(items) => {
unsafe {
Gecko_ClearAndResizeStyleContents(&mut *self.gecko,
items.len() as u32);
}
for (i, item) in items.into_vec().into_iter().enumerate() {
// NB: Gecko compares the mString value if type is not image
// or URI independently of whatever gets there. In the quote
// cases, they set it to null, so do the same here.
unsafe {
*self.gecko.mContents[i].mContent.mString.as_mut() = ptr::null_mut();
}
match item {
ContentItem::String(ref value) => {
self.gecko.mContents[i].mType = StyleContentType::String;
unsafe {
// NB: we share allocators, so doing this is fine.
*self.gecko.mContents[i].mContent.mString.as_mut() =
as_utf16_and_forget(&value);
}
}
ContentItem::Attr(ref attr) => {
self.gecko.mContents[i].mType = StyleContentType::Attr;
unsafe {
// NB: we share allocators, so doing this is fine.
let maybe_ns = attr.namespace.clone();
let attr_struct = Box::new(nsStyleContentAttr {
mName: structs::RefPtr {
mRawPtr: attr.attribute.clone().into_addrefed(),
_phantom_0: PhantomData,
},
mNamespaceURL: structs::RefPtr {
mRawPtr: maybe_ns.map_or(ptr::null_mut(), |x| (x.1).0.into_addrefed()),
_phantom_0: PhantomData,
},
});
*self.gecko.mContents[i].mContent.mAttr.as_mut() =
Box::into_raw(attr_struct);
}
}
ContentItem::OpenQuote
=> self.gecko.mContents[i].mType = StyleContentType::OpenQuote,
ContentItem::CloseQuote
=> self.gecko.mContents[i].mType = StyleContentType::CloseQuote,
ContentItem::NoOpenQuote
=> self.gecko.mContents[i].mType = StyleContentType::NoOpenQuote,
ContentItem::NoCloseQuote
=> self.gecko.mContents[i].mType = StyleContentType::NoCloseQuote,
ContentItem::Counter(name, style) => {
set_counter_function(
&mut self.gecko.mContents[i],
StyleContentType::Counter,
name,
"",
style,
);
}
ContentItem::Counters(name, sep, style) => {
set_counter_function(
&mut self.gecko.mContents[i],
StyleContentType::Counters,
name,
&sep,
style,
);
}
ContentItem::Url(ref url) => {
unsafe {
bindings::Gecko_SetContentDataImageValue(
&mut self.gecko.mContents[i],
url,
)
}
}
}
}
}
}
}
pub fn copy_content_from(&mut self, other: &Self) {
use crate::gecko_bindings::bindings::Gecko_CopyStyleContentsFrom;
unsafe {
Gecko_CopyStyleContentsFrom(&mut *self.gecko, &*other.gecko)
}
}
pub fn reset_content(&mut self, other: &Self) {
self.copy_content_from(other)
}
pub fn clone_content(&self) -> longhands::content::computed_value::T {
use {Atom, Namespace};
use crate::gecko::conversions::string_from_chars_pointer;
use crate::gecko_bindings::structs::StyleContentType;
use crate::values::generics::counters::{Content, ContentItem};
use crate::values::{CustomIdent, Either};
use crate::values::generics::CounterStyle;
use crate::values::specified::Attr;
if self.gecko.mContents.is_empty() {
return Content::None;
}
if self.gecko.mContents.len() == 1 &&
self.gecko.mContents[0].mType == StyleContentType::AltContent {
return Content::MozAltContent;
}
Content::Items(
self.gecko.mContents.iter().map(|gecko_content| {
match gecko_content.mType {
StyleContentType::OpenQuote => ContentItem::OpenQuote,
StyleContentType::CloseQuote => ContentItem::CloseQuote,
StyleContentType::NoOpenQuote => ContentItem::NoOpenQuote,
StyleContentType::NoCloseQuote => ContentItem::NoCloseQuote,
StyleContentType::String => {
let gecko_chars = unsafe { gecko_content.mContent.mString.as_ref() };
let string = unsafe { string_from_chars_pointer(*gecko_chars) };
ContentItem::String(string.into_boxed_str())
},
StyleContentType::Attr => {
let (namespace, attribute) = unsafe {
let s = &**gecko_content.mContent.mAttr.as_ref();
let ns = if s.mNamespaceURL.mRawPtr.is_null() {
None
} else {
// FIXME(bholley): We don't have any way to get the prefix here. :-(
let prefix = atom!("");
Some((prefix, Namespace(Atom::from_raw(s.mNamespaceURL.mRawPtr))))
};
(ns, Atom::from_raw(s.mName.mRawPtr))
};
ContentItem::Attr(Attr { namespace, attribute })
},
StyleContentType::Counter | StyleContentType::Counters => {
let gecko_function =
unsafe { &**gecko_content.mContent.mCounters.as_ref() };
let ident = CustomIdent(unsafe {
Atom::from_raw(gecko_function.mIdent.mRawPtr)
});
let style =
CounterStyle::from_gecko_value(&gecko_function.mCounterStyle);
let style = match style {
Either::First(counter_style) => counter_style,
Either::Second(_) =>
unreachable!("counter function shouldn't have single string type"),
};
if gecko_content.mType == StyleContentType::Counter {
ContentItem::Counter(ident, style)
} else {
let separator = gecko_function.mSeparator.to_string();
ContentItem::Counters(ident, separator.into_boxed_str(), style)
}
},
StyleContentType::Image => {
unsafe {
let gecko_image_request =
&**gecko_content.mContent.mImage.as_ref();
ContentItem::Url(
ComputedImageUrl::from_image_request(gecko_image_request)
)
}
},
_ => panic!("Found unexpected value in style struct for content property"),
}
}).collect::<Vec<_>>().into_boxed_slice()
)
!self.gecko.mContent.is_items()
}
</%self:impl_trait>

View File

@ -16,7 +16,7 @@ pub type CounterIncrement = GenericCounterIncrement<i32>;
pub type CounterSetOrReset = GenericCounterSetOrReset<i32>;
/// A computed value for the `content` property.
pub type Content = generics::Content<ComputedImageUrl>;
pub type Content = generics::GenericContent<ComputedImageUrl>;
/// A computed content item.
pub type ContentItem = generics::ContentItem<ComputedImageUrl>;
pub type ContentItem = generics::GenericContentItem<ComputedImageUrl>;

View File

@ -471,6 +471,7 @@ trivial_to_computed_value!(Atom);
trivial_to_computed_value!(Prefix);
trivial_to_computed_value!(String);
trivial_to_computed_value!(Box<str>);
trivial_to_computed_value!(crate::OwnedStr);
/// A `<number>` value.
pub type Number = CSSFloat;

View File

@ -153,22 +153,26 @@ fn is_decimal(counter_type: &CounterStyleType) -> bool {
SpecifiedValueInfo,
ToComputedValue,
ToCss,
ToResolvedValue,
ToShmem,
)]
pub enum Content<ImageUrl> {
#[repr(u8)]
pub enum GenericContent<ImageUrl> {
/// `normal` reserved keyword.
Normal,
/// `none` reserved keyword.
None,
/// `-moz-alt-content`.
#[cfg(feature = "gecko")]
MozAltContent,
/// Content items.
Items(#[css(iterable)] Box<[ContentItem<ImageUrl>]>),
Items(#[css(iterable)] crate::OwnedSlice<GenericContentItem<ImageUrl>>),
}
pub use self::GenericContent as Content;
impl<ImageUrl> Content<ImageUrl> {
#[inline]
pub(crate) fn is_items(&self) -> bool {
matches!(*self, Self::Items(..))
}
/// Set `content` property to `normal`.
#[inline]
pub fn normal() -> Self {
@ -189,9 +193,10 @@ impl<ImageUrl> Content<ImageUrl> {
ToResolvedValue,
ToShmem,
)]
pub enum ContentItem<ImageUrl> {
#[repr(u8)]
pub enum GenericContentItem<ImageUrl> {
/// Literal string content.
String(Box<str>),
String(crate::OwnedStr),
/// `counter(name, style)`.
#[css(comma, function)]
Counter(CustomIdent, #[css(skip_if = "is_decimal")] CounterStyleType),
@ -199,7 +204,7 @@ pub enum ContentItem<ImageUrl> {
#[css(comma, function)]
Counters(
CustomIdent,
Box<str>,
crate::OwnedStr,
#[css(skip_if = "is_decimal")] CounterStyleType,
),
/// `open-quote`.
@ -210,9 +215,14 @@ pub enum ContentItem<ImageUrl> {
NoOpenQuote,
/// `no-close-quote`.
NoCloseQuote,
/// `-moz-alt-content`.
#[cfg(feature = "gecko")]
MozAltContent,
/// `attr([namespace? `|`]? ident)`
#[cfg(feature = "gecko")]
Attr(Attr),
/// `url(url)`
Url(ImageUrl),
}
pub use self::GenericContentItem as ContentItem;

View File

@ -39,7 +39,7 @@ pub mod transform;
pub mod ui;
pub mod url;
// https://drafts.csswg.org/css-counter-styles/#typedef-symbols-type
/// https://drafts.csswg.org/css-counter-styles/#typedef-symbols-type
#[allow(missing_docs)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[derive(
@ -55,6 +55,7 @@ pub mod url;
ToResolvedValue,
ToShmem,
)]
#[repr(u8)]
pub enum SymbolsType {
Cyclic,
Numeric,
@ -63,39 +64,12 @@ pub enum SymbolsType {
Fixed,
}
#[cfg(feature = "gecko")]
impl SymbolsType {
/// Convert symbols type to their corresponding Gecko values.
pub fn to_gecko_keyword(self) -> u8 {
use crate::gecko_bindings::structs;
match self {
SymbolsType::Cyclic => structs::NS_STYLE_COUNTER_SYSTEM_CYCLIC as u8,
SymbolsType::Numeric => structs::NS_STYLE_COUNTER_SYSTEM_NUMERIC as u8,
SymbolsType::Alphabetic => structs::NS_STYLE_COUNTER_SYSTEM_ALPHABETIC as u8,
SymbolsType::Symbolic => structs::NS_STYLE_COUNTER_SYSTEM_SYMBOLIC as u8,
SymbolsType::Fixed => structs::NS_STYLE_COUNTER_SYSTEM_FIXED as u8,
}
}
/// Convert Gecko value to symbol type.
pub fn from_gecko_keyword(gecko_value: u32) -> SymbolsType {
use crate::gecko_bindings::structs;
match gecko_value {
structs::NS_STYLE_COUNTER_SYSTEM_CYCLIC => SymbolsType::Cyclic,
structs::NS_STYLE_COUNTER_SYSTEM_NUMERIC => SymbolsType::Numeric,
structs::NS_STYLE_COUNTER_SYSTEM_ALPHABETIC => SymbolsType::Alphabetic,
structs::NS_STYLE_COUNTER_SYSTEM_SYMBOLIC => SymbolsType::Symbolic,
structs::NS_STYLE_COUNTER_SYSTEM_FIXED => SymbolsType::Fixed,
x => panic!("Unexpected value for symbol type {}", x),
}
}
}
/// <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),

View File

@ -0,0 +1,46 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
//! Resolved values for counter properties
use super::{Context, ToResolvedValue};
use crate::values::computed;
/// https://drafts.csswg.org/css-content/#content-property
///
/// We implement this at resolved value time because otherwise it causes us to
/// allocate a bunch of useless initial structs for ::before / ::after, which is
/// a bit unfortunate.
///
/// Though these should be temporary, mostly, so if this causes complexity in
/// other places, it should be fine to move to `StyleAdjuster`.
///
/// See https://github.com/w3c/csswg-drafts/issues/4632 for where some related
/// issues are being discussed.
impl ToResolvedValue for computed::Content {
type ResolvedValue = Self;
#[inline]
fn to_resolved_value(self, context: &Context) -> Self {
let is_before_or_after =
context.style.pseudo().map_or(false, |p| p.is_before_or_after());
match self {
Self::Normal if is_before_or_after => Self::None,
// For now, make `content: none` compute to `normal` on other
// elements, as we don't respect it.
//
// FIXME(emilio, bug 1605473): for marker this should be preserved
// and respected, probably.
Self::None if !is_before_or_after => Self::Normal,
other => other,
}
}
#[inline]
fn from_resolved_value(resolved: Self) -> Self {
resolved
}
}

View File

@ -10,6 +10,7 @@ use cssparser;
use smallvec::SmallVec;
mod color;
mod counters;
use crate::values::computed;
@ -68,6 +69,7 @@ trivial_to_resolved_value!(u32);
trivial_to_resolved_value!(usize);
trivial_to_resolved_value!(String);
trivial_to_resolved_value!(Box<str>);
trivial_to_resolved_value!(crate::OwnedStr);
trivial_to_resolved_value!(cssparser::RGBA);
trivial_to_resolved_value!(crate::Atom);
trivial_to_resolved_value!(app_units::Au);

View File

@ -9,8 +9,6 @@ use crate::computed_values::list_style_type::T as ListStyleType;
use crate::parser::{Parse, ParserContext};
use crate::values::generics::counters as generics;
use crate::values::generics::counters::CounterPair;
use crate::values::generics::counters::GenericCounterIncrement;
use crate::values::generics::counters::GenericCounterSetOrReset;
#[cfg(feature = "gecko")]
use crate::values::generics::CounterStyle;
use crate::values::specified::url::SpecifiedImageUrl;
@ -23,7 +21,7 @@ use selectors::parser::SelectorParseErrorKind;
use style_traits::{ParseError, StyleParseErrorKind};
/// A specified value for the `counter-increment` property.
pub type CounterIncrement = GenericCounterIncrement<Integer>;
pub type CounterIncrement = generics::GenericCounterIncrement<Integer>;
impl Parse for CounterIncrement {
fn parse<'i, 't>(
@ -35,7 +33,7 @@ impl Parse for CounterIncrement {
}
/// A specified value for the `counter-set` and `counter-reset` properties.
pub type CounterSetOrReset = GenericCounterSetOrReset<Integer>;
pub type CounterSetOrReset = generics::GenericCounterSetOrReset<Integer>;
impl Parse for CounterSetOrReset {
fn parse<'i, 't>(
@ -84,10 +82,10 @@ fn parse_counters<'i, 't>(
}
/// The specified value for the `content` property.
pub type Content = generics::Content<SpecifiedImageUrl>;
pub type Content = generics::GenericContent<SpecifiedImageUrl>;
/// The specified value for a content item in the `content` property.
pub type ContentItem = generics::ContentItem<SpecifiedImageUrl>;
pub type ContentItem = generics::GenericContentItem<SpecifiedImageUrl>;
impl Content {
#[cfg(feature = "servo")]
@ -131,17 +129,9 @@ impl Parse for Content {
{
return Ok(generics::Content::None);
}
#[cfg(feature = "gecko")]
{
if input
.try(|input| input.expect_ident_matching("-moz-alt-content"))
.is_ok()
{
return Ok(generics::Content::MozAltContent);
}
}
let mut content = vec![];
let mut has_alt_content = false;
loop {
#[cfg(feature = "gecko")]
{
@ -153,7 +143,7 @@ impl Parse for Content {
match input.next() {
Ok(&Token::QuotedString(ref value)) => {
content.push(generics::ContentItem::String(
value.as_ref().to_owned().into_boxed_str(),
value.as_ref().to_owned().into(),
));
},
Ok(&Token::Function(ref name)) => {
@ -168,7 +158,7 @@ impl Parse for Content {
let location = input.current_source_location();
let name = CustomIdent::from_ident(location, input.expect_ident()?, &[])?;
input.expect_comma()?;
let separator = input.expect_string()?.as_ref().to_owned().into_boxed_str();
let separator = input.expect_string()?.as_ref().to_owned().into();
let style = Content::parse_counter_style(context, input);
Ok(generics::ContentItem::Counters(name, separator, style))
}),
@ -191,6 +181,11 @@ impl Parse for Content {
"close-quote" => generics::ContentItem::CloseQuote,
"no-open-quote" => generics::ContentItem::NoOpenQuote,
"no-close-quote" => generics::ContentItem::NoCloseQuote,
#[cfg(feature = "gecko")]
"-moz-alt-content" => {
has_alt_content = true;
generics::ContentItem::MozAltContent
},
_ =>{
let ident = ident.clone();
return Err(input.new_custom_error(
@ -206,9 +201,10 @@ impl Parse for Content {
},
}
}
if content.is_empty() {
// We don't allow to parse `-moz-alt-content in multiple positions.
if content.is_empty() || (has_alt_content && content.len() != 1) {
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
}
Ok(generics::Content::Items(content.into_boxed_slice()))
Ok(generics::Content::Items(content.into()))
}
}

View File

@ -767,9 +767,12 @@ impl AllowQuirks {
ToShmem,
)]
#[css(function)]
#[repr(C)]
pub struct Attr {
/// Optional namespace prefix and URL.
pub namespace: Option<(Prefix, Namespace)>,
/// Optional namespace prefix.
pub namespace_prefix: Prefix,
/// Optional namespace URL.
pub namespace_url: Namespace,
/// Attribute name
pub attribute: Atom,
}
@ -814,7 +817,7 @@ impl Attr {
ref t => return Err(location.new_unexpected_token_error(t.clone())),
};
let prefix_and_ns = if let Some(ns) = first {
let (namespace_prefix, namespace_url) = if let Some(ns) = first {
let prefix = Prefix::from(ns.as_ref());
let ns = match get_namespace_for_prefix(&prefix, context) {
Some(ns) => ns,
@ -823,17 +826,18 @@ impl Attr {
.new_custom_error(StyleParseErrorKind::UnspecifiedError));
},
};
Some((prefix, ns))
(prefix, ns)
} else {
None
(Prefix::default(), Namespace::default())
};
return Ok(Attr {
namespace: prefix_and_ns,
namespace_prefix,
namespace_url,
attribute: Atom::from(second_token.as_ref()),
});
},
// In the case of attr(foobar ) we don't want to error out
// because of the trailing whitespace
// because of the trailing whitespace.
Token::WhiteSpace(..) => {},
ref t => return Err(input.new_unexpected_token_error(t.clone())),
}
@ -841,7 +845,8 @@ impl Attr {
if let Some(first) = first {
Ok(Attr {
namespace: None,
namespace_prefix: Prefix::default(),
namespace_url: Namespace::default(),
attribute: Atom::from(first.as_ref()),
})
} else {
@ -856,8 +861,8 @@ impl ToCss for Attr {
W: Write,
{
dest.write_str("attr(")?;
if let Some((ref prefix, ref _url)) = self.namespace {
serialize_atom_identifier(prefix, dest)?;
if !self.namespace_prefix.is_empty() {
serialize_atom_identifier(&self.namespace_prefix, dest)?;
dest.write_str("|")?;
}
serialize_atom_identifier(&self.attribute, dest)?;

View File

@ -186,6 +186,8 @@ include = [
"CounterIncrement",
"WritingMode",
"VecU8",
"Content",
"ContentItem",
]
item_types = ["enums", "structs", "typedefs", "functions", "constants"]
renaming_overrides_prefixing = true
@ -599,7 +601,7 @@ renaming_overrides_prefixing = true
inline StyleCorsMode CorsMode() const;
already_AddRefed<nsIURI> ResolveLocalRef(nsIURI* aBase) const;
already_AddRefed<nsIURI> ResolveLocalRef(const nsIContent* aContent) const;
imgRequestProxy* LoadImage(mozilla::dom::Document&);
already_AddRefed<imgRequestProxy> LoadImage(mozilla::dom::Document&);
"""
"GenericGradient" = """

View File

@ -0,0 +1,15 @@
<!doctype html>
<meta charset="utf-8">
<title>CSS Test: initial computed value of content for elements is not none</title>
<link rel="help" href="https://drafts.csswg.org/css-content/#content-property">
<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1605803">
<link rel="author" href="https://mozilla.org" title="Mozilla">
<link rel="author" href="mailto:emilio@crisal.io" title="Emilio Cobos Álvarez">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script>
test(function() {
assert_equals(getComputedStyle(document.documentElement, "::before").content, "none");
assert_not_equals(getComputedStyle(document.documentElement).content, "none");
}, "initial computed value of content for elements is not none");
</script>