forked from mirrors/gecko-dev
		
	 680815cd6e
			
		
	
	
		680815cd6e
		
	
	
	
	
		
			
			This patch was generated automatically by the "modeline.py" script, available here: https://github.com/amccreight/moz-source-tools/blob/master/modeline.py For every file that is modified in this patch, the changes are as follows: (1) The patch changes the file to use the exact C++ mode lines from the Mozilla coding style guide, available here: https://developer.mozilla.org/en-US/docs/Mozilla/Developer_guide/Coding_Style#Mode_Line (2) The patch deletes any blank lines between the mode line & the MPL boilerplate comment. (3) If the file previously had the mode lines and MPL boilerplate in a single contiguous C++ comment, then the patch splits them into separate C++ comments, to match the boilerplate in the coding style. MozReview-Commit-ID: EuRsDue63tK --HG-- extra : rebase_source : 3356d4b80ff6213935192e87cdbc9103fec6084c
		
			
				
	
	
		
			440 lines
		
	
	
	
		
			12 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			440 lines
		
	
	
	
		
			12 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 | |
| /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 | |
| /* This Source Code Form is subject to the terms of the Mozilla Public
 | |
|  * License, v. 2.0. If a copy of the MPL was not distributed with this
 | |
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 | |
| 
 | |
| /* diagnostic reporting for CSS style sheet parser */
 | |
| 
 | |
| #include "mozilla/css/ErrorReporter.h"
 | |
| 
 | |
| #include "mozilla/StyleSheetInlines.h"
 | |
| #include "mozilla/css/Loader.h"
 | |
| #include "mozilla/Preferences.h"
 | |
| #include "mozilla/Services.h"
 | |
| #include "mozilla/SystemGroup.h"
 | |
| #include "nsCSSScanner.h"
 | |
| #include "nsIConsoleService.h"
 | |
| #include "nsIDocument.h"
 | |
| #include "nsIFactory.h"
 | |
| #include "nsIScriptError.h"
 | |
| #include "nsISensitiveInfoHiddenURI.h"
 | |
| #include "nsIStringBundle.h"
 | |
| #include "nsServiceManagerUtils.h"
 | |
| #include "nsStyleUtil.h"
 | |
| #include "nsThreadUtils.h"
 | |
| #include "nsNetUtil.h"
 | |
| 
 | |
| #ifdef CSS_REPORT_PARSE_ERRORS
 | |
| 
 | |
| using namespace mozilla;
 | |
| 
 | |
| namespace {
 | |
| class ShortTermURISpecCache : public Runnable {
 | |
| public:
 | |
|   ShortTermURISpecCache()
 | |
|    : Runnable("ShortTermURISpecCache")
 | |
|    , mPending(false) {}
 | |
| 
 | |
|   nsString const& GetSpec(nsIURI* aURI) {
 | |
|     if (mURI != aURI) {
 | |
|       mURI = aURI;
 | |
| 
 | |
|       if (NS_FAILED(NS_GetSanitizedURIStringFromURI(mURI, mSpec))) {
 | |
|         mSpec.AssignLiteral("[nsIURI::GetSpec failed]");
 | |
|       }
 | |
|     }
 | |
|     return mSpec;
 | |
|   }
 | |
| 
 | |
|   bool IsInUse() const { return mURI != nullptr; }
 | |
|   bool IsPending() const { return mPending; }
 | |
|   void SetPending() { mPending = true; }
 | |
| 
 | |
|   // When invoked as a runnable, zap the cache.
 | |
|   NS_IMETHOD Run() override {
 | |
|     mURI = nullptr;
 | |
|     mSpec.Truncate();
 | |
|     mPending = false;
 | |
|     return NS_OK;
 | |
|   }
 | |
| 
 | |
| private:
 | |
|   nsCOMPtr<nsIURI> mURI;
 | |
|   nsString mSpec;
 | |
|   bool mPending;
 | |
| };
 | |
| 
 | |
| } // namespace
 | |
| 
 | |
| static bool sReportErrors;
 | |
| static nsIConsoleService *sConsoleService;
 | |
| static nsIFactory *sScriptErrorFactory;
 | |
| static nsIStringBundle *sStringBundle;
 | |
| static ShortTermURISpecCache *sSpecCache;
 | |
| 
 | |
| #define CSS_ERRORS_PREF "layout.css.report_errors"
 | |
| 
 | |
| static bool
 | |
| InitGlobals()
 | |
| {
 | |
|   MOZ_ASSERT(!sConsoleService && !sScriptErrorFactory && !sStringBundle,
 | |
|              "should not have been called");
 | |
| 
 | |
|   if (NS_FAILED(Preferences::AddBoolVarCache(&sReportErrors, CSS_ERRORS_PREF,
 | |
|                                              true))) {
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   nsCOMPtr<nsIConsoleService> cs = do_GetService(NS_CONSOLESERVICE_CONTRACTID);
 | |
|   if (!cs) {
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   nsCOMPtr<nsIFactory> sf = do_GetClassObject(NS_SCRIPTERROR_CONTRACTID);
 | |
|   if (!sf) {
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   nsCOMPtr<nsIStringBundleService> sbs = services::GetStringBundleService();
 | |
|   if (!sbs) {
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   nsCOMPtr<nsIStringBundle> sb;
 | |
|   nsresult rv = sbs->CreateBundle("chrome://global/locale/css.properties",
 | |
|                                   getter_AddRefs(sb));
 | |
|   if (NS_FAILED(rv) || !sb) {
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   cs.forget(&sConsoleService);
 | |
|   sf.forget(&sScriptErrorFactory);
 | |
|   sb.forget(&sStringBundle);
 | |
| 
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| static inline bool
 | |
| ShouldReportErrors()
 | |
| {
 | |
|   if (!sConsoleService) {
 | |
|     if (!InitGlobals()) {
 | |
|       return false;
 | |
|     }
 | |
|   }
 | |
|   return sReportErrors;
 | |
| }
 | |
| 
 | |
| namespace mozilla {
 | |
| namespace css {
 | |
| 
 | |
| /* static */ void
 | |
| ErrorReporter::ReleaseGlobals()
 | |
| {
 | |
|   NS_IF_RELEASE(sConsoleService);
 | |
|   NS_IF_RELEASE(sScriptErrorFactory);
 | |
|   NS_IF_RELEASE(sStringBundle);
 | |
|   NS_IF_RELEASE(sSpecCache);
 | |
| }
 | |
| 
 | |
| ErrorReporter::ErrorReporter(const nsCSSScanner& aScanner,
 | |
|                              const StyleSheet* aSheet,
 | |
|                              const Loader* aLoader,
 | |
|                              nsIURI* aURI)
 | |
|   : mScanner(&aScanner), mSheet(aSheet), mLoader(aLoader), mURI(aURI),
 | |
|     mInnerWindowID(0), mErrorLineNumber(0), mPrevErrorLineNumber(0),
 | |
|     mErrorColNumber(0)
 | |
| {
 | |
| }
 | |
| 
 | |
| ErrorReporter::ErrorReporter(const ServoStyleSheet* aSheet,
 | |
|                              const Loader* aLoader,
 | |
|                              nsIURI* aURI)
 | |
|   : mScanner(nullptr), mSheet(aSheet), mLoader(aLoader), mURI(aURI),
 | |
|     mInnerWindowID(0), mErrorLineNumber(0), mPrevErrorLineNumber(0),
 | |
|     mErrorColNumber(0)
 | |
| {
 | |
| }
 | |
| 
 | |
| ErrorReporter::~ErrorReporter()
 | |
| {
 | |
|   // Schedule deferred cleanup for cached data. We want to strike a
 | |
|   // balance between performance and memory usage, so we only allow
 | |
|   // short-term caching.
 | |
|   if (sSpecCache && sSpecCache->IsInUse() && !sSpecCache->IsPending()) {
 | |
|     nsCOMPtr<nsIRunnable> runnable(sSpecCache);
 | |
|     nsresult rv =
 | |
|       SystemGroup::Dispatch(TaskCategory::Other, runnable.forget());
 | |
|     if (NS_FAILED(rv)) {
 | |
|       // Peform the "deferred" cleanup immediately if the dispatch fails.
 | |
|       sSpecCache->Run();
 | |
|     } else {
 | |
|       sSpecCache->SetPending();
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| void
 | |
| ErrorReporter::OutputError()
 | |
| {
 | |
|   if (mError.IsEmpty()) {
 | |
|     return;
 | |
|   }
 | |
|   if (!ShouldReportErrors()) {
 | |
|     ClearError();
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   if (mInnerWindowID == 0 && (mSheet || mLoader)) {
 | |
|     if (mSheet) {
 | |
|       mInnerWindowID = mSheet->FindOwningWindowInnerID();
 | |
|     }
 | |
|     if (mInnerWindowID == 0 && mLoader) {
 | |
|       nsIDocument* doc = mLoader->GetDocument();
 | |
|       if (doc) {
 | |
|         mInnerWindowID = doc->InnerWindowID();
 | |
|       }
 | |
|     }
 | |
|     // don't attempt this again, even if we failed
 | |
|     mSheet = nullptr;
 | |
|     mLoader = nullptr;
 | |
|   }
 | |
| 
 | |
|   if (mFileName.IsEmpty()) {
 | |
|     if (mURI) {
 | |
|       if (!sSpecCache) {
 | |
|         sSpecCache = new ShortTermURISpecCache;
 | |
|         NS_ADDREF(sSpecCache);
 | |
|       }
 | |
|       mFileName = sSpecCache->GetSpec(mURI);
 | |
|       mURI = nullptr;
 | |
|     } else {
 | |
|       mFileName.AssignLiteral("from DOM");
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   nsresult rv;
 | |
|   nsCOMPtr<nsIScriptError> errorObject =
 | |
|     do_CreateInstance(sScriptErrorFactory, &rv);
 | |
| 
 | |
|   if (NS_SUCCEEDED(rv)) {
 | |
|     // It is safe to used InitWithSanitizedSource because mFileName is
 | |
|     // an already anonymized uri spec.
 | |
|     rv = errorObject->InitWithSanitizedSource(mError,
 | |
|                                               mFileName,
 | |
|                                               mErrorLine,
 | |
|                                               mErrorLineNumber,
 | |
|                                               mErrorColNumber,
 | |
|                                               nsIScriptError::warningFlag,
 | |
|                                               "CSS Parser",
 | |
|                                               mInnerWindowID);
 | |
|     if (NS_SUCCEEDED(rv)) {
 | |
|       sConsoleService->LogMessage(errorObject);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   ClearError();
 | |
| }
 | |
| 
 | |
| void
 | |
| ErrorReporter::OutputError(uint32_t aLineNumber, uint32_t aColNumber)
 | |
| {
 | |
|   mErrorLineNumber = aLineNumber;
 | |
|   mErrorColNumber = aColNumber;
 | |
|   OutputError();
 | |
| }
 | |
| 
 | |
| // When Stylo's CSS parser is in use, this reporter does not have access to the CSS parser's
 | |
| // state. The users of ErrorReporter need to provide:
 | |
| // - the line number of the error
 | |
| // - the column number of the error
 | |
| // - the complete source line containing the invalid CSS
 | |
| 
 | |
| void
 | |
| ErrorReporter::OutputError(uint32_t aLineNumber,
 | |
|                            uint32_t aColNumber,
 | |
|                            const nsACString& aSourceLine)
 | |
| {
 | |
|   mErrorLineNumber = aLineNumber;
 | |
|   mErrorColNumber = aColNumber;
 | |
| 
 | |
|   // Retrieve the error line once per line, and reuse the same nsString
 | |
|   // for all errors on that line.  That causes the text of the line to
 | |
|   // be shared among all the nsIScriptError objects.
 | |
|   if (mErrorLine.IsEmpty() || mErrorLineNumber != mPrevErrorLineNumber) {
 | |
|     mErrorLine.Truncate();
 | |
|     // This could be a really long string for minified CSS; just leave it empty if we OOM.
 | |
|     if (!AppendUTF8toUTF16(aSourceLine, mErrorLine, fallible)) {
 | |
|       mErrorLine.Truncate();
 | |
|     }
 | |
| 
 | |
|     mPrevErrorLineNumber = aLineNumber;
 | |
|   }
 | |
| 
 | |
|   OutputError();
 | |
| }
 | |
| 
 | |
| void
 | |
| ErrorReporter::ClearError()
 | |
| {
 | |
|   mError.Truncate();
 | |
| }
 | |
| 
 | |
| void
 | |
| ErrorReporter::AddToError(const nsString &aErrorText)
 | |
| {
 | |
|   if (!ShouldReportErrors()) return;
 | |
| 
 | |
|   if (mError.IsEmpty()) {
 | |
|     mError = aErrorText;
 | |
|     // If this error reporter is being used from Stylo, the equivalent operation occurs
 | |
|     // in the OutputError variant that provides source information.
 | |
|     if (!IsServo()) {
 | |
|       mErrorLineNumber = mScanner->GetLineNumber();
 | |
|       mErrorColNumber = mScanner->GetColumnNumber();
 | |
|       // Retrieve the error line once per line, and reuse the same nsString
 | |
|       // for all errors on that line.  That causes the text of the line to
 | |
|       // be shared among all the nsIScriptError objects.
 | |
|       if (mErrorLine.IsEmpty() || mErrorLineNumber != mPrevErrorLineNumber) {
 | |
|         // Be careful here: the error line might be really long and OOM
 | |
|         // when we try to make a copy here.  If so, just leave it empty.
 | |
|         if (!mErrorLine.Assign(mScanner->GetCurrentLine(), fallible)) {
 | |
|           mErrorLine.Truncate();
 | |
|         }
 | |
|         mPrevErrorLineNumber = mErrorLineNumber;
 | |
|       }
 | |
|     }
 | |
|   } else {
 | |
|     mError.AppendLiteral("  ");
 | |
|     mError.Append(aErrorText);
 | |
|   }
 | |
| }
 | |
| 
 | |
| void
 | |
| ErrorReporter::ReportUnexpected(const char *aMessage)
 | |
| {
 | |
|   if (!ShouldReportErrors()) return;
 | |
| 
 | |
|   nsAutoString str;
 | |
|   sStringBundle->GetStringFromName(aMessage, str);
 | |
|   AddToError(str);
 | |
| }
 | |
| 
 | |
| void
 | |
| ErrorReporter::ReportUnexpected(const char *aMessage,
 | |
|                                 const nsString &aParam)
 | |
| {
 | |
|   if (!ShouldReportErrors()) return;
 | |
| 
 | |
|   nsAutoString qparam;
 | |
|   nsStyleUtil::AppendEscapedCSSIdent(aParam, qparam);
 | |
|   const char16_t *params[1] = { qparam.get() };
 | |
| 
 | |
|   nsAutoString str;
 | |
|   sStringBundle->FormatStringFromName(aMessage, params, ArrayLength(params),
 | |
|                                       str);
 | |
|   AddToError(str);
 | |
| }
 | |
| 
 | |
| void
 | |
| ErrorReporter::ReportUnexpectedUnescaped(const char *aMessage,
 | |
|                                          const nsAutoString& aParam)
 | |
| {
 | |
|   if (!ShouldReportErrors()) return;
 | |
| 
 | |
|   const char16_t *params[1] = { aParam.get() };
 | |
| 
 | |
|   nsAutoString str;
 | |
|   sStringBundle->FormatStringFromName(aMessage, params, ArrayLength(params),
 | |
|                                       str);
 | |
|   AddToError(str);
 | |
| }
 | |
| 
 | |
| void
 | |
| ErrorReporter::ReportUnexpected(const char *aMessage,
 | |
|                                 const nsCSSToken &aToken)
 | |
| {
 | |
|   if (!ShouldReportErrors()) return;
 | |
| 
 | |
|   nsAutoString tokenString;
 | |
|   aToken.AppendToString(tokenString);
 | |
|   ReportUnexpectedUnescaped(aMessage, tokenString);
 | |
| }
 | |
| 
 | |
| void
 | |
| ErrorReporter::ReportUnexpected(const char *aMessage,
 | |
|                                 const nsCSSToken &aToken,
 | |
|                                 char16_t aChar)
 | |
| {
 | |
|   if (!ShouldReportErrors()) return;
 | |
| 
 | |
|   nsAutoString tokenString;
 | |
|   aToken.AppendToString(tokenString);
 | |
|   const char16_t charStr[2] = { aChar, 0 };
 | |
|   const char16_t *params[2] = { tokenString.get(), charStr };
 | |
| 
 | |
|   nsAutoString str;
 | |
|   sStringBundle->FormatStringFromName(aMessage, params, ArrayLength(params),
 | |
|                                       str);
 | |
|   AddToError(str);
 | |
| }
 | |
| 
 | |
| void
 | |
| ErrorReporter::ReportUnexpected(const char *aMessage,
 | |
|                                 const nsString &aParam,
 | |
|                                 const nsString &aValue)
 | |
| {
 | |
|   if (!ShouldReportErrors()) return;
 | |
| 
 | |
|   nsAutoString qparam;
 | |
|   nsStyleUtil::AppendEscapedCSSIdent(aParam, qparam);
 | |
|   const char16_t *params[2] = { qparam.get(), aValue.get() };
 | |
| 
 | |
|   nsAutoString str;
 | |
|   sStringBundle->FormatStringFromName(aMessage, params, ArrayLength(params),
 | |
|                                       str);
 | |
|   AddToError(str);
 | |
| }
 | |
| 
 | |
| void
 | |
| ErrorReporter::ReportUnexpectedEOF(const char *aMessage)
 | |
| {
 | |
|   if (!ShouldReportErrors()) return;
 | |
| 
 | |
|   nsAutoString innerStr;
 | |
|   sStringBundle->GetStringFromName(aMessage, innerStr);
 | |
|   const char16_t *params[1] = { innerStr.get() };
 | |
| 
 | |
|   nsAutoString str;
 | |
|   sStringBundle->FormatStringFromName("PEUnexpEOF2", params,
 | |
|                                       ArrayLength(params), str);
 | |
|   AddToError(str);
 | |
| }
 | |
| 
 | |
| void
 | |
| ErrorReporter::ReportUnexpectedEOF(char16_t aExpected)
 | |
| {
 | |
|   if (!ShouldReportErrors()) return;
 | |
| 
 | |
|   const char16_t expectedStr[] = {
 | |
|     char16_t('\''), aExpected, char16_t('\''), char16_t(0)
 | |
|   };
 | |
|   const char16_t *params[1] = { expectedStr };
 | |
| 
 | |
|   nsAutoString str;
 | |
|   sStringBundle->FormatStringFromName("PEUnexpEOF2", params,
 | |
|                                       ArrayLength(params), str);
 | |
|   AddToError(str);
 | |
| }
 | |
| 
 | |
| bool
 | |
| ErrorReporter::IsServo() const
 | |
| {
 | |
|   return !mScanner;
 | |
| }
 | |
| 
 | |
| } // namespace css
 | |
| } // namespace mozilla
 | |
| 
 | |
| #endif
 |