Bug 1594275 - Parse the exportparts attribute. r=bzbarsky

But don't hook it into style yet, that'll be a follow-up patch.

I had this patch in my local queue for a bit and there was no point in not
landing it I guess.

The value of this attribute could be stored only in the shadow root (as this
only applies to shadow hosts), but that would make invalidation harder, I think,
so do the obvious thing for now.

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

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Emilio Cobos Álvarez 2019-11-06 18:03:51 +00:00
parent a9f5350d66
commit 785ebbeab9
9 changed files with 197 additions and 4 deletions

View File

@ -16,6 +16,7 @@
#include "mozilla/DebugOnly.h"
#include "mozilla/StaticPrefs_dom.h"
#include "mozilla/StaticPrefs_layout.h"
#include "mozilla/StaticPrefs_full_screen_api.h"
#include "mozilla/dom/Animation.h"
#include "mozilla/dom/Attr.h"
#include "mozilla/dom/BindContext.h"
@ -2517,6 +2518,12 @@ bool Element::ParseAttribute(int32_t aNamespaceID, nsAtom* aAttribute,
return true;
}
if (aAttribute == nsGkAtoms::exportparts &&
StaticPrefs::layout_css_shadow_parts_enabled()) {
aResult.ParsePartMapping(aValue);
return true;
}
if (aAttribute == nsGkAtoms::id) {
// Store id as an atom. id="" means that the element has no id,
// not that it has an emptystring as the id.

View File

@ -20,6 +20,7 @@
#include "mozilla/MemoryReporting.h"
#include "mozilla/ServoBindingTypes.h"
#include "mozilla/ServoUtils.h"
#include "mozilla/ShadowParts.h"
#include "mozilla/DeclarationBlock.h"
#include "nsContentUtils.h"
#include "nsReadableUtils.h"
@ -281,6 +282,7 @@ void nsAttrValue::SetTo(const nsAttrValue& aOther) {
cont->mValue.mColor = otherCont->mValue.mColor;
break;
}
case eShadowParts:
case eCSSDeclaration: {
MOZ_CRASH("These should be refcounted!");
}
@ -301,9 +303,10 @@ void nsAttrValue::SetTo(const nsAttrValue& aOther) {
break;
}
case eIntMarginValue: {
if (otherCont->mValue.mIntMargin)
if (otherCont->mValue.mIntMargin) {
cont->mValue.mIntMargin =
new nsIntMargin(*otherCont->mValue.mIntMargin);
}
break;
}
default: {
@ -1155,7 +1158,7 @@ void nsAttrValue::ParseAtomArray(const nsAString& aValue) {
void nsAttrValue::ParseStringOrAtom(const nsAString& aValue) {
uint32_t len = aValue.Length();
// Don't bother with atoms if it's an empty string since
// we can store those efficently anyway.
// we can store those efficiently anyway.
if (len && len <= NS_ATTRVALUE_MAX_STRINGLENGTH_ATOM) {
ParseAtom(aValue);
} else {
@ -1163,6 +1166,17 @@ void nsAttrValue::ParseStringOrAtom(const nsAString& aValue) {
}
}
void nsAttrValue::ParsePartMapping(const nsAString& aValue) {
ResetIfSet();
MiscContainer* cont = EnsureEmptyMiscContainer();
cont->mType = eShadowParts;
cont->mValue.mShadowParts = new ShadowParts(ShadowParts::Parse(aValue));
NS_ADDREF(cont);
SetMiscAtomOrString(&aValue);
MOZ_ASSERT(cont->mValue.mRefCount == 1);
}
void nsAttrValue::SetIntValueAndType(int32_t aValue, ValueType aType,
const nsAString* aStringValue) {
if (aStringValue || aValue > NS_ATTRVALUE_INTEGERTYPE_MAXVALUE ||
@ -1740,6 +1754,12 @@ MiscContainer* nsAttrValue::ClearMiscContainer() {
NS_RELEASE(cont->mValue.mCSSDeclaration);
break;
}
case eShadowParts: {
MOZ_ASSERT(cont->mValue.mRefCount == 1);
cont->Release();
delete cont->mValue.mShadowParts;
break;
}
case eURL: {
NS_RELEASE(cont->mValue.mURL);
break;

View File

@ -101,6 +101,10 @@ class nsAttrValue {
eAtomArray,
eDoubleValue,
eIntMarginValue,
// eShadowParts is refcounted in the misc container, as we do copy attribute
// values quite a bit (for example to process style invalidation), and the
// underlying value could get expensive to copy.
eShadowParts,
eSVGIntegerPair,
eSVGTypesBegin = eSVGIntegerPair,
eSVGOrient,
@ -256,6 +260,13 @@ class nsAttrValue {
void ParseAtomArray(const nsAString& aValue);
void ParseStringOrAtom(const nsAString& aValue);
/**
* Parses an exportparts attribute.
*
* https://drafts.csswg.org/css-shadow-parts/#parsing-mapping-list
*/
void ParsePartMapping(const nsAString&);
/**
* Structure for a mapping from int (enum) values to strings. When you use
* it you generally create an array of them.

View File

@ -14,6 +14,10 @@
#include "mozilla/Attributes.h"
#include "mozilla/ServoUtils.h"
namespace mozilla {
class ShadowParts;
}
struct MiscContainer final {
typedef nsAttrValue::ValueType ValueType;
@ -41,6 +45,7 @@ struct MiscContainer final {
nsIURI* mURL;
mozilla::AtomArray* mAtomArray;
nsIntMargin* mIntMargin;
const mozilla::ShadowParts* mShadowParts;
const mozilla::SVGAnimatedIntegerPair* mSVGAnimatedIntegerPair;
const mozilla::SVGAnimatedLength* mSVGLength;
const mozilla::SVGAnimatedNumberPair* mSVGAnimatedNumberPair;
@ -95,7 +100,8 @@ struct MiscContainer final {
// Nothing stops us from refcounting (and sharing) other types of
// MiscContainer (except eDoubleValue types) but there's no compelling
// reason to.
return mType == nsAttrValue::eCSSDeclaration;
return mType == nsAttrValue::eCSSDeclaration ||
mType == nsAttrValue::eShadowParts;
}
inline int32_t AddRef() {

View File

@ -0,0 +1,114 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "ShadowParts.h"
#include "nsContentUtils.h"
#include "nsString.h"
namespace mozilla {
static bool IsSpace(char16_t aChar) {
return nsContentUtils::IsHTMLWhitespace(aChar);
};
using SingleMapping = std::pair<RefPtr<nsAtom>, RefPtr<nsAtom>>;
// https://drafts.csswg.org/css-shadow-parts/#parsing-mapping
//
// Returns null on both tokens to signal an error.
static SingleMapping ParseSingleMapping(const nsAString& aString) {
const char16_t* c = aString.BeginReading();
const char16_t* end = aString.EndReading();
const auto CollectASequenceOfSpaces = [&c, end]() {
while (c != end && IsSpace(*c)) {
++c;
}
};
const auto CollectToken = [&c, end]() -> RefPtr<nsAtom> {
const char16_t* t = c;
while (c != end && !IsSpace(*c) && *c != ':') {
++c;
}
if (c == t) {
return nullptr;
}
return NS_AtomizeMainThread(Substring(t, c));
};
// Steps 1 and 2 are variable declarations.
//
// 3. Collect a sequence of code points that are space characters.
CollectASequenceOfSpaces();
// 4. Collect a sequence of code points that are not space characters or
// U+003A COLON characters, and call the result first token.
RefPtr<nsAtom> firstToken = CollectToken();
// 5. If first token is empty then return error.
if (!firstToken) {
return {nullptr, nullptr};
}
// 6. Collect a sequence of code points that are space characters.
CollectASequenceOfSpaces();
// 7. If the end of the input has been reached, return the pair first
// token/first token.
if (c == end) {
return {firstToken, firstToken};
}
// 8. If character at position is not a U+003A COLON character, return error.
if (*c != ':') {
return {nullptr, nullptr};
}
// 9. Consume the U+003A COLON character.
++c;
// 10. Collect a sequence of code points that are space characters.
CollectASequenceOfSpaces();
// 11. Collect a sequence of code points that are not space characters or
// U+003A COLON characters. and let second token be the result.
RefPtr<nsAtom> secondToken = CollectToken();
// 12. If second token is empty then return error.
if (!secondToken) {
return {nullptr, nullptr};
}
// 13. Collect a sequence of code points that are space characters.
CollectASequenceOfSpaces();
// 14. If position is not past the end of input then return error.
if (c != end) {
return {nullptr, nullptr};
}
// 15. Return the pair first token/second token.
return {std::move(firstToken), std::move(secondToken)};
}
// https://drafts.csswg.org/css-shadow-parts/#parsing-mapping-list
ShadowParts ShadowParts::Parse(const nsAString& aString) {
ShadowParts parts;
for (const auto& substring : aString.Split(',')) {
auto mapping = ParseSingleMapping(substring);
if (!mapping.first) {
MOZ_ASSERT(!mapping.second);
continue;
}
parts.mMappings.GetOrInsert(mapping.first) = std::move(mapping.second);
}
return parts;
}
} // namespace mozilla

View File

@ -0,0 +1,32 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_ShadowParts_h
#define mozilla_ShadowParts_h
#include "nsAtom.h"
#include "nsTHashtable.h"
#include "nsRefPtrHashtable.h"
#include "nsStringFwd.h"
namespace mozilla {
class ShadowParts final {
public:
ShadowParts(ShadowParts&&) = default;
ShadowParts(const ShadowParts&) = delete;
static ShadowParts Parse(const nsAString&);
private:
ShadowParts() = default;
nsRefPtrHashtable<nsRefPtrHashKey<nsAtom>, nsAtom> mMappings;
};
} // namespace mozilla
#endif // mozilla_ShadowParts_h

View File

@ -107,6 +107,7 @@ EXPORTS.mozilla += [
'ServoTraversalStatistics.h',
'ServoTypes.h',
'ServoUtils.h',
'ShadowParts.h',
'StyleAnimationValue.h',
'StyleColorInlines.h',
'StyleSheet.h',
@ -221,6 +222,7 @@ UNIFIED_SOURCES += [
'ServoCSSRuleList.cpp',
'ServoElementSnapshot.cpp',
'ServoStyleSet.cpp',
'ShadowParts.cpp',
'StreamLoader.cpp',
'StyleAnimationValue.cpp',
'StyleColor.cpp',

View File

@ -424,7 +424,7 @@ void nsLayoutStylesheetCache::InitSharedSheetsInParent() {
// TODO(heycam): This won't be true on Windows unless we allow creating the
// shared memory with SEC_RESERVE so that the pages are reserved but not
// committed.
size_t pageSize = ipc::SharedMemory::SystemPageSize();
size_t pageSize = mozilla::ipc::SharedMemory::SystemPageSize();
mUsedSharedMemory =
(Servo_SharedMemoryBuilder_GetLength(builder.get()) + pageSize - 1) &
~(pageSize - 1);

View File

@ -413,6 +413,7 @@ STATIC_ATOMS = [
Atom("event", "event"),
Atom("events", "events"),
Atom("excludeResultPrefixes", "exclude-result-prefixes"),
Atom("exportparts", "exportparts"),
Atom("extends", "extends"),
Atom("extensionElementPrefixes", "extension-element-prefixes"),
Atom("face", "face"),