Bug 867089 - Validate the playbackRate before using it. r=ehsan
[gecko.git] / layout / style / ErrorReporter.cpp
blob77d8d7b7db5d97b51094132d31c78250dac0e73b
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 /* diagnostic reporting for CSS style sheet parser */
8 #include "mozilla/css/ErrorReporter.h"
9 #include "mozilla/css/Loader.h"
10 #include "mozilla/Preferences.h"
11 #include "mozilla/Services.h"
12 #include "nsCSSScanner.h"
13 #include "nsCSSStyleSheet.h"
14 #include "nsIConsoleService.h"
15 #include "nsIDocument.h"
16 #include "nsIFactory.h"
17 #include "nsIScriptError.h"
18 #include "nsIStringBundle.h"
19 #include "nsServiceManagerUtils.h"
20 #include "nsStyleUtil.h"
21 #include "nsThreadUtils.h"
23 #ifdef CSS_REPORT_PARSE_ERRORS
25 using mozilla::Preferences;
26 namespace services = mozilla::services;
28 namespace {
29 class ShortTermURISpecCache : public nsRunnable {
30 public:
31 ShortTermURISpecCache() : mPending(false) {}
33 nsString const& GetSpec(nsIURI* aURI) {
34 if (mURI != aURI) {
35 mURI = aURI;
37 nsAutoCString cSpec;
38 mURI->GetSpec(cSpec);
39 CopyUTF8toUTF16(cSpec, mSpec);
41 return mSpec;
44 bool IsInUse() const { return mURI != nullptr; }
45 bool IsPending() const { return mPending; }
46 void SetPending() { mPending = true; }
48 // When invoked as a runnable, zap the cache.
49 NS_IMETHOD Run() {
50 mURI = nullptr;
51 mSpec.Truncate();
52 mPending = false;
53 return NS_OK;
56 private:
57 nsCOMPtr<nsIURI> mURI;
58 nsString mSpec;
59 bool mPending;
63 static bool sReportErrors;
64 static nsIConsoleService *sConsoleService;
65 static nsIFactory *sScriptErrorFactory;
66 static nsIStringBundle *sStringBundle;
67 static ShortTermURISpecCache *sSpecCache;
69 #define CSS_ERRORS_PREF "layout.css.report_errors"
71 static bool
72 InitGlobals()
74 NS_ABORT_IF_FALSE(!sConsoleService && !sScriptErrorFactory && !sStringBundle,
75 "should not have been called");
77 if (NS_FAILED(Preferences::AddBoolVarCache(&sReportErrors, CSS_ERRORS_PREF,
78 true))) {
79 return false;
82 nsCOMPtr<nsIConsoleService> cs = do_GetService(NS_CONSOLESERVICE_CONTRACTID);
83 if (!cs) {
84 return false;
87 nsCOMPtr<nsIFactory> sf = do_GetClassObject(NS_SCRIPTERROR_CONTRACTID);
88 if (!sf) {
89 return false;
92 nsCOMPtr<nsIStringBundleService> sbs = services::GetStringBundleService();
93 if (!sbs) {
94 return false;
97 nsCOMPtr<nsIStringBundle> sb;
98 nsresult rv = sbs->CreateBundle("chrome://global/locale/css.properties",
99 getter_AddRefs(sb));
100 if (NS_FAILED(rv) || !sb) {
101 return false;
104 sConsoleService = cs.forget().get();
105 sScriptErrorFactory = sf.forget().get();
106 sStringBundle = sb.forget().get();
108 return true;
111 static inline bool
112 ShouldReportErrors()
114 if (!sConsoleService) {
115 if (!InitGlobals()) {
116 return false;
119 return sReportErrors;
122 namespace mozilla {
123 namespace css {
125 /* static */ void
126 ErrorReporter::ReleaseGlobals()
128 NS_IF_RELEASE(sConsoleService);
129 NS_IF_RELEASE(sScriptErrorFactory);
130 NS_IF_RELEASE(sStringBundle);
131 NS_IF_RELEASE(sSpecCache);
134 ErrorReporter::ErrorReporter(const nsCSSScanner& aScanner,
135 const nsCSSStyleSheet* aSheet,
136 const Loader* aLoader,
137 nsIURI* aURI)
138 : mScanner(&aScanner), mSheet(aSheet), mLoader(aLoader), mURI(aURI),
139 mInnerWindowID(0), mErrorLineNumber(0), mPrevErrorLineNumber(0),
140 mErrorColNumber(0)
144 ErrorReporter::~ErrorReporter()
146 // Schedule deferred cleanup for cached data. We want to strike a
147 // balance between performance and memory usage, so we only allow
148 // short-term caching.
149 if (sSpecCache && sSpecCache->IsInUse() && !sSpecCache->IsPending()) {
150 if (NS_FAILED(NS_DispatchToCurrentThread(sSpecCache))) {
151 // Peform the "deferred" cleanup immediately if the dispatch fails.
152 sSpecCache->Run();
153 } else {
154 sSpecCache->SetPending();
159 void
160 ErrorReporter::OutputError()
162 if (mError.IsEmpty()) {
163 return;
165 if (!ShouldReportErrors()) {
166 ClearError();
167 return;
170 if (mInnerWindowID == 0 && (mSheet || mLoader)) {
171 if (mSheet) {
172 mInnerWindowID = mSheet->FindOwningWindowInnerID();
174 if (mInnerWindowID == 0 && mLoader) {
175 nsIDocument* doc = mLoader->GetDocument();
176 if (doc) {
177 mInnerWindowID = doc->InnerWindowID();
180 // don't attempt this again, even if we failed
181 mSheet = nullptr;
182 mLoader = nullptr;
185 if (mFileName.IsEmpty()) {
186 if (mURI) {
187 if (!sSpecCache) {
188 sSpecCache = new ShortTermURISpecCache;
189 NS_ADDREF(sSpecCache);
191 mFileName = sSpecCache->GetSpec(mURI);
192 mURI = nullptr;
193 } else {
194 mFileName.AssignLiteral("from DOM");
198 nsresult rv;
199 nsCOMPtr<nsIScriptError> errorObject =
200 do_CreateInstance(sScriptErrorFactory, &rv);
202 if (NS_SUCCEEDED(rv)) {
203 rv = errorObject->InitWithWindowID(mError,
204 mFileName,
205 mErrorLine,
206 mErrorLineNumber,
207 mErrorColNumber,
208 nsIScriptError::warningFlag,
209 "CSS Parser",
210 mInnerWindowID);
211 if (NS_SUCCEEDED(rv)) {
212 sConsoleService->LogMessage(errorObject);
216 ClearError();
219 void
220 ErrorReporter::ClearError()
222 mError.Truncate();
225 void
226 ErrorReporter::AddToError(const nsString &aErrorText)
228 if (!ShouldReportErrors()) return;
230 if (mError.IsEmpty()) {
231 mError = aErrorText;
232 mErrorLineNumber = mScanner->GetLineNumber();
233 mErrorColNumber = mScanner->GetColumnNumber();
234 // Retrieve the error line once per line, and reuse the same nsString
235 // for all errors on that line. That causes the text of the line to
236 // be shared among all the nsIScriptError objects.
237 if (mErrorLine.IsEmpty() || mErrorLineNumber != mPrevErrorLineNumber) {
238 mErrorLine = mScanner->GetCurrentLine();
239 mPrevErrorLineNumber = mErrorLineNumber;
241 } else {
242 mError.AppendLiteral(" ");
243 mError.Append(aErrorText);
247 void
248 ErrorReporter::ReportUnexpected(const char *aMessage)
250 if (!ShouldReportErrors()) return;
252 nsAutoString str;
253 sStringBundle->GetStringFromName(NS_ConvertASCIItoUTF16(aMessage).get(),
254 getter_Copies(str));
255 AddToError(str);
258 void
259 ErrorReporter::ReportUnexpected(const char *aMessage,
260 const nsString &aParam)
262 if (!ShouldReportErrors()) return;
264 nsAutoString qparam;
265 nsStyleUtil::AppendEscapedCSSIdent(aParam, qparam);
266 const PRUnichar *params[1] = { qparam.get() };
268 nsAutoString str;
269 sStringBundle->FormatStringFromName(NS_ConvertASCIItoUTF16(aMessage).get(),
270 params, ArrayLength(params),
271 getter_Copies(str));
272 AddToError(str);
275 void
276 ErrorReporter::ReportUnexpected(const char *aMessage,
277 const nsCSSToken &aToken)
279 if (!ShouldReportErrors()) return;
281 nsAutoString tokenString;
282 aToken.AppendToString(tokenString);
283 const PRUnichar *params[1] = { tokenString.get() };
285 nsAutoString str;
286 sStringBundle->FormatStringFromName(NS_ConvertASCIItoUTF16(aMessage).get(),
287 params, ArrayLength(params),
288 getter_Copies(str));
289 AddToError(str);
292 void
293 ErrorReporter::ReportUnexpected(const char *aMessage,
294 const nsCSSToken &aToken,
295 PRUnichar aChar)
297 if (!ShouldReportErrors()) return;
299 nsAutoString tokenString;
300 aToken.AppendToString(tokenString);
301 const PRUnichar charStr[2] = { aChar, 0 };
302 const PRUnichar *params[2] = { tokenString.get(), charStr };
304 nsAutoString str;
305 sStringBundle->FormatStringFromName(NS_ConvertASCIItoUTF16(aMessage).get(),
306 params, ArrayLength(params),
307 getter_Copies(str));
308 AddToError(str);
311 void
312 ErrorReporter::ReportUnexpectedEOF(const char *aMessage)
314 if (!ShouldReportErrors()) return;
316 nsAutoString innerStr;
317 sStringBundle->GetStringFromName(NS_ConvertASCIItoUTF16(aMessage).get(),
318 getter_Copies(innerStr));
319 const PRUnichar *params[1] = { innerStr.get() };
321 nsAutoString str;
322 sStringBundle->FormatStringFromName(NS_LITERAL_STRING("PEUnexpEOF2").get(),
323 params, ArrayLength(params),
324 getter_Copies(str));
325 AddToError(str);
328 void
329 ErrorReporter::ReportUnexpectedEOF(PRUnichar aExpected)
331 if (!ShouldReportErrors()) return;
333 const PRUnichar expectedStr[] = {
334 PRUnichar('\''), aExpected, PRUnichar('\''), PRUnichar(0)
336 const PRUnichar *params[1] = { expectedStr };
338 nsAutoString str;
339 sStringBundle->FormatStringFromName(NS_LITERAL_STRING("PEUnexpEOF2").get(),
340 params, ArrayLength(params),
341 getter_Copies(str));
342 AddToError(str);
345 } // namespace css
346 } // namespace mozilla
348 #endif