Merge mozilla-central and tracemonkey. (a=blockers)
[mozilla-central.git] / layout / base / nsStyleSheetService.cpp
blob0b62c8ec5e20eeba8502ece0d18765bab850db87
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
15 * The Original Code is Mozilla.
17 * The Initial Developer of the Original Code is
18 * IBM Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 2005
20 * the Initial Developer. All Rights Reserved.
22 * Contributor(s):
23 * Brian Ryner <bryner@brianryner.com>
25 * Alternatively, the contents of this file may be used under the terms of
26 * either the GNU General Public License Version 2 or later (the "GPL"), or
27 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the MPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the MPL, the GPL or the LGPL.
37 * ***** END LICENSE BLOCK ***** */
39 /* implementation of interface for managing user and user-agent style sheets */
41 #include "prlog.h"
42 #include "nsStyleSheetService.h"
43 #include "nsIStyleSheet.h"
44 #include "mozilla/css/Loader.h"
45 #include "nsCSSStyleSheet.h"
46 #include "nsIURI.h"
47 #include "nsContentCID.h"
48 #include "nsCOMPtr.h"
49 #include "nsIServiceManager.h"
50 #include "nsICategoryManager.h"
51 #include "nsISupportsPrimitives.h"
52 #include "nsNetUtil.h"
53 #include "nsIObserverService.h"
54 #include "nsLayoutStatics.h"
56 nsStyleSheetService *nsStyleSheetService::gInstance = nsnull;
58 nsStyleSheetService::nsStyleSheetService()
60 PR_STATIC_ASSERT(0 == AGENT_SHEET && 1 == USER_SHEET);
61 NS_ASSERTION(!gInstance, "Someone is using CreateInstance instead of GetService");
62 gInstance = this;
63 nsLayoutStatics::AddRef();
66 nsStyleSheetService::~nsStyleSheetService()
68 gInstance = nsnull;
69 nsLayoutStatics::Release();
72 NS_IMPL_ISUPPORTS1(nsStyleSheetService, nsIStyleSheetService)
74 void
75 nsStyleSheetService::RegisterFromEnumerator(nsICategoryManager *aManager,
76 const char *aCategory,
77 nsISimpleEnumerator *aEnumerator,
78 PRUint32 aSheetType)
80 if (!aEnumerator)
81 return;
83 PRBool hasMore;
84 while (NS_SUCCEEDED(aEnumerator->HasMoreElements(&hasMore)) && hasMore) {
85 nsCOMPtr<nsISupports> element;
86 if (NS_FAILED(aEnumerator->GetNext(getter_AddRefs(element))))
87 break;
89 nsCOMPtr<nsISupportsCString> icStr = do_QueryInterface(element);
90 NS_ASSERTION(icStr,
91 "category manager entries must be nsISupportsCStrings");
93 nsCAutoString name;
94 icStr->GetData(name);
96 nsXPIDLCString spec;
97 aManager->GetCategoryEntry(aCategory, name.get(), getter_Copies(spec));
99 nsCOMPtr<nsIURI> uri;
100 NS_NewURI(getter_AddRefs(uri), spec);
101 if (uri)
102 LoadAndRegisterSheetInternal(uri, aSheetType);
106 PRInt32
107 nsStyleSheetService::FindSheetByURI(const nsCOMArray<nsIStyleSheet> &sheets,
108 nsIURI *sheetURI)
110 for (PRInt32 i = sheets.Count() - 1; i >= 0; i-- ) {
111 PRBool bEqual;
112 nsIURI* uri = sheets[i]->GetSheetURI();
113 if (uri
114 && NS_SUCCEEDED(uri->Equals(sheetURI, &bEqual))
115 && bEqual) {
116 return i;
120 return -1;
123 nsresult
124 nsStyleSheetService::Init()
126 // Enumerate all of the style sheet URIs registered in the category
127 // manager and load them.
129 nsCOMPtr<nsICategoryManager> catMan =
130 do_GetService(NS_CATEGORYMANAGER_CONTRACTID);
132 NS_ENSURE_TRUE(catMan, NS_ERROR_OUT_OF_MEMORY);
134 nsCOMPtr<nsISimpleEnumerator> sheets;
135 catMan->EnumerateCategory("agent-style-sheets", getter_AddRefs(sheets));
136 RegisterFromEnumerator(catMan, "agent-style-sheets", sheets, AGENT_SHEET);
138 catMan->EnumerateCategory("user-style-sheets", getter_AddRefs(sheets));
139 RegisterFromEnumerator(catMan, "user-style-sheets", sheets, USER_SHEET);
141 return NS_OK;
144 NS_IMETHODIMP
145 nsStyleSheetService::LoadAndRegisterSheet(nsIURI *aSheetURI,
146 PRUint32 aSheetType)
148 nsresult rv = LoadAndRegisterSheetInternal(aSheetURI, aSheetType);
149 if (NS_SUCCEEDED(rv)) {
150 const char* message = (aSheetType == AGENT_SHEET) ?
151 "agent-sheet-added" : "user-sheet-added";
152 nsCOMPtr<nsIObserverService> serv =
153 mozilla::services::GetObserverService();
154 if (serv) {
155 // We're guaranteed that the new sheet is the last sheet in
156 // mSheets[aSheetType]
157 const nsCOMArray<nsIStyleSheet> & sheets = mSheets[aSheetType];
158 serv->NotifyObservers(sheets[sheets.Count() - 1], message, nsnull);
161 return rv;
164 nsresult
165 nsStyleSheetService::LoadAndRegisterSheetInternal(nsIURI *aSheetURI,
166 PRUint32 aSheetType)
168 NS_ENSURE_ARG(aSheetType == AGENT_SHEET || aSheetType == USER_SHEET);
169 NS_ENSURE_ARG_POINTER(aSheetURI);
171 nsRefPtr<mozilla::css::Loader> loader = new mozilla::css::Loader();
172 NS_ENSURE_TRUE(loader, NS_ERROR_OUT_OF_MEMORY);
174 nsRefPtr<nsCSSStyleSheet> sheet;
175 // Allow UA sheets, but not user sheets, to use unsafe rules
176 nsresult rv = loader->LoadSheetSync(aSheetURI, aSheetType == AGENT_SHEET,
177 PR_TRUE, getter_AddRefs(sheet));
178 NS_ENSURE_SUCCESS(rv, rv);
180 if (!mSheets[aSheetType].AppendObject(sheet)) {
181 rv = NS_ERROR_OUT_OF_MEMORY;
184 return rv;
187 NS_IMETHODIMP
188 nsStyleSheetService::SheetRegistered(nsIURI *sheetURI,
189 PRUint32 aSheetType, PRBool *_retval)
191 NS_ENSURE_ARG(aSheetType == AGENT_SHEET || aSheetType == USER_SHEET);
192 NS_ENSURE_ARG_POINTER(sheetURI);
193 NS_PRECONDITION(_retval, "Null out param");
195 *_retval = (FindSheetByURI(mSheets[aSheetType], sheetURI) >= 0);
197 return NS_OK;
200 NS_IMETHODIMP
201 nsStyleSheetService::UnregisterSheet(nsIURI *sheetURI, PRUint32 aSheetType)
203 NS_ENSURE_ARG(aSheetType == AGENT_SHEET || aSheetType == USER_SHEET);
204 NS_ENSURE_ARG_POINTER(sheetURI);
206 PRInt32 foundIndex = FindSheetByURI(mSheets[aSheetType], sheetURI);
207 NS_ENSURE_TRUE(foundIndex >= 0, NS_ERROR_INVALID_ARG);
208 nsCOMPtr<nsIStyleSheet> sheet = mSheets[aSheetType][foundIndex];
209 mSheets[aSheetType].RemoveObjectAt(foundIndex);
211 const char* message = (aSheetType == AGENT_SHEET) ?
212 "agent-sheet-removed" : "user-sheet-removed";
213 nsCOMPtr<nsIObserverService> serv =
214 mozilla::services::GetObserverService();
215 if (serv)
216 serv->NotifyObservers(sheet, message, nsnull);
218 return NS_OK;