mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-25 19:25:43 +00:00
18fae65f38
This requires replacing inclusions of it with inclusions of more specific prefs files. The exception is that StaticPrefsAll.h, which is equivalent to StaticPrefs.h, and is used in `Codegen.py` because doing something smarter is tricky and suitable for a follow-up. As a result, any change to StaticPrefList.yaml will still trigger recompilation of all the generated DOM bindings files, but that's still a big improvement over trigger recompilation of every file that uses static prefs. Most of the changes in this commit are very boring. The only changes that are not boring are modules/libpref/*, Codegen.py, and ServoBindings.toml. Differential Revision: https://phabricator.services.mozilla.com/D39138 --HG-- extra : moz-landing-system : lando
316 lines
8.4 KiB
C++
316 lines
8.4 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/StaticPrefs_layout.h"
|
|
#include "mozilla/StyleSheetInlines.h"
|
|
#include "mozilla/css/Loader.h"
|
|
#include "mozilla/Preferences.h"
|
|
#include "mozilla/Services.h"
|
|
#include "mozilla/SystemGroup.h"
|
|
#include "nsIConsoleService.h"
|
|
#include "mozilla/dom/Document.h"
|
|
#include "nsIDocShell.h"
|
|
#include "nsIFactory.h"
|
|
#include "nsINode.h"
|
|
#include "nsIScriptError.h"
|
|
#include "nsISensitiveInfoHiddenURI.h"
|
|
#include "nsIStringBundle.h"
|
|
#include "nsServiceManagerUtils.h"
|
|
#include "nsStyleUtil.h"
|
|
#include "nsThreadUtils.h"
|
|
#include "nsNetUtil.h"
|
|
|
|
using namespace mozilla;
|
|
using namespace mozilla::css;
|
|
using namespace mozilla::dom;
|
|
|
|
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
|
|
|
|
bool ErrorReporter::sInitialized = false;
|
|
|
|
static nsIConsoleService* sConsoleService;
|
|
static nsIFactory* sScriptErrorFactory;
|
|
static nsIStringBundle* sStringBundle;
|
|
static ShortTermURISpecCache* sSpecCache;
|
|
|
|
void ErrorReporter::InitGlobals() {
|
|
MOZ_RELEASE_ASSERT(NS_IsMainThread());
|
|
MOZ_ASSERT(!sInitialized, "should not have been called");
|
|
|
|
sInitialized = true;
|
|
|
|
nsCOMPtr<nsIConsoleService> cs = do_GetService(NS_CONSOLESERVICE_CONTRACTID);
|
|
if (!cs) {
|
|
return;
|
|
}
|
|
|
|
nsCOMPtr<nsIFactory> sf = do_GetClassObject(NS_SCRIPTERROR_CONTRACTID);
|
|
if (!sf) {
|
|
return;
|
|
}
|
|
|
|
nsCOMPtr<nsIStringBundleService> sbs = services::GetStringBundleService();
|
|
if (!sbs) {
|
|
return;
|
|
}
|
|
|
|
nsCOMPtr<nsIStringBundle> sb;
|
|
nsresult rv = sbs->CreateBundle("chrome://global/locale/css.properties",
|
|
getter_AddRefs(sb));
|
|
if (NS_FAILED(rv) || !sb) {
|
|
return;
|
|
}
|
|
|
|
cs.forget(&sConsoleService);
|
|
sf.forget(&sScriptErrorFactory);
|
|
sb.forget(&sStringBundle);
|
|
}
|
|
|
|
namespace mozilla {
|
|
namespace css {
|
|
|
|
/* static */
|
|
void ErrorReporter::ReleaseGlobals() {
|
|
NS_IF_RELEASE(sConsoleService);
|
|
NS_IF_RELEASE(sScriptErrorFactory);
|
|
NS_IF_RELEASE(sStringBundle);
|
|
NS_IF_RELEASE(sSpecCache);
|
|
}
|
|
|
|
static uint64_t FindInnerWindowID(const StyleSheet* aSheet,
|
|
const Loader* aLoader) {
|
|
uint64_t innerWindowID = 0;
|
|
if (aSheet) {
|
|
innerWindowID = aSheet->FindOwningWindowInnerID();
|
|
}
|
|
if (innerWindowID == 0 && aLoader) {
|
|
if (Document* doc = aLoader->GetDocument()) {
|
|
innerWindowID = doc->InnerWindowID();
|
|
}
|
|
}
|
|
return innerWindowID;
|
|
}
|
|
|
|
ErrorReporter::ErrorReporter(const StyleSheet* aSheet, const Loader* aLoader,
|
|
nsIURI* aURI)
|
|
: mSheet(aSheet),
|
|
mLoader(aLoader),
|
|
mURI(aURI),
|
|
mErrorLineNumber(0),
|
|
mPrevErrorLineNumber(0),
|
|
mErrorColNumber(0) {
|
|
MOZ_ASSERT(ShouldReportErrors(mSheet, mLoader));
|
|
EnsureGlobalsInitialized();
|
|
}
|
|
|
|
ErrorReporter::~ErrorReporter() {
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
// 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();
|
|
}
|
|
}
|
|
}
|
|
|
|
bool ErrorReporter::ShouldReportErrors(const Document& aDoc) {
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
nsIDocShell* shell = aDoc.GetDocShell();
|
|
if (!shell) {
|
|
return false;
|
|
}
|
|
|
|
bool report = false;
|
|
shell->GetCssErrorReportingEnabled(&report);
|
|
return report;
|
|
}
|
|
|
|
static nsINode* SheetOwner(const StyleSheet& aSheet) {
|
|
if (nsINode* owner = aSheet.GetOwnerNode()) {
|
|
return owner;
|
|
}
|
|
|
|
auto* associated = aSheet.GetAssociatedDocumentOrShadowRoot();
|
|
return associated ? &associated->AsNode() : nullptr;
|
|
}
|
|
|
|
bool ErrorReporter::ShouldReportErrors(const StyleSheet* aSheet,
|
|
const Loader* aLoader) {
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
if (!StaticPrefs::layout_css_report_errors()) {
|
|
return false;
|
|
}
|
|
|
|
if (aSheet) {
|
|
nsINode* owner = SheetOwner(*aSheet);
|
|
if (owner && ShouldReportErrors(*owner->OwnerDoc())) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
if (aLoader && aLoader->GetDocument() &&
|
|
ShouldReportErrors(*aLoader->GetDocument())) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void ErrorReporter::OutputError() {
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
MOZ_ASSERT(ShouldReportErrors(mSheet, mLoader));
|
|
|
|
if (mError.IsEmpty()) {
|
|
return;
|
|
}
|
|
|
|
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",
|
|
FindInnerWindowID(mSheet, mLoader));
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
errorObject->SetCssSelectors(mSelectors);
|
|
sConsoleService->LogMessage(errorObject);
|
|
}
|
|
}
|
|
|
|
ClearError();
|
|
}
|
|
|
|
// 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,
|
|
const nsACString& aSelectors) {
|
|
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;
|
|
}
|
|
|
|
if (!AppendUTF8toUTF16(aSelectors, mSelectors, fallible)) {
|
|
mSelectors.Truncate();
|
|
}
|
|
|
|
OutputError();
|
|
}
|
|
|
|
void ErrorReporter::ClearError() { mError.Truncate(); }
|
|
|
|
void ErrorReporter::AddToError(const nsString& aErrorText) {
|
|
MOZ_ASSERT(ShouldReportErrors(mSheet, mLoader));
|
|
|
|
if (mError.IsEmpty()) {
|
|
mError = aErrorText;
|
|
} else {
|
|
mError.AppendLiteral(" ");
|
|
mError.Append(aErrorText);
|
|
}
|
|
}
|
|
|
|
void ErrorReporter::ReportUnexpected(const char* aMessage) {
|
|
MOZ_ASSERT(ShouldReportErrors(mSheet, mLoader));
|
|
|
|
nsAutoString str;
|
|
sStringBundle->GetStringFromName(aMessage, str);
|
|
AddToError(str);
|
|
}
|
|
|
|
void ErrorReporter::ReportUnexpectedUnescaped(
|
|
const char* aMessage, const nsTArray<nsString>& aParam) {
|
|
MOZ_ASSERT(ShouldReportErrors(mSheet, mLoader));
|
|
|
|
nsAutoString str;
|
|
sStringBundle->FormatStringFromName(aMessage, aParam, str);
|
|
AddToError(str);
|
|
}
|
|
|
|
} // namespace css
|
|
} // namespace mozilla
|