Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(133)

Side by Side Diff: chrome/browser/extensions/api/extension_action/browser_action_interactive_test.cc

Issue 2918293002: Ensure all BrowserAction ExtensionHosts are destroyed in BrowserActionInteractiveTest (Closed)
Patch Set: clear upstream CL Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "base/test/test_timeouts.h"
5 #include "build/build_config.h" 6 #include "build/build_config.h"
6 #include "chrome/browser/extensions/browser_action_test_util.h" 7 #include "chrome/browser/extensions/browser_action_test_util.h"
7 #include "chrome/browser/extensions/extension_action.h" 8 #include "chrome/browser/extensions/extension_action.h"
8 #include "chrome/browser/extensions/extension_action_manager.h" 9 #include "chrome/browser/extensions/extension_action_manager.h"
9 #include "chrome/browser/extensions/extension_apitest.h" 10 #include "chrome/browser/extensions/extension_apitest.h"
10 #include "chrome/browser/extensions/extension_service.h" 11 #include "chrome/browser/extensions/extension_service.h"
11 #include "chrome/browser/sessions/session_tab_helper.h" 12 #include "chrome/browser/sessions/session_tab_helper.h"
12 #include "chrome/browser/ui/browser.h" 13 #include "chrome/browser/ui/browser.h"
13 #include "chrome/browser/ui/browser_commands.h" 14 #include "chrome/browser/ui/browser_commands.h"
14 #include "chrome/browser/ui/browser_finder.h" 15 #include "chrome/browser/ui/browser_finder.h"
(...skipping 15 matching lines...) Expand all
30 #include "extensions/test/result_catcher.h" 31 #include "extensions/test/result_catcher.h"
31 #include "ui/base/ui_features.h" 32 #include "ui/base/ui_features.h"
32 33
33 #if defined(OS_WIN) 34 #if defined(OS_WIN)
34 #include "ui/views/win/hwnd_util.h" 35 #include "ui/views/win/hwnd_util.h"
35 #endif 36 #endif
36 37
37 namespace extensions { 38 namespace extensions {
38 namespace { 39 namespace {
39 40
41 // Helper to ensure all extension hosts are destroyed during the test. If a host
42 // is still alive, the Profile can not be destroyed in
43 // BrowserProcessImpl::StartTearDown(). TODO(tapted): The existence of this
Devlin 2017/06/05 14:22:11 I think I'd agree with this. What happens if a us
tapted 2017/06/05 20:59:52 The code in ProfileDestroyer::DestroyProfileWhenAp
44 // helper is probably a bug. Extension hosts do not currently block shutdown the
45 // way a browser tab does. Maybe they should. See http://crbug.com/729476.
46 class ExtensionHostWatcher : public content::NotificationObserver {
47 public:
48 ExtensionHostWatcher() {
49 registrar_.Add(this, NOTIFICATION_EXTENSION_HOST_CREATED,
50 content::NotificationService::AllSources());
51 registrar_.Add(this, NOTIFICATION_EXTENSION_HOST_DESTROYED,
52 content::NotificationService::AllSources());
53 }
54
55 void Wait() {
56 if (created_ == destroyed_)
57 return;
58
59 base::RunLoop run_loop;
60 quit_closure_ = run_loop.QuitClosure();
61 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
62 FROM_HERE, quit_closure_, TestTimeouts::action_timeout());
Devlin 2017/06/05 14:22:12 Interesting! I don't think I've seen this before.
63 run_loop.Run();
64 }
65
66 int created() const { return created_; }
67 int destroyed() const { return destroyed_; }
68
69 // NotificationObserver:
70 void Observe(int type,
71 const content::NotificationSource& source,
72 const content::NotificationDetails& details) override {
73 ++(type == NOTIFICATION_EXTENSION_HOST_CREATED ? created_ : destroyed_);
74 if (!quit_closure_.is_null() && created_ == destroyed_)
75 quit_closure_.Run();
76 }
77
78 private:
79 content::NotificationRegistrar registrar_;
80 base::Closure quit_closure_;
81 int created_ = 0;
82 int destroyed_ = 0;
83
84 DISALLOW_COPY_AND_ASSIGN(ExtensionHostWatcher);
85 };
86
40 // chrome.browserAction API tests that interact with the UI in such a way that 87 // chrome.browserAction API tests that interact with the UI in such a way that
41 // they cannot be run concurrently (i.e. openPopup API tests that require the 88 // they cannot be run concurrently (i.e. openPopup API tests that require the
42 // window be focused/active). 89 // window be focused/active).
43 class BrowserActionInteractiveTest : public ExtensionApiTest { 90 class BrowserActionInteractiveTest : public ExtensionApiTest {
44 public: 91 public:
45 BrowserActionInteractiveTest() {} 92 BrowserActionInteractiveTest() {}
46 ~BrowserActionInteractiveTest() override {} 93 ~BrowserActionInteractiveTest() override {}
47 94
48 // BrowserTestBase: 95 // BrowserTestBase:
49 void SetUpOnMainThread() override { 96 void SetUpOnMainThread() override {
97 host_watcher_ = base::MakeUnique<ExtensionHostWatcher>();
50 ExtensionApiTest::SetUpOnMainThread(); 98 ExtensionApiTest::SetUpOnMainThread();
51 EXPECT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser())); 99 EXPECT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
52 } 100 }
53 101
102 void TearDownOnMainThread() override {
103 // Note browser windows are closed in PostRunTestOnMainThread(), which is
104 // called after this. But relying on the window close to close the
105 // extension host can cause flakes. See http://crbug.com/729476.
106 // Waiting here requires individual tests to ensure their popup has closed.
107 ExtensionApiTest::TearDownOnMainThread();
108 host_watcher_->Wait();
109 EXPECT_EQ(host_watcher_->created(), host_watcher_->destroyed());
110 }
111
54 protected: 112 protected:
55 // Function to control whether to run popup tests for the current platform. 113 // Function to control whether to run popup tests for the current platform.
56 // These tests require RunExtensionSubtest to work as expected and the browser 114 // These tests require RunExtensionSubtest to work as expected and the browser
57 // window to able to be made active automatically. Returns false for platforms 115 // window to able to be made active automatically. Returns false for platforms
58 // where these conditions are not met. 116 // where these conditions are not met.
59 bool ShouldRunPopupTest() { 117 bool ShouldRunPopupTest() {
60 // TODO(justinlin): http://crbug.com/177163 118 // TODO(justinlin): http://crbug.com/177163
61 #if defined(OS_WIN) && !defined(NDEBUG) 119 #if defined(OS_WIN) && !defined(NDEBUG)
62 return false; 120 return false;
63 #else 121 #else
(...skipping 24 matching lines...) Expand all
88 // Open an extension popup by clicking the browser action button. 146 // Open an extension popup by clicking the browser action button.
89 void OpenPopupViaToolbar() { 147 void OpenPopupViaToolbar() {
90 content::WindowedNotificationObserver frame_observer( 148 content::WindowedNotificationObserver frame_observer(
91 content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME, 149 content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
92 content::NotificationService::AllSources()); 150 content::NotificationService::AllSources());
93 BrowserActionTestUtil(browser()).Press(0); 151 BrowserActionTestUtil(browser()).Press(0);
94 frame_observer.Wait(); 152 frame_observer.Wait();
95 EnsurePopupActive(); 153 EnsurePopupActive();
96 } 154 }
97 155
156 // Close the popup window directly.
157 void ClosePopup() { BrowserActionTestUtil(browser()).HidePopup(); }
158
98 // Trigger a focus loss to close the popup. 159 // Trigger a focus loss to close the popup.
99 void ClosePopupViaFocusLoss() { 160 void ClosePopupViaFocusLoss() {
100 EXPECT_TRUE(BrowserActionTestUtil(browser()).HasPopup()); 161 EXPECT_TRUE(BrowserActionTestUtil(browser()).HasPopup());
101 content::WindowedNotificationObserver observer( 162 content::WindowedNotificationObserver observer(
102 extensions::NOTIFICATION_EXTENSION_HOST_DESTROYED, 163 extensions::NOTIFICATION_EXTENSION_HOST_DESTROYED,
103 content::NotificationService::AllSources()); 164 content::NotificationService::AllSources());
104 165
105 #if defined(OS_MACOSX) 166 #if defined(OS_MACOSX)
106 // ClickOnView() in an inactive window is not robust on Mac. The click does 167 // ClickOnView() in an inactive window is not robust on Mac. The click does
107 // not guarantee window activation on trybots. So activate the browser 168 // not guarantee window activation on trybots. So activate the browser
108 // explicitly, thus causing the bubble to lose focus and dismiss itself. 169 // explicitly, thus causing the bubble to lose focus and dismiss itself.
109 // This works because bubbles on Mac are always toplevel. 170 // This works because bubbles on Mac are always toplevel.
110 EXPECT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser())); 171 EXPECT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
111 #else 172 #else
112 // Elsewhere, click on the omnibox. Note that with aura, the browser may be 173 // Elsewhere, click on the omnibox. Note that with aura, the browser may be
113 // "active" the entire time when the popup is not a toplevel window. It's 174 // "active" the entire time when the popup is not a toplevel window. It's
114 // aura::Window::Focus() that determines where key events go in this case. 175 // aura::Window::Focus() that determines where key events go in this case.
115 ui_test_utils::ClickOnView(browser(), VIEW_ID_OMNIBOX); 176 ui_test_utils::ClickOnView(browser(), VIEW_ID_OMNIBOX);
116 #endif 177 #endif
117 178
118 // The window disappears immediately. 179 // The window disappears immediately.
119 EXPECT_FALSE(BrowserActionTestUtil(browser()).HasPopup()); 180 EXPECT_FALSE(BrowserActionTestUtil(browser()).HasPopup());
120 181
121 // Wait for the notification to achieve a consistent state and verify that 182 // Wait for the notification to achieve a consistent state and verify that
122 // the popup was properly torn down. 183 // the popup was properly torn down.
123 observer.Wait(); 184 observer.Wait();
124 base::RunLoop().RunUntilIdle(); 185 base::RunLoop().RunUntilIdle();
125 } 186 }
187
188 private:
189 std::unique_ptr<ExtensionHostWatcher> host_watcher_;
190
191 DISALLOW_COPY_AND_ASSIGN(BrowserActionInteractiveTest);
126 }; 192 };
127 193
128 // Tests opening a popup using the chrome.browserAction.openPopup API. This test 194 // Tests opening a popup using the chrome.browserAction.openPopup API. This test
129 // opens a popup in the starting window, closes the popup, creates a new window 195 // opens a popup in the starting window, closes the popup, creates a new window
130 // and opens a popup in the new window. Both popups should succeed in opening. 196 // and opens a popup in the new window. Both popups should succeed in opening.
131 IN_PROC_BROWSER_TEST_F(BrowserActionInteractiveTest, TestOpenPopup) { 197 IN_PROC_BROWSER_TEST_F(BrowserActionInteractiveTest, TestOpenPopup) {
132 if (!ShouldRunPopupTest()) 198 if (!ShouldRunPopupTest())
133 return; 199 return;
134 200
135 BrowserActionTestUtil browserActionBar(browser()); 201 BrowserActionTestUtil browserActionBar(browser());
(...skipping 17 matching lines...) Expand all
153 WindowOpenDisposition::NEW_WINDOW, 219 WindowOpenDisposition::NEW_WINDOW,
154 ui::PAGE_TRANSITION_TYPED, false))); 220 ui::PAGE_TRANSITION_TYPED, false)));
155 // Hide all the buttons to test that it opens even when the browser action 221 // Hide all the buttons to test that it opens even when the browser action
156 // is in the overflow bucket. 222 // is in the overflow bucket.
157 ToolbarActionsModel::Get(profile())->SetVisibleIconCount(0); 223 ToolbarActionsModel::Get(profile())->SetVisibleIconCount(0);
158 frame_observer.Wait(); 224 frame_observer.Wait();
159 } 225 }
160 226
161 EXPECT_TRUE(new_browser != NULL); 227 EXPECT_TRUE(new_browser != NULL);
162 228
163 // Flaky on non-aura linux http://crbug.com/309749
164 #if !(defined(OS_LINUX) && !defined(USE_AURA))
165 ResultCatcher catcher; 229 ResultCatcher catcher;
166 { 230 {
167 content::WindowedNotificationObserver frame_observer( 231 content::WindowedNotificationObserver frame_observer(
168 content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME, 232 content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
169 content::NotificationService::AllSources()); 233 content::NotificationService::AllSources());
170 // Show second popup in new window. 234 // Show second popup in new window.
171 listener.Reply("show another"); 235 listener.Reply("show another");
172 frame_observer.Wait(); 236 frame_observer.Wait();
173 EXPECT_TRUE(BrowserActionTestUtil(new_browser).HasPopup()); 237 EXPECT_TRUE(BrowserActionTestUtil(new_browser).HasPopup());
174 } 238 }
175 ASSERT_TRUE(catcher.GetNextResult()) << message_; 239 ASSERT_TRUE(catcher.GetNextResult()) << message_;
176 #endif 240 BrowserActionTestUtil(new_browser).HidePopup();
177 } 241 }
178 242
179 // Tests opening a popup in an incognito window. 243 // Tests opening a popup in an incognito window.
180 IN_PROC_BROWSER_TEST_F(BrowserActionInteractiveTest, TestOpenPopupIncognito) { 244 IN_PROC_BROWSER_TEST_F(BrowserActionInteractiveTest, TestOpenPopupIncognito) {
181 if (!ShouldRunPopupTest()) 245 if (!ShouldRunPopupTest())
182 return; 246 return;
183 247
184 content::WindowedNotificationObserver frame_observer( 248 content::WindowedNotificationObserver frame_observer(
185 content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME, 249 content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
186 content::NotificationService::AllSources()); 250 content::NotificationService::AllSources());
187 ASSERT_TRUE(RunExtensionSubtest("browser_action/open_popup", 251 ASSERT_TRUE(RunExtensionSubtest("browser_action/open_popup",
188 "open_popup_succeeds.html", 252 "open_popup_succeeds.html",
189 kFlagEnableIncognito | kFlagUseIncognito)) 253 kFlagEnableIncognito | kFlagUseIncognito))
190 << message_; 254 << message_;
191 frame_observer.Wait(); 255 frame_observer.Wait();
192 // Non-Aura Linux uses a singleton for the popup, so it looks like all windows 256 // Non-Aura Linux uses a singleton for the popup, so it looks like all windows
193 // have popups if there is any popup open. 257 // have popups if there is any popup open.
194 #if !(defined(OS_LINUX) && !defined(USE_AURA)) 258 #if !(defined(OS_LINUX) && !defined(USE_AURA))
195 // Starting window does not have a popup. 259 // Starting window does not have a popup.
196 EXPECT_FALSE(BrowserActionTestUtil(browser()).HasPopup()); 260 EXPECT_FALSE(BrowserActionTestUtil(browser()).HasPopup());
197 #endif 261 #endif
198 // Incognito window should have a popup. 262 // Incognito window should have a popup.
199 EXPECT_TRUE(BrowserActionTestUtil(BrowserList::GetInstance()->GetLastActive()) 263 BrowserActionTestUtil test_util(BrowserList::GetInstance()->GetLastActive());
200 .HasPopup()); 264 EXPECT_TRUE(test_util.HasPopup());
265 test_util.HidePopup();
201 } 266 }
202 267
203 // Tests that an extension can open a popup in the last active incognito window 268 // Tests that an extension can open a popup in the last active incognito window
204 // even from a background page with a non-incognito profile. 269 // even from a background page with a non-incognito profile.
205 // (crbug.com/448853) 270 // (crbug.com/448853)
206 #if defined(OS_WIN) 271 #if defined(OS_WIN)
207 // Fails on XP: http://crbug.com/515717 272 // Fails on XP: http://crbug.com/515717
208 #define MAYBE_TestOpenPopupIncognitoFromBackground \ 273 #define MAYBE_TestOpenPopupIncognitoFromBackground \
209 DISABLED_TestOpenPopupIncognitoFromBackground 274 DISABLED_TestOpenPopupIncognitoFromBackground
210 #else 275 #else
211 #define MAYBE_TestOpenPopupIncognitoFromBackground \ 276 #define MAYBE_TestOpenPopupIncognitoFromBackground \
212 TestOpenPopupIncognitoFromBackground 277 TestOpenPopupIncognitoFromBackground
213 #endif 278 #endif
214 IN_PROC_BROWSER_TEST_F(BrowserActionInteractiveTest, 279 IN_PROC_BROWSER_TEST_F(BrowserActionInteractiveTest,
215 MAYBE_TestOpenPopupIncognitoFromBackground) { 280 MAYBE_TestOpenPopupIncognitoFromBackground) {
216 if (!ShouldRunPopupTest()) 281 if (!ShouldRunPopupTest())
217 return; 282 return;
218 283
219 const Extension* extension = 284 const Extension* extension =
220 LoadExtensionIncognito(test_data_dir_.AppendASCII("browser_action"). 285 LoadExtensionIncognito(test_data_dir_.AppendASCII("browser_action").
221 AppendASCII("open_popup_background")); 286 AppendASCII("open_popup_background"));
222 ASSERT_TRUE(extension); 287 ASSERT_TRUE(extension);
223 ExtensionTestMessageListener listener(false); 288 ExtensionTestMessageListener listener(false);
224 listener.set_extension_id(extension->id()); 289 listener.set_extension_id(extension->id());
225 290
226 Browser* incognito_browser = 291 Browser* incognito_browser =
227 OpenURLOffTheRecord(profile(), GURL("chrome://newtab/")); 292 OpenURLOffTheRecord(profile(), GURL("chrome://newtab/"));
228 listener.WaitUntilSatisfied(); 293 listener.WaitUntilSatisfied();
229 EXPECT_EQ(std::string("opened"), listener.message()); 294 EXPECT_EQ(std::string("opened"), listener.message());
230 EXPECT_TRUE(BrowserActionTestUtil(incognito_browser).HasPopup()); 295 BrowserActionTestUtil test_util(incognito_browser);
296 EXPECT_TRUE(test_util.HasPopup());
297 test_util.HidePopup();
231 } 298 }
232 299
233 #if defined(OS_LINUX) 300 #if defined(OS_LINUX)
234 #define MAYBE_TestOpenPopupDoesNotCloseOtherPopups DISABLED_TestOpenPopupDoesNot CloseOtherPopups 301 #define MAYBE_TestOpenPopupDoesNotCloseOtherPopups DISABLED_TestOpenPopupDoesNot CloseOtherPopups
235 #else 302 #else
236 #define MAYBE_TestOpenPopupDoesNotCloseOtherPopups TestOpenPopupDoesNotCloseOthe rPopups 303 #define MAYBE_TestOpenPopupDoesNotCloseOtherPopups TestOpenPopupDoesNotCloseOthe rPopups
237 #endif 304 #endif
238 // Tests if there is already a popup open (by a user click or otherwise), that 305 // Tests if there is already a popup open (by a user click or otherwise), that
239 // the openPopup API does not override it. 306 // the openPopup API does not override it.
240 IN_PROC_BROWSER_TEST_F(BrowserActionInteractiveTest, 307 IN_PROC_BROWSER_TEST_F(BrowserActionInteractiveTest,
(...skipping 11 matching lines...) Expand all
252 // Load the test extension which will do nothing except notifyPass() to 319 // Load the test extension which will do nothing except notifyPass() to
253 // return control here. 320 // return control here.
254 ASSERT_TRUE(RunExtensionSubtest("browser_action/open_popup", 321 ASSERT_TRUE(RunExtensionSubtest("browser_action/open_popup",
255 "open_popup_fails.html")) << message_; 322 "open_popup_fails.html")) << message_;
256 EXPECT_TRUE(listener.WaitUntilSatisfied()); 323 EXPECT_TRUE(listener.WaitUntilSatisfied());
257 OpenPopupViaToolbar(); 324 OpenPopupViaToolbar();
258 ResultCatcher catcher; 325 ResultCatcher catcher;
259 // Return control to javascript to validate that opening a popup fails now. 326 // Return control to javascript to validate that opening a popup fails now.
260 listener.Reply("show another"); 327 listener.Reply("show another");
261 ASSERT_TRUE(catcher.GetNextResult()) << message_; 328 ASSERT_TRUE(catcher.GetNextResult()) << message_;
329 ClosePopup();
262 } 330 }
263 331
264 // Test that openPopup does not grant tab permissions like for browser action 332 // Test that openPopup does not grant tab permissions like for browser action
265 // clicks if the activeTab permission is set. 333 // clicks if the activeTab permission is set.
266 IN_PROC_BROWSER_TEST_F(BrowserActionInteractiveTest, 334 IN_PROC_BROWSER_TEST_F(BrowserActionInteractiveTest,
267 TestOpenPopupDoesNotGrantTabPermissions) { 335 TestOpenPopupDoesNotGrantTabPermissions) {
268 if (!ShouldRunPopupTest()) 336 if (!ShouldRunPopupTest())
269 return; 337 return;
270 338
271 OpenPopupViaAPI(); 339 OpenPopupViaAPI();
272 ExtensionService* service = extensions::ExtensionSystem::Get( 340 ExtensionService* service = extensions::ExtensionSystem::Get(
273 browser()->profile())->extension_service(); 341 browser()->profile())->extension_service();
274 ASSERT_FALSE( 342 ASSERT_FALSE(
275 service->GetExtensionById(last_loaded_extension_id(), false) 343 service->GetExtensionById(last_loaded_extension_id(), false)
276 ->permissions_data() 344 ->permissions_data()
277 ->HasAPIPermissionForTab( 345 ->HasAPIPermissionForTab(
278 SessionTabHelper::IdForTab( 346 SessionTabHelper::IdForTab(
279 browser()->tab_strip_model()->GetActiveWebContents()), 347 browser()->tab_strip_model()->GetActiveWebContents()),
280 APIPermission::kTab)); 348 APIPermission::kTab));
349 ClosePopup();
281 } 350 }
282 351
283 // Test that the extension popup is closed when the browser window is focused. 352 // Test that the extension popup is closed when the browser window is focused.
284 IN_PROC_BROWSER_TEST_F(BrowserActionInteractiveTest, FocusLossClosesPopup1) { 353 IN_PROC_BROWSER_TEST_F(BrowserActionInteractiveTest, FocusLossClosesPopup1) {
285 if (!ShouldRunPopupTest()) 354 if (!ShouldRunPopupTest())
286 return; 355 return;
287 OpenPopupViaAPI(); 356 OpenPopupViaAPI();
288 ClosePopupViaFocusLoss(); 357 ClosePopupViaFocusLoss();
289 } 358 }
290 359
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after
410 479
411 // Forcibly closing the browser HWND should not cause a crash. 480 // Forcibly closing the browser HWND should not cause a crash.
412 EXPECT_EQ(TRUE, ::CloseWindow(hwnd)); 481 EXPECT_EQ(TRUE, ::CloseWindow(hwnd));
413 EXPECT_EQ(TRUE, ::DestroyWindow(hwnd)); 482 EXPECT_EQ(TRUE, ::DestroyWindow(hwnd));
414 EXPECT_EQ(FALSE, ::IsWindow(hwnd)); 483 EXPECT_EQ(FALSE, ::IsWindow(hwnd));
415 } 484 }
416 #endif // OS_WIN 485 #endif // OS_WIN
417 486
418 } // namespace 487 } // namespace
419 } // namespace extensions 488 } // namespace extensions
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698