Bug 1318283 - Debug patch - r=milan
authorEdwin Flores <eflores@mozilla.com>
Mon, 28 Nov 2016 19:32:49 +0000
changeset 324464 f5624a5ba41e1f690b1a6ffb9d50beee80ef3bcc
parent 324463 f50ae3e4924d028b4d7488833999fd7012782727
child 324465 d5ffc2a28d39c6274a639d002006216c0b668677
push id24
push usermaklebus@msu.edu
push dateTue, 20 Dec 2016 03:11:33 +0000
reviewersmilan
bugs1318283
milestone53.0a1
Bug 1318283 - Debug patch - r=milan
dom/canvas/CanvasRenderingContext2D.cpp
dom/canvas/CanvasRenderingContext2D.h
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -560,17 +560,17 @@ private:
 class AdjustedTarget
 {
 public:
   typedef CanvasRenderingContext2D::ContextState ContextState;
 
   explicit AdjustedTarget(CanvasRenderingContext2D* aCtx,
                           const gfx::Rect *aBounds = nullptr)
   {
-    mTarget = aCtx->mTarget;
+    mTarget = (DrawTarget*)aCtx->mTarget;
 
     // All rects in this function are in the device space of ctx->mTarget.
 
     // In order to keep our temporary surfaces as small as possible, we first
     // calculate what their maximum required bounds would need to be if we
     // were to fill the whole canvas. Everything outside those bounds we don't
     // need to render.
     gfx::Rect r(0, 0, aCtx->mWidth, aCtx->mHeight);
@@ -1715,17 +1715,17 @@ void
 CanvasRenderingContext2D::SetErrorState()
 {
   EnsureErrorTarget();
 
   if (mTarget && mTarget != sErrorTarget) {
     gCanvasAzureMemoryUsed -= mWidth * mHeight * 4;
   }
 
-  mTarget = sErrorTarget;
+  mTarget = (DrawTarget*)sErrorTarget;
   mBufferProvider = nullptr;
 
   // clear transforms, clips, etc.
   SetInitialState();
 }
 
 void
 CanvasRenderingContext2D::RegisterAllocation()
@@ -1970,17 +1970,17 @@ CanvasRenderingContext2D::InitializeWith
 {
   RemovePostRefreshObserver();
   mDocShell = aShell;
   AddPostRefreshObserverIfNecessary();
 
   IntSize size = aTarget->GetSize();
   SetDimensions(size.width, size.height);
 
-  mTarget = aTarget;
+  mTarget = (DrawTarget*)aTarget;
   mBufferProvider = new PersistentBufferProviderBasic(aTarget);
 
   if (mTarget->GetBackendType() == gfx::BackendType::CAIRO) {
     // Cf comment in EnsureTarget
     mTarget->PushClipRect(gfx::Rect(Point(0, 0), Size(mWidth, mHeight)));
   }
 
   return NS_OK;
@@ -3149,16 +3149,18 @@ CanvasRenderingContext2D::BeginPath()
   mPathBuilder = nullptr;
   mDSPathBuilder = nullptr;
   mPathTransformWillUpdate = false;
 }
 
 void
 CanvasRenderingContext2D::Fill(const CanvasWindingRule& aWinding)
 {
+  auto autoNotNull = mTarget.MakeAuto();
+
   EnsureUserSpacePath(aWinding);
 
   if (!mPath) {
     return;
   }
 
   gfx::Rect bounds;
 
@@ -4753,16 +4755,18 @@ CanvasRenderingContext2D::CachedSurfaceF
 void
 CanvasRenderingContext2D::DrawImage(const CanvasImageSource& aImage,
                                     double aSx, double aSy, double aSw,
                                     double aSh, double aDx, double aDy,
                                     double aDw, double aDh,
                                     uint8_t aOptional_argc,
                                     ErrorResult& aError)
 {
+  auto autoNotNull = mTarget.MakeAuto();
+
   if (mDrawObserver) {
     mDrawObserver->DidDrawCall(CanvasDrawObserver::DrawCallType::DrawImage);
   }
 
   MOZ_ASSERT(aOptional_argc == 0 || aOptional_argc == 2 || aOptional_argc == 6);
 
   if (!ValidateRect(aDx, aDy, aDw, aDh, true)) {
     return;
@@ -5014,17 +5018,17 @@ CanvasRenderingContext2D::DrawImage(cons
       // waste if sourceRect doesn't cover the whole canvas.
       // We avoid copying the whole canvas by manually copying just the part
       // that we need.
       srcSurf = ExtractSubrect(srcSurf, &sourceRect, mTarget);
     }
 
     AdjustedTarget tempTarget(this, bounds.IsEmpty() ? nullptr : &bounds);
     if (!tempTarget) {
-      gfxDevCrash(LogReason::InvalidDrawTarget) << "Invalid adjusted target in Canvas2D " << gfx::hexa(mTarget) << ", " << NeedToDrawShadow() << NeedToApplyFilter();
+      gfxDevCrash(LogReason::InvalidDrawTarget) << "Invalid adjusted target in Canvas2D " << gfx::hexa((DrawTarget*)mTarget) << ", " << NeedToDrawShadow() << NeedToApplyFilter();
       return;
     }
     tempTarget->DrawSurface(srcSurf,
                   gfx::Rect(aDx, aDy, aDw, aDh),
                   sourceRect,
                   DrawSurfaceOptions(samplingFilter, SamplingBounds::UNBOUNDED),
                   DrawOptions(CurrentState().globalAlpha, UsedOperation(), antialiasMode));
   } else {
--- a/dom/canvas/CanvasRenderingContext2D.h
+++ b/dom/canvas/CanvasRenderingContext2D.h
@@ -42,16 +42,128 @@ class HTMLImageElementOrHTMLCanvasElemen
 typedef HTMLImageElementOrHTMLCanvasElementOrHTMLVideoElementOrImageBitmap CanvasImageSource;
 class ImageData;
 class StringOrCanvasGradientOrCanvasPattern;
 class OwningStringOrCanvasGradientOrCanvasPattern;
 class TextMetrics;
 class CanvasFilterChainObserver;
 class CanvasPath;
 
+template<class T>
+struct MaybeNotNull
+{
+  MOZ_IMPLICIT MaybeNotNull() : mWrapped(nullptr), mEnsure(false) {}
+  MOZ_IMPLICIT MaybeNotNull(T&& aValue) : mWrapped(aValue), mEnsure(false) {}
+  ~MaybeNotNull() {}
+
+  void BeginNotNull() {
+    mEnsure = true;
+  }
+
+  void EndNotNull() {
+    mEnsure = false;
+  }
+
+  void MaybeCheckWrapped() {
+    if (mEnsure && !mWrapped) {
+      MOZ_CRASH("GFX: Setting mTarget to nullptr?");
+    }
+  }
+
+  typename T::element_type* operator->() const {
+    return mWrapped.get();
+  }
+
+  already_AddRefed<typename T::element_type> forget() {
+    already_AddRefed<typename T::element_type>&& ret = mWrapped.forget();
+    MaybeCheckWrapped();
+    return Move(ret);
+  }
+
+  MOZ_IMPLICIT operator bool () {
+    return mWrapped;
+  }
+
+  operator T&() {
+    return mWrapped;
+  }
+
+  operator typename T::element_type*() {
+    return mWrapped.get();
+  }
+
+  bool operator!() const {
+    return !mWrapped;
+  }
+
+  MaybeNotNull& operator=(decltype(nullptr)) {
+    mWrapped = nullptr;
+    MaybeCheckWrapped();
+    return *this;
+  }
+
+  template<class U>
+  MaybeNotNull& operator=(U& aOther){
+    mWrapped = aOther;
+    MaybeCheckWrapped();
+    return *this;
+  }
+
+  template<class U>
+  MaybeNotNull& operator=(U&& aOther){
+    mWrapped = aOther;
+    MaybeCheckWrapped();
+    return *this;
+  }
+
+  struct AutoNotNull
+  {
+    MOZ_IMPLICIT AutoNotNull(MaybeNotNull* aMaybe) : mMaybe(aMaybe)
+    {
+      mMaybe->BeginNotNull();
+    }
+
+    ~AutoNotNull()
+    {
+      mMaybe->EndNotNull();
+    }
+
+    MaybeNotNull* mMaybe;
+  };
+
+  AutoNotNull MakeAuto()
+  {
+    return AutoNotNull(this);
+  }
+
+  T mWrapped;
+
+  bool mEnsure;
+};
+
+template<class T, class U>
+  bool operator!=(const MaybeNotNull<T>& aT, const U& aU) {
+  return aT.mWrapped != aU;
+}
+
+template<class T, class U>
+  bool operator==(const MaybeNotNull<T>& aT, const U& aU) {
+  return aT.mWrapped == aU;
+}
+
+template<class T, class U>
+  bool operator||(const MaybeNotNull<T>& aT, const U& aU) {
+  return aT.mWrapped || aU;
+}
+
+template<class T, class U>
+  bool operator||(const T& aT, const MaybeNotNull<U>& aU) {
+  return aT || aU.mWrapped;
+}
+
 extern const mozilla::gfx::Float SIGMA_MAX;
 
 template<typename T> class Optional;
 
 struct CanvasBidiProcessor;
 class CanvasRenderingContext2DUserData;
 class CanvasDrawObserver;
 class CanvasShutdownObserver;
@@ -681,17 +793,17 @@ protected:
    * rendering.
    */
   void ReturnTarget(bool aForceReset = false);
 
   /**
    * Check if the target is valid after calling EnsureTarget.
    */
   bool IsTargetValid() const {
-    return mTarget && mTarget != sErrorTarget;
+    return !!mTarget && mTarget != sErrorTarget;
   }
 
   /**
     * Returns the surface format this canvas should be allocated using. Takes
     * into account mOpaque, platform requirements, etc.
     */
   mozilla::gfx::SurfaceFormat GetSurfaceFormat() const;
 
@@ -766,17 +878,17 @@ protected:
   nsTArray<CanvasRenderingContext2DUserData*> mUserDatas;
 
   // If mCanvasElement is not provided, then a docshell is
   nsCOMPtr<nsIDocShell> mDocShell;
 
   // This is created lazily so it is necessary to call EnsureTarget before
   // accessing it. In the event of an error it will be equal to
   // sErrorTarget.
-  RefPtr<mozilla::gfx::DrawTarget> mTarget;
+  MaybeNotNull<RefPtr<mozilla::gfx::DrawTarget>> mTarget;
 
   RefPtr<mozilla::layers::PersistentBufferProvider> mBufferProvider;
 
   uint32_t SkiaGLTex() const;
 
   // This observes our draw calls at the beginning of the canvas
   // lifetime and switches to software or GPU mode depending on
   // what it thinks is best