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