diff --git a/dom/base/Element.cpp b/dom/base/Element.cpp index 8eee0a43be29..af2b0ab6ff51 100644 --- a/dom/base/Element.cpp +++ b/dom/base/Element.cpp @@ -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. diff --git a/dom/base/nsAttrValue.cpp b/dom/base/nsAttrValue.cpp index c000eebb80b8..8875d23680b7 100644 --- a/dom/base/nsAttrValue.cpp +++ b/dom/base/nsAttrValue.cpp @@ -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; diff --git a/dom/base/nsAttrValue.h b/dom/base/nsAttrValue.h index 0dd4c227e9fc..29d2a0cbd3cd 100644 --- a/dom/base/nsAttrValue.h +++ b/dom/base/nsAttrValue.h @@ -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. diff --git a/dom/base/nsAttrValueInlines.h b/dom/base/nsAttrValueInlines.h index 274b13fb7604..5d74d241e9cd 100644 --- a/dom/base/nsAttrValueInlines.h +++ b/dom/base/nsAttrValueInlines.h @@ -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() { diff --git a/layout/style/ShadowParts.cpp b/layout/style/ShadowParts.cpp new file mode 100644 index 000000000000..16fc5c8ec231 --- /dev/null +++ b/layout/style/ShadowParts.cpp @@ -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>; + +// 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 { + 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 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 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 diff --git a/layout/style/ShadowParts.h b/layout/style/ShadowParts.h new file mode 100644 index 000000000000..7be97386cf50 --- /dev/null +++ b/layout/style/ShadowParts.h @@ -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, nsAtom> mMappings; +}; + +} // namespace mozilla + +#endif // mozilla_ShadowParts_h diff --git a/layout/style/moz.build b/layout/style/moz.build index 3d3d18eb731c..3f3dc5477106 100644 --- a/layout/style/moz.build +++ b/layout/style/moz.build @@ -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', diff --git a/layout/style/nsLayoutStylesheetCache.cpp b/layout/style/nsLayoutStylesheetCache.cpp index 4f9e09deb36c..3300baa0df38 100644 --- a/layout/style/nsLayoutStylesheetCache.cpp +++ b/layout/style/nsLayoutStylesheetCache.cpp @@ -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); diff --git a/xpcom/ds/StaticAtoms.py b/xpcom/ds/StaticAtoms.py index c794c945f617..ac14cbd6a7f5 100644 --- a/xpcom/ds/StaticAtoms.py +++ b/xpcom/ds/StaticAtoms.py @@ -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"),