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/. */
7 /* implementation of interface for managing user and user-agent style sheets */
9 #include "nsStyleSheetService.h"
10 #include "nsIStyleSheet.h"
11 #include "mozilla/CSSStyleSheet.h"
12 #include "mozilla/MemoryReporting.h"
13 #include "mozilla/unused.h"
14 #include "mozilla/css/Loader.h"
15 #include "mozilla/dom/ContentParent.h"
16 #include "mozilla/ipc/URIUtils.h"
19 #include "nsICategoryManager.h"
20 #include "nsISupportsPrimitives.h"
21 #include "nsNetUtil.h"
22 #include "nsIObserverService.h"
23 #include "nsLayoutStatics.h"
25 using namespace mozilla
;
27 nsStyleSheetService
*nsStyleSheetService::gInstance
= nullptr;
29 nsStyleSheetService::nsStyleSheetService()
31 PR_STATIC_ASSERT(0 == AGENT_SHEET
&& 1 == USER_SHEET
&& 2 == AUTHOR_SHEET
);
32 NS_ASSERTION(!gInstance
, "Someone is using CreateInstance instead of GetService");
34 nsLayoutStatics::AddRef();
37 nsStyleSheetService::~nsStyleSheetService()
39 UnregisterWeakMemoryReporter(this);
42 nsLayoutStatics::Release();
46 nsStyleSheetService
, nsIStyleSheetService
, nsIMemoryReporter
)
49 nsStyleSheetService::RegisterFromEnumerator(nsICategoryManager
*aManager
,
50 const char *aCategory
,
51 nsISimpleEnumerator
*aEnumerator
,
58 while (NS_SUCCEEDED(aEnumerator
->HasMoreElements(&hasMore
)) && hasMore
) {
59 nsCOMPtr
<nsISupports
> element
;
60 if (NS_FAILED(aEnumerator
->GetNext(getter_AddRefs(element
))))
63 nsCOMPtr
<nsISupportsCString
> icStr
= do_QueryInterface(element
);
65 "category manager entries must be nsISupportsCStrings");
71 aManager
->GetCategoryEntry(aCategory
, name
.get(), getter_Copies(spec
));
74 NS_NewURI(getter_AddRefs(uri
), spec
);
76 LoadAndRegisterSheetInternal(uri
, aSheetType
);
81 nsStyleSheetService::FindSheetByURI(const nsCOMArray
<nsIStyleSheet
> &sheets
,
84 for (int32_t i
= sheets
.Count() - 1; i
>= 0; i
-- ) {
86 nsIURI
* uri
= sheets
[i
]->GetSheetURI();
88 && NS_SUCCEEDED(uri
->Equals(sheetURI
, &bEqual
))
98 nsStyleSheetService::Init()
100 // If you make changes here, consider whether
101 // SVGDocument::EnsureNonSVGUserAgentStyleSheetsLoaded should be updated too.
103 // Child processes get their style sheets from the ContentParent.
104 if (XRE_GetProcessType() == GeckoProcessType_Content
) {
108 // Enumerate all of the style sheet URIs registered in the category
109 // manager and load them.
111 nsCOMPtr
<nsICategoryManager
> catMan
=
112 do_GetService(NS_CATEGORYMANAGER_CONTRACTID
);
114 NS_ENSURE_TRUE(catMan
, NS_ERROR_OUT_OF_MEMORY
);
116 nsCOMPtr
<nsISimpleEnumerator
> sheets
;
117 catMan
->EnumerateCategory("agent-style-sheets", getter_AddRefs(sheets
));
118 RegisterFromEnumerator(catMan
, "agent-style-sheets", sheets
, AGENT_SHEET
);
120 catMan
->EnumerateCategory("user-style-sheets", getter_AddRefs(sheets
));
121 RegisterFromEnumerator(catMan
, "user-style-sheets", sheets
, USER_SHEET
);
123 catMan
->EnumerateCategory("author-style-sheets", getter_AddRefs(sheets
));
124 RegisterFromEnumerator(catMan
, "author-style-sheets", sheets
, AUTHOR_SHEET
);
126 RegisterWeakMemoryReporter(this);
132 nsStyleSheetService::LoadAndRegisterSheet(nsIURI
*aSheetURI
,
135 nsresult rv
= LoadAndRegisterSheetInternal(aSheetURI
, aSheetType
);
136 if (NS_SUCCEEDED(rv
)) {
138 switch (aSheetType
) {
140 message
= "agent-sheet-added";
143 message
= "user-sheet-added";
146 message
= "author-sheet-added";
149 return NS_ERROR_INVALID_ARG
;
151 nsCOMPtr
<nsIObserverService
> serv
= services::GetObserverService();
153 // We're guaranteed that the new sheet is the last sheet in
154 // mSheets[aSheetType]
155 const nsCOMArray
<nsIStyleSheet
> & sheets
= mSheets
[aSheetType
];
156 serv
->NotifyObservers(sheets
[sheets
.Count() - 1], message
, nullptr);
159 if (XRE_GetProcessType() == GeckoProcessType_Default
) {
160 nsTArray
<dom::ContentParent
*> children
;
161 dom::ContentParent::GetAll(children
);
163 if (children
.IsEmpty()) {
167 mozilla::ipc::URIParams uri
;
168 SerializeURI(aSheetURI
, uri
);
170 for (uint32_t i
= 0; i
< children
.Length(); i
++) {
171 unused
<< children
[i
]->SendLoadAndRegisterSheet(uri
, aSheetType
);
179 nsStyleSheetService::LoadAndRegisterSheetInternal(nsIURI
*aSheetURI
,
182 NS_ENSURE_ARG(aSheetType
== AGENT_SHEET
||
183 aSheetType
== USER_SHEET
||
184 aSheetType
== AUTHOR_SHEET
);
185 NS_ENSURE_ARG_POINTER(aSheetURI
);
187 nsRefPtr
<css::Loader
> loader
= new css::Loader();
189 nsRefPtr
<CSSStyleSheet
> sheet
;
190 // Allow UA sheets, but not user sheets, to use unsafe rules
191 nsresult rv
= loader
->LoadSheetSync(aSheetURI
, aSheetType
== AGENT_SHEET
,
192 true, getter_AddRefs(sheet
));
193 NS_ENSURE_SUCCESS(rv
, rv
);
195 if (!mSheets
[aSheetType
].AppendObject(sheet
)) {
196 rv
= NS_ERROR_OUT_OF_MEMORY
;
203 nsStyleSheetService::SheetRegistered(nsIURI
*sheetURI
,
204 uint32_t aSheetType
, bool *_retval
)
206 NS_ENSURE_ARG(aSheetType
== AGENT_SHEET
||
207 aSheetType
== USER_SHEET
||
208 aSheetType
== AUTHOR_SHEET
);
209 NS_ENSURE_ARG_POINTER(sheetURI
);
210 NS_PRECONDITION(_retval
, "Null out param");
212 *_retval
= (FindSheetByURI(mSheets
[aSheetType
], sheetURI
) >= 0);
218 nsStyleSheetService::PreloadSheet(nsIURI
*aSheetURI
, uint32_t aSheetType
,
219 nsIDOMStyleSheet
**aSheet
)
221 NS_ENSURE_ARG(aSheetType
== AGENT_SHEET
||
222 aSheetType
== USER_SHEET
||
223 aSheetType
== AUTHOR_SHEET
);
224 NS_ENSURE_ARG_POINTER(aSheetURI
);
225 NS_PRECONDITION(aSheet
, "Null out param");
227 nsRefPtr
<css::Loader
> loader
= new css::Loader();
229 // Allow UA sheets, but not user sheets, to use unsafe rules
230 nsRefPtr
<CSSStyleSheet
> sheet
;
231 nsresult rv
= loader
->LoadSheetSync(aSheetURI
, aSheetType
== AGENT_SHEET
,
232 true, getter_AddRefs(sheet
));
233 NS_ENSURE_SUCCESS(rv
, rv
);
234 sheet
.forget(aSheet
);
239 nsStyleSheetService::UnregisterSheet(nsIURI
*aSheetURI
, uint32_t aSheetType
)
241 NS_ENSURE_ARG(aSheetType
== AGENT_SHEET
||
242 aSheetType
== USER_SHEET
||
243 aSheetType
== AUTHOR_SHEET
);
244 NS_ENSURE_ARG_POINTER(aSheetURI
);
246 int32_t foundIndex
= FindSheetByURI(mSheets
[aSheetType
], aSheetURI
);
247 NS_ENSURE_TRUE(foundIndex
>= 0, NS_ERROR_INVALID_ARG
);
248 nsCOMPtr
<nsIStyleSheet
> sheet
= mSheets
[aSheetType
][foundIndex
];
249 mSheets
[aSheetType
].RemoveObjectAt(foundIndex
);
252 switch (aSheetType
) {
254 message
= "agent-sheet-removed";
257 message
= "user-sheet-removed";
260 message
= "author-sheet-removed";
264 nsCOMPtr
<nsIObserverService
> serv
= services::GetObserverService();
266 serv
->NotifyObservers(sheet
, message
, nullptr);
268 if (XRE_GetProcessType() == GeckoProcessType_Default
) {
269 nsTArray
<dom::ContentParent
*> children
;
270 dom::ContentParent::GetAll(children
);
272 if (children
.IsEmpty()) {
276 mozilla::ipc::URIParams uri
;
277 SerializeURI(aSheetURI
, uri
);
279 for (uint32_t i
= 0; i
< children
.Length(); i
++) {
280 unused
<< children
[i
]->SendUnregisterSheet(uri
, aSheetType
);
288 nsStyleSheetService
*
289 nsStyleSheetService::GetInstance()
291 static bool first
= true;
293 // make sure at first call that it's inited
294 nsCOMPtr
<nsIStyleSheetService
> dummy
=
295 do_GetService(NS_STYLESHEETSERVICE_CONTRACTID
);
303 SizeOfElementIncludingThis(nsIStyleSheet
* aElement
,
304 MallocSizeOf aMallocSizeOf
, void *aData
)
306 return aElement
->SizeOfIncludingThis(aMallocSizeOf
);
309 MOZ_DEFINE_MALLOC_SIZE_OF(StyleSheetServiceMallocSizeOf
)
312 nsStyleSheetService::CollectReports(nsIHandleReportCallback
* aHandleReport
,
313 nsISupports
* aData
, bool aAnonymize
)
315 return MOZ_COLLECT_REPORT(
316 "explicit/layout/style-sheet-service", KIND_HEAP
, UNITS_BYTES
,
317 SizeOfIncludingThis(StyleSheetServiceMallocSizeOf
),
318 "Memory used for style sheets held by the style sheet service.");
322 nsStyleSheetService::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf
) const
324 size_t n
= aMallocSizeOf(this);
325 n
+= mSheets
[AGENT_SHEET
].SizeOfExcludingThis(SizeOfElementIncludingThis
,
327 n
+= mSheets
[USER_SHEET
].SizeOfExcludingThis(SizeOfElementIncludingThis
,
329 n
+= mSheets
[AUTHOR_SHEET
].SizeOfExcludingThis(SizeOfElementIncludingThis
,