Line data Source code
1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* This Source Code Form is subject to the terms of the Mozilla Public
3 : * License, v. 2.0. If a copy of the MPL was not distributed with this
4 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 :
6 : /* DOM object for element.style */
7 :
8 : #include "nsDOMCSSAttrDeclaration.h"
9 :
10 : #include "mozilla/css/Declaration.h"
11 : #include "mozilla/css/StyleRule.h"
12 : #include "mozilla/DeclarationBlock.h"
13 : #include "mozilla/DeclarationBlockInlines.h"
14 : #include "mozilla/dom/Element.h"
15 : #include "mozilla/InternalMutationEvent.h"
16 : #include "mozilla/ServoDeclarationBlock.h"
17 : #include "nsContentUtils.h"
18 : #include "nsIDocument.h"
19 : #include "nsIDOMMutationEvent.h"
20 : #include "nsIURI.h"
21 : #include "nsNodeUtils.h"
22 : #include "nsWrapperCacheInlines.h"
23 : #include "nsIFrame.h"
24 : #include "ActiveLayerTracker.h"
25 :
26 : using namespace mozilla;
27 :
28 5 : nsDOMCSSAttributeDeclaration::nsDOMCSSAttributeDeclaration(dom::Element* aElement,
29 5 : bool aIsSMILOverride)
30 : : mElement(aElement)
31 5 : , mIsSMILOverride(aIsSMILOverride)
32 : {
33 5 : NS_ASSERTION(aElement, "Inline style for a NULL element?");
34 5 : }
35 :
36 0 : nsDOMCSSAttributeDeclaration::~nsDOMCSSAttributeDeclaration()
37 : {
38 0 : }
39 :
40 15 : NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsDOMCSSAttributeDeclaration, mElement)
41 :
42 : // mElement holds a strong ref to us, so if it's going to be
43 : // skipped, the attribute declaration can't be part of a garbage
44 : // cycle.
45 0 : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsDOMCSSAttributeDeclaration)
46 0 : if (tmp->mElement && Element::CanSkip(tmp->mElement, true)) {
47 0 : if (tmp->PreservingWrapper()) {
48 0 : tmp->MarkWrapperLive();
49 : }
50 0 : return true;
51 : }
52 0 : return tmp->HasKnownLiveWrapper();
53 : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
54 :
55 0 : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsDOMCSSAttributeDeclaration)
56 0 : return tmp->HasKnownLiveWrapper() ||
57 0 : (tmp->mElement && Element::CanSkipInCC(tmp->mElement));
58 : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
59 :
60 0 : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsDOMCSSAttributeDeclaration)
61 0 : return tmp->HasKnownLiveWrapper() ||
62 0 : (tmp->mElement && Element::CanSkipThis(tmp->mElement));
63 : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
64 :
65 55 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMCSSAttributeDeclaration)
66 10 : NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
67 5 : NS_IMPL_QUERY_TAIL_INHERITING(nsDOMCSSDeclaration)
68 :
69 15 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDOMCSSAttributeDeclaration)
70 5 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDOMCSSAttributeDeclaration)
71 :
72 : nsresult
73 5 : nsDOMCSSAttributeDeclaration::SetCSSDeclaration(DeclarationBlock* aDecl)
74 : {
75 5 : NS_ASSERTION(mElement, "Must have Element to set the declaration!");
76 5 : aDecl->SetDirty();
77 5 : return mIsSMILOverride
78 10 : ? mElement->SetSMILOverrideStyleDeclaration(aDecl, true)
79 10 : : mElement->SetInlineStyleDeclaration(aDecl, nullptr, true);
80 : }
81 :
82 : nsIDocument*
83 9 : nsDOMCSSAttributeDeclaration::DocToUpdate()
84 : {
85 : // We need OwnerDoc() rather than GetUncomposedDoc() because it might
86 : // be the BeginUpdate call that inserts mElement into the document.
87 9 : return mElement->OwnerDoc();
88 : }
89 :
90 : DeclarationBlock*
91 28 : nsDOMCSSAttributeDeclaration::GetCSSDeclaration(Operation aOperation)
92 : {
93 28 : if (!mElement)
94 0 : return nullptr;
95 :
96 : DeclarationBlock* declaration;
97 28 : if (mIsSMILOverride) {
98 0 : declaration = mElement->GetSMILOverrideStyleDeclaration();
99 : } else {
100 28 : declaration = mElement->GetInlineStyleDeclaration();
101 : }
102 :
103 : // Notify observers that our style="" attribute is going to change
104 : // unless:
105 : // * this is a declaration that holds SMIL animation values (which
106 : // aren't reflected in the DOM style="" attribute), or
107 : // * we're getting the declaration for reading, or
108 : // * we're getting it for property removal but we don't currently have
109 : // a declaration.
110 :
111 : // XXXbz this is a bit of a hack, especially doing it before the
112 : // BeginUpdate(), but this is a good chokepoint where we know we
113 : // plan to modify the CSSDeclaration, so need to notify
114 : // AttributeWillChange if this is inline style.
115 28 : if (!mIsSMILOverride &&
116 20 : ((aOperation == eOperation_Modify) ||
117 11 : (aOperation == eOperation_RemoveProperty && declaration))) {
118 9 : nsNodeUtils::AttributeWillChange(mElement, kNameSpaceID_None,
119 : nsGkAtoms::style,
120 : nsIDOMMutationEvent::MODIFICATION,
121 18 : nullptr);
122 : }
123 :
124 28 : if (declaration) {
125 10 : if (aOperation != eOperation_Read &&
126 5 : nsContentUtils::HasMutationListeners(
127 5 : mElement, NS_EVENT_BITS_MUTATION_ATTRMODIFIED, mElement)) {
128 : // If there is any mutation listener on the element, we need to
129 : // ensure that any change would create a new declaration so that
130 : // nsStyledElement::SetInlineStyleDeclaration can generate the
131 : // correct old value.
132 0 : declaration->SetImmutable();
133 : }
134 5 : return declaration;
135 : }
136 :
137 23 : if (aOperation != eOperation_Modify) {
138 19 : return nullptr;
139 : }
140 :
141 : // cannot fail
142 8 : RefPtr<DeclarationBlock> decl;
143 4 : if (mElement->IsStyledByServo()) {
144 0 : decl = new ServoDeclarationBlock();
145 : } else {
146 4 : decl = new css::Declaration();
147 4 : decl->AsGecko()->InitializeEmpty();
148 : }
149 :
150 : // this *can* fail (inside SetAttrAndNotify, at least).
151 : nsresult rv;
152 4 : if (mIsSMILOverride) {
153 0 : rv = mElement->SetSMILOverrideStyleDeclaration(decl, false);
154 : } else {
155 4 : rv = mElement->SetInlineStyleDeclaration(decl, nullptr, false);
156 : }
157 :
158 4 : if (NS_FAILED(rv)) {
159 0 : return nullptr; // the decl will be destroyed along with the style rule
160 : }
161 :
162 4 : return decl;
163 : }
164 :
165 : void
166 8 : nsDOMCSSAttributeDeclaration::GetCSSParsingEnvironment(CSSParsingEnvironment& aCSSParseEnv)
167 : {
168 8 : NS_ASSERTION(mElement, "Something is severely broken -- there should be an Element here!");
169 :
170 8 : nsIDocument* doc = mElement->OwnerDoc();
171 8 : aCSSParseEnv.mSheetURI = doc->GetDocumentURI();
172 8 : aCSSParseEnv.mBaseURI = mElement->GetBaseURIForStyleAttr();
173 8 : aCSSParseEnv.mPrincipal = mElement->NodePrincipal();
174 8 : aCSSParseEnv.mCSSLoader = doc->CSSLoader();
175 8 : }
176 :
177 : nsDOMCSSDeclaration::ServoCSSParsingEnvironment
178 0 : nsDOMCSSAttributeDeclaration::GetServoCSSParsingEnvironment() const
179 : {
180 : return {
181 0 : mElement->GetURLDataForStyleAttr(),
182 0 : mElement->OwnerDoc()->GetCompatibilityMode(),
183 0 : mElement->OwnerDoc()->CSSLoader(),
184 0 : };
185 : }
186 :
187 : NS_IMETHODIMP
188 0 : nsDOMCSSAttributeDeclaration::GetParentRule(nsIDOMCSSRule **aParent)
189 : {
190 0 : NS_ENSURE_ARG_POINTER(aParent);
191 :
192 0 : *aParent = nullptr;
193 0 : return NS_OK;
194 : }
195 :
196 : /* virtual */ nsINode*
197 5 : nsDOMCSSAttributeDeclaration::GetParentObject()
198 : {
199 5 : return mElement;
200 : }
201 :
202 : NS_IMETHODIMP
203 10 : nsDOMCSSAttributeDeclaration::SetPropertyValue(const nsCSSPropertyID aPropID,
204 : const nsAString& aValue)
205 : {
206 : // Scripted modifications to style.opacity or style.transform
207 : // could immediately force us into the animated state if heuristics suggest
208 : // this is scripted animation.
209 : // FIXME: This is missing the margin shorthand and the logical versions of
210 : // the margin properties, see bug 1266287.
211 10 : if (aPropID == eCSSProperty_opacity || aPropID == eCSSProperty_transform ||
212 10 : aPropID == eCSSProperty_left || aPropID == eCSSProperty_top ||
213 10 : aPropID == eCSSProperty_right || aPropID == eCSSProperty_bottom ||
214 10 : aPropID == eCSSProperty_margin_left || aPropID == eCSSProperty_margin_top ||
215 10 : aPropID == eCSSProperty_margin_right || aPropID == eCSSProperty_margin_bottom ||
216 10 : aPropID == eCSSProperty_background_position_x ||
217 10 : aPropID == eCSSProperty_background_position_y ||
218 : aPropID == eCSSProperty_background_position) {
219 0 : nsIFrame* frame = mElement->GetPrimaryFrame();
220 0 : if (frame) {
221 0 : ActiveLayerTracker::NotifyInlineStyleRuleModified(frame, aPropID, aValue, this);
222 : }
223 : }
224 10 : return nsDOMCSSDeclaration::SetPropertyValue(aPropID, aValue);
225 : }
|