1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/layout/base/nsStyleSheetService.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,310 @@ 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 +/* implementation of interface for managing user and user-agent style sheets */ 1.11 + 1.12 +#include "nsStyleSheetService.h" 1.13 +#include "nsIStyleSheet.h" 1.14 +#include "mozilla/MemoryReporting.h" 1.15 +#include "mozilla/unused.h" 1.16 +#include "mozilla/css/Loader.h" 1.17 +#include "mozilla/dom/ContentParent.h" 1.18 +#include "mozilla/ipc/URIUtils.h" 1.19 +#include "nsCSSStyleSheet.h" 1.20 +#include "nsIURI.h" 1.21 +#include "nsCOMPtr.h" 1.22 +#include "nsICategoryManager.h" 1.23 +#include "nsISupportsPrimitives.h" 1.24 +#include "nsNetUtil.h" 1.25 +#include "nsIObserverService.h" 1.26 +#include "nsLayoutStatics.h" 1.27 + 1.28 +using namespace mozilla; 1.29 + 1.30 +nsStyleSheetService *nsStyleSheetService::gInstance = nullptr; 1.31 + 1.32 +nsStyleSheetService::nsStyleSheetService() 1.33 +{ 1.34 + PR_STATIC_ASSERT(0 == AGENT_SHEET && 1 == USER_SHEET && 2 == AUTHOR_SHEET); 1.35 + NS_ASSERTION(!gInstance, "Someone is using CreateInstance instead of GetService"); 1.36 + gInstance = this; 1.37 + nsLayoutStatics::AddRef(); 1.38 +} 1.39 + 1.40 +nsStyleSheetService::~nsStyleSheetService() 1.41 +{ 1.42 + UnregisterWeakMemoryReporter(this); 1.43 + 1.44 + gInstance = nullptr; 1.45 + nsLayoutStatics::Release(); 1.46 +} 1.47 + 1.48 +NS_IMPL_ISUPPORTS( 1.49 + nsStyleSheetService, nsIStyleSheetService, nsIMemoryReporter) 1.50 + 1.51 +void 1.52 +nsStyleSheetService::RegisterFromEnumerator(nsICategoryManager *aManager, 1.53 + const char *aCategory, 1.54 + nsISimpleEnumerator *aEnumerator, 1.55 + uint32_t aSheetType) 1.56 +{ 1.57 + if (!aEnumerator) 1.58 + return; 1.59 + 1.60 + bool hasMore; 1.61 + while (NS_SUCCEEDED(aEnumerator->HasMoreElements(&hasMore)) && hasMore) { 1.62 + nsCOMPtr<nsISupports> element; 1.63 + if (NS_FAILED(aEnumerator->GetNext(getter_AddRefs(element)))) 1.64 + break; 1.65 + 1.66 + nsCOMPtr<nsISupportsCString> icStr = do_QueryInterface(element); 1.67 + NS_ASSERTION(icStr, 1.68 + "category manager entries must be nsISupportsCStrings"); 1.69 + 1.70 + nsAutoCString name; 1.71 + icStr->GetData(name); 1.72 + 1.73 + nsXPIDLCString spec; 1.74 + aManager->GetCategoryEntry(aCategory, name.get(), getter_Copies(spec)); 1.75 + 1.76 + nsCOMPtr<nsIURI> uri; 1.77 + NS_NewURI(getter_AddRefs(uri), spec); 1.78 + if (uri) 1.79 + LoadAndRegisterSheetInternal(uri, aSheetType); 1.80 + } 1.81 +} 1.82 + 1.83 +int32_t 1.84 +nsStyleSheetService::FindSheetByURI(const nsCOMArray<nsIStyleSheet> &sheets, 1.85 + nsIURI *sheetURI) 1.86 +{ 1.87 + for (int32_t i = sheets.Count() - 1; i >= 0; i-- ) { 1.88 + bool bEqual; 1.89 + nsIURI* uri = sheets[i]->GetSheetURI(); 1.90 + if (uri 1.91 + && NS_SUCCEEDED(uri->Equals(sheetURI, &bEqual)) 1.92 + && bEqual) { 1.93 + return i; 1.94 + } 1.95 + } 1.96 + 1.97 + return -1; 1.98 +} 1.99 + 1.100 +nsresult 1.101 +nsStyleSheetService::Init() 1.102 +{ 1.103 + // Child processes get their style sheets from the ContentParent. 1.104 + if (XRE_GetProcessType() == GeckoProcessType_Content) { 1.105 + return NS_OK; 1.106 + } 1.107 + 1.108 + // Enumerate all of the style sheet URIs registered in the category 1.109 + // manager and load them. 1.110 + 1.111 + nsCOMPtr<nsICategoryManager> catMan = 1.112 + do_GetService(NS_CATEGORYMANAGER_CONTRACTID); 1.113 + 1.114 + NS_ENSURE_TRUE(catMan, NS_ERROR_OUT_OF_MEMORY); 1.115 + 1.116 + nsCOMPtr<nsISimpleEnumerator> sheets; 1.117 + catMan->EnumerateCategory("agent-style-sheets", getter_AddRefs(sheets)); 1.118 + RegisterFromEnumerator(catMan, "agent-style-sheets", sheets, AGENT_SHEET); 1.119 + 1.120 + catMan->EnumerateCategory("user-style-sheets", getter_AddRefs(sheets)); 1.121 + RegisterFromEnumerator(catMan, "user-style-sheets", sheets, USER_SHEET); 1.122 + 1.123 + catMan->EnumerateCategory("author-style-sheets", getter_AddRefs(sheets)); 1.124 + RegisterFromEnumerator(catMan, "author-style-sheets", sheets, AUTHOR_SHEET); 1.125 + 1.126 + RegisterWeakMemoryReporter(this); 1.127 + 1.128 + return NS_OK; 1.129 +} 1.130 + 1.131 +NS_IMETHODIMP 1.132 +nsStyleSheetService::LoadAndRegisterSheet(nsIURI *aSheetURI, 1.133 + uint32_t aSheetType) 1.134 +{ 1.135 + nsresult rv = LoadAndRegisterSheetInternal(aSheetURI, aSheetType); 1.136 + if (NS_SUCCEEDED(rv)) { 1.137 + const char* message; 1.138 + switch (aSheetType) { 1.139 + case AGENT_SHEET: 1.140 + message = "agent-sheet-added"; 1.141 + break; 1.142 + case USER_SHEET: 1.143 + message = "user-sheet-added"; 1.144 + break; 1.145 + case AUTHOR_SHEET: 1.146 + message = "author-sheet-added"; 1.147 + break; 1.148 + default: 1.149 + return NS_ERROR_INVALID_ARG; 1.150 + } 1.151 + nsCOMPtr<nsIObserverService> serv = services::GetObserverService(); 1.152 + if (serv) { 1.153 + // We're guaranteed that the new sheet is the last sheet in 1.154 + // mSheets[aSheetType] 1.155 + const nsCOMArray<nsIStyleSheet> & sheets = mSheets[aSheetType]; 1.156 + serv->NotifyObservers(sheets[sheets.Count() - 1], message, nullptr); 1.157 + } 1.158 + 1.159 + if (XRE_GetProcessType() == GeckoProcessType_Default) { 1.160 + nsTArray<dom::ContentParent*> children; 1.161 + dom::ContentParent::GetAll(children); 1.162 + 1.163 + if (children.IsEmpty()) { 1.164 + return rv; 1.165 + } 1.166 + 1.167 + mozilla::ipc::URIParams uri; 1.168 + SerializeURI(aSheetURI, uri); 1.169 + 1.170 + for (uint32_t i = 0; i < children.Length(); i++) { 1.171 + unused << children[i]->SendLoadAndRegisterSheet(uri, aSheetType); 1.172 + } 1.173 + } 1.174 + } 1.175 + return rv; 1.176 +} 1.177 + 1.178 +nsresult 1.179 +nsStyleSheetService::LoadAndRegisterSheetInternal(nsIURI *aSheetURI, 1.180 + uint32_t aSheetType) 1.181 +{ 1.182 + NS_ENSURE_ARG(aSheetType == AGENT_SHEET || 1.183 + aSheetType == USER_SHEET || 1.184 + aSheetType == AUTHOR_SHEET); 1.185 + NS_ENSURE_ARG_POINTER(aSheetURI); 1.186 + 1.187 + nsRefPtr<css::Loader> loader = new css::Loader(); 1.188 + 1.189 + nsRefPtr<nsCSSStyleSheet> sheet; 1.190 + // Allow UA sheets, but not user sheets, to use unsafe rules 1.191 + nsresult rv = loader->LoadSheetSync(aSheetURI, aSheetType == AGENT_SHEET, 1.192 + true, getter_AddRefs(sheet)); 1.193 + NS_ENSURE_SUCCESS(rv, rv); 1.194 + 1.195 + if (!mSheets[aSheetType].AppendObject(sheet)) { 1.196 + rv = NS_ERROR_OUT_OF_MEMORY; 1.197 + } 1.198 + 1.199 + return rv; 1.200 +} 1.201 + 1.202 +NS_IMETHODIMP 1.203 +nsStyleSheetService::SheetRegistered(nsIURI *sheetURI, 1.204 + uint32_t aSheetType, bool *_retval) 1.205 +{ 1.206 + NS_ENSURE_ARG(aSheetType == AGENT_SHEET || 1.207 + aSheetType == USER_SHEET || 1.208 + aSheetType == AUTHOR_SHEET); 1.209 + NS_ENSURE_ARG_POINTER(sheetURI); 1.210 + NS_PRECONDITION(_retval, "Null out param"); 1.211 + 1.212 + *_retval = (FindSheetByURI(mSheets[aSheetType], sheetURI) >= 0); 1.213 + 1.214 + return NS_OK; 1.215 +} 1.216 + 1.217 +NS_IMETHODIMP 1.218 +nsStyleSheetService::UnregisterSheet(nsIURI *aSheetURI, uint32_t aSheetType) 1.219 +{ 1.220 + NS_ENSURE_ARG(aSheetType == AGENT_SHEET || 1.221 + aSheetType == USER_SHEET || 1.222 + aSheetType == AUTHOR_SHEET); 1.223 + NS_ENSURE_ARG_POINTER(aSheetURI); 1.224 + 1.225 + int32_t foundIndex = FindSheetByURI(mSheets[aSheetType], aSheetURI); 1.226 + NS_ENSURE_TRUE(foundIndex >= 0, NS_ERROR_INVALID_ARG); 1.227 + nsCOMPtr<nsIStyleSheet> sheet = mSheets[aSheetType][foundIndex]; 1.228 + mSheets[aSheetType].RemoveObjectAt(foundIndex); 1.229 + 1.230 + const char* message; 1.231 + switch (aSheetType) { 1.232 + case AGENT_SHEET: 1.233 + message = "agent-sheet-removed"; 1.234 + break; 1.235 + case USER_SHEET: 1.236 + message = "user-sheet-removed"; 1.237 + break; 1.238 + case AUTHOR_SHEET: 1.239 + message = "author-sheet-removed"; 1.240 + break; 1.241 + } 1.242 + 1.243 + nsCOMPtr<nsIObserverService> serv = services::GetObserverService(); 1.244 + if (serv) 1.245 + serv->NotifyObservers(sheet, message, nullptr); 1.246 + 1.247 + if (XRE_GetProcessType() == GeckoProcessType_Default) { 1.248 + nsTArray<dom::ContentParent*> children; 1.249 + dom::ContentParent::GetAll(children); 1.250 + 1.251 + if (children.IsEmpty()) { 1.252 + return NS_OK; 1.253 + } 1.254 + 1.255 + mozilla::ipc::URIParams uri; 1.256 + SerializeURI(aSheetURI, uri); 1.257 + 1.258 + for (uint32_t i = 0; i < children.Length(); i++) { 1.259 + unused << children[i]->SendUnregisterSheet(uri, aSheetType); 1.260 + } 1.261 + } 1.262 + 1.263 + return NS_OK; 1.264 +} 1.265 + 1.266 +//static 1.267 +nsStyleSheetService * 1.268 +nsStyleSheetService::GetInstance() 1.269 +{ 1.270 + static bool first = true; 1.271 + if (first) { 1.272 + // make sure at first call that it's inited 1.273 + nsCOMPtr<nsIStyleSheetService> dummy = 1.274 + do_GetService(NS_STYLESHEETSERVICE_CONTRACTID); 1.275 + first = false; 1.276 + } 1.277 + 1.278 + return gInstance; 1.279 +} 1.280 + 1.281 +static size_t 1.282 +SizeOfElementIncludingThis(nsIStyleSheet* aElement, 1.283 + MallocSizeOf aMallocSizeOf, void *aData) 1.284 +{ 1.285 + return aElement->SizeOfIncludingThis(aMallocSizeOf); 1.286 +} 1.287 + 1.288 +MOZ_DEFINE_MALLOC_SIZE_OF(StyleSheetServiceMallocSizeOf) 1.289 + 1.290 +NS_IMETHODIMP 1.291 +nsStyleSheetService::CollectReports(nsIHandleReportCallback* aHandleReport, 1.292 + nsISupports* aData) 1.293 +{ 1.294 + return MOZ_COLLECT_REPORT( 1.295 + "explicit/layout/style-sheet-service", KIND_HEAP, UNITS_BYTES, 1.296 + SizeOfIncludingThis(StyleSheetServiceMallocSizeOf), 1.297 + "Memory used for style sheets held by the style sheet service."); 1.298 +} 1.299 + 1.300 +size_t 1.301 +nsStyleSheetService::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const 1.302 +{ 1.303 + size_t n = aMallocSizeOf(this); 1.304 + n += mSheets[AGENT_SHEET].SizeOfExcludingThis(SizeOfElementIncludingThis, 1.305 + aMallocSizeOf); 1.306 + n += mSheets[USER_SHEET].SizeOfExcludingThis(SizeOfElementIncludingThis, 1.307 + aMallocSizeOf); 1.308 + n += mSheets[AUTHOR_SHEET].SizeOfExcludingThis(SizeOfElementIncludingThis, 1.309 + aMallocSizeOf); 1.310 + return n; 1.311 +} 1.312 + 1.313 +