1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is Mozilla.
16 : *
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.
21 : *
22 : * Contributor(s):
23 : * Brian Ryner <bryner@brianryner.com>
24 : *
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.
36 : *
37 : * ***** END LICENSE BLOCK ***** */
38 :
39 : /* implementation of interface for managing user and user-agent style sheets */
40 :
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"
55 :
56 : nsStyleSheetService *nsStyleSheetService::gInstance = nsnull;
57 :
58 0 : nsStyleSheetService::nsStyleSheetService()
59 : {
60 : PR_STATIC_ASSERT(0 == AGENT_SHEET && 1 == USER_SHEET);
61 0 : NS_ASSERTION(!gInstance, "Someone is using CreateInstance instead of GetService");
62 0 : gInstance = this;
63 0 : nsLayoutStatics::AddRef();
64 0 : }
65 :
66 0 : nsStyleSheetService::~nsStyleSheetService()
67 : {
68 0 : gInstance = nsnull;
69 0 : nsLayoutStatics::Release();
70 0 : }
71 :
72 0 : NS_IMPL_ISUPPORTS1(nsStyleSheetService, nsIStyleSheetService)
73 :
74 : void
75 0 : nsStyleSheetService::RegisterFromEnumerator(nsICategoryManager *aManager,
76 : const char *aCategory,
77 : nsISimpleEnumerator *aEnumerator,
78 : PRUint32 aSheetType)
79 : {
80 0 : if (!aEnumerator)
81 0 : return;
82 :
83 : bool hasMore;
84 0 : while (NS_SUCCEEDED(aEnumerator->HasMoreElements(&hasMore)) && hasMore) {
85 0 : nsCOMPtr<nsISupports> element;
86 0 : if (NS_FAILED(aEnumerator->GetNext(getter_AddRefs(element))))
87 : break;
88 :
89 0 : nsCOMPtr<nsISupportsCString> icStr = do_QueryInterface(element);
90 0 : NS_ASSERTION(icStr,
91 : "category manager entries must be nsISupportsCStrings");
92 :
93 0 : nsCAutoString name;
94 0 : icStr->GetData(name);
95 :
96 0 : nsXPIDLCString spec;
97 0 : aManager->GetCategoryEntry(aCategory, name.get(), getter_Copies(spec));
98 :
99 0 : nsCOMPtr<nsIURI> uri;
100 0 : NS_NewURI(getter_AddRefs(uri), spec);
101 0 : if (uri)
102 0 : LoadAndRegisterSheetInternal(uri, aSheetType);
103 : }
104 : }
105 :
106 : PRInt32
107 0 : nsStyleSheetService::FindSheetByURI(const nsCOMArray<nsIStyleSheet> &sheets,
108 : nsIURI *sheetURI)
109 : {
110 0 : for (PRInt32 i = sheets.Count() - 1; i >= 0; i-- ) {
111 : bool bEqual;
112 0 : nsIURI* uri = sheets[i]->GetSheetURI();
113 0 : if (uri
114 0 : && NS_SUCCEEDED(uri->Equals(sheetURI, &bEqual))
115 : && bEqual) {
116 0 : return i;
117 : }
118 : }
119 :
120 0 : return -1;
121 : }
122 :
123 : nsresult
124 0 : nsStyleSheetService::Init()
125 : {
126 : // Enumerate all of the style sheet URIs registered in the category
127 : // manager and load them.
128 :
129 : nsCOMPtr<nsICategoryManager> catMan =
130 0 : do_GetService(NS_CATEGORYMANAGER_CONTRACTID);
131 :
132 0 : NS_ENSURE_TRUE(catMan, NS_ERROR_OUT_OF_MEMORY);
133 :
134 0 : nsCOMPtr<nsISimpleEnumerator> sheets;
135 0 : catMan->EnumerateCategory("agent-style-sheets", getter_AddRefs(sheets));
136 0 : RegisterFromEnumerator(catMan, "agent-style-sheets", sheets, AGENT_SHEET);
137 :
138 0 : catMan->EnumerateCategory("user-style-sheets", getter_AddRefs(sheets));
139 0 : RegisterFromEnumerator(catMan, "user-style-sheets", sheets, USER_SHEET);
140 :
141 0 : return NS_OK;
142 : }
143 :
144 : NS_IMETHODIMP
145 0 : nsStyleSheetService::LoadAndRegisterSheet(nsIURI *aSheetURI,
146 : PRUint32 aSheetType)
147 : {
148 0 : nsresult rv = LoadAndRegisterSheetInternal(aSheetURI, aSheetType);
149 0 : if (NS_SUCCEEDED(rv)) {
150 : const char* message = (aSheetType == AGENT_SHEET) ?
151 0 : "agent-sheet-added" : "user-sheet-added";
152 : nsCOMPtr<nsIObserverService> serv =
153 0 : mozilla::services::GetObserverService();
154 0 : if (serv) {
155 : // We're guaranteed that the new sheet is the last sheet in
156 : // mSheets[aSheetType]
157 0 : const nsCOMArray<nsIStyleSheet> & sheets = mSheets[aSheetType];
158 0 : serv->NotifyObservers(sheets[sheets.Count() - 1], message, nsnull);
159 : }
160 : }
161 0 : return rv;
162 : }
163 :
164 : nsresult
165 0 : nsStyleSheetService::LoadAndRegisterSheetInternal(nsIURI *aSheetURI,
166 : PRUint32 aSheetType)
167 : {
168 0 : NS_ENSURE_ARG(aSheetType == AGENT_SHEET || aSheetType == USER_SHEET);
169 0 : NS_ENSURE_ARG_POINTER(aSheetURI);
170 :
171 0 : nsRefPtr<mozilla::css::Loader> loader = new mozilla::css::Loader();
172 :
173 0 : nsRefPtr<nsCSSStyleSheet> sheet;
174 : // Allow UA sheets, but not user sheets, to use unsafe rules
175 : nsresult rv = loader->LoadSheetSync(aSheetURI, aSheetType == AGENT_SHEET,
176 0 : true, getter_AddRefs(sheet));
177 0 : NS_ENSURE_SUCCESS(rv, rv);
178 :
179 0 : if (!mSheets[aSheetType].AppendObject(sheet)) {
180 0 : rv = NS_ERROR_OUT_OF_MEMORY;
181 : }
182 :
183 0 : return rv;
184 : }
185 :
186 : NS_IMETHODIMP
187 0 : nsStyleSheetService::SheetRegistered(nsIURI *sheetURI,
188 : PRUint32 aSheetType, bool *_retval)
189 : {
190 0 : NS_ENSURE_ARG(aSheetType == AGENT_SHEET || aSheetType == USER_SHEET);
191 0 : NS_ENSURE_ARG_POINTER(sheetURI);
192 0 : NS_PRECONDITION(_retval, "Null out param");
193 :
194 0 : *_retval = (FindSheetByURI(mSheets[aSheetType], sheetURI) >= 0);
195 :
196 0 : return NS_OK;
197 : }
198 :
199 : NS_IMETHODIMP
200 0 : nsStyleSheetService::UnregisterSheet(nsIURI *sheetURI, PRUint32 aSheetType)
201 : {
202 0 : NS_ENSURE_ARG(aSheetType == AGENT_SHEET || aSheetType == USER_SHEET);
203 0 : NS_ENSURE_ARG_POINTER(sheetURI);
204 :
205 0 : PRInt32 foundIndex = FindSheetByURI(mSheets[aSheetType], sheetURI);
206 0 : NS_ENSURE_TRUE(foundIndex >= 0, NS_ERROR_INVALID_ARG);
207 0 : nsCOMPtr<nsIStyleSheet> sheet = mSheets[aSheetType][foundIndex];
208 0 : mSheets[aSheetType].RemoveObjectAt(foundIndex);
209 :
210 : const char* message = (aSheetType == AGENT_SHEET) ?
211 0 : "agent-sheet-removed" : "user-sheet-removed";
212 : nsCOMPtr<nsIObserverService> serv =
213 0 : mozilla::services::GetObserverService();
214 0 : if (serv)
215 0 : serv->NotifyObservers(sheet, message, nsnull);
216 :
217 0 : return NS_OK;
218 : }
|