• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2016 The Chromium Embedded Framework Authors. All rights
2 // reserved. Use of this source code is governed by a BSD-style license that
3 // can be found in the LICENSE file.
4 
5 #include "tests/cefclient/browser/root_window_views.h"
6 
7 #include "include/base/cef_bind.h"
8 #include "include/base/cef_build.h"
9 #include "include/cef_app.h"
10 #include "include/wrapper/cef_helpers.h"
11 #include "tests/cefclient/browser/client_handler_std.h"
12 
13 namespace client {
14 
15 namespace {
16 
17 // Images that are loaded early and cached.
18 static const char* kDefaultImageCache[] = {"menu_icon", "window_icon"};
19 
20 }  // namespace
21 
RootWindowViews()22 RootWindowViews::RootWindowViews()
23     : with_controls_(false),
24       always_on_top_(false),
25       with_extension_(false),
26       initially_hidden_(false),
27       is_popup_(false),
28       position_on_resize_(false),
29       initialized_(false),
30       window_destroyed_(false),
31       browser_destroyed_(false) {}
32 
~RootWindowViews()33 RootWindowViews::~RootWindowViews() {
34   REQUIRE_MAIN_THREAD();
35 }
36 
Init(RootWindow::Delegate * delegate,const RootWindowConfig & config,const CefBrowserSettings & settings)37 void RootWindowViews::Init(RootWindow::Delegate* delegate,
38                            const RootWindowConfig& config,
39                            const CefBrowserSettings& settings) {
40   DCHECK(delegate);
41   DCHECK(!config.with_osr);  // Windowless rendering is not supported.
42   DCHECK(!initialized_);
43 
44   delegate_ = delegate;
45   with_controls_ = config.with_controls;
46   always_on_top_ = config.always_on_top;
47   with_extension_ = config.with_extension;
48   initially_hidden_ = config.initially_hidden;
49   if (initially_hidden_ && !config.source_bounds.IsEmpty()) {
50     // The window will be sized and positioned in OnAutoResize().
51     initial_bounds_ = config.source_bounds;
52     position_on_resize_ = true;
53   } else {
54     initial_bounds_ = config.bounds;
55   }
56   parent_window_ = config.parent_window;
57   close_callback_ = config.close_callback;
58 
59   CreateClientHandler(config.url);
60   initialized_ = true;
61 
62   // Continue initialization on the UI thread.
63   InitOnUIThread(settings, config.url, delegate_->GetRequestContext(this));
64 }
65 
InitAsPopup(RootWindow::Delegate * delegate,bool with_controls,bool with_osr,const CefPopupFeatures & popupFeatures,CefWindowInfo & windowInfo,CefRefPtr<CefClient> & client,CefBrowserSettings & settings)66 void RootWindowViews::InitAsPopup(RootWindow::Delegate* delegate,
67                                   bool with_controls,
68                                   bool with_osr,
69                                   const CefPopupFeatures& popupFeatures,
70                                   CefWindowInfo& windowInfo,
71                                   CefRefPtr<CefClient>& client,
72                                   CefBrowserSettings& settings) {
73   CEF_REQUIRE_UI_THREAD();
74 
75   DCHECK(delegate);
76   DCHECK(!with_osr);  // Windowless rendering is not supported.
77   DCHECK(!initialized_);
78 
79   delegate_ = delegate;
80   with_controls_ = with_controls;
81   is_popup_ = true;
82 
83   if (popupFeatures.xSet)
84     initial_bounds_.x = popupFeatures.x;
85   if (popupFeatures.ySet)
86     initial_bounds_.y = popupFeatures.y;
87   if (popupFeatures.widthSet)
88     initial_bounds_.width = popupFeatures.width;
89   if (popupFeatures.heightSet)
90     initial_bounds_.height = popupFeatures.height;
91 
92   CreateClientHandler(std::string());
93   initialized_ = true;
94 
95   // The Window will be created in ViewsWindow::OnPopupBrowserViewCreated().
96   client = client_handler_;
97 }
98 
Show(ShowMode mode)99 void RootWindowViews::Show(ShowMode mode) {
100   if (!CefCurrentlyOn(TID_UI)) {
101     // Execute this method on the UI thread.
102     CefPostTask(TID_UI, base::Bind(&RootWindowViews::Show, this, mode));
103     return;
104   }
105 
106   if (!window_)
107     return;
108 
109   window_->Show();
110 
111   switch (mode) {
112     case ShowMinimized:
113       window_->Minimize();
114       break;
115     case ShowMaximized:
116       window_->Maximize();
117       break;
118     default:
119       break;
120   }
121 }
122 
Hide()123 void RootWindowViews::Hide() {
124   if (!CefCurrentlyOn(TID_UI)) {
125     // Execute this method on the UI thread.
126     CefPostTask(TID_UI, base::Bind(&RootWindowViews::Hide, this));
127     return;
128   }
129 
130   if (window_)
131     window_->Hide();
132 }
133 
SetBounds(int x,int y,size_t width,size_t height)134 void RootWindowViews::SetBounds(int x, int y, size_t width, size_t height) {
135   if (!CefCurrentlyOn(TID_UI)) {
136     // Execute this method on the UI thread.
137     CefPostTask(TID_UI, base::Bind(&RootWindowViews::SetBounds, this, x, y,
138                                    width, height));
139     return;
140   }
141 
142   if (window_) {
143     window_->SetBounds(
144         CefRect(x, y, static_cast<int>(width), static_cast<int>(height)));
145   }
146 }
147 
Close(bool force)148 void RootWindowViews::Close(bool force) {
149   if (!CefCurrentlyOn(TID_UI)) {
150     // Execute this method on the UI thread.
151     CefPostTask(TID_UI, base::Bind(&RootWindowViews::Close, this, force));
152     return;
153   }
154 
155   if (window_)
156     window_->Close(force);
157 }
158 
SetDeviceScaleFactor(float device_scale_factor)159 void RootWindowViews::SetDeviceScaleFactor(float device_scale_factor) {
160   REQUIRE_MAIN_THREAD();
161   // Windowless rendering is not supported.
162   NOTREACHED();
163 }
164 
GetDeviceScaleFactor() const165 float RootWindowViews::GetDeviceScaleFactor() const {
166   REQUIRE_MAIN_THREAD();
167   // Windowless rendering is not supported.
168   NOTREACHED();
169   return 0.0;
170 }
171 
GetBrowser() const172 CefRefPtr<CefBrowser> RootWindowViews::GetBrowser() const {
173   REQUIRE_MAIN_THREAD();
174   return browser_;
175 }
176 
GetWindowHandle() const177 ClientWindowHandle RootWindowViews::GetWindowHandle() const {
178   REQUIRE_MAIN_THREAD();
179 #if defined(OS_LINUX)
180   // ClientWindowHandle is a GtkWidget* on Linux and we don't have one of those.
181   return NULL;
182 #else
183   if (browser_)
184     return browser_->GetHost()->GetWindowHandle();
185   return kNullWindowHandle;
186 #endif
187 }
188 
WithExtension() const189 bool RootWindowViews::WithExtension() const {
190   DCHECK(initialized_);
191   return with_extension_;
192 }
193 
WithControls()194 bool RootWindowViews::WithControls() {
195   DCHECK(initialized_);
196   return with_controls_;
197 }
198 
WithExtension()199 bool RootWindowViews::WithExtension() {
200   DCHECK(initialized_);
201   return with_extension_;
202 }
203 
OnExtensionsChanged(const ExtensionSet & extensions)204 void RootWindowViews::OnExtensionsChanged(const ExtensionSet& extensions) {
205   if (!CefCurrentlyOn(TID_UI)) {
206     // Execute this method on the UI thread.
207     CefPostTask(TID_UI, base::Bind(&RootWindowViews::OnExtensionsChanged, this,
208                                    extensions));
209     return;
210   }
211 
212   if (window_) {
213     window_->OnExtensionsChanged(extensions);
214   } else {
215     // Window may not exist yet for popups.
216     pending_extensions_ = extensions;
217   }
218 }
219 
InitiallyHidden()220 bool RootWindowViews::InitiallyHidden() {
221   CEF_REQUIRE_UI_THREAD();
222   return initially_hidden_;
223 }
224 
GetParentWindow()225 CefRefPtr<CefWindow> RootWindowViews::GetParentWindow() {
226   CEF_REQUIRE_UI_THREAD();
227   return parent_window_;
228 }
229 
GetWindowBounds()230 CefRect RootWindowViews::GetWindowBounds() {
231   CEF_REQUIRE_UI_THREAD();
232   return initial_bounds_;
233 }
234 
GetImageCache()235 scoped_refptr<ImageCache> RootWindowViews::GetImageCache() {
236   CEF_REQUIRE_UI_THREAD();
237   return image_cache_;
238 }
239 
OnViewsWindowCreated(CefRefPtr<ViewsWindow> window)240 void RootWindowViews::OnViewsWindowCreated(CefRefPtr<ViewsWindow> window) {
241   CEF_REQUIRE_UI_THREAD();
242   DCHECK(!window_);
243   window_ = window;
244   window_->SetAlwaysOnTop(always_on_top_);
245 
246   if (!pending_extensions_.empty()) {
247     window_->OnExtensionsChanged(pending_extensions_);
248     pending_extensions_.clear();
249   }
250 }
251 
OnViewsWindowDestroyed(CefRefPtr<ViewsWindow> window)252 void RootWindowViews::OnViewsWindowDestroyed(CefRefPtr<ViewsWindow> window) {
253   CEF_REQUIRE_UI_THREAD();
254   window_ = nullptr;
255 
256   // Continue on the main thread.
257   MAIN_POST_CLOSURE(
258       base::Bind(&RootWindowViews::NotifyViewsWindowDestroyed, this));
259 }
260 
OnViewsWindowActivated(CefRefPtr<ViewsWindow> window)261 void RootWindowViews::OnViewsWindowActivated(CefRefPtr<ViewsWindow> window) {
262   CEF_REQUIRE_UI_THREAD();
263 
264   // Continue on the main thread.
265   MAIN_POST_CLOSURE(
266       base::Bind(&RootWindowViews::NotifyViewsWindowActivated, this));
267 }
268 
GetDelegateForPopup(CefRefPtr<CefClient> client)269 ViewsWindow::Delegate* RootWindowViews::GetDelegateForPopup(
270     CefRefPtr<CefClient> client) {
271   CEF_REQUIRE_UI_THREAD();
272   // |handler| was created in RootWindowViews::InitAsPopup().
273   ClientHandlerStd* handler = static_cast<ClientHandlerStd*>(client.get());
274   RootWindowViews* root_window =
275       static_cast<RootWindowViews*>(handler->delegate());
276 
277   // Transfer some state to the child RootWindowViews.
278   root_window->image_cache_ = image_cache_;
279 
280   return root_window;
281 }
282 
CreateExtensionWindow(CefRefPtr<CefExtension> extension,const CefRect & source_bounds,CefRefPtr<CefWindow> parent_window,const base::Closure & close_callback)283 void RootWindowViews::CreateExtensionWindow(
284     CefRefPtr<CefExtension> extension,
285     const CefRect& source_bounds,
286     CefRefPtr<CefWindow> parent_window,
287     const base::Closure& close_callback) {
288   if (!CURRENTLY_ON_MAIN_THREAD()) {
289     // Execute this method on the main thread.
290     MAIN_POST_CLOSURE(base::Bind(&RootWindowViews::CreateExtensionWindow, this,
291                                  extension, source_bounds, parent_window,
292                                  close_callback));
293     return;
294   }
295 
296   delegate_->CreateExtensionWindow(extension, source_bounds, parent_window,
297                                    close_callback, false);
298 }
299 
OnTest(int test_id)300 void RootWindowViews::OnTest(int test_id) {
301   if (!CURRENTLY_ON_MAIN_THREAD()) {
302     // Execute this method on the main thread.
303     MAIN_POST_CLOSURE(base::Bind(&RootWindowViews::OnTest, this, test_id));
304     return;
305   }
306 
307   delegate_->OnTest(this, test_id);
308 }
309 
OnExit()310 void RootWindowViews::OnExit() {
311   if (!CURRENTLY_ON_MAIN_THREAD()) {
312     // Execute this method on the main thread.
313     MAIN_POST_CLOSURE(base::Bind(&RootWindowViews::OnExit, this));
314     return;
315   }
316 
317   delegate_->OnExit(this);
318 }
319 
OnBrowserCreated(CefRefPtr<CefBrowser> browser)320 void RootWindowViews::OnBrowserCreated(CefRefPtr<CefBrowser> browser) {
321   REQUIRE_MAIN_THREAD();
322   DCHECK(!browser_);
323   browser_ = browser;
324   delegate_->OnBrowserCreated(this, browser);
325 }
326 
OnBrowserClosing(CefRefPtr<CefBrowser> browser)327 void RootWindowViews::OnBrowserClosing(CefRefPtr<CefBrowser> browser) {
328   REQUIRE_MAIN_THREAD();
329   // Nothing to do here.
330 }
331 
OnBrowserClosed(CefRefPtr<CefBrowser> browser)332 void RootWindowViews::OnBrowserClosed(CefRefPtr<CefBrowser> browser) {
333   REQUIRE_MAIN_THREAD();
334   if (browser_) {
335     DCHECK_EQ(browser->GetIdentifier(), browser_->GetIdentifier());
336     browser_ = nullptr;
337   }
338 
339   client_handler_->DetachDelegate();
340   client_handler_ = nullptr;
341 
342   browser_destroyed_ = true;
343   NotifyDestroyedIfDone();
344 }
345 
OnSetAddress(const std::string & url)346 void RootWindowViews::OnSetAddress(const std::string& url) {
347   if (!CefCurrentlyOn(TID_UI)) {
348     // Execute this method on the UI thread.
349     CefPostTask(TID_UI, base::Bind(&RootWindowViews::OnSetAddress, this, url));
350     return;
351   }
352 
353   if (window_ && with_controls_)
354     window_->SetAddress(url);
355 }
356 
OnSetTitle(const std::string & title)357 void RootWindowViews::OnSetTitle(const std::string& title) {
358   if (!CefCurrentlyOn(TID_UI)) {
359     // Execute this method on the UI thread.
360     CefPostTask(TID_UI, base::Bind(&RootWindowViews::OnSetTitle, this, title));
361     return;
362   }
363 
364   if (window_)
365     window_->SetTitle(title);
366 }
367 
OnSetFavicon(CefRefPtr<CefImage> image)368 void RootWindowViews::OnSetFavicon(CefRefPtr<CefImage> image) {
369   if (!CefCurrentlyOn(TID_UI)) {
370     // Execute this method on the UI thread.
371     CefPostTask(TID_UI,
372                 base::Bind(&RootWindowViews::OnSetFavicon, this, image));
373     return;
374   }
375 
376   if (window_)
377     window_->SetFavicon(image);
378 }
379 
OnSetFullscreen(bool fullscreen)380 void RootWindowViews::OnSetFullscreen(bool fullscreen) {
381   if (!CefCurrentlyOn(TID_UI)) {
382     // Execute this method on the UI thread.
383     CefPostTask(TID_UI, base::Bind(&RootWindowViews::OnSetFullscreen, this,
384                                    fullscreen));
385     return;
386   }
387 
388   if (window_)
389     window_->SetFullscreen(fullscreen);
390 }
391 
OnAutoResize(const CefSize & new_size)392 void RootWindowViews::OnAutoResize(const CefSize& new_size) {
393   if (!CefCurrentlyOn(TID_UI)) {
394     // Execute this method on the UI thread.
395     CefPostTask(TID_UI,
396                 base::Bind(&RootWindowViews::OnAutoResize, this, new_size));
397     return;
398   }
399 
400   bool has_position = false;
401   CefPoint position;
402   if (position_on_resize_) {
403     // Position the window centered on and immediately below the source.
404     const int x_offset = (initial_bounds_.width - new_size.width) / 2;
405     position.Set(initial_bounds_.x + x_offset,
406                  initial_bounds_.y + initial_bounds_.height);
407     has_position = true;
408 
409     // Don't change the window position on future resizes.
410     position_on_resize_ = false;
411   }
412 
413   if (window_) {
414     window_->SetBrowserSize(new_size, has_position, position);
415     window_->Show();
416   }
417 }
418 
OnSetLoadingState(bool isLoading,bool canGoBack,bool canGoForward)419 void RootWindowViews::OnSetLoadingState(bool isLoading,
420                                         bool canGoBack,
421                                         bool canGoForward) {
422   if (!CefCurrentlyOn(TID_UI)) {
423     // Execute this method on the UI thread.
424     CefPostTask(TID_UI, base::Bind(&RootWindowViews::OnSetLoadingState, this,
425                                    isLoading, canGoBack, canGoForward));
426     return;
427   }
428 
429   if (window_) {
430     if (with_controls_)
431       window_->SetLoadingState(isLoading, canGoBack, canGoForward);
432 
433     if (isLoading) {
434       // Reset to the default window icon when loading begins.
435       window_->SetFavicon(
436           delegate_->GetImageCache()->GetCachedImage("window_icon"));
437     }
438   }
439 }
440 
OnSetDraggableRegions(const std::vector<CefDraggableRegion> & regions)441 void RootWindowViews::OnSetDraggableRegions(
442     const std::vector<CefDraggableRegion>& regions) {
443   if (!CefCurrentlyOn(TID_UI)) {
444     // Execute this method on the UI thread.
445     CefPostTask(TID_UI, base::Bind(&RootWindowViews::OnSetDraggableRegions,
446                                    this, regions));
447     return;
448   }
449 
450   if (window_)
451     window_->SetDraggableRegions(regions);
452 }
453 
OnTakeFocus(bool next)454 void RootWindowViews::OnTakeFocus(bool next) {
455   if (!CefCurrentlyOn(TID_UI)) {
456     // Execute this method on the UI thread.
457     CefPostTask(TID_UI, base::Bind(&RootWindowViews::OnTakeFocus, this, next));
458     return;
459   }
460 
461   if (window_)
462     window_->TakeFocus(next);
463 }
464 
OnBeforeContextMenu(CefRefPtr<CefMenuModel> model)465 void RootWindowViews::OnBeforeContextMenu(CefRefPtr<CefMenuModel> model) {
466   CEF_REQUIRE_UI_THREAD();
467   if (window_)
468     window_->OnBeforeContextMenu(model);
469 }
470 
CreateClientHandler(const std::string & url)471 void RootWindowViews::CreateClientHandler(const std::string& url) {
472   DCHECK(!client_handler_);
473 
474   client_handler_ = new ClientHandlerStd(this, url);
475   client_handler_->set_download_favicon_images(true);
476 }
477 
InitOnUIThread(const CefBrowserSettings & settings,const std::string & startup_url,CefRefPtr<CefRequestContext> request_context)478 void RootWindowViews::InitOnUIThread(
479     const CefBrowserSettings& settings,
480     const std::string& startup_url,
481     CefRefPtr<CefRequestContext> request_context) {
482   if (!CefCurrentlyOn(TID_UI)) {
483     // Execute this method on the UI thread.
484     CefPostTask(TID_UI, base::Bind(&RootWindowViews::InitOnUIThread, this,
485                                    settings, startup_url, request_context));
486     return;
487   }
488 
489   image_cache_ = delegate_->GetImageCache();
490 
491   // Populate the default image cache.
492   ImageCache::ImageInfoSet image_set;
493   for (size_t i = 0U; i < arraysize(kDefaultImageCache); ++i)
494     image_set.push_back(ImageCache::ImageInfo::Create2x(kDefaultImageCache[i]));
495 
496   image_cache_->LoadImages(
497       image_set, base::Bind(&RootWindowViews::CreateViewsWindow, this, settings,
498                             startup_url, request_context));
499 }
500 
CreateViewsWindow(const CefBrowserSettings & settings,const std::string & startup_url,CefRefPtr<CefRequestContext> request_context,const ImageCache::ImageSet & images)501 void RootWindowViews::CreateViewsWindow(
502     const CefBrowserSettings& settings,
503     const std::string& startup_url,
504     CefRefPtr<CefRequestContext> request_context,
505     const ImageCache::ImageSet& images) {
506   CEF_REQUIRE_UI_THREAD();
507   DCHECK(!window_);
508 
509 #ifndef NDEBUG
510   // Make sure the default images loaded successfully.
511   DCHECK_EQ(images.size(), arraysize(kDefaultImageCache));
512   for (size_t i = 0U; i < arraysize(kDefaultImageCache); ++i) {
513     DCHECK(images[i]) << "Default image " << i << " failed to load";
514   }
515 #endif
516 
517   // Create the ViewsWindow. It will show itself after creation.
518   ViewsWindow::Create(this, client_handler_, startup_url, settings,
519                       request_context);
520 }
521 
NotifyViewsWindowDestroyed()522 void RootWindowViews::NotifyViewsWindowDestroyed() {
523   REQUIRE_MAIN_THREAD();
524   window_destroyed_ = true;
525   NotifyDestroyedIfDone();
526 }
527 
NotifyViewsWindowActivated()528 void RootWindowViews::NotifyViewsWindowActivated() {
529   REQUIRE_MAIN_THREAD();
530   delegate_->OnRootWindowActivated(this);
531 }
532 
NotifyDestroyedIfDone()533 void RootWindowViews::NotifyDestroyedIfDone() {
534   // Notify once both the window and the browser have been destroyed.
535   if (window_destroyed_ && browser_destroyed_) {
536     delegate_->OnRootWindowDestroyed(this);
537     if (!close_callback_.is_null())
538       close_callback_.Run();
539   }
540 }
541 
542 }  // namespace client
543