Backed out 17 changesets (bug 1898153) as reuqested by Aryx for causing wasm crashes.
[gecko.git] / layout / style / ErrorReporter.cpp
blob6335c695acca73005ce03fc215337a8f23ab4cc2
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 /* diagnostic reporting for CSS style sheet parser */
9 #include "mozilla/css/ErrorReporter.h"
11 #include "mozilla/StaticPrefs_layout.h"
12 #include "mozilla/StyleSheetInlines.h"
13 #include "mozilla/css/Loader.h"
14 #include "mozilla/Preferences.h"
15 #include "mozilla/SchedulerGroup.h"
16 #include "mozilla/Components.h"
17 #include "nsIConsoleService.h"
18 #include "mozilla/dom/Document.h"
19 #include "nsComponentManagerUtils.h"
20 #include "nsIDocShell.h"
21 #include "nsIFactory.h"
22 #include "nsINode.h"
23 #include "nsIScriptError.h"
24 #include "nsIStringBundle.h"
25 #include "nsServiceManagerUtils.h"
26 #include "nsStyleUtil.h"
27 #include "nsThreadUtils.h"
28 #include "nsNetUtil.h"
30 using namespace mozilla;
31 using namespace mozilla::css;
32 using namespace mozilla::dom;
34 namespace {
35 class ShortTermURISpecCache : public Runnable {
36 public:
37 ShortTermURISpecCache()
38 : Runnable("ShortTermURISpecCache"), mPending(false) {}
40 nsString const& GetSpec(nsIURI* aURI) {
41 if (mURI != aURI) {
42 mURI = aURI;
44 if (NS_FAILED(NS_GetSanitizedURIStringFromURI(mURI, mSpec))) {
45 mSpec.AssignLiteral("[nsIURI::GetSpec failed]");
48 return mSpec;
51 bool IsInUse() const { return mURI != nullptr; }
52 bool IsPending() const { return mPending; }
53 void SetPending() { mPending = true; }
55 // When invoked as a runnable, zap the cache.
56 NS_IMETHOD Run() override {
57 mURI = nullptr;
58 mSpec.Truncate();
59 mPending = false;
60 return NS_OK;
63 private:
64 nsCOMPtr<nsIURI> mURI;
65 nsString mSpec;
66 bool mPending;
69 } // namespace
71 bool ErrorReporter::sInitialized = false;
73 static nsIConsoleService* sConsoleService;
74 static nsIFactory* sScriptErrorFactory;
75 static nsIStringBundle* sStringBundle;
76 static ShortTermURISpecCache* sSpecCache;
78 void ErrorReporter::InitGlobals() {
79 MOZ_RELEASE_ASSERT(NS_IsMainThread());
80 MOZ_ASSERT(!sInitialized, "should not have been called");
82 sInitialized = true;
84 nsCOMPtr<nsIConsoleService> cs = do_GetService(NS_CONSOLESERVICE_CONTRACTID);
85 if (!cs) {
86 return;
89 nsCOMPtr<nsIFactory> sf = do_GetClassObject(NS_SCRIPTERROR_CONTRACTID);
90 if (!sf) {
91 return;
94 nsCOMPtr<nsIStringBundleService> sbs = components::StringBundle::Service();
95 if (!sbs) {
96 return;
99 nsCOMPtr<nsIStringBundle> sb;
100 nsresult rv = sbs->CreateBundle("chrome://global/locale/css.properties",
101 getter_AddRefs(sb));
102 if (NS_FAILED(rv) || !sb) {
103 return;
106 cs.forget(&sConsoleService);
107 sf.forget(&sScriptErrorFactory);
108 sb.forget(&sStringBundle);
111 namespace mozilla {
112 namespace css {
114 /* static */
115 void ErrorReporter::ReleaseGlobals() {
116 NS_IF_RELEASE(sConsoleService);
117 NS_IF_RELEASE(sScriptErrorFactory);
118 NS_IF_RELEASE(sStringBundle);
119 NS_IF_RELEASE(sSpecCache);
122 uint64_t ErrorReporter::FindInnerWindowId(const StyleSheet* aSheet,
123 const Loader* aLoader) {
124 if (aSheet) {
125 if (uint64_t id = aSheet->FindOwningWindowInnerID()) {
126 return id;
129 if (aLoader) {
130 if (Document* doc = aLoader->GetDocument()) {
131 return doc->InnerWindowID();
134 return 0;
137 ErrorReporter::ErrorReporter(uint64_t aInnerWindowId)
138 : mInnerWindowId(aInnerWindowId) {
139 EnsureGlobalsInitialized();
142 ErrorReporter::~ErrorReporter() {
143 MOZ_ASSERT(NS_IsMainThread());
144 // Schedule deferred cleanup for cached data. We want to strike a
145 // balance between performance and memory usage, so we only allow
146 // short-term caching.
147 if (sSpecCache && sSpecCache->IsInUse() && !sSpecCache->IsPending()) {
148 nsCOMPtr<nsIRunnable> runnable(sSpecCache);
149 nsresult rv = SchedulerGroup::Dispatch(runnable.forget());
150 if (NS_FAILED(rv)) {
151 // Peform the "deferred" cleanup immediately if the dispatch fails.
152 sSpecCache->Run();
153 } else {
154 sSpecCache->SetPending();
159 bool ErrorReporter::ShouldReportErrors(const Document& aDoc) {
160 MOZ_ASSERT(NS_IsMainThread());
161 nsIDocShell* shell = aDoc.GetDocShell();
162 if (!shell) {
163 return false;
166 bool report = false;
167 shell->GetCssErrorReportingEnabled(&report);
168 return report;
171 static nsINode* SheetOwner(const StyleSheet& aSheet) {
172 if (nsINode* owner = aSheet.GetOwnerNode()) {
173 return owner;
176 auto* associated = aSheet.GetAssociatedDocumentOrShadowRoot();
177 return associated ? &associated->AsNode() : nullptr;
180 bool ErrorReporter::ShouldReportErrors(const StyleSheet* aSheet,
181 const Loader* aLoader) {
182 MOZ_ASSERT(NS_IsMainThread());
184 if (!StaticPrefs::layout_css_report_errors()) {
185 return false;
188 if (aSheet) {
189 nsINode* owner = SheetOwner(*aSheet);
190 if (owner && ShouldReportErrors(*owner->OwnerDoc())) {
191 return true;
195 if (aLoader && aLoader->GetDocument() &&
196 ShouldReportErrors(*aLoader->GetDocument())) {
197 return true;
200 return false;
203 void ErrorReporter::OutputError(const nsACString& aSourceLine,
204 const nsACString& aSelectors,
205 uint32_t aLineNumber, uint32_t aColNumber,
206 nsIURI* aURI) {
207 nsAutoString errorLine;
208 // This could be a really long string for minified CSS; just leave it empty
209 // if we OOM.
210 if (!AppendUTF8toUTF16(aSourceLine, errorLine, fallible)) {
211 errorLine.Truncate();
214 nsAutoString selectors;
215 if (!AppendUTF8toUTF16(aSelectors, selectors, fallible)) {
216 selectors.Truncate();
219 if (mError.IsEmpty()) {
220 return;
223 nsAutoString fileName;
224 if (aURI) {
225 if (!sSpecCache) {
226 sSpecCache = new ShortTermURISpecCache;
227 NS_ADDREF(sSpecCache);
229 fileName = sSpecCache->GetSpec(aURI);
230 } else {
231 fileName.AssignLiteral("from DOM");
234 nsresult rv;
235 nsCOMPtr<nsIScriptError> errorObject =
236 do_CreateInstance(sScriptErrorFactory, &rv);
238 if (NS_SUCCEEDED(rv)) {
239 // It is safe to used InitWithSanitizedSource because fileName is
240 // an already anonymized uri spec.
241 rv = errorObject->InitWithSanitizedSource(
242 mError, fileName, errorLine, aLineNumber, aColNumber,
243 nsIScriptError::warningFlag, "CSS Parser", mInnerWindowId);
245 if (NS_SUCCEEDED(rv)) {
246 errorObject->SetCssSelectors(selectors);
247 sConsoleService->LogMessage(errorObject);
251 mError.Truncate();
254 void ErrorReporter::AddToError(const nsString& aErrorText) {
255 if (mError.IsEmpty()) {
256 mError = aErrorText;
257 } else {
258 mError.AppendLiteral(" ");
259 mError.Append(aErrorText);
263 void ErrorReporter::ReportUnexpected(const char* aMessage) {
264 nsAutoString str;
265 sStringBundle->GetStringFromName(aMessage, str);
266 AddToError(str);
269 void ErrorReporter::ReportUnexpectedUnescaped(
270 const char* aMessage, const nsTArray<nsString>& aParam) {
271 nsAutoString str;
272 sStringBundle->FormatStringFromName(aMessage, aParam, str);
273 AddToError(str);
276 } // namespace css
277 } // namespace mozilla