summaryrefslogtreecommitdiffstats
path: root/layout/style/nsDOMCSSAttrDeclaration.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'layout/style/nsDOMCSSAttrDeclaration.cpp')
-rw-r--r--layout/style/nsDOMCSSAttrDeclaration.cpp216
1 files changed, 216 insertions, 0 deletions
diff --git a/layout/style/nsDOMCSSAttrDeclaration.cpp b/layout/style/nsDOMCSSAttrDeclaration.cpp
new file mode 100644
index 0000000000..acb4296eee
--- /dev/null
+++ b/layout/style/nsDOMCSSAttrDeclaration.cpp
@@ -0,0 +1,216 @@
+/* -*- 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/. */
+
+/* DOM object for element.style */
+
+#include "nsDOMCSSAttrDeclaration.h"
+
+#include "mozilla/dom/Document.h"
+#include "mozilla/dom/Element.h"
+#include "mozilla/dom/SVGElement.h"
+#include "mozilla/dom/MutationEventBinding.h"
+#include "mozilla/DeclarationBlock.h"
+#include "mozilla/InternalMutationEvent.h"
+#include "mozilla/SMILCSSValueType.h"
+#include "mozilla/SMILValue.h"
+#include "mozAutoDocUpdate.h"
+#include "nsWrapperCacheInlines.h"
+#include "nsIFrame.h"
+#include "ActiveLayerTracker.h"
+
+using namespace mozilla;
+using namespace mozilla::dom;
+
+nsDOMCSSAttributeDeclaration::nsDOMCSSAttributeDeclaration(Element* aElement,
+ bool aIsSMILOverride)
+ : mElement(aElement), mIsSMILOverride(aIsSMILOverride) {
+ NS_ASSERTION(aElement, "Inline style for a NULL element?");
+}
+
+nsDOMCSSAttributeDeclaration::~nsDOMCSSAttributeDeclaration() = default;
+
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsDOMCSSAttributeDeclaration, mElement)
+
+// mElement holds a strong ref to us, so if it's going to be
+// skipped, the attribute declaration can't be part of a garbage
+// cycle.
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsDOMCSSAttributeDeclaration)
+ if (tmp->mElement && Element::CanSkip(tmp->mElement, true)) {
+ if (tmp->PreservingWrapper()) {
+ tmp->MarkWrapperLive();
+ }
+ return true;
+ }
+ return tmp->HasKnownLiveWrapper();
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
+
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsDOMCSSAttributeDeclaration)
+ return tmp->HasKnownLiveWrapper() ||
+ (tmp->mElement && Element::CanSkipInCC(tmp->mElement));
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
+
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsDOMCSSAttributeDeclaration)
+ return tmp->HasKnownLiveWrapper() ||
+ (tmp->mElement && Element::CanSkipThis(tmp->mElement));
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMCSSAttributeDeclaration)
+ NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
+NS_INTERFACE_MAP_END_INHERITING(nsDOMCSSDeclaration)
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDOMCSSAttributeDeclaration)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDOMCSSAttributeDeclaration)
+
+nsresult nsDOMCSSAttributeDeclaration::SetCSSDeclaration(
+ DeclarationBlock* aDecl, MutationClosureData* aClosureData) {
+ NS_ASSERTION(mElement, "Must have Element to set the declaration!");
+
+ // Whenever changing element.style values, aClosureData must be non-null.
+ // SMIL doesn't update Element's attribute values, so closure data isn't
+ // needed.
+ MOZ_ASSERT_IF(!mIsSMILOverride, aClosureData);
+
+ // The closure needs to have been called by now, otherwise we shouldn't be
+ // getting here when the attribute hasn't changed.
+ MOZ_ASSERT_IF(aClosureData, !aClosureData->mClosure);
+
+ aDecl->SetDirty();
+ if (mIsSMILOverride) {
+ mElement->SetSMILOverrideStyleDeclaration(*aDecl);
+ return NS_OK;
+ }
+ return mElement->SetInlineStyleDeclaration(*aDecl, *aClosureData);
+}
+
+Document* nsDOMCSSAttributeDeclaration::DocToUpdate() {
+ // We need OwnerDoc() rather than GetUncomposedDoc() because it might
+ // be the BeginUpdate call that inserts mElement into the document.
+ return mElement->OwnerDoc();
+}
+
+DeclarationBlock* nsDOMCSSAttributeDeclaration::GetOrCreateCSSDeclaration(
+ Operation aOperation, DeclarationBlock** aCreated) {
+ MOZ_ASSERT(aOperation != eOperation_Modify || aCreated);
+
+ if (!mElement) return nullptr;
+
+ DeclarationBlock* declaration;
+ if (mIsSMILOverride) {
+ declaration = mElement->GetSMILOverrideStyleDeclaration();
+ } else {
+ declaration = mElement->GetInlineStyleDeclaration();
+ }
+
+ if (declaration) {
+ return declaration;
+ }
+
+ if (aOperation != eOperation_Modify) {
+ return nullptr;
+ }
+
+ // cannot fail
+ RefPtr<DeclarationBlock> decl = new DeclarationBlock();
+ // Mark the declaration dirty so that it can be reused by the caller.
+ // Normally SetDirty is called later in SetCSSDeclaration.
+ decl->SetDirty();
+#ifdef DEBUG
+ RefPtr<DeclarationBlock> mutableDecl = decl->EnsureMutable();
+ MOZ_ASSERT(mutableDecl == decl);
+#endif
+ decl.swap(*aCreated);
+ return *aCreated;
+}
+
+nsDOMCSSDeclaration::ParsingEnvironment
+nsDOMCSSAttributeDeclaration::GetParsingEnvironment(
+ nsIPrincipal* aSubjectPrincipal) const {
+ return {
+ mElement->GetURLDataForStyleAttr(aSubjectPrincipal),
+ mElement->OwnerDoc()->GetCompatibilityMode(),
+ mElement->OwnerDoc()->CSSLoader(),
+ };
+}
+
+template <typename SetterFunc>
+nsresult nsDOMCSSAttributeDeclaration::SetSMILValueHelper(SetterFunc aFunc) {
+ MOZ_ASSERT(mIsSMILOverride);
+
+ // No need to do the ActiveLayerTracker / ScrollLinkedEffectDetector bits,
+ // since we're in a SMIL animation anyway, no need to try to detect we're a
+ // scripted animation.
+ RefPtr<DeclarationBlock> created;
+ DeclarationBlock* olddecl =
+ GetOrCreateCSSDeclaration(eOperation_Modify, getter_AddRefs(created));
+ if (!olddecl) {
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+ mozAutoDocUpdate autoUpdate(DocToUpdate(), true);
+ RefPtr<DeclarationBlock> decl = olddecl->EnsureMutable();
+
+ bool changed = aFunc(*decl);
+
+ if (changed) {
+ // We can pass nullptr as the latter param, since this is
+ // mIsSMILOverride == true case.
+ SetCSSDeclaration(decl, nullptr);
+ }
+ return NS_OK;
+}
+
+nsresult nsDOMCSSAttributeDeclaration::SetSMILValue(
+ const nsCSSPropertyID /*aPropID*/, const SMILValue& aValue) {
+ MOZ_ASSERT(aValue.mType == &SMILCSSValueType::sSingleton,
+ "We should only try setting a CSS value type");
+ return SetSMILValueHelper([&aValue](DeclarationBlock& aDecl) {
+ return SMILCSSValueType::SetPropertyValues(aValue, aDecl);
+ });
+}
+
+nsresult nsDOMCSSAttributeDeclaration::SetSMILValue(
+ const nsCSSPropertyID aPropID, const SVGAnimatedLength& aLength) {
+ return SetSMILValueHelper([aPropID, &aLength](DeclarationBlock& aDecl) {
+ return SVGElement::UpdateDeclarationBlockFromLength(
+ aDecl, aPropID, aLength, SVGElement::ValToUse::Anim);
+ });
+}
+
+void nsDOMCSSAttributeDeclaration::SetPropertyValue(
+ const nsCSSPropertyID aPropID, const nsACString& aValue,
+ nsIPrincipal* aSubjectPrincipal, ErrorResult& aRv) {
+ // Scripted modifications to style.opacity or style.transform (or other
+ // transform-like properties, e.g. style.translate, style.rotate, style.scale)
+ // could immediately force us into the animated state if heuristics suggest
+ // this is scripted animation.
+ // FIXME: This is missing the margin shorthand and the logical versions of
+ // the margin properties, see bug 1266287.
+ if (aPropID == eCSSProperty_opacity || aPropID == eCSSProperty_transform ||
+ aPropID == eCSSProperty_translate || aPropID == eCSSProperty_rotate ||
+ aPropID == eCSSProperty_scale || aPropID == eCSSProperty_offset_path ||
+ aPropID == eCSSProperty_offset_distance ||
+ aPropID == eCSSProperty_offset_rotate ||
+ aPropID == eCSSProperty_offset_anchor || aPropID == eCSSProperty_left ||
+ aPropID == eCSSProperty_top || aPropID == eCSSProperty_right ||
+ aPropID == eCSSProperty_bottom ||
+ aPropID == eCSSProperty_background_position_x ||
+ aPropID == eCSSProperty_background_position_y ||
+ aPropID == eCSSProperty_background_position) {
+ nsIFrame* frame = mElement->GetPrimaryFrame();
+ if (frame) {
+ ActiveLayerTracker::NotifyInlineStyleRuleModified(frame, aPropID, aValue,
+ this);
+ }
+ }
+ nsDOMCSSDeclaration::SetPropertyValue(aPropID, aValue, aSubjectPrincipal,
+ aRv);
+}
+
+void nsDOMCSSAttributeDeclaration::MutationClosureFunction(void* aData) {
+ MutationClosureData* data = static_cast<MutationClosureData*>(aData);
+ // Clear mClosure pointer so that it doesn't get called again.
+ data->mClosure = nullptr;
+ data->mElement->InlineStyleDeclarationWillChange(*data);
+}