Bug 801176 - part5-v2: Fix Assertions in debug build. r=roc
authorvincentliu <vliu@mozilla.com>
Fri, 04 Mar 2016 15:23:40 +0800
changeset 336836 0fb279e041e14f05a1a1dd9fed8eb00b46f16d90
parent 336835 c090dc98c670430e2dd99bd139fabe1b094f8582
child 336837 e210473d793ce93f41642780fc66b56e97972eee
push id12189
push usercku@mozilla.com
push dateFri, 04 Mar 2016 07:52:22 +0000
reviewersroc
bugs801176
milestone47.0a1
Bug 801176 - part5-v2: Fix Assertions in debug build. r=roc --- dom/canvas/CanvasRenderingContext2D.cpp | 47 ++++++++++++++++++++------------- 1 file changed, 29 insertions(+), 18 deletions(-)
dom/canvas/CanvasRenderingContext2D.cpp
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -92,16 +92,17 @@
 #include "mozilla/ipc/PDocumentRendererParent.h"
 #include "mozilla/layers/PersistentBufferProvider.h"
 #include "mozilla/MathAlgorithms.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/TimeStamp.h"
 #include "mozilla/UniquePtr.h"
 #include "mozilla/unused.h"
+#include "mozilla/StaticMutex.h"
 #include "nsCCUncollectableMarker.h"
 #include "nsWrapperCacheInlines.h"
 #include "mozilla/dom/CanvasRenderingContext2DBinding.h"
 #include "mozilla/dom/CanvasPath.h"
 #include "mozilla/dom/HTMLImageElement.h"
 #include "mozilla/dom/HTMLVideoElement.h"
 #include "mozilla/dom/SVGMatrix.h"
 #include "mozilla/dom/TextMetrics.h"
@@ -157,25 +158,26 @@ using namespace mozilla::layers;
 namespace mozilla {
 namespace dom {
 
 // Cap sigma to avoid overly large temp surfaces.
 const Float SIGMA_MAX = 100;
 
 /* Memory reporter stuff */
 static int64_t gCanvasAzureMemoryUsed = 0;
+static StaticMutex sMemoryReportMutex;
 
 // This is KIND_OTHER because it's not always clear where in memory the pixels
 // of a canvas are stored.  Furthermore, this memory will be tracked by the
 // underlying surface implementations.  See bug 655638 for details.
 class Canvas2dPixelsReporter final : public nsIMemoryReporter
 {
   ~Canvas2dPixelsReporter() {}
 public:
-  NS_DECL_ISUPPORTS
+  NS_DECL_THREADSAFE_ISUPPORTS
 
   NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport,
                             nsISupports* aData, bool aAnonymize) override
   {
     return MOZ_COLLECT_REPORT(
       "canvas-2d-pixels", KIND_OTHER, UNITS_BYTES,
       gCanvasAzureMemoryUsed,
       "Memory used by 2D canvases. Each canvas requires "
@@ -1059,16 +1061,17 @@ CanvasRenderingContext2D::Reset()
 {
   if (mCanvasElement) {
     mCanvasElement->InvalidateCanvas();
   }
 
   // only do this for non-docshell created contexts,
   // since those are the ones that we created a surface for
   if (mTarget && IsTargetValid() && !mDocShell) {
+    StaticMutexAutoLock lock(sMemoryReportMutex);
     gCanvasAzureMemoryUsed -= mWidth * mHeight * 4;
   }
 
   ReturnTarget();
   mTarget = nullptr;
   mBufferProvider = nullptr;
 
   // reset hit regions
@@ -1140,24 +1143,26 @@ CanvasRenderingContext2D::Redraw()
   mIsCapturedFrameInvalid = true;
 
   if (mIsEntireFrameInvalid) {
     return NS_OK;
   }
 
   mIsEntireFrameInvalid = true;
 
-  if (!mCanvasElement) {
-    NS_ASSERTION(mDocShell, "Redraw with no canvas element or docshell!");
-    return NS_OK;
-  }
-
-  nsSVGEffects::InvalidateDirectRenderingObservers(mCanvasElement);
-
-  mCanvasElement->InvalidateCanvasContent(nullptr);
+  if (NS_IsMainThread()) {
+    if (!mCanvasElement) {
+      NS_ASSERTION(mDocShell, "Redraw with no canvas element or docshell!");
+      return NS_OK;
+    }
+
+    nsSVGEffects::InvalidateDirectRenderingObservers(mCanvasElement);
+
+    mCanvasElement->InvalidateCanvasContent(nullptr);
+  }
 
   return NS_OK;
 }
 
 void
 CanvasRenderingContext2D::Redraw(const gfx::Rect& aR)
 {
   mIsCapturedFrameInvalid = true;
@@ -1169,24 +1174,26 @@ CanvasRenderingContext2D::Redraw(const g
   }
 
   if (mPredictManyRedrawCalls ||
     mInvalidateCount > kCanvasMaxInvalidateCount) {
     Redraw();
     return;
   }
 
-  if (!mCanvasElement) {
-    NS_ASSERTION(mDocShell, "Redraw with no canvas element or docshell!");
-    return;
-  }
-
-  nsSVGEffects::InvalidateDirectRenderingObservers(mCanvasElement);
-
-  mCanvasElement->InvalidateCanvasContent(&aR);
+  if (NS_IsMainThread()) {
+    if (!mCanvasElement) {
+      NS_ASSERTION(mDocShell, "Redraw with no canvas element or docshell!");
+      return;
+    }
+
+    nsSVGEffects::InvalidateDirectRenderingObservers(mCanvasElement);
+
+    mCanvasElement->InvalidateCanvasContent(&aR);
+  }
 }
 
 void
 CanvasRenderingContext2D::DidRefresh()
 {
   if (IsTargetValid() && SkiaGLTex()) {
     SkiaGLGlue* glue = gfxPlatform::GetPlatform()->GetSkiaGLGlue();
     MOZ_ASSERT(glue);
@@ -1419,32 +1426,31 @@ CanvasRenderingContext2D::EnsureTarget(R
 
     RefPtr<LayerManager> layerManager = nullptr;
 
     if (ownerDoc) {
       layerManager =
         nsContentUtils::PersistentLayerManagerForDocument(ownerDoc);
     }
 
-    if (mode == RenderingMode::OpenGLBackendMode &&
+    if (NS_IsMainThread() &&
+        mode == RenderingMode::OpenGLBackendMode &&
         gfxPlatform::GetPlatform()->UseAcceleratedCanvas() &&
         CheckSizeForSkiaGL(size)) {
       DemoteOldestContextIfNecessary();
       mBufferProvider = nullptr;
 
 #if USE_SKIA_GPU
       SkiaGLGlue* glue = gfxPlatform::GetPlatform()->GetSkiaGLGlue();
 
       if (glue && glue->GetGrContext() && glue->GetGLContext()) {
         mTarget = Factory::CreateDrawTargetSkiaWithGrContext(glue->GetGrContext(), size, format);
         if (mTarget) {
           AddDemotableContext(this);
-          if (NS_IsMainThread()) {
-            mBufferProvider = new PersistentBufferProviderBasic(mTarget);
-          }
+          mBufferProvider = new PersistentBufferProviderBasic(mTarget);
           mIsSkiaGL = true;
         } else {
           gfxCriticalNote << "Failed to create a SkiaGL DrawTarget, falling back to software\n";
           mode = RenderingMode::SoftwareBackendMode;
         }
       }
 #endif
     }
@@ -1468,17 +1474,22 @@ CanvasRenderingContext2D::EnsureTarget(R
   if (mTarget) {
     static bool registered = false;
     if (!registered) {
       registered = true;
       RegisterStrongMemoryReporter(new Canvas2dPixelsReporter());
     }
 
     gCanvasAzureMemoryUsed += mWidth * mHeight * 4;
-    JSContext* context = nsContentUtils::GetCurrentJSContext();
+    JSContext* context;
+    if (NS_IsMainThread()) {
+      context = nsContentUtils::GetCurrentJSContext();
+    } else {
+      context = nsContentUtils::GetDefaultJSContextForThread();
+    }
     if (context) {
       JS_updateMallocCounter(context, mWidth * mHeight * 4);
     }
 
     mTarget->ClearRect(gfx::Rect(Point(0, 0), Size(mWidth, mHeight)));
     if (mTarget->GetBackendType() == gfx::BackendType::CAIRO) {
       // Cairo doesn't play well with huge clips. When given a very big clip it
       // will try to allocate big mask surface without taking the target