|
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ |
|
3 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
4 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
6 |
|
7 #include "nsLayoutStylesheetCache.h" |
|
8 |
|
9 #include "nsAppDirectoryServiceDefs.h" |
|
10 #include "mozilla/MemoryReporting.h" |
|
11 #include "mozilla/Preferences.h" |
|
12 #include "mozilla/css/Loader.h" |
|
13 #include "nsIFile.h" |
|
14 #include "nsNetUtil.h" |
|
15 #include "nsIObserverService.h" |
|
16 #include "nsServiceManagerUtils.h" |
|
17 #include "nsIXULRuntime.h" |
|
18 #include "nsCSSStyleSheet.h" |
|
19 |
|
20 using namespace mozilla; |
|
21 |
|
22 static bool sNumberControlEnabled; |
|
23 |
|
24 #define NUMBER_CONTROL_PREF "dom.forms.number" |
|
25 |
|
26 NS_IMPL_ISUPPORTS( |
|
27 nsLayoutStylesheetCache, nsIObserver, nsIMemoryReporter) |
|
28 |
|
29 nsresult |
|
30 nsLayoutStylesheetCache::Observe(nsISupports* aSubject, |
|
31 const char* aTopic, |
|
32 const char16_t* aData) |
|
33 { |
|
34 if (!strcmp(aTopic, "profile-before-change")) { |
|
35 mUserContentSheet = nullptr; |
|
36 mUserChromeSheet = nullptr; |
|
37 } |
|
38 else if (!strcmp(aTopic, "profile-do-change")) { |
|
39 InitFromProfile(); |
|
40 } |
|
41 else if (strcmp(aTopic, "chrome-flush-skin-caches") == 0 || |
|
42 strcmp(aTopic, "chrome-flush-caches") == 0) { |
|
43 mScrollbarsSheet = nullptr; |
|
44 mFormsSheet = nullptr; |
|
45 mNumberControlSheet = nullptr; |
|
46 } |
|
47 else { |
|
48 NS_NOTREACHED("Unexpected observer topic."); |
|
49 } |
|
50 return NS_OK; |
|
51 } |
|
52 |
|
53 nsCSSStyleSheet* |
|
54 nsLayoutStylesheetCache::ScrollbarsSheet() |
|
55 { |
|
56 EnsureGlobal(); |
|
57 if (!gStyleCache) |
|
58 return nullptr; |
|
59 |
|
60 if (!gStyleCache->mScrollbarsSheet) { |
|
61 nsCOMPtr<nsIURI> sheetURI; |
|
62 NS_NewURI(getter_AddRefs(sheetURI), |
|
63 NS_LITERAL_CSTRING("chrome://global/skin/scrollbars.css")); |
|
64 |
|
65 // Scrollbars don't need access to unsafe rules |
|
66 if (sheetURI) |
|
67 LoadSheet(sheetURI, gStyleCache->mScrollbarsSheet, false); |
|
68 NS_ASSERTION(gStyleCache->mScrollbarsSheet, "Could not load scrollbars.css."); |
|
69 } |
|
70 |
|
71 return gStyleCache->mScrollbarsSheet; |
|
72 } |
|
73 |
|
74 nsCSSStyleSheet* |
|
75 nsLayoutStylesheetCache::FormsSheet() |
|
76 { |
|
77 EnsureGlobal(); |
|
78 if (!gStyleCache) |
|
79 return nullptr; |
|
80 |
|
81 if (!gStyleCache->mFormsSheet) { |
|
82 nsCOMPtr<nsIURI> sheetURI; |
|
83 NS_NewURI(getter_AddRefs(sheetURI), |
|
84 NS_LITERAL_CSTRING("resource://gre-resources/forms.css")); |
|
85 |
|
86 // forms.css needs access to unsafe rules |
|
87 if (sheetURI) |
|
88 LoadSheet(sheetURI, gStyleCache->mFormsSheet, true); |
|
89 |
|
90 NS_ASSERTION(gStyleCache->mFormsSheet, "Could not load forms.css."); |
|
91 } |
|
92 |
|
93 return gStyleCache->mFormsSheet; |
|
94 } |
|
95 |
|
96 nsCSSStyleSheet* |
|
97 nsLayoutStylesheetCache::NumberControlSheet() |
|
98 { |
|
99 EnsureGlobal(); |
|
100 if (!gStyleCache) |
|
101 return nullptr; |
|
102 |
|
103 if (!sNumberControlEnabled) { |
|
104 return nullptr; |
|
105 } |
|
106 |
|
107 if (!gStyleCache->mNumberControlSheet) { |
|
108 nsCOMPtr<nsIURI> sheetURI; |
|
109 NS_NewURI(getter_AddRefs(sheetURI), |
|
110 NS_LITERAL_CSTRING("resource://gre-resources/number-control.css")); |
|
111 |
|
112 if (sheetURI) |
|
113 LoadSheet(sheetURI, gStyleCache->mNumberControlSheet, false); |
|
114 |
|
115 NS_ASSERTION(gStyleCache->mNumberControlSheet, "Could not load number-control.css"); |
|
116 } |
|
117 |
|
118 return gStyleCache->mNumberControlSheet; |
|
119 } |
|
120 |
|
121 nsCSSStyleSheet* |
|
122 nsLayoutStylesheetCache::UserContentSheet() |
|
123 { |
|
124 EnsureGlobal(); |
|
125 if (!gStyleCache) |
|
126 return nullptr; |
|
127 |
|
128 return gStyleCache->mUserContentSheet; |
|
129 } |
|
130 |
|
131 nsCSSStyleSheet* |
|
132 nsLayoutStylesheetCache::UserChromeSheet() |
|
133 { |
|
134 EnsureGlobal(); |
|
135 if (!gStyleCache) |
|
136 return nullptr; |
|
137 |
|
138 return gStyleCache->mUserChromeSheet; |
|
139 } |
|
140 |
|
141 nsCSSStyleSheet* |
|
142 nsLayoutStylesheetCache::UASheet() |
|
143 { |
|
144 EnsureGlobal(); |
|
145 if (!gStyleCache) |
|
146 return nullptr; |
|
147 |
|
148 return gStyleCache->mUASheet; |
|
149 } |
|
150 |
|
151 nsCSSStyleSheet* |
|
152 nsLayoutStylesheetCache::QuirkSheet() |
|
153 { |
|
154 EnsureGlobal(); |
|
155 if (!gStyleCache) |
|
156 return nullptr; |
|
157 |
|
158 return gStyleCache->mQuirkSheet; |
|
159 } |
|
160 |
|
161 nsCSSStyleSheet* |
|
162 nsLayoutStylesheetCache::FullScreenOverrideSheet() |
|
163 { |
|
164 EnsureGlobal(); |
|
165 if (!gStyleCache) |
|
166 return nullptr; |
|
167 |
|
168 return gStyleCache->mFullScreenOverrideSheet; |
|
169 } |
|
170 |
|
171 void |
|
172 nsLayoutStylesheetCache::Shutdown() |
|
173 { |
|
174 NS_IF_RELEASE(gCSSLoader); |
|
175 NS_IF_RELEASE(gStyleCache); |
|
176 } |
|
177 |
|
178 MOZ_DEFINE_MALLOC_SIZE_OF(LayoutStylesheetCacheMallocSizeOf) |
|
179 |
|
180 NS_IMETHODIMP |
|
181 nsLayoutStylesheetCache::CollectReports(nsIHandleReportCallback* aHandleReport, |
|
182 nsISupports* aData) |
|
183 { |
|
184 return MOZ_COLLECT_REPORT( |
|
185 "explicit/layout/style-sheet-cache", KIND_HEAP, UNITS_BYTES, |
|
186 SizeOfIncludingThis(LayoutStylesheetCacheMallocSizeOf), |
|
187 "Memory used for some built-in style sheets."); |
|
188 } |
|
189 |
|
190 |
|
191 size_t |
|
192 nsLayoutStylesheetCache::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const |
|
193 { |
|
194 size_t n = aMallocSizeOf(this); |
|
195 |
|
196 #define MEASURE(s) n += s ? s->SizeOfIncludingThis(aMallocSizeOf) : 0; |
|
197 |
|
198 MEASURE(mScrollbarsSheet); |
|
199 MEASURE(mFormsSheet); |
|
200 MEASURE(mNumberControlSheet); |
|
201 MEASURE(mUserContentSheet); |
|
202 MEASURE(mUserChromeSheet); |
|
203 MEASURE(mUASheet); |
|
204 MEASURE(mQuirkSheet); |
|
205 MEASURE(mFullScreenOverrideSheet); |
|
206 |
|
207 // Measurement of the following members may be added later if DMD finds it is |
|
208 // worthwhile: |
|
209 // - gCSSLoader |
|
210 |
|
211 return n; |
|
212 } |
|
213 |
|
214 nsLayoutStylesheetCache::nsLayoutStylesheetCache() |
|
215 { |
|
216 nsCOMPtr<nsIObserverService> obsSvc = |
|
217 mozilla::services::GetObserverService(); |
|
218 NS_ASSERTION(obsSvc, "No global observer service?"); |
|
219 |
|
220 if (obsSvc) { |
|
221 obsSvc->AddObserver(this, "profile-before-change", false); |
|
222 obsSvc->AddObserver(this, "profile-do-change", false); |
|
223 obsSvc->AddObserver(this, "chrome-flush-skin-caches", false); |
|
224 obsSvc->AddObserver(this, "chrome-flush-caches", false); |
|
225 } |
|
226 |
|
227 InitFromProfile(); |
|
228 |
|
229 // And make sure that we load our UA sheets. No need to do this |
|
230 // per-profile, since they're profile-invariant. |
|
231 nsCOMPtr<nsIURI> uri; |
|
232 NS_NewURI(getter_AddRefs(uri), "resource://gre-resources/ua.css"); |
|
233 if (uri) { |
|
234 LoadSheet(uri, mUASheet, true); |
|
235 } |
|
236 NS_ASSERTION(mUASheet, "Could not load ua.css"); |
|
237 |
|
238 NS_NewURI(getter_AddRefs(uri), "resource://gre-resources/quirk.css"); |
|
239 if (uri) { |
|
240 LoadSheet(uri, mQuirkSheet, true); |
|
241 } |
|
242 NS_ASSERTION(mQuirkSheet, "Could not load quirk.css"); |
|
243 |
|
244 NS_NewURI(getter_AddRefs(uri), "resource://gre-resources/full-screen-override.css"); |
|
245 if (uri) { |
|
246 LoadSheet(uri, mFullScreenOverrideSheet, true); |
|
247 } |
|
248 NS_ASSERTION(mFullScreenOverrideSheet, "Could not load full-screen-override.css"); |
|
249 } |
|
250 |
|
251 nsLayoutStylesheetCache::~nsLayoutStylesheetCache() |
|
252 { |
|
253 mozilla::UnregisterWeakMemoryReporter(this); |
|
254 gStyleCache = nullptr; |
|
255 } |
|
256 |
|
257 void |
|
258 nsLayoutStylesheetCache::InitMemoryReporter() |
|
259 { |
|
260 mozilla::RegisterWeakMemoryReporter(this); |
|
261 } |
|
262 |
|
263 void |
|
264 nsLayoutStylesheetCache::EnsureGlobal() |
|
265 { |
|
266 if (gStyleCache) return; |
|
267 |
|
268 gStyleCache = new nsLayoutStylesheetCache(); |
|
269 if (!gStyleCache) return; |
|
270 |
|
271 NS_ADDREF(gStyleCache); |
|
272 |
|
273 gStyleCache->InitMemoryReporter(); |
|
274 |
|
275 Preferences::AddBoolVarCache(&sNumberControlEnabled, NUMBER_CONTROL_PREF, |
|
276 true); |
|
277 } |
|
278 |
|
279 void |
|
280 nsLayoutStylesheetCache::InitFromProfile() |
|
281 { |
|
282 nsCOMPtr<nsIXULRuntime> appInfo = do_GetService("@mozilla.org/xre/app-info;1"); |
|
283 if (appInfo) { |
|
284 bool inSafeMode = false; |
|
285 appInfo->GetInSafeMode(&inSafeMode); |
|
286 if (inSafeMode) |
|
287 return; |
|
288 } |
|
289 nsCOMPtr<nsIFile> contentFile; |
|
290 nsCOMPtr<nsIFile> chromeFile; |
|
291 |
|
292 NS_GetSpecialDirectory(NS_APP_USER_CHROME_DIR, |
|
293 getter_AddRefs(contentFile)); |
|
294 if (!contentFile) { |
|
295 // if we don't have a profile yet, that's OK! |
|
296 return; |
|
297 } |
|
298 |
|
299 contentFile->Clone(getter_AddRefs(chromeFile)); |
|
300 if (!chromeFile) return; |
|
301 |
|
302 contentFile->Append(NS_LITERAL_STRING("userContent.css")); |
|
303 chromeFile->Append(NS_LITERAL_STRING("userChrome.css")); |
|
304 |
|
305 LoadSheetFile(contentFile, mUserContentSheet); |
|
306 LoadSheetFile(chromeFile, mUserChromeSheet); |
|
307 } |
|
308 |
|
309 void |
|
310 nsLayoutStylesheetCache::LoadSheetFile(nsIFile* aFile, nsRefPtr<nsCSSStyleSheet> &aSheet) |
|
311 { |
|
312 bool exists = false; |
|
313 aFile->Exists(&exists); |
|
314 |
|
315 if (!exists) return; |
|
316 |
|
317 nsCOMPtr<nsIURI> uri; |
|
318 NS_NewFileURI(getter_AddRefs(uri), aFile); |
|
319 |
|
320 LoadSheet(uri, aSheet, false); |
|
321 } |
|
322 |
|
323 void |
|
324 nsLayoutStylesheetCache::LoadSheet(nsIURI* aURI, |
|
325 nsRefPtr<nsCSSStyleSheet> &aSheet, |
|
326 bool aEnableUnsafeRules) |
|
327 { |
|
328 if (!aURI) { |
|
329 NS_ERROR("Null URI. Out of memory?"); |
|
330 return; |
|
331 } |
|
332 |
|
333 if (!gCSSLoader) { |
|
334 gCSSLoader = new mozilla::css::Loader(); |
|
335 NS_IF_ADDREF(gCSSLoader); |
|
336 } |
|
337 |
|
338 if (gCSSLoader) { |
|
339 gCSSLoader->LoadSheetSync(aURI, aEnableUnsafeRules, true, |
|
340 getter_AddRefs(aSheet)); |
|
341 } |
|
342 } |
|
343 |
|
344 nsLayoutStylesheetCache* |
|
345 nsLayoutStylesheetCache::gStyleCache = nullptr; |
|
346 |
|
347 mozilla::css::Loader* |
|
348 nsLayoutStylesheetCache::gCSSLoader = nullptr; |