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>
WebKitCreateInstance(REFCLSID clsid,T ** object)35 static HRESULT WebKitCreateInstance(REFCLSID clsid, T** object)
36 {
37 return WebKitCreateInstance(clsid, 0, __uuidof(T), reinterpret_cast<void**>(object));
38 }
39
webViewCount()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
createAndInitializeWebView(COMPtr<IWebView> & outWebView,HostWindow & window,HWND & viewWindow)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
runMessagePump(DWORD timeoutMilliseconds)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
finishWebViewDestructionTest(COMPtr<IWebView> & webView,HWND viewWindow)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.
TEST(WebViewDestruction,NoInitWithFrame)97 TEST(WebViewDestruction, NoInitWithFrame)
98 {
99 COMPtr<IWebView> webView;
100 TEST_ASSERT(SUCCEEDED(WebKitCreateInstance(__uuidof(WebView), &webView)));
101
102 finishWebViewDestructionTest(webView, 0);
103 }
104
TEST(WebViewDestruction,CloseWithoutInitWithFrame)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>
TEST(WebViewDestruction,NoCloseOrDestroyViewWindow)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>
TEST(WebViewDestruction,CloseWithoutDestroyViewWindow)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
TEST(WebViewDestruction,DestroyViewWindowWithoutClose)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
TEST(WebViewDestruction,CloseThenDestroyViewWindow)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
TEST(WebViewDestruction,DestroyViewWindowThenClose)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
TEST(WebViewDestruction,DestroyHostWindow)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
TEST(WebViewDestruction,DestroyHostWindowThenClose)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
TEST(WebViewDestruction,CloseThenDestroyHostWindow)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>
TEST(WebViewDestruction,MainFrameAfterClose)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