/* -*- 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 "mozilla/dom/CSSKeyframeRule.h" #include "mozilla/DeclarationBlock.h" #include "mozilla/dom/CSSKeyframeRuleBinding.h" #include "nsDOMCSSDeclaration.h" namespace mozilla::dom { // ------------------------------------------- // CSSKeyframeDeclaration // class CSSKeyframeDeclaration : public nsDOMCSSDeclaration { public: explicit CSSKeyframeDeclaration(CSSKeyframeRule* aRule) : mRule(aRule) { mDecls = new DeclarationBlock(Servo_Keyframe_GetStyle(aRule->Raw()).Consume()); mDecls->SetOwningRule(aRule); } NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS_AMBIGUOUS(CSSKeyframeDeclaration, nsICSSDeclaration) css::Rule* GetParentRule() final { return mRule; } void DropReference() { mRule = nullptr; mDecls->SetOwningRule(nullptr); } DeclarationBlock* GetOrCreateCSSDeclaration( Operation aOperation, DeclarationBlock** aCreated) final { if (aOperation != Operation::Read && mRule) { if (StyleSheet* sheet = mRule->GetStyleSheet()) { sheet->WillDirty(); } } return mDecls; } nsresult SetCSSDeclaration(DeclarationBlock* aDecls, MutationClosureData* aClosureData) final { if (!mRule) { return NS_OK; } mRule->UpdateRule([this, aDecls]() { if (mDecls != aDecls) { mDecls->SetOwningRule(nullptr); mDecls = aDecls; mDecls->SetOwningRule(mRule); Servo_Keyframe_SetStyle(mRule->Raw(), mDecls->Raw()); } }); return NS_OK; } ParsingEnvironment GetParsingEnvironment( nsIPrincipal* aSubjectPrincipal) const final { return GetParsingEnvironmentForRule(mRule, StyleCssRuleType::Keyframe); } Document* DocToUpdate() final { return nullptr; } nsINode* GetAssociatedNode() const final { return mRule ? mRule->GetAssociatedDocumentOrShadowRoot() : nullptr; } nsISupports* GetParentObject() const final { return mRule ? mRule->GetParentObject() : nullptr; } size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const { size_t n = aMallocSizeOf(this); // TODO we may want to add size of mDecls as well return n; } void SetRawAfterClone(StyleLockedKeyframe* aKeyframe) { mDecls->SetOwningRule(nullptr); mDecls = new DeclarationBlock(Servo_Keyframe_GetStyle(aKeyframe).Consume()); mDecls->SetOwningRule(mRule); } private: virtual ~CSSKeyframeDeclaration() { MOZ_ASSERT(!mRule, "Backpointer should have been cleared"); } CSSKeyframeRule* mRule; RefPtr mDecls; }; NS_IMPL_CYCLE_COLLECTING_ADDREF(CSSKeyframeDeclaration) NS_IMPL_CYCLE_COLLECTING_RELEASE(CSSKeyframeDeclaration) NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(CSSKeyframeDeclaration) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CSSKeyframeDeclaration) NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY NS_INTERFACE_MAP_END_INHERITING(nsDOMCSSDeclaration) // ------------------------------------------- // CSSKeyframeRule // CSSKeyframeRule::CSSKeyframeRule(already_AddRefed aRaw, StyleSheet* aSheet, css::Rule* aParentRule, uint32_t aLine, uint32_t aColumn) : css::Rule(aSheet, aParentRule, aLine, aColumn), mRaw(aRaw) {} CSSKeyframeRule::~CSSKeyframeRule() { if (mDeclaration) { mDeclaration->DropReference(); } } NS_IMPL_ADDREF_INHERITED(CSSKeyframeRule, css::Rule) NS_IMPL_RELEASE_INHERITED(CSSKeyframeRule, css::Rule) // QueryInterface implementation for nsCSSKeyframeRule NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CSSKeyframeRule) NS_INTERFACE_MAP_END_INHERITING(css::Rule) NS_IMPL_CYCLE_COLLECTION_CLASS(CSSKeyframeRule) NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(CSSKeyframeRule, css::Rule) if (tmp->mDeclaration) { tmp->mDeclaration->DropReference(); tmp->mDeclaration = nullptr; } NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(CSSKeyframeRule, css::Rule) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDeclaration) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END bool CSSKeyframeRule::IsCCLeaf() const { return Rule::IsCCLeaf() && !mDeclaration; } StyleCssRuleType CSSKeyframeRule::Type() const { return StyleCssRuleType::Keyframe; } void CSSKeyframeRule::SetRawAfterClone(RefPtr aRaw) { mRaw = std::move(aRaw); if (mDeclaration) { mDeclaration->SetRawAfterClone(mRaw); } } #ifdef DEBUG /* virtual */ void CSSKeyframeRule::List(FILE* out, int32_t aIndent) const { nsAutoCString str; for (int32_t i = 0; i < aIndent; i++) { str.AppendLiteral(" "); } Servo_Keyframe_Debug(mRaw, &str); fprintf_stderr(out, "%s\n", str.get()); } #endif template void CSSKeyframeRule::UpdateRule(Func aCallback) { if (IsReadOnly()) { return; } StyleSheet* sheet = GetStyleSheet(); if (sheet) { sheet->WillDirty(); } aCallback(); if (sheet) { sheet->RuleChanged(this, StyleRuleChangeKind::Generic); } } void CSSKeyframeRule::GetKeyText(nsACString& aKeyText) { Servo_Keyframe_GetKeyText(mRaw, &aKeyText); } void CSSKeyframeRule::SetKeyText(const nsACString& aKeyText) { UpdateRule( [this, &aKeyText]() { Servo_Keyframe_SetKeyText(mRaw, &aKeyText); }); } void CSSKeyframeRule::GetCssText(nsACString& aCssText) const { Servo_Keyframe_GetCssText(mRaw, &aCssText); } nsICSSDeclaration* CSSKeyframeRule::Style() { if (!mDeclaration) { mDeclaration = new CSSKeyframeDeclaration(this); } return mDeclaration; } size_t CSSKeyframeRule::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const { size_t n = aMallocSizeOf(this); if (mDeclaration) { n += mDeclaration->SizeOfIncludingThis(aMallocSizeOf); } return n; } /* virtual */ JSObject* CSSKeyframeRule::WrapObject(JSContext* aCx, JS::Handle aGivenProto) { return CSSKeyframeRule_Binding::Wrap(aCx, this, aGivenProto); } } // namespace mozilla::dom