1 /* 2 * Copyright (C) 2010 Apple 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 "HostWindow.h" 26 #include "Test.h" 27 #include <WebCore/COMPtr.h> 28 #include <WebKit/WebKit.h> 29 #include <WebKit/WebKitCOMAPI.h> 30 #include <wtf/PassOwnPtr.h> 31 32 namespace WebKitAPITest { 33 34 template <typename T> 35 static HRESULT WebKitCreateInstance(REFCLSID clsid, T** object) 36 { 37 return WebKitCreateInstance(clsid, 0, __uuidof(T), reinterpret_cast<void**>(object)); 38 } 39 40 static int webViewCount() 41 { 42 COMPtr<IWebKitStatistics> statistics; 43 if (FAILED(WebKitCreateInstance(__uuidof(WebKitStatistics), &statistics))) 44 return -1; 45 int count; 46 if (FAILED(statistics->webViewCount(&count))) 47 return -1; 48 return count; 49 } 50 51 static void createAndInitializeWebView(COMPtr<IWebView>& outWebView, HostWindow& window, HWND& viewWindow) 52 { 53 COMPtr<IWebView> webView; 54 TEST_ASSERT(SUCCEEDED(WebKitCreateInstance(__uuidof(WebView), &webView))); 55 56 TEST_ASSERT(window.initialize()); 57 TEST_ASSERT(SUCCEEDED(webView->setHostWindow(reinterpret_cast<OLE_HANDLE>(window.window())))); 58 TEST_ASSERT(SUCCEEDED(webView->initWithFrame(window.clientRect(), 0, 0))); 59 60 COMPtr<IWebViewPrivate> viewPrivate(Query, webView); 61 TEST_ASSERT(viewPrivate); 62 TEST_ASSERT(SUCCEEDED(viewPrivate->viewWindow(reinterpret_cast<OLE_HANDLE*>(&viewWindow)))); 63 TEST_ASSERT(IsWindow(viewWindow)); 64 65 outWebView.adoptRef(webView.releaseRef()); 66 } 67 68 static void runMessagePump(DWORD timeoutMilliseconds) 69 { 70 DWORD startTickCount = GetTickCount(); 71 MSG msg; 72 BOOL result; 73 while ((result = PeekMessageW(&msg, 0, 0, 0, PM_REMOVE)) && GetTickCount() - startTickCount <= timeoutMilliseconds) { 74 if (result == -1) 75 break; 76 TranslateMessage(&msg); 77 DispatchMessage(&msg); 78 } 79 } 80 81 static void finishWebViewDestructionTest(COMPtr<IWebView>& webView, HWND viewWindow) 82 { 83 // Allow window messages to be processed, because in some cases that would trigger a crash (e.g., <http://webkit.org/b/32827>). 84 runMessagePump(50); 85 86 // We haven't crashed. Release the WebView and ensure that its view window has been destroyed and the WebView doesn't leak. 87 int currentWebViewCount = webViewCount(); 88 TEST_ASSERT(currentWebViewCount > 0); 89 90 webView = 0; 91 92 TEST_ASSERT(webViewCount() == currentWebViewCount - 1); 93 TEST_ASSERT(!IsWindow(viewWindow)); 94 } 95 96 // Tests that releasing a WebView without calling IWebView::initWithFrame works. 97 TEST(WebViewDestruction, NoInitWithFrame) 98 { 99 COMPtr<IWebView> webView; 100 TEST_ASSERT(SUCCEEDED(WebKitCreateInstance(__uuidof(WebView), &webView))); 101 102 finishWebViewDestructionTest(webView, 0); 103 } 104 105 TEST(WebViewDestruction, CloseWithoutInitWithFrame) 106 { 107 COMPtr<IWebView> webView; 108 TEST_ASSERT(SUCCEEDED(WebKitCreateInstance(__uuidof(WebView), &webView))); 109 110 TEST_ASSERT(SUCCEEDED(webView->close())); 111 112 finishWebViewDestructionTest(webView, 0); 113 } 114 115 // Tests that releasing a WebView without calling IWebView::close or DestroyWindow doesn't leak. <http://webkit.org/b/33162> 116 TEST(WebViewDestruction, NoCloseOrDestroyViewWindow) 117 { 118 COMPtr<IWebView> webView; 119 HostWindow window; 120 HWND viewWindow; 121 createAndInitializeWebView(webView, window, viewWindow); 122 123 finishWebViewDestructionTest(webView, viewWindow); 124 } 125 126 // Tests that calling IWebView::close without calling DestroyWindow, then releasing a WebView doesn't crash. <http://webkit.org/b/32827> 127 TEST(WebViewDestruction, CloseWithoutDestroyViewWindow) 128 { 129 COMPtr<IWebView> webView; 130 HostWindow window; 131 HWND viewWindow; 132 createAndInitializeWebView(webView, window, viewWindow); 133 134 TEST_ASSERT(SUCCEEDED(webView->close())); 135 136 finishWebViewDestructionTest(webView, viewWindow); 137 } 138 139 TEST(WebViewDestruction, DestroyViewWindowWithoutClose) 140 { 141 COMPtr<IWebView> webView; 142 HostWindow window; 143 HWND viewWindow; 144 createAndInitializeWebView(webView, window, viewWindow); 145 146 DestroyWindow(viewWindow); 147 148 finishWebViewDestructionTest(webView, viewWindow); 149 } 150 151 TEST(WebViewDestruction, CloseThenDestroyViewWindow) 152 { 153 COMPtr<IWebView> webView; 154 HostWindow window; 155 HWND viewWindow; 156 createAndInitializeWebView(webView, window, viewWindow); 157 158 TEST_ASSERT(SUCCEEDED(webView->close())); 159 DestroyWindow(viewWindow); 160 161 finishWebViewDestructionTest(webView, viewWindow); 162 } 163 164 TEST(WebViewDestruction, DestroyViewWindowThenClose) 165 { 166 COMPtr<IWebView> webView; 167 HostWindow window; 168 HWND viewWindow; 169 createAndInitializeWebView(webView, window, viewWindow); 170 171 DestroyWindow(viewWindow); 172 TEST_ASSERT(SUCCEEDED(webView->close())); 173 174 finishWebViewDestructionTest(webView, viewWindow); 175 } 176 177 TEST(WebViewDestruction, DestroyHostWindow) 178 { 179 COMPtr<IWebView> webView; 180 HostWindow window; 181 HWND viewWindow; 182 createAndInitializeWebView(webView, window, viewWindow); 183 184 DestroyWindow(window.window()); 185 186 finishWebViewDestructionTest(webView, viewWindow); 187 } 188 189 TEST(WebViewDestruction, DestroyHostWindowThenClose) 190 { 191 COMPtr<IWebView> webView; 192 HostWindow window; 193 HWND viewWindow; 194 createAndInitializeWebView(webView, window, viewWindow); 195 196 DestroyWindow(window.window()); 197 TEST_ASSERT(SUCCEEDED(webView->close())); 198 199 finishWebViewDestructionTest(webView, viewWindow); 200 } 201 202 TEST(WebViewDestruction, CloseThenDestroyHostWindow) 203 { 204 COMPtr<IWebView> webView; 205 HostWindow window; 206 HWND viewWindow; 207 createAndInitializeWebView(webView, window, viewWindow); 208 209 TEST_ASSERT(SUCCEEDED(webView->close())); 210 DestroyWindow(window.window()); 211 212 finishWebViewDestructionTest(webView, viewWindow); 213 } 214 215 // Tests that calling IWebView::mainFrame after calling IWebView::close doesn't crash. <http://webkit.org/b/32868> 216 TEST(WebViewDestruction, MainFrameAfterClose) 217 { 218 COMPtr<IWebView> webView; 219 HostWindow window; 220 HWND viewWindow; 221 createAndInitializeWebView(webView, window, viewWindow); 222 223 TEST_ASSERT(SUCCEEDED(webView->close())); 224 COMPtr<IWebFrame> mainFrame; 225 TEST_ASSERT(SUCCEEDED(webView->mainFrame(&mainFrame))); 226 227 finishWebViewDestructionTest(webView, viewWindow); 228 } 229 230 } // namespace WebKitAPITest 231