URI the sheet was loaded from, its certificate (if any) and the loader principal, not just on the page the sheet is being applied to. Propagate this principal as the loading principal to @import loads from stylesheets. Change sheet access checks to use this principal instead of the sheet URI. Bug 221428, r+sr=peterv git-svn-id: svn://10.0.0.236/trunk@225401 18797224-902f-48f8-a5cc-f745e15eee43
1899 lines
48 KiB
C++
1899 lines
48 KiB
C++
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
// vim:cindent:tabstop=2:expandtab:shiftwidth=2:
|
|
/* ***** BEGIN LICENSE BLOCK *****
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
*
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
* the License. You may obtain a copy of the License at
|
|
* http://www.mozilla.org/MPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
* for the specific language governing rights and limitations under the
|
|
* License.
|
|
*
|
|
* The Original Code is mozilla.org code.
|
|
*
|
|
* The Initial Developer of the Original Code is
|
|
* Netscape Communications Corporation.
|
|
* Portions created by the Initial Developer are Copyright (C) 1998
|
|
* the Initial Developer. All Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
* L. David Baron <dbaron@dbaron.org>
|
|
* Pierre Phaneuf <pp@ludusdesign.com>
|
|
* Daniel Glazman <glazman@netscape.com>
|
|
*
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
|
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
* use your version of this file under the terms of the MPL, indicate your
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
* the provisions above, a recipient may use your version of this file under
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
*
|
|
* ***** END LICENSE BLOCK ***** */
|
|
|
|
/* representation of a CSS style sheet */
|
|
|
|
#include "nsCSSStyleSheet.h"
|
|
|
|
#include "nsCRT.h"
|
|
#include "nsIAtom.h"
|
|
#include "nsIServiceManager.h"
|
|
#include "nsCSSRuleProcessor.h"
|
|
#include "nsICSSStyleRule.h"
|
|
#include "nsICSSNameSpaceRule.h"
|
|
#include "nsICSSGroupRule.h"
|
|
#include "nsICSSImportRule.h"
|
|
#include "nsIMediaList.h"
|
|
#include "nsIDocument.h"
|
|
#include "nsPresContext.h"
|
|
#include "nsGkAtoms.h"
|
|
#include "nsString.h"
|
|
#include "nsVoidArray.h"
|
|
#include "nsIDOMStyleSheetList.h"
|
|
#include "nsIDOMCSSStyleSheet.h"
|
|
#include "nsIDOMCSSRule.h"
|
|
#include "nsIDOMCSSImportRule.h"
|
|
#include "nsIDOMCSSRuleList.h"
|
|
#include "nsIDOMMediaList.h"
|
|
#include "nsIDOMNode.h"
|
|
#include "nsDOMError.h"
|
|
#include "nsICSSParser.h"
|
|
#include "nsICSSLoader.h"
|
|
#include "nsICSSLoaderObserver.h"
|
|
#include "nsINameSpaceManager.h"
|
|
#include "nsXMLNameSpaceMap.h"
|
|
#include "nsCOMPtr.h"
|
|
#include "nsContentUtils.h"
|
|
#include "nsIJSContextStack.h"
|
|
#include "nsIScriptSecurityManager.h"
|
|
|
|
// -------------------------------
|
|
// Style Rule List for the DOM
|
|
//
|
|
class CSSRuleListImpl : public nsIDOMCSSRuleList
|
|
{
|
|
public:
|
|
CSSRuleListImpl(nsCSSStyleSheet *aStyleSheet);
|
|
|
|
NS_DECL_ISUPPORTS
|
|
|
|
// nsIDOMCSSRuleList interface
|
|
NS_IMETHOD GetLength(PRUint32* aLength);
|
|
NS_IMETHOD Item(PRUint32 aIndex, nsIDOMCSSRule** aReturn);
|
|
|
|
void DropReference() { mStyleSheet = nsnull; }
|
|
|
|
protected:
|
|
virtual ~CSSRuleListImpl();
|
|
|
|
nsCSSStyleSheet* mStyleSheet;
|
|
public:
|
|
PRBool mRulesAccessed;
|
|
};
|
|
|
|
CSSRuleListImpl::CSSRuleListImpl(nsCSSStyleSheet *aStyleSheet)
|
|
{
|
|
// Not reference counted to avoid circular references.
|
|
// The style sheet will tell us when its going away.
|
|
mStyleSheet = aStyleSheet;
|
|
mRulesAccessed = PR_FALSE;
|
|
}
|
|
|
|
CSSRuleListImpl::~CSSRuleListImpl()
|
|
{
|
|
}
|
|
|
|
// QueryInterface implementation for CSSRuleList
|
|
NS_INTERFACE_MAP_BEGIN(CSSRuleListImpl)
|
|
NS_INTERFACE_MAP_ENTRY(nsIDOMCSSRuleList)
|
|
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
|
NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(CSSRuleList)
|
|
NS_INTERFACE_MAP_END
|
|
|
|
|
|
NS_IMPL_ADDREF(CSSRuleListImpl)
|
|
NS_IMPL_RELEASE(CSSRuleListImpl)
|
|
|
|
|
|
NS_IMETHODIMP
|
|
CSSRuleListImpl::GetLength(PRUint32* aLength)
|
|
{
|
|
if (nsnull != mStyleSheet) {
|
|
PRInt32 count;
|
|
mStyleSheet->StyleRuleCount(count);
|
|
*aLength = (PRUint32)count;
|
|
}
|
|
else {
|
|
*aLength = 0;
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
CSSRuleListImpl::Item(PRUint32 aIndex, nsIDOMCSSRule** aReturn)
|
|
{
|
|
nsresult result = NS_OK;
|
|
|
|
*aReturn = nsnull;
|
|
if (mStyleSheet) {
|
|
result = mStyleSheet->EnsureUniqueInner(); // needed to ensure rules have correct parent
|
|
if (NS_SUCCEEDED(result)) {
|
|
nsCOMPtr<nsICSSRule> rule;
|
|
|
|
result = mStyleSheet->GetStyleRuleAt(aIndex, *getter_AddRefs(rule));
|
|
if (rule) {
|
|
result = rule->GetDOMRule(aReturn);
|
|
mRulesAccessed = PR_TRUE; // signal to never share rules again
|
|
} else if (result == NS_ERROR_ILLEGAL_VALUE) {
|
|
result = NS_OK; // per spec: "Return Value ... null if ... not a valid index."
|
|
}
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
NS_INTERFACE_MAP_BEGIN(nsMediaList)
|
|
NS_INTERFACE_MAP_ENTRY(nsIDOMMediaList)
|
|
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
|
NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(MediaList)
|
|
NS_INTERFACE_MAP_END
|
|
|
|
NS_IMPL_ADDREF(nsMediaList)
|
|
NS_IMPL_RELEASE(nsMediaList)
|
|
|
|
|
|
nsMediaList::nsMediaList()
|
|
: mStyleSheet(nsnull)
|
|
{
|
|
}
|
|
|
|
nsMediaList::~nsMediaList()
|
|
{
|
|
}
|
|
|
|
nsresult
|
|
nsMediaList::GetText(nsAString& aMediaText)
|
|
{
|
|
aMediaText.Truncate();
|
|
|
|
for (PRInt32 i = 0, i_end = mArray.Count(); i < i_end; ++i) {
|
|
nsIAtom* medium = mArray[i];
|
|
NS_ENSURE_TRUE(medium, NS_ERROR_FAILURE);
|
|
|
|
nsAutoString buffer;
|
|
medium->ToString(buffer);
|
|
aMediaText.Append(buffer);
|
|
if (i + 1 < i_end) {
|
|
aMediaText.AppendLiteral(", ");
|
|
}
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
// XXXbz this is so ill-defined in the spec, it's not clear quite what
|
|
// it should be doing....
|
|
nsresult
|
|
nsMediaList::SetText(const nsAString& aMediaText)
|
|
{
|
|
nsCOMPtr<nsICSSParser> parser;
|
|
nsresult rv = NS_NewCSSParser(getter_AddRefs(parser));
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
PRBool htmlMode = PR_FALSE;
|
|
nsCOMPtr<nsIDOMStyleSheet> domSheet =
|
|
do_QueryInterface(NS_STATIC_CAST(nsICSSStyleSheet*, mStyleSheet));
|
|
if (domSheet) {
|
|
nsCOMPtr<nsIDOMNode> node;
|
|
domSheet->GetOwnerNode(getter_AddRefs(node));
|
|
htmlMode = !!node;
|
|
}
|
|
|
|
return parser->ParseMediaList(nsString(aMediaText), nsnull, 0,
|
|
this, htmlMode);
|
|
}
|
|
|
|
/*
|
|
* aMatch is true when we contain the desired medium or contain the
|
|
* "all" medium or contain no media at all, which is the same as
|
|
* containing "all"
|
|
*/
|
|
PRBool
|
|
nsMediaList::Matches(nsPresContext* aPresContext)
|
|
{
|
|
if (-1 != mArray.IndexOf(aPresContext->Medium()) ||
|
|
-1 != mArray.IndexOf(nsGkAtoms::all))
|
|
return PR_TRUE;
|
|
return mArray.Count() == 0;
|
|
}
|
|
|
|
nsresult
|
|
nsMediaList::SetStyleSheet(nsICSSStyleSheet *aSheet)
|
|
{
|
|
NS_ASSERTION(aSheet == mStyleSheet || !aSheet || !mStyleSheet,
|
|
"multiple style sheets competing for one media list");
|
|
mStyleSheet = NS_STATIC_CAST(nsCSSStyleSheet*, aSheet);
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
nsMediaList::Clone(nsMediaList** aResult)
|
|
{
|
|
nsRefPtr<nsMediaList> result = new nsMediaList();
|
|
if (!result)
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
if (!result->mArray.AppendObjects(mArray))
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
NS_ADDREF(*aResult = result);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsMediaList::GetMediaText(nsAString& aMediaText)
|
|
{
|
|
return GetText(aMediaText);
|
|
}
|
|
|
|
// "sheet" should be an nsCSSStyleSheet and "doc" should be an
|
|
// nsCOMPtr<nsIDocument>
|
|
#define BEGIN_MEDIA_CHANGE(sheet, doc) \
|
|
if (sheet) { \
|
|
rv = sheet->GetOwningDocument(*getter_AddRefs(doc)); \
|
|
NS_ENSURE_SUCCESS(rv, rv); \
|
|
} \
|
|
mozAutoDocUpdate updateBatch(doc, UPDATE_STYLE, PR_TRUE); \
|
|
if (sheet) { \
|
|
rv = sheet->WillDirty(); \
|
|
NS_ENSURE_SUCCESS(rv, rv); \
|
|
}
|
|
|
|
#define END_MEDIA_CHANGE(sheet, doc) \
|
|
if (sheet) { \
|
|
sheet->DidDirty(); \
|
|
} \
|
|
/* XXXldb Pass something meaningful? */ \
|
|
if (doc) { \
|
|
doc->StyleRuleChanged(sheet, nsnull, nsnull); \
|
|
}
|
|
|
|
|
|
NS_IMETHODIMP
|
|
nsMediaList::SetMediaText(const nsAString& aMediaText)
|
|
{
|
|
nsresult rv = NS_OK;
|
|
nsCOMPtr<nsIDocument> doc;
|
|
|
|
BEGIN_MEDIA_CHANGE(mStyleSheet, doc)
|
|
|
|
rv = SetText(aMediaText);
|
|
if (NS_FAILED(rv))
|
|
return rv;
|
|
|
|
END_MEDIA_CHANGE(mStyleSheet, doc)
|
|
|
|
return rv;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsMediaList::GetLength(PRUint32* aLength)
|
|
{
|
|
NS_ENSURE_ARG_POINTER(aLength);
|
|
|
|
*aLength = mArray.Count();
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsMediaList::Item(PRUint32 aIndex, nsAString& aReturn)
|
|
{
|
|
PRInt32 index = aIndex;
|
|
if (0 <= index && index < Count()) {
|
|
MediumAt(aIndex)->ToString(aReturn);
|
|
} else {
|
|
SetDOMStringToNull(aReturn);
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsMediaList::DeleteMedium(const nsAString& aOldMedium)
|
|
{
|
|
nsresult rv = NS_OK;
|
|
nsCOMPtr<nsIDocument> doc;
|
|
|
|
BEGIN_MEDIA_CHANGE(mStyleSheet, doc)
|
|
|
|
rv = Delete(aOldMedium);
|
|
if (NS_FAILED(rv))
|
|
return rv;
|
|
|
|
END_MEDIA_CHANGE(mStyleSheet, doc)
|
|
|
|
return rv;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsMediaList::AppendMedium(const nsAString& aNewMedium)
|
|
{
|
|
nsresult rv = NS_OK;
|
|
nsCOMPtr<nsIDocument> doc;
|
|
|
|
BEGIN_MEDIA_CHANGE(mStyleSheet, doc)
|
|
|
|
rv = Append(aNewMedium);
|
|
if (NS_FAILED(rv))
|
|
return rv;
|
|
|
|
END_MEDIA_CHANGE(mStyleSheet, doc)
|
|
|
|
return rv;
|
|
}
|
|
|
|
nsresult
|
|
nsMediaList::Delete(const nsAString& aOldMedium)
|
|
{
|
|
if (aOldMedium.IsEmpty())
|
|
return NS_ERROR_DOM_NOT_FOUND_ERR;
|
|
|
|
nsCOMPtr<nsIAtom> old = do_GetAtom(aOldMedium);
|
|
NS_ENSURE_TRUE(old, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
PRInt32 indx = mArray.IndexOf(old);
|
|
|
|
if (indx < 0) {
|
|
return NS_ERROR_DOM_NOT_FOUND_ERR;
|
|
}
|
|
|
|
mArray.RemoveObjectAt(indx);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
nsMediaList::Append(const nsAString& aNewMedium)
|
|
{
|
|
if (aNewMedium.IsEmpty())
|
|
return NS_ERROR_DOM_NOT_FOUND_ERR;
|
|
|
|
nsCOMPtr<nsIAtom> media = do_GetAtom(aNewMedium);
|
|
NS_ENSURE_TRUE(media, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
PRInt32 indx = mArray.IndexOf(media);
|
|
|
|
if (indx >= 0) {
|
|
mArray.RemoveObjectAt(indx);
|
|
}
|
|
|
|
mArray.AppendObject(media);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
// -------------------------------
|
|
// Imports Collection for the DOM
|
|
//
|
|
class CSSImportsCollectionImpl : public nsIDOMStyleSheetList
|
|
{
|
|
public:
|
|
CSSImportsCollectionImpl(nsICSSStyleSheet *aStyleSheet);
|
|
|
|
NS_DECL_ISUPPORTS
|
|
|
|
// nsIDOMCSSStyleSheetList interface
|
|
NS_IMETHOD GetLength(PRUint32* aLength);
|
|
NS_IMETHOD Item(PRUint32 aIndex, nsIDOMStyleSheet** aReturn);
|
|
|
|
void DropReference() { mStyleSheet = nsnull; }
|
|
|
|
protected:
|
|
virtual ~CSSImportsCollectionImpl();
|
|
|
|
nsICSSStyleSheet* mStyleSheet;
|
|
};
|
|
|
|
CSSImportsCollectionImpl::CSSImportsCollectionImpl(nsICSSStyleSheet *aStyleSheet)
|
|
{
|
|
// Not reference counted to avoid circular references.
|
|
// The style sheet will tell us when its going away.
|
|
mStyleSheet = aStyleSheet;
|
|
}
|
|
|
|
CSSImportsCollectionImpl::~CSSImportsCollectionImpl()
|
|
{
|
|
}
|
|
|
|
|
|
// QueryInterface implementation for CSSImportsCollectionImpl
|
|
NS_INTERFACE_MAP_BEGIN(CSSImportsCollectionImpl)
|
|
NS_INTERFACE_MAP_ENTRY(nsIDOMStyleSheetList)
|
|
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
|
NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(StyleSheetList)
|
|
NS_INTERFACE_MAP_END
|
|
|
|
|
|
NS_IMPL_ADDREF(CSSImportsCollectionImpl)
|
|
NS_IMPL_RELEASE(CSSImportsCollectionImpl)
|
|
|
|
|
|
NS_IMETHODIMP
|
|
CSSImportsCollectionImpl::GetLength(PRUint32* aLength)
|
|
{
|
|
if (nsnull != mStyleSheet) {
|
|
PRInt32 count;
|
|
mStyleSheet->StyleSheetCount(count);
|
|
*aLength = (PRUint32)count;
|
|
}
|
|
else {
|
|
*aLength = 0;
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
CSSImportsCollectionImpl::Item(PRUint32 aIndex, nsIDOMStyleSheet** aReturn)
|
|
{
|
|
nsresult result = NS_OK;
|
|
|
|
*aReturn = nsnull;
|
|
|
|
if (mStyleSheet) {
|
|
nsCOMPtr<nsICSSStyleSheet> sheet;
|
|
|
|
result = mStyleSheet->GetStyleSheetAt(aIndex, *getter_AddRefs(sheet));
|
|
if (NS_SUCCEEDED(result)) {
|
|
result = CallQueryInterface(sheet, aReturn);
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
// -------------------------------
|
|
// CSS Style Sheet Inner Data Container
|
|
//
|
|
|
|
|
|
static PRBool SetStyleSheetReference(nsICSSRule* aRule, void* aSheet)
|
|
{
|
|
if (aRule) {
|
|
aRule->SetStyleSheet((nsICSSStyleSheet*)aSheet);
|
|
}
|
|
return PR_TRUE;
|
|
}
|
|
|
|
nsCSSStyleSheetInner::nsCSSStyleSheetInner(nsICSSStyleSheet* aParentSheet)
|
|
: mSheets(),
|
|
mComplete(PR_FALSE)
|
|
#ifdef DEBUG
|
|
, mPrincipalSet(PR_FALSE)
|
|
#endif
|
|
{
|
|
MOZ_COUNT_CTOR(nsCSSStyleSheetInner);
|
|
mSheets.AppendElement(aParentSheet);
|
|
|
|
mPrincipal = do_CreateInstance("@mozilla.org/nullprincipal;1");
|
|
}
|
|
|
|
static PRBool
|
|
CloneRuleInto(nsICSSRule* aRule, void* aArray)
|
|
{
|
|
nsICSSRule* clone = nsnull;
|
|
aRule->Clone(clone);
|
|
if (clone) {
|
|
NS_STATIC_CAST(nsCOMArray<nsICSSRule>*, aArray)->AppendObject(clone);
|
|
NS_RELEASE(clone);
|
|
}
|
|
return PR_TRUE;
|
|
}
|
|
|
|
nsCSSStyleSheetInner::nsCSSStyleSheetInner(nsCSSStyleSheetInner& aCopy,
|
|
nsICSSStyleSheet* aParentSheet)
|
|
: mSheets(),
|
|
mSheetURI(aCopy.mSheetURI),
|
|
mBaseURI(aCopy.mBaseURI),
|
|
mPrincipal(aCopy.mPrincipal),
|
|
mComplete(aCopy.mComplete)
|
|
#ifdef DEBUG
|
|
, mPrincipalSet(aCopy.mPrincipalSet)
|
|
#endif
|
|
{
|
|
MOZ_COUNT_CTOR(nsCSSStyleSheetInner);
|
|
mSheets.AppendElement(aParentSheet);
|
|
aCopy.mOrderedRules.EnumerateForwards(CloneRuleInto, &mOrderedRules);
|
|
mOrderedRules.EnumerateForwards(SetStyleSheetReference, aParentSheet);
|
|
RebuildNameSpaces();
|
|
}
|
|
|
|
nsCSSStyleSheetInner::~nsCSSStyleSheetInner()
|
|
{
|
|
MOZ_COUNT_DTOR(nsCSSStyleSheetInner);
|
|
mOrderedRules.EnumerateForwards(SetStyleSheetReference, nsnull);
|
|
}
|
|
|
|
nsCSSStyleSheetInner*
|
|
nsCSSStyleSheetInner::CloneFor(nsICSSStyleSheet* aParentSheet)
|
|
{
|
|
return new nsCSSStyleSheetInner(*this, aParentSheet);
|
|
}
|
|
|
|
void
|
|
nsCSSStyleSheetInner::AddSheet(nsICSSStyleSheet* aParentSheet)
|
|
{
|
|
mSheets.AppendElement(aParentSheet);
|
|
}
|
|
|
|
void
|
|
nsCSSStyleSheetInner::RemoveSheet(nsICSSStyleSheet* aParentSheet)
|
|
{
|
|
if (1 == mSheets.Count()) {
|
|
NS_ASSERTION(aParentSheet == (nsICSSStyleSheet*)mSheets.ElementAt(0), "bad parent");
|
|
delete this;
|
|
return;
|
|
}
|
|
if (aParentSheet == (nsICSSStyleSheet*)mSheets.ElementAt(0)) {
|
|
mSheets.RemoveElementAt(0);
|
|
NS_ASSERTION(mSheets.Count(), "no parents");
|
|
mOrderedRules.EnumerateForwards(SetStyleSheetReference,
|
|
(nsICSSStyleSheet*)mSheets.ElementAt(0));
|
|
}
|
|
else {
|
|
mSheets.RemoveElement(aParentSheet);
|
|
}
|
|
}
|
|
|
|
static PRBool
|
|
CreateNameSpace(nsICSSRule* aRule, void* aNameSpacePtr)
|
|
{
|
|
PRInt32 type = nsICSSRule::UNKNOWN_RULE;
|
|
aRule->GetType(type);
|
|
if (nsICSSRule::NAMESPACE_RULE == type) {
|
|
nsICSSNameSpaceRule* nameSpaceRule = (nsICSSNameSpaceRule*)aRule;
|
|
nsXMLNameSpaceMap *nameSpaceMap =
|
|
NS_STATIC_CAST(nsXMLNameSpaceMap*, aNameSpacePtr);
|
|
|
|
nsIAtom* prefix = nsnull;
|
|
nsAutoString urlSpec;
|
|
nameSpaceRule->GetPrefix(prefix);
|
|
nameSpaceRule->GetURLSpec(urlSpec);
|
|
|
|
nameSpaceMap->AddPrefix(prefix, urlSpec);
|
|
return PR_TRUE;
|
|
}
|
|
// stop if not namespace, import or charset because namespace can't follow anything else
|
|
return (((nsICSSRule::CHARSET_RULE == type) ||
|
|
(nsICSSRule::IMPORT_RULE)) ? PR_TRUE : PR_FALSE);
|
|
}
|
|
|
|
void
|
|
nsCSSStyleSheetInner::RebuildNameSpaces()
|
|
{
|
|
if (mNameSpaceMap) {
|
|
mNameSpaceMap->Clear();
|
|
} else {
|
|
mNameSpaceMap = nsXMLNameSpaceMap::Create();
|
|
if (!mNameSpaceMap) {
|
|
return; // out of memory
|
|
}
|
|
}
|
|
|
|
mOrderedRules.EnumerateForwards(CreateNameSpace, mNameSpaceMap);
|
|
}
|
|
|
|
|
|
// -------------------------------
|
|
// CSS Style Sheet
|
|
//
|
|
|
|
nsCSSStyleSheet::nsCSSStyleSheet()
|
|
: nsICSSStyleSheet(),
|
|
mRefCnt(0),
|
|
mTitle(),
|
|
mMedia(nsnull),
|
|
mFirstChild(nsnull),
|
|
mNext(nsnull),
|
|
mParent(nsnull),
|
|
mOwnerRule(nsnull),
|
|
mImportsCollection(nsnull),
|
|
mRuleCollection(nsnull),
|
|
mDocument(nsnull),
|
|
mOwningNode(nsnull),
|
|
mDisabled(PR_FALSE),
|
|
mDirty(PR_FALSE),
|
|
mRuleProcessors(nsnull)
|
|
{
|
|
|
|
mInner = new nsCSSStyleSheetInner(this);
|
|
}
|
|
|
|
nsCSSStyleSheet::nsCSSStyleSheet(const nsCSSStyleSheet& aCopy,
|
|
nsICSSStyleSheet* aParentToUse,
|
|
nsICSSImportRule* aOwnerRuleToUse,
|
|
nsIDocument* aDocumentToUse,
|
|
nsIDOMNode* aOwningNodeToUse)
|
|
: nsICSSStyleSheet(),
|
|
mRefCnt(0),
|
|
mTitle(aCopy.mTitle),
|
|
mMedia(nsnull),
|
|
mFirstChild(nsnull),
|
|
mNext(nsnull),
|
|
mParent(aParentToUse),
|
|
mOwnerRule(aOwnerRuleToUse),
|
|
mImportsCollection(nsnull), // re-created lazily
|
|
mRuleCollection(nsnull), // re-created lazily
|
|
mDocument(aDocumentToUse),
|
|
mOwningNode(aOwningNodeToUse),
|
|
mDisabled(aCopy.mDisabled),
|
|
mDirty(PR_FALSE),
|
|
mInner(aCopy.mInner),
|
|
mRuleProcessors(nsnull)
|
|
{
|
|
|
|
mInner->AddSheet(this);
|
|
|
|
if (aCopy.mRuleCollection &&
|
|
aCopy.mRuleCollection->mRulesAccessed) { // CSSOM's been there, force full copy now
|
|
NS_ASSERTION(mInner->mComplete, "Why have rules been accessed on an incomplete sheet?");
|
|
EnsureUniqueInner();
|
|
}
|
|
|
|
if (aCopy.mMedia) {
|
|
aCopy.mMedia->Clone(getter_AddRefs(mMedia));
|
|
}
|
|
|
|
if (aCopy.mFirstChild) {
|
|
nsCSSStyleSheet* otherChild = aCopy.mFirstChild;
|
|
nsCSSStyleSheet** ourSlot = &mFirstChild;
|
|
do {
|
|
// XXX This is wrong; we should be keeping @import rules and
|
|
// sheets in sync!
|
|
nsCSSStyleSheet* child = new nsCSSStyleSheet(*otherChild,
|
|
this,
|
|
nsnull,
|
|
aDocumentToUse,
|
|
nsnull);
|
|
if (child) {
|
|
NS_ADDREF(child);
|
|
(*ourSlot) = child;
|
|
ourSlot = &(child->mNext);
|
|
}
|
|
otherChild = otherChild->mNext;
|
|
}
|
|
while (otherChild && ourSlot);
|
|
}
|
|
}
|
|
|
|
nsCSSStyleSheet::~nsCSSStyleSheet()
|
|
{
|
|
if (mFirstChild) {
|
|
nsCSSStyleSheet* child = mFirstChild;
|
|
do {
|
|
child->mParent = nsnull;
|
|
child->mDocument = nsnull;
|
|
child = child->mNext;
|
|
} while (child);
|
|
NS_RELEASE(mFirstChild);
|
|
}
|
|
NS_IF_RELEASE(mNext);
|
|
if (nsnull != mRuleCollection) {
|
|
mRuleCollection->DropReference();
|
|
NS_RELEASE(mRuleCollection);
|
|
}
|
|
if (nsnull != mImportsCollection) {
|
|
mImportsCollection->DropReference();
|
|
NS_RELEASE(mImportsCollection);
|
|
}
|
|
if (mMedia) {
|
|
mMedia->SetStyleSheet(nsnull);
|
|
mMedia = nsnull;
|
|
}
|
|
mInner->RemoveSheet(this);
|
|
// XXX The document reference is not reference counted and should
|
|
// not be released. The document will let us know when it is going
|
|
// away.
|
|
if (mRuleProcessors) {
|
|
NS_ASSERTION(mRuleProcessors->Count() == 0, "destructing sheet with rule processor reference");
|
|
delete mRuleProcessors; // weak refs, should be empty here anyway
|
|
}
|
|
}
|
|
|
|
|
|
// QueryInterface implementation for nsCSSStyleSheet
|
|
NS_INTERFACE_MAP_BEGIN(nsCSSStyleSheet)
|
|
NS_INTERFACE_MAP_ENTRY(nsICSSStyleSheet)
|
|
NS_INTERFACE_MAP_ENTRY(nsIStyleSheet)
|
|
NS_INTERFACE_MAP_ENTRY(nsIDOMStyleSheet)
|
|
NS_INTERFACE_MAP_ENTRY(nsIDOMCSSStyleSheet)
|
|
NS_INTERFACE_MAP_ENTRY(nsICSSLoaderObserver)
|
|
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsICSSStyleSheet)
|
|
NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(CSSStyleSheet)
|
|
NS_INTERFACE_MAP_END
|
|
|
|
|
|
NS_IMPL_ADDREF(nsCSSStyleSheet)
|
|
NS_IMPL_RELEASE(nsCSSStyleSheet)
|
|
|
|
|
|
NS_IMETHODIMP
|
|
nsCSSStyleSheet::AddRuleProcessor(nsCSSRuleProcessor* aProcessor)
|
|
{
|
|
if (! mRuleProcessors) {
|
|
mRuleProcessors = new nsAutoVoidArray();
|
|
if (!mRuleProcessors)
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
}
|
|
NS_ASSERTION(-1 == mRuleProcessors->IndexOf(aProcessor),
|
|
"processor already registered");
|
|
mRuleProcessors->AppendElement(aProcessor); // weak ref
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsCSSStyleSheet::DropRuleProcessor(nsCSSRuleProcessor* aProcessor)
|
|
{
|
|
if (!mRuleProcessors)
|
|
return NS_ERROR_FAILURE;
|
|
return mRuleProcessors->RemoveElement(aProcessor)
|
|
? NS_OK
|
|
: NS_ERROR_FAILURE;
|
|
}
|
|
|
|
|
|
NS_IMETHODIMP
|
|
nsCSSStyleSheet::SetURIs(nsIURI* aSheetURI, nsIURI* aBaseURI)
|
|
{
|
|
NS_PRECONDITION(aSheetURI && aBaseURI, "null ptr");
|
|
|
|
NS_ASSERTION(mInner->mOrderedRules.Count() == 0 && !mInner->mComplete,
|
|
"Can't call SetURL on sheets that are complete or have rules");
|
|
|
|
mInner->mSheetURI = aSheetURI;
|
|
mInner->mBaseURI = aBaseURI;
|
|
return NS_OK;
|
|
}
|
|
|
|
void
|
|
nsCSSStyleSheet::SetPrincipal(nsIPrincipal* aPrincipal)
|
|
{
|
|
NS_PRECONDITION(!mInner->mPrincipalSet,
|
|
"Should have an inner whose principal has not yet been set");
|
|
if (aPrincipal) {
|
|
mInner->mPrincipal = aPrincipal;
|
|
#ifdef DEBUG
|
|
mInner->mPrincipalSet = PR_TRUE;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
nsIPrincipal*
|
|
nsCSSStyleSheet::Principal() const
|
|
{
|
|
return mInner->mPrincipal;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsCSSStyleSheet::GetSheetURI(nsIURI** aSheetURI) const
|
|
{
|
|
NS_IF_ADDREF(*aSheetURI = mInner->mSheetURI.get());
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsCSSStyleSheet::GetBaseURI(nsIURI** aBaseURI) const
|
|
{
|
|
NS_IF_ADDREF(*aBaseURI = mInner->mBaseURI.get());
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsCSSStyleSheet::SetTitle(const nsAString& aTitle)
|
|
{
|
|
mTitle = aTitle;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsCSSStyleSheet::GetType(nsString& aType) const
|
|
{
|
|
aType.AssignLiteral("text/css");
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP_(PRBool)
|
|
nsCSSStyleSheet::UseForMedium(nsPresContext* aPresContext) const
|
|
{
|
|
if (mMedia) {
|
|
return mMedia->Matches(aPresContext);
|
|
}
|
|
return PR_TRUE;
|
|
}
|
|
|
|
|
|
NS_IMETHODIMP
|
|
nsCSSStyleSheet::SetMedia(nsMediaList* aMedia)
|
|
{
|
|
mMedia = aMedia;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP_(PRBool)
|
|
nsCSSStyleSheet::HasRules() const
|
|
{
|
|
PRInt32 count;
|
|
StyleRuleCount(count);
|
|
return count != 0;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsCSSStyleSheet::GetApplicable(PRBool& aApplicable) const
|
|
{
|
|
aApplicable = !mDisabled && mInner->mComplete;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsCSSStyleSheet::SetEnabled(PRBool aEnabled)
|
|
{
|
|
// Internal method, so callers must handle BeginUpdate/EndUpdate
|
|
PRBool oldDisabled = mDisabled;
|
|
mDisabled = !aEnabled;
|
|
|
|
if (mDocument && mInner->mComplete && oldDisabled != mDisabled) {
|
|
ClearRuleCascades();
|
|
|
|
mDocument->SetStyleSheetApplicableState(this, !mDisabled);
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsCSSStyleSheet::GetComplete(PRBool& aComplete) const
|
|
{
|
|
aComplete = mInner->mComplete;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsCSSStyleSheet::SetComplete()
|
|
{
|
|
NS_ASSERTION(!mDirty, "Can't set a dirty sheet complete!");
|
|
mInner->mComplete = PR_TRUE;
|
|
if (mDocument && !mDisabled) {
|
|
// Let the document know
|
|
mDocument->BeginUpdate(UPDATE_STYLE);
|
|
mDocument->SetStyleSheetApplicableState(this, PR_TRUE);
|
|
mDocument->EndUpdate(UPDATE_STYLE);
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsCSSStyleSheet::GetParentSheet(nsIStyleSheet*& aParent) const
|
|
{
|
|
aParent = mParent;
|
|
NS_IF_ADDREF(aParent);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsCSSStyleSheet::GetOwningDocument(nsIDocument*& aDocument) const
|
|
{
|
|
aDocument = mDocument;
|
|
NS_IF_ADDREF(aDocument);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsCSSStyleSheet::SetOwningDocument(nsIDocument* aDocument)
|
|
{ // not ref counted
|
|
mDocument = aDocument;
|
|
// Now set the same document on all our child sheets....
|
|
for (nsCSSStyleSheet* child = mFirstChild; child; child = child->mNext) {
|
|
child->SetOwningDocument(aDocument);
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsCSSStyleSheet::SetOwningNode(nsIDOMNode* aOwningNode)
|
|
{ // not ref counted
|
|
mOwningNode = aOwningNode;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsCSSStyleSheet::SetOwnerRule(nsICSSImportRule* aOwnerRule)
|
|
{ // not ref counted
|
|
mOwnerRule = aOwnerRule;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsCSSStyleSheet::GetOwnerRule(nsICSSImportRule** aOwnerRule)
|
|
{
|
|
*aOwnerRule = mOwnerRule;
|
|
NS_IF_ADDREF(*aOwnerRule);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsCSSStyleSheet::ContainsStyleSheet(nsIURI* aURL, PRBool& aContains, nsIStyleSheet** aTheChild /*=nsnull*/)
|
|
{
|
|
NS_PRECONDITION(nsnull != aURL, "null arg");
|
|
|
|
if (!mInner->mSheetURI) {
|
|
// We're not yet far enough along in our load to know what our URL is (we
|
|
// may still get redirected and such). Assert (caller should really not be
|
|
// calling this on us at this stage) and return.
|
|
NS_ERROR("ContainsStyleSheet called on a sheet that's still loading");
|
|
aContains = PR_FALSE;
|
|
return NS_OK;
|
|
}
|
|
|
|
// first check ourself out
|
|
nsresult rv = mInner->mSheetURI->Equals(aURL, &aContains);
|
|
if (NS_FAILED(rv)) aContains = PR_FALSE;
|
|
|
|
if (aContains) {
|
|
// if we found it and the out-param is there, set it and addref
|
|
if (aTheChild) {
|
|
rv = QueryInterface( NS_GET_IID(nsIStyleSheet), (void **)aTheChild);
|
|
}
|
|
} else {
|
|
nsCSSStyleSheet* child = mFirstChild;
|
|
// now check the chil'ins out (recursively)
|
|
while ((PR_FALSE == aContains) && (nsnull != child)) {
|
|
child->ContainsStyleSheet(aURL, aContains, aTheChild);
|
|
if (aContains) {
|
|
break;
|
|
} else {
|
|
child = child->mNext;
|
|
}
|
|
}
|
|
}
|
|
|
|
// NOTE: if there are errors in the above we are handling them locally
|
|
// and not promoting them to the caller
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsCSSStyleSheet::AppendStyleSheet(nsICSSStyleSheet* aSheet)
|
|
{
|
|
NS_PRECONDITION(nsnull != aSheet, "null arg");
|
|
|
|
if (NS_SUCCEEDED(WillDirty())) {
|
|
NS_ADDREF(aSheet);
|
|
nsCSSStyleSheet* sheet = (nsCSSStyleSheet*)aSheet;
|
|
|
|
if (! mFirstChild) {
|
|
mFirstChild = sheet;
|
|
}
|
|
else {
|
|
nsCSSStyleSheet* child = mFirstChild;
|
|
while (child->mNext) {
|
|
child = child->mNext;
|
|
}
|
|
child->mNext = sheet;
|
|
}
|
|
|
|
// This is not reference counted. Our parent tells us when
|
|
// it's going away.
|
|
sheet->mParent = this;
|
|
sheet->mDocument = mDocument;
|
|
DidDirty();
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsCSSStyleSheet::InsertStyleSheetAt(nsICSSStyleSheet* aSheet, PRInt32 aIndex)
|
|
{
|
|
NS_PRECONDITION(nsnull != aSheet, "null arg");
|
|
|
|
nsresult result = WillDirty();
|
|
|
|
if (NS_SUCCEEDED(result)) {
|
|
NS_ADDREF(aSheet);
|
|
nsCSSStyleSheet* sheet = (nsCSSStyleSheet*)aSheet;
|
|
nsCSSStyleSheet* child = mFirstChild;
|
|
|
|
if (aIndex && child) {
|
|
while ((0 < --aIndex) && child->mNext) {
|
|
child = child->mNext;
|
|
}
|
|
sheet->mNext = child->mNext;
|
|
child->mNext = sheet;
|
|
}
|
|
else {
|
|
sheet->mNext = mFirstChild;
|
|
mFirstChild = sheet;
|
|
}
|
|
|
|
// This is not reference counted. Our parent tells us when
|
|
// it's going away.
|
|
sheet->mParent = this;
|
|
sheet->mDocument = mDocument;
|
|
DidDirty();
|
|
}
|
|
return result;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsCSSStyleSheet::PrependStyleRule(nsICSSRule* aRule)
|
|
{
|
|
NS_PRECONDITION(nsnull != aRule, "null arg");
|
|
|
|
if (NS_SUCCEEDED(WillDirty())) {
|
|
mInner->mOrderedRules.InsertObjectAt(aRule, 0);
|
|
aRule->SetStyleSheet(this);
|
|
DidDirty();
|
|
|
|
PRInt32 type = nsICSSRule::UNKNOWN_RULE;
|
|
aRule->GetType(type);
|
|
if (nsICSSRule::NAMESPACE_RULE == type) {
|
|
// no api to prepend a namespace (ugh), release old ones and re-create them all
|
|
mInner->RebuildNameSpaces();
|
|
}
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsCSSStyleSheet::AppendStyleRule(nsICSSRule* aRule)
|
|
{
|
|
NS_PRECONDITION(nsnull != aRule, "null arg");
|
|
|
|
if (NS_SUCCEEDED(WillDirty())) {
|
|
mInner->mOrderedRules.AppendObject(aRule);
|
|
aRule->SetStyleSheet(this);
|
|
DidDirty();
|
|
|
|
PRInt32 type = nsICSSRule::UNKNOWN_RULE;
|
|
aRule->GetType(type);
|
|
if (nsICSSRule::NAMESPACE_RULE == type) {
|
|
if (!mInner->mNameSpaceMap) {
|
|
mInner->mNameSpaceMap = nsXMLNameSpaceMap::Create();
|
|
NS_ENSURE_TRUE(mInner->mNameSpaceMap, NS_ERROR_OUT_OF_MEMORY);
|
|
}
|
|
|
|
nsCOMPtr<nsICSSNameSpaceRule> nameSpaceRule(do_QueryInterface(aRule));
|
|
|
|
nsCOMPtr<nsIAtom> prefix;
|
|
nsAutoString urlSpec;
|
|
nameSpaceRule->GetPrefix(*getter_AddRefs(prefix));
|
|
nameSpaceRule->GetURLSpec(urlSpec);
|
|
|
|
mInner->mNameSpaceMap->AddPrefix(prefix, urlSpec);
|
|
}
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsCSSStyleSheet::ReplaceStyleRule(nsICSSRule* aOld, nsICSSRule* aNew)
|
|
{
|
|
NS_PRECONDITION(mInner->mOrderedRules.Count() != 0, "can't have old rule");
|
|
NS_PRECONDITION(mInner->mComplete, "No replacing in an incomplete sheet!");
|
|
|
|
if (NS_SUCCEEDED(WillDirty())) {
|
|
PRInt32 index = mInner->mOrderedRules.IndexOf(aOld);
|
|
NS_ENSURE_TRUE(index != -1, NS_ERROR_UNEXPECTED);
|
|
mInner->mOrderedRules.ReplaceObjectAt(aNew, index);
|
|
|
|
aNew->SetStyleSheet(this);
|
|
aOld->SetStyleSheet(nsnull);
|
|
DidDirty();
|
|
#ifdef DEBUG
|
|
PRInt32 type = nsICSSRule::UNKNOWN_RULE;
|
|
aNew->GetType(type);
|
|
NS_ASSERTION(nsICSSRule::NAMESPACE_RULE != type, "not yet implemented");
|
|
aOld->GetType(type);
|
|
NS_ASSERTION(nsICSSRule::NAMESPACE_RULE != type, "not yet implemented");
|
|
#endif
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsCSSStyleSheet::StyleRuleCount(PRInt32& aCount) const
|
|
{
|
|
aCount = mInner->mOrderedRules.Count();
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsCSSStyleSheet::GetStyleRuleAt(PRInt32 aIndex, nsICSSRule*& aRule) const
|
|
{
|
|
// Important: If this function is ever made scriptable, we must add
|
|
// a security check here. See GetCSSRules below for an example.
|
|
aRule = mInner->mOrderedRules.SafeObjectAt(aIndex);
|
|
if (aRule) {
|
|
NS_ADDREF(aRule);
|
|
return NS_OK;
|
|
}
|
|
|
|
return NS_ERROR_ILLEGAL_VALUE;
|
|
}
|
|
|
|
nsXMLNameSpaceMap*
|
|
nsCSSStyleSheet::GetNameSpaceMap() const
|
|
{
|
|
return mInner->mNameSpaceMap;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsCSSStyleSheet::StyleSheetCount(PRInt32& aCount) const
|
|
{
|
|
// XXX Far from an ideal way to do this, but the hope is that
|
|
// it won't be done too often. If it is, we might want to
|
|
// consider storing the children in an array.
|
|
aCount = 0;
|
|
|
|
const nsCSSStyleSheet* child = mFirstChild;
|
|
while (child) {
|
|
aCount++;
|
|
child = child->mNext;
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsCSSStyleSheet::GetStyleSheetAt(PRInt32 aIndex, nsICSSStyleSheet*& aSheet) const
|
|
{
|
|
// XXX Ughh...an O(n^2) method for doing iteration. Again, we hope
|
|
// that this isn't done too often. If it is, we need to change the
|
|
// underlying storage mechanism
|
|
aSheet = nsnull;
|
|
|
|
if (mFirstChild) {
|
|
const nsCSSStyleSheet* child = mFirstChild;
|
|
while ((child) && (0 != aIndex)) {
|
|
--aIndex;
|
|
child = child->mNext;
|
|
}
|
|
|
|
aSheet = (nsICSSStyleSheet*)child;
|
|
NS_IF_ADDREF(aSheet);
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
nsCSSStyleSheet::EnsureUniqueInner()
|
|
{
|
|
if (1 < mInner->mSheets.Count()) {
|
|
nsCSSStyleSheetInner* clone = mInner->CloneFor(this);
|
|
if (clone) {
|
|
mInner->RemoveSheet(this);
|
|
mInner = clone;
|
|
}
|
|
else {
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
}
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsCSSStyleSheet::Clone(nsICSSStyleSheet* aCloneParent,
|
|
nsICSSImportRule* aCloneOwnerRule,
|
|
nsIDocument* aCloneDocument,
|
|
nsIDOMNode* aCloneOwningNode,
|
|
nsICSSStyleSheet** aClone) const
|
|
{
|
|
NS_PRECONDITION(aClone, "Null out param!");
|
|
nsCSSStyleSheet* clone = new nsCSSStyleSheet(*this,
|
|
aCloneParent,
|
|
aCloneOwnerRule,
|
|
aCloneDocument,
|
|
aCloneOwningNode);
|
|
if (clone) {
|
|
*aClone = NS_STATIC_CAST(nsICSSStyleSheet*, clone);
|
|
NS_ADDREF(*aClone);
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
static void
|
|
ListRules(const nsCOMArray<nsICSSRule>& aRules, FILE* aOut, PRInt32 aIndent)
|
|
{
|
|
for (PRInt32 index = aRules.Count() - 1; index >= 0; --index) {
|
|
aRules.ObjectAt(index)->List(aOut, aIndent);
|
|
}
|
|
}
|
|
|
|
struct ListEnumData {
|
|
ListEnumData(FILE* aOut, PRInt32 aIndent)
|
|
: mOut(aOut),
|
|
mIndent(aIndent)
|
|
{
|
|
}
|
|
FILE* mOut;
|
|
PRInt32 mIndent;
|
|
};
|
|
|
|
void nsCSSStyleSheet::List(FILE* out, PRInt32 aIndent) const
|
|
{
|
|
|
|
PRInt32 index;
|
|
|
|
// Indent
|
|
for (index = aIndent; --index >= 0; ) fputs(" ", out);
|
|
|
|
fputs("CSS Style Sheet: ", out);
|
|
nsCAutoString urlSpec;
|
|
nsresult rv = mInner->mSheetURI->GetSpec(urlSpec);
|
|
if (NS_SUCCEEDED(rv) && !urlSpec.IsEmpty()) {
|
|
fputs(urlSpec.get(), out);
|
|
}
|
|
|
|
if (mMedia) {
|
|
fputs(" media: ", out);
|
|
nsAutoString buffer;
|
|
mMedia->GetText(buffer);
|
|
fputs(NS_ConvertUTF16toUTF8(buffer).get(), out);
|
|
}
|
|
fputs("\n", out);
|
|
|
|
const nsCSSStyleSheet* child = mFirstChild;
|
|
while (nsnull != child) {
|
|
child->List(out, aIndent + 1);
|
|
child = child->mNext;
|
|
}
|
|
|
|
fputs("Rules in source order:\n", out);
|
|
ListRules(mInner->mOrderedRules, out, aIndent);
|
|
}
|
|
#endif
|
|
|
|
static PRBool PR_CALLBACK
|
|
EnumClearRuleCascades(void* aProcessor, void* aData)
|
|
{
|
|
nsCSSRuleProcessor* processor =
|
|
NS_STATIC_CAST(nsCSSRuleProcessor*, aProcessor);
|
|
processor->ClearRuleCascades();
|
|
return PR_TRUE;
|
|
}
|
|
|
|
void
|
|
nsCSSStyleSheet::ClearRuleCascades()
|
|
{
|
|
if (mRuleProcessors) {
|
|
mRuleProcessors->EnumerateForwards(EnumClearRuleCascades, nsnull);
|
|
}
|
|
if (mParent) {
|
|
nsCSSStyleSheet* parent = (nsCSSStyleSheet*)mParent;
|
|
parent->ClearRuleCascades();
|
|
}
|
|
}
|
|
|
|
nsresult
|
|
nsCSSStyleSheet::WillDirty()
|
|
{
|
|
if (!mInner->mComplete) {
|
|
// Do nothing
|
|
return NS_OK;
|
|
}
|
|
|
|
return EnsureUniqueInner();
|
|
}
|
|
|
|
void
|
|
nsCSSStyleSheet::DidDirty()
|
|
{
|
|
ClearRuleCascades();
|
|
mDirty = PR_TRUE;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsCSSStyleSheet::IsModified(PRBool* aSheetModified) const
|
|
{
|
|
*aSheetModified = mDirty;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsCSSStyleSheet::SetModified(PRBool aModified)
|
|
{
|
|
mDirty = aModified;
|
|
return NS_OK;
|
|
}
|
|
|
|
// nsIDOMStyleSheet interface
|
|
NS_IMETHODIMP
|
|
nsCSSStyleSheet::GetType(nsAString& aType)
|
|
{
|
|
aType.AssignLiteral("text/css");
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsCSSStyleSheet::GetDisabled(PRBool* aDisabled)
|
|
{
|
|
*aDisabled = mDisabled;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsCSSStyleSheet::SetDisabled(PRBool aDisabled)
|
|
{
|
|
// DOM method, so handle BeginUpdate/EndUpdate
|
|
MOZ_AUTO_DOC_UPDATE(mDocument, UPDATE_STYLE, PR_TRUE);
|
|
nsresult rv = nsCSSStyleSheet::SetEnabled(!aDisabled);
|
|
return rv;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsCSSStyleSheet::GetOwnerNode(nsIDOMNode** aOwnerNode)
|
|
{
|
|
*aOwnerNode = mOwningNode;
|
|
NS_IF_ADDREF(*aOwnerNode);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsCSSStyleSheet::GetParentStyleSheet(nsIDOMStyleSheet** aParentStyleSheet)
|
|
{
|
|
NS_ENSURE_ARG_POINTER(aParentStyleSheet);
|
|
|
|
nsresult rv = NS_OK;
|
|
|
|
if (mParent) {
|
|
rv = mParent->QueryInterface(NS_GET_IID(nsIDOMStyleSheet),
|
|
(void **)aParentStyleSheet);
|
|
} else {
|
|
*aParentStyleSheet = nsnull;
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsCSSStyleSheet::GetHref(nsAString& aHref)
|
|
{
|
|
nsCAutoString str;
|
|
|
|
// XXXldb The DOM spec says that this should be null for inline style sheets.
|
|
if (mInner->mSheetURI) {
|
|
mInner->mSheetURI->GetSpec(str);
|
|
}
|
|
|
|
CopyUTF8toUTF16(str, aHref);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsCSSStyleSheet::GetTitle(nsString& aTitle) const
|
|
{
|
|
aTitle = mTitle;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsCSSStyleSheet::GetTitle(nsAString& aTitle)
|
|
{
|
|
aTitle.Assign(mTitle);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsCSSStyleSheet::GetMedia(nsIDOMMediaList** aMedia)
|
|
{
|
|
NS_ENSURE_ARG_POINTER(aMedia);
|
|
*aMedia = nsnull;
|
|
|
|
if (!mMedia) {
|
|
mMedia = new nsMediaList();
|
|
NS_ENSURE_TRUE(mMedia, NS_ERROR_OUT_OF_MEMORY);
|
|
mMedia->SetStyleSheet(this);
|
|
}
|
|
|
|
*aMedia = mMedia;
|
|
NS_ADDREF(*aMedia);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsCSSStyleSheet::GetOwnerRule(nsIDOMCSSRule** aOwnerRule)
|
|
{
|
|
if (mOwnerRule) {
|
|
return mOwnerRule->GetDOMRule(aOwnerRule);
|
|
}
|
|
|
|
*aOwnerRule = nsnull;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsCSSStyleSheet::GetCssRules(nsIDOMCSSRuleList** aCssRules)
|
|
{
|
|
// No doing this on incomplete sheets!
|
|
PRBool complete;
|
|
GetComplete(complete);
|
|
if (!complete) {
|
|
return NS_ERROR_DOM_INVALID_ACCESS_ERR;
|
|
}
|
|
|
|
//-- Security check: Only scripts whose principal subsumes that of the
|
|
// style sheet can access rule collections.
|
|
|
|
// Get the security manager and do the subsumes check
|
|
nsIScriptSecurityManager *securityManager =
|
|
nsContentUtils::GetSecurityManager();
|
|
|
|
nsCOMPtr<nsIPrincipal> subjectPrincipal;
|
|
securityManager->GetSubjectPrincipal(getter_AddRefs(subjectPrincipal));
|
|
|
|
nsresult rv = NS_OK;
|
|
if (subjectPrincipal) {
|
|
PRBool subsumes;
|
|
rv = subjectPrincipal->Subsumes(mInner->mPrincipal, &subsumes);
|
|
if (NS_SUCCEEDED(rv) && !subsumes &&
|
|
!nsContentUtils::IsCallerTrustedForRead()) {
|
|
rv = NS_ERROR_DOM_SECURITY_ERR;
|
|
}
|
|
|
|
if (NS_FAILED(rv)) {
|
|
return rv;
|
|
}
|
|
}
|
|
|
|
// OK, security check passed, so get the rule collection
|
|
if (nsnull == mRuleCollection) {
|
|
mRuleCollection = new CSSRuleListImpl(this);
|
|
if (nsnull == mRuleCollection) {
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
}
|
|
NS_ADDREF(mRuleCollection);
|
|
}
|
|
|
|
*aCssRules = mRuleCollection;
|
|
NS_ADDREF(mRuleCollection);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsCSSStyleSheet::InsertRule(const nsAString& aRule,
|
|
PRUint32 aIndex,
|
|
PRUint32* aReturn)
|
|
{
|
|
// No doing this if the sheet is not complete!
|
|
PRBool complete;
|
|
GetComplete(complete);
|
|
if (!complete) {
|
|
return NS_ERROR_DOM_INVALID_ACCESS_ERR;
|
|
}
|
|
|
|
if (aRule.IsEmpty()) {
|
|
// Nothing to do here
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult result;
|
|
result = WillDirty();
|
|
if (NS_FAILED(result))
|
|
return result;
|
|
|
|
if (aIndex > PRUint32(mInner->mOrderedRules.Count()))
|
|
return NS_ERROR_DOM_INDEX_SIZE_ERR;
|
|
|
|
NS_ASSERTION(PRUint32(mInner->mOrderedRules.Count()) <= PR_INT32_MAX,
|
|
"Too many style rules!");
|
|
|
|
// Hold strong ref to the CSSLoader in case the document update
|
|
// kills the document
|
|
nsCOMPtr<nsICSSLoader> loader;
|
|
if (mDocument) {
|
|
loader = mDocument->CSSLoader();
|
|
NS_ASSERTION(loader, "Document with no CSS loader!");
|
|
}
|
|
|
|
nsCOMPtr<nsICSSParser> css;
|
|
if (loader) {
|
|
result = loader->GetParserFor(this, getter_AddRefs(css));
|
|
}
|
|
else {
|
|
result = NS_NewCSSParser(getter_AddRefs(css));
|
|
if (css) {
|
|
css->SetStyleSheet(this);
|
|
}
|
|
}
|
|
if (NS_FAILED(result))
|
|
return result;
|
|
|
|
mozAutoDocUpdate updateBatch(mDocument, UPDATE_STYLE, PR_TRUE);
|
|
|
|
nsCOMArray<nsICSSRule> rules;
|
|
result = css->ParseRule(aRule, mInner->mSheetURI, mInner->mBaseURI, rules);
|
|
if (NS_FAILED(result))
|
|
return result;
|
|
|
|
PRInt32 rulecount = rules.Count();
|
|
if (rulecount == 0) {
|
|
// Since we know aRule was not an empty string, just throw
|
|
return NS_ERROR_DOM_SYNTAX_ERR;
|
|
}
|
|
|
|
// Hierarchy checking. Just check the first and last rule in the list.
|
|
|
|
// check that we're not inserting before a charset rule
|
|
PRInt32 nextType = nsICSSRule::UNKNOWN_RULE;
|
|
nsICSSRule* nextRule = mInner->mOrderedRules.SafeObjectAt(aIndex);
|
|
if (nextRule) {
|
|
nextRule->GetType(nextType);
|
|
if (nextType == nsICSSRule::CHARSET_RULE) {
|
|
return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
|
|
}
|
|
|
|
// check last rule in list
|
|
nsICSSRule* lastRule = rules.ObjectAt(rulecount - 1);
|
|
PRInt32 lastType = nsICSSRule::UNKNOWN_RULE;
|
|
lastRule->GetType(lastType);
|
|
|
|
if (nextType == nsICSSRule::IMPORT_RULE &&
|
|
lastType != nsICSSRule::CHARSET_RULE &&
|
|
lastType != nsICSSRule::IMPORT_RULE) {
|
|
return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
|
|
}
|
|
|
|
if (nextType == nsICSSRule::NAMESPACE_RULE &&
|
|
lastType != nsICSSRule::CHARSET_RULE &&
|
|
lastType != nsICSSRule::IMPORT_RULE &&
|
|
lastType != nsICSSRule::NAMESPACE_RULE) {
|
|
return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
|
|
}
|
|
}
|
|
|
|
// check first rule in list
|
|
nsICSSRule* firstRule = rules.ObjectAt(0);
|
|
PRInt32 firstType = nsICSSRule::UNKNOWN_RULE;
|
|
firstRule->GetType(firstType);
|
|
if (aIndex != 0) {
|
|
if (firstType == nsICSSRule::CHARSET_RULE) { // no inserting charset at nonzero position
|
|
return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
|
|
}
|
|
|
|
nsICSSRule* prevRule = mInner->mOrderedRules.SafeObjectAt(aIndex - 1);
|
|
PRInt32 prevType = nsICSSRule::UNKNOWN_RULE;
|
|
prevRule->GetType(prevType);
|
|
|
|
if (firstType == nsICSSRule::IMPORT_RULE &&
|
|
prevType != nsICSSRule::CHARSET_RULE &&
|
|
prevType != nsICSSRule::IMPORT_RULE) {
|
|
return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
|
|
}
|
|
|
|
if (firstType == nsICSSRule::NAMESPACE_RULE &&
|
|
prevType != nsICSSRule::CHARSET_RULE &&
|
|
prevType != nsICSSRule::IMPORT_RULE &&
|
|
prevType != nsICSSRule::NAMESPACE_RULE) {
|
|
return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
|
|
}
|
|
}
|
|
|
|
PRBool insertResult = mInner->mOrderedRules.InsertObjectsAt(rules, aIndex);
|
|
NS_ENSURE_TRUE(insertResult, NS_ERROR_OUT_OF_MEMORY);
|
|
DidDirty();
|
|
|
|
for (PRInt32 counter = 0; counter < rulecount; counter++) {
|
|
nsICSSRule* cssRule = rules.ObjectAt(counter);
|
|
cssRule->SetStyleSheet(this);
|
|
|
|
PRInt32 type = nsICSSRule::UNKNOWN_RULE;
|
|
cssRule->GetType(type);
|
|
if (type == nsICSSRule::NAMESPACE_RULE) {
|
|
if (!mInner->mNameSpaceMap) {
|
|
mInner->mNameSpaceMap = nsXMLNameSpaceMap::Create();
|
|
NS_ENSURE_TRUE(mInner->mNameSpaceMap, NS_ERROR_OUT_OF_MEMORY);
|
|
}
|
|
|
|
nsCOMPtr<nsICSSNameSpaceRule> nameSpaceRule(do_QueryInterface(cssRule));
|
|
|
|
nsCOMPtr<nsIAtom> prefix;
|
|
nsAutoString urlSpec;
|
|
nameSpaceRule->GetPrefix(*getter_AddRefs(prefix));
|
|
nameSpaceRule->GetURLSpec(urlSpec);
|
|
|
|
mInner->mNameSpaceMap->AddPrefix(prefix, urlSpec);
|
|
}
|
|
|
|
// We don't notify immediately for @import rules, but rather when
|
|
// the sheet the rule is importing is loaded
|
|
PRBool notify = PR_TRUE;
|
|
if (type == nsICSSRule::IMPORT_RULE) {
|
|
nsCOMPtr<nsIDOMCSSImportRule> importRule(do_QueryInterface(cssRule));
|
|
NS_ASSERTION(importRule, "Rule which has type IMPORT_RULE and does not implement nsIDOMCSSImportRule!");
|
|
nsCOMPtr<nsIDOMCSSStyleSheet> childSheet;
|
|
importRule->GetStyleSheet(getter_AddRefs(childSheet));
|
|
if (!childSheet) {
|
|
notify = PR_FALSE;
|
|
}
|
|
}
|
|
if (mDocument && notify) {
|
|
mDocument->StyleRuleAdded(this, cssRule);
|
|
}
|
|
}
|
|
|
|
if (loader) {
|
|
loader->RecycleParser(css);
|
|
}
|
|
|
|
*aReturn = aIndex;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsCSSStyleSheet::DeleteRule(PRUint32 aIndex)
|
|
{
|
|
nsresult result = NS_ERROR_DOM_INDEX_SIZE_ERR;
|
|
// No doing this if the sheet is not complete!
|
|
PRBool complete;
|
|
GetComplete(complete);
|
|
if (!complete) {
|
|
return NS_ERROR_DOM_INVALID_ACCESS_ERR;
|
|
}
|
|
|
|
// XXX TBI: handle @rule types
|
|
mozAutoDocUpdate updateBatch(mDocument, UPDATE_STYLE, PR_TRUE);
|
|
|
|
result = WillDirty();
|
|
|
|
if (NS_SUCCEEDED(result)) {
|
|
if (aIndex >= PRUint32(mInner->mOrderedRules.Count()))
|
|
return NS_ERROR_DOM_INDEX_SIZE_ERR;
|
|
|
|
NS_ASSERTION(PRUint32(mInner->mOrderedRules.Count()) <= PR_INT32_MAX,
|
|
"Too many style rules!");
|
|
|
|
// Hold a strong ref to the rule so it doesn't die when we RemoveObjectAt
|
|
nsCOMPtr<nsICSSRule> rule = mInner->mOrderedRules.ObjectAt(aIndex);
|
|
if (rule) {
|
|
mInner->mOrderedRules.RemoveObjectAt(aIndex);
|
|
rule->SetStyleSheet(nsnull);
|
|
DidDirty();
|
|
|
|
if (mDocument) {
|
|
mDocument->StyleRuleRemoved(this, rule);
|
|
}
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsCSSStyleSheet::DeleteRuleFromGroup(nsICSSGroupRule* aGroup, PRUint32 aIndex)
|
|
{
|
|
NS_ENSURE_ARG_POINTER(aGroup);
|
|
NS_ASSERTION(mInner->mComplete, "No deleting from an incomplete sheet!");
|
|
nsresult result;
|
|
nsCOMPtr<nsICSSRule> rule;
|
|
result = aGroup->GetStyleRuleAt(aIndex, *getter_AddRefs(rule));
|
|
NS_ENSURE_SUCCESS(result, result);
|
|
|
|
// check that the rule actually belongs to this sheet!
|
|
nsCOMPtr<nsIStyleSheet> ruleSheet;
|
|
rule->GetStyleSheet(*getter_AddRefs(ruleSheet));
|
|
if (this != ruleSheet) {
|
|
return NS_ERROR_INVALID_ARG;
|
|
}
|
|
|
|
mozAutoDocUpdate updateBatch(mDocument, UPDATE_STYLE, PR_TRUE);
|
|
|
|
result = WillDirty();
|
|
NS_ENSURE_SUCCESS(result, result);
|
|
|
|
result = aGroup->DeleteStyleRuleAt(aIndex);
|
|
NS_ENSURE_SUCCESS(result, result);
|
|
|
|
rule->SetStyleSheet(nsnull);
|
|
|
|
DidDirty();
|
|
|
|
if (mDocument) {
|
|
mDocument->StyleRuleRemoved(this, rule);
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsCSSStyleSheet::InsertRuleIntoGroup(const nsAString & aRule,
|
|
nsICSSGroupRule* aGroup,
|
|
PRUint32 aIndex,
|
|
PRUint32* _retval)
|
|
{
|
|
nsresult result;
|
|
NS_ASSERTION(mInner->mComplete, "No inserting into an incomplete sheet!");
|
|
// check that the group actually belongs to this sheet!
|
|
nsCOMPtr<nsIStyleSheet> groupSheet;
|
|
aGroup->GetStyleSheet(*getter_AddRefs(groupSheet));
|
|
if (this != groupSheet) {
|
|
return NS_ERROR_INVALID_ARG;
|
|
}
|
|
|
|
if (aRule.IsEmpty()) {
|
|
// Nothing to do here
|
|
return NS_OK;
|
|
}
|
|
|
|
// Hold strong ref to the CSSLoader in case the document update
|
|
// kills the document
|
|
nsCOMPtr<nsICSSLoader> loader;
|
|
if (mDocument) {
|
|
loader = mDocument->CSSLoader();
|
|
NS_ASSERTION(loader, "Document with no CSS loader!");
|
|
}
|
|
|
|
nsCOMPtr<nsICSSParser> css;
|
|
if (loader) {
|
|
result = loader->GetParserFor(this, getter_AddRefs(css));
|
|
}
|
|
else {
|
|
result = NS_NewCSSParser(getter_AddRefs(css));
|
|
if (css) {
|
|
css->SetStyleSheet(this);
|
|
}
|
|
}
|
|
NS_ENSURE_SUCCESS(result, result);
|
|
|
|
// parse and grab the rule
|
|
mozAutoDocUpdate updateBatch(mDocument, UPDATE_STYLE, PR_TRUE);
|
|
|
|
result = WillDirty();
|
|
NS_ENSURE_SUCCESS(result, result);
|
|
|
|
nsCOMArray<nsICSSRule> rules;
|
|
result = css->ParseRule(aRule, mInner->mSheetURI, mInner->mBaseURI, rules);
|
|
NS_ENSURE_SUCCESS(result, result);
|
|
|
|
PRInt32 rulecount = rules.Count();
|
|
if (rulecount == 0) {
|
|
// Since we know aRule was not an empty string, just throw
|
|
return NS_ERROR_DOM_SYNTAX_ERR;
|
|
}
|
|
|
|
PRInt32 counter;
|
|
nsICSSRule* rule;
|
|
for (counter = 0; counter < rulecount; counter++) {
|
|
// Only rulesets are allowed in a group as of CSS2
|
|
PRInt32 type = nsICSSRule::UNKNOWN_RULE;
|
|
rule = rules.ObjectAt(counter);
|
|
rule->GetType(type);
|
|
if (type != nsICSSRule::STYLE_RULE) {
|
|
return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
|
|
}
|
|
}
|
|
|
|
result = aGroup->InsertStyleRulesAt(aIndex, rules);
|
|
NS_ENSURE_SUCCESS(result, result);
|
|
DidDirty();
|
|
for (counter = 0; counter < rulecount; counter++) {
|
|
rule = rules.ObjectAt(counter);
|
|
|
|
if (mDocument) {
|
|
mDocument->StyleRuleAdded(this, rule);
|
|
}
|
|
}
|
|
|
|
if (loader) {
|
|
loader->RecycleParser(css);
|
|
}
|
|
|
|
*_retval = aIndex;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsCSSStyleSheet::ReplaceRuleInGroup(nsICSSGroupRule* aGroup,
|
|
nsICSSRule* aOld, nsICSSRule* aNew)
|
|
{
|
|
nsresult result;
|
|
NS_PRECONDITION(mInner->mComplete, "No replacing in an incomplete sheet!");
|
|
#ifdef DEBUG
|
|
{
|
|
nsCOMPtr<nsIStyleSheet> groupSheet;
|
|
aGroup->GetStyleSheet(*getter_AddRefs(groupSheet));
|
|
NS_ASSERTION(this == groupSheet, "group doesn't belong to this sheet");
|
|
}
|
|
#endif
|
|
result = WillDirty();
|
|
NS_ENSURE_SUCCESS(result, result);
|
|
|
|
result = aGroup->ReplaceStyleRule(aOld, aNew);
|
|
DidDirty();
|
|
return result;
|
|
}
|
|
|
|
// nsICSSLoaderObserver implementation
|
|
NS_IMETHODIMP
|
|
nsCSSStyleSheet::StyleSheetLoaded(nsICSSStyleSheet* aSheet,
|
|
PRBool aWasAlternate,
|
|
nsresult aStatus)
|
|
{
|
|
#ifdef DEBUG
|
|
nsCOMPtr<nsIStyleSheet> styleSheet(do_QueryInterface(aSheet));
|
|
NS_ASSERTION(styleSheet, "Sheet not implementing nsIStyleSheet!\n");
|
|
nsCOMPtr<nsIStyleSheet> parentSheet;
|
|
aSheet->GetParentSheet(*getter_AddRefs(parentSheet));
|
|
nsCOMPtr<nsIStyleSheet> thisSheet;
|
|
QueryInterface(NS_GET_IID(nsIStyleSheet), getter_AddRefs(thisSheet));
|
|
NS_ASSERTION(thisSheet == parentSheet, "We are being notified of a sheet load for a sheet that is not our child!\n");
|
|
#endif
|
|
|
|
if (mDocument && NS_SUCCEEDED(aStatus)) {
|
|
nsCOMPtr<nsICSSImportRule> ownerRule;
|
|
aSheet->GetOwnerRule(getter_AddRefs(ownerRule));
|
|
|
|
mozAutoDocUpdate updateBatch(mDocument, UPDATE_STYLE, PR_TRUE);
|
|
|
|
// XXXldb @import rules shouldn't even implement nsIStyleRule (but
|
|
// they do)!
|
|
nsCOMPtr<nsIStyleRule> styleRule(do_QueryInterface(ownerRule));
|
|
|
|
mDocument->StyleRuleAdded(this, styleRule);
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
NS_NewCSSStyleSheet(nsICSSStyleSheet** aInstancePtrResult)
|
|
{
|
|
*aInstancePtrResult = nsnull;
|
|
nsCSSStyleSheet *it = new nsCSSStyleSheet();
|
|
|
|
if (!it) {
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
}
|
|
|
|
NS_ADDREF(it);
|
|
|
|
if (!it->mInner || !it->mInner->mPrincipal) {
|
|
NS_RELEASE(it);
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
}
|
|
|
|
*aInstancePtrResult = it;
|
|
return NS_OK;
|
|
}
|