Bug 1352669 - Hook up Stylo CSS parser to Gecko error reporter. r=emilio
authorJosh Matthews <josh@joshmatthews.net>
Mon, 10 Jul 2017 17:52:00 -0400
changeset 403960 28e303771cc05441ca0312ed951a80e19c8fd898
parent 403959 98c3565c595d21d0a715899e21ed47fdddaffabf
child 403961 81adbdebbfe38cfb2264c7adc6748c32936a41db
push idunknown
push userunknown
push dateunknown
reviewersemilio
bugs1352669
milestone56.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1352669 - Hook up Stylo CSS parser to Gecko error reporter. r=emilio MozReview-Commit-ID: 3r5Z6KiPgRM
dom/animation/KeyframeUtils.cpp
dom/base/nsAttrValue.cpp
dom/canvas/CanvasRenderingContext2D.cpp
dom/smil/nsSMILCSSValueType.cpp
dom/svg/nsSVGElement.cpp
layout/style/CSSStyleSheet.cpp
layout/style/CSSStyleSheet.h
layout/style/ErrorReporter.cpp
layout/style/ErrorReporter.h
layout/style/ServoBindingList.h
layout/style/ServoBindings.cpp
layout/style/ServoBindings.h
layout/style/ServoBindings.toml
layout/style/ServoDeclarationBlock.cpp
layout/style/ServoDeclarationBlock.h
layout/style/StyleSheet.cpp
layout/style/StyleSheet.h
layout/style/nsDOMCSSAttrDeclaration.cpp
layout/style/nsDOMCSSDeclaration.cpp
layout/style/nsDOMCSSDeclaration.h
--- a/dom/animation/KeyframeUtils.cpp
+++ b/dom/animation/KeyframeUtils.cpp
@@ -562,17 +562,18 @@ KeyframeUtils::ParseProperty(nsCSSProper
   // FIXME this is using the wrong base uri (bug 1343919)
   RefPtr<URLExtraData> data = new URLExtraData(aDocument->GetDocumentURI(),
                                                aDocument->GetDocumentURI(),
                                                aDocument->NodePrincipal());
   return Servo_ParseProperty(aProperty,
                              &value,
                              data,
                              ParsingMode::Default,
-                             aDocument->GetCompatibilityMode()).Consume();
+                             aDocument->GetCompatibilityMode(),
+                             aDocument->CSSLoader()).Consume();
 }
 
 // ------------------------------------------------------------------
 //
 // Internal helpers
 //
 // ------------------------------------------------------------------
 
--- a/dom/base/nsAttrValue.cpp
+++ b/dom/base/nsAttrValue.cpp
@@ -1752,17 +1752,18 @@ nsAttrValue::ParseStyleAttribute(const n
     }
   }
 
   RefPtr<DeclarationBlock> decl;
   if (ownerDoc->GetStyleBackendType() == StyleBackendType::Servo) {
     RefPtr<URLExtraData> data = new URLExtraData(baseURI, docURI,
                                                  aElement->NodePrincipal());
     decl = ServoDeclarationBlock::FromCssText(aString, data,
-                                              ownerDoc->GetCompatibilityMode());
+                                              ownerDoc->GetCompatibilityMode(),
+                                              ownerDoc->CSSLoader());
   } else {
     css::Loader* cssLoader = ownerDoc->CSSLoader();
     nsCSSParser cssParser(cssLoader);
     decl = cssParser.ParseStyleAttribute(aString, docURI, baseURI,
                                          aElement->NodePrincipal());
   }
   if (!decl) {
     return false;
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -2807,34 +2807,36 @@ CreateDeclarationForServo(nsCSSPropertyI
 
   NS_ConvertUTF16toUTF8 value(aPropertyValue);
 
   RefPtr<RawServoDeclarationBlock> servoDeclarations =
     Servo_ParseProperty(aProperty,
                         &value,
                         data,
                         ParsingMode::Default,
-                        aDocument->GetCompatibilityMode()).Consume();
+                        aDocument->GetCompatibilityMode(),
+                        aDocument->CSSLoader()).Consume();
 
   if (!servoDeclarations) {
     // We got a syntax error.  The spec says this value must be ignored.
     return nullptr;
   }
 
   // From canvas spec, force to set line-height property to 'normal' font
   // property.
   if (aProperty == eCSSProperty_font) {
     const nsCString normalString = NS_LITERAL_CSTRING("normal");
     Servo_DeclarationBlock_SetPropertyById(servoDeclarations,
                                            eCSSProperty_line_height,
                                            &normalString,
                                            false,
                                            data,
                                            ParsingMode::Default,
-                                           aDocument->GetCompatibilityMode());
+                                           aDocument->GetCompatibilityMode(),
+                                           aDocument->CSSLoader());
   }
 
   return servoDeclarations.forget();
 }
 
 static already_AddRefed<RawServoDeclarationBlock>
 CreateFontDeclarationForServo(const nsAString& aFont,
                               nsIDocument* aDocument)
--- a/dom/smil/nsSMILCSSValueType.cpp
+++ b/dom/smil/nsSMILCSSValueType.cpp
@@ -689,17 +689,18 @@ ValueFromStringHelper(nsCSSPropertyID aP
                                                doc->NodePrincipal());
   NS_ConvertUTF16toUTF8 value(aString);
   RefPtr<RawServoDeclarationBlock> servoDeclarationBlock =
     Servo_ParseProperty(aPropID,
                         &value,
                         data,
                         ParsingMode::AllowUnitlessLength |
                         ParsingMode::AllowAllNumericValues,
-                        doc->GetCompatibilityMode()).Consume();
+                        doc->GetCompatibilityMode(),
+                        doc->CSSLoader()).Consume();
   if (!servoDeclarationBlock) {
     return result;
   }
 
   // Get a suitable style context for Servo
   const ServoComputedValues* currentStyle =
     aStyleContext->ComputedValues();
 
--- a/dom/svg/nsSVGElement.cpp
+++ b/dom/svg/nsSVGElement.cpp
@@ -1188,16 +1188,17 @@ public:
   // already_AddRefed css::Declaration that incorporates the parsed
   // values. Otherwise, this method returns null.
   already_AddRefed<DeclarationBlock> GetDeclarationBlock();
 
 private:
   // MEMBER DATA
   // -----------
   nsCSSParser       mParser;
+  css::Loader*      mLoader;
 
   // Arguments for nsCSSParser::ParseProperty
   nsIURI*           mDocURI;
   nsCOMPtr<nsIURI>  mBaseURI;
 
   // Declaration for storing parsed values (lazily initialized)
   RefPtr<DeclarationBlock> mDecl;
 
@@ -1207,17 +1208,17 @@ private:
   StyleBackendType mBackend;
 };
 
 MappedAttrParser::MappedAttrParser(css::Loader* aLoader,
                                    nsIURI* aDocURI,
                                    already_AddRefed<nsIURI> aBaseURI,
                                    nsSVGElement* aElement,
                                    StyleBackendType aBackend)
-  : mParser(aLoader), mDocURI(aDocURI), mBaseURI(aBaseURI),
+  : mParser(aLoader), mLoader(aLoader), mDocURI(aDocURI), mBaseURI(aBaseURI),
     mElement(aElement), mBackend(aBackend)
 {
 }
 
 MappedAttrParser::~MappedAttrParser()
 {
   MOZ_ASSERT(!mDecl,
              "If mDecl was initialized, it should have been returned via "
@@ -1248,17 +1249,17 @@ MappedAttrParser::ParseMappedAttrValue(n
                             mElement->NodePrincipal(), mDecl->AsGecko(), &changed, false, true);
     } else {
       NS_ConvertUTF16toUTF8 value(aMappedAttrValue);
       // FIXME (bug 1343964): Figure out a better solution for sending the base uri to servo
       RefPtr<URLExtraData> data = new URLExtraData(mBaseURI, mDocURI,
                                                    mElement->NodePrincipal());
       changed = Servo_DeclarationBlock_SetPropertyById(
         mDecl->AsServo()->Raw(), propertyID, &value, false, data,
-        ParsingMode::AllowUnitlessLength, mElement->OwnerDoc()->GetCompatibilityMode());
+        ParsingMode::AllowUnitlessLength, mElement->OwnerDoc()->GetCompatibilityMode(), mLoader);
     }
 
     if (changed) {
       // The normal reporting of use counters by the nsCSSParser won't happen
       // since it doesn't have a sheet.
       if (nsCSSProps::IsShorthand(propertyID)) {
         CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(subprop, propertyID,
                                              CSSEnabledState::eForAllContent) {
--- a/layout/style/CSSStyleSheet.cpp
+++ b/layout/style/CSSStyleSheet.cpp
@@ -514,44 +514,16 @@ CSSStyleSheet::HasRules() const
 }
 
 void
 CSSStyleSheet::EnabledStateChangedInternal()
 {
   ClearRuleCascades();
 }
 
-uint64_t
-CSSStyleSheet::FindOwningWindowInnerID() const
-{
-  uint64_t windowID = 0;
-  if (mDocument) {
-    windowID = mDocument->InnerWindowID();
-  }
-
-  if (windowID == 0 && mOwningNode) {
-    windowID = mOwningNode->OwnerDoc()->InnerWindowID();
-  }
-
-  if (windowID == 0 && mOwnerRule) {
-    RefPtr<StyleSheet> sheet =
-      static_cast<css::Rule*>(mOwnerRule)->GetStyleSheet();
-    if (sheet) {
-      windowID = sheet->AsGecko()->FindOwningWindowInnerID();
-    }
-  }
-
-  if (windowID == 0 && mParent) {
-    CSSStyleSheet* parentAsCSS = mParent->AsGecko();
-    windowID = parentAsCSS->FindOwningWindowInnerID();
-  }
-
-  return windowID;
-}
-
 void
 CSSStyleSheet::AppendStyleRule(css::Rule* aRule)
 {
   NS_PRECONDITION(nullptr != aRule, "null arg");
 
   WillDirty();
   Inner()->mOrderedRules.AppendObject(aRule);
   aRule->SetStyleSheet(this);
--- a/layout/style/CSSStyleSheet.h
+++ b/layout/style/CSSStyleSheet.h
@@ -96,18 +96,16 @@ public:
 
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(CSSStyleSheet, StyleSheet)
 
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_CSS_STYLE_SHEET_IMPL_CID)
 
   bool HasRules() const;
 
-  // Find the ID of the owner inner window.
-  uint64_t FindOwningWindowInnerID() const;
 #ifdef DEBUG
   void List(FILE* out = stdout, int32_t aIndent = 0) const override;
 #endif
 
   // XXX do these belong here or are they generic?
   void AppendStyleRule(css::Rule* aRule);
 
   int32_t StyleRuleCount() const;
--- a/layout/style/ErrorReporter.cpp
+++ b/layout/style/ErrorReporter.cpp
@@ -134,25 +134,34 @@ ErrorReporter::ReleaseGlobals()
 {
   NS_IF_RELEASE(sConsoleService);
   NS_IF_RELEASE(sScriptErrorFactory);
   NS_IF_RELEASE(sStringBundle);
   NS_IF_RELEASE(sSpecCache);
 }
 
 ErrorReporter::ErrorReporter(const nsCSSScanner& aScanner,
-                             const CSSStyleSheet* aSheet,
+                             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 StyleSheet* 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 =
@@ -223,45 +232,65 @@ ErrorReporter::OutputError()
       sConsoleService->LogMessage(errorObject);
     }
   }
 
   ClearError();
 }
 
 void
-ErrorReporter::OutputError(uint32_t aLineNumber, uint32_t aLineOffset)
+ErrorReporter::OutputError(uint32_t aLineNumber, uint32_t aColNumber)
 {
   mErrorLineNumber = aLineNumber;
-  mErrorColNumber = aLineOffset;
+  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)
+{
+  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(aLineNumber, aColNumber);
+}
+
 void
 ErrorReporter::ClearError()
 {
   mError.Truncate();
 }
 
 void
 ErrorReporter::AddToError(const nsString &aErrorText)
 {
   if (!ShouldReportErrors()) return;
 
   if (mError.IsEmpty()) {
     mError = aErrorText;
-    mErrorLineNumber = mScanner->GetLineNumber();
-    mErrorColNumber = mScanner->GetColumnNumber();
+    mErrorLineNumber = mScanner ? mScanner->GetLineNumber() : 0;
+    mErrorColNumber = mScanner ? mScanner->GetColumnNumber() : 0;
     // 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)) {
+      if (!mScanner || !mErrorLine.Assign(mScanner->GetCurrentLine(), fallible)) {
         mErrorLine.Truncate();
       }
       mPrevErrorLineNumber = mErrorLineNumber;
     }
   } else {
     mError.AppendLiteral("  ");
     mError.Append(aErrorText);
   }
@@ -291,30 +320,39 @@ ErrorReporter::ReportUnexpected(const ch
   nsAutoString str;
   sStringBundle->FormatStringFromName(NS_ConvertASCIItoUTF16(aMessage).get(),
                                       params, ArrayLength(params),
                                       getter_Copies(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(NS_ConvertASCIItoUTF16(aMessage).get(),
+                                      params, ArrayLength(params),
+                                      getter_Copies(str));
+  AddToError(str);
+}
+
+void
 ErrorReporter::ReportUnexpected(const char *aMessage,
                                 const nsCSSToken &aToken)
 {
   if (!ShouldReportErrors()) return;
 
   nsAutoString tokenString;
   aToken.AppendToString(tokenString);
-  const char16_t *params[1] = { tokenString.get() };
-
-  nsAutoString str;
-  sStringBundle->FormatStringFromName(NS_ConvertASCIItoUTF16(aMessage).get(),
-                                      params, ArrayLength(params),
-                                      getter_Copies(str));
-  AddToError(str);
+  ReportUnexpectedUnescaped(aMessage, tokenString);
 }
 
 void
 ErrorReporter::ReportUnexpected(const char *aMessage,
                                 const nsCSSToken &aToken,
                                 char16_t aChar)
 {
   if (!ShouldReportErrors()) return;
--- a/layout/style/ErrorReporter.h
+++ b/layout/style/ErrorReporter.h
@@ -21,40 +21,47 @@ namespace mozilla {
 class CSSStyleSheet;
 
 namespace css {
 
 class Loader;
 
 // If CSS_REPORT_PARSE_ERRORS is not defined, all of this class's
 // methods become inline stubs.
-class MOZ_STACK_CLASS ErrorReporter {
+class ErrorReporter {
 public:
   ErrorReporter(const nsCSSScanner &aScanner,
-                const CSSStyleSheet *aSheet,
+                const StyleSheet *aSheet,
+                const Loader *aLoader,
+                nsIURI *aURI);
+  ErrorReporter(const StyleSheet *aSheet,
                 const Loader *aLoader,
                 nsIURI *aURI);
   ~ErrorReporter();
 
   static void ReleaseGlobals();
 
   void OutputError();
   void OutputError(uint32_t aLineNumber, uint32_t aLineOffset);
+  void OutputError(uint32_t aLineNumber, uint32_t aLineOffset, const nsACString& aSource);
   void ClearError();
 
   // In all overloads of ReportUnexpected, aMessage is a stringbundle
   // name, which will be processed as a format string with the
   // indicated number of parameters.
 
   // no parameters
   void ReportUnexpected(const char *aMessage);
   // one parameter, a string
   void ReportUnexpected(const char *aMessage, const nsString& aParam);
   // one parameter, a token
   void ReportUnexpected(const char *aMessage, const nsCSSToken& aToken);
+  // one parameter which has already been escaped appropriately
+  void ReportUnexpectedUnescaped(const char *aMessage,
+                                 const nsAutoString& aParam);
   // two parameters, a token and a character, in that order
   void ReportUnexpected(const char *aMessage, const nsCSSToken& aToken,
                         char16_t aChar);
   // two parameters, a param and a value
   void ReportUnexpected(const char *aMessage, const nsString& aParam,
                         const nsString& aValue);
 
   // for ReportUnexpectedEOF, aExpected can be either a stringbundle
@@ -66,17 +73,17 @@ public:
 private:
   void AddToError(const nsString &aErrorText);
 
 #ifdef CSS_REPORT_PARSE_ERRORS
   nsAutoString mError;
   nsString mErrorLine;
   nsString mFileName;
   const nsCSSScanner *mScanner;
-  const CSSStyleSheet *mSheet;
+  const StyleSheet *mSheet;
   const Loader *mLoader;
   nsIURI *mURI;
   uint64_t mInnerWindowID;
   uint32_t mErrorLineNumber;
   uint32_t mPrevErrorLineNumber;
   uint32_t mErrorColNumber;
 #endif
 };
--- a/layout/style/ServoBindingList.h
+++ b/layout/style/ServoBindingList.h
@@ -210,17 +210,18 @@ SERVO_BINDING_FUNC(Servo_DocumentRule_Ge
                    RawServoDocumentRuleBorrowed rule, nsAString* result)
 
 // Animations API
 SERVO_BINDING_FUNC(Servo_ParseProperty,
                    RawServoDeclarationBlockStrong,
                    nsCSSPropertyID property, const nsACString* value,
                    RawGeckoURLExtraData* data,
                    mozilla::ParsingMode parsing_mode,
-                   nsCompatibility quirks_mode)
+                   nsCompatibility quirks_mode,
+                   mozilla::css::Loader* loader)
 SERVO_BINDING_FUNC(Servo_ParseEasing, bool,
                    const nsAString* easing,
                    RawGeckoURLExtraData* data,
                    nsTimingFunctionBorrowedMut output)
 SERVO_BINDING_FUNC(Servo_GetComputedKeyframeValues, void,
                    RawGeckoKeyframeListBorrowed keyframes,
                    RawGeckoElementBorrowed element,
                    ServoComputedValuesBorrowed style,
@@ -305,17 +306,18 @@ SERVO_BINDING_FUNC(Servo_AnimationValue_
                    RawServoDeclarationBlockBorrowed declarations,
                    ServoComputedValuesBorrowed style,
                    RawServoStyleSetBorrowed raw_data)
 
 // Style attribute
 SERVO_BINDING_FUNC(Servo_ParseStyleAttribute, RawServoDeclarationBlockStrong,
                    const nsACString* data,
                    RawGeckoURLExtraData* extra_data,
-                   nsCompatibility quirks_mode)
+                   nsCompatibility quirks_mode,
+                   mozilla::css::Loader* loader)
 SERVO_BINDING_FUNC(Servo_DeclarationBlock_CreateEmpty,
                    RawServoDeclarationBlockStrong)
 SERVO_BINDING_FUNC(Servo_DeclarationBlock_Clone, RawServoDeclarationBlockStrong,
                    RawServoDeclarationBlockBorrowed declarations)
 SERVO_BINDING_FUNC(Servo_DeclarationBlock_Equals, bool,
                    RawServoDeclarationBlockBorrowed a,
                    RawServoDeclarationBlockBorrowed b)
 SERVO_BINDING_FUNC(Servo_DeclarationBlock_GetCssText, void,
@@ -339,24 +341,26 @@ SERVO_BINDING_FUNC(Servo_DeclarationBloc
                    RawServoDeclarationBlockBorrowed declarations,
                    const nsACString* property)
 SERVO_BINDING_FUNC(Servo_DeclarationBlock_SetProperty, bool,
                    RawServoDeclarationBlockBorrowed declarations,
                    const nsACString* property,
                    const nsACString* value, bool is_important,
                    RawGeckoURLExtraData* data,
                    mozilla::ParsingMode parsing_mode,
-                   nsCompatibility quirks_mode)
+                   nsCompatibility quirks_mode,
+                   mozilla::css::Loader* loader)
 SERVO_BINDING_FUNC(Servo_DeclarationBlock_SetPropertyById, bool,
                    RawServoDeclarationBlockBorrowed declarations,
                    nsCSSPropertyID property,
                    const nsACString* value, bool is_important,
                    RawGeckoURLExtraData* data,
                    mozilla::ParsingMode parsing_mode,
-                   nsCompatibility quirks_mode)
+                   nsCompatibility quirks_mode,
+                   mozilla::css::Loader* loader)
 SERVO_BINDING_FUNC(Servo_DeclarationBlock_RemoveProperty, void,
                    RawServoDeclarationBlockBorrowed declarations,
                    const nsACString* property)
 SERVO_BINDING_FUNC(Servo_DeclarationBlock_RemovePropertyById, void,
                    RawServoDeclarationBlockBorrowed declarations,
                    nsCSSPropertyID property)
 SERVO_BINDING_FUNC(Servo_DeclarationBlock_HasCSSWideKeyword, bool,
                    RawServoDeclarationBlockBorrowed declarations,
--- a/layout/style/ServoBindings.cpp
+++ b/layout/style/ServoBindings.cpp
@@ -2,16 +2,17 @@
 /* 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/. */
 
 #include "mozilla/ServoBindings.h"
 
 #include "ChildIterator.h"
+#include "ErrorReporter.h"
 #include "GeckoProfiler.h"
 #include "gfxFontFamilyList.h"
 #include "nsAnimationManager.h"
 #include "nsAttrValueInlines.h"
 #include "nsCSSCounterStyleRule.h"
 #include "nsCSSFontFaceRule.h"
 #include "nsCSSFrameConstructor.h"
 #include "nsCSSProps.h"
@@ -65,16 +66,17 @@
 #include "mozilla/LookAndFeel.h"
 #include "mozilla/URLExtraData.h"
 
 #if defined(MOZ_MEMORY)
 # include "mozmemory.h"
 #endif
 
 using namespace mozilla;
+using namespace mozilla::css;
 using namespace mozilla::dom;
 
 #define SERVO_ARC_TYPE(name_, type_) \
   already_AddRefed<type_>            \
   type_##Strong::Consume() {         \
     RefPtr<type_> result;            \
     result.swap(mPtr);               \
     return result.forget();          \
@@ -2626,8 +2628,43 @@ Gecko_SetJemallocThreadLocalArena(bool e
 #ifndef MOZ_STYLO
 #define SERVO_BINDING_FUNC(name_, return_, ...)                               \
   return_ name_(__VA_ARGS__) {                                                \
     MOZ_CRASH("stylo: shouldn't be calling " #name_ "in a non-stylo build");  \
   }
 #include "ServoBindingList.h"
 #undef SERVO_BINDING_FUNC
 #endif
+
+ErrorReporter*
+Gecko_CreateCSSErrorReporter(ServoStyleSheet* sheet,
+                             Loader* loader,
+                             nsIURI* uri)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  return new ErrorReporter(sheet, loader, uri);
+}
+
+void
+Gecko_DestroyCSSErrorReporter(ErrorReporter* reporter)
+{
+  delete reporter;
+}
+
+void
+Gecko_ReportUnexpectedCSSError(ErrorReporter* reporter,
+                               const char* message,
+                               const char* param,
+                               uint32_t paramLen,
+                               const char* source,
+                               uint32_t sourceLen,
+                               uint32_t lineNumber,
+                               uint32_t colNumber,
+                               nsIURI* uri)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsDependentCSubstring paramValue(param, paramLen);
+  nsAutoString wideParam = NS_ConvertUTF8toUTF16(paramValue);
+  reporter->ReportUnexpectedUnescaped(message, wideParam);
+  nsDependentCSubstring sourceValue(source, sourceLen);
+  reporter->OutputError(lineNumber, colNumber, sourceValue);
+}
--- a/layout/style/ServoBindings.h
+++ b/layout/style/ServoBindings.h
@@ -634,11 +634,25 @@ void Gecko_SetJemallocThreadLocalArena(b
   const uint32_t SERVO_CSS_PSEUDO_ELEMENT_FLAGS_##name_ = flags_;
 #include "nsCSSPseudoElementList.h"
 #undef CSS_PSEUDO_ELEMENT
 
 #define SERVO_BINDING_FUNC(name_, return_, ...) return_ name_(__VA_ARGS__);
 #include "mozilla/ServoBindingList.h"
 #undef SERVO_BINDING_FUNC
 
+mozilla::css::ErrorReporter* Gecko_CreateCSSErrorReporter(mozilla::ServoStyleSheet* sheet,
+                                                          mozilla::css::Loader* loader,
+                                                          nsIURI* uri);
+void Gecko_DestroyCSSErrorReporter(mozilla::css::ErrorReporter* reporter);
+void Gecko_ReportUnexpectedCSSError(mozilla::css::ErrorReporter* reporter,
+                                    const char* message,
+                                    const char* param,
+                                    uint32_t paramLen,
+                                    const char* source,
+                                    uint32_t sourceLen,
+                                    uint32_t lineNumber,
+                                    uint32_t colNumber,
+                                    nsIURI* aURI);
+
 } // extern "C"
 
 #endif // mozilla_ServoBindings_h
--- a/layout/style/ServoBindings.toml
+++ b/layout/style/ServoBindings.toml
@@ -51,16 +51,17 @@ headers = [
     "mozilla/dom/AnimationEffectReadOnlyBinding.h",
     "mozilla/dom/KeyframeEffectBinding.h",
     "mozilla/AnimationPropertySegment.h",
     "mozilla/ComputedTiming.h",
     "mozilla/ComputedTimingFunction.h",
     "mozilla/Keyframe.h",
     "mozilla/ServoElementSnapshot.h",
     "mozilla/ServoElementSnapshotTable.h",
+    "mozilla/css/ErrorReporter.h",
     "mozilla/dom/Element.h",
     "mozilla/dom/ChildIterator.h",
     "mozilla/dom/NameSpaceConstants.h",
     "mozilla/LookAndFeel.h",
     "mozilla/ServoBindings.h",
     "mozilla/ServoMediaList.h",
     "nsCSSCounterStyleRule.h",
     "nsCSSFontFaceRule.h",
@@ -117,16 +118,17 @@ whitelist-types = [
     "RawGecko.*",
     "mozilla::AnimationPropertySegment",
     "mozilla::ComputedTiming",
     "mozilla::ComputedTimingFunction",
     "mozilla::ComputedTimingFunction::BeforeFlag",
     "mozilla::ServoElementSnapshot.*",
     "mozilla::ServoStyleSheetInner",
     "mozilla::CSSPseudoClassType",
+    "mozilla::css::ErrorReporter",
     "mozilla::css::SheetParsingMode",
     "mozilla::css::URLMatchingFunction",
     "mozilla::dom::IterationCompositeOperation",
     "mozilla::dom::StyleChildrenIterator",
     "mozilla::HalfCorner",
     "mozilla::PropertyStyleAnimationValuePair",
     "mozilla::TraversalRestyleBehavior",
     "mozilla::TraversalRootBehavior",
@@ -324,16 +326,17 @@ raw-lines = [
     "use gecko_bindings::structs::nsStyleTransformMatrix;",
     "use gecko_bindings::structs::nsTArray;",
     "type nsACString_internal = nsACString;",
     "type nsAString_internal = nsAString;",
 ]
 whitelist-functions = ["Servo_.*", "Gecko_.*"]
 structs-types = [
     "mozilla::css::GridTemplateAreasValue",
+    "mozilla::css::ErrorReporter",
     "mozilla::css::ImageValue",
     "mozilla::css::URLValue",
     "mozilla::css::URLValueData",
     "mozilla::MallocSizeOf",
     "mozilla::Side",
     "nsIContent",
     "nsIDocument",
     "nsIDocument_DocumentTheme",
@@ -389,16 +392,17 @@ structs-types = [
     "nsCSSShadowArray",
     "nsCSSUnit",
     "nsCSSValue",
     "nsCSSValueSharedList",
     "nsChangeHint",
     "nsCursorImage",
     "nsFont",
     "nsIAtom",
+    "nsIURI",
     "nsCompatibility",
     "nsMediaFeature",
     "nsRestyleHint",
     "nsStyleBackground",
     "nsStyleBorder",
     "nsStyleColor",
     "nsStyleColumn",
     "nsStyleContent",
--- a/layout/style/ServoDeclarationBlock.cpp
+++ b/layout/style/ServoDeclarationBlock.cpp
@@ -9,22 +9,23 @@
 
 #include "nsCSSProps.h"
 
 namespace mozilla {
 
 /* static */ already_AddRefed<ServoDeclarationBlock>
 ServoDeclarationBlock::FromCssText(const nsAString& aCssText,
                                    URLExtraData* aExtraData,
-                                   nsCompatibility aMode)
+                                   nsCompatibility aMode,
+                                   css::Loader* aLoader)
 {
   NS_ConvertUTF16toUTF8 value(aCssText);
   // FIXME (bug 1343964): Figure out a better solution for sending the base uri to servo
   RefPtr<RawServoDeclarationBlock>
-    raw = Servo_ParseStyleAttribute(&value, aExtraData, aMode).Consume();
+      raw = Servo_ParseStyleAttribute(&value, aExtraData, aMode, aLoader).Consume();
   RefPtr<ServoDeclarationBlock> decl = new ServoDeclarationBlock(raw.forget());
   return decl.forget();
 }
 
 void
 ServoDeclarationBlock::GetPropertyValue(const nsAString& aProperty,
                                         nsAString& aValue) const
 {
--- a/layout/style/ServoDeclarationBlock.h
+++ b/layout/style/ServoDeclarationBlock.h
@@ -24,17 +24,17 @@ public:
   ServoDeclarationBlock(const ServoDeclarationBlock& aCopy)
     : DeclarationBlock(aCopy)
     , mRaw(Servo_DeclarationBlock_Clone(aCopy.mRaw).Consume()) {}
 
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ServoDeclarationBlock)
 
   static already_AddRefed<ServoDeclarationBlock>
   FromCssText(const nsAString& aCssText, URLExtraData* aExtraData,
-              nsCompatibility aMode);
+              nsCompatibility aMode, css::Loader* aLoader);
 
   RawServoDeclarationBlock* Raw() const { return mRaw; }
   RawServoDeclarationBlock* const* RefRaw() const {
     static_assert(sizeof(RefPtr<RawServoDeclarationBlock>) ==
                   sizeof(RawServoDeclarationBlock*),
                   "RefPtr should just be a pointer");
     return reinterpret_cast<RawServoDeclarationBlock* const*>(&mRaw);
   }
--- a/layout/style/StyleSheet.cpp
+++ b/layout/style/StyleSheet.cpp
@@ -606,16 +606,43 @@ StyleSheet::InsertRuleIntoGroup(const ns
 
   if (mDocument) {
     mDocument->StyleRuleAdded(this, aGroup->GetStyleRuleAt(aIndex));
   }
 
   return NS_OK;
 }
 
+uint64_t
+StyleSheet::FindOwningWindowInnerID() const
+{
+  uint64_t windowID = 0;
+  if (mDocument) {
+    windowID = mDocument->InnerWindowID();
+  }
+
+  if (windowID == 0 && mOwningNode) {
+    windowID = mOwningNode->OwnerDoc()->InnerWindowID();
+  }
+
+  RefPtr<css::Rule> ownerRule;
+  if (windowID == 0 && (ownerRule = GetDOMOwnerRule())) {
+    RefPtr<StyleSheet> sheet = ownerRule->GetStyleSheet();
+    if (sheet) {
+      windowID = sheet->FindOwningWindowInnerID();
+    }
+  }
+
+  if (windowID == 0 && mParent) {
+    windowID = mParent->FindOwningWindowInnerID();
+  }
+
+  return windowID;
+}
+
 void
 StyleSheet::EnabledStateChanged()
 {
   FORWARD_INTERNAL(EnabledStateChangedInternal, ())
 }
 
 #undef FORWARD_INTERNAL
 
--- a/layout/style/StyleSheet.h
+++ b/layout/style/StyleSheet.h
@@ -259,16 +259,19 @@ public:
 
   void AddStyleSet(const StyleSetHandle& aStyleSet);
   void DropStyleSet(const StyleSetHandle& aStyleSet);
 
   nsresult DeleteRuleFromGroup(css::GroupRule* aGroup, uint32_t aIndex);
   nsresult InsertRuleIntoGroup(const nsAString& aRule,
                                css::GroupRule* aGroup, uint32_t aIndex);
 
+  // Find the ID of the owner inner window.
+  uint64_t FindOwningWindowInnerID() const;
+
   template<typename Func>
   void EnumerateChildSheets(Func aCallback) {
     for (StyleSheet* child = GetFirstChild(); child; child = child->mNext) {
       aCallback(child);
     }
   }
 
 private:
--- a/layout/style/nsDOMCSSAttrDeclaration.cpp
+++ b/layout/style/nsDOMCSSAttrDeclaration.cpp
@@ -175,16 +175,17 @@ nsDOMCSSAttributeDeclaration::GetCSSPars
 }
 
 nsDOMCSSDeclaration::ServoCSSParsingEnvironment
 nsDOMCSSAttributeDeclaration::GetServoCSSParsingEnvironment() const
 {
   return {
     mElement->GetURLDataForStyleAttr(),
     mElement->OwnerDoc()->GetCompatibilityMode(),
+    mElement->OwnerDoc()->CSSLoader(),
   };
 }
 
 NS_IMETHODIMP
 nsDOMCSSAttributeDeclaration::GetParentRule(nsIDOMCSSRule **aParent)
 {
   NS_ENSURE_ARG_POINTER(aParent);
 
--- a/layout/style/nsDOMCSSDeclaration.cpp
+++ b/layout/style/nsDOMCSSDeclaration.cpp
@@ -125,17 +125,17 @@ nsDOMCSSDeclaration::SetCssText(const ns
   RefPtr<DeclarationBlock> newdecl;
   if (olddecl->IsServo()) {
     ServoCSSParsingEnvironment servoEnv = GetServoCSSParsingEnvironment();
     if (!servoEnv.mUrlExtraData) {
       return NS_ERROR_NOT_AVAILABLE;
     }
 
     newdecl = ServoDeclarationBlock::FromCssText(aCssText, servoEnv.mUrlExtraData,
-                                                 servoEnv.mCompatMode);
+                                                 servoEnv.mCompatMode, servoEnv.mLoader);
   } else {
     CSSParsingEnvironment geckoEnv;
     GetCSSParsingEnvironment(geckoEnv);
     if (!geckoEnv.mPrincipal) {
       return NS_ERROR_NOT_AVAILABLE;
     }
 
     RefPtr<css::Declaration> decl(new css::Declaration());
@@ -279,29 +279,31 @@ nsDOMCSSDeclaration::GetCSSParsingEnviro
   aCSSParseEnv.mCSSLoader = document ? document->CSSLoader() : nullptr;
 }
 
 /* static */ nsDOMCSSDeclaration::ServoCSSParsingEnvironment
 nsDOMCSSDeclaration::GetServoCSSParsingEnvironmentForRule(const css::Rule* aRule)
 {
   StyleSheet* sheet = aRule ? aRule->GetStyleSheet() : nullptr;
   if (!sheet) {
-    return { nullptr, eCompatibility_FullStandards };
+    return { nullptr, eCompatibility_FullStandards, nullptr };
   }
 
   if (nsIDocument* document = aRule->GetDocument()) {
     return {
       sheet->AsServo()->URLData(),
       document->GetCompatibilityMode(),
+      document->CSSLoader(),
     };
   }
 
   return {
     sheet->AsServo()->URLData(),
     eCompatibility_FullStandards,
+    nullptr,
   };
 }
 
 template<typename GeckoFunc, typename ServoFunc>
 nsresult
 nsDOMCSSDeclaration::ModifyDeclaration(GeckoFunc aGeckoFunc,
                                        ServoFunc aServoFunc)
 {
@@ -364,17 +366,17 @@ nsDOMCSSDeclaration::ParsePropertyValue(
       cssParser.ParseProperty(aPropID, aPropValue,
                               env.mSheetURI, env.mBaseURI, env.mPrincipal,
                               decl, changed, aIsImportant);
     },
     [&](ServoDeclarationBlock* decl, ServoCSSParsingEnvironment& env) {
       NS_ConvertUTF16toUTF8 value(aPropValue);
       return Servo_DeclarationBlock_SetPropertyById(
         decl->Raw(), aPropID, &value, aIsImportant, env.mUrlExtraData,
-        ParsingMode::Default, env.mCompatMode);
+        ParsingMode::Default, env.mCompatMode, env.mLoader);
     });
 }
 
 nsresult
 nsDOMCSSDeclaration::ParseCustomPropertyValue(const nsAString& aPropertyName,
                                               const nsAString& aPropValue,
                                               bool aIsImportant)
 {
@@ -387,17 +389,17 @@ nsDOMCSSDeclaration::ParseCustomProperty
                               env.mBaseURI, env.mPrincipal, decl,
                               changed, aIsImportant);
     },
     [&](ServoDeclarationBlock* decl, ServoCSSParsingEnvironment& env) {
       NS_ConvertUTF16toUTF8 property(aPropertyName);
       NS_ConvertUTF16toUTF8 value(aPropValue);
       return Servo_DeclarationBlock_SetProperty(
         decl->Raw(), &property, &value, aIsImportant, env.mUrlExtraData,
-        ParsingMode::Default, env.mCompatMode);
+        ParsingMode::Default, env.mCompatMode, env.mLoader);
     });
 }
 
 nsresult
 nsDOMCSSDeclaration::RemovePropertyInternal(nsCSSPropertyID aPropID)
 {
   DeclarationBlock* olddecl = GetCSSDeclaration(eOperation_RemoveProperty);
   if (!olddecl) {
--- a/layout/style/nsDOMCSSDeclaration.h
+++ b/layout/style/nsDOMCSSDeclaration.h
@@ -148,21 +148,24 @@ protected:
                                          "performance overhead (see bug 649163)") mCSSLoader;
   };
 
   // Information neded to parse a declaration for Servo side.
   struct MOZ_STACK_CLASS ServoCSSParsingEnvironment
   {
     mozilla::URLExtraData* mUrlExtraData;
     nsCompatibility mCompatMode;
+    mozilla::css::Loader* mLoader;
 
     ServoCSSParsingEnvironment(mozilla::URLExtraData* aUrlData,
-                               nsCompatibility aCompatMode)
+                               nsCompatibility aCompatMode,
+                               mozilla::css::Loader* aLoader)
       : mUrlExtraData(aUrlData)
       , mCompatMode(aCompatMode)
+      , mLoader(aLoader)
     {}
   };
 
   // On failure, mPrincipal should be set to null in aCSSParseEnv.
   // If mPrincipal is null, the other members may not be set to
   // anything meaningful.
   virtual void GetCSSParsingEnvironment(CSSParsingEnvironment& aCSSParseEnv) = 0;