Home | History | Annotate | Download | only in graphics
      1 /*
      2  * Copyright (C) 2011 Google Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  * 1.  Redistributions of source code must retain the above copyright
      8  *     notice, this list of conditions and the following disclaimer.
      9  * 2.  Redistributions in binary form must reproduce the above copyright
     10  *     notice, this list of conditions and the following disclaimer in the
     11  *     documentation and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
     14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     16  * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
     17  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     18  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     19  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
     20  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     21  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     22  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     23  */
     24 
     25 #include "config.h"
     26 
     27 #include "platform/graphics/Canvas2DLayerBridge.h"
     28 
     29 #include "SkDeferredCanvas.h"
     30 #include "SkSurface.h"
     31 #include "platform/graphics/ImageBuffer.h"
     32 #include "platform/graphics/test/MockWebGraphicsContext3D.h"
     33 #include "public/platform/Platform.h"
     34 #include "public/platform/WebExternalBitmap.h"
     35 #include "public/platform/WebGraphicsContext3DProvider.h"
     36 #include "public/platform/WebThread.h"
     37 #include "third_party/skia/include/core/SkDevice.h"
     38 #include "wtf/RefPtr.h"
     39 
     40 #include <gmock/gmock.h>
     41 #include <gtest/gtest.h>
     42 
     43 using namespace blink;
     44 using testing::InSequence;
     45 using testing::Return;
     46 using testing::Test;
     47 
     48 namespace {
     49 
     50 class MockCanvasContext : public MockWebGraphicsContext3D {
     51 public:
     52     MOCK_METHOD0(flush, void(void));
     53     MOCK_METHOD0(createTexture, unsigned(void));
     54     MOCK_METHOD1(deleteTexture, void(unsigned));
     55 };
     56 
     57 class MockWebGraphicsContext3DProvider : public WebGraphicsContext3DProvider {
     58 public:
     59     MockWebGraphicsContext3DProvider(WebGraphicsContext3D* context3d)
     60         : m_context3d(context3d) { }
     61 
     62     WebGraphicsContext3D* context3d()
     63     {
     64         return m_context3d;
     65     }
     66 
     67     GrContext* grContext()
     68     {
     69         return 0;
     70     }
     71 
     72 private:
     73     WebGraphicsContext3D* m_context3d;
     74 };
     75 
     76 class Canvas2DLayerBridgePtr {
     77 public:
     78     Canvas2DLayerBridgePtr(PassRefPtr<Canvas2DLayerBridge> layerBridge)
     79         : m_layerBridge(layerBridge) { }
     80 
     81     ~Canvas2DLayerBridgePtr()
     82     {
     83         m_layerBridge->beginDestruction();
     84     }
     85 
     86     Canvas2DLayerBridge* operator->() { return m_layerBridge.get(); }
     87     Canvas2DLayerBridge* get() { return m_layerBridge.get(); }
     88 
     89 private:
     90     RefPtr<Canvas2DLayerBridge> m_layerBridge;
     91 };
     92 
     93 class NullWebExternalBitmap : public WebExternalBitmap {
     94 public:
     95     virtual WebSize size()
     96     {
     97         return WebSize();
     98     }
     99 
    100     virtual void setSize(WebSize)
    101     {
    102     }
    103 
    104     virtual uint8* pixels()
    105     {
    106         return 0;
    107     }
    108 };
    109 
    110 } // namespace
    111 
    112 class Canvas2DLayerBridgeTest : public Test {
    113 protected:
    114     void fullLifecycleTest()
    115     {
    116         MockCanvasContext mainMock;
    117         OwnPtr<MockWebGraphicsContext3DProvider> mainMockProvider = adoptPtr(new MockWebGraphicsContext3DProvider(&mainMock));
    118         RefPtr<SkSurface> surface = adoptRef(SkSurface::NewRasterPMColor(300, 150));
    119         OwnPtr<SkDeferredCanvas> canvas = adoptPtr(SkDeferredCanvas::Create(surface.get()));
    120 
    121         ::testing::Mock::VerifyAndClearExpectations(&mainMock);
    122 
    123         {
    124             Canvas2DLayerBridgePtr bridge(adoptRef(new Canvas2DLayerBridge(mainMockProvider.release(), canvas.release(), surface, 0, NonOpaque)));
    125 
    126             ::testing::Mock::VerifyAndClearExpectations(&mainMock);
    127 
    128             EXPECT_CALL(mainMock, flush());
    129             unsigned textureId = bridge->getBackingTexture();
    130             EXPECT_EQ(textureId, 0u);
    131 
    132             ::testing::Mock::VerifyAndClearExpectations(&mainMock);
    133         } // bridge goes out of scope here
    134 
    135         ::testing::Mock::VerifyAndClearExpectations(&mainMock);
    136     }
    137 
    138     void noDrawOnContextLostTest()
    139     {
    140         MockCanvasContext mainMock;
    141         OwnPtr<MockWebGraphicsContext3DProvider> mainMockProvider = adoptPtr(new MockWebGraphicsContext3DProvider(&mainMock));
    142         RefPtr<SkSurface> surface = adoptRef(SkSurface::NewRasterPMColor(300, 150));
    143         OwnPtr<SkDeferredCanvas> canvas = adoptPtr(SkDeferredCanvas::Create(surface.get()));
    144 
    145         ::testing::Mock::VerifyAndClearExpectations(&mainMock);
    146 
    147         {
    148             Canvas2DLayerBridgePtr bridge(adoptRef(new Canvas2DLayerBridge(mainMockProvider.release(), canvas.release(), surface, 0, NonOpaque)));
    149             ::testing::Mock::VerifyAndClearExpectations(&mainMock);
    150             EXPECT_TRUE(bridge->checkSurfaceValid());
    151             SkPaint paint;
    152             uint32_t genID = surface->generationID();
    153             bridge->canvas()->drawRect(SkRect::MakeXYWH(0, 0, 1, 1), paint);
    154             EXPECT_EQ(genID, surface->generationID());
    155             mainMock.fakeContextLost();
    156             EXPECT_EQ(genID, surface->generationID());
    157             bridge->canvas()->drawRect(SkRect::MakeXYWH(0, 0, 1, 1), paint);
    158             EXPECT_EQ(genID, surface->generationID());
    159             EXPECT_FALSE(bridge->checkSurfaceValid());
    160             EXPECT_EQ(genID, surface->generationID());
    161             bridge->canvas()->drawRect(SkRect::MakeXYWH(0, 0, 1, 1), paint);
    162             EXPECT_EQ(genID, surface->generationID());
    163             bridge->freeTransientResources();
    164             EXPECT_EQ(genID, surface->generationID());
    165             ::testing::Mock::VerifyAndClearExpectations(&mainMock);
    166         }
    167 
    168         ::testing::Mock::VerifyAndClearExpectations(&mainMock);
    169     }
    170 
    171     void prepareMailboxWithBitmapTest()
    172     {
    173         MockCanvasContext mainMock;
    174         RefPtr<SkSurface> surface = adoptRef(SkSurface::NewRasterPMColor(300, 150));
    175         OwnPtr<SkDeferredCanvas> canvas = adoptPtr(SkDeferredCanvas::Create(surface.get()));
    176         OwnPtr<MockWebGraphicsContext3DProvider> mainMockProvider = adoptPtr(new MockWebGraphicsContext3DProvider(&mainMock));
    177         Canvas2DLayerBridgePtr bridge(adoptRef(new Canvas2DLayerBridge(mainMockProvider.release(), canvas.release(), surface, 0, NonOpaque)));
    178         bridge->m_lastImageId = 1;
    179 
    180         NullWebExternalBitmap bitmap;
    181         bridge->prepareMailbox(0, &bitmap);
    182         EXPECT_EQ(0u, bridge->m_lastImageId);
    183     }
    184 
    185     void prepareMailboxAndLoseResourceTest()
    186     {
    187         MockCanvasContext mainMock;
    188         RefPtr<SkSurface> surface = adoptRef(SkSurface::NewRasterPMColor(300, 150));
    189         bool lostResource = true;
    190 
    191         // Prepare a mailbox, then report the resource as lost.
    192         // This test passes by not crashing and not triggering assertions.
    193         {
    194             WebExternalTextureMailbox mailbox;
    195             OwnPtr<SkDeferredCanvas> canvas = adoptPtr(SkDeferredCanvas::Create(surface.get()));
    196             OwnPtr<MockWebGraphicsContext3DProvider> mainMockProvider = adoptPtr(new MockWebGraphicsContext3DProvider(&mainMock));
    197             Canvas2DLayerBridgePtr bridge(adoptRef(new Canvas2DLayerBridge(mainMockProvider.release(), canvas.release(), surface, 0, NonOpaque)));
    198             bridge->prepareMailbox(&mailbox, 0);
    199             bridge->mailboxReleased(mailbox, lostResource);
    200         }
    201 
    202         // Retry with mailbox released while bridge destruction is in progress
    203         {
    204             OwnPtr<SkDeferredCanvas> canvas = adoptPtr(SkDeferredCanvas::Create(surface.get()));
    205             OwnPtr<MockWebGraphicsContext3DProvider> mainMockProvider = adoptPtr(new MockWebGraphicsContext3DProvider(&mainMock));
    206             WebExternalTextureMailbox mailbox;
    207             Canvas2DLayerBridge* rawBridge;
    208             {
    209                 Canvas2DLayerBridgePtr bridge(adoptRef(new Canvas2DLayerBridge(mainMockProvider.release(), canvas.release(), surface, 0, NonOpaque)));
    210                 bridge->prepareMailbox(&mailbox, 0);
    211                 rawBridge = bridge.get();
    212             } // bridge goes out of scope, but object is kept alive by self references
    213             // before fixing crbug.com/411864, the following line you cause a memory use after free
    214             // that sometimes causes a crash in normal builds and crashes consistently with ASAN.
    215             rawBridge->mailboxReleased(mailbox, lostResource); // This should self-destruct the bridge.
    216         }
    217     }
    218 };
    219 
    220 namespace {
    221 
    222 TEST_F(Canvas2DLayerBridgeTest, testFullLifecycleSingleThreaded)
    223 {
    224     fullLifecycleTest();
    225 }
    226 
    227 TEST_F(Canvas2DLayerBridgeTest, testNoDrawOnContextLost)
    228 {
    229     noDrawOnContextLostTest();
    230 }
    231 
    232 TEST_F(Canvas2DLayerBridgeTest, testPrepareMailboxWithBitmap)
    233 {
    234     prepareMailboxWithBitmapTest();
    235 }
    236 
    237 TEST_F(Canvas2DLayerBridgeTest, testPrepareMailboxAndLoseResource)
    238 {
    239     prepareMailboxAndLoseResourceTest();
    240 }
    241 
    242 } // namespace
    243