Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 : /* This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #include "nsStyledElement.h"
8 : #include "mozAutoDocUpdate.h"
9 : #include "nsGkAtoms.h"
10 : #include "nsAttrValue.h"
11 : #include "nsAttrValueInlines.h"
12 : #include "mozilla/dom/ElementInlines.h"
13 : #include "mozilla/InternalMutationEvent.h"
14 : #include "nsDOMCSSDeclaration.h"
15 : #include "nsDOMCSSAttrDeclaration.h"
16 : #include "nsServiceManagerUtils.h"
17 : #include "nsIDocument.h"
18 : #include "mozilla/DeclarationBlockInlines.h"
19 : #include "nsCSSParser.h"
20 : #include "mozilla/css/Loader.h"
21 : #include "nsIDOMMutationEvent.h"
22 : #include "nsXULElement.h"
23 : #include "nsContentUtils.h"
24 : #include "nsStyleUtil.h"
25 :
26 : using namespace mozilla;
27 : using namespace mozilla::dom;
28 :
29 2354 : NS_IMPL_QUERY_INTERFACE_INHERITED(nsStyledElement,
30 : nsStyledElementBase,
31 : nsStyledElement)
32 :
33 : //----------------------------------------------------------------------
34 : // nsIContent methods
35 :
36 : bool
37 1190 : nsStyledElement::ParseAttribute(int32_t aNamespaceID,
38 : nsIAtom* aAttribute,
39 : const nsAString& aValue,
40 : nsAttrValue& aResult)
41 : {
42 1190 : if (aAttribute == nsGkAtoms::style && aNamespaceID == kNameSpaceID_None) {
43 0 : ParseStyleAttribute(aValue, aResult, false);
44 0 : return true;
45 : }
46 :
47 1190 : return nsStyledElementBase::ParseAttribute(aNamespaceID, aAttribute, aValue,
48 1190 : aResult);
49 : }
50 :
51 : nsresult
52 1548 : nsStyledElement::BeforeSetAttr(int32_t aNamespaceID, nsIAtom* aName,
53 : const nsAttrValueOrString* aValue, bool aNotify)
54 : {
55 1548 : if (aNamespaceID == kNameSpaceID_None) {
56 1468 : if (aName == nsGkAtoms::style) {
57 0 : if (aValue) {
58 0 : SetMayHaveStyle();
59 : }
60 : }
61 : }
62 :
63 1548 : return nsStyledElementBase::BeforeSetAttr(aNamespaceID, aName, aValue,
64 1548 : aNotify);
65 : }
66 :
67 : nsresult
68 9 : nsStyledElement::SetInlineStyleDeclaration(DeclarationBlock* aDeclaration,
69 : const nsAString* aSerialized,
70 : bool aNotify)
71 : {
72 9 : SetMayHaveStyle();
73 9 : bool modification = false;
74 18 : nsAttrValue oldValue;
75 9 : bool oldValueSet = false;
76 :
77 14 : bool hasListeners = aNotify &&
78 5 : nsContentUtils::HasMutationListeners(this,
79 : NS_EVENT_BITS_MUTATION_ATTRMODIFIED,
80 9 : this);
81 :
82 : // There's no point in comparing the stylerule pointers since we're always
83 : // getting a new stylerule here. And we can't compare the stringvalues of
84 : // the old and the new rules since both will point to the same declaration
85 : // and thus will be the same.
86 9 : if (hasListeners) {
87 : // save the old attribute so we can set up the mutation event properly
88 0 : nsAutoString oldValueStr;
89 0 : modification = GetAttr(kNameSpaceID_None, nsGkAtoms::style,
90 0 : oldValueStr);
91 0 : if (modification) {
92 0 : oldValue.SetTo(oldValueStr);
93 0 : oldValueSet = true;
94 : }
95 : }
96 9 : else if (aNotify && IsInUncomposedDoc()) {
97 5 : modification = !!mAttrsAndChildren.GetAttr(nsGkAtoms::style);
98 : }
99 :
100 18 : nsAttrValue attrValue(do_AddRef(aDeclaration), aSerialized);
101 :
102 : // XXXbz do we ever end up with ADDITION here? I doubt it.
103 9 : uint8_t modType = modification ?
104 : static_cast<uint8_t>(nsIDOMMutationEvent::MODIFICATION) :
105 9 : static_cast<uint8_t>(nsIDOMMutationEvent::ADDITION);
106 :
107 9 : nsIDocument* document = GetComposedDoc();
108 18 : mozAutoDocUpdate updateBatch(document, UPDATE_CONTENT_MODEL, aNotify);
109 9 : return SetAttrAndNotify(kNameSpaceID_None, nsGkAtoms::style, nullptr,
110 : oldValueSet ? &oldValue : nullptr, attrValue, modType,
111 : hasListeners, aNotify, kDontCallAfterSetAttr,
112 18 : document, updateBatch);
113 : }
114 :
115 : // ---------------------------------------------------------------
116 : // Others and helpers
117 :
118 : nsICSSDeclaration*
119 19 : nsStyledElement::Style()
120 : {
121 19 : Element::nsDOMSlots *slots = DOMSlots();
122 :
123 19 : if (!slots->mStyle) {
124 : // Just in case...
125 5 : ReparseStyleAttribute(true, false);
126 :
127 5 : slots->mStyle = new nsDOMCSSAttributeDeclaration(this, false);
128 5 : SetMayHaveStyle();
129 : }
130 :
131 19 : return slots->mStyle;
132 : }
133 :
134 : nsresult
135 5 : nsStyledElement::ReparseStyleAttribute(bool aForceInDataDoc, bool aForceIfAlreadyParsed)
136 : {
137 5 : if (!MayHaveStyle()) {
138 5 : return NS_OK;
139 : }
140 0 : const nsAttrValue* oldVal = mAttrsAndChildren.GetAttr(nsGkAtoms::style);
141 0 : if (oldVal && (aForceIfAlreadyParsed || oldVal->Type() != nsAttrValue::eCSSDeclaration)) {
142 0 : nsAttrValue attrValue;
143 0 : nsAutoString stringValue;
144 0 : oldVal->ToString(stringValue);
145 0 : ParseStyleAttribute(stringValue, attrValue, aForceInDataDoc);
146 : // Don't bother going through SetInlineStyleDeclaration; we don't
147 : // want to fire off mutation events or document notifications anyway
148 : bool oldValueSet;
149 0 : nsresult rv = mAttrsAndChildren.SetAndSwapAttr(nsGkAtoms::style, attrValue,
150 0 : &oldValueSet);
151 0 : NS_ENSURE_SUCCESS(rv, rv);
152 : }
153 :
154 0 : return NS_OK;
155 : }
156 :
157 : void
158 0 : nsStyledElement::NodeInfoChanged(nsIDocument* aOldDoc)
159 : {
160 0 : nsStyledElementBase::NodeInfoChanged(aOldDoc);
161 0 : if (OwnerDoc()->GetStyleBackendType() != aOldDoc->GetStyleBackendType()) {
162 0 : ReparseStyleAttribute(false, /* aForceIfAlreadyParsed */ true);
163 : }
164 0 : }
165 :
166 : nsICSSDeclaration*
167 0 : nsStyledElement::GetExistingStyle()
168 : {
169 0 : Element::nsDOMSlots* slots = GetExistingDOMSlots();
170 0 : if (!slots) {
171 0 : return nullptr;
172 : }
173 :
174 0 : return slots->mStyle;
175 : }
176 :
177 : void
178 0 : nsStyledElement::ParseStyleAttribute(const nsAString& aValue,
179 : nsAttrValue& aResult,
180 : bool aForceInDataDoc)
181 : {
182 0 : nsIDocument* doc = OwnerDoc();
183 0 : bool isNativeAnon = IsInNativeAnonymousSubtree();
184 :
185 0 : if (!isNativeAnon &&
186 0 : !nsStyleUtil::CSPAllowsInlineStyle(nullptr, NodePrincipal(),
187 : doc->GetDocumentURI(), 0, aValue,
188 : nullptr))
189 0 : return;
190 :
191 0 : if (aForceInDataDoc ||
192 0 : !doc->IsLoadedAsData() ||
193 0 : GetExistingStyle() ||
194 0 : doc->IsStaticDocument()) {
195 0 : bool isCSS = true; // assume CSS until proven otherwise
196 :
197 0 : if (!isNativeAnon) { // native anonymous content always assumes CSS
198 0 : nsAutoString styleType;
199 0 : doc->GetHeaderData(nsGkAtoms::headerContentStyleType, styleType);
200 0 : if (!styleType.IsEmpty()) {
201 : static const char textCssStr[] = "text/css";
202 0 : isCSS = (styleType.EqualsIgnoreCase(textCssStr, sizeof(textCssStr) - 1));
203 : }
204 : }
205 :
206 0 : if (isCSS && aResult.ParseStyleAttribute(aValue, this)) {
207 0 : return;
208 : }
209 : }
210 :
211 0 : aResult.SetTo(aValue);
212 : }
|