1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/layout/style/nsLayoutStylesheetCache.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,348 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include "nsLayoutStylesheetCache.h" 1.11 + 1.12 +#include "nsAppDirectoryServiceDefs.h" 1.13 +#include "mozilla/MemoryReporting.h" 1.14 +#include "mozilla/Preferences.h" 1.15 +#include "mozilla/css/Loader.h" 1.16 +#include "nsIFile.h" 1.17 +#include "nsNetUtil.h" 1.18 +#include "nsIObserverService.h" 1.19 +#include "nsServiceManagerUtils.h" 1.20 +#include "nsIXULRuntime.h" 1.21 +#include "nsCSSStyleSheet.h" 1.22 + 1.23 +using namespace mozilla; 1.24 + 1.25 +static bool sNumberControlEnabled; 1.26 + 1.27 +#define NUMBER_CONTROL_PREF "dom.forms.number" 1.28 + 1.29 +NS_IMPL_ISUPPORTS( 1.30 + nsLayoutStylesheetCache, nsIObserver, nsIMemoryReporter) 1.31 + 1.32 +nsresult 1.33 +nsLayoutStylesheetCache::Observe(nsISupports* aSubject, 1.34 + const char* aTopic, 1.35 + const char16_t* aData) 1.36 +{ 1.37 + if (!strcmp(aTopic, "profile-before-change")) { 1.38 + mUserContentSheet = nullptr; 1.39 + mUserChromeSheet = nullptr; 1.40 + } 1.41 + else if (!strcmp(aTopic, "profile-do-change")) { 1.42 + InitFromProfile(); 1.43 + } 1.44 + else if (strcmp(aTopic, "chrome-flush-skin-caches") == 0 || 1.45 + strcmp(aTopic, "chrome-flush-caches") == 0) { 1.46 + mScrollbarsSheet = nullptr; 1.47 + mFormsSheet = nullptr; 1.48 + mNumberControlSheet = nullptr; 1.49 + } 1.50 + else { 1.51 + NS_NOTREACHED("Unexpected observer topic."); 1.52 + } 1.53 + return NS_OK; 1.54 +} 1.55 + 1.56 +nsCSSStyleSheet* 1.57 +nsLayoutStylesheetCache::ScrollbarsSheet() 1.58 +{ 1.59 + EnsureGlobal(); 1.60 + if (!gStyleCache) 1.61 + return nullptr; 1.62 + 1.63 + if (!gStyleCache->mScrollbarsSheet) { 1.64 + nsCOMPtr<nsIURI> sheetURI; 1.65 + NS_NewURI(getter_AddRefs(sheetURI), 1.66 + NS_LITERAL_CSTRING("chrome://global/skin/scrollbars.css")); 1.67 + 1.68 + // Scrollbars don't need access to unsafe rules 1.69 + if (sheetURI) 1.70 + LoadSheet(sheetURI, gStyleCache->mScrollbarsSheet, false); 1.71 + NS_ASSERTION(gStyleCache->mScrollbarsSheet, "Could not load scrollbars.css."); 1.72 + } 1.73 + 1.74 + return gStyleCache->mScrollbarsSheet; 1.75 +} 1.76 + 1.77 +nsCSSStyleSheet* 1.78 +nsLayoutStylesheetCache::FormsSheet() 1.79 +{ 1.80 + EnsureGlobal(); 1.81 + if (!gStyleCache) 1.82 + return nullptr; 1.83 + 1.84 + if (!gStyleCache->mFormsSheet) { 1.85 + nsCOMPtr<nsIURI> sheetURI; 1.86 + NS_NewURI(getter_AddRefs(sheetURI), 1.87 + NS_LITERAL_CSTRING("resource://gre-resources/forms.css")); 1.88 + 1.89 + // forms.css needs access to unsafe rules 1.90 + if (sheetURI) 1.91 + LoadSheet(sheetURI, gStyleCache->mFormsSheet, true); 1.92 + 1.93 + NS_ASSERTION(gStyleCache->mFormsSheet, "Could not load forms.css."); 1.94 + } 1.95 + 1.96 + return gStyleCache->mFormsSheet; 1.97 +} 1.98 + 1.99 +nsCSSStyleSheet* 1.100 +nsLayoutStylesheetCache::NumberControlSheet() 1.101 +{ 1.102 + EnsureGlobal(); 1.103 + if (!gStyleCache) 1.104 + return nullptr; 1.105 + 1.106 + if (!sNumberControlEnabled) { 1.107 + return nullptr; 1.108 + } 1.109 + 1.110 + if (!gStyleCache->mNumberControlSheet) { 1.111 + nsCOMPtr<nsIURI> sheetURI; 1.112 + NS_NewURI(getter_AddRefs(sheetURI), 1.113 + NS_LITERAL_CSTRING("resource://gre-resources/number-control.css")); 1.114 + 1.115 + if (sheetURI) 1.116 + LoadSheet(sheetURI, gStyleCache->mNumberControlSheet, false); 1.117 + 1.118 + NS_ASSERTION(gStyleCache->mNumberControlSheet, "Could not load number-control.css"); 1.119 + } 1.120 + 1.121 + return gStyleCache->mNumberControlSheet; 1.122 +} 1.123 + 1.124 +nsCSSStyleSheet* 1.125 +nsLayoutStylesheetCache::UserContentSheet() 1.126 +{ 1.127 + EnsureGlobal(); 1.128 + if (!gStyleCache) 1.129 + return nullptr; 1.130 + 1.131 + return gStyleCache->mUserContentSheet; 1.132 +} 1.133 + 1.134 +nsCSSStyleSheet* 1.135 +nsLayoutStylesheetCache::UserChromeSheet() 1.136 +{ 1.137 + EnsureGlobal(); 1.138 + if (!gStyleCache) 1.139 + return nullptr; 1.140 + 1.141 + return gStyleCache->mUserChromeSheet; 1.142 +} 1.143 + 1.144 +nsCSSStyleSheet* 1.145 +nsLayoutStylesheetCache::UASheet() 1.146 +{ 1.147 + EnsureGlobal(); 1.148 + if (!gStyleCache) 1.149 + return nullptr; 1.150 + 1.151 + return gStyleCache->mUASheet; 1.152 +} 1.153 + 1.154 +nsCSSStyleSheet* 1.155 +nsLayoutStylesheetCache::QuirkSheet() 1.156 +{ 1.157 + EnsureGlobal(); 1.158 + if (!gStyleCache) 1.159 + return nullptr; 1.160 + 1.161 + return gStyleCache->mQuirkSheet; 1.162 +} 1.163 + 1.164 +nsCSSStyleSheet* 1.165 +nsLayoutStylesheetCache::FullScreenOverrideSheet() 1.166 +{ 1.167 + EnsureGlobal(); 1.168 + if (!gStyleCache) 1.169 + return nullptr; 1.170 + 1.171 + return gStyleCache->mFullScreenOverrideSheet; 1.172 +} 1.173 + 1.174 +void 1.175 +nsLayoutStylesheetCache::Shutdown() 1.176 +{ 1.177 + NS_IF_RELEASE(gCSSLoader); 1.178 + NS_IF_RELEASE(gStyleCache); 1.179 +} 1.180 + 1.181 +MOZ_DEFINE_MALLOC_SIZE_OF(LayoutStylesheetCacheMallocSizeOf) 1.182 + 1.183 +NS_IMETHODIMP 1.184 +nsLayoutStylesheetCache::CollectReports(nsIHandleReportCallback* aHandleReport, 1.185 + nsISupports* aData) 1.186 +{ 1.187 + return MOZ_COLLECT_REPORT( 1.188 + "explicit/layout/style-sheet-cache", KIND_HEAP, UNITS_BYTES, 1.189 + SizeOfIncludingThis(LayoutStylesheetCacheMallocSizeOf), 1.190 + "Memory used for some built-in style sheets."); 1.191 +} 1.192 + 1.193 + 1.194 +size_t 1.195 +nsLayoutStylesheetCache::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const 1.196 +{ 1.197 + size_t n = aMallocSizeOf(this); 1.198 + 1.199 + #define MEASURE(s) n += s ? s->SizeOfIncludingThis(aMallocSizeOf) : 0; 1.200 + 1.201 + MEASURE(mScrollbarsSheet); 1.202 + MEASURE(mFormsSheet); 1.203 + MEASURE(mNumberControlSheet); 1.204 + MEASURE(mUserContentSheet); 1.205 + MEASURE(mUserChromeSheet); 1.206 + MEASURE(mUASheet); 1.207 + MEASURE(mQuirkSheet); 1.208 + MEASURE(mFullScreenOverrideSheet); 1.209 + 1.210 + // Measurement of the following members may be added later if DMD finds it is 1.211 + // worthwhile: 1.212 + // - gCSSLoader 1.213 + 1.214 + return n; 1.215 +} 1.216 + 1.217 +nsLayoutStylesheetCache::nsLayoutStylesheetCache() 1.218 +{ 1.219 + nsCOMPtr<nsIObserverService> obsSvc = 1.220 + mozilla::services::GetObserverService(); 1.221 + NS_ASSERTION(obsSvc, "No global observer service?"); 1.222 + 1.223 + if (obsSvc) { 1.224 + obsSvc->AddObserver(this, "profile-before-change", false); 1.225 + obsSvc->AddObserver(this, "profile-do-change", false); 1.226 + obsSvc->AddObserver(this, "chrome-flush-skin-caches", false); 1.227 + obsSvc->AddObserver(this, "chrome-flush-caches", false); 1.228 + } 1.229 + 1.230 + InitFromProfile(); 1.231 + 1.232 + // And make sure that we load our UA sheets. No need to do this 1.233 + // per-profile, since they're profile-invariant. 1.234 + nsCOMPtr<nsIURI> uri; 1.235 + NS_NewURI(getter_AddRefs(uri), "resource://gre-resources/ua.css"); 1.236 + if (uri) { 1.237 + LoadSheet(uri, mUASheet, true); 1.238 + } 1.239 + NS_ASSERTION(mUASheet, "Could not load ua.css"); 1.240 + 1.241 + NS_NewURI(getter_AddRefs(uri), "resource://gre-resources/quirk.css"); 1.242 + if (uri) { 1.243 + LoadSheet(uri, mQuirkSheet, true); 1.244 + } 1.245 + NS_ASSERTION(mQuirkSheet, "Could not load quirk.css"); 1.246 + 1.247 + NS_NewURI(getter_AddRefs(uri), "resource://gre-resources/full-screen-override.css"); 1.248 + if (uri) { 1.249 + LoadSheet(uri, mFullScreenOverrideSheet, true); 1.250 + } 1.251 + NS_ASSERTION(mFullScreenOverrideSheet, "Could not load full-screen-override.css"); 1.252 +} 1.253 + 1.254 +nsLayoutStylesheetCache::~nsLayoutStylesheetCache() 1.255 +{ 1.256 + mozilla::UnregisterWeakMemoryReporter(this); 1.257 + gStyleCache = nullptr; 1.258 +} 1.259 + 1.260 +void 1.261 +nsLayoutStylesheetCache::InitMemoryReporter() 1.262 +{ 1.263 + mozilla::RegisterWeakMemoryReporter(this); 1.264 +} 1.265 + 1.266 +void 1.267 +nsLayoutStylesheetCache::EnsureGlobal() 1.268 +{ 1.269 + if (gStyleCache) return; 1.270 + 1.271 + gStyleCache = new nsLayoutStylesheetCache(); 1.272 + if (!gStyleCache) return; 1.273 + 1.274 + NS_ADDREF(gStyleCache); 1.275 + 1.276 + gStyleCache->InitMemoryReporter(); 1.277 + 1.278 + Preferences::AddBoolVarCache(&sNumberControlEnabled, NUMBER_CONTROL_PREF, 1.279 + true); 1.280 +} 1.281 + 1.282 +void 1.283 +nsLayoutStylesheetCache::InitFromProfile() 1.284 +{ 1.285 + nsCOMPtr<nsIXULRuntime> appInfo = do_GetService("@mozilla.org/xre/app-info;1"); 1.286 + if (appInfo) { 1.287 + bool inSafeMode = false; 1.288 + appInfo->GetInSafeMode(&inSafeMode); 1.289 + if (inSafeMode) 1.290 + return; 1.291 + } 1.292 + nsCOMPtr<nsIFile> contentFile; 1.293 + nsCOMPtr<nsIFile> chromeFile; 1.294 + 1.295 + NS_GetSpecialDirectory(NS_APP_USER_CHROME_DIR, 1.296 + getter_AddRefs(contentFile)); 1.297 + if (!contentFile) { 1.298 + // if we don't have a profile yet, that's OK! 1.299 + return; 1.300 + } 1.301 + 1.302 + contentFile->Clone(getter_AddRefs(chromeFile)); 1.303 + if (!chromeFile) return; 1.304 + 1.305 + contentFile->Append(NS_LITERAL_STRING("userContent.css")); 1.306 + chromeFile->Append(NS_LITERAL_STRING("userChrome.css")); 1.307 + 1.308 + LoadSheetFile(contentFile, mUserContentSheet); 1.309 + LoadSheetFile(chromeFile, mUserChromeSheet); 1.310 +} 1.311 + 1.312 +void 1.313 +nsLayoutStylesheetCache::LoadSheetFile(nsIFile* aFile, nsRefPtr<nsCSSStyleSheet> &aSheet) 1.314 +{ 1.315 + bool exists = false; 1.316 + aFile->Exists(&exists); 1.317 + 1.318 + if (!exists) return; 1.319 + 1.320 + nsCOMPtr<nsIURI> uri; 1.321 + NS_NewFileURI(getter_AddRefs(uri), aFile); 1.322 + 1.323 + LoadSheet(uri, aSheet, false); 1.324 +} 1.325 + 1.326 +void 1.327 +nsLayoutStylesheetCache::LoadSheet(nsIURI* aURI, 1.328 + nsRefPtr<nsCSSStyleSheet> &aSheet, 1.329 + bool aEnableUnsafeRules) 1.330 +{ 1.331 + if (!aURI) { 1.332 + NS_ERROR("Null URI. Out of memory?"); 1.333 + return; 1.334 + } 1.335 + 1.336 + if (!gCSSLoader) { 1.337 + gCSSLoader = new mozilla::css::Loader(); 1.338 + NS_IF_ADDREF(gCSSLoader); 1.339 + } 1.340 + 1.341 + if (gCSSLoader) { 1.342 + gCSSLoader->LoadSheetSync(aURI, aEnableUnsafeRules, true, 1.343 + getter_AddRefs(aSheet)); 1.344 + } 1.345 +} 1.346 + 1.347 +nsLayoutStylesheetCache* 1.348 +nsLayoutStylesheetCache::gStyleCache = nullptr; 1.349 + 1.350 +mozilla::css::Loader* 1.351 +nsLayoutStylesheetCache::gCSSLoader = nullptr;