Bug 801176 - part3-v6: Keep CSSParser operations as threading safe. r=heycam
authorvincentliu <vliu@mozilla.com>
Fri, 04 Mar 2016 15:22:58 +0800
changeset 336834 fc509e59a0cd5a3537914158fada88c9cd1033a6
parent 336833 134a8c56335a92fdf3461ecb489a7a4b1dfcaf1c
child 336835 c090dc98c670430e2dd99bd139fabe1b094f8582
push id12189
push usercku@mozilla.com
push dateFri, 04 Mar 2016 07:52:22 +0000
reviewersheycam
bugs801176
milestone47.0a1
Bug 801176 - part3-v6: Keep CSSParser operations as threading safe. r=heycam --- dom/canvas/CanvasRenderingContext2D.cpp | 13 +++++--- layout/style/ErrorReporter.cpp | 9 +++++- layout/style/nsCSSParser.cpp | 55 ++++++++++++++++++++------------- 3 files changed, 51 insertions(+), 26 deletions(-)
dom/canvas/CanvasRenderingContext2D.cpp
layout/style/ErrorReporter.cpp
layout/style/nsCSSParser.cpp
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -679,17 +679,19 @@ CanvasGradient::AddColorStop(float aOffs
   nsCSSValue value;
   nsCSSParser parser;
   if (!parser.ParseColorString(aColorstr, nullptr, 0, value)) {
     aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
     return;
   }
 
   nscolor color;
-  nsCOMPtr<nsIPresShell> presShell = mContext ? mContext->GetPresShell() : nullptr;
+  nsCOMPtr<nsIPresShell> presShell = NS_IsMainThread() && mContext
+                                     ? mContext->GetPresShell()
+                                     : nullptr;
   if (!nsRuleNode::ComputeColor(value, presShell ? presShell->GetPresContext() : nullptr,
                                 nullptr, color)) {
     aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
     return;
   }
 
   mStops = nullptr;
 
@@ -1012,35 +1014,38 @@ CanvasRenderingContext2D::WrapObject(JSC
 {
   return CanvasRenderingContext2DBinding::Wrap(aCx, this, aGivenProto);
 }
 
 bool
 CanvasRenderingContext2D::ParseColor(const nsAString& aString,
                                      nscolor* aColor)
 {
-  nsIDocument* document = mCanvasElement
+  nsIDocument* document = NS_IsMainThread() && mCanvasElement
                           ? mCanvasElement->OwnerDoc()
                           : nullptr;
 
   // Pass the CSS Loader object to the parser, to allow parser error
   // reports to include the outer window ID.
   nsCSSParser parser(document ? document->CSSLoader() : nullptr);
   nsCSSValue value;
   if (!parser.ParseColorString(aString, nullptr, 0, value)) {
     return false;
   }
 
   if (value.IsNumericColorUnit()) {
     // if we already have a color we can just use it directly
     *aColor = value.GetColorValue();
   } else {
     // otherwise resolve it
-    nsCOMPtr<nsIPresShell> presShell = GetPresShell();
-    RefPtr<nsStyleContext> parentContext;
+    nsCOMPtr<nsIPresShell> presShell = NS_IsMainThread()
+                                      ? GetPresShell()
+                                      : nullptr;
+
+    RefPtr<nsStyleContext> parentContext = nullptr;
     if (mCanvasElement && mCanvasElement->IsInDoc()) {
       // Inherit from the canvas element.
       parentContext = nsComputedDOMStyle::GetStyleContextForElement(
         mCanvasElement, nullptr, presShell);
     }
 
     Unused << nsRuleNode::ComputeColor(
       value, presShell ? presShell->GetPresContext() : nullptr, parentContext,
--- a/layout/style/ErrorReporter.cpp
+++ b/layout/style/ErrorReporter.cpp
@@ -107,16 +107,22 @@ InitGlobals()
   sb.forget(&sStringBundle);
 
   return true;
 }
 
 static inline bool
 ShouldReportErrors()
 {
+  // we only need to do CSS parsing off the main thread for canvas-on-workers currently,
+  // where we don't need to report any CSS parser errors
+  if (!NS_IsMainThread()) {
+    return false;
+  }
+
   if (!sConsoleService) {
     if (!InitGlobals()) {
       return false;
     }
   }
   return sReportErrors;
 }
 
@@ -142,17 +148,18 @@ ErrorReporter::ErrorReporter(const nsCSS
 {
 }
 
 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()) {
+  if (NS_IsMainThread() && sSpecCache && sSpecCache->IsInUse() &&
+      !sSpecCache->IsPending()) {
     if (NS_FAILED(NS_DispatchToCurrentThread(sSpecCache))) {
       // Peform the "deferred" cleanup immediately if the dispatch fails.
       sSpecCache->Run();
     } else {
       sSpecCache->SetPending();
     }
   }
 }
--- a/layout/style/nsCSSParser.cpp
+++ b/layout/style/nsCSSParser.cpp
@@ -1529,22 +1529,24 @@ CSSParserImpl::CSSParserImpl()
     mParsingCompoundProperty(false),
     mInSupportsCondition(false),
     mInFailingSupportsRule(false),
     mSuppressErrors(false),
     mSheetPrincipalRequired(true),
     mWebkitBoxUnprefixState(eNotParsingDecls),
     mNextFree(nullptr)
 {
+  MOZ_COUNT_CTOR(CSSParserImpl);
 }
 
 CSSParserImpl::~CSSParserImpl()
 {
   mData.AssertInitialState();
   mTempData.AssertInitialState();
+  MOZ_COUNT_DTOR(CSSParserImpl);
 }
 
 nsresult
 CSSParserImpl::SetStyleSheet(CSSStyleSheet* aSheet)
 {
   if (aSheet != mSheet) {
     // Switch to using the new sheet, if any
     mGroupStack.Clear();
@@ -17166,55 +17168,66 @@ nsCSSParser::Startup()
                                "layout.css.prefixes.gradients");
   Preferences::AddBoolVarCache(&sControlCharVisibility,
                                "layout.css.control-characters.visible");
 }
 
 nsCSSParser::nsCSSParser(mozilla::css::Loader* aLoader,
                          CSSStyleSheet* aSheet)
 {
-  CSSParserImpl *impl = gFreeList;
-  if (impl) {
-    gFreeList = impl->mNextFree;
-    impl->mNextFree = nullptr;
+  CSSParserImpl *impl;
+  if (NS_IsMainThread()) {
+    impl = gFreeList;
+    if (impl) {
+      gFreeList = impl->mNextFree;
+      impl->mNextFree = nullptr;
+    } else {
+      impl = new CSSParserImpl();
+    }
+
+    if (aLoader) {
+      impl->SetChildLoader(aLoader);
+      impl->SetQuirkMode(aLoader->GetCompatibilityMode() ==
+                         eCompatibility_NavQuirks);
+    }
+    if (aSheet) {
+      impl->SetStyleSheet(aSheet);
+    }
   } else {
+    MOZ_ASSERT(!aLoader);
+    MOZ_ASSERT(!aSheet);
     impl = new CSSParserImpl();
   }
-
-  if (aLoader) {
-    impl->SetChildLoader(aLoader);
-    impl->SetQuirkMode(aLoader->GetCompatibilityMode() ==
-                       eCompatibility_NavQuirks);
-  }
-  if (aSheet) {
-    impl->SetStyleSheet(aSheet);
-  }
-
   mImpl = static_cast<void*>(impl);
 }
 
 nsCSSParser::~nsCSSParser()
 {
   CSSParserImpl *impl = static_cast<CSSParserImpl*>(mImpl);
   impl->Reset();
-  impl->mNextFree = gFreeList;
-  gFreeList = impl;
+  if (NS_IsMainThread()) {
+    impl->mNextFree = gFreeList;
+    gFreeList = impl;
+  } else {
+    delete impl;
+  }
 }
 
 /* static */ void
 nsCSSParser::Shutdown()
 {
+  MOZ_ASSERT(NS_IsMainThread());
   CSSParserImpl *tofree = gFreeList;
   CSSParserImpl *next;
   while (tofree)
-    {
-      next = tofree->mNextFree;
-      delete tofree;
-      tofree = next;
-    }
+  {
+    next = tofree->mNextFree;
+    delete tofree;
+    tofree = next;
+  }
 }
 
 // Wrapper methods
 
 nsresult
 nsCSSParser::ParseSheet(const nsAString& aInput,
                         nsIURI*          aSheetURI,
                         nsIURI*          aBaseURI,