1 : /* -*- Mode: C++; tab-width: 8; 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 Gecko Layout
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Benjamin Smedberg <bsmedberg@covad.net>
19 : * Portions created by the Initial Developer are Copyright (C) 2004
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either the GNU General Public License Version 2 or later (the "GPL"), or
26 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 :
38 : #include "nsLayoutStylesheetCache.h"
39 :
40 : #include "nsAppDirectoryServiceDefs.h"
41 : #include "mozilla/css/Loader.h"
42 : #include "nsIFile.h"
43 : #include "nsLayoutCID.h"
44 : #include "nsIMemoryReporter.h"
45 : #include "nsNetUtil.h"
46 : #include "nsIObserverService.h"
47 : #include "nsServiceManagerUtils.h"
48 : #include "nsIXULRuntime.h"
49 : #include "nsCSSStyleSheet.h"
50 :
51 0 : NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(LayoutStyleSheetCacheMallocSizeOf,
52 : "layout/style-sheet-cache")
53 :
54 : static PRInt64
55 0 : GetStylesheetCacheSize()
56 : {
57 : return nsLayoutStylesheetCache::SizeOfIncludingThis(
58 0 : LayoutStyleSheetCacheMallocSizeOf);
59 : }
60 :
61 0 : NS_MEMORY_REPORTER_IMPLEMENT(Sheets,
62 : "explicit/layout/style-sheet-cache",
63 : KIND_HEAP,
64 : nsIMemoryReporter::UNITS_BYTES,
65 : GetStylesheetCacheSize,
66 0 : "Memory used for some built-in style sheets.")
67 :
68 0 : NS_IMPL_ISUPPORTS1(nsLayoutStylesheetCache, nsIObserver)
69 :
70 : nsresult
71 0 : nsLayoutStylesheetCache::Observe(nsISupports* aSubject,
72 : const char* aTopic,
73 : const PRUnichar* aData)
74 : {
75 0 : if (!strcmp(aTopic, "profile-before-change")) {
76 0 : mUserContentSheet = nsnull;
77 0 : mUserChromeSheet = nsnull;
78 : }
79 0 : else if (!strcmp(aTopic, "profile-do-change")) {
80 0 : InitFromProfile();
81 : }
82 0 : else if (strcmp(aTopic, "chrome-flush-skin-caches") == 0 ||
83 0 : strcmp(aTopic, "chrome-flush-caches") == 0) {
84 0 : mScrollbarsSheet = nsnull;
85 0 : mFormsSheet = nsnull;
86 : }
87 : else {
88 0 : NS_NOTREACHED("Unexpected observer topic.");
89 : }
90 0 : return NS_OK;
91 : }
92 :
93 : nsCSSStyleSheet*
94 0 : nsLayoutStylesheetCache::ScrollbarsSheet()
95 : {
96 0 : EnsureGlobal();
97 0 : if (!gStyleCache)
98 0 : return nsnull;
99 :
100 0 : if (!gStyleCache->mScrollbarsSheet) {
101 0 : nsCOMPtr<nsIURI> sheetURI;
102 0 : NS_NewURI(getter_AddRefs(sheetURI),
103 0 : NS_LITERAL_CSTRING("chrome://global/skin/scrollbars.css"));
104 :
105 : // Scrollbars don't need access to unsafe rules
106 0 : if (sheetURI)
107 0 : LoadSheet(sheetURI, gStyleCache->mScrollbarsSheet, false);
108 0 : NS_ASSERTION(gStyleCache->mScrollbarsSheet, "Could not load scrollbars.css.");
109 : }
110 :
111 0 : return gStyleCache->mScrollbarsSheet;
112 : }
113 :
114 : nsCSSStyleSheet*
115 0 : nsLayoutStylesheetCache::FormsSheet()
116 : {
117 0 : EnsureGlobal();
118 0 : if (!gStyleCache)
119 0 : return nsnull;
120 :
121 0 : if (!gStyleCache->mFormsSheet) {
122 0 : nsCOMPtr<nsIURI> sheetURI;
123 0 : NS_NewURI(getter_AddRefs(sheetURI),
124 0 : NS_LITERAL_CSTRING("resource://gre-resources/forms.css"));
125 :
126 : // forms.css needs access to unsafe rules
127 0 : if (sheetURI)
128 0 : LoadSheet(sheetURI, gStyleCache->mFormsSheet, true);
129 :
130 0 : NS_ASSERTION(gStyleCache->mFormsSheet, "Could not load forms.css.");
131 : }
132 :
133 0 : return gStyleCache->mFormsSheet;
134 : }
135 :
136 : nsCSSStyleSheet*
137 0 : nsLayoutStylesheetCache::UserContentSheet()
138 : {
139 0 : EnsureGlobal();
140 0 : if (!gStyleCache)
141 0 : return nsnull;
142 :
143 0 : return gStyleCache->mUserContentSheet;
144 : }
145 :
146 : nsCSSStyleSheet*
147 0 : nsLayoutStylesheetCache::UserChromeSheet()
148 : {
149 0 : EnsureGlobal();
150 0 : if (!gStyleCache)
151 0 : return nsnull;
152 :
153 0 : return gStyleCache->mUserChromeSheet;
154 : }
155 :
156 : nsCSSStyleSheet*
157 0 : nsLayoutStylesheetCache::UASheet()
158 : {
159 0 : EnsureGlobal();
160 0 : if (!gStyleCache)
161 0 : return nsnull;
162 :
163 0 : return gStyleCache->mUASheet;
164 : }
165 :
166 : nsCSSStyleSheet*
167 0 : nsLayoutStylesheetCache::QuirkSheet()
168 : {
169 0 : EnsureGlobal();
170 0 : if (!gStyleCache)
171 0 : return nsnull;
172 :
173 0 : return gStyleCache->mQuirkSheet;
174 : }
175 :
176 : nsCSSStyleSheet*
177 0 : nsLayoutStylesheetCache::FullScreenOverrideSheet()
178 : {
179 0 : EnsureGlobal();
180 0 : if (!gStyleCache)
181 0 : return nsnull;
182 :
183 0 : return gStyleCache->mFullScreenOverrideSheet;
184 : }
185 :
186 : void
187 1403 : nsLayoutStylesheetCache::Shutdown()
188 : {
189 1403 : NS_IF_RELEASE(gCSSLoader);
190 1403 : NS_IF_RELEASE(gStyleCache);
191 1403 : }
192 :
193 : size_t
194 0 : nsLayoutStylesheetCache::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf)
195 : {
196 0 : if (nsLayoutStylesheetCache::gStyleCache) {
197 : return nsLayoutStylesheetCache::gStyleCache->
198 0 : SizeOfIncludingThisHelper(aMallocSizeOf);
199 : }
200 0 : return 0;
201 : }
202 :
203 : size_t
204 0 : nsLayoutStylesheetCache::SizeOfIncludingThisHelper(nsMallocSizeOfFun aMallocSizeOf) const
205 : {
206 0 : size_t n = aMallocSizeOf(this);
207 :
208 : #define MEASURE(s) n += s ? s->SizeOfIncludingThis(aMallocSizeOf) : 0;
209 :
210 0 : MEASURE(mScrollbarsSheet);
211 0 : MEASURE(mFormsSheet);
212 0 : MEASURE(mUserContentSheet);
213 0 : MEASURE(mUserChromeSheet);
214 0 : MEASURE(mUASheet);
215 0 : MEASURE(mQuirkSheet);
216 0 : MEASURE(mFullScreenOverrideSheet);
217 :
218 : // Measurement of the following members may be added later if DMD finds it is
219 : // worthwhile:
220 : // - gCSSLoader
221 :
222 0 : return n;
223 : }
224 :
225 0 : nsLayoutStylesheetCache::nsLayoutStylesheetCache()
226 : {
227 : nsCOMPtr<nsIObserverService> obsSvc =
228 0 : mozilla::services::GetObserverService();
229 0 : NS_ASSERTION(obsSvc, "No global observer service?");
230 :
231 0 : if (obsSvc) {
232 0 : obsSvc->AddObserver(this, "profile-before-change", false);
233 0 : obsSvc->AddObserver(this, "profile-do-change", false);
234 0 : obsSvc->AddObserver(this, "chrome-flush-skin-caches", false);
235 0 : obsSvc->AddObserver(this, "chrome-flush-caches", false);
236 : }
237 :
238 0 : InitFromProfile();
239 :
240 : // And make sure that we load our UA sheets. No need to do this
241 : // per-profile, since they're profile-invariant.
242 0 : nsCOMPtr<nsIURI> uri;
243 0 : NS_NewURI(getter_AddRefs(uri), "resource://gre-resources/ua.css");
244 0 : if (uri) {
245 0 : LoadSheet(uri, mUASheet, true);
246 : }
247 0 : NS_ASSERTION(mUASheet, "Could not load ua.css");
248 :
249 0 : NS_NewURI(getter_AddRefs(uri), "resource://gre-resources/quirk.css");
250 0 : if (uri) {
251 0 : LoadSheet(uri, mQuirkSheet, true);
252 : }
253 0 : NS_ASSERTION(mQuirkSheet, "Could not load quirk.css");
254 :
255 0 : NS_NewURI(getter_AddRefs(uri), "resource://gre-resources/full-screen-override.css");
256 0 : if (uri) {
257 0 : LoadSheet(uri, mFullScreenOverrideSheet, true);
258 : }
259 0 : NS_ASSERTION(mFullScreenOverrideSheet, "Could not load full-screen-override.css");
260 :
261 0 : mSheetsReporter = new NS_MEMORY_REPORTER_NAME(Sheets);
262 0 : (void)::NS_RegisterMemoryReporter(mSheetsReporter);
263 0 : }
264 :
265 0 : nsLayoutStylesheetCache::~nsLayoutStylesheetCache()
266 : {
267 0 : (void)::NS_UnregisterMemoryReporter(mSheetsReporter);
268 0 : mSheetsReporter = nsnull;
269 0 : }
270 :
271 : void
272 0 : nsLayoutStylesheetCache::EnsureGlobal()
273 : {
274 0 : if (gStyleCache) return;
275 :
276 0 : gStyleCache = new nsLayoutStylesheetCache();
277 0 : if (!gStyleCache) return;
278 :
279 0 : NS_ADDREF(gStyleCache);
280 : }
281 :
282 : void
283 0 : nsLayoutStylesheetCache::InitFromProfile()
284 : {
285 0 : nsCOMPtr<nsIXULRuntime> appInfo = do_GetService("@mozilla.org/xre/app-info;1");
286 0 : if (appInfo) {
287 0 : bool inSafeMode = false;
288 0 : appInfo->GetInSafeMode(&inSafeMode);
289 0 : if (inSafeMode)
290 : return;
291 : }
292 0 : nsCOMPtr<nsIFile> contentFile;
293 0 : nsCOMPtr<nsIFile> chromeFile;
294 :
295 : NS_GetSpecialDirectory(NS_APP_USER_CHROME_DIR,
296 0 : getter_AddRefs(contentFile));
297 0 : if (!contentFile) {
298 : // if we don't have a profile yet, that's OK!
299 : return;
300 : }
301 :
302 0 : contentFile->Clone(getter_AddRefs(chromeFile));
303 0 : if (!chromeFile) return;
304 :
305 0 : contentFile->Append(NS_LITERAL_STRING("userContent.css"));
306 0 : chromeFile->Append(NS_LITERAL_STRING("userChrome.css"));
307 :
308 0 : LoadSheetFile(contentFile, mUserContentSheet);
309 0 : LoadSheetFile(chromeFile, mUserChromeSheet);
310 : }
311 :
312 : void
313 0 : nsLayoutStylesheetCache::LoadSheetFile(nsIFile* aFile, nsRefPtr<nsCSSStyleSheet> &aSheet)
314 : {
315 0 : bool exists = false;
316 0 : aFile->Exists(&exists);
317 :
318 0 : if (!exists) return;
319 :
320 0 : nsCOMPtr<nsIURI> uri;
321 0 : NS_NewFileURI(getter_AddRefs(uri), aFile);
322 :
323 0 : LoadSheet(uri, aSheet, false);
324 : }
325 :
326 : void
327 0 : nsLayoutStylesheetCache::LoadSheet(nsIURI* aURI,
328 : nsRefPtr<nsCSSStyleSheet> &aSheet,
329 : bool aEnableUnsafeRules)
330 : {
331 0 : if (!aURI) {
332 0 : NS_ERROR("Null URI. Out of memory?");
333 0 : return;
334 : }
335 :
336 0 : if (!gCSSLoader) {
337 0 : gCSSLoader = new mozilla::css::Loader();
338 0 : NS_IF_ADDREF(gCSSLoader);
339 : }
340 :
341 0 : if (gCSSLoader) {
342 : gCSSLoader->LoadSheetSync(aURI, aEnableUnsafeRules, true,
343 0 : getter_AddRefs(aSheet));
344 : }
345 : }
346 :
347 : nsLayoutStylesheetCache*
348 : nsLayoutStylesheetCache::gStyleCache = nsnull;
349 :
350 : mozilla::css::Loader*
351 : nsLayoutStylesheetCache::gCSSLoader = nsnull;
|