From d999dfa37e93190304800cd4304bb5dc4d5adaeb Mon Sep 17 00:00:00 2001 From: Emily McDonough Date: Tue, 16 Apr 2024 19:52:39 +0000 Subject: [PATCH] Bug 1833466 - Implement CSSMarginRule and the corresponding DOM API. r=webidl,firefox-style-system-reviewers,smaug,emilio Differential Revision: https://phabricator.services.mozilla.com/D206804 --- dom/webidl/CSSMarginRule.webidl | 15 ++ dom/webidl/moz.build | 1 + layout/style/CSSMarginRule.cpp | 183 ++++++++++++++++++ layout/style/CSSMarginRule.h | 107 ++++++++++ layout/style/Rule.cpp | 8 +- layout/style/ServoBindingTypes.h | 1 + layout/style/ServoBindings.h | 1 + layout/style/ServoCSSRuleList.cpp | 9 +- layout/style/ServoLockedArcTypeList.h | 1 + layout/style/ServoStyleConstsInlines.h | 1 + layout/style/ServoStyleSet.cpp | 5 +- layout/style/moz.build | 2 + servo/components/style/gecko/arc_types.rs | 9 +- .../style/stylesheets/margin_rule.rs | 42 +++- servo/ports/geckolib/glue.rs | 24 ++- 15 files changed, 385 insertions(+), 24 deletions(-) create mode 100644 dom/webidl/CSSMarginRule.webidl create mode 100644 layout/style/CSSMarginRule.cpp create mode 100644 layout/style/CSSMarginRule.h diff --git a/dom/webidl/CSSMarginRule.webidl b/dom/webidl/CSSMarginRule.webidl new file mode 100644 index 000000000000..8210bbb79fe2 --- /dev/null +++ b/dom/webidl/CSSMarginRule.webidl @@ -0,0 +1,15 @@ +/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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/. + * + * The origin of this IDL file is + * https://drafts.csswg.org/cssom/#the-cssmarginrule-interface + */ + +// https://drafts.csswg.org/cssom/#the-cssmarginrule-interface +[Pref="layout.css.margin-rules.enabled", Exposed=Window] +interface CSSMarginRule : CSSRule { + readonly attribute UTF8String name; + [SameObject, PutForwards=cssText] readonly attribute CSSStyleDeclaration style; +}; diff --git a/dom/webidl/moz.build b/dom/webidl/moz.build index 9f8832d042ee..58eb0ef8b613 100644 --- a/dom/webidl/moz.build +++ b/dom/webidl/moz.build @@ -491,6 +491,7 @@ WEBIDL_FILES = [ "CSSKeyframesRule.webidl", "CSSLayerBlockRule.webidl", "CSSLayerStatementRule.webidl", + "CSSMarginRule.webidl", "CSSMediaRule.webidl", "CSSMozDocumentRule.webidl", "CSSNamespaceRule.webidl", diff --git a/layout/style/CSSMarginRule.cpp b/layout/style/CSSMarginRule.cpp new file mode 100644 index 000000000000..64a706666cdc --- /dev/null +++ b/layout/style/CSSMarginRule.cpp @@ -0,0 +1,183 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=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 "mozilla/dom/CSSMarginRule.h" +#include "mozilla/dom/CSSMarginRuleBinding.h" + +#include "mozilla/DeclarationBlock.h" +#include "mozilla/ServoBindings.h" + +namespace mozilla::dom { + +// -- CSSMarginRuleDeclaration --------------------------------------- + +CSSMarginRuleDeclaration::CSSMarginRuleDeclaration( + already_AddRefed aDecls) + : mDecls(new DeclarationBlock(std::move(aDecls))) { + mDecls->SetOwningRule(Rule()); +} + +CSSMarginRuleDeclaration::~CSSMarginRuleDeclaration() { + mDecls->SetOwningRule(nullptr); +} + +// QueryInterface implementation for CSSMarginRuleDeclaration +NS_INTERFACE_MAP_BEGIN(CSSMarginRuleDeclaration) + NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY + // We forward the cycle collection interfaces to Rule(), which is + // never null (in fact, we're part of that object!) + if (aIID.Equals(NS_GET_IID(nsCycleCollectionISupports)) || + aIID.Equals(NS_GET_IID(nsXPCOMCycleCollectionParticipant))) { + return Rule()->QueryInterface(aIID, aInstancePtr); + } +NS_INTERFACE_MAP_END_INHERITING(nsDOMCSSDeclaration) + +NS_IMPL_ADDREF_USING_AGGREGATOR(CSSMarginRuleDeclaration, Rule()) +NS_IMPL_RELEASE_USING_AGGREGATOR(CSSMarginRuleDeclaration, Rule()) + +/* nsDOMCSSDeclaration implementation */ +css::Rule* CSSMarginRuleDeclaration::GetParentRule() { return Rule(); } + +nsINode* CSSMarginRuleDeclaration::GetAssociatedNode() const { + return Rule()->GetAssociatedDocumentOrShadowRoot(); +} + +nsISupports* CSSMarginRuleDeclaration::GetParentObject() const { + return Rule()->GetParentObject(); +} + +DeclarationBlock* CSSMarginRuleDeclaration::GetOrCreateCSSDeclaration( + Operation aOperation, DeclarationBlock** aCreated) { + if (aOperation != Operation::Read) { + if (StyleSheet* sheet = Rule()->GetStyleSheet()) { + sheet->WillDirty(); + } + } + return mDecls; +} + +void CSSMarginRuleDeclaration::SetRawAfterClone( + RefPtr aDeclarationBlock) { + mDecls->SetOwningRule(nullptr); + mDecls = new DeclarationBlock(aDeclarationBlock.forget()); + mDecls->SetOwningRule(Rule()); +} + +nsresult CSSMarginRuleDeclaration::SetCSSDeclaration( + DeclarationBlock* aDecl, MutationClosureData* aClosureData) { + MOZ_ASSERT(aDecl, "must be non-null"); + CSSMarginRule* rule = Rule(); + + if (aDecl != mDecls) { + mDecls->SetOwningRule(nullptr); + RefPtr decls = aDecl; + // TODO alaskanemily: bug 1890418 for implementing this and margin-rule + // style properties in general. + // Servo_MarginRule_SetStyle(rule->Raw(), decls->Raw()); + mDecls = std::move(decls); + mDecls->SetOwningRule(rule); + } + + return NS_OK; +} + +nsDOMCSSDeclaration::ParsingEnvironment +CSSMarginRuleDeclaration::GetParsingEnvironment( + nsIPrincipal* aSubjectPrincipal) const { + return GetParsingEnvironmentForRule(Rule(), StyleCssRuleType::Margin); +} + +// -- CSSMarginRule -------------------------------------------------- + +CSSMarginRule::CSSMarginRule(RefPtr aRawRule, + StyleSheet* aSheet, css::Rule* aParentRule, + uint32_t aLine, uint32_t aColumn) + : css::Rule(aSheet, aParentRule, aLine, aColumn), + mRawRule(std::move(aRawRule)), + mDecls(Servo_MarginRule_GetStyle(mRawRule).Consume()) {} + +NS_IMPL_ADDREF_INHERITED(CSSMarginRule, css::Rule) +NS_IMPL_RELEASE_INHERITED(CSSMarginRule, css::Rule) + +// QueryInterface implementation for MarginRule +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CSSMarginRule) +NS_INTERFACE_MAP_END_INHERITING(css::Rule) + +NS_IMPL_CYCLE_COLLECTION_CLASS(CSSMarginRule) + +NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(CSSMarginRule, css::Rule) + // Keep this in sync with IsCCLeaf. + + // Trace the wrapper for our declaration. This just expands out + // NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER which we can't use + // directly because the wrapper is on the declaration, not on us. + tmp->mDecls.TraceWrapper(aCallbacks, aClosure); +NS_IMPL_CYCLE_COLLECTION_TRACE_END + +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(CSSMarginRule) + // Keep this in sync with IsCCLeaf. + + // Unlink the wrapper for our declaration. + // + // Note that this has to happen before unlinking css::Rule. + tmp->UnlinkDeclarationWrapper(tmp->mDecls); + tmp->mDecls.mDecls->SetOwningRule(nullptr); +NS_IMPL_CYCLE_COLLECTION_UNLINK_END_INHERITED(css::Rule) + +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(CSSMarginRule, css::Rule) + // Keep this in sync with IsCCLeaf. +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END + +bool CSSMarginRule::IsCCLeaf() const { + if (!Rule::IsCCLeaf()) { + return false; + } + + return !mDecls.PreservingWrapper(); +} + +void CSSMarginRule::SetRawAfterClone(RefPtr aRaw) { + mRawRule = std::move(aRaw); + mDecls.SetRawAfterClone(Servo_MarginRule_GetStyle(mRawRule.get()).Consume()); +} + +// WebIDL interfaces +StyleCssRuleType CSSMarginRule::Type() const { + return StyleCssRuleType::Margin; +} + +// CSSRule implementation + +void CSSMarginRule::GetCssText(nsACString& aCssText) const { + Servo_MarginRule_GetCssText(mRawRule, &aCssText); +} + +void CSSMarginRule::GetName(nsACString& aRuleName) const { + Servo_MarginRule_GetName(mRawRule, &aRuleName); +} + +size_t CSSMarginRule::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const { + // TODO Implement this! + return aMallocSizeOf(this); +} + +#ifdef DEBUG +void CSSMarginRule::List(FILE* out, int32_t aIndent) const { + nsAutoCString str; + for (int32_t i = 0; i < aIndent; i++) { + str.AppendLiteral(" "); + } + Servo_MarginRule_Debug(mRawRule, &str); + fprintf_stderr(out, "%s\n", str.get()); +} +#endif + +JSObject* CSSMarginRule::WrapObject(JSContext* aCx, + JS::Handle aGivenProto) { + return CSSMarginRule_Binding::Wrap(aCx, this, aGivenProto); +} + +} // namespace mozilla::dom diff --git a/layout/style/CSSMarginRule.h b/layout/style/CSSMarginRule.h new file mode 100644 index 000000000000..0ad5f60dbda7 --- /dev/null +++ b/layout/style/CSSMarginRule.h @@ -0,0 +1,107 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=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_dom_CSSMarginRule_h +#define mozilla_dom_CSSMarginRule_h + +#include "mozilla/css/Rule.h" +#include "mozilla/ServoBindingTypes.h" + +#include "nsDOMCSSDeclaration.h" +#include "nsICSSDeclaration.h" + +namespace mozilla { +class DeclarationBlock; + +namespace dom { +class CSSMarginRule; + +class CSSMarginRuleDeclaration final : public nsDOMCSSDeclaration { + public: + NS_DECL_ISUPPORTS_INHERITED + + css::Rule* GetParentRule() final; + nsINode* GetAssociatedNode() const final; + nsISupports* GetParentObject() const final; + + protected: + DeclarationBlock* GetOrCreateCSSDeclaration( + Operation aOperation, DeclarationBlock** aCreated) final; + nsresult SetCSSDeclaration(DeclarationBlock* aDecl, + MutationClosureData* aClosureData) final; + Document* DocToUpdate() final { return nullptr; } + nsDOMCSSDeclaration::ParsingEnvironment GetParsingEnvironment( + nsIPrincipal* aSubjectPrincipal) const final; + + private: + // For accessing the constructor. + friend class CSSMarginRule; + + explicit CSSMarginRuleDeclaration( + already_AddRefed aDecls); + void SetRawAfterClone(RefPtr); + + ~CSSMarginRuleDeclaration(); + + inline CSSMarginRule* Rule(); + inline const CSSMarginRule* Rule() const; + + RefPtr mDecls; +}; + +class CSSMarginRule final : public css::Rule { + public: + CSSMarginRule(RefPtr aRawRule, StyleSheet* aSheet, + css::Rule* aParentRule, uint32_t aLine, uint32_t aColumn); + + NS_DECL_ISUPPORTS_INHERITED + NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(CSSMarginRule, + css::Rule) + + bool IsCCLeaf() const final; + + StyleMarginRule* Raw() const { return mRawRule; } + void SetRawAfterClone(RefPtr); + + // WebIDL interfaces + StyleCssRuleType Type() const final; + void GetCssText(nsACString& aCssText) const final; + nsICSSDeclaration* Style() { return &mDecls; } + + void GetName(nsACString& aRuleName) const; + + size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const final; + +#ifdef DEBUG + void List(FILE* out = stdout, int32_t aIndent = 0) const final; +#endif + + JSObject* WrapObject(JSContext* aCx, JS::Handle aGivenProto) final; + + private: + ~CSSMarginRule() = default; + + // For computing the offset of mDecls. + friend class CSSMarginRuleDeclaration; + + RefPtr mRawRule; + CSSMarginRuleDeclaration mDecls; +}; + +CSSMarginRule* CSSMarginRuleDeclaration::Rule() { + return reinterpret_cast(reinterpret_cast(this) - + offsetof(CSSMarginRule, mDecls)); +} + +const CSSMarginRule* CSSMarginRuleDeclaration::Rule() const { + return reinterpret_cast( + reinterpret_cast(this) - offsetof(CSSMarginRule, mDecls)); +} + +} // namespace dom +} // namespace mozilla + +#endif // mozilla_dom_CSSMarginRule_h diff --git a/layout/style/Rule.cpp b/layout/style/Rule.cpp index 4b0f783bd961..deaa46576caa 100644 --- a/layout/style/Rule.cpp +++ b/layout/style/Rule.cpp @@ -95,9 +95,10 @@ Rule* Rule::GetParentRule() const { return mParentRule; } #ifdef DEBUG void Rule::AssertParentRuleType() { - // Would be nice to check that this->Type() is KEYFRAME_RULE when - // mParentRule->Tye() is KEYFRAMES_RULE, but we can't call + // Would be nice to check that this->Type() is StyleCssRuleType::Keyframe + // when mParentRule->Tye() is StyleCssRuleType::Keyframes, but we can't call // this->Type() here since it's virtual. + // Same for StyleCssRuleType::Margin and StyleCssRuleType::Page. if (mParentRule) { auto type = mParentRule->Type(); MOZ_ASSERT(type == StyleCssRuleType::Media || @@ -108,7 +109,8 @@ void Rule::AssertParentRuleType() { type == StyleCssRuleType::LayerBlock || type == StyleCssRuleType::Container || type == StyleCssRuleType::Scope || - type == StyleCssRuleType::StartingStyle); + type == StyleCssRuleType::StartingStyle || + type == StyleCssRuleType::Page); } } #endif diff --git a/layout/style/ServoBindingTypes.h b/layout/style/ServoBindingTypes.h index b081a4981bd9..e2443ef52674 100644 --- a/layout/style/ServoBindingTypes.h +++ b/layout/style/ServoBindingTypes.h @@ -123,6 +123,7 @@ UNLOCKED_RULE_TYPE(Property) UNLOCKED_RULE_TYPE(LayerBlock) UNLOCKED_RULE_TYPE(LayerStatement) UNLOCKED_RULE_TYPE(Namespace) +UNLOCKED_RULE_TYPE(Margin) UNLOCKED_RULE_TYPE(Container) UNLOCKED_RULE_TYPE(Media) UNLOCKED_RULE_TYPE(Supports) diff --git a/layout/style/ServoBindings.h b/layout/style/ServoBindings.h index 52538cafb8e3..2c0abbe0db16 100644 --- a/layout/style/ServoBindings.h +++ b/layout/style/ServoBindings.h @@ -77,6 +77,7 @@ BASIC_RULE_FUNCS_LOCKED(Keyframes) GROUP_RULE_FUNCS_UNLOCKED(Media) GROUP_RULE_FUNCS_UNLOCKED(Document) BASIC_RULE_FUNCS_UNLOCKED(Namespace) +BASIC_RULE_FUNCS_UNLOCKED(Margin) GROUP_RULE_FUNCS_LOCKED(Page) BASIC_RULE_FUNCS_UNLOCKED(Property) GROUP_RULE_FUNCS_UNLOCKED(Supports) diff --git a/layout/style/ServoCSSRuleList.cpp b/layout/style/ServoCSSRuleList.cpp index 133a9622567a..b7172879def1 100644 --- a/layout/style/ServoCSSRuleList.cpp +++ b/layout/style/ServoCSSRuleList.cpp @@ -17,6 +17,7 @@ #include "mozilla/dom/CSSLayerStatementRule.h" #include "mozilla/dom/CSSKeyframesRule.h" #include "mozilla/dom/CSSContainerRule.h" +#include "mozilla/dom/CSSMarginRule.h" #include "mozilla/dom/CSSMediaRule.h" #include "mozilla/dom/CSSMozDocumentRule.h" #include "mozilla/dom/CSSNamespaceRule.h" @@ -88,6 +89,7 @@ css::Rule* ServoCSSRuleList::GetRule(uint32_t aIndex) { CASE_RULE_LOCKED(Keyframes, Keyframes) CASE_RULE_UNLOCKED(Media, Media) CASE_RULE_UNLOCKED(Namespace, Namespace) + CASE_RULE_UNLOCKED(Margin, Margin) CASE_RULE_LOCKED(Page, Page) CASE_RULE_UNLOCKED(Property, Property) CASE_RULE_UNLOCKED(Supports, Supports) @@ -108,9 +110,6 @@ css::Rule* ServoCSSRuleList::GetRule(uint32_t aIndex) { case StyleCssRuleType::Keyframe: MOZ_ASSERT_UNREACHABLE("keyframe rule cannot be here"); return nullptr; - case StyleCssRuleType::Margin: - // Margin rules not implemented yet, see bug 1864737 - return nullptr; } rule = CastToUint(ruleObj.forget().take()); mRules[aIndex] = rule; @@ -277,6 +276,7 @@ void ServoCSSRuleList::SetRawContents(RefPtr aNewRules, RULE_CASE_LOCKED(Keyframes, Keyframes) RULE_CASE_UNLOCKED(Media, Media) RULE_CASE_UNLOCKED(Namespace, Namespace) + RULE_CASE_UNLOCKED(Margin, Margin) RULE_CASE_LOCKED(Page, Page) RULE_CASE_UNLOCKED(Property, Property) RULE_CASE_UNLOCKED(Supports, Supports) @@ -294,9 +294,6 @@ void ServoCSSRuleList::SetRawContents(RefPtr aNewRules, case StyleCssRuleType::Keyframe: MOZ_ASSERT_UNREACHABLE("keyframe rule cannot be here"); break; - case StyleCssRuleType::Margin: - // Margin rules not implemented yet, see bug 1864737 - break; } #undef RULE_CASE_WITH_PREFIX #undef RULE_CASE_LOCKED diff --git a/layout/style/ServoLockedArcTypeList.h b/layout/style/ServoLockedArcTypeList.h index 2d356aabf923..70adc7bd8ea8 100644 --- a/layout/style/ServoLockedArcTypeList.h +++ b/layout/style/ServoLockedArcTypeList.h @@ -19,6 +19,7 @@ SERVO_LOCKED_ARC_TYPE(StyleRule) SERVO_LOCKED_ARC_TYPE(ImportRule) SERVO_LOCKED_ARC_TYPE(Keyframe) SERVO_LOCKED_ARC_TYPE(KeyframesRule) +SERVO_LOCKED_ARC_TYPE(MarginList) SERVO_LOCKED_ARC_TYPE(MediaList) SERVO_LOCKED_ARC_TYPE(PageRule) SERVO_LOCKED_ARC_TYPE(FontFaceRule) diff --git a/layout/style/ServoStyleConstsInlines.h b/layout/style/ServoStyleConstsInlines.h index f1cfa8565a55..39d0efce00a8 100644 --- a/layout/style/ServoStyleConstsInlines.h +++ b/layout/style/ServoStyleConstsInlines.h @@ -45,6 +45,7 @@ template struct StyleStrong; template struct StyleStrong; template struct StyleStrong; template struct StyleStrong; +template struct StyleStrong; template struct StyleStrong; template struct StyleStrong; template struct StyleStrong; diff --git a/layout/style/ServoStyleSet.cpp b/layout/style/ServoStyleSet.cpp index 91231af2b029..692bbbe18f37 100644 --- a/layout/style/ServoStyleSet.cpp +++ b/layout/style/ServoStyleSet.cpp @@ -34,6 +34,7 @@ #include "mozilla/dom/CSSContainerRule.h" #include "mozilla/dom/CSSLayerBlockRule.h" #include "mozilla/dom/CSSLayerStatementRule.h" +#include "mozilla/dom/CSSMarginRule.h" #include "mozilla/dom/CSSMediaRule.h" #include "mozilla/dom/CSSMozDocumentRule.h" #include "mozilla/dom/CSSKeyframesRule.h" @@ -994,6 +995,7 @@ void ServoStyleSet::RuleChangedInternal(StyleSheet& aSheet, css::Rule& aRule, CASE_FOR(Import, Import) CASE_FOR(Media, Media) CASE_FOR(Keyframes, Keyframes) + CASE_FOR(Margin, Margin) CASE_FOR(FontFeatureValues, FontFeatureValues) CASE_FOR(FontPaletteValues, FontPaletteValues) CASE_FOR(FontFace, FontFace) @@ -1014,9 +1016,6 @@ void ServoStyleSet::RuleChangedInternal(StyleSheet& aSheet, css::Rule& aRule, // FIXME: We should probably just forward to the parent @keyframes rule? I // think that'd do the right thing, but meanwhile... return MarkOriginsDirty(ToOriginFlags(aSheet.GetOrigin())); - case StyleCssRuleType::Margin: - // Margin rules not implemented yet, see bug 1864737 - break; } #undef CASE_FOR diff --git a/layout/style/moz.build b/layout/style/moz.build index b77fa34983af..ce9ee36cea7f 100644 --- a/layout/style/moz.build +++ b/layout/style/moz.build @@ -138,6 +138,7 @@ EXPORTS.mozilla.dom += [ "CSSKeyframesRule.h", "CSSLayerBlockRule.h", "CSSLayerStatementRule.h", + "CSSMarginRule.h", "CSSMediaRule.h", "CSSMozDocumentRule.h", "CSSNamespaceRule.h", @@ -191,6 +192,7 @@ UNIFIED_SOURCES += [ "CSSKeyframesRule.cpp", "CSSLayerBlockRule.cpp", "CSSLayerStatementRule.cpp", + "CSSMarginRule.cpp", "CSSMediaRule.cpp", "CSSMozDocumentRule.cpp", "CSSNamespaceRule.cpp", diff --git a/servo/components/style/gecko/arc_types.rs b/servo/components/style/gecko/arc_types.rs index 420b86d3325b..259d9f1570a0 100644 --- a/servo/components/style/gecko/arc_types.rs +++ b/servo/components/style/gecko/arc_types.rs @@ -16,8 +16,8 @@ use crate::stylesheets::keyframes_rule::Keyframe; use crate::stylesheets::{ ContainerRule, CounterStyleRule, CssRules, DocumentRule, FontFaceRule, FontFeatureValuesRule, FontPaletteValuesRule, ImportRule, KeyframesRule, LayerBlockRule, LayerStatementRule, - MediaRule, NamespaceRule, PageRule, PropertyRule, ScopeRule, StartingStyleRule, StyleRule, - StylesheetContents, SupportsRule, + MarginRule, MediaRule, NamespaceRule, PageRule, PropertyRule, ScopeRule, StartingStyleRule, + StyleRule, StylesheetContents, SupportsRule, }; use servo_arc::Arc; @@ -101,6 +101,11 @@ impl_simple_arc_ffi!( Servo_NamespaceRule_AddRef, Servo_NamespaceRule_Release ); +impl_simple_arc_ffi!( + MarginRule, + Servo_MarginRule_AddRef, + Servo_MarginRule_Release +); impl_locked_arc_ffi!( PageRule, LockedPageRule, diff --git a/servo/components/style/stylesheets/margin_rule.rs b/servo/components/style/stylesheets/margin_rule.rs index ab462831515d..19928c04ba50 100644 --- a/servo/components/style/stylesheets/margin_rule.rs +++ b/servo/components/style/stylesheets/margin_rule.rs @@ -21,19 +21,21 @@ macro_rules! margin_rule_types { /// [`@margin`][margin] rule names. /// /// https://drafts.csswg.org/css-page-3/#margin-at-rules - #[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, ToShmem)] + #[derive(Clone, Copy, Eq, MallocSizeOf, PartialEq, ToShmem)] #[repr(u8)] pub enum MarginRuleType { $($(#[$($meta)+])* $id,)+ } + /// All [`@margin`][margin] rule names, with a preceding '@'. + /// + /// This array lets us have just one single memory region used for + /// to_str, name, and the Debug implementation. + const MARGIN_RULE_AT_NAMES:&[&'static str] = &[ + $( concat!('@', $val), )+ + ]; + impl MarginRuleType { - #[inline] - fn to_str(&self) -> &'static str { - match *self { - $(MarginRuleType::$id => concat!('@', $val),)+ - } - } /// Matches the rule type for this name. This does not expect a /// leading '@'. pub fn match_name(name: &str) -> Option { @@ -113,6 +115,27 @@ margin_rule_types! { RightBottom => "right-bottom", } +impl MarginRuleType { + #[inline] + fn to_str(&self) -> &'static str { + &MARGIN_RULE_AT_NAMES[*self as usize] + } + #[inline] + fn name(&self) -> &'static str { + // Use the at-name array, skipping the first character to get + // the name without the @ sign. + &MARGIN_RULE_AT_NAMES[*self as usize][1..] + } +} + +// Implement Debug manually so that it will share the same string memory as +// MarginRuleType::name and MarginRuleType::to_str. +impl fmt::Debug for MarginRuleType { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + f.write_str(self.name()) + } +} + /// A [`@margin`][margin] rule. /// /// [margin]: https://drafts.csswg.org/css-page-3/#margin-at-rules @@ -134,6 +157,11 @@ impl MarginRule { self.block.unconditional_shallow_size_of(ops) + self.block.read_with(guard).size_of(ops) } + /// Gets the name for this margin rule. + #[inline] + pub fn name(&self) -> &'static str { + self.rule_type.name() + } } impl ToCssWithGuard for MarginRule { diff --git a/servo/ports/geckolib/glue.rs b/servo/ports/geckolib/glue.rs index d8d4573f94b4..69a2357aa455 100644 --- a/servo/ports/geckolib/glue.rs +++ b/servo/ports/geckolib/glue.rs @@ -137,9 +137,10 @@ use style::stylesheets::{ AllowImportRules, ContainerRule, CounterStyleRule, CssRule, CssRuleType, CssRuleTypes, CssRules, CssRulesHelpers, DocumentRule, FontFaceRule, FontFeatureValuesRule, FontPaletteValuesRule, ImportRule, KeyframesRule, LayerBlockRule, LayerStatementRule, - MediaRule, NamespaceRule, Origin, OriginSet, PagePseudoClassFlags, PageRule, PropertyRule, - SanitizationData, SanitizationKind, StartingStyleRule, StyleRule, StylesheetContents, - StylesheetLoader as StyleStylesheetLoader, SupportsRule, UrlExtraData, ScopeRule, + MarginRule, MediaRule, NamespaceRule, Origin, OriginSet, PagePseudoClassFlags, PageRule, + PropertyRule, SanitizationData, SanitizationKind, StartingStyleRule, StyleRule, + StylesheetContents, StylesheetLoader as StyleStylesheetLoader, SupportsRule, UrlExtraData, + ScopeRule, }; use style::stylist::{add_size_of_ua_cache, AuthorStylesEnabled, RuleInclusion, Stylist}; use style::thread_state; @@ -2402,6 +2403,13 @@ impl_group_rule_funcs! { (Media, MediaRule, MediaRule), changed: Servo_StyleSet_MediaRuleChanged, } +impl_basic_rule_funcs! { (Margin, MarginRule, MarginRule), + getter: Servo_CssRules_GetMarginRuleAt, + debug: Servo_MarginRule_Debug, + to_css: Servo_MarginRule_GetCssText, + changed: Servo_StyleSet_MarginRuleChanged, +} + impl_basic_rule_funcs! { (Namespace, NamespaceRule, NamespaceRule), getter: Servo_CssRules_GetNamespaceRuleAt, debug: Servo_NamespaceRule_Debug, @@ -2938,6 +2946,16 @@ pub extern "C" fn Servo_NamespaceRule_GetURI(rule: &NamespaceRule) -> *mut nsAto rule.url.0.as_ptr() } +#[no_mangle] +pub extern "C" fn Servo_MarginRule_GetStyle(rule: &MarginRule) -> Strong { + rule.block.clone().into() +} + +#[no_mangle] +pub extern "C" fn Servo_MarginRule_GetName(rule: &MarginRule, out: &mut nsACString) { + out.assign(rule.name()); +} + #[no_mangle] pub extern "C" fn Servo_PageRule_GetStyle(rule: &LockedPageRule) -> Strong { read_locked_arc(rule, |rule: &PageRule| rule.block.clone().into())