CLOSED TREE: TraceMonkey merge head. (a=blockers)
[mozilla-central.git] / layout / style / nsCSSStyleSheet.cpp
blobde63fc7d284791690af6996073fdce3b90fa326d
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 // vim:cindent:tabstop=2:expandtab:shiftwidth=2:
3 /* ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
14 * License.
16 * The Original Code is mozilla.org code.
18 * The Initial Developer of the Original Code is
19 * Netscape Communications Corporation.
20 * Portions created by the Initial Developer are Copyright (C) 1998
21 * the Initial Developer. All Rights Reserved.
23 * Contributor(s):
24 * L. David Baron <dbaron@dbaron.org>
25 * Pierre Phaneuf <pp@ludusdesign.com>
26 * Daniel Glazman <glazman@netscape.com>
28 * Alternatively, the contents of this file may be used under the terms of
29 * either of the GNU General Public License Version 2 or later (the "GPL"),
30 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
31 * in which case the provisions of the GPL or the LGPL are applicable instead
32 * of those above. If you wish to allow use of your version of this file only
33 * under the terms of either the GPL or the LGPL, and not to allow others to
34 * use your version of this file under the terms of the MPL, indicate your
35 * decision by deleting the provisions above and replace them with the notice
36 * and other provisions required by the GPL or the LGPL. If you do not delete
37 * the provisions above, a recipient may use your version of this file under
38 * the terms of any one of the MPL, the GPL or the LGPL.
40 * ***** END LICENSE BLOCK ***** */
42 /* representation of a CSS style sheet */
44 #include "nsCSSStyleSheet.h"
46 #include "nsCRT.h"
47 #include "nsIAtom.h"
48 #include "nsCSSRuleProcessor.h"
49 #include "nsICSSNameSpaceRule.h"
50 #include "nsICSSGroupRule.h"
51 #include "nsICSSImportRule.h"
52 #include "nsIMediaList.h"
53 #include "nsIDocument.h"
54 #include "nsPresContext.h"
55 #include "nsGkAtoms.h"
56 #include "nsString.h"
57 #include "nsTArray.h"
58 #include "nsIDOMCSSStyleSheet.h"
59 #include "nsIDOMCSSImportRule.h"
60 #include "nsICSSRuleList.h"
61 #include "nsIDOMMediaList.h"
62 #include "nsIDOMNode.h"
63 #include "nsDOMError.h"
64 #include "nsCSSParser.h"
65 #include "mozilla/css/Loader.h"
66 #include "nsICSSLoaderObserver.h"
67 #include "nsINameSpaceManager.h"
68 #include "nsXMLNameSpaceMap.h"
69 #include "nsCOMPtr.h"
70 #include "nsContentUtils.h"
71 #include "nsIScriptSecurityManager.h"
72 #include "mozAutoDocUpdate.h"
73 #include "mozilla/css/Declaration.h"
74 #include "nsRuleNode.h"
75 #include "nsMediaFeatures.h"
77 namespace css = mozilla::css;
79 // -------------------------------
80 // Style Rule List for the DOM
82 class CSSRuleListImpl : public nsICSSRuleList
84 public:
85 CSSRuleListImpl(nsCSSStyleSheet *aStyleSheet);
87 NS_DECL_ISUPPORTS
89 // nsIDOMCSSRuleList interface
90 NS_IMETHOD GetLength(PRUint32* aLength);
91 NS_IMETHOD Item(PRUint32 aIndex, nsIDOMCSSRule** aReturn);
93 virtual nsIDOMCSSRule* GetItemAt(PRUint32 aIndex, nsresult* aResult);
95 void DropReference() { mStyleSheet = nsnull; }
97 protected:
98 virtual ~CSSRuleListImpl();
100 nsCSSStyleSheet* mStyleSheet;
101 public:
102 PRBool mRulesAccessed;
105 CSSRuleListImpl::CSSRuleListImpl(nsCSSStyleSheet *aStyleSheet)
107 // Not reference counted to avoid circular references.
108 // The style sheet will tell us when its going away.
109 mStyleSheet = aStyleSheet;
110 mRulesAccessed = PR_FALSE;
113 CSSRuleListImpl::~CSSRuleListImpl()
117 DOMCI_DATA(CSSRuleList, CSSRuleListImpl)
119 // QueryInterface implementation for CSSRuleList
120 NS_INTERFACE_MAP_BEGIN(CSSRuleListImpl)
121 NS_INTERFACE_MAP_ENTRY(nsICSSRuleList)
122 NS_INTERFACE_MAP_ENTRY(nsIDOMCSSRuleList)
123 NS_INTERFACE_MAP_ENTRY(nsISupports)
124 NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(CSSRuleList)
125 NS_INTERFACE_MAP_END
128 NS_IMPL_ADDREF(CSSRuleListImpl)
129 NS_IMPL_RELEASE(CSSRuleListImpl)
132 NS_IMETHODIMP
133 CSSRuleListImpl::GetLength(PRUint32* aLength)
135 if (nsnull != mStyleSheet) {
136 PRInt32 count = mStyleSheet->StyleRuleCount();
137 *aLength = (PRUint32)count;
139 else {
140 *aLength = 0;
143 return NS_OK;
146 nsIDOMCSSRule*
147 CSSRuleListImpl::GetItemAt(PRUint32 aIndex, nsresult* aResult)
149 nsresult result = NS_OK;
151 if (mStyleSheet) {
152 // ensure rules have correct parent
153 if (mStyleSheet->EnsureUniqueInner() !=
154 nsCSSStyleSheet::eUniqueInner_CloneFailed) {
155 nsCOMPtr<nsICSSRule> rule;
157 result = mStyleSheet->GetStyleRuleAt(aIndex, *getter_AddRefs(rule));
158 if (rule) {
159 mRulesAccessed = PR_TRUE; // signal to never share rules again
160 return rule->GetDOMRuleWeak(aResult);
162 if (result == NS_ERROR_ILLEGAL_VALUE) {
163 result = NS_OK; // per spec: "Return Value ... null if ... not a valid index."
168 *aResult = result;
169 return nsnull;
172 NS_IMETHODIMP
173 CSSRuleListImpl::Item(PRUint32 aIndex, nsIDOMCSSRule** aReturn)
175 nsresult rv;
176 nsIDOMCSSRule* rule = GetItemAt(aIndex, &rv);
177 if (!rule) {
178 *aReturn = nsnull;
180 return rv;
183 NS_ADDREF(*aReturn = rule);
184 return NS_OK;
187 template <class Numeric>
188 PRInt32 DoCompare(Numeric a, Numeric b)
190 if (a == b)
191 return 0;
192 if (a < b)
193 return -1;
194 return 1;
197 PRBool
198 nsMediaExpression::Matches(nsPresContext *aPresContext,
199 const nsCSSValue& aActualValue) const
201 const nsCSSValue& actual = aActualValue;
202 const nsCSSValue& required = mValue;
204 // If we don't have the feature, the match fails.
205 if (actual.GetUnit() == eCSSUnit_Null) {
206 return PR_FALSE;
209 // If the expression had no value to match, the match succeeds,
210 // unless the value is an integer 0 or a zero length.
211 if (required.GetUnit() == eCSSUnit_Null) {
212 if (actual.GetUnit() == eCSSUnit_Integer)
213 return actual.GetIntValue() != 0;
214 if (actual.IsLengthUnit())
215 return actual.GetFloatValue() != 0;
216 return PR_TRUE;
219 NS_ASSERTION(mFeature->mRangeType == nsMediaFeature::eMinMaxAllowed ||
220 mRange == nsMediaExpression::eEqual, "yikes");
221 PRInt32 cmp; // -1 (actual < required)
222 // 0 (actual == required)
223 // 1 (actual > required)
224 switch (mFeature->mValueType) {
225 case nsMediaFeature::eLength:
227 NS_ASSERTION(actual.IsLengthUnit(), "bad actual value");
228 NS_ASSERTION(required.IsLengthUnit(), "bad required value");
229 nscoord actualCoord = nsRuleNode::CalcLengthWithInitialFont(
230 aPresContext, actual);
231 nscoord requiredCoord = nsRuleNode::CalcLengthWithInitialFont(
232 aPresContext, required);
233 cmp = DoCompare(actualCoord, requiredCoord);
235 break;
236 case nsMediaFeature::eInteger:
237 case nsMediaFeature::eBoolInteger:
239 NS_ASSERTION(actual.GetUnit() == eCSSUnit_Integer,
240 "bad actual value");
241 NS_ASSERTION(required.GetUnit() == eCSSUnit_Integer,
242 "bad required value");
243 NS_ASSERTION(mFeature->mValueType != nsMediaFeature::eBoolInteger ||
244 actual.GetIntValue() == 0 || actual.GetIntValue() == 1,
245 "bad actual bool integer value");
246 NS_ASSERTION(mFeature->mValueType != nsMediaFeature::eBoolInteger ||
247 required.GetIntValue() == 0 || required.GetIntValue() == 1,
248 "bad required bool integer value");
249 cmp = DoCompare(actual.GetIntValue(), required.GetIntValue());
251 break;
252 case nsMediaFeature::eFloat:
254 NS_ASSERTION(actual.GetUnit() == eCSSUnit_Number,
255 "bad actual value");
256 NS_ASSERTION(required.GetUnit() == eCSSUnit_Number,
257 "bad required value");
258 cmp = DoCompare(actual.GetFloatValue(), required.GetFloatValue());
260 break;
261 case nsMediaFeature::eIntRatio:
263 NS_ASSERTION(actual.GetUnit() == eCSSUnit_Array &&
264 actual.GetArrayValue()->Count() == 2 &&
265 actual.GetArrayValue()->Item(0).GetUnit() ==
266 eCSSUnit_Integer &&
267 actual.GetArrayValue()->Item(1).GetUnit() ==
268 eCSSUnit_Integer,
269 "bad actual value");
270 NS_ASSERTION(required.GetUnit() == eCSSUnit_Array &&
271 required.GetArrayValue()->Count() == 2 &&
272 required.GetArrayValue()->Item(0).GetUnit() ==
273 eCSSUnit_Integer &&
274 required.GetArrayValue()->Item(1).GetUnit() ==
275 eCSSUnit_Integer,
276 "bad required value");
277 // Convert to PRInt64 so we can multiply without worry. Note
278 // that while the spec requires that both halves of |required|
279 // be positive, the numerator or denominator of |actual| might
280 // be zero (e.g., when testing 'aspect-ratio' on a 0-width or
281 // 0-height iframe).
282 PRInt64 actualNum = actual.GetArrayValue()->Item(0).GetIntValue(),
283 actualDen = actual.GetArrayValue()->Item(1).GetIntValue(),
284 requiredNum = required.GetArrayValue()->Item(0).GetIntValue(),
285 requiredDen = required.GetArrayValue()->Item(1).GetIntValue();
286 cmp = DoCompare(actualNum * requiredDen, requiredNum * actualDen);
288 break;
289 case nsMediaFeature::eResolution:
291 NS_ASSERTION(actual.GetUnit() == eCSSUnit_Inch ||
292 actual.GetUnit() == eCSSUnit_Centimeter,
293 "bad actual value");
294 NS_ASSERTION(required.GetUnit() == eCSSUnit_Inch ||
295 required.GetUnit() == eCSSUnit_Centimeter,
296 "bad required value");
297 float actualDPI = actual.GetFloatValue();
298 if (actual.GetUnit() == eCSSUnit_Centimeter)
299 actualDPI = actualDPI * 2.54f;
300 float requiredDPI = required.GetFloatValue();
301 if (required.GetUnit() == eCSSUnit_Centimeter)
302 requiredDPI = requiredDPI * 2.54f;
303 cmp = DoCompare(actualDPI, requiredDPI);
305 break;
306 case nsMediaFeature::eEnumerated:
308 NS_ASSERTION(actual.GetUnit() == eCSSUnit_Enumerated,
309 "bad actual value");
310 NS_ASSERTION(required.GetUnit() == eCSSUnit_Enumerated,
311 "bad required value");
312 NS_ASSERTION(mFeature->mRangeType == nsMediaFeature::eMinMaxNotAllowed,
313 "bad range"); // we asserted above about mRange
314 // We don't really need DoCompare, but it doesn't hurt (and
315 // maybe the compiler will condense this case with eInteger).
316 cmp = DoCompare(actual.GetIntValue(), required.GetIntValue());
318 break;
319 case nsMediaFeature::eIdent:
321 NS_ASSERTION(actual.GetUnit() == eCSSUnit_Ident,
322 "bad actual value");
323 NS_ASSERTION(required.GetUnit() == eCSSUnit_Ident,
324 "bad required value");
325 NS_ASSERTION(mFeature->mRangeType == nsMediaFeature::eMinMaxNotAllowed,
326 "bad range");
327 cmp = !(actual == required); // string comparison
329 break;
331 switch (mRange) {
332 case nsMediaExpression::eMin:
333 return cmp != -1;
334 case nsMediaExpression::eMax:
335 return cmp != 1;
336 case nsMediaExpression::eEqual:
337 return cmp == 0;
339 NS_NOTREACHED("unexpected mRange");
340 return PR_FALSE;
343 void
344 nsMediaQueryResultCacheKey::AddExpression(const nsMediaExpression* aExpression,
345 PRBool aExpressionMatches)
347 const nsMediaFeature *feature = aExpression->mFeature;
348 FeatureEntry *entry = nsnull;
349 for (PRUint32 i = 0; i < mFeatureCache.Length(); ++i) {
350 if (mFeatureCache[i].mFeature == feature) {
351 entry = &mFeatureCache[i];
352 break;
355 if (!entry) {
356 entry = mFeatureCache.AppendElement();
357 if (!entry) {
358 return; /* out of memory */
360 entry->mFeature = feature;
363 ExpressionEntry eentry = { *aExpression, aExpressionMatches };
364 entry->mExpressions.AppendElement(eentry);
367 PRBool
368 nsMediaQueryResultCacheKey::Matches(nsPresContext* aPresContext) const
370 if (aPresContext->Medium() != mMedium) {
371 return PR_FALSE;
374 for (PRUint32 i = 0; i < mFeatureCache.Length(); ++i) {
375 const FeatureEntry *entry = &mFeatureCache[i];
376 nsCSSValue actual;
377 nsresult rv =
378 (entry->mFeature->mGetter)(aPresContext, entry->mFeature, actual);
379 NS_ENSURE_SUCCESS(rv, PR_FALSE); // any better ideas?
381 for (PRUint32 j = 0; j < entry->mExpressions.Length(); ++j) {
382 const ExpressionEntry &eentry = entry->mExpressions[j];
383 if (eentry.mExpression.Matches(aPresContext, actual) !=
384 eentry.mExpressionMatches) {
385 return PR_FALSE;
390 return PR_TRUE;
393 void
394 nsMediaQuery::AppendToString(nsAString& aString) const
396 if (mHadUnknownExpression) {
397 aString.AppendLiteral("not all");
398 return;
401 NS_ASSERTION(!mNegated || !mHasOnly, "can't have not and only");
402 NS_ASSERTION(!mTypeOmitted || (!mNegated && !mHasOnly),
403 "can't have not or only when type is omitted");
404 if (!mTypeOmitted) {
405 if (mNegated) {
406 aString.AppendLiteral("not ");
407 } else if (mHasOnly) {
408 aString.AppendLiteral("only ");
410 aString.Append(nsDependentAtomString(mMediaType));
413 for (PRUint32 i = 0, i_end = mExpressions.Length(); i < i_end; ++i) {
414 if (i > 0 || !mTypeOmitted)
415 aString.AppendLiteral(" and ");
416 aString.AppendLiteral("(");
418 const nsMediaExpression &expr = mExpressions[i];
419 if (expr.mRange == nsMediaExpression::eMin) {
420 aString.AppendLiteral("min-");
421 } else if (expr.mRange == nsMediaExpression::eMax) {
422 aString.AppendLiteral("max-");
425 const nsMediaFeature *feature = expr.mFeature;
426 aString.Append(nsDependentAtomString(*feature->mName));
428 if (expr.mValue.GetUnit() != eCSSUnit_Null) {
429 aString.AppendLiteral(": ");
430 switch (feature->mValueType) {
431 case nsMediaFeature::eLength:
432 NS_ASSERTION(expr.mValue.IsLengthUnit(), "bad unit");
433 // Use 'width' as a property that takes length values
434 // written in the normal way.
435 expr.mValue.AppendToString(eCSSProperty_width, aString);
436 break;
437 case nsMediaFeature::eInteger:
438 case nsMediaFeature::eBoolInteger:
439 NS_ASSERTION(expr.mValue.GetUnit() == eCSSUnit_Integer,
440 "bad unit");
441 // Use 'z-index' as a property that takes integer values
442 // written without anything extra.
443 expr.mValue.AppendToString(eCSSProperty_z_index, aString);
444 break;
445 case nsMediaFeature::eFloat:
447 NS_ASSERTION(expr.mValue.GetUnit() == eCSSUnit_Number,
448 "bad unit");
449 // Use 'line-height' as a property that takes float values
450 // written in the normal way.
451 expr.mValue.AppendToString(eCSSProperty_line_height, aString);
453 break;
454 case nsMediaFeature::eIntRatio:
456 NS_ASSERTION(expr.mValue.GetUnit() == eCSSUnit_Array,
457 "bad unit");
458 nsCSSValue::Array *array = expr.mValue.GetArrayValue();
459 NS_ASSERTION(array->Count() == 2, "unexpected length");
460 NS_ASSERTION(array->Item(0).GetUnit() == eCSSUnit_Integer,
461 "bad unit");
462 NS_ASSERTION(array->Item(1).GetUnit() == eCSSUnit_Integer,
463 "bad unit");
464 array->Item(0).AppendToString(eCSSProperty_z_index, aString);
465 aString.AppendLiteral("/");
466 array->Item(1).AppendToString(eCSSProperty_z_index, aString);
468 break;
469 case nsMediaFeature::eResolution:
471 aString.AppendFloat(expr.mValue.GetFloatValue());
472 if (expr.mValue.GetUnit() == eCSSUnit_Inch) {
473 aString.AppendLiteral("dpi");
474 } else {
475 NS_ASSERTION(expr.mValue.GetUnit() == eCSSUnit_Centimeter,
476 "bad unit");
477 aString.AppendLiteral("dpcm");
480 break;
481 case nsMediaFeature::eEnumerated:
482 NS_ASSERTION(expr.mValue.GetUnit() == eCSSUnit_Enumerated,
483 "bad unit");
484 AppendASCIItoUTF16(
485 nsCSSProps::ValueToKeyword(expr.mValue.GetIntValue(),
486 feature->mData.mKeywordTable),
487 aString);
488 break;
489 case nsMediaFeature::eIdent:
490 NS_ASSERTION(expr.mValue.GetUnit() == eCSSUnit_Ident,
491 "bad unit");
492 aString.Append(expr.mValue.GetStringBufferValue());
493 break;
497 aString.AppendLiteral(")");
501 nsMediaQuery*
502 nsMediaQuery::Clone() const
504 nsAutoPtr<nsMediaQuery> result(new nsMediaQuery(*this));
505 NS_ENSURE_TRUE(result &&
506 result->mExpressions.Length() == mExpressions.Length(),
507 nsnull);
508 return result.forget();
511 PRBool
512 nsMediaQuery::Matches(nsPresContext* aPresContext,
513 nsMediaQueryResultCacheKey& aKey) const
515 if (mHadUnknownExpression)
516 return PR_FALSE;
518 PRBool match =
519 mMediaType == aPresContext->Medium() || mMediaType == nsGkAtoms::all;
520 for (PRUint32 i = 0, i_end = mExpressions.Length(); match && i < i_end; ++i) {
521 const nsMediaExpression &expr = mExpressions[i];
522 nsCSSValue actual;
523 nsresult rv =
524 (expr.mFeature->mGetter)(aPresContext, expr.mFeature, actual);
525 NS_ENSURE_SUCCESS(rv, PR_FALSE); // any better ideas?
527 match = expr.Matches(aPresContext, actual);
528 aKey.AddExpression(&expr, match);
531 return match == !mNegated;
534 DOMCI_DATA(MediaList, nsMediaList)
536 NS_INTERFACE_MAP_BEGIN(nsMediaList)
537 NS_INTERFACE_MAP_ENTRY(nsIDOMMediaList)
538 NS_INTERFACE_MAP_ENTRY(nsISupports)
539 NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(MediaList)
540 NS_INTERFACE_MAP_END
542 NS_IMPL_ADDREF(nsMediaList)
543 NS_IMPL_RELEASE(nsMediaList)
546 nsMediaList::nsMediaList()
547 : mIsEmpty(PR_TRUE)
548 , mStyleSheet(nsnull)
552 nsMediaList::~nsMediaList()
556 nsresult
557 nsMediaList::GetText(nsAString& aMediaText)
559 aMediaText.Truncate();
561 if (mArray.Length() == 0 && !mIsEmpty) {
562 aMediaText.AppendLiteral("not all");
565 for (PRInt32 i = 0, i_end = mArray.Length(); i < i_end; ++i) {
566 nsMediaQuery* query = mArray[i];
567 NS_ENSURE_TRUE(query, NS_ERROR_FAILURE);
569 query->AppendToString(aMediaText);
571 if (i + 1 < i_end) {
572 aMediaText.AppendLiteral(", ");
576 return NS_OK;
579 // XXXbz this is so ill-defined in the spec, it's not clear quite what
580 // it should be doing....
581 nsresult
582 nsMediaList::SetText(const nsAString& aMediaText)
584 nsCSSParser parser;
585 NS_ENSURE_TRUE(parser, NS_ERROR_OUT_OF_MEMORY);
587 PRBool htmlMode = PR_FALSE;
588 if (mStyleSheet) {
589 nsCOMPtr<nsIDOMNode> node;
590 mStyleSheet->GetOwnerNode(getter_AddRefs(node));
591 htmlMode = !!node;
594 return parser.ParseMediaList(nsString(aMediaText), nsnull, 0,
595 this, htmlMode);
598 PRBool
599 nsMediaList::Matches(nsPresContext* aPresContext,
600 nsMediaQueryResultCacheKey& aKey)
602 for (PRInt32 i = 0, i_end = mArray.Length(); i < i_end; ++i) {
603 if (mArray[i]->Matches(aPresContext, aKey)) {
604 return PR_TRUE;
607 return mIsEmpty;
610 nsresult
611 nsMediaList::SetStyleSheet(nsCSSStyleSheet *aSheet)
613 NS_ASSERTION(aSheet == mStyleSheet || !aSheet || !mStyleSheet,
614 "multiple style sheets competing for one media list");
615 mStyleSheet = aSheet;
616 return NS_OK;
619 nsresult
620 nsMediaList::Clone(nsMediaList** aResult)
622 nsRefPtr<nsMediaList> result = new nsMediaList();
623 if (!result || !result->mArray.AppendElements(mArray.Length()))
624 return NS_ERROR_OUT_OF_MEMORY;
625 for (PRInt32 i = 0, i_end = mArray.Length(); i < i_end; ++i) {
626 if (!(result->mArray[i] = mArray[i]->Clone())) {
627 return NS_ERROR_OUT_OF_MEMORY;
630 result->mIsEmpty = mIsEmpty;
631 NS_ADDREF(*aResult = result);
632 return NS_OK;
635 NS_IMETHODIMP
636 nsMediaList::GetMediaText(nsAString& aMediaText)
638 return GetText(aMediaText);
641 // "sheet" should be an nsCSSStyleSheet and "doc" should be an
642 // nsCOMPtr<nsIDocument>
643 #define BEGIN_MEDIA_CHANGE(sheet, doc) \
644 if (sheet) { \
645 doc = sheet->GetOwningDocument(); \
647 mozAutoDocUpdate updateBatch(doc, UPDATE_STYLE, PR_TRUE); \
648 if (sheet) { \
649 rv = sheet->WillDirty(); \
650 NS_ENSURE_SUCCESS(rv, rv); \
653 #define END_MEDIA_CHANGE(sheet, doc) \
654 if (sheet) { \
655 sheet->DidDirty(); \
657 /* XXXldb Pass something meaningful? */ \
658 if (doc) { \
659 doc->StyleRuleChanged(sheet, nsnull, nsnull); \
663 NS_IMETHODIMP
664 nsMediaList::SetMediaText(const nsAString& aMediaText)
666 nsresult rv = NS_OK;
667 nsCOMPtr<nsIDocument> doc;
669 BEGIN_MEDIA_CHANGE(mStyleSheet, doc)
671 rv = SetText(aMediaText);
672 if (NS_FAILED(rv))
673 return rv;
675 END_MEDIA_CHANGE(mStyleSheet, doc)
677 return rv;
680 NS_IMETHODIMP
681 nsMediaList::GetLength(PRUint32* aLength)
683 NS_ENSURE_ARG_POINTER(aLength);
685 *aLength = mArray.Length();
686 return NS_OK;
689 NS_IMETHODIMP
690 nsMediaList::Item(PRUint32 aIndex, nsAString& aReturn)
692 PRInt32 index = aIndex;
693 if (0 <= index && index < Count()) {
694 nsMediaQuery* query = mArray[index];
695 NS_ENSURE_TRUE(query, NS_ERROR_FAILURE);
697 aReturn.Truncate();
698 query->AppendToString(aReturn);
699 } else {
700 SetDOMStringToNull(aReturn);
703 return NS_OK;
706 NS_IMETHODIMP
707 nsMediaList::DeleteMedium(const nsAString& aOldMedium)
709 nsresult rv = NS_OK;
710 nsCOMPtr<nsIDocument> doc;
712 BEGIN_MEDIA_CHANGE(mStyleSheet, doc)
714 rv = Delete(aOldMedium);
715 if (NS_FAILED(rv))
716 return rv;
718 END_MEDIA_CHANGE(mStyleSheet, doc)
720 return rv;
723 NS_IMETHODIMP
724 nsMediaList::AppendMedium(const nsAString& aNewMedium)
726 nsresult rv = NS_OK;
727 nsCOMPtr<nsIDocument> doc;
729 BEGIN_MEDIA_CHANGE(mStyleSheet, doc)
731 rv = Append(aNewMedium);
732 if (NS_FAILED(rv))
733 return rv;
735 END_MEDIA_CHANGE(mStyleSheet, doc)
737 return rv;
740 nsresult
741 nsMediaList::Delete(const nsAString& aOldMedium)
743 if (aOldMedium.IsEmpty())
744 return NS_ERROR_DOM_NOT_FOUND_ERR;
746 for (PRInt32 i = 0, i_end = mArray.Length(); i < i_end; ++i) {
747 nsMediaQuery* query = mArray[i];
748 NS_ENSURE_TRUE(query, NS_ERROR_FAILURE);
750 nsAutoString buf;
751 query->AppendToString(buf);
752 if (buf == aOldMedium) {
753 mArray.RemoveElementAt(i);
754 return NS_OK;
758 return NS_ERROR_DOM_NOT_FOUND_ERR;
761 nsresult
762 nsMediaList::Append(const nsAString& aNewMedium)
764 if (aNewMedium.IsEmpty())
765 return NS_ERROR_DOM_NOT_FOUND_ERR;
767 Delete(aNewMedium);
769 nsresult rv = NS_OK;
770 nsTArray<nsAutoPtr<nsMediaQuery> > buf;
771 #ifdef DEBUG
772 PRBool ok =
773 #endif
774 mArray.SwapElements(buf);
775 NS_ASSERTION(ok, "SwapElements should never fail when neither array "
776 "is an auto array");
777 SetText(aNewMedium);
778 if (mArray.Length() == 1) {
779 nsMediaQuery *query = mArray[0].forget();
780 if (!buf.AppendElement(query)) {
781 delete query;
782 rv = NS_ERROR_OUT_OF_MEMORY;
785 #ifdef DEBUG
786 ok =
787 #endif
788 mArray.SwapElements(buf);
789 NS_ASSERTION(ok, "SwapElements should never fail when neither array "
790 "is an auto array");
791 return rv;
794 // -------------------------------
795 // CSS Style Sheet Inner Data Container
799 nsCSSStyleSheetInner::nsCSSStyleSheetInner(nsCSSStyleSheet* aPrimarySheet)
800 : mSheets(),
801 mComplete(PR_FALSE)
802 #ifdef DEBUG
803 , mPrincipalSet(PR_FALSE)
804 #endif
806 MOZ_COUNT_CTOR(nsCSSStyleSheetInner);
807 mSheets.AppendElement(aPrimarySheet);
809 mPrincipal = do_CreateInstance("@mozilla.org/nullprincipal;1");
812 static PRBool SetStyleSheetReference(nsICSSRule* aRule, void* aSheet)
814 if (aRule) {
815 aRule->SetStyleSheet(static_cast<nsCSSStyleSheet*>(aSheet));
817 return PR_TRUE;
820 static PRBool
821 CloneRuleInto(nsICSSRule* aRule, void* aArray)
823 nsCOMPtr<nsICSSRule> clone = aRule->Clone();
824 static_cast<nsCOMArray<nsICSSRule>*>(aArray)->AppendObject(clone);
825 return PR_TRUE;
828 struct ChildSheetListBuilder {
829 nsRefPtr<nsCSSStyleSheet>* sheetSlot;
830 nsCSSStyleSheet* parent;
832 void SetParentLinks(nsCSSStyleSheet* aSheet) {
833 aSheet->mParent = parent;
834 aSheet->SetOwningDocument(parent->mDocument);
837 static void ReparentChildList(nsCSSStyleSheet* aPrimarySheet,
838 nsCSSStyleSheet* aFirstChild)
840 for (nsCSSStyleSheet *child = aFirstChild; child; child = child->mNext) {
841 child->mParent = aPrimarySheet;
842 child->SetOwningDocument(aPrimarySheet->mDocument);
847 PRBool
848 nsCSSStyleSheet::RebuildChildList(nsICSSRule* aRule, void* aBuilder)
850 PRInt32 type = aRule->GetType();
851 if (type < nsICSSRule::IMPORT_RULE) {
852 // Keep going till we get to the import rules.
853 return PR_TRUE;
856 if (type != nsICSSRule::IMPORT_RULE) {
857 // We're past all the import rules; stop the enumeration.
858 return PR_FALSE;
861 ChildSheetListBuilder* builder =
862 static_cast<ChildSheetListBuilder*>(aBuilder);
864 // XXXbz We really need to decomtaminate all this stuff. Is there a reason
865 // that I can't just QI to nsICSSImportRule and get an nsCSSStyleSheet
866 // directly from it?
867 nsCOMPtr<nsIDOMCSSImportRule> importRule(do_QueryInterface(aRule));
868 NS_ASSERTION(importRule, "GetType lied");
870 nsCOMPtr<nsIDOMCSSStyleSheet> childSheet;
871 importRule->GetStyleSheet(getter_AddRefs(childSheet));
873 // Have to do this QI to be safe, since XPConnect can fake
874 // nsIDOMCSSStyleSheets
875 nsRefPtr<nsCSSStyleSheet> cssSheet = do_QueryObject(childSheet);
876 if (!cssSheet) {
877 return PR_TRUE;
880 (*builder->sheetSlot) = cssSheet;
881 builder->SetParentLinks(*builder->sheetSlot);
882 builder->sheetSlot = &(*builder->sheetSlot)->mNext;
883 return PR_TRUE;
886 nsCSSStyleSheetInner::nsCSSStyleSheetInner(nsCSSStyleSheetInner& aCopy,
887 nsCSSStyleSheet* aPrimarySheet)
888 : mSheets(),
889 mSheetURI(aCopy.mSheetURI),
890 mOriginalSheetURI(aCopy.mOriginalSheetURI),
891 mBaseURI(aCopy.mBaseURI),
892 mPrincipal(aCopy.mPrincipal),
893 mComplete(aCopy.mComplete)
894 #ifdef DEBUG
895 , mPrincipalSet(aCopy.mPrincipalSet)
896 #endif
898 MOZ_COUNT_CTOR(nsCSSStyleSheetInner);
899 AddSheet(aPrimarySheet);
900 aCopy.mOrderedRules.EnumerateForwards(CloneRuleInto, &mOrderedRules);
901 mOrderedRules.EnumerateForwards(SetStyleSheetReference, aPrimarySheet);
903 ChildSheetListBuilder builder = { &mFirstChild, aPrimarySheet };
904 mOrderedRules.EnumerateForwards(nsCSSStyleSheet::RebuildChildList, &builder);
906 RebuildNameSpaces();
909 nsCSSStyleSheetInner::~nsCSSStyleSheetInner()
911 MOZ_COUNT_DTOR(nsCSSStyleSheetInner);
912 mOrderedRules.EnumerateForwards(SetStyleSheetReference, nsnull);
915 nsCSSStyleSheetInner*
916 nsCSSStyleSheetInner::CloneFor(nsCSSStyleSheet* aPrimarySheet)
918 return new nsCSSStyleSheetInner(*this, aPrimarySheet);
921 void
922 nsCSSStyleSheetInner::AddSheet(nsCSSStyleSheet* aSheet)
924 mSheets.AppendElement(aSheet);
927 void
928 nsCSSStyleSheetInner::RemoveSheet(nsCSSStyleSheet* aSheet)
930 if (1 == mSheets.Length()) {
931 NS_ASSERTION(aSheet == mSheets.ElementAt(0), "bad parent");
932 delete this;
933 return;
935 if (aSheet == mSheets.ElementAt(0)) {
936 mSheets.RemoveElementAt(0);
937 NS_ASSERTION(mSheets.Length(), "no parents");
938 mOrderedRules.EnumerateForwards(SetStyleSheetReference,
939 mSheets.ElementAt(0));
941 ChildSheetListBuilder::ReparentChildList(mSheets[0], mFirstChild);
943 else {
944 mSheets.RemoveElement(aSheet);
948 static void
949 AddNamespaceRuleToMap(nsICSSRule* aRule, nsXMLNameSpaceMap* aMap)
951 NS_ASSERTION(aRule->GetType() == nsICSSRule::NAMESPACE_RULE, "Bogus rule type");
953 nsCOMPtr<nsICSSNameSpaceRule> nameSpaceRule = do_QueryInterface(aRule);
955 nsCOMPtr<nsIAtom> prefix;
956 nsAutoString urlSpec;
957 nameSpaceRule->GetPrefix(*getter_AddRefs(prefix));
958 nameSpaceRule->GetURLSpec(urlSpec);
960 aMap->AddPrefix(prefix, urlSpec);
963 static PRBool
964 CreateNameSpace(nsICSSRule* aRule, void* aNameSpacePtr)
966 PRInt32 type = aRule->GetType();
967 if (nsICSSRule::NAMESPACE_RULE == type) {
968 AddNamespaceRuleToMap(aRule,
969 static_cast<nsXMLNameSpaceMap*>(aNameSpacePtr));
970 return PR_TRUE;
972 // stop if not namespace, import or charset because namespace can't follow
973 // anything else
974 return (nsICSSRule::CHARSET_RULE == type || nsICSSRule::IMPORT_RULE == type);
977 void
978 nsCSSStyleSheetInner::RebuildNameSpaces()
980 // Just nuke our existing namespace map, if any
981 if (NS_SUCCEEDED(CreateNamespaceMap())) {
982 mOrderedRules.EnumerateForwards(CreateNameSpace, mNameSpaceMap);
986 nsresult
987 nsCSSStyleSheetInner::CreateNamespaceMap()
989 mNameSpaceMap = nsXMLNameSpaceMap::Create(PR_FALSE);
990 NS_ENSURE_TRUE(mNameSpaceMap, NS_ERROR_OUT_OF_MEMORY);
991 // Override the default namespace map behavior for the null prefix to
992 // return the wildcard namespace instead of the null namespace.
993 mNameSpaceMap->AddPrefix(nsnull, kNameSpaceID_Unknown);
994 return NS_OK;
997 // -------------------------------
998 // CSS Style Sheet
1001 nsCSSStyleSheet::nsCSSStyleSheet()
1002 : mTitle(),
1003 mParent(nsnull),
1004 mOwnerRule(nsnull),
1005 mRuleCollection(nsnull),
1006 mDocument(nsnull),
1007 mOwningNode(nsnull),
1008 mDisabled(PR_FALSE),
1009 mDirty(PR_FALSE),
1010 mRuleProcessors(nsnull)
1013 mInner = new nsCSSStyleSheetInner(this);
1016 nsCSSStyleSheet::nsCSSStyleSheet(const nsCSSStyleSheet& aCopy,
1017 nsCSSStyleSheet* aParentToUse,
1018 nsICSSImportRule* aOwnerRuleToUse,
1019 nsIDocument* aDocumentToUse,
1020 nsIDOMNode* aOwningNodeToUse)
1021 : mTitle(aCopy.mTitle),
1022 mParent(aParentToUse),
1023 mOwnerRule(aOwnerRuleToUse),
1024 mRuleCollection(nsnull), // re-created lazily
1025 mDocument(aDocumentToUse),
1026 mOwningNode(aOwningNodeToUse),
1027 mDisabled(aCopy.mDisabled),
1028 mDirty(PR_FALSE),
1029 mInner(aCopy.mInner),
1030 mRuleProcessors(nsnull)
1033 mInner->AddSheet(this);
1035 if (aCopy.mRuleCollection &&
1036 aCopy.mRuleCollection->mRulesAccessed) { // CSSOM's been there, force full copy now
1037 NS_ASSERTION(mInner->mComplete, "Why have rules been accessed on an incomplete sheet?");
1038 // FIXME: handle failure?
1039 EnsureUniqueInner();
1042 if (aCopy.mMedia) {
1043 // XXX This is wrong; we should be keeping @import rules and
1044 // sheets in sync!
1045 aCopy.mMedia->Clone(getter_AddRefs(mMedia));
1049 nsCSSStyleSheet::~nsCSSStyleSheet()
1051 for (nsCSSStyleSheet* child = mInner->mFirstChild;
1052 child;
1053 child = child->mNext) {
1054 // XXXbz this is a little bogus; see the XXX comment where we
1055 // declare mFirstChild.
1056 if (child->mParent == this) {
1057 child->mParent = nsnull;
1058 child->mDocument = nsnull;
1061 if (nsnull != mRuleCollection) {
1062 mRuleCollection->DropReference();
1063 NS_RELEASE(mRuleCollection);
1065 if (mMedia) {
1066 mMedia->SetStyleSheet(nsnull);
1067 mMedia = nsnull;
1069 mInner->RemoveSheet(this);
1070 // XXX The document reference is not reference counted and should
1071 // not be released. The document will let us know when it is going
1072 // away.
1073 if (mRuleProcessors) {
1074 NS_ASSERTION(mRuleProcessors->Length() == 0, "destructing sheet with rule processor reference");
1075 delete mRuleProcessors; // weak refs, should be empty here anyway
1080 DOMCI_DATA(CSSStyleSheet, nsCSSStyleSheet)
1082 // QueryInterface implementation for nsCSSStyleSheet
1083 NS_INTERFACE_MAP_BEGIN(nsCSSStyleSheet)
1084 NS_INTERFACE_MAP_ENTRY(nsIStyleSheet)
1085 NS_INTERFACE_MAP_ENTRY(nsIDOMStyleSheet)
1086 NS_INTERFACE_MAP_ENTRY(nsIDOMCSSStyleSheet)
1087 NS_INTERFACE_MAP_ENTRY(nsICSSLoaderObserver)
1088 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIStyleSheet)
1089 NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(CSSStyleSheet)
1090 if (aIID.Equals(NS_GET_IID(nsCSSStyleSheet)))
1091 foundInterface = reinterpret_cast<nsISupports*>(this);
1092 else
1093 NS_INTERFACE_MAP_END
1096 NS_IMPL_ADDREF(nsCSSStyleSheet)
1097 NS_IMPL_RELEASE(nsCSSStyleSheet)
1100 nsresult
1101 nsCSSStyleSheet::AddRuleProcessor(nsCSSRuleProcessor* aProcessor)
1103 if (! mRuleProcessors) {
1104 mRuleProcessors = new nsAutoTArray<nsCSSRuleProcessor*, 8>();
1105 if (!mRuleProcessors)
1106 return NS_ERROR_OUT_OF_MEMORY;
1108 NS_ASSERTION(mRuleProcessors->NoIndex == mRuleProcessors->IndexOf(aProcessor),
1109 "processor already registered");
1110 mRuleProcessors->AppendElement(aProcessor); // weak ref
1111 return NS_OK;
1114 nsresult
1115 nsCSSStyleSheet::DropRuleProcessor(nsCSSRuleProcessor* aProcessor)
1117 if (!mRuleProcessors)
1118 return NS_ERROR_FAILURE;
1119 return mRuleProcessors->RemoveElement(aProcessor)
1120 ? NS_OK
1121 : NS_ERROR_FAILURE;
1125 void
1126 nsCSSStyleSheet::SetURIs(nsIURI* aSheetURI, nsIURI* aOriginalSheetURI,
1127 nsIURI* aBaseURI)
1129 NS_PRECONDITION(aSheetURI && aBaseURI, "null ptr");
1131 NS_ASSERTION(mInner->mOrderedRules.Count() == 0 && !mInner->mComplete,
1132 "Can't call SetURL on sheets that are complete or have rules");
1134 mInner->mSheetURI = aSheetURI;
1135 mInner->mOriginalSheetURI = aOriginalSheetURI;
1136 mInner->mBaseURI = aBaseURI;
1139 void
1140 nsCSSStyleSheet::SetPrincipal(nsIPrincipal* aPrincipal)
1142 NS_PRECONDITION(!mInner->mPrincipalSet,
1143 "Should have an inner whose principal has not yet been set");
1144 if (aPrincipal) {
1145 mInner->mPrincipal = aPrincipal;
1146 #ifdef DEBUG
1147 mInner->mPrincipalSet = PR_TRUE;
1148 #endif
1152 /* virtual */ nsIURI*
1153 nsCSSStyleSheet::GetSheetURI() const
1155 return mInner->mSheetURI;
1158 /* virtual */ nsIURI*
1159 nsCSSStyleSheet::GetBaseURI() const
1161 return mInner->mBaseURI;
1164 /* virtual */ void
1165 nsCSSStyleSheet::GetType(nsString& aType) const
1167 aType.AssignLiteral("text/css");
1170 PRBool
1171 nsCSSStyleSheet::UseForPresentation(nsPresContext* aPresContext,
1172 nsMediaQueryResultCacheKey& aKey) const
1174 if (mMedia) {
1175 return mMedia->Matches(aPresContext, aKey);
1177 return PR_TRUE;
1181 void
1182 nsCSSStyleSheet::SetMedia(nsMediaList* aMedia)
1184 mMedia = aMedia;
1187 /* virtual */ PRBool
1188 nsCSSStyleSheet::HasRules() const
1190 return StyleRuleCount() != 0;
1193 /* virtual */ PRBool
1194 nsCSSStyleSheet::IsApplicable() const
1196 return !mDisabled && mInner->mComplete;
1199 /* virtual */ void
1200 nsCSSStyleSheet::SetEnabled(PRBool aEnabled)
1202 // Internal method, so callers must handle BeginUpdate/EndUpdate
1203 PRBool oldDisabled = mDisabled;
1204 mDisabled = !aEnabled;
1206 if (mInner->mComplete && oldDisabled != mDisabled) {
1207 ClearRuleCascades();
1209 if (mDocument) {
1210 mDocument->SetStyleSheetApplicableState(this, !mDisabled);
1215 /* virtual */ PRBool
1216 nsCSSStyleSheet::IsComplete() const
1218 return mInner->mComplete;
1221 /* virtual */ void
1222 nsCSSStyleSheet::SetComplete()
1224 NS_ASSERTION(!mDirty, "Can't set a dirty sheet complete!");
1225 mInner->mComplete = PR_TRUE;
1226 if (mDocument && !mDisabled) {
1227 // Let the document know
1228 mDocument->BeginUpdate(UPDATE_STYLE);
1229 mDocument->SetStyleSheetApplicableState(this, PR_TRUE);
1230 mDocument->EndUpdate(UPDATE_STYLE);
1234 /* virtual */ nsIStyleSheet*
1235 nsCSSStyleSheet::GetParentSheet() const
1237 return mParent;
1240 /* virtual */ nsIDocument*
1241 nsCSSStyleSheet::GetOwningDocument() const
1243 return mDocument;
1246 /* virtual */ void
1247 nsCSSStyleSheet::SetOwningDocument(nsIDocument* aDocument)
1248 { // not ref counted
1249 mDocument = aDocument;
1250 // Now set the same document on all our child sheets....
1251 // XXXbz this is a little bogus; see the XXX comment where we
1252 // declare mFirstChild.
1253 for (nsCSSStyleSheet* child = mInner->mFirstChild;
1254 child; child = child->mNext) {
1255 if (child->mParent == this) {
1256 child->SetOwningDocument(aDocument);
1261 /* virtual */ PRUint64
1262 nsCSSStyleSheet::FindOwningWindowID() const
1264 PRUint64 windowID = 0;
1265 if (mDocument) {
1266 windowID = mDocument->OuterWindowID();
1269 if (windowID == 0 && mOwningNode) {
1270 nsCOMPtr<nsIContent> node = do_QueryInterface(mOwningNode);
1271 if (node) {
1272 nsIDocument* doc = node->GetOwnerDoc();
1273 if (doc) {
1274 windowID = doc->OuterWindowID();
1279 if (windowID == 0 && mOwnerRule) {
1280 nsCOMPtr<nsIStyleSheet> sheet = mOwnerRule->GetStyleSheet();
1281 if (sheet) {
1282 nsRefPtr<nsCSSStyleSheet> cssSheet = do_QueryObject(sheet);
1283 if (cssSheet) {
1284 windowID = cssSheet->FindOwningWindowID();
1289 if (windowID == 0 && mParent) {
1290 windowID = mParent->FindOwningWindowID();
1293 return windowID;
1296 void
1297 nsCSSStyleSheet::AppendStyleSheet(nsCSSStyleSheet* aSheet)
1299 NS_PRECONDITION(nsnull != aSheet, "null arg");
1301 if (NS_SUCCEEDED(WillDirty())) {
1302 nsRefPtr<nsCSSStyleSheet>* tail = &mInner->mFirstChild;
1303 while (*tail) {
1304 tail = &(*tail)->mNext;
1306 *tail = aSheet;
1308 // This is not reference counted. Our parent tells us when
1309 // it's going away.
1310 aSheet->mParent = this;
1311 aSheet->mDocument = mDocument;
1312 DidDirty();
1316 void
1317 nsCSSStyleSheet::InsertStyleSheetAt(nsCSSStyleSheet* aSheet, PRInt32 aIndex)
1319 NS_PRECONDITION(nsnull != aSheet, "null arg");
1321 if (NS_SUCCEEDED(WillDirty())) {
1322 nsRefPtr<nsCSSStyleSheet>* tail = &mInner->mFirstChild;
1323 while (*tail && aIndex) {
1324 --aIndex;
1325 tail = &(*tail)->mNext;
1327 aSheet->mNext = *tail;
1328 *tail = aSheet;
1330 // This is not reference counted. Our parent tells us when
1331 // it's going away.
1332 aSheet->mParent = this;
1333 aSheet->mDocument = mDocument;
1334 DidDirty();
1338 void
1339 nsCSSStyleSheet::PrependStyleRule(nsICSSRule* aRule)
1341 NS_PRECONDITION(nsnull != aRule, "null arg");
1343 if (NS_SUCCEEDED(WillDirty())) {
1344 mInner->mOrderedRules.InsertObjectAt(aRule, 0);
1345 aRule->SetStyleSheet(this);
1346 DidDirty();
1348 if (nsICSSRule::NAMESPACE_RULE == aRule->GetType()) {
1349 // no api to prepend a namespace (ugh), release old ones and re-create them all
1350 mInner->RebuildNameSpaces();
1355 void
1356 nsCSSStyleSheet::AppendStyleRule(nsICSSRule* aRule)
1358 NS_PRECONDITION(nsnull != aRule, "null arg");
1360 if (NS_SUCCEEDED(WillDirty())) {
1361 mInner->mOrderedRules.AppendObject(aRule);
1362 aRule->SetStyleSheet(this);
1363 DidDirty();
1365 if (nsICSSRule::NAMESPACE_RULE == aRule->GetType()) {
1366 nsresult rv = RegisterNamespaceRule(aRule);
1367 NS_WARN_IF_FALSE(NS_SUCCEEDED(rv),
1368 "RegisterNamespaceRule returned error");
1373 void
1374 nsCSSStyleSheet::ReplaceStyleRule(nsICSSRule* aOld, nsICSSRule* aNew)
1376 NS_PRECONDITION(mInner->mOrderedRules.Count() != 0, "can't have old rule");
1377 NS_PRECONDITION(mInner->mComplete, "No replacing in an incomplete sheet!");
1379 if (NS_SUCCEEDED(WillDirty())) {
1380 PRInt32 index = mInner->mOrderedRules.IndexOf(aOld);
1381 if (NS_UNLIKELY(index == -1)) {
1382 NS_NOTREACHED("Couldn't find old rule");
1383 return;
1385 mInner->mOrderedRules.ReplaceObjectAt(aNew, index);
1387 aNew->SetStyleSheet(this);
1388 aOld->SetStyleSheet(nsnull);
1389 DidDirty();
1390 NS_ASSERTION(nsICSSRule::NAMESPACE_RULE != aNew->GetType(), "not yet implemented");
1391 NS_ASSERTION(nsICSSRule::NAMESPACE_RULE != aOld->GetType(), "not yet implemented");
1395 PRInt32
1396 nsCSSStyleSheet::StyleRuleCount() const
1398 return mInner->mOrderedRules.Count();
1401 nsresult
1402 nsCSSStyleSheet::GetStyleRuleAt(PRInt32 aIndex, nsICSSRule*& aRule) const
1404 // Important: If this function is ever made scriptable, we must add
1405 // a security check here. See GetCssRules below for an example.
1406 aRule = mInner->mOrderedRules.SafeObjectAt(aIndex);
1407 if (aRule) {
1408 NS_ADDREF(aRule);
1409 return NS_OK;
1412 return NS_ERROR_ILLEGAL_VALUE;
1415 PRInt32
1416 nsCSSStyleSheet::StyleSheetCount() const
1418 // XXX Far from an ideal way to do this, but the hope is that
1419 // it won't be done too often. If it is, we might want to
1420 // consider storing the children in an array.
1421 PRInt32 count = 0;
1423 const nsCSSStyleSheet* child = mInner->mFirstChild;
1424 while (child) {
1425 count++;
1426 child = child->mNext;
1429 return count;
1432 nsCSSStyleSheet::EnsureUniqueInnerResult
1433 nsCSSStyleSheet::EnsureUniqueInner()
1435 NS_ABORT_IF_FALSE(mInner->mSheets.Length() != 0,
1436 "unexpected number of outers");
1437 if (mInner->mSheets.Length() == 1) {
1438 return eUniqueInner_AlreadyUnique;
1440 nsCSSStyleSheetInner* clone = mInner->CloneFor(this);
1441 if (!clone) {
1442 return eUniqueInner_CloneFailed;
1444 mInner->RemoveSheet(this);
1445 mInner = clone;
1447 // otherwise the rule processor has pointers to the old rules
1448 ClearRuleCascades();
1450 return eUniqueInner_ClonedInner;
1453 PRBool
1454 nsCSSStyleSheet::AppendAllChildSheets(nsTArray<nsCSSStyleSheet*>& aArray)
1456 for (nsCSSStyleSheet* child = mInner->mFirstChild; child;
1457 child = child->mNext) {
1458 if (!aArray.AppendElement(child)) {
1459 return PR_FALSE;
1462 return PR_TRUE;
1465 already_AddRefed<nsCSSStyleSheet>
1466 nsCSSStyleSheet::Clone(nsCSSStyleSheet* aCloneParent,
1467 nsICSSImportRule* aCloneOwnerRule,
1468 nsIDocument* aCloneDocument,
1469 nsIDOMNode* aCloneOwningNode) const
1471 nsCSSStyleSheet* clone = new nsCSSStyleSheet(*this,
1472 aCloneParent,
1473 aCloneOwnerRule,
1474 aCloneDocument,
1475 aCloneOwningNode);
1476 NS_IF_ADDREF(clone);
1477 return clone;
1480 #ifdef DEBUG
1481 static void
1482 ListRules(const nsCOMArray<nsICSSRule>& aRules, FILE* aOut, PRInt32 aIndent)
1484 for (PRInt32 index = aRules.Count() - 1; index >= 0; --index) {
1485 aRules.ObjectAt(index)->List(aOut, aIndent);
1489 struct ListEnumData {
1490 ListEnumData(FILE* aOut, PRInt32 aIndent)
1491 : mOut(aOut),
1492 mIndent(aIndent)
1495 FILE* mOut;
1496 PRInt32 mIndent;
1499 /* virtual */ void
1500 nsCSSStyleSheet::List(FILE* out, PRInt32 aIndent) const
1503 PRInt32 index;
1505 // Indent
1506 for (index = aIndent; --index >= 0; ) fputs(" ", out);
1508 fputs("CSS Style Sheet: ", out);
1509 nsCAutoString urlSpec;
1510 nsresult rv = mInner->mSheetURI->GetSpec(urlSpec);
1511 if (NS_SUCCEEDED(rv) && !urlSpec.IsEmpty()) {
1512 fputs(urlSpec.get(), out);
1515 if (mMedia) {
1516 fputs(" media: ", out);
1517 nsAutoString buffer;
1518 mMedia->GetText(buffer);
1519 fputs(NS_ConvertUTF16toUTF8(buffer).get(), out);
1521 fputs("\n", out);
1523 for (const nsCSSStyleSheet* child = mInner->mFirstChild;
1524 child;
1525 child = child->mNext) {
1526 child->List(out, aIndent + 1);
1529 fputs("Rules in source order:\n", out);
1530 ListRules(mInner->mOrderedRules, out, aIndent);
1532 #endif
1534 void
1535 nsCSSStyleSheet::ClearRuleCascades()
1537 if (mRuleProcessors) {
1538 nsCSSRuleProcessor **iter = mRuleProcessors->Elements(),
1539 **end = iter + mRuleProcessors->Length();
1540 for(; iter != end; ++iter) {
1541 (*iter)->ClearRuleCascades();
1544 if (mParent) {
1545 nsCSSStyleSheet* parent = (nsCSSStyleSheet*)mParent;
1546 parent->ClearRuleCascades();
1550 nsresult
1551 nsCSSStyleSheet::WillDirty()
1553 if (!mInner->mComplete) {
1554 // Do nothing
1555 return NS_OK;
1558 if (EnsureUniqueInner() == eUniqueInner_CloneFailed) {
1559 return NS_ERROR_OUT_OF_MEMORY;
1561 return NS_OK;
1564 void
1565 nsCSSStyleSheet::DidDirty()
1567 ClearRuleCascades();
1568 mDirty = PR_TRUE;
1571 nsresult
1572 nsCSSStyleSheet::SubjectSubsumesInnerPrincipal() const
1574 // Get the security manager and do the subsumes check
1575 nsIScriptSecurityManager *securityManager =
1576 nsContentUtils::GetSecurityManager();
1578 nsCOMPtr<nsIPrincipal> subjectPrincipal;
1579 securityManager->GetSubjectPrincipal(getter_AddRefs(subjectPrincipal));
1581 if (!subjectPrincipal) {
1582 return NS_ERROR_DOM_SECURITY_ERR;
1585 PRBool subsumes;
1586 nsresult rv = subjectPrincipal->Subsumes(mInner->mPrincipal, &subsumes);
1587 NS_ENSURE_SUCCESS(rv, rv);
1589 if (subsumes) {
1590 return NS_OK;
1593 if (!nsContentUtils::IsCallerTrustedForWrite()) {
1594 return NS_ERROR_DOM_SECURITY_ERR;
1597 return NS_OK;
1600 nsresult
1601 nsCSSStyleSheet::RegisterNamespaceRule(nsICSSRule* aRule)
1603 if (!mInner->mNameSpaceMap) {
1604 nsresult rv = mInner->CreateNamespaceMap();
1605 NS_ENSURE_SUCCESS(rv, rv);
1608 AddNamespaceRuleToMap(aRule, mInner->mNameSpaceMap);
1609 return NS_OK;
1612 // nsIDOMStyleSheet interface
1613 NS_IMETHODIMP
1614 nsCSSStyleSheet::GetType(nsAString& aType)
1616 aType.AssignLiteral("text/css");
1617 return NS_OK;
1620 NS_IMETHODIMP
1621 nsCSSStyleSheet::GetDisabled(PRBool* aDisabled)
1623 *aDisabled = mDisabled;
1624 return NS_OK;
1627 NS_IMETHODIMP
1628 nsCSSStyleSheet::SetDisabled(PRBool aDisabled)
1630 // DOM method, so handle BeginUpdate/EndUpdate
1631 MOZ_AUTO_DOC_UPDATE(mDocument, UPDATE_STYLE, PR_TRUE);
1632 nsCSSStyleSheet::SetEnabled(!aDisabled);
1633 return NS_OK;
1636 NS_IMETHODIMP
1637 nsCSSStyleSheet::GetOwnerNode(nsIDOMNode** aOwnerNode)
1639 *aOwnerNode = mOwningNode;
1640 NS_IF_ADDREF(*aOwnerNode);
1641 return NS_OK;
1644 NS_IMETHODIMP
1645 nsCSSStyleSheet::GetParentStyleSheet(nsIDOMStyleSheet** aParentStyleSheet)
1647 NS_ENSURE_ARG_POINTER(aParentStyleSheet);
1649 NS_IF_ADDREF(*aParentStyleSheet = mParent);
1651 return NS_OK;
1654 NS_IMETHODIMP
1655 nsCSSStyleSheet::GetHref(nsAString& aHref)
1657 if (mInner->mOriginalSheetURI) {
1658 nsCAutoString str;
1659 mInner->mOriginalSheetURI->GetSpec(str);
1660 CopyUTF8toUTF16(str, aHref);
1661 } else {
1662 SetDOMStringToNull(aHref);
1665 return NS_OK;
1668 /* virtual */ void
1669 nsCSSStyleSheet::GetTitle(nsString& aTitle) const
1671 aTitle = mTitle;
1674 NS_IMETHODIMP
1675 nsCSSStyleSheet::GetTitle(nsAString& aTitle)
1677 aTitle.Assign(mTitle);
1678 return NS_OK;
1681 NS_IMETHODIMP
1682 nsCSSStyleSheet::GetMedia(nsIDOMMediaList** aMedia)
1684 NS_ENSURE_ARG_POINTER(aMedia);
1685 *aMedia = nsnull;
1687 if (!mMedia) {
1688 mMedia = new nsMediaList();
1689 NS_ENSURE_TRUE(mMedia, NS_ERROR_OUT_OF_MEMORY);
1690 mMedia->SetStyleSheet(this);
1693 *aMedia = mMedia;
1694 NS_ADDREF(*aMedia);
1696 return NS_OK;
1699 NS_IMETHODIMP
1700 nsCSSStyleSheet::GetOwnerRule(nsIDOMCSSRule** aOwnerRule)
1702 if (mOwnerRule) {
1703 return mOwnerRule->GetDOMRule(aOwnerRule);
1706 *aOwnerRule = nsnull;
1707 return NS_OK;
1710 NS_IMETHODIMP
1711 nsCSSStyleSheet::GetCssRules(nsIDOMCSSRuleList** aCssRules)
1713 // No doing this on incomplete sheets!
1714 if (!mInner->mComplete) {
1715 return NS_ERROR_DOM_INVALID_ACCESS_ERR;
1718 //-- Security check: Only scripts whose principal subsumes that of the
1719 // style sheet can access rule collections.
1720 nsresult rv = SubjectSubsumesInnerPrincipal();
1721 NS_ENSURE_SUCCESS(rv, rv);
1723 // OK, security check passed, so get the rule collection
1724 if (nsnull == mRuleCollection) {
1725 mRuleCollection = new CSSRuleListImpl(this);
1726 if (nsnull == mRuleCollection) {
1727 return NS_ERROR_OUT_OF_MEMORY;
1729 NS_ADDREF(mRuleCollection);
1732 *aCssRules = mRuleCollection;
1733 NS_ADDREF(mRuleCollection);
1735 return NS_OK;
1738 NS_IMETHODIMP
1739 nsCSSStyleSheet::InsertRule(const nsAString& aRule,
1740 PRUint32 aIndex,
1741 PRUint32* aReturn)
1743 //-- Security check: Only scripts whose principal subsumes that of the
1744 // style sheet can modify rule collections.
1745 nsresult rv = SubjectSubsumesInnerPrincipal();
1746 NS_ENSURE_SUCCESS(rv, rv);
1748 return InsertRuleInternal(aRule, aIndex, aReturn);
1751 nsresult
1752 nsCSSStyleSheet::InsertRuleInternal(const nsAString& aRule,
1753 PRUint32 aIndex,
1754 PRUint32* aReturn)
1756 // No doing this if the sheet is not complete!
1757 if (!mInner->mComplete) {
1758 return NS_ERROR_DOM_INVALID_ACCESS_ERR;
1761 if (aRule.IsEmpty()) {
1762 // Nothing to do here
1763 return NS_OK;
1766 nsresult result;
1767 result = WillDirty();
1768 if (NS_FAILED(result))
1769 return result;
1771 if (aIndex > PRUint32(mInner->mOrderedRules.Count()))
1772 return NS_ERROR_DOM_INDEX_SIZE_ERR;
1774 NS_ASSERTION(PRUint32(mInner->mOrderedRules.Count()) <= PR_INT32_MAX,
1775 "Too many style rules!");
1777 // Hold strong ref to the CSSLoader in case the document update
1778 // kills the document
1779 nsRefPtr<css::Loader> loader;
1780 if (mDocument) {
1781 loader = mDocument->CSSLoader();
1782 NS_ASSERTION(loader, "Document with no CSS loader!");
1785 nsCSSParser css(loader, this);
1786 if (!css)
1787 return NS_ERROR_OUT_OF_MEMORY;
1789 mozAutoDocUpdate updateBatch(mDocument, UPDATE_STYLE, PR_TRUE);
1791 nsCOMArray<nsICSSRule> rules;
1792 result = css.ParseRule(aRule, mInner->mSheetURI, mInner->mBaseURI,
1793 mInner->mPrincipal, rules);
1794 if (NS_FAILED(result))
1795 return result;
1797 PRInt32 rulecount = rules.Count();
1798 if (rulecount == 0) {
1799 // Since we know aRule was not an empty string, just throw
1800 return NS_ERROR_DOM_SYNTAX_ERR;
1803 // Hierarchy checking. Just check the first and last rule in the list.
1805 // check that we're not inserting before a charset rule
1806 nsICSSRule* nextRule = mInner->mOrderedRules.SafeObjectAt(aIndex);
1807 if (nextRule) {
1808 PRInt32 nextType = nextRule->GetType();
1809 if (nextType == nsICSSRule::CHARSET_RULE) {
1810 return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
1813 // check last rule in list
1814 nsICSSRule* lastRule = rules.ObjectAt(rulecount - 1);
1815 PRInt32 lastType = lastRule->GetType();
1817 if (nextType == nsICSSRule::IMPORT_RULE &&
1818 lastType != nsICSSRule::CHARSET_RULE &&
1819 lastType != nsICSSRule::IMPORT_RULE) {
1820 return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
1823 if (nextType == nsICSSRule::NAMESPACE_RULE &&
1824 lastType != nsICSSRule::CHARSET_RULE &&
1825 lastType != nsICSSRule::IMPORT_RULE &&
1826 lastType != nsICSSRule::NAMESPACE_RULE) {
1827 return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
1831 // check first rule in list
1832 nsICSSRule* firstRule = rules.ObjectAt(0);
1833 PRInt32 firstType = firstRule->GetType();
1834 if (aIndex != 0) {
1835 if (firstType == nsICSSRule::CHARSET_RULE) { // no inserting charset at nonzero position
1836 return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
1839 nsICSSRule* prevRule = mInner->mOrderedRules.SafeObjectAt(aIndex - 1);
1840 PRInt32 prevType = prevRule->GetType();
1842 if (firstType == nsICSSRule::IMPORT_RULE &&
1843 prevType != nsICSSRule::CHARSET_RULE &&
1844 prevType != nsICSSRule::IMPORT_RULE) {
1845 return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
1848 if (firstType == nsICSSRule::NAMESPACE_RULE &&
1849 prevType != nsICSSRule::CHARSET_RULE &&
1850 prevType != nsICSSRule::IMPORT_RULE &&
1851 prevType != nsICSSRule::NAMESPACE_RULE) {
1852 return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
1856 PRBool insertResult = mInner->mOrderedRules.InsertObjectsAt(rules, aIndex);
1857 NS_ENSURE_TRUE(insertResult, NS_ERROR_OUT_OF_MEMORY);
1858 DidDirty();
1860 for (PRInt32 counter = 0; counter < rulecount; counter++) {
1861 nsICSSRule* cssRule = rules.ObjectAt(counter);
1862 cssRule->SetStyleSheet(this);
1864 PRInt32 type = cssRule->GetType();
1865 if (type == nsICSSRule::NAMESPACE_RULE) {
1866 // XXXbz does this screw up when inserting a namespace rule before
1867 // another namespace rule that binds the same prefix to a different
1868 // namespace?
1869 result = RegisterNamespaceRule(cssRule);
1870 NS_ENSURE_SUCCESS(result, result);
1873 // We don't notify immediately for @import rules, but rather when
1874 // the sheet the rule is importing is loaded
1875 PRBool notify = PR_TRUE;
1876 if (type == nsICSSRule::IMPORT_RULE) {
1877 nsCOMPtr<nsIDOMCSSImportRule> importRule(do_QueryInterface(cssRule));
1878 NS_ASSERTION(importRule, "Rule which has type IMPORT_RULE and does not implement nsIDOMCSSImportRule!");
1879 nsCOMPtr<nsIDOMCSSStyleSheet> childSheet;
1880 importRule->GetStyleSheet(getter_AddRefs(childSheet));
1881 if (!childSheet) {
1882 notify = PR_FALSE;
1885 if (mDocument && notify) {
1886 mDocument->StyleRuleAdded(this, cssRule);
1890 *aReturn = aIndex;
1891 return NS_OK;
1894 NS_IMETHODIMP
1895 nsCSSStyleSheet::DeleteRule(PRUint32 aIndex)
1897 nsresult result = NS_ERROR_DOM_INDEX_SIZE_ERR;
1898 // No doing this if the sheet is not complete!
1899 if (!mInner->mComplete) {
1900 return NS_ERROR_DOM_INVALID_ACCESS_ERR;
1903 //-- Security check: Only scripts whose principal subsumes that of the
1904 // style sheet can modify rule collections.
1905 nsresult rv = SubjectSubsumesInnerPrincipal();
1906 NS_ENSURE_SUCCESS(rv, rv);
1908 // XXX TBI: handle @rule types
1909 mozAutoDocUpdate updateBatch(mDocument, UPDATE_STYLE, PR_TRUE);
1911 result = WillDirty();
1913 if (NS_SUCCEEDED(result)) {
1914 if (aIndex >= PRUint32(mInner->mOrderedRules.Count()))
1915 return NS_ERROR_DOM_INDEX_SIZE_ERR;
1917 NS_ASSERTION(PRUint32(mInner->mOrderedRules.Count()) <= PR_INT32_MAX,
1918 "Too many style rules!");
1920 // Hold a strong ref to the rule so it doesn't die when we RemoveObjectAt
1921 nsCOMPtr<nsICSSRule> rule = mInner->mOrderedRules.ObjectAt(aIndex);
1922 if (rule) {
1923 mInner->mOrderedRules.RemoveObjectAt(aIndex);
1924 rule->SetStyleSheet(nsnull);
1925 DidDirty();
1927 if (mDocument) {
1928 mDocument->StyleRuleRemoved(this, rule);
1933 return result;
1936 nsresult
1937 nsCSSStyleSheet::DeleteRuleFromGroup(nsICSSGroupRule* aGroup, PRUint32 aIndex)
1939 NS_ENSURE_ARG_POINTER(aGroup);
1940 NS_ASSERTION(mInner->mComplete, "No deleting from an incomplete sheet!");
1941 nsresult result;
1942 nsCOMPtr<nsICSSRule> rule;
1943 result = aGroup->GetStyleRuleAt(aIndex, *getter_AddRefs(rule));
1944 NS_ENSURE_SUCCESS(result, result);
1946 // check that the rule actually belongs to this sheet!
1947 nsCOMPtr<nsIStyleSheet> ruleSheet = rule->GetStyleSheet();
1948 if (this != ruleSheet) {
1949 return NS_ERROR_INVALID_ARG;
1952 mozAutoDocUpdate updateBatch(mDocument, UPDATE_STYLE, PR_TRUE);
1954 result = WillDirty();
1955 NS_ENSURE_SUCCESS(result, result);
1957 result = aGroup->DeleteStyleRuleAt(aIndex);
1958 NS_ENSURE_SUCCESS(result, result);
1960 rule->SetStyleSheet(nsnull);
1962 DidDirty();
1964 if (mDocument) {
1965 mDocument->StyleRuleRemoved(this, rule);
1968 return NS_OK;
1971 nsresult
1972 nsCSSStyleSheet::InsertRuleIntoGroup(const nsAString & aRule,
1973 nsICSSGroupRule* aGroup,
1974 PRUint32 aIndex,
1975 PRUint32* _retval)
1977 nsresult result;
1978 NS_ASSERTION(mInner->mComplete, "No inserting into an incomplete sheet!");
1979 // check that the group actually belongs to this sheet!
1980 nsCOMPtr<nsIStyleSheet> groupSheet = aGroup->GetStyleSheet();
1981 if (this != groupSheet) {
1982 return NS_ERROR_INVALID_ARG;
1985 if (aRule.IsEmpty()) {
1986 // Nothing to do here
1987 return NS_OK;
1990 // Hold strong ref to the CSSLoader in case the document update
1991 // kills the document
1992 nsRefPtr<css::Loader> loader;
1993 if (mDocument) {
1994 loader = mDocument->CSSLoader();
1995 NS_ASSERTION(loader, "Document with no CSS loader!");
1998 nsCSSParser css(loader, this);
1999 if (!css) {
2000 return NS_ERROR_OUT_OF_MEMORY;
2003 // parse and grab the rule
2004 mozAutoDocUpdate updateBatch(mDocument, UPDATE_STYLE, PR_TRUE);
2006 result = WillDirty();
2007 NS_ENSURE_SUCCESS(result, result);
2009 nsCOMArray<nsICSSRule> rules;
2010 result = css.ParseRule(aRule, mInner->mSheetURI, mInner->mBaseURI,
2011 mInner->mPrincipal, rules);
2012 NS_ENSURE_SUCCESS(result, result);
2014 PRInt32 rulecount = rules.Count();
2015 if (rulecount == 0) {
2016 // Since we know aRule was not an empty string, just throw
2017 return NS_ERROR_DOM_SYNTAX_ERR;
2020 PRInt32 counter;
2021 nsICSSRule* rule;
2022 for (counter = 0; counter < rulecount; counter++) {
2023 // Only rulesets are allowed in a group as of CSS2
2024 rule = rules.ObjectAt(counter);
2025 if (rule->GetType() != nsICSSRule::STYLE_RULE) {
2026 return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
2030 result = aGroup->InsertStyleRulesAt(aIndex, rules);
2031 NS_ENSURE_SUCCESS(result, result);
2032 DidDirty();
2033 for (counter = 0; counter < rulecount; counter++) {
2034 rule = rules.ObjectAt(counter);
2036 if (mDocument) {
2037 mDocument->StyleRuleAdded(this, rule);
2041 *_retval = aIndex;
2042 return NS_OK;
2045 nsresult
2046 nsCSSStyleSheet::ReplaceRuleInGroup(nsICSSGroupRule* aGroup,
2047 nsICSSRule* aOld, nsICSSRule* aNew)
2049 nsresult result;
2050 NS_PRECONDITION(mInner->mComplete, "No replacing in an incomplete sheet!");
2051 #ifdef DEBUG
2053 nsCOMPtr<nsIStyleSheet> groupSheet = aGroup->GetStyleSheet();
2054 NS_ASSERTION(this == groupSheet, "group doesn't belong to this sheet");
2056 #endif
2057 result = WillDirty();
2058 NS_ENSURE_SUCCESS(result, result);
2060 result = aGroup->ReplaceStyleRule(aOld, aNew);
2061 DidDirty();
2062 return result;
2065 // nsICSSLoaderObserver implementation
2066 NS_IMETHODIMP
2067 nsCSSStyleSheet::StyleSheetLoaded(nsCSSStyleSheet* aSheet,
2068 PRBool aWasAlternate,
2069 nsresult aStatus)
2071 NS_ASSERTION(this == aSheet->GetParentSheet(),
2072 "We are being notified of a sheet load for a sheet that is not our child!");
2074 if (mDocument && NS_SUCCEEDED(aStatus)) {
2075 nsCOMPtr<nsICSSImportRule> ownerRule = aSheet->GetOwnerRule();
2077 mozAutoDocUpdate updateBatch(mDocument, UPDATE_STYLE, PR_TRUE);
2079 // XXXldb @import rules shouldn't even implement nsIStyleRule (but
2080 // they do)!
2081 nsCOMPtr<nsIStyleRule> styleRule(do_QueryInterface(ownerRule));
2083 mDocument->StyleRuleAdded(this, styleRule);
2086 return NS_OK;
2089 /* virtual */ nsIURI*
2090 nsCSSStyleSheet::GetOriginalURI() const
2092 return mInner->mOriginalSheetURI;
2095 nsresult
2096 NS_NewCSSStyleSheet(nsCSSStyleSheet** aInstancePtrResult)
2098 *aInstancePtrResult = nsnull;
2099 nsCSSStyleSheet *it = new nsCSSStyleSheet();
2101 if (!it) {
2102 return NS_ERROR_OUT_OF_MEMORY;
2105 NS_ADDREF(it);
2107 if (!it->mInner || !it->mInner->mPrincipal) {
2108 NS_RELEASE(it);
2109 return NS_ERROR_OUT_OF_MEMORY;
2112 *aInstancePtrResult = it;
2113 return NS_OK;