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 43using namespace blink; 44using testing::InSequence; 45using testing::Return; 46using testing::Test; 47 48namespace { 49 50class MockCanvasContext : public MockWebGraphicsContext3D { 51public: 52 MOCK_METHOD0(flush, void(void)); 53 MOCK_METHOD0(createTexture, unsigned(void)); 54 MOCK_METHOD1(deleteTexture, void(unsigned)); 55}; 56 57class MockWebGraphicsContext3DProvider : public WebGraphicsContext3DProvider { 58public: 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 72private: 73 WebGraphicsContext3D* m_context3d; 74}; 75 76class Canvas2DLayerBridgePtr { 77public: 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 89private: 90 RefPtr<Canvas2DLayerBridge> m_layerBridge; 91}; 92 93class NullWebExternalBitmap : public WebExternalBitmap { 94public: 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 112class Canvas2DLayerBridgeTest : public Test { 113protected: 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 220namespace { 221 222TEST_F(Canvas2DLayerBridgeTest, testFullLifecycleSingleThreaded) 223{ 224 fullLifecycleTest(); 225} 226 227TEST_F(Canvas2DLayerBridgeTest, testNoDrawOnContextLost) 228{ 229 noDrawOnContextLostTest(); 230} 231 232TEST_F(Canvas2DLayerBridgeTest, testPrepareMailboxWithBitmap) 233{ 234 prepareMailboxWithBitmapTest(); 235} 236 237TEST_F(Canvas2DLayerBridgeTest, testPrepareMailboxAndLoseResource) 238{ 239 prepareMailboxAndLoseResourceTest(); 240} 241 242} // namespace 243