1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is Mozilla Communicator client code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1998
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * Mats Palmgren <mats.palmgren@bredband.net>
24 : *
25 : * Alternatively, the contents of this file may be used under the terms of
26 : * either of the GNU General Public License Version 2 or later (the "GPL"),
27 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 : * in which case the provisions of the GPL or the LGPL are applicable instead
29 : * of those above. If you wish to allow use of your version of this file only
30 : * under the terms of either the GPL or the LGPL, and not to allow others to
31 : * use your version of this file under the terms of the MPL, indicate your
32 : * decision by deleting the provisions above and replace them with the notice
33 : * and other provisions required by the GPL or the LGPL. If you do not delete
34 : * the provisions above, a recipient may use your version of this file under
35 : * the terms of any one of the MPL, the GPL or the LGPL.
36 : *
37 : * ***** END LICENSE BLOCK ***** */
38 :
39 : /* base class for DOM objects for element.style and cssStyleRule.style */
40 :
41 : #include "nsDOMCSSDeclaration.h"
42 : #include "nsIDOMCSSRule.h"
43 : #include "nsCSSParser.h"
44 : #include "mozilla/css/Loader.h"
45 : #include "nsCSSStyleSheet.h"
46 : #include "nsIStyleRule.h"
47 : #include "mozilla/css/Rule.h"
48 : #include "mozilla/css/Declaration.h"
49 : #include "nsCSSProps.h"
50 : #include "nsCOMPtr.h"
51 : #include "nsIURL.h"
52 : #include "nsReadableUtils.h"
53 : #include "nsIPrincipal.h"
54 :
55 : #include "nsContentUtils.h"
56 : #include "mozAutoDocUpdate.h"
57 :
58 : namespace css = mozilla::css;
59 :
60 0 : nsDOMCSSDeclaration::~nsDOMCSSDeclaration()
61 : {
62 0 : }
63 :
64 : DOMCI_DATA(CSSStyleDeclaration, nsDOMCSSDeclaration)
65 :
66 0 : NS_INTERFACE_TABLE_HEAD(nsDOMCSSDeclaration)
67 0 : NS_INTERFACE_TABLE3(nsDOMCSSDeclaration,
68 : nsICSSDeclaration,
69 : nsIDOMCSSStyleDeclaration,
70 : nsIDOMCSS2Properties)
71 0 : NS_INTERFACE_TABLE_TO_MAP_SEGUE
72 0 : NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(CSSStyleDeclaration)
73 0 : NS_INTERFACE_MAP_END
74 :
75 : NS_IMETHODIMP
76 0 : nsDOMCSSDeclaration::GetPropertyValue(const nsCSSProperty aPropID,
77 : nsAString& aValue)
78 : {
79 0 : NS_PRECONDITION(aPropID != eCSSProperty_UNKNOWN,
80 : "Should never pass eCSSProperty_UNKNOWN around");
81 :
82 0 : css::Declaration* decl = GetCSSDeclaration(false);
83 :
84 0 : aValue.Truncate();
85 0 : if (decl) {
86 0 : decl->GetValue(aPropID, aValue);
87 : }
88 0 : return NS_OK;
89 : }
90 :
91 : NS_IMETHODIMP
92 0 : nsDOMCSSDeclaration::SetPropertyValue(const nsCSSProperty aPropID,
93 : const nsAString& aValue)
94 : {
95 0 : if (aValue.IsEmpty()) {
96 : // If the new value of the property is an empty string we remove the
97 : // property.
98 0 : return RemoveProperty(aPropID);
99 : }
100 :
101 0 : return ParsePropertyValue(aPropID, aValue, false);
102 : }
103 :
104 :
105 : NS_IMETHODIMP
106 0 : nsDOMCSSDeclaration::GetCssText(nsAString& aCssText)
107 : {
108 0 : css::Declaration* decl = GetCSSDeclaration(false);
109 0 : aCssText.Truncate();
110 :
111 0 : if (decl) {
112 0 : decl->ToString(aCssText);
113 : }
114 :
115 0 : return NS_OK;
116 : }
117 :
118 : NS_IMETHODIMP
119 0 : nsDOMCSSDeclaration::SetCssText(const nsAString& aCssText)
120 : {
121 : // We don't need to *do* anything with the old declaration, but we need
122 : // to ensure that it exists, or else SetCSSDeclaration may crash.
123 0 : css::Declaration* olddecl = GetCSSDeclaration(true);
124 0 : if (!olddecl) {
125 0 : return NS_ERROR_FAILURE;
126 : }
127 :
128 0 : CSSParsingEnvironment env;
129 0 : GetCSSParsingEnvironment(env);
130 0 : if (!env.mPrincipal) {
131 0 : return NS_ERROR_NOT_AVAILABLE;
132 : }
133 :
134 : // For nsDOMCSSAttributeDeclaration, SetCSSDeclaration will lead to
135 : // Attribute setting code, which leads in turn to BeginUpdate. We
136 : // need to start the update now so that the old rule doesn't get used
137 : // between when we mutate the declaration and when we set the new
138 : // rule (see stack in bug 209575).
139 0 : mozAutoDocConditionalContentUpdateBatch autoUpdate(DocToUpdate(), true);
140 :
141 0 : nsAutoPtr<css::Declaration> decl(new css::Declaration());
142 0 : decl->InitializeEmpty();
143 0 : nsCSSParser cssParser(env.mCSSLoader);
144 : bool changed;
145 : nsresult result = cssParser.ParseDeclarations(aCssText, env.mSheetURI,
146 : env.mBaseURI,
147 0 : env.mPrincipal, decl, &changed);
148 0 : if (NS_FAILED(result) || !changed) {
149 0 : return result;
150 : }
151 :
152 0 : return SetCSSDeclaration(decl.forget());
153 : }
154 :
155 : NS_IMETHODIMP
156 0 : nsDOMCSSDeclaration::GetLength(PRUint32* aLength)
157 : {
158 0 : css::Declaration* decl = GetCSSDeclaration(false);
159 :
160 0 : if (decl) {
161 0 : *aLength = decl->Count();
162 : } else {
163 0 : *aLength = 0;
164 : }
165 :
166 0 : return NS_OK;
167 : }
168 :
169 : NS_IMETHODIMP
170 0 : nsDOMCSSDeclaration::GetPropertyCSSValue(const nsAString& aPropertyName,
171 : nsIDOMCSSValue** aReturn)
172 : {
173 0 : NS_ENSURE_ARG_POINTER(aReturn);
174 :
175 : // We don't support CSSValue yet so we'll just return null...
176 0 : *aReturn = nsnull;
177 :
178 0 : return NS_OK;
179 : }
180 :
181 : NS_IMETHODIMP
182 0 : nsDOMCSSDeclaration::Item(PRUint32 aIndex, nsAString& aReturn)
183 : {
184 0 : css::Declaration* decl = GetCSSDeclaration(false);
185 :
186 0 : aReturn.SetLength(0);
187 0 : if (decl) {
188 0 : decl->GetNthProperty(aIndex, aReturn);
189 : }
190 :
191 0 : return NS_OK;
192 : }
193 :
194 : NS_IMETHODIMP
195 0 : nsDOMCSSDeclaration::GetPropertyValue(const nsAString& aPropertyName,
196 : nsAString& aReturn)
197 : {
198 0 : const nsCSSProperty propID = nsCSSProps::LookupProperty(aPropertyName);
199 0 : if (propID == eCSSProperty_UNKNOWN) {
200 0 : aReturn.Truncate();
201 0 : return NS_OK;
202 : }
203 :
204 0 : return GetPropertyValue(propID, aReturn);
205 : }
206 :
207 : NS_IMETHODIMP
208 0 : nsDOMCSSDeclaration::GetPropertyPriority(const nsAString& aPropertyName,
209 : nsAString& aReturn)
210 : {
211 0 : css::Declaration* decl = GetCSSDeclaration(false);
212 :
213 0 : aReturn.Truncate();
214 0 : if (decl && decl->GetValueIsImportant(aPropertyName)) {
215 0 : aReturn.AssignLiteral("important");
216 : }
217 :
218 0 : return NS_OK;
219 : }
220 :
221 : NS_IMETHODIMP
222 0 : nsDOMCSSDeclaration::SetProperty(const nsAString& aPropertyName,
223 : const nsAString& aValue,
224 : const nsAString& aPriority)
225 : {
226 : // In the common (and fast) cases we can use the property id
227 0 : nsCSSProperty propID = nsCSSProps::LookupProperty(aPropertyName);
228 0 : if (propID == eCSSProperty_UNKNOWN) {
229 0 : return NS_OK;
230 : }
231 :
232 0 : if (aValue.IsEmpty()) {
233 : // If the new value of the property is an empty string we remove the
234 : // property.
235 : // XXX this ignores the priority string, should it?
236 0 : return RemoveProperty(propID);
237 : }
238 :
239 0 : if (aPriority.IsEmpty()) {
240 0 : return ParsePropertyValue(propID, aValue, false);
241 : }
242 :
243 0 : if (aPriority.EqualsLiteral("important")) {
244 0 : return ParsePropertyValue(propID, aValue, true);
245 : }
246 :
247 : // XXX silent failure?
248 0 : return NS_OK;
249 : }
250 :
251 : NS_IMETHODIMP
252 0 : nsDOMCSSDeclaration::RemoveProperty(const nsAString& aPropertyName,
253 : nsAString& aReturn)
254 : {
255 0 : const nsCSSProperty propID = nsCSSProps::LookupProperty(aPropertyName);
256 0 : if (propID == eCSSProperty_UNKNOWN) {
257 0 : aReturn.Truncate();
258 0 : return NS_OK;
259 : }
260 :
261 0 : nsresult rv = GetPropertyValue(propID, aReturn);
262 0 : NS_ENSURE_SUCCESS(rv, rv);
263 :
264 0 : return RemoveProperty(propID);
265 : }
266 :
267 : /* static */ void
268 0 : nsDOMCSSDeclaration::GetCSSParsingEnvironmentForRule(css::Rule* aRule,
269 : CSSParsingEnvironment& aCSSParseEnv)
270 : {
271 0 : nsIStyleSheet* sheet = aRule ? aRule->GetStyleSheet() : nsnull;
272 0 : nsRefPtr<nsCSSStyleSheet> cssSheet(do_QueryObject(sheet));
273 0 : if (!cssSheet) {
274 0 : aCSSParseEnv.mPrincipal = nsnull;
275 : return;
276 : }
277 :
278 0 : nsIDocument* document = sheet->GetOwningDocument();
279 0 : aCSSParseEnv.mSheetURI = sheet->GetSheetURI();
280 0 : aCSSParseEnv.mBaseURI = sheet->GetBaseURI();
281 0 : aCSSParseEnv.mPrincipal = cssSheet->Principal();
282 0 : aCSSParseEnv.mCSSLoader = document ? document->CSSLoader() : nsnull;
283 : }
284 :
285 : nsresult
286 0 : nsDOMCSSDeclaration::ParsePropertyValue(const nsCSSProperty aPropID,
287 : const nsAString& aPropValue,
288 : bool aIsImportant)
289 : {
290 0 : css::Declaration* olddecl = GetCSSDeclaration(true);
291 0 : if (!olddecl) {
292 0 : return NS_ERROR_FAILURE;
293 : }
294 :
295 0 : CSSParsingEnvironment env;
296 0 : GetCSSParsingEnvironment(env);
297 0 : if (!env.mPrincipal) {
298 0 : return NS_ERROR_NOT_AVAILABLE;
299 : }
300 :
301 : // For nsDOMCSSAttributeDeclaration, SetCSSDeclaration will lead to
302 : // Attribute setting code, which leads in turn to BeginUpdate. We
303 : // need to start the update now so that the old rule doesn't get used
304 : // between when we mutate the declaration and when we set the new
305 : // rule (see stack in bug 209575).
306 0 : mozAutoDocConditionalContentUpdateBatch autoUpdate(DocToUpdate(), true);
307 0 : css::Declaration* decl = olddecl->EnsureMutable();
308 :
309 0 : nsCSSParser cssParser(env.mCSSLoader);
310 : bool changed;
311 : nsresult result = cssParser.ParseProperty(aPropID, aPropValue, env.mSheetURI,
312 : env.mBaseURI, env.mPrincipal, decl,
313 0 : &changed, aIsImportant);
314 0 : if (NS_FAILED(result) || !changed) {
315 0 : if (decl != olddecl) {
316 0 : delete decl;
317 : }
318 0 : return result;
319 : }
320 :
321 0 : return SetCSSDeclaration(decl);
322 : }
323 :
324 : nsresult
325 0 : nsDOMCSSDeclaration::RemoveProperty(const nsCSSProperty aPropID)
326 : {
327 0 : css::Declaration* decl = GetCSSDeclaration(false);
328 0 : if (!decl) {
329 0 : return NS_OK; // no decl, so nothing to remove
330 : }
331 :
332 : // For nsDOMCSSAttributeDeclaration, SetCSSDeclaration will lead to
333 : // Attribute setting code, which leads in turn to BeginUpdate. We
334 : // need to start the update now so that the old rule doesn't get used
335 : // between when we mutate the declaration and when we set the new
336 : // rule (see stack in bug 209575).
337 0 : mozAutoDocConditionalContentUpdateBatch autoUpdate(DocToUpdate(), true);
338 :
339 0 : decl = decl->EnsureMutable();
340 0 : decl->RemoveProperty(aPropID);
341 0 : return SetCSSDeclaration(decl);
342 : }
343 :
344 : // nsIDOMCSS2Properties
345 :
346 : #define CSS_PROP_DOMPROP_PREFIXED(prop_) Moz ## prop_
347 : #define CSS_PROP(name_, id_, method_, flags_, parsevariant_, kwtable_, \
348 : stylestruct_, stylestructoffset_, animtype_) \
349 : NS_IMETHODIMP \
350 : nsDOMCSSDeclaration::Get##method_(nsAString& aValue) \
351 : { \
352 : return GetPropertyValue(eCSSProperty_##id_, aValue); \
353 : } \
354 : \
355 : NS_IMETHODIMP \
356 : nsDOMCSSDeclaration::Set##method_(const nsAString& aValue) \
357 : { \
358 : return SetPropertyValue(eCSSProperty_##id_, aValue); \
359 : }
360 :
361 : #define CSS_PROP_LIST_EXCLUDE_INTERNAL
362 : #define CSS_PROP_SHORTHAND(name_, id_, method_, flags_) \
363 : CSS_PROP(name_, id_, method_, flags_, X, X, X, X, X)
364 : #include "nsCSSPropList.h"
365 :
366 : #define CSS_PROP_ALIAS(aliasname_, propid_, aliasmethod_) \
367 : CSS_PROP(X, propid_, aliasmethod_, X, X, X, X, X, X)
368 : #include "nsCSSPropAliasList.h"
369 : #undef CSS_PROP_ALIAS
370 :
371 : #undef CSS_PROP_SHORTHAND
372 : #undef CSS_PROP_LIST_EXCLUDE_INTERNAL
373 : #undef CSS_PROP
374 : #undef CSS_PROP_DOMPROP_PREFIXED
|