Bug 1391136 - Handle context lost in layers-free mode. draft
authorMorris Tseng <mtseng@mozilla.com>
Thu, 17 Aug 2017 02:57:20 +0000
changeset 648787 4bcf04a14a7263470e35627f85124fdf8e38fec1
parent 648786 78786d2f02d1fd7e0690c7aacaa698eb136ad988
child 648788 136161d1bf224f0b7c235b9cf19148b7bb68b380
push id74883
push userbmo:ethlin@mozilla.com
push dateFri, 18 Aug 2017 09:52:39 +0000
bugs1391136
milestone57.0a1
Bug 1391136 - Handle context lost in layers-free mode.
dom/canvas/CanvasRenderingContext2D.cpp
dom/canvas/CanvasRenderingContext2D.h
dom/canvas/WebGLContext.cpp
dom/canvas/WebGLContext.h
dom/canvas/nsICanvasRenderingContextInternal.h
dom/html/HTMLCanvasElement.cpp
dom/html/HTMLCanvasElement.h
layout/generic/nsHTMLCanvasFrame.cpp
layout/generic/nsHTMLCanvasFrame.h
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -6284,17 +6284,17 @@ CanvasRenderingContext2D::GetCanvasLayer
   uint32_t flags = mOpaque ? Layer::CONTENT_OPAQUE : 0;
   canvasLayer->SetContentFlags(flags);
 
   mResetLayer = false;
 
   return canvasLayer.forget();
 }
 
-void
+bool
 CanvasRenderingContext2D::InitializeCanvasRenderer(nsDisplayListBuilder* aBuilder,
                                                    CanvasRenderer* aRenderer,
                                                    bool aMirror)
 {
   CanvasInitializeData data;
   data.mSize = GetSize();
   data.mHasAlpha = !mOpaque;
   data.mPreTransCallback = CanvasRenderingContext2DUserData::PreTransactionCallback;
@@ -6317,16 +6317,17 @@ CanvasRenderingContext2D::InitializeCanv
         data.mFrontbufferGLTex = skiaGLTex;
       }
   }
 
   data.mBufferProvider = mBufferProvider;
 
   aRenderer->Initialize(data);
   aRenderer->SetDirty();
+  return true;
 }
 
 void
 CanvasRenderingContext2D::MarkContextClean()
 {
   if (mInvalidateCount > 0) {
     mPredictManyRedrawCalls = mInvalidateCount > kCanvasMaxInvalidateCount;
   }
--- a/dom/canvas/CanvasRenderingContext2D.h
+++ b/dom/canvas/CanvasRenderingContext2D.h
@@ -463,17 +463,17 @@ public:
 
   virtual void SetIsOpaque(bool aIsOpaque) override;
   bool GetIsOpaque() override { return mOpaque; }
   NS_IMETHOD Reset() override;
   already_AddRefed<Layer> GetCanvasLayer(nsDisplayListBuilder* aBuilder,
                                          Layer* aOldLayer,
                                          LayerManager* aManager,
                                          bool aMirror = false) override;
-  void InitializeCanvasRenderer(nsDisplayListBuilder* aBuilder,
+  bool InitializeCanvasRenderer(nsDisplayListBuilder* aBuilder,
                                 CanvasRenderer* aRenderer,
                                 bool aMirror = false) override;
   virtual bool ShouldForceInactiveLayer(LayerManager* aManager) override;
   void MarkContextClean() override;
   void MarkContextCleanForFrameCapture() override;
   bool IsContextCleanForFrameCapture() override;
   NS_IMETHOD SetIsIPC(bool aIsIPC) override;
   // this rect is in canvas device space
--- a/dom/canvas/WebGLContext.cpp
+++ b/dom/canvas/WebGLContext.cpp
@@ -1317,19 +1317,16 @@ private:
 };
 
 already_AddRefed<layers::Layer>
 WebGLContext::GetCanvasLayer(nsDisplayListBuilder* builder,
                              Layer* oldLayer,
                              LayerManager* manager,
                              bool aMirror /*= false*/)
 {
-    if (IsContextLost())
-        return nullptr;
-
     if (!mResetLayer && oldLayer &&
         oldLayer->HasUserData(aMirror ? &gWebGLMirrorLayerUserData : &gWebGLLayerUserData)) {
         RefPtr<layers::Layer> ret = oldLayer;
         return ret.forget();
     }
 
     RefPtr<CanvasLayer> canvasLayer = manager->CreateCanvasLayer();
     if (!canvasLayer) {
@@ -1340,34 +1337,39 @@ WebGLContext::GetCanvasLayer(nsDisplayLi
     WebGLContextUserData* userData = nullptr;
     if (builder->IsPaintingToWindow() && mCanvasElement && !aMirror) {
         userData = new WebGLContextUserData(mCanvasElement);
     }
 
     canvasLayer->SetUserData(aMirror ? &gWebGLMirrorLayerUserData : &gWebGLLayerUserData, userData);
 
     CanvasRenderer* canvasRenderer = canvasLayer->CreateOrGetCanvasRenderer();
-    InitializeCanvasRenderer(builder, canvasRenderer, aMirror);
+    if (!InitializeCanvasRenderer(builder, canvasRenderer, aMirror))
+      return nullptr;
+
     uint32_t flags = gl->Caps().alpha ? 0 : Layer::CONTENT_OPAQUE;
     canvasLayer->SetContentFlags(flags);
 
     mResetLayer = false;
     // We only wish to update mLayerIsMirror when a new layer is returned.
     // If a cached layer is returned above, aMirror is not changing since
     // the last cached layer was created and mLayerIsMirror is still valid.
     mLayerIsMirror = aMirror;
 
     return canvasLayer.forget();
 }
 
-void
+bool
 WebGLContext::InitializeCanvasRenderer(nsDisplayListBuilder* aBuilder,
                                        CanvasRenderer* aRenderer,
                                        bool aMirror)
 {
+    if (IsContextLost())
+        return false;
+
     CanvasInitializeData data;
     if (aBuilder->IsPaintingToWindow() && mCanvasElement && !aMirror) {
         // Make the layer tell us whenever a transaction finishes (including
         // the current transaction), so we can clear our invalidation state and
         // start invalidating again. We need to do this for the layer that is
         // being painted to a window (there shouldn't be more than one at a time,
         // and if there is, flushing the invalidation state more often than
         // necessary is harmless).
@@ -1386,16 +1388,17 @@ WebGLContext::InitializeCanvasRenderer(n
     data.mGLContext = gl;
     data.mSize = nsIntSize(mWidth, mHeight);
     data.mHasAlpha = gl->Caps().alpha;
     data.mIsGLAlphaPremult = IsPremultAlpha() || !data.mHasAlpha;
     data.mIsMirror = aMirror;
 
     aRenderer->Initialize(data);
     aRenderer->SetDirty();
+    return true;
 }
 
 layers::LayersBackend
 WebGLContext::GetCompositorBackendType() const
 {
     if (mCanvasElement) {
         return mCanvasElement->GetCompositorBackendType();
     } else if (mOffscreenCanvas) {
--- a/dom/canvas/WebGLContext.h
+++ b/dom/canvas/WebGLContext.h
@@ -457,17 +457,17 @@ public:
     }
 
     void InvalidateResolveCacheForTextureWithTexUnit(const GLuint);
 
     already_AddRefed<Layer>
     GetCanvasLayer(nsDisplayListBuilder* builder, Layer* oldLayer,
                    LayerManager* manager,
                    bool aMirror = false) override;
-    void
+    bool
     InitializeCanvasRenderer(nsDisplayListBuilder* aBuilder,
                              CanvasRenderer* aRenderer,
                              bool aMirror = false) override;
 
     // Note that 'clean' here refers to its invalidation state, not the
     // contents of the buffer.
     void MarkContextClean() override { mInvalidated = false; }
 
--- a/dom/canvas/nsICanvasRenderingContextInternal.h
+++ b/dom/canvas/nsICanvasRenderingContextInternal.h
@@ -136,19 +136,19 @@ public:
   NS_IMETHOD Reset() = 0;
 
   // Return the CanvasLayer for this context, creating
   // one for the given layer manager if not available.
   virtual already_AddRefed<Layer> GetCanvasLayer(nsDisplayListBuilder* builder,
                                                  Layer *oldLayer,
                                                  LayerManager *manager,
                                                  bool aMirror = false) = 0;
-  virtual void InitializeCanvasRenderer(nsDisplayListBuilder* aBuilder,
+  virtual bool InitializeCanvasRenderer(nsDisplayListBuilder* aBuilder,
                                         CanvasRenderer* aRenderer,
-                                        bool aMirror = false) { };
+                                        bool aMirror = false) { return true; }
 
   // Return true if the canvas should be forced to be "inactive" to ensure
   // it can be drawn to the screen even if it's too large to be blitted by
   // an accelerated CanvasLayer.
   virtual bool ShouldForceInactiveLayer(LayerManager *manager) { return false; }
 
   virtual void MarkContextClean() = 0;
 
--- a/dom/html/HTMLCanvasElement.cpp
+++ b/dom/html/HTMLCanvasElement.cpp
@@ -1183,39 +1183,45 @@ HTMLCanvasElement::GetCanvasLayer(nsDisp
       NS_WARNING("CreateCanvasLayer failed!");
       return nullptr;
     }
 
     LayerUserData* userData = nullptr;
     layer->SetUserData(&sOffscreenCanvasLayerUserDataDummy, userData);
 
     CanvasRenderer* canvasRenderer = layer->CreateOrGetCanvasRenderer();
-    InitializeCanvasRenderer(aBuilder, canvasRenderer);
+
+    if (!InitializeCanvasRenderer(aBuilder, canvasRenderer)) {
+      return nullptr;
+    }
 
     layer->Updated();
     return layer.forget();
   }
 
   return nullptr;
 }
 
-void
+bool
 HTMLCanvasElement::InitializeCanvasRenderer(nsDisplayListBuilder* aBuilder,
                                             CanvasRenderer* aRenderer)
 {
   if (mCurrentContext) {
-    mCurrentContext->InitializeCanvasRenderer(aBuilder, aRenderer);
+    return mCurrentContext->InitializeCanvasRenderer(aBuilder, aRenderer);
   }
 
   if (mOffscreenCanvas) {
     CanvasInitializeData data;
     data.mRenderer = GetAsyncCanvasRenderer();
     data.mSize = GetWidthHeight();
     aRenderer->Initialize(data);
+    return true;
   }
+
+  return true;
 }
 
 bool
 HTMLCanvasElement::ShouldForceInactiveLayer(LayerManager* aManager)
 {
   if (mCurrentContext) {
     return mCurrentContext->ShouldForceInactiveLayer(aManager);
   }
--- a/dom/html/HTMLCanvasElement.h
+++ b/dom/html/HTMLCanvasElement.h
@@ -305,17 +305,17 @@ public:
 
   /*
    * Helpers called by various users of Canvas
    */
 
   already_AddRefed<Layer> GetCanvasLayer(nsDisplayListBuilder* aBuilder,
                                          Layer *aOldLayer,
                                          LayerManager *aManager);
-  void InitializeCanvasRenderer(nsDisplayListBuilder* aBuilder,
+  bool InitializeCanvasRenderer(nsDisplayListBuilder* aBuilder,
                                 CanvasRenderer* aRenderer);
   // Should return true if the canvas layer should always be marked inactive.
   // We should return true here if we can't do accelerated compositing with
   // a non-BasicCanvasLayer.
   bool ShouldForceInactiveLayer(LayerManager *aManager);
 
   // Call this whenever we need future changes to the canvas
   // to trigger fresh invalidation requests. This needs to be called
--- a/layout/generic/nsHTMLCanvasFrame.cpp
+++ b/layout/generic/nsHTMLCanvasFrame.cpp
@@ -136,17 +136,20 @@ public:
       {
         bool isRecycled;
         RefPtr<WebRenderCanvasData> canvasData =
           aManager->CreateOrRecycleWebRenderUserData<WebRenderCanvasData>(this, &isRecycled);
         WebRenderCanvasRendererAsync* data =
           static_cast<WebRenderCanvasRendererAsync*>(canvasData->GetCanvasRenderer());
 
         if (!isRecycled) {
-          static_cast<nsHTMLCanvasFrame*>(mFrame)->InitializeCanvasRenderer(aDisplayListBuilder, data);
+          nsHTMLCanvasFrame *canvasFrame = static_cast<nsHTMLCanvasFrame*>(mFrame);
+          if (!canvasFrame->InitializeCanvasRenderer(aDisplayListBuilder, data)) {
+            return true;
+          }
         }
 
         data->UpdateCompositableClient();
 
         // Push IFrame for async image pipeline.
         // XXX Remove this once partial display list update is supported.
 
         /* ScrollingLayersHelper scroller(this, aBuilder, aSc); */
@@ -450,22 +453,22 @@ nsHTMLCanvasFrame::BuildLayer(nsDisplayL
   } else if (layer->GetType() == layers::Layer::TYPE_IMAGE) {
     RefPtr<ImageLayer> imageLayer = static_cast<ImageLayer*>(layer.get());
     imageLayer->SetSamplingFilter(nsLayoutUtils::GetSamplingFilterForFrame(this));
   }
 
   return layer.forget();
 }
 
-void
+bool
 nsHTMLCanvasFrame::InitializeCanvasRenderer(nsDisplayListBuilder* aBuilder,
                                             CanvasRenderer* aRenderer)
 {
   HTMLCanvasElement* element = static_cast<HTMLCanvasElement*>(GetContent());
-  element->InitializeCanvasRenderer(aBuilder, aRenderer);
+  return element->InitializeCanvasRenderer(aBuilder, aRenderer);
 }
 
 void
 nsHTMLCanvasFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                                     const nsDisplayListSet& aLists)
 {
   if (!IsVisibleForPainting(aBuilder))
     return;
--- a/layout/generic/nsHTMLCanvasFrame.h
+++ b/layout/generic/nsHTMLCanvasFrame.h
@@ -47,17 +47,17 @@ public:
 
   virtual void BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                                 const nsDisplayListSet& aLists) override;
 
   already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
                                      LayerManager* aManager,
                                      nsDisplayItem* aItem,
                                      const ContainerLayerParameters& aContainerParameters);
-  void InitializeCanvasRenderer(nsDisplayListBuilder* aBuilder,
+  bool InitializeCanvasRenderer(nsDisplayListBuilder* aBuilder,
                                 CanvasRenderer* aRenderer);
 
   /* get the size of the canvas's image */
   nsIntSize GetCanvasSize();
 
   virtual nscoord GetMinISize(gfxContext *aRenderingContext) override;
   virtual nscoord GetPrefISize(gfxContext *aRenderingContext) override;
   virtual mozilla::IntrinsicSize GetIntrinsicSize() override;