Bug 451040 ? Passwords Manager Empty after convert to MozStorage. r=gavin
[wine-gecko.git] / layout / style / nsCSSStyleSheet.cpp
blob45d66cb6414559865e001f8f20551ea00cb9e0f0
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 "nsIServiceManager.h"
49 #include "nsCSSRuleProcessor.h"
50 #include "nsICSSStyleRule.h"
51 #include "nsICSSNameSpaceRule.h"
52 #include "nsICSSGroupRule.h"
53 #include "nsICSSImportRule.h"
54 #include "nsIMediaList.h"
55 #include "nsIDocument.h"
56 #include "nsPresContext.h"
57 #include "nsGkAtoms.h"
58 #include "nsString.h"
59 #include "nsVoidArray.h"
60 #include "nsIDOMStyleSheetList.h"
61 #include "nsIDOMCSSStyleSheet.h"
62 #include "nsIDOMCSSRule.h"
63 #include "nsIDOMCSSImportRule.h"
64 #include "nsIDOMCSSRuleList.h"
65 #include "nsIDOMMediaList.h"
66 #include "nsIDOMNode.h"
67 #include "nsDOMError.h"
68 #include "nsICSSParser.h"
69 #include "nsICSSLoader.h"
70 #include "nsICSSLoaderObserver.h"
71 #include "nsINameSpaceManager.h"
72 #include "nsXMLNameSpaceMap.h"
73 #include "nsCOMPtr.h"
74 #include "nsContentUtils.h"
75 #include "nsIJSContextStack.h"
76 #include "nsIScriptSecurityManager.h"
77 #include "mozAutoDocUpdate.h"
78 #include "nsCSSDeclaration.h"
79 #include "nsRuleNode.h"
81 // -------------------------------
82 // Style Rule List for the DOM
84 class CSSRuleListImpl : public nsIDOMCSSRuleList
86 public:
87 CSSRuleListImpl(nsCSSStyleSheet *aStyleSheet);
89 NS_DECL_ISUPPORTS
91 // nsIDOMCSSRuleList interface
92 NS_IMETHOD GetLength(PRUint32* aLength);
93 NS_IMETHOD Item(PRUint32 aIndex, nsIDOMCSSRule** aReturn);
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 // QueryInterface implementation for CSSRuleList
118 NS_INTERFACE_MAP_BEGIN(CSSRuleListImpl)
119 NS_INTERFACE_MAP_ENTRY(nsIDOMCSSRuleList)
120 NS_INTERFACE_MAP_ENTRY(nsISupports)
121 NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(CSSRuleList)
122 NS_INTERFACE_MAP_END
125 NS_IMPL_ADDREF(CSSRuleListImpl)
126 NS_IMPL_RELEASE(CSSRuleListImpl)
129 NS_IMETHODIMP
130 CSSRuleListImpl::GetLength(PRUint32* aLength)
132 if (nsnull != mStyleSheet) {
133 PRInt32 count;
134 mStyleSheet->StyleRuleCount(count);
135 *aLength = (PRUint32)count;
137 else {
138 *aLength = 0;
141 return NS_OK;
144 NS_IMETHODIMP
145 CSSRuleListImpl::Item(PRUint32 aIndex, nsIDOMCSSRule** aReturn)
147 nsresult result = NS_OK;
149 *aReturn = nsnull;
150 if (mStyleSheet) {
151 result = mStyleSheet->EnsureUniqueInner(); // needed to ensure rules have correct parent
152 if (NS_SUCCEEDED(result)) {
153 nsCOMPtr<nsICSSRule> rule;
155 result = mStyleSheet->GetStyleRuleAt(aIndex, *getter_AddRefs(rule));
156 if (rule) {
157 result = rule->GetDOMRule(aReturn);
158 mRulesAccessed = PR_TRUE; // signal to never share rules again
159 } else if (result == NS_ERROR_ILLEGAL_VALUE) {
160 result = NS_OK; // per spec: "Return Value ... null if ... not a valid index."
165 return result;
168 template <class Numeric>
169 PRInt32 DoCompare(Numeric a, Numeric b)
171 if (a == b)
172 return 0;
173 if (a < b)
174 return -1;
175 return 1;
178 PRBool
179 nsMediaExpression::Matches(nsPresContext *aPresContext,
180 const nsCSSValue& aActualValue) const
182 const nsCSSValue& actual = aActualValue;
183 const nsCSSValue& required = mValue;
185 // If we don't have the feature, the match fails.
186 if (actual.GetUnit() == eCSSUnit_Null) {
187 return PR_FALSE;
190 // If the expression had no value to match, the match succeeds,
191 // unless the value is an integer 0.
192 if (required.GetUnit() == eCSSUnit_Null) {
193 return actual.GetUnit() != eCSSUnit_Integer ||
194 actual.GetIntValue() != 0;
197 NS_ASSERTION(mFeature->mRangeType == nsMediaFeature::eMinMaxAllowed ||
198 mRange == nsMediaExpression::eEqual, "yikes");
199 PRInt32 cmp; // -1 (actual < required)
200 // 0 (actual == required)
201 // 1 (actual > required)
202 switch (mFeature->mValueType) {
203 case nsMediaFeature::eLength:
205 NS_ASSERTION(actual.IsLengthUnit(), "bad actual value");
206 NS_ASSERTION(required.IsLengthUnit(), "bad required value");
207 nscoord actualCoord = nsRuleNode::CalcLengthWithInitialFont(
208 aPresContext, actual);
209 nscoord requiredCoord = nsRuleNode::CalcLengthWithInitialFont(
210 aPresContext, required);
211 cmp = DoCompare(actualCoord, requiredCoord);
213 break;
214 case nsMediaFeature::eInteger:
216 NS_ASSERTION(actual.GetUnit() == eCSSUnit_Integer,
217 "bad actual value");
218 NS_ASSERTION(required.GetUnit() == eCSSUnit_Integer,
219 "bad required value");
220 cmp = DoCompare(actual.GetIntValue(), required.GetIntValue());
222 break;
223 case nsMediaFeature::eIntRatio:
225 NS_ASSERTION(actual.GetUnit() == eCSSUnit_Array &&
226 actual.GetArrayValue()->Count() == 2 &&
227 actual.GetArrayValue()->Item(0).GetUnit() ==
228 eCSSUnit_Integer &&
229 actual.GetArrayValue()->Item(1).GetUnit() ==
230 eCSSUnit_Integer,
231 "bad actual value");
232 NS_ASSERTION(required.GetUnit() == eCSSUnit_Array &&
233 required.GetArrayValue()->Count() == 2 &&
234 required.GetArrayValue()->Item(0).GetUnit() ==
235 eCSSUnit_Integer &&
236 required.GetArrayValue()->Item(1).GetUnit() ==
237 eCSSUnit_Integer,
238 "bad required value");
239 // Convert to PRInt64 so we can multiply without worry. Note
240 // that while the spec requires that both halves of |required|
241 // be positive, the numerator or denominator of |actual| might
242 // be zero (e.g., when testing 'aspect-ratio' on a 0-width or
243 // 0-height iframe).
244 PRInt64 actualNum = actual.GetArrayValue()->Item(0).GetIntValue(),
245 actualDen = actual.GetArrayValue()->Item(1).GetIntValue(),
246 requiredNum = required.GetArrayValue()->Item(0).GetIntValue(),
247 requiredDen = required.GetArrayValue()->Item(1).GetIntValue();
248 cmp = DoCompare(actualNum * requiredDen, requiredNum * actualDen);
250 break;
251 case nsMediaFeature::eResolution:
253 NS_ASSERTION(actual.GetUnit() == eCSSUnit_Inch ||
254 actual.GetUnit() == eCSSUnit_Centimeter,
255 "bad actual value");
256 NS_ASSERTION(required.GetUnit() == eCSSUnit_Inch ||
257 required.GetUnit() == eCSSUnit_Centimeter,
258 "bad required value");
259 float actualDPI = actual.GetFloatValue();
260 if (actual.GetUnit() == eCSSUnit_Centimeter)
261 actualDPI = actualDPI * 2.54f;
262 float requiredDPI = required.GetFloatValue();
263 if (required.GetUnit() == eCSSUnit_Centimeter)
264 requiredDPI = requiredDPI * 2.54f;
265 cmp = DoCompare(actualDPI, requiredDPI);
267 break;
268 case nsMediaFeature::eEnumerated:
270 NS_ASSERTION(actual.GetUnit() == eCSSUnit_Enumerated,
271 "bad actual value");
272 NS_ASSERTION(required.GetUnit() == eCSSUnit_Enumerated,
273 "bad required value");
274 NS_ASSERTION(mFeature->mRangeType == nsMediaFeature::eMinMaxNotAllowed,
275 "bad range"); // we asserted above about mRange
276 // We don't really need DoCompare, but it doesn't hurt (and
277 // maybe the compiler will condense this case with eInteger).
278 cmp = DoCompare(actual.GetIntValue(), required.GetIntValue());
280 break;
282 switch (mRange) {
283 case nsMediaExpression::eMin:
284 return cmp != -1;
285 case nsMediaExpression::eMax:
286 return cmp != 1;
287 case nsMediaExpression::eEqual:
288 return cmp == 0;
290 NS_NOTREACHED("unexpected mRange");
291 return PR_FALSE;
294 void
295 nsMediaQueryResultCacheKey::AddExpression(const nsMediaExpression* aExpression,
296 PRBool aExpressionMatches)
298 const nsMediaFeature *feature = aExpression->mFeature;
299 FeatureEntry *entry = nsnull;
300 for (PRUint32 i = 0; i < mFeatureCache.Length(); ++i) {
301 if (mFeatureCache[i].mFeature == feature) {
302 entry = &mFeatureCache[i];
303 break;
306 if (!entry) {
307 entry = mFeatureCache.AppendElement();
308 if (!entry) {
309 return; /* out of memory */
311 entry->mFeature = feature;
314 ExpressionEntry eentry = { *aExpression, aExpressionMatches };
315 entry->mExpressions.AppendElement(eentry);
318 PRBool
319 nsMediaQueryResultCacheKey::Matches(nsPresContext* aPresContext) const
321 if (aPresContext->Medium() != mMedium) {
322 return PR_FALSE;
325 for (PRUint32 i = 0; i < mFeatureCache.Length(); ++i) {
326 const FeatureEntry *entry = &mFeatureCache[i];
327 nsCSSValue actual;
328 nsresult rv = (entry->mFeature->mGetter)(aPresContext, actual);
329 NS_ENSURE_SUCCESS(rv, PR_FALSE); // any better ideas?
331 for (PRUint32 j = 0; j < entry->mExpressions.Length(); ++j) {
332 const ExpressionEntry &eentry = entry->mExpressions[j];
333 if (eentry.mExpression.Matches(aPresContext, actual) !=
334 eentry.mExpressionMatches) {
335 return PR_FALSE;
340 return PR_TRUE;
343 void
344 nsMediaQuery::AppendToString(nsAString& aString) const
346 nsAutoString buffer;
348 if (mHadUnknownExpression) {
349 aString.AppendLiteral("not all");
350 return;
353 NS_ASSERTION(!mNegated || !mHasOnly, "can't have not and only");
354 NS_ASSERTION(!mTypeOmitted || (!mNegated && !mHasOnly),
355 "can't have not or only when type is omitted");
356 if (!mTypeOmitted) {
357 if (mNegated) {
358 aString.AppendLiteral("not ");
359 } else if (mHasOnly) {
360 aString.AppendLiteral("only ");
362 mMediaType->ToString(buffer);
363 aString.Append(buffer);
364 buffer.Truncate();
367 for (PRUint32 i = 0, i_end = mExpressions.Length(); i < i_end; ++i) {
368 if (i > 0 || !mTypeOmitted)
369 aString.AppendLiteral(" and ");
370 aString.AppendLiteral("(");
372 const nsMediaExpression &expr = mExpressions[i];
373 if (expr.mRange == nsMediaExpression::eMin) {
374 aString.AppendLiteral("min-");
375 } else if (expr.mRange == nsMediaExpression::eMax) {
376 aString.AppendLiteral("max-");
379 const nsMediaFeature *feature = expr.mFeature;
380 (*feature->mName)->ToString(buffer);
381 aString.Append(buffer);
382 buffer.Truncate();
384 if (expr.mValue.GetUnit() != eCSSUnit_Null) {
385 aString.AppendLiteral(": ");
386 switch (feature->mValueType) {
387 case nsMediaFeature::eLength:
388 NS_ASSERTION(expr.mValue.IsLengthUnit(), "bad unit");
389 // Use 'width' as a property that takes length values
390 // written in the normal way.
391 nsCSSDeclaration::AppendCSSValueToString(eCSSProperty_width,
392 expr.mValue, aString);
393 break;
394 case nsMediaFeature::eInteger:
395 NS_ASSERTION(expr.mValue.GetUnit() == eCSSUnit_Integer,
396 "bad unit");
397 // Use 'z-index' as a property that takes integer values
398 // written without anything extra.
399 nsCSSDeclaration::AppendCSSValueToString(eCSSProperty_z_index,
400 expr.mValue, aString);
401 break;
402 case nsMediaFeature::eIntRatio:
404 NS_ASSERTION(expr.mValue.GetUnit() == eCSSUnit_Array,
405 "bad unit");
406 nsCSSValue::Array *array = expr.mValue.GetArrayValue();
407 NS_ASSERTION(array->Count() == 2, "unexpected length");
408 NS_ASSERTION(array->Item(0).GetUnit() == eCSSUnit_Integer,
409 "bad unit");
410 NS_ASSERTION(array->Item(1).GetUnit() == eCSSUnit_Integer,
411 "bad unit");
412 nsCSSDeclaration::AppendCSSValueToString(eCSSProperty_z_index,
413 array->Item(0), aString);
414 aString.AppendLiteral("/");
415 nsCSSDeclaration::AppendCSSValueToString(eCSSProperty_z_index,
416 array->Item(1), aString);
418 break;
419 case nsMediaFeature::eResolution:
420 buffer.AppendFloat(expr.mValue.GetFloatValue());
421 aString.Append(buffer);
422 buffer.Truncate();
423 if (expr.mValue.GetUnit() == eCSSUnit_Inch) {
424 aString.AppendLiteral("dpi");
425 } else {
426 NS_ASSERTION(expr.mValue.GetUnit() == eCSSUnit_Centimeter,
427 "bad unit");
428 aString.AppendLiteral("dpcm");
430 break;
431 case nsMediaFeature::eEnumerated:
432 NS_ASSERTION(expr.mValue.GetUnit() == eCSSUnit_Enumerated,
433 "bad unit");
434 AppendASCIItoUTF16(
435 nsCSSProps::ValueToKeyword(expr.mValue.GetIntValue(),
436 feature->mKeywordTable),
437 aString);
438 break;
442 aString.AppendLiteral(")");
446 nsMediaQuery*
447 nsMediaQuery::Clone() const
449 nsAutoPtr<nsMediaQuery> result(new nsMediaQuery(*this));
450 NS_ENSURE_TRUE(result &&
451 result->mExpressions.Length() == mExpressions.Length(),
452 nsnull);
453 return result.forget();
456 PRBool
457 nsMediaQuery::Matches(nsPresContext* aPresContext,
458 nsMediaQueryResultCacheKey& aKey) const
460 if (mHadUnknownExpression)
461 return PR_FALSE;
463 PRBool match =
464 mMediaType == aPresContext->Medium() || mMediaType == nsGkAtoms::all;
465 for (PRUint32 i = 0, i_end = mExpressions.Length(); match && i < i_end; ++i) {
466 const nsMediaExpression &expr = mExpressions[i];
467 nsCSSValue actual;
468 nsresult rv = (expr.mFeature->mGetter)(aPresContext, actual);
469 NS_ENSURE_SUCCESS(rv, PR_FALSE); // any better ideas?
471 match = expr.Matches(aPresContext, actual);
472 aKey.AddExpression(&expr, match);
475 return match == !mNegated;
478 NS_INTERFACE_MAP_BEGIN(nsMediaList)
479 NS_INTERFACE_MAP_ENTRY(nsIDOMMediaList)
480 NS_INTERFACE_MAP_ENTRY(nsISupports)
481 NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(MediaList)
482 NS_INTERFACE_MAP_END
484 NS_IMPL_ADDREF(nsMediaList)
485 NS_IMPL_RELEASE(nsMediaList)
488 nsMediaList::nsMediaList()
489 : mIsEmpty(PR_TRUE)
490 , mStyleSheet(nsnull)
494 nsMediaList::~nsMediaList()
498 nsresult
499 nsMediaList::GetText(nsAString& aMediaText)
501 aMediaText.Truncate();
503 if (mArray.Length() == 0 && !mIsEmpty) {
504 aMediaText.AppendLiteral("not all");
507 for (PRInt32 i = 0, i_end = mArray.Length(); i < i_end; ++i) {
508 nsMediaQuery* query = mArray[i];
509 NS_ENSURE_TRUE(query, NS_ERROR_FAILURE);
511 query->AppendToString(aMediaText);
513 if (i + 1 < i_end) {
514 aMediaText.AppendLiteral(", ");
518 return NS_OK;
521 // XXXbz this is so ill-defined in the spec, it's not clear quite what
522 // it should be doing....
523 nsresult
524 nsMediaList::SetText(const nsAString& aMediaText)
526 nsCOMPtr<nsICSSParser> parser;
527 nsresult rv = NS_NewCSSParser(getter_AddRefs(parser));
528 NS_ENSURE_SUCCESS(rv, rv);
530 PRBool htmlMode = PR_FALSE;
531 nsCOMPtr<nsIDOMStyleSheet> domSheet =
532 do_QueryInterface(static_cast<nsICSSStyleSheet*>(mStyleSheet));
533 if (domSheet) {
534 nsCOMPtr<nsIDOMNode> node;
535 domSheet->GetOwnerNode(getter_AddRefs(node));
536 htmlMode = !!node;
539 return parser->ParseMediaList(nsString(aMediaText), nsnull, 0,
540 this, htmlMode);
543 PRBool
544 nsMediaList::Matches(nsPresContext* aPresContext,
545 nsMediaQueryResultCacheKey& aKey)
547 for (PRInt32 i = 0, i_end = mArray.Length(); i < i_end; ++i) {
548 if (mArray[i]->Matches(aPresContext, aKey)) {
549 return PR_TRUE;
552 return mIsEmpty;
555 nsresult
556 nsMediaList::SetStyleSheet(nsICSSStyleSheet *aSheet)
558 NS_ASSERTION(aSheet == mStyleSheet || !aSheet || !mStyleSheet,
559 "multiple style sheets competing for one media list");
560 mStyleSheet = static_cast<nsCSSStyleSheet*>(aSheet);
561 return NS_OK;
564 nsresult
565 nsMediaList::Clone(nsMediaList** aResult)
567 nsRefPtr<nsMediaList> result = new nsMediaList();
568 if (!result || !result->mArray.AppendElements(mArray.Length()))
569 return NS_ERROR_OUT_OF_MEMORY;
570 for (PRInt32 i = 0, i_end = mArray.Length(); i < i_end; ++i) {
571 if (!(result->mArray[i] = mArray[i]->Clone())) {
572 return NS_ERROR_OUT_OF_MEMORY;
575 NS_ADDREF(*aResult = result);
576 return NS_OK;
579 NS_IMETHODIMP
580 nsMediaList::GetMediaText(nsAString& aMediaText)
582 return GetText(aMediaText);
585 // "sheet" should be an nsCSSStyleSheet and "doc" should be an
586 // nsCOMPtr<nsIDocument>
587 #define BEGIN_MEDIA_CHANGE(sheet, doc) \
588 if (sheet) { \
589 rv = sheet->GetOwningDocument(*getter_AddRefs(doc)); \
590 NS_ENSURE_SUCCESS(rv, rv); \
592 mozAutoDocUpdate updateBatch(doc, UPDATE_STYLE, PR_TRUE); \
593 if (sheet) { \
594 rv = sheet->WillDirty(); \
595 NS_ENSURE_SUCCESS(rv, rv); \
598 #define END_MEDIA_CHANGE(sheet, doc) \
599 if (sheet) { \
600 sheet->DidDirty(); \
602 /* XXXldb Pass something meaningful? */ \
603 if (doc) { \
604 doc->StyleRuleChanged(sheet, nsnull, nsnull); \
608 NS_IMETHODIMP
609 nsMediaList::SetMediaText(const nsAString& aMediaText)
611 nsresult rv = NS_OK;
612 nsCOMPtr<nsIDocument> doc;
614 BEGIN_MEDIA_CHANGE(mStyleSheet, doc)
616 rv = SetText(aMediaText);
617 if (NS_FAILED(rv))
618 return rv;
620 END_MEDIA_CHANGE(mStyleSheet, doc)
622 return rv;
625 NS_IMETHODIMP
626 nsMediaList::GetLength(PRUint32* aLength)
628 NS_ENSURE_ARG_POINTER(aLength);
630 *aLength = mArray.Length();
631 return NS_OK;
634 NS_IMETHODIMP
635 nsMediaList::Item(PRUint32 aIndex, nsAString& aReturn)
637 PRInt32 index = aIndex;
638 if (0 <= index && index < Count()) {
639 nsMediaQuery* query = mArray[index];
640 NS_ENSURE_TRUE(query, NS_ERROR_FAILURE);
642 aReturn.Truncate();
643 query->AppendToString(aReturn);
644 } else {
645 SetDOMStringToNull(aReturn);
648 return NS_OK;
651 NS_IMETHODIMP
652 nsMediaList::DeleteMedium(const nsAString& aOldMedium)
654 nsresult rv = NS_OK;
655 nsCOMPtr<nsIDocument> doc;
657 BEGIN_MEDIA_CHANGE(mStyleSheet, doc)
659 rv = Delete(aOldMedium);
660 if (NS_FAILED(rv))
661 return rv;
663 END_MEDIA_CHANGE(mStyleSheet, doc)
665 return rv;
668 NS_IMETHODIMP
669 nsMediaList::AppendMedium(const nsAString& aNewMedium)
671 nsresult rv = NS_OK;
672 nsCOMPtr<nsIDocument> doc;
674 BEGIN_MEDIA_CHANGE(mStyleSheet, doc)
676 rv = Append(aNewMedium);
677 if (NS_FAILED(rv))
678 return rv;
680 END_MEDIA_CHANGE(mStyleSheet, doc)
682 return rv;
685 nsresult
686 nsMediaList::Delete(const nsAString& aOldMedium)
688 if (aOldMedium.IsEmpty())
689 return NS_ERROR_DOM_NOT_FOUND_ERR;
691 for (PRInt32 i = 0, i_end = mArray.Length(); i < i_end; ++i) {
692 nsMediaQuery* query = mArray[i];
693 NS_ENSURE_TRUE(query, NS_ERROR_FAILURE);
695 nsAutoString buf;
696 query->AppendToString(buf);
697 if (buf == aOldMedium) {
698 mArray.RemoveElementAt(i);
699 return NS_OK;
703 return NS_ERROR_DOM_NOT_FOUND_ERR;
706 nsresult
707 nsMediaList::Append(const nsAString& aNewMedium)
709 if (aNewMedium.IsEmpty())
710 return NS_ERROR_DOM_NOT_FOUND_ERR;
712 Delete(aNewMedium);
714 nsresult rv = NS_OK;
715 nsTArray<nsAutoPtr<nsMediaQuery> > buf;
716 #ifdef DEBUG
717 PRBool ok =
718 #endif
719 mArray.SwapElements(buf);
720 NS_ASSERTION(ok, "SwapElements should never fail when neither array "
721 "is an auto array");
722 SetText(aNewMedium);
723 if (mArray.Length() == 1) {
724 nsMediaQuery *query = mArray[0].forget();
725 if (!buf.AppendElement(query)) {
726 delete query;
727 rv = NS_ERROR_OUT_OF_MEMORY;
730 #ifdef DEBUG
731 ok =
732 #endif
733 mArray.SwapElements(buf);
734 NS_ASSERTION(ok, "SwapElements should never fail when neither array "
735 "is an auto array");
736 return rv;
739 // -------------------------------
740 // Imports Collection for the DOM
742 class CSSImportsCollectionImpl : public nsIDOMStyleSheetList
744 public:
745 CSSImportsCollectionImpl(nsICSSStyleSheet *aStyleSheet);
747 NS_DECL_ISUPPORTS
749 // nsIDOMCSSStyleSheetList interface
750 NS_IMETHOD GetLength(PRUint32* aLength);
751 NS_IMETHOD Item(PRUint32 aIndex, nsIDOMStyleSheet** aReturn);
753 void DropReference() { mStyleSheet = nsnull; }
755 protected:
756 virtual ~CSSImportsCollectionImpl();
758 nsICSSStyleSheet* mStyleSheet;
761 CSSImportsCollectionImpl::CSSImportsCollectionImpl(nsICSSStyleSheet *aStyleSheet)
763 // Not reference counted to avoid circular references.
764 // The style sheet will tell us when its going away.
765 mStyleSheet = aStyleSheet;
768 CSSImportsCollectionImpl::~CSSImportsCollectionImpl()
773 // QueryInterface implementation for CSSImportsCollectionImpl
774 NS_INTERFACE_MAP_BEGIN(CSSImportsCollectionImpl)
775 NS_INTERFACE_MAP_ENTRY(nsIDOMStyleSheetList)
776 NS_INTERFACE_MAP_ENTRY(nsISupports)
777 NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(StyleSheetList)
778 NS_INTERFACE_MAP_END
781 NS_IMPL_ADDREF(CSSImportsCollectionImpl)
782 NS_IMPL_RELEASE(CSSImportsCollectionImpl)
785 NS_IMETHODIMP
786 CSSImportsCollectionImpl::GetLength(PRUint32* aLength)
788 if (nsnull != mStyleSheet) {
789 PRInt32 count;
790 mStyleSheet->StyleSheetCount(count);
791 *aLength = (PRUint32)count;
793 else {
794 *aLength = 0;
797 return NS_OK;
800 NS_IMETHODIMP
801 CSSImportsCollectionImpl::Item(PRUint32 aIndex, nsIDOMStyleSheet** aReturn)
803 nsresult result = NS_OK;
805 *aReturn = nsnull;
807 if (mStyleSheet) {
808 nsCOMPtr<nsICSSStyleSheet> sheet;
810 result = mStyleSheet->GetStyleSheetAt(aIndex, *getter_AddRefs(sheet));
811 if (NS_SUCCEEDED(result)) {
812 result = CallQueryInterface(sheet, aReturn);
816 return result;
819 // -------------------------------
820 // CSS Style Sheet Inner Data Container
824 static PRBool SetStyleSheetReference(nsICSSRule* aRule, void* aSheet)
826 if (aRule) {
827 aRule->SetStyleSheet((nsICSSStyleSheet*)aSheet);
829 return PR_TRUE;
832 nsCSSStyleSheetInner::nsCSSStyleSheetInner(nsICSSStyleSheet* aParentSheet)
833 : mSheets(),
834 mComplete(PR_FALSE)
835 #ifdef DEBUG
836 , mPrincipalSet(PR_FALSE)
837 #endif
839 MOZ_COUNT_CTOR(nsCSSStyleSheetInner);
840 mSheets.AppendElement(aParentSheet);
842 mPrincipal = do_CreateInstance("@mozilla.org/nullprincipal;1");
845 static PRBool
846 CloneRuleInto(nsICSSRule* aRule, void* aArray)
848 nsICSSRule* clone = nsnull;
849 aRule->Clone(clone);
850 if (clone) {
851 static_cast<nsCOMArray<nsICSSRule>*>(aArray)->AppendObject(clone);
852 NS_RELEASE(clone);
854 return PR_TRUE;
857 nsCSSStyleSheetInner::nsCSSStyleSheetInner(nsCSSStyleSheetInner& aCopy,
858 nsICSSStyleSheet* aParentSheet)
859 : mSheets(),
860 mSheetURI(aCopy.mSheetURI),
861 mOriginalSheetURI(aCopy.mOriginalSheetURI),
862 mBaseURI(aCopy.mBaseURI),
863 mPrincipal(aCopy.mPrincipal),
864 mComplete(aCopy.mComplete)
865 #ifdef DEBUG
866 , mPrincipalSet(aCopy.mPrincipalSet)
867 #endif
869 MOZ_COUNT_CTOR(nsCSSStyleSheetInner);
870 mSheets.AppendElement(aParentSheet);
871 aCopy.mOrderedRules.EnumerateForwards(CloneRuleInto, &mOrderedRules);
872 mOrderedRules.EnumerateForwards(SetStyleSheetReference, aParentSheet);
873 RebuildNameSpaces();
876 nsCSSStyleSheetInner::~nsCSSStyleSheetInner()
878 MOZ_COUNT_DTOR(nsCSSStyleSheetInner);
879 mOrderedRules.EnumerateForwards(SetStyleSheetReference, nsnull);
882 nsCSSStyleSheetInner*
883 nsCSSStyleSheetInner::CloneFor(nsICSSStyleSheet* aParentSheet)
885 return new nsCSSStyleSheetInner(*this, aParentSheet);
888 void
889 nsCSSStyleSheetInner::AddSheet(nsICSSStyleSheet* aParentSheet)
891 mSheets.AppendElement(aParentSheet);
894 void
895 nsCSSStyleSheetInner::RemoveSheet(nsICSSStyleSheet* aParentSheet)
897 if (1 == mSheets.Count()) {
898 NS_ASSERTION(aParentSheet == (nsICSSStyleSheet*)mSheets.ElementAt(0), "bad parent");
899 delete this;
900 return;
902 if (aParentSheet == (nsICSSStyleSheet*)mSheets.ElementAt(0)) {
903 mSheets.RemoveElementAt(0);
904 NS_ASSERTION(mSheets.Count(), "no parents");
905 mOrderedRules.EnumerateForwards(SetStyleSheetReference,
906 (nsICSSStyleSheet*)mSheets.ElementAt(0));
908 else {
909 mSheets.RemoveElement(aParentSheet);
913 static PRBool
914 CreateNameSpace(nsICSSRule* aRule, void* aNameSpacePtr)
916 PRInt32 type = nsICSSRule::UNKNOWN_RULE;
917 aRule->GetType(type);
918 if (nsICSSRule::NAMESPACE_RULE == type) {
919 nsICSSNameSpaceRule* nameSpaceRule = (nsICSSNameSpaceRule*)aRule;
920 nsXMLNameSpaceMap *nameSpaceMap =
921 static_cast<nsXMLNameSpaceMap*>(aNameSpacePtr);
923 nsIAtom* prefix = nsnull;
924 nsAutoString urlSpec;
925 nameSpaceRule->GetPrefix(prefix);
926 nameSpaceRule->GetURLSpec(urlSpec);
928 nameSpaceMap->AddPrefix(prefix, urlSpec);
929 return PR_TRUE;
931 // stop if not namespace, import or charset because namespace can't follow anything else
932 return (((nsICSSRule::CHARSET_RULE == type) ||
933 (nsICSSRule::IMPORT_RULE)) ? PR_TRUE : PR_FALSE);
936 void
937 nsCSSStyleSheetInner::RebuildNameSpaces()
939 if (mNameSpaceMap) {
940 mNameSpaceMap->Clear();
941 } else {
942 mNameSpaceMap = nsXMLNameSpaceMap::Create();
943 if (!mNameSpaceMap) {
944 return; // out of memory
948 mOrderedRules.EnumerateForwards(CreateNameSpace, mNameSpaceMap);
952 // -------------------------------
953 // CSS Style Sheet
956 nsCSSStyleSheet::nsCSSStyleSheet()
957 : nsICSSStyleSheet(),
958 mRefCnt(0),
959 mTitle(),
960 mMedia(nsnull),
961 mFirstChild(nsnull),
962 mNext(nsnull),
963 mParent(nsnull),
964 mOwnerRule(nsnull),
965 mImportsCollection(nsnull),
966 mRuleCollection(nsnull),
967 mDocument(nsnull),
968 mOwningNode(nsnull),
969 mDisabled(PR_FALSE),
970 mDirty(PR_FALSE),
971 mRuleProcessors(nsnull)
974 mInner = new nsCSSStyleSheetInner(this);
977 nsCSSStyleSheet::nsCSSStyleSheet(const nsCSSStyleSheet& aCopy,
978 nsICSSStyleSheet* aParentToUse,
979 nsICSSImportRule* aOwnerRuleToUse,
980 nsIDocument* aDocumentToUse,
981 nsIDOMNode* aOwningNodeToUse)
982 : nsICSSStyleSheet(),
983 mRefCnt(0),
984 mTitle(aCopy.mTitle),
985 mMedia(nsnull),
986 mFirstChild(nsnull),
987 mNext(nsnull),
988 mParent(aParentToUse),
989 mOwnerRule(aOwnerRuleToUse),
990 mImportsCollection(nsnull), // re-created lazily
991 mRuleCollection(nsnull), // re-created lazily
992 mDocument(aDocumentToUse),
993 mOwningNode(aOwningNodeToUse),
994 mDisabled(aCopy.mDisabled),
995 mDirty(PR_FALSE),
996 mInner(aCopy.mInner),
997 mRuleProcessors(nsnull)
1000 mInner->AddSheet(this);
1002 if (aCopy.mRuleCollection &&
1003 aCopy.mRuleCollection->mRulesAccessed) { // CSSOM's been there, force full copy now
1004 NS_ASSERTION(mInner->mComplete, "Why have rules been accessed on an incomplete sheet?");
1005 EnsureUniqueInner();
1008 if (aCopy.mMedia) {
1009 aCopy.mMedia->Clone(getter_AddRefs(mMedia));
1012 if (aCopy.mFirstChild) {
1013 nsCSSStyleSheet* otherChild = aCopy.mFirstChild;
1014 nsCSSStyleSheet** ourSlot = &mFirstChild;
1015 do {
1016 // XXX This is wrong; we should be keeping @import rules and
1017 // sheets in sync!
1018 nsCSSStyleSheet* child = new nsCSSStyleSheet(*otherChild,
1019 this,
1020 nsnull,
1021 aDocumentToUse,
1022 nsnull);
1023 if (child) {
1024 NS_ADDREF(child);
1025 (*ourSlot) = child;
1026 ourSlot = &(child->mNext);
1028 otherChild = otherChild->mNext;
1030 while (otherChild && ourSlot);
1034 nsCSSStyleSheet::~nsCSSStyleSheet()
1036 if (mFirstChild) {
1037 nsCSSStyleSheet* child = mFirstChild;
1038 do {
1039 child->mParent = nsnull;
1040 child->mDocument = nsnull;
1041 child = child->mNext;
1042 } while (child);
1043 NS_RELEASE(mFirstChild);
1045 NS_IF_RELEASE(mNext);
1046 if (nsnull != mRuleCollection) {
1047 mRuleCollection->DropReference();
1048 NS_RELEASE(mRuleCollection);
1050 if (nsnull != mImportsCollection) {
1051 mImportsCollection->DropReference();
1052 NS_RELEASE(mImportsCollection);
1054 if (mMedia) {
1055 mMedia->SetStyleSheet(nsnull);
1056 mMedia = nsnull;
1058 mInner->RemoveSheet(this);
1059 // XXX The document reference is not reference counted and should
1060 // not be released. The document will let us know when it is going
1061 // away.
1062 if (mRuleProcessors) {
1063 NS_ASSERTION(mRuleProcessors->Count() == 0, "destructing sheet with rule processor reference");
1064 delete mRuleProcessors; // weak refs, should be empty here anyway
1069 // QueryInterface implementation for nsCSSStyleSheet
1070 NS_INTERFACE_MAP_BEGIN(nsCSSStyleSheet)
1071 NS_INTERFACE_MAP_ENTRY(nsICSSStyleSheet)
1072 NS_INTERFACE_MAP_ENTRY(nsIStyleSheet)
1073 NS_INTERFACE_MAP_ENTRY(nsIDOMStyleSheet)
1074 NS_INTERFACE_MAP_ENTRY(nsIDOMCSSStyleSheet)
1075 NS_INTERFACE_MAP_ENTRY(nsICSSLoaderObserver)
1076 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsICSSStyleSheet)
1077 NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(CSSStyleSheet)
1078 NS_INTERFACE_MAP_END
1081 NS_IMPL_ADDREF(nsCSSStyleSheet)
1082 NS_IMPL_RELEASE(nsCSSStyleSheet)
1085 NS_IMETHODIMP
1086 nsCSSStyleSheet::AddRuleProcessor(nsCSSRuleProcessor* aProcessor)
1088 if (! mRuleProcessors) {
1089 mRuleProcessors = new nsAutoVoidArray();
1090 if (!mRuleProcessors)
1091 return NS_ERROR_OUT_OF_MEMORY;
1093 NS_ASSERTION(-1 == mRuleProcessors->IndexOf(aProcessor),
1094 "processor already registered");
1095 mRuleProcessors->AppendElement(aProcessor); // weak ref
1096 return NS_OK;
1099 NS_IMETHODIMP
1100 nsCSSStyleSheet::DropRuleProcessor(nsCSSRuleProcessor* aProcessor)
1102 if (!mRuleProcessors)
1103 return NS_ERROR_FAILURE;
1104 return mRuleProcessors->RemoveElement(aProcessor)
1105 ? NS_OK
1106 : NS_ERROR_FAILURE;
1110 NS_IMETHODIMP
1111 nsCSSStyleSheet::SetURIs(nsIURI* aSheetURI, nsIURI* aOriginalSheetURI,
1112 nsIURI* aBaseURI)
1114 NS_PRECONDITION(aSheetURI && aBaseURI, "null ptr");
1116 NS_ASSERTION(mInner->mOrderedRules.Count() == 0 && !mInner->mComplete,
1117 "Can't call SetURL on sheets that are complete or have rules");
1119 mInner->mSheetURI = aSheetURI;
1120 mInner->mOriginalSheetURI = aOriginalSheetURI;
1121 mInner->mBaseURI = aBaseURI;
1122 return NS_OK;
1125 void
1126 nsCSSStyleSheet::SetPrincipal(nsIPrincipal* aPrincipal)
1128 NS_PRECONDITION(!mInner->mPrincipalSet,
1129 "Should have an inner whose principal has not yet been set");
1130 if (aPrincipal) {
1131 mInner->mPrincipal = aPrincipal;
1132 #ifdef DEBUG
1133 mInner->mPrincipalSet = PR_TRUE;
1134 #endif
1138 nsIPrincipal*
1139 nsCSSStyleSheet::Principal() const
1141 return mInner->mPrincipal;
1144 NS_IMETHODIMP
1145 nsCSSStyleSheet::GetSheetURI(nsIURI** aSheetURI) const
1147 NS_IF_ADDREF(*aSheetURI = mInner->mSheetURI.get());
1148 return NS_OK;
1151 NS_IMETHODIMP
1152 nsCSSStyleSheet::GetBaseURI(nsIURI** aBaseURI) const
1154 NS_IF_ADDREF(*aBaseURI = mInner->mBaseURI.get());
1155 return NS_OK;
1158 NS_IMETHODIMP
1159 nsCSSStyleSheet::SetTitle(const nsAString& aTitle)
1161 mTitle = aTitle;
1162 return NS_OK;
1165 NS_IMETHODIMP
1166 nsCSSStyleSheet::GetType(nsString& aType) const
1168 aType.AssignLiteral("text/css");
1169 return NS_OK;
1172 PRBool
1173 nsCSSStyleSheet::UseForPresentation(nsPresContext* aPresContext,
1174 nsMediaQueryResultCacheKey& aKey) const
1176 if (mMedia) {
1177 return mMedia->Matches(aPresContext, aKey);
1179 return PR_TRUE;
1183 NS_IMETHODIMP
1184 nsCSSStyleSheet::SetMedia(nsMediaList* aMedia)
1186 mMedia = aMedia;
1187 return NS_OK;
1190 NS_IMETHODIMP_(PRBool)
1191 nsCSSStyleSheet::HasRules() const
1193 PRInt32 count;
1194 StyleRuleCount(count);
1195 return count != 0;
1198 NS_IMETHODIMP
1199 nsCSSStyleSheet::GetApplicable(PRBool& aApplicable) const
1201 aApplicable = !mDisabled && mInner->mComplete;
1202 return NS_OK;
1205 NS_IMETHODIMP
1206 nsCSSStyleSheet::SetEnabled(PRBool aEnabled)
1208 // Internal method, so callers must handle BeginUpdate/EndUpdate
1209 PRBool oldDisabled = mDisabled;
1210 mDisabled = !aEnabled;
1212 if (mDocument && mInner->mComplete && oldDisabled != mDisabled) {
1213 ClearRuleCascades();
1215 mDocument->SetStyleSheetApplicableState(this, !mDisabled);
1218 return NS_OK;
1221 NS_IMETHODIMP
1222 nsCSSStyleSheet::GetComplete(PRBool& aComplete) const
1224 aComplete = mInner->mComplete;
1225 return NS_OK;
1228 NS_IMETHODIMP
1229 nsCSSStyleSheet::SetComplete()
1231 NS_ASSERTION(!mDirty, "Can't set a dirty sheet complete!");
1232 mInner->mComplete = PR_TRUE;
1233 if (mDocument && !mDisabled) {
1234 // Let the document know
1235 mDocument->BeginUpdate(UPDATE_STYLE);
1236 mDocument->SetStyleSheetApplicableState(this, PR_TRUE);
1237 mDocument->EndUpdate(UPDATE_STYLE);
1239 return NS_OK;
1242 NS_IMETHODIMP
1243 nsCSSStyleSheet::GetParentSheet(nsIStyleSheet*& aParent) const
1245 aParent = mParent;
1246 NS_IF_ADDREF(aParent);
1247 return NS_OK;
1250 NS_IMETHODIMP
1251 nsCSSStyleSheet::GetOwningDocument(nsIDocument*& aDocument) const
1253 aDocument = mDocument;
1254 NS_IF_ADDREF(aDocument);
1255 return NS_OK;
1258 NS_IMETHODIMP
1259 nsCSSStyleSheet::SetOwningDocument(nsIDocument* aDocument)
1260 { // not ref counted
1261 mDocument = aDocument;
1262 // Now set the same document on all our child sheets....
1263 for (nsCSSStyleSheet* child = mFirstChild; child; child = child->mNext) {
1264 child->SetOwningDocument(aDocument);
1266 return NS_OK;
1269 NS_IMETHODIMP
1270 nsCSSStyleSheet::SetOwningNode(nsIDOMNode* aOwningNode)
1271 { // not ref counted
1272 mOwningNode = aOwningNode;
1273 return NS_OK;
1276 NS_IMETHODIMP
1277 nsCSSStyleSheet::SetOwnerRule(nsICSSImportRule* aOwnerRule)
1278 { // not ref counted
1279 mOwnerRule = aOwnerRule;
1280 return NS_OK;
1283 NS_IMETHODIMP
1284 nsCSSStyleSheet::GetOwnerRule(nsICSSImportRule** aOwnerRule)
1286 *aOwnerRule = mOwnerRule;
1287 NS_IF_ADDREF(*aOwnerRule);
1288 return NS_OK;
1291 NS_IMETHODIMP
1292 nsCSSStyleSheet::ContainsStyleSheet(nsIURI* aURL, PRBool& aContains, nsIStyleSheet** aTheChild /*=nsnull*/)
1294 NS_PRECONDITION(nsnull != aURL, "null arg");
1296 if (!mInner->mSheetURI) {
1297 // We're not yet far enough along in our load to know what our URL is (we
1298 // may still get redirected and such). Assert (caller should really not be
1299 // calling this on us at this stage) and return.
1300 NS_ERROR("ContainsStyleSheet called on a sheet that's still loading");
1301 aContains = PR_FALSE;
1302 return NS_OK;
1305 // first check ourself out
1306 nsresult rv = mInner->mSheetURI->Equals(aURL, &aContains);
1307 if (NS_FAILED(rv)) aContains = PR_FALSE;
1309 if (aContains) {
1310 // if we found it and the out-param is there, set it and addref
1311 if (aTheChild) {
1312 rv = QueryInterface( NS_GET_IID(nsIStyleSheet), (void **)aTheChild);
1314 } else {
1315 nsCSSStyleSheet* child = mFirstChild;
1316 // now check the chil'ins out (recursively)
1317 while ((PR_FALSE == aContains) && (nsnull != child)) {
1318 child->ContainsStyleSheet(aURL, aContains, aTheChild);
1319 if (aContains) {
1320 break;
1321 } else {
1322 child = child->mNext;
1327 // NOTE: if there are errors in the above we are handling them locally
1328 // and not promoting them to the caller
1329 return NS_OK;
1332 NS_IMETHODIMP
1333 nsCSSStyleSheet::AppendStyleSheet(nsICSSStyleSheet* aSheet)
1335 NS_PRECONDITION(nsnull != aSheet, "null arg");
1337 if (NS_SUCCEEDED(WillDirty())) {
1338 NS_ADDREF(aSheet);
1339 nsCSSStyleSheet* sheet = (nsCSSStyleSheet*)aSheet;
1341 if (! mFirstChild) {
1342 mFirstChild = sheet;
1344 else {
1345 nsCSSStyleSheet* child = mFirstChild;
1346 while (child->mNext) {
1347 child = child->mNext;
1349 child->mNext = sheet;
1352 // This is not reference counted. Our parent tells us when
1353 // it's going away.
1354 sheet->mParent = this;
1355 sheet->mDocument = mDocument;
1356 DidDirty();
1358 return NS_OK;
1361 NS_IMETHODIMP
1362 nsCSSStyleSheet::InsertStyleSheetAt(nsICSSStyleSheet* aSheet, PRInt32 aIndex)
1364 NS_PRECONDITION(nsnull != aSheet, "null arg");
1366 nsresult result = WillDirty();
1368 if (NS_SUCCEEDED(result)) {
1369 NS_ADDREF(aSheet);
1370 nsCSSStyleSheet* sheet = (nsCSSStyleSheet*)aSheet;
1371 nsCSSStyleSheet* child = mFirstChild;
1373 if (aIndex && child) {
1374 while ((0 < --aIndex) && child->mNext) {
1375 child = child->mNext;
1377 sheet->mNext = child->mNext;
1378 child->mNext = sheet;
1380 else {
1381 sheet->mNext = mFirstChild;
1382 mFirstChild = sheet;
1385 // This is not reference counted. Our parent tells us when
1386 // it's going away.
1387 sheet->mParent = this;
1388 sheet->mDocument = mDocument;
1389 DidDirty();
1391 return result;
1394 NS_IMETHODIMP
1395 nsCSSStyleSheet::PrependStyleRule(nsICSSRule* aRule)
1397 NS_PRECONDITION(nsnull != aRule, "null arg");
1399 if (NS_SUCCEEDED(WillDirty())) {
1400 mInner->mOrderedRules.InsertObjectAt(aRule, 0);
1401 aRule->SetStyleSheet(this);
1402 DidDirty();
1404 PRInt32 type = nsICSSRule::UNKNOWN_RULE;
1405 aRule->GetType(type);
1406 if (nsICSSRule::NAMESPACE_RULE == type) {
1407 // no api to prepend a namespace (ugh), release old ones and re-create them all
1408 mInner->RebuildNameSpaces();
1411 return NS_OK;
1414 NS_IMETHODIMP
1415 nsCSSStyleSheet::AppendStyleRule(nsICSSRule* aRule)
1417 NS_PRECONDITION(nsnull != aRule, "null arg");
1419 if (NS_SUCCEEDED(WillDirty())) {
1420 mInner->mOrderedRules.AppendObject(aRule);
1421 aRule->SetStyleSheet(this);
1422 DidDirty();
1424 PRInt32 type = nsICSSRule::UNKNOWN_RULE;
1425 aRule->GetType(type);
1426 if (nsICSSRule::NAMESPACE_RULE == type) {
1427 if (!mInner->mNameSpaceMap) {
1428 mInner->mNameSpaceMap = nsXMLNameSpaceMap::Create();
1429 NS_ENSURE_TRUE(mInner->mNameSpaceMap, NS_ERROR_OUT_OF_MEMORY);
1432 nsCOMPtr<nsICSSNameSpaceRule> nameSpaceRule(do_QueryInterface(aRule));
1434 nsCOMPtr<nsIAtom> prefix;
1435 nsAutoString urlSpec;
1436 nameSpaceRule->GetPrefix(*getter_AddRefs(prefix));
1437 nameSpaceRule->GetURLSpec(urlSpec);
1439 mInner->mNameSpaceMap->AddPrefix(prefix, urlSpec);
1442 return NS_OK;
1445 NS_IMETHODIMP
1446 nsCSSStyleSheet::ReplaceStyleRule(nsICSSRule* aOld, nsICSSRule* aNew)
1448 NS_PRECONDITION(mInner->mOrderedRules.Count() != 0, "can't have old rule");
1449 NS_PRECONDITION(mInner->mComplete, "No replacing in an incomplete sheet!");
1451 if (NS_SUCCEEDED(WillDirty())) {
1452 PRInt32 index = mInner->mOrderedRules.IndexOf(aOld);
1453 NS_ENSURE_TRUE(index != -1, NS_ERROR_UNEXPECTED);
1454 mInner->mOrderedRules.ReplaceObjectAt(aNew, index);
1456 aNew->SetStyleSheet(this);
1457 aOld->SetStyleSheet(nsnull);
1458 DidDirty();
1459 #ifdef DEBUG
1460 PRInt32 type = nsICSSRule::UNKNOWN_RULE;
1461 aNew->GetType(type);
1462 NS_ASSERTION(nsICSSRule::NAMESPACE_RULE != type, "not yet implemented");
1463 aOld->GetType(type);
1464 NS_ASSERTION(nsICSSRule::NAMESPACE_RULE != type, "not yet implemented");
1465 #endif
1467 return NS_OK;
1470 NS_IMETHODIMP
1471 nsCSSStyleSheet::StyleRuleCount(PRInt32& aCount) const
1473 aCount = mInner->mOrderedRules.Count();
1474 return NS_OK;
1477 NS_IMETHODIMP
1478 nsCSSStyleSheet::GetStyleRuleAt(PRInt32 aIndex, nsICSSRule*& aRule) const
1480 // Important: If this function is ever made scriptable, we must add
1481 // a security check here. See GetCssRules below for an example.
1482 aRule = mInner->mOrderedRules.SafeObjectAt(aIndex);
1483 if (aRule) {
1484 NS_ADDREF(aRule);
1485 return NS_OK;
1488 return NS_ERROR_ILLEGAL_VALUE;
1491 nsXMLNameSpaceMap*
1492 nsCSSStyleSheet::GetNameSpaceMap() const
1494 return mInner->mNameSpaceMap;
1497 NS_IMETHODIMP
1498 nsCSSStyleSheet::StyleSheetCount(PRInt32& aCount) const
1500 // XXX Far from an ideal way to do this, but the hope is that
1501 // it won't be done too often. If it is, we might want to
1502 // consider storing the children in an array.
1503 aCount = 0;
1505 const nsCSSStyleSheet* child = mFirstChild;
1506 while (child) {
1507 aCount++;
1508 child = child->mNext;
1511 return NS_OK;
1514 NS_IMETHODIMP
1515 nsCSSStyleSheet::GetStyleSheetAt(PRInt32 aIndex, nsICSSStyleSheet*& aSheet) const
1517 // XXX Ughh...an O(n^2) method for doing iteration. Again, we hope
1518 // that this isn't done too often. If it is, we need to change the
1519 // underlying storage mechanism
1520 aSheet = nsnull;
1522 if (mFirstChild) {
1523 const nsCSSStyleSheet* child = mFirstChild;
1524 while ((child) && (0 != aIndex)) {
1525 --aIndex;
1526 child = child->mNext;
1529 aSheet = (nsICSSStyleSheet*)child;
1530 NS_IF_ADDREF(aSheet);
1533 return NS_OK;
1536 nsresult
1537 nsCSSStyleSheet::EnsureUniqueInner()
1539 if (1 < mInner->mSheets.Count()) {
1540 nsCSSStyleSheetInner* clone = mInner->CloneFor(this);
1541 if (clone) {
1542 mInner->RemoveSheet(this);
1543 mInner = clone;
1545 else {
1546 return NS_ERROR_OUT_OF_MEMORY;
1549 return NS_OK;
1552 NS_IMETHODIMP
1553 nsCSSStyleSheet::Clone(nsICSSStyleSheet* aCloneParent,
1554 nsICSSImportRule* aCloneOwnerRule,
1555 nsIDocument* aCloneDocument,
1556 nsIDOMNode* aCloneOwningNode,
1557 nsICSSStyleSheet** aClone) const
1559 NS_PRECONDITION(aClone, "Null out param!");
1560 nsCSSStyleSheet* clone = new nsCSSStyleSheet(*this,
1561 aCloneParent,
1562 aCloneOwnerRule,
1563 aCloneDocument,
1564 aCloneOwningNode);
1565 if (clone) {
1566 *aClone = static_cast<nsICSSStyleSheet*>(clone);
1567 NS_ADDREF(*aClone);
1569 return NS_OK;
1572 #ifdef DEBUG
1573 static void
1574 ListRules(const nsCOMArray<nsICSSRule>& aRules, FILE* aOut, PRInt32 aIndent)
1576 for (PRInt32 index = aRules.Count() - 1; index >= 0; --index) {
1577 aRules.ObjectAt(index)->List(aOut, aIndent);
1581 struct ListEnumData {
1582 ListEnumData(FILE* aOut, PRInt32 aIndent)
1583 : mOut(aOut),
1584 mIndent(aIndent)
1587 FILE* mOut;
1588 PRInt32 mIndent;
1591 void nsCSSStyleSheet::List(FILE* out, PRInt32 aIndent) const
1594 PRInt32 index;
1596 // Indent
1597 for (index = aIndent; --index >= 0; ) fputs(" ", out);
1599 fputs("CSS Style Sheet: ", out);
1600 nsCAutoString urlSpec;
1601 nsresult rv = mInner->mSheetURI->GetSpec(urlSpec);
1602 if (NS_SUCCEEDED(rv) && !urlSpec.IsEmpty()) {
1603 fputs(urlSpec.get(), out);
1606 if (mMedia) {
1607 fputs(" media: ", out);
1608 nsAutoString buffer;
1609 mMedia->GetText(buffer);
1610 fputs(NS_ConvertUTF16toUTF8(buffer).get(), out);
1612 fputs("\n", out);
1614 const nsCSSStyleSheet* child = mFirstChild;
1615 while (nsnull != child) {
1616 child->List(out, aIndent + 1);
1617 child = child->mNext;
1620 fputs("Rules in source order:\n", out);
1621 ListRules(mInner->mOrderedRules, out, aIndent);
1623 #endif
1625 static PRBool PR_CALLBACK
1626 EnumClearRuleCascades(void* aProcessor, void* aData)
1628 nsCSSRuleProcessor* processor =
1629 static_cast<nsCSSRuleProcessor*>(aProcessor);
1630 processor->ClearRuleCascades();
1631 return PR_TRUE;
1634 void
1635 nsCSSStyleSheet::ClearRuleCascades()
1637 if (mRuleProcessors) {
1638 mRuleProcessors->EnumerateForwards(EnumClearRuleCascades, nsnull);
1640 if (mParent) {
1641 nsCSSStyleSheet* parent = (nsCSSStyleSheet*)mParent;
1642 parent->ClearRuleCascades();
1646 nsresult
1647 nsCSSStyleSheet::WillDirty()
1649 if (!mInner->mComplete) {
1650 // Do nothing
1651 return NS_OK;
1654 return EnsureUniqueInner();
1657 void
1658 nsCSSStyleSheet::DidDirty()
1660 ClearRuleCascades();
1661 mDirty = PR_TRUE;
1664 nsresult
1665 nsCSSStyleSheet::SubjectSubsumesInnerPrincipal() const
1667 // Get the security manager and do the subsumes check
1668 nsIScriptSecurityManager *securityManager =
1669 nsContentUtils::GetSecurityManager();
1671 nsCOMPtr<nsIPrincipal> subjectPrincipal;
1672 securityManager->GetSubjectPrincipal(getter_AddRefs(subjectPrincipal));
1674 if (!subjectPrincipal) {
1675 return NS_ERROR_DOM_SECURITY_ERR;
1678 PRBool subsumes;
1679 nsresult rv = subjectPrincipal->Subsumes(mInner->mPrincipal, &subsumes);
1680 NS_ENSURE_SUCCESS(rv, rv);
1682 if (subsumes) {
1683 return NS_OK;
1686 if (!nsContentUtils::IsCallerTrustedForWrite()) {
1687 return NS_ERROR_DOM_SECURITY_ERR;
1690 return NS_OK;
1693 NS_IMETHODIMP
1694 nsCSSStyleSheet::IsModified(PRBool* aSheetModified) const
1696 *aSheetModified = mDirty;
1697 return NS_OK;
1700 NS_IMETHODIMP
1701 nsCSSStyleSheet::SetModified(PRBool aModified)
1703 mDirty = aModified;
1704 return NS_OK;
1707 // nsIDOMStyleSheet interface
1708 NS_IMETHODIMP
1709 nsCSSStyleSheet::GetType(nsAString& aType)
1711 aType.AssignLiteral("text/css");
1712 return NS_OK;
1715 NS_IMETHODIMP
1716 nsCSSStyleSheet::GetDisabled(PRBool* aDisabled)
1718 *aDisabled = mDisabled;
1719 return NS_OK;
1722 NS_IMETHODIMP
1723 nsCSSStyleSheet::SetDisabled(PRBool aDisabled)
1725 // DOM method, so handle BeginUpdate/EndUpdate
1726 MOZ_AUTO_DOC_UPDATE(mDocument, UPDATE_STYLE, PR_TRUE);
1727 nsresult rv = nsCSSStyleSheet::SetEnabled(!aDisabled);
1728 return rv;
1731 NS_IMETHODIMP
1732 nsCSSStyleSheet::GetOwnerNode(nsIDOMNode** aOwnerNode)
1734 *aOwnerNode = mOwningNode;
1735 NS_IF_ADDREF(*aOwnerNode);
1736 return NS_OK;
1739 NS_IMETHODIMP
1740 nsCSSStyleSheet::GetParentStyleSheet(nsIDOMStyleSheet** aParentStyleSheet)
1742 NS_ENSURE_ARG_POINTER(aParentStyleSheet);
1744 nsresult rv = NS_OK;
1746 if (mParent) {
1747 rv = mParent->QueryInterface(NS_GET_IID(nsIDOMStyleSheet),
1748 (void **)aParentStyleSheet);
1749 } else {
1750 *aParentStyleSheet = nsnull;
1753 return rv;
1756 NS_IMETHODIMP
1757 nsCSSStyleSheet::GetHref(nsAString& aHref)
1759 if (mInner->mOriginalSheetURI) {
1760 nsCAutoString str;
1761 mInner->mOriginalSheetURI->GetSpec(str);
1762 CopyUTF8toUTF16(str, aHref);
1763 } else {
1764 SetDOMStringToNull(aHref);
1767 return NS_OK;
1770 NS_IMETHODIMP
1771 nsCSSStyleSheet::GetTitle(nsString& aTitle) const
1773 aTitle = mTitle;
1774 return NS_OK;
1777 NS_IMETHODIMP
1778 nsCSSStyleSheet::GetTitle(nsAString& aTitle)
1780 aTitle.Assign(mTitle);
1781 return NS_OK;
1784 NS_IMETHODIMP
1785 nsCSSStyleSheet::GetMedia(nsIDOMMediaList** aMedia)
1787 NS_ENSURE_ARG_POINTER(aMedia);
1788 *aMedia = nsnull;
1790 if (!mMedia) {
1791 mMedia = new nsMediaList();
1792 NS_ENSURE_TRUE(mMedia, NS_ERROR_OUT_OF_MEMORY);
1793 mMedia->SetStyleSheet(this);
1796 *aMedia = mMedia;
1797 NS_ADDREF(*aMedia);
1799 return NS_OK;
1802 NS_IMETHODIMP
1803 nsCSSStyleSheet::GetOwnerRule(nsIDOMCSSRule** aOwnerRule)
1805 if (mOwnerRule) {
1806 return mOwnerRule->GetDOMRule(aOwnerRule);
1809 *aOwnerRule = nsnull;
1810 return NS_OK;
1813 NS_IMETHODIMP
1814 nsCSSStyleSheet::GetCssRules(nsIDOMCSSRuleList** aCssRules)
1816 // No doing this on incomplete sheets!
1817 PRBool complete;
1818 GetComplete(complete);
1819 if (!complete) {
1820 return NS_ERROR_DOM_INVALID_ACCESS_ERR;
1823 //-- Security check: Only scripts whose principal subsumes that of the
1824 // style sheet can access rule collections.
1825 nsresult rv = SubjectSubsumesInnerPrincipal();
1826 NS_ENSURE_SUCCESS(rv, rv);
1828 // OK, security check passed, so get the rule collection
1829 if (nsnull == mRuleCollection) {
1830 mRuleCollection = new CSSRuleListImpl(this);
1831 if (nsnull == mRuleCollection) {
1832 return NS_ERROR_OUT_OF_MEMORY;
1834 NS_ADDREF(mRuleCollection);
1837 *aCssRules = mRuleCollection;
1838 NS_ADDREF(mRuleCollection);
1840 return NS_OK;
1843 NS_IMETHODIMP
1844 nsCSSStyleSheet::InsertRule(const nsAString& aRule,
1845 PRUint32 aIndex,
1846 PRUint32* aReturn)
1848 //-- Security check: Only scripts whose principal subsumes that of the
1849 // style sheet can modify rule collections.
1850 nsresult rv = SubjectSubsumesInnerPrincipal();
1851 NS_ENSURE_SUCCESS(rv, rv);
1853 return InsertRuleInternal(aRule, aIndex, aReturn);
1856 NS_IMETHODIMP
1857 nsCSSStyleSheet::InsertRuleInternal(const nsAString& aRule,
1858 PRUint32 aIndex,
1859 PRUint32* aReturn)
1861 // No doing this if the sheet is not complete!
1862 PRBool complete;
1863 GetComplete(complete);
1864 if (!complete) {
1865 return NS_ERROR_DOM_INVALID_ACCESS_ERR;
1868 if (aRule.IsEmpty()) {
1869 // Nothing to do here
1870 return NS_OK;
1873 nsresult result;
1874 result = WillDirty();
1875 if (NS_FAILED(result))
1876 return result;
1878 if (aIndex > PRUint32(mInner->mOrderedRules.Count()))
1879 return NS_ERROR_DOM_INDEX_SIZE_ERR;
1881 NS_ASSERTION(PRUint32(mInner->mOrderedRules.Count()) <= PR_INT32_MAX,
1882 "Too many style rules!");
1884 // Hold strong ref to the CSSLoader in case the document update
1885 // kills the document
1886 nsCOMPtr<nsICSSLoader> loader;
1887 if (mDocument) {
1888 loader = mDocument->CSSLoader();
1889 NS_ASSERTION(loader, "Document with no CSS loader!");
1892 nsCOMPtr<nsICSSParser> css;
1893 if (loader) {
1894 result = loader->GetParserFor(this, getter_AddRefs(css));
1896 else {
1897 result = NS_NewCSSParser(getter_AddRefs(css));
1898 if (css) {
1899 css->SetStyleSheet(this);
1902 if (NS_FAILED(result))
1903 return result;
1905 mozAutoDocUpdate updateBatch(mDocument, UPDATE_STYLE, PR_TRUE);
1907 nsCOMArray<nsICSSRule> rules;
1908 result = css->ParseRule(aRule, mInner->mSheetURI, mInner->mBaseURI,
1909 mInner->mPrincipal, rules);
1910 if (NS_FAILED(result))
1911 return result;
1913 PRInt32 rulecount = rules.Count();
1914 if (rulecount == 0) {
1915 // Since we know aRule was not an empty string, just throw
1916 return NS_ERROR_DOM_SYNTAX_ERR;
1919 // Hierarchy checking. Just check the first and last rule in the list.
1921 // check that we're not inserting before a charset rule
1922 PRInt32 nextType = nsICSSRule::UNKNOWN_RULE;
1923 nsICSSRule* nextRule = mInner->mOrderedRules.SafeObjectAt(aIndex);
1924 if (nextRule) {
1925 nextRule->GetType(nextType);
1926 if (nextType == nsICSSRule::CHARSET_RULE) {
1927 return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
1930 // check last rule in list
1931 nsICSSRule* lastRule = rules.ObjectAt(rulecount - 1);
1932 PRInt32 lastType = nsICSSRule::UNKNOWN_RULE;
1933 lastRule->GetType(lastType);
1935 if (nextType == nsICSSRule::IMPORT_RULE &&
1936 lastType != nsICSSRule::CHARSET_RULE &&
1937 lastType != nsICSSRule::IMPORT_RULE) {
1938 return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
1941 if (nextType == nsICSSRule::NAMESPACE_RULE &&
1942 lastType != nsICSSRule::CHARSET_RULE &&
1943 lastType != nsICSSRule::IMPORT_RULE &&
1944 lastType != nsICSSRule::NAMESPACE_RULE) {
1945 return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
1949 // check first rule in list
1950 nsICSSRule* firstRule = rules.ObjectAt(0);
1951 PRInt32 firstType = nsICSSRule::UNKNOWN_RULE;
1952 firstRule->GetType(firstType);
1953 if (aIndex != 0) {
1954 if (firstType == nsICSSRule::CHARSET_RULE) { // no inserting charset at nonzero position
1955 return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
1958 nsICSSRule* prevRule = mInner->mOrderedRules.SafeObjectAt(aIndex - 1);
1959 PRInt32 prevType = nsICSSRule::UNKNOWN_RULE;
1960 prevRule->GetType(prevType);
1962 if (firstType == nsICSSRule::IMPORT_RULE &&
1963 prevType != nsICSSRule::CHARSET_RULE &&
1964 prevType != nsICSSRule::IMPORT_RULE) {
1965 return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
1968 if (firstType == nsICSSRule::NAMESPACE_RULE &&
1969 prevType != nsICSSRule::CHARSET_RULE &&
1970 prevType != nsICSSRule::IMPORT_RULE &&
1971 prevType != nsICSSRule::NAMESPACE_RULE) {
1972 return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
1976 PRBool insertResult = mInner->mOrderedRules.InsertObjectsAt(rules, aIndex);
1977 NS_ENSURE_TRUE(insertResult, NS_ERROR_OUT_OF_MEMORY);
1978 DidDirty();
1980 for (PRInt32 counter = 0; counter < rulecount; counter++) {
1981 nsICSSRule* cssRule = rules.ObjectAt(counter);
1982 cssRule->SetStyleSheet(this);
1984 PRInt32 type = nsICSSRule::UNKNOWN_RULE;
1985 cssRule->GetType(type);
1986 if (type == nsICSSRule::NAMESPACE_RULE) {
1987 if (!mInner->mNameSpaceMap) {
1988 mInner->mNameSpaceMap = nsXMLNameSpaceMap::Create();
1989 NS_ENSURE_TRUE(mInner->mNameSpaceMap, NS_ERROR_OUT_OF_MEMORY);
1992 nsCOMPtr<nsICSSNameSpaceRule> nameSpaceRule(do_QueryInterface(cssRule));
1994 nsCOMPtr<nsIAtom> prefix;
1995 nsAutoString urlSpec;
1996 nameSpaceRule->GetPrefix(*getter_AddRefs(prefix));
1997 nameSpaceRule->GetURLSpec(urlSpec);
1999 mInner->mNameSpaceMap->AddPrefix(prefix, urlSpec);
2002 // We don't notify immediately for @import rules, but rather when
2003 // the sheet the rule is importing is loaded
2004 PRBool notify = PR_TRUE;
2005 if (type == nsICSSRule::IMPORT_RULE) {
2006 nsCOMPtr<nsIDOMCSSImportRule> importRule(do_QueryInterface(cssRule));
2007 NS_ASSERTION(importRule, "Rule which has type IMPORT_RULE and does not implement nsIDOMCSSImportRule!");
2008 nsCOMPtr<nsIDOMCSSStyleSheet> childSheet;
2009 importRule->GetStyleSheet(getter_AddRefs(childSheet));
2010 if (!childSheet) {
2011 notify = PR_FALSE;
2014 if (mDocument && notify) {
2015 mDocument->StyleRuleAdded(this, cssRule);
2019 if (loader) {
2020 loader->RecycleParser(css);
2023 *aReturn = aIndex;
2024 return NS_OK;
2027 NS_IMETHODIMP
2028 nsCSSStyleSheet::DeleteRule(PRUint32 aIndex)
2030 nsresult result = NS_ERROR_DOM_INDEX_SIZE_ERR;
2031 // No doing this if the sheet is not complete!
2032 PRBool complete;
2033 GetComplete(complete);
2034 if (!complete) {
2035 return NS_ERROR_DOM_INVALID_ACCESS_ERR;
2038 //-- Security check: Only scripts whose principal subsumes that of the
2039 // style sheet can modify rule collections.
2040 nsresult rv = SubjectSubsumesInnerPrincipal();
2041 NS_ENSURE_SUCCESS(rv, rv);
2043 // XXX TBI: handle @rule types
2044 mozAutoDocUpdate updateBatch(mDocument, UPDATE_STYLE, PR_TRUE);
2046 result = WillDirty();
2048 if (NS_SUCCEEDED(result)) {
2049 if (aIndex >= PRUint32(mInner->mOrderedRules.Count()))
2050 return NS_ERROR_DOM_INDEX_SIZE_ERR;
2052 NS_ASSERTION(PRUint32(mInner->mOrderedRules.Count()) <= PR_INT32_MAX,
2053 "Too many style rules!");
2055 // Hold a strong ref to the rule so it doesn't die when we RemoveObjectAt
2056 nsCOMPtr<nsICSSRule> rule = mInner->mOrderedRules.ObjectAt(aIndex);
2057 if (rule) {
2058 mInner->mOrderedRules.RemoveObjectAt(aIndex);
2059 rule->SetStyleSheet(nsnull);
2060 DidDirty();
2062 if (mDocument) {
2063 mDocument->StyleRuleRemoved(this, rule);
2068 return result;
2071 NS_IMETHODIMP
2072 nsCSSStyleSheet::DeleteRuleFromGroup(nsICSSGroupRule* aGroup, PRUint32 aIndex)
2074 NS_ENSURE_ARG_POINTER(aGroup);
2075 NS_ASSERTION(mInner->mComplete, "No deleting from an incomplete sheet!");
2076 nsresult result;
2077 nsCOMPtr<nsICSSRule> rule;
2078 result = aGroup->GetStyleRuleAt(aIndex, *getter_AddRefs(rule));
2079 NS_ENSURE_SUCCESS(result, result);
2081 // check that the rule actually belongs to this sheet!
2082 nsCOMPtr<nsIStyleSheet> ruleSheet;
2083 rule->GetStyleSheet(*getter_AddRefs(ruleSheet));
2084 if (this != ruleSheet) {
2085 return NS_ERROR_INVALID_ARG;
2088 mozAutoDocUpdate updateBatch(mDocument, UPDATE_STYLE, PR_TRUE);
2090 result = WillDirty();
2091 NS_ENSURE_SUCCESS(result, result);
2093 result = aGroup->DeleteStyleRuleAt(aIndex);
2094 NS_ENSURE_SUCCESS(result, result);
2096 rule->SetStyleSheet(nsnull);
2098 DidDirty();
2100 if (mDocument) {
2101 mDocument->StyleRuleRemoved(this, rule);
2104 return NS_OK;
2107 NS_IMETHODIMP
2108 nsCSSStyleSheet::InsertRuleIntoGroup(const nsAString & aRule,
2109 nsICSSGroupRule* aGroup,
2110 PRUint32 aIndex,
2111 PRUint32* _retval)
2113 nsresult result;
2114 NS_ASSERTION(mInner->mComplete, "No inserting into an incomplete sheet!");
2115 // check that the group actually belongs to this sheet!
2116 nsCOMPtr<nsIStyleSheet> groupSheet;
2117 aGroup->GetStyleSheet(*getter_AddRefs(groupSheet));
2118 if (this != groupSheet) {
2119 return NS_ERROR_INVALID_ARG;
2122 if (aRule.IsEmpty()) {
2123 // Nothing to do here
2124 return NS_OK;
2127 // Hold strong ref to the CSSLoader in case the document update
2128 // kills the document
2129 nsCOMPtr<nsICSSLoader> loader;
2130 if (mDocument) {
2131 loader = mDocument->CSSLoader();
2132 NS_ASSERTION(loader, "Document with no CSS loader!");
2135 nsCOMPtr<nsICSSParser> css;
2136 if (loader) {
2137 result = loader->GetParserFor(this, getter_AddRefs(css));
2139 else {
2140 result = NS_NewCSSParser(getter_AddRefs(css));
2141 if (css) {
2142 css->SetStyleSheet(this);
2145 NS_ENSURE_SUCCESS(result, result);
2147 // parse and grab the rule
2148 mozAutoDocUpdate updateBatch(mDocument, UPDATE_STYLE, PR_TRUE);
2150 result = WillDirty();
2151 NS_ENSURE_SUCCESS(result, result);
2153 nsCOMArray<nsICSSRule> rules;
2154 result = css->ParseRule(aRule, mInner->mSheetURI, mInner->mBaseURI,
2155 mInner->mPrincipal, rules);
2156 NS_ENSURE_SUCCESS(result, result);
2158 PRInt32 rulecount = rules.Count();
2159 if (rulecount == 0) {
2160 // Since we know aRule was not an empty string, just throw
2161 return NS_ERROR_DOM_SYNTAX_ERR;
2164 PRInt32 counter;
2165 nsICSSRule* rule;
2166 for (counter = 0; counter < rulecount; counter++) {
2167 // Only rulesets are allowed in a group as of CSS2
2168 PRInt32 type = nsICSSRule::UNKNOWN_RULE;
2169 rule = rules.ObjectAt(counter);
2170 rule->GetType(type);
2171 if (type != nsICSSRule::STYLE_RULE) {
2172 return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
2176 result = aGroup->InsertStyleRulesAt(aIndex, rules);
2177 NS_ENSURE_SUCCESS(result, result);
2178 DidDirty();
2179 for (counter = 0; counter < rulecount; counter++) {
2180 rule = rules.ObjectAt(counter);
2182 if (mDocument) {
2183 mDocument->StyleRuleAdded(this, rule);
2187 if (loader) {
2188 loader->RecycleParser(css);
2191 *_retval = aIndex;
2192 return NS_OK;
2195 NS_IMETHODIMP
2196 nsCSSStyleSheet::ReplaceRuleInGroup(nsICSSGroupRule* aGroup,
2197 nsICSSRule* aOld, nsICSSRule* aNew)
2199 nsresult result;
2200 NS_PRECONDITION(mInner->mComplete, "No replacing in an incomplete sheet!");
2201 #ifdef DEBUG
2203 nsCOMPtr<nsIStyleSheet> groupSheet;
2204 aGroup->GetStyleSheet(*getter_AddRefs(groupSheet));
2205 NS_ASSERTION(this == groupSheet, "group doesn't belong to this sheet");
2207 #endif
2208 result = WillDirty();
2209 NS_ENSURE_SUCCESS(result, result);
2211 result = aGroup->ReplaceStyleRule(aOld, aNew);
2212 DidDirty();
2213 return result;
2216 // nsICSSLoaderObserver implementation
2217 NS_IMETHODIMP
2218 nsCSSStyleSheet::StyleSheetLoaded(nsICSSStyleSheet* aSheet,
2219 PRBool aWasAlternate,
2220 nsresult aStatus)
2222 #ifdef DEBUG
2223 nsCOMPtr<nsIStyleSheet> styleSheet(do_QueryInterface(aSheet));
2224 NS_ASSERTION(styleSheet, "Sheet not implementing nsIStyleSheet!\n");
2225 nsCOMPtr<nsIStyleSheet> parentSheet;
2226 aSheet->GetParentSheet(*getter_AddRefs(parentSheet));
2227 nsCOMPtr<nsIStyleSheet> thisSheet;
2228 QueryInterface(NS_GET_IID(nsIStyleSheet), getter_AddRefs(thisSheet));
2229 NS_ASSERTION(thisSheet == parentSheet, "We are being notified of a sheet load for a sheet that is not our child!\n");
2230 #endif
2232 if (mDocument && NS_SUCCEEDED(aStatus)) {
2233 nsCOMPtr<nsICSSImportRule> ownerRule;
2234 aSheet->GetOwnerRule(getter_AddRefs(ownerRule));
2236 mozAutoDocUpdate updateBatch(mDocument, UPDATE_STYLE, PR_TRUE);
2238 // XXXldb @import rules shouldn't even implement nsIStyleRule (but
2239 // they do)!
2240 nsCOMPtr<nsIStyleRule> styleRule(do_QueryInterface(ownerRule));
2242 mDocument->StyleRuleAdded(this, styleRule);
2245 return NS_OK;
2248 nsresult
2249 NS_NewCSSStyleSheet(nsICSSStyleSheet** aInstancePtrResult)
2251 *aInstancePtrResult = nsnull;
2252 nsCSSStyleSheet *it = new nsCSSStyleSheet();
2254 if (!it) {
2255 return NS_ERROR_OUT_OF_MEMORY;
2258 NS_ADDREF(it);
2260 if (!it->mInner || !it->mInner->mPrincipal) {
2261 NS_RELEASE(it);
2262 return NS_ERROR_OUT_OF_MEMORY;
2265 *aInstancePtrResult = it;
2266 return NS_OK;