OLD | NEW |
| (Empty) |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "athena/content/web_activity.h" | |
6 | |
7 #include "athena/activity/public/activity_factory.h" | |
8 #include "athena/activity/public/activity_manager.h" | |
9 #include "athena/activity/public/activity_view.h" | |
10 #include "athena/content/content_proxy.h" | |
11 #include "athena/content/media_utils.h" | |
12 #include "athena/content/public/dialogs.h" | |
13 #include "athena/content/web_activity_helpers.h" | |
14 #include "athena/input/public/accelerator_manager.h" | |
15 #include "athena/strings/grit/athena_strings.h" | |
16 #include "base/bind.h" | |
17 #include "base/command_line.h" | |
18 #include "base/strings/utf_string_conversions.h" | |
19 #include "components/app_modal/javascript_dialog_manager.h" | |
20 #include "components/favicon_base/select_favicon_frames.h" | |
21 #include "content/public/browser/navigation_controller.h" | |
22 #include "content/public/browser/web_contents.h" | |
23 #include "content/public/browser/web_contents_delegate.h" | |
24 #include "content/public/common/content_switches.h" | |
25 #include "content/public/common/favicon_url.h" | |
26 #include "ui/aura/window.h" | |
27 #include "ui/base/l10n/l10n_util.h" | |
28 #include "ui/compositor/closure_animation_observer.h" | |
29 #include "ui/compositor/scoped_layer_animation_settings.h" | |
30 #include "ui/content_accelerators/accelerator_util.h" | |
31 #include "ui/views/background.h" | |
32 #include "ui/views/controls/label.h" | |
33 #include "ui/views/controls/webview/unhandled_keyboard_event_handler.h" | |
34 #include "ui/views/controls/webview/webview.h" | |
35 #include "ui/views/focus/focus_manager.h" | |
36 #include "ui/views/widget/widget.h" | |
37 | |
38 namespace athena { | |
39 namespace { | |
40 | |
41 class WebActivityController : public AcceleratorHandler { | |
42 public: | |
43 enum Command { | |
44 CMD_BACK, | |
45 CMD_FORWARD, | |
46 CMD_RELOAD, | |
47 CMD_RELOAD_IGNORE_CACHE, | |
48 CMD_CLOSE, | |
49 CMD_STOP, | |
50 }; | |
51 | |
52 explicit WebActivityController(WebActivity* owner_activity, | |
53 views::WebView* web_view) | |
54 : owner_activity_(owner_activity), | |
55 web_view_(web_view), | |
56 reserved_accelerator_enabled_(true) {} | |
57 ~WebActivityController() override {} | |
58 | |
59 // Installs accelerators for web activity. | |
60 void InstallAccelerators() { | |
61 accelerator_manager_ = AcceleratorManager::CreateForFocusManager( | |
62 web_view_->GetFocusManager()).Pass(); | |
63 const AcceleratorData accelerator_data[] = { | |
64 {TRIGGER_ON_PRESS, ui::VKEY_R, ui::EF_CONTROL_DOWN, CMD_RELOAD, | |
65 AF_NONE}, | |
66 {TRIGGER_ON_PRESS, ui::VKEY_BROWSER_REFRESH, ui::EF_NONE, CMD_RELOAD, | |
67 AF_NONE}, | |
68 {TRIGGER_ON_PRESS, ui::VKEY_BROWSER_REFRESH, ui::EF_CONTROL_DOWN, | |
69 CMD_RELOAD_IGNORE_CACHE, AF_NONE}, | |
70 {TRIGGER_ON_PRESS, ui::VKEY_BROWSER_FORWARD, ui::EF_NONE, CMD_FORWARD, | |
71 AF_NONE}, | |
72 {TRIGGER_ON_PRESS, ui::VKEY_BROWSER_BACK, ui::EF_NONE, CMD_BACK, | |
73 AF_NONE}, | |
74 {TRIGGER_ON_PRESS, ui::VKEY_W, ui::EF_CONTROL_DOWN, CMD_CLOSE, AF_NONE}, | |
75 {TRIGGER_ON_PRESS, ui::VKEY_ESCAPE, ui::EF_NONE, CMD_STOP, AF_NONE}, | |
76 }; | |
77 accelerator_manager_->RegisterAccelerators( | |
78 accelerator_data, arraysize(accelerator_data), this); | |
79 } | |
80 | |
81 // Methods that are called before and after key events are consumed by the web | |
82 // contents. | |
83 // See the documentation in WebContentsDelegate: for more details. | |
84 bool PreHandleKeyboardEvent(content::WebContents* source, | |
85 const content::NativeWebKeyboardEvent& event, | |
86 bool* is_keyboard_shortcut) { | |
87 ui::Accelerator accelerator = | |
88 ui::GetAcceleratorFromNativeWebKeyboardEvent(event); | |
89 | |
90 if (reserved_accelerator_enabled_ && | |
91 accelerator_manager_->IsRegistered(accelerator, AF_RESERVED)) { | |
92 return web_view_->GetFocusManager()->ProcessAccelerator(accelerator); | |
93 } | |
94 *is_keyboard_shortcut = | |
95 accelerator_manager_->IsRegistered(accelerator, AF_NONE); | |
96 return false; | |
97 } | |
98 | |
99 void HandleKeyboardEvent(content::WebContents* source, | |
100 const content::NativeWebKeyboardEvent& event) { | |
101 unhandled_keyboard_event_handler_.HandleKeyboardEvent( | |
102 event, web_view_->GetFocusManager()); | |
103 } | |
104 | |
105 private: | |
106 // AcceleratorHandler: | |
107 bool IsCommandEnabled(int command_id) const override { | |
108 switch (command_id) { | |
109 case CMD_RELOAD: | |
110 case CMD_RELOAD_IGNORE_CACHE: | |
111 return true; | |
112 case CMD_BACK: | |
113 return web_view_->GetWebContents()->GetController().CanGoBack(); | |
114 case CMD_FORWARD: | |
115 return web_view_->GetWebContents()->GetController().CanGoForward(); | |
116 case CMD_CLOSE: | |
117 // TODO(oshima): check onbeforeunload handler. | |
118 return true; | |
119 case CMD_STOP: | |
120 return web_view_->GetWebContents()->IsLoading(); | |
121 } | |
122 return false; | |
123 } | |
124 | |
125 bool OnAcceleratorFired(int command_id, | |
126 const ui::Accelerator& accelerator) override { | |
127 switch (command_id) { | |
128 case CMD_RELOAD: | |
129 web_view_->GetWebContents()->GetController().Reload(false); | |
130 return true; | |
131 case CMD_RELOAD_IGNORE_CACHE: | |
132 web_view_->GetWebContents()->GetController().ReloadIgnoringCache(false); | |
133 return true; | |
134 case CMD_BACK: | |
135 web_view_->GetWebContents()->GetController().GoBack(); | |
136 return true; | |
137 case CMD_FORWARD: | |
138 web_view_->GetWebContents()->GetController().GoForward(); | |
139 return true; | |
140 case CMD_CLOSE: | |
141 Activity::Delete(owner_activity_); | |
142 return true; | |
143 case CMD_STOP: | |
144 web_view_->GetWebContents()->Stop(); | |
145 return true; | |
146 } | |
147 return false; | |
148 } | |
149 | |
150 Activity* const owner_activity_; | |
151 views::WebView* web_view_; | |
152 bool reserved_accelerator_enabled_; | |
153 scoped_ptr<AcceleratorManager> accelerator_manager_; | |
154 views::UnhandledKeyboardEventHandler unhandled_keyboard_event_handler_; | |
155 | |
156 DISALLOW_COPY_AND_ASSIGN(WebActivityController); | |
157 }; | |
158 | |
159 const SkColor kDefaultTitleColor = SkColorSetRGB(0xf2, 0xf2, 0xf2); | |
160 const int kIconSize = 32; | |
161 const float kDistanceShowReloadMessage = 100; | |
162 const float kDistanceReload = 150; | |
163 | |
164 } // namespace | |
165 | |
166 // A web view for athena's web activity. Note that AthenaWebView will create its | |
167 // own content so that it can eject and reload it. | |
168 class AthenaWebView : public views::WebView { | |
169 public: | |
170 explicit AthenaWebView(content::BrowserContext* context, | |
171 WebActivity* owner_activity) | |
172 : views::WebView(context), | |
173 controller_(new WebActivityController(owner_activity, this)), | |
174 owner_activity_(owner_activity), | |
175 fullscreen_(false), | |
176 overscroll_y_(0) { | |
177 SetEmbedFullscreenWidgetMode(true); | |
178 // TODO(skuhne): Add content observer to detect renderer crash and set | |
179 // content status to unloaded if that happens. | |
180 } | |
181 | |
182 AthenaWebView(content::WebContents* web_contents, | |
183 WebActivity* owner_activity) | |
184 : views::WebView(web_contents->GetBrowserContext()), | |
185 controller_(new WebActivityController(owner_activity, this)), | |
186 owner_activity_(owner_activity) { | |
187 scoped_ptr<content::WebContents> old_contents( | |
188 SwapWebContents(scoped_ptr<content::WebContents>(web_contents))); | |
189 } | |
190 | |
191 ~AthenaWebView() override {} | |
192 | |
193 void InstallAccelerators() { controller_->InstallAccelerators(); } | |
194 | |
195 void EvictContent() { | |
196 scoped_ptr<content::WebContents> old_contents(SwapWebContents( | |
197 scoped_ptr<content::WebContents>(content::WebContents::Create( | |
198 content::WebContents::CreateParams(browser_context()))))); | |
199 // If there is a progress bar, we need to get rid of it now since its | |
200 // associated content, parent window and layers will disappear with evicting | |
201 // the content. | |
202 progress_bar_.reset(); | |
203 evicted_web_contents_.reset( | |
204 content::WebContents::Create(content::WebContents::CreateParams( | |
205 old_contents->GetBrowserContext()))); | |
206 evicted_web_contents_->GetController().CopyStateFrom( | |
207 old_contents->GetController()); | |
208 // As soon as the new contents becomes visible, it should reload. | |
209 // TODO(skuhne): This breaks script connections with other activities. | |
210 // Even though this is the same technique as used by the TabStripModel, | |
211 // we might want to address this cleaner since we are more likely to | |
212 // run into this state. by unloading. | |
213 } | |
214 | |
215 void AttachHelpers() { | |
216 if (!IsContentEvicted()) | |
217 AttachWebActivityHelpers(GetWebContents()); | |
218 // Else: The helpers will be attached when the evicted content is reloaded. | |
219 } | |
220 | |
221 void ReloadEvictedContent() { | |
222 CHECK(evicted_web_contents_.get()); | |
223 | |
224 // Order is important. The helpers must be attached prior to the RenderView | |
225 // being created. | |
226 AttachWebActivityHelpers(evicted_web_contents_.get()); | |
227 | |
228 SwapWebContents(evicted_web_contents_.Pass()); | |
229 } | |
230 | |
231 // Check if the content got evicted. | |
232 const bool IsContentEvicted() { return !!evicted_web_contents_.get(); } | |
233 | |
234 // content::WebContentsDelegate: | |
235 content::WebContents* OpenURLFromTab( | |
236 content::WebContents* source, | |
237 const content::OpenURLParams& params) override { | |
238 switch(params.disposition) { | |
239 case CURRENT_TAB: { | |
240 DCHECK(source == web_contents()); | |
241 content::NavigationController::LoadURLParams load_url_params( | |
242 params.url); | |
243 load_url_params.referrer = params.referrer; | |
244 load_url_params.frame_tree_node_id = params.frame_tree_node_id; | |
245 load_url_params.transition_type = params.transition; | |
246 load_url_params.extra_headers = params.extra_headers; | |
247 load_url_params.should_replace_current_entry = | |
248 params.should_replace_current_entry; | |
249 load_url_params.is_renderer_initiated = params.is_renderer_initiated; | |
250 load_url_params.transferred_global_request_id = | |
251 params.transferred_global_request_id; | |
252 web_contents()->GetController().LoadURLWithParams(load_url_params); | |
253 return web_contents(); | |
254 } | |
255 case NEW_FOREGROUND_TAB: | |
256 case NEW_BACKGROUND_TAB: | |
257 case NEW_POPUP: | |
258 case NEW_WINDOW: { | |
259 Activity* activity = ActivityFactory::Get()->CreateWebActivity( | |
260 browser_context(), base::string16(), params.url); | |
261 Activity::Show(activity); | |
262 break; | |
263 } | |
264 default: | |
265 break; | |
266 } | |
267 // nullptr is returned if the URL wasn't opened immediately. | |
268 return nullptr; | |
269 } | |
270 | |
271 bool CanOverscrollContent() const override { | |
272 const std::string value = | |
273 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( | |
274 switches::kOverscrollHistoryNavigation); | |
275 return value != "0"; | |
276 } | |
277 | |
278 void OverscrollUpdate(float delta_y) override { | |
279 overscroll_y_ = delta_y; | |
280 if (overscroll_y_ > kDistanceShowReloadMessage) { | |
281 if (!reload_message_) | |
282 CreateReloadMessage(); | |
283 reload_message_->Show(); | |
284 float opacity = 1.0f; | |
285 if (overscroll_y_ < kDistanceReload) { | |
286 opacity = (overscroll_y_ - kDistanceShowReloadMessage) / | |
287 (kDistanceReload - kDistanceShowReloadMessage); | |
288 } | |
289 reload_message_->GetLayer()->SetOpacity(opacity); | |
290 } else if (reload_message_) { | |
291 reload_message_->Hide(); | |
292 } | |
293 } | |
294 | |
295 void OverscrollComplete() override { | |
296 if (overscroll_y_ >= kDistanceReload) | |
297 GetWebContents()->GetController().Reload(false); | |
298 if (reload_message_) | |
299 reload_message_->Hide(); | |
300 overscroll_y_ = 0; | |
301 } | |
302 | |
303 void AddNewContents(content::WebContents* source, | |
304 content::WebContents* new_contents, | |
305 WindowOpenDisposition disposition, | |
306 const gfx::Rect& initial_pos, | |
307 bool user_gesture, | |
308 bool* was_blocked) override { | |
309 Activity* activity = | |
310 ActivityFactory::Get()->CreateWebActivity(new_contents); | |
311 Activity::Show(activity); | |
312 } | |
313 | |
314 bool PreHandleKeyboardEvent(content::WebContents* source, | |
315 const content::NativeWebKeyboardEvent& event, | |
316 bool* is_keyboard_shortcut) override { | |
317 return controller_->PreHandleKeyboardEvent( | |
318 source, event, is_keyboard_shortcut); | |
319 } | |
320 | |
321 void HandleKeyboardEvent( | |
322 content::WebContents* source, | |
323 const content::NativeWebKeyboardEvent& event) override { | |
324 controller_->HandleKeyboardEvent(source, event); | |
325 } | |
326 | |
327 void ToggleFullscreenModeForTab(content::WebContents* web_contents, | |
328 bool enter_fullscreen) override { | |
329 fullscreen_ = enter_fullscreen; | |
330 GetWidget()->SetFullscreen(fullscreen_); | |
331 } | |
332 | |
333 bool IsFullscreenForTabOrPending( | |
334 const content::WebContents* web_contents) const override { | |
335 return fullscreen_; | |
336 } | |
337 | |
338 void LoadingStateChanged(content::WebContents* source, | |
339 bool to_different_document) override { | |
340 bool has_stopped = source == nullptr || !source->IsLoading(); | |
341 LoadProgressChanged(source, has_stopped ? 1 : 0); | |
342 } | |
343 | |
344 void LoadProgressChanged(content::WebContents* source, | |
345 double progress) override { | |
346 if (!progress) | |
347 return; | |
348 | |
349 if (!progress_bar_) { | |
350 CreateProgressBar(); | |
351 source->GetNativeView()->layer()->Add(progress_bar_.get()); | |
352 } | |
353 progress_bar_->SetBounds(gfx::Rect( | |
354 0, 0, progress * progress_bar_->parent()->bounds().width(), 3)); | |
355 if (progress < 1) | |
356 return; | |
357 | |
358 ui::ScopedLayerAnimationSettings settings(progress_bar_->GetAnimator()); | |
359 settings.SetTweenType(gfx::Tween::EASE_IN); | |
360 ui::Layer* layer = progress_bar_.get(); | |
361 settings.AddObserver(new ui::ClosureAnimationObserver( | |
362 base::Bind(&base::DeletePointer<ui::Layer>, progress_bar_.release()))); | |
363 layer->SetOpacity(0.f); | |
364 } | |
365 | |
366 content::JavaScriptDialogManager* GetJavaScriptDialogManager( | |
367 content::WebContents* contents) override { | |
368 return app_modal::JavaScriptDialogManager::GetInstance(); | |
369 } | |
370 | |
371 content::ColorChooser* OpenColorChooser( | |
372 content::WebContents* web_contents, | |
373 SkColor color, | |
374 const std::vector<content::ColorSuggestion>& suggestions) override { | |
375 return athena::OpenColorChooser(web_contents, color, suggestions); | |
376 } | |
377 | |
378 // Called when a file selection is to be done. | |
379 void RunFileChooser(content::WebContents* web_contents, | |
380 const content::FileChooserParams& params) override { | |
381 return athena::OpenFileChooser(web_contents, params); | |
382 } | |
383 | |
384 void CloseContents(content::WebContents* contents) override { | |
385 Activity::Delete(owner_activity_); | |
386 } | |
387 | |
388 private: | |
389 void CreateProgressBar() { | |
390 CHECK(!progress_bar_); | |
391 progress_bar_.reset(new ui::Layer(ui::LAYER_SOLID_COLOR)); | |
392 progress_bar_->SetColor(SkColorSetRGB(0x17, 0x59, 0xcd)); | |
393 } | |
394 | |
395 void CreateReloadMessage() { | |
396 CHECK(!reload_message_); | |
397 reload_message_.reset(new views::Widget); | |
398 views::Widget::InitParams params(views::Widget::InitParams::TYPE_CONTROL); | |
399 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; | |
400 params.parent = GetWidget()->GetNativeView(); | |
401 reload_message_->Init(params); | |
402 | |
403 views::Label* label = new views::Label( | |
404 l10n_util::GetStringUTF16(IDS_ATHENA_PULL_TO_RELOAD_MESSAGE)); | |
405 label->SetBackgroundColor(SK_ColorGRAY); | |
406 label->set_background( | |
407 views::Background::CreateSolidBackground(SK_ColorGRAY)); | |
408 | |
409 reload_message_->SetContentsView(label); | |
410 reload_message_->SetBounds(ConvertRectToWidget( | |
411 gfx::Rect(0, 0, width(), label->GetPreferredSize().height()))); | |
412 } | |
413 | |
414 scoped_ptr<WebActivityController> controller_; | |
415 | |
416 Activity* const owner_activity_; | |
417 | |
418 // If the activity got evicted, this is the web content which holds the known | |
419 // state of the content before eviction. | |
420 scoped_ptr<content::WebContents> evicted_web_contents_; | |
421 | |
422 scoped_ptr<ui::Layer> progress_bar_; | |
423 | |
424 scoped_ptr<views::Widget> reload_message_; | |
425 | |
426 // TODO(oshima): Find out if we should support window fullscreen. | |
427 // It may still useful when a user is in split mode. | |
428 bool fullscreen_; | |
429 | |
430 // The distance that the user has overscrolled vertically. | |
431 float overscroll_y_; | |
432 | |
433 DISALLOW_COPY_AND_ASSIGN(AthenaWebView); | |
434 }; | |
435 | |
436 WebActivity::WebActivity(content::BrowserContext* browser_context, | |
437 const base::string16& title, | |
438 const GURL& url) | |
439 : browser_context_(browser_context), | |
440 web_view_(new AthenaWebView(browser_context, this)), | |
441 title_(title), | |
442 title_color_(kDefaultTitleColor), | |
443 current_state_(ACTIVITY_UNLOADED), | |
444 activity_view_(nullptr), | |
445 weak_ptr_factory_(this) { | |
446 // Order is important. The web activity helpers must be attached prior to the | |
447 // RenderView being created. | |
448 SetCurrentState(ACTIVITY_INVISIBLE); | |
449 web_view_->LoadInitialURL(url); | |
450 } | |
451 | |
452 WebActivity::WebActivity(content::WebContents* contents) | |
453 : browser_context_(contents->GetBrowserContext()), | |
454 web_view_(new AthenaWebView(contents, this)), | |
455 title_color_(kDefaultTitleColor), | |
456 current_state_(ACTIVITY_UNLOADED), | |
457 activity_view_(nullptr), | |
458 weak_ptr_factory_(this) { | |
459 // If the activity was created as a result of | |
460 // WebContentsDelegate::AddNewContents(), web activity helpers may not be | |
461 // created prior to the RenderView being created. Desktop Chrome has a | |
462 // similar problem. | |
463 SetCurrentState(ACTIVITY_INVISIBLE); | |
464 } | |
465 | |
466 WebActivity::~WebActivity() { | |
467 // It is not required to change the activity state to UNLOADED - unless we | |
468 // would add state observers. | |
469 } | |
470 | |
471 ActivityViewModel* WebActivity::GetActivityViewModel() { | |
472 return this; | |
473 } | |
474 | |
475 void WebActivity::SetCurrentState(Activity::ActivityState state) { | |
476 DCHECK_NE(state, current_state_); | |
477 if (current_state_ == ACTIVITY_UNLOADED) { | |
478 web_view_->AttachHelpers(); | |
479 if (web_view_->IsContentEvicted()) | |
480 web_view_->ReloadEvictedContent(); | |
481 Observe(web_view_->GetWebContents()); | |
482 } | |
483 | |
484 switch (state) { | |
485 case ACTIVITY_VISIBLE: | |
486 HideContentProxy(); | |
487 break; | |
488 case ACTIVITY_INVISIBLE: | |
489 if (current_state_ == ACTIVITY_VISIBLE) | |
490 ShowContentProxy(); | |
491 | |
492 break; | |
493 case ACTIVITY_BACKGROUND_LOW_PRIORITY: | |
494 DCHECK(ACTIVITY_VISIBLE == current_state_ || | |
495 ACTIVITY_INVISIBLE == current_state_); | |
496 // TODO(skuhne): Do this. | |
497 break; | |
498 case ACTIVITY_PERSISTENT: | |
499 DCHECK_EQ(ACTIVITY_BACKGROUND_LOW_PRIORITY, current_state_); | |
500 // TODO(skuhne): Do this. As soon as the new resource management is | |
501 // agreed upon - or remove otherwise. | |
502 break; | |
503 case ACTIVITY_UNLOADED: | |
504 DCHECK_NE(ACTIVITY_UNLOADED, current_state_); | |
505 if (content_proxy_) | |
506 content_proxy_->ContentWillUnload(); | |
507 Observe(nullptr); | |
508 web_view_->EvictContent(); | |
509 break; | |
510 } | |
511 // Remember the last requested state. | |
512 current_state_ = state; | |
513 } | |
514 | |
515 Activity::ActivityState WebActivity::GetCurrentState() { | |
516 // If the content is evicted, the state has to be UNLOADED. | |
517 DCHECK(!web_view_->IsContentEvicted() || | |
518 current_state_ == ACTIVITY_UNLOADED); | |
519 return current_state_; | |
520 } | |
521 | |
522 bool WebActivity::IsVisible() { | |
523 return web_view_->visible() && current_state_ != ACTIVITY_UNLOADED; | |
524 } | |
525 | |
526 Activity::ActivityMediaState WebActivity::GetMediaState() { | |
527 return current_state_ == ACTIVITY_UNLOADED ? | |
528 Activity::ACTIVITY_MEDIA_STATE_NONE : | |
529 GetActivityMediaState(GetWebContents()); | |
530 } | |
531 | |
532 aura::Window* WebActivity::GetWindow() { | |
533 return web_view_->GetWidget() ? web_view_->GetWidget()->GetNativeWindow() | |
534 : nullptr; | |
535 } | |
536 | |
537 content::WebContents* WebActivity::GetWebContents() { | |
538 return web_view_->GetWebContents(); | |
539 } | |
540 | |
541 void WebActivity::Init() { | |
542 web_view_->InstallAccelerators(); | |
543 } | |
544 | |
545 SkColor WebActivity::GetRepresentativeColor() const { | |
546 return title_color_; | |
547 } | |
548 | |
549 base::string16 WebActivity::GetTitle() const { | |
550 if (!title_.empty()) | |
551 return title_; | |
552 const base::string16& title = web_view_->GetWebContents()->GetTitle(); | |
553 if (!title.empty()) | |
554 return title; | |
555 return base::UTF8ToUTF16(web_view_->GetWebContents()->GetVisibleURL().host()); | |
556 } | |
557 | |
558 gfx::ImageSkia WebActivity::GetIcon() const { | |
559 return icon_; | |
560 } | |
561 | |
562 void WebActivity::SetActivityView(ActivityView* view) { | |
563 DCHECK(!activity_view_); | |
564 activity_view_ = view; | |
565 } | |
566 | |
567 bool WebActivity::UsesFrame() const { | |
568 return true; | |
569 } | |
570 | |
571 views::View* WebActivity::GetContentsView() { | |
572 return web_view_; | |
573 } | |
574 | |
575 gfx::ImageSkia WebActivity::GetOverviewModeImage() { | |
576 if (content_proxy_.get()) | |
577 return content_proxy_->GetContentImage(); | |
578 return gfx::ImageSkia(); | |
579 } | |
580 | |
581 void WebActivity::PrepareContentsForOverview() { | |
582 // Turn on fast resizing to avoid re-laying out the web contents when | |
583 // entering / exiting overview mode and the content is visible. | |
584 if (!content_proxy_.get()) | |
585 web_view_->SetFastResize(true); | |
586 } | |
587 | |
588 void WebActivity::ResetContentsView() { | |
589 // Turn on fast resizing to avoid re-laying out the web contents when | |
590 // entering / exiting overview mode and the content is visible. | |
591 if (!content_proxy_.get()) { | |
592 web_view_->SetFastResize(false); | |
593 web_view_->Layout(); | |
594 } | |
595 } | |
596 | |
597 void WebActivity::TitleWasSet(content::NavigationEntry* entry, | |
598 bool explicit_set) { | |
599 if (activity_view_) | |
600 activity_view_->UpdateTitle(); | |
601 } | |
602 | |
603 void WebActivity::DidNavigateMainFrame( | |
604 const content::LoadCommittedDetails& details, | |
605 const content::FrameNavigateParams& params) { | |
606 // Prevent old image requests from calling back to OnDidDownloadFavicon(). | |
607 weak_ptr_factory_.InvalidateWeakPtrs(); | |
608 | |
609 icon_ = gfx::ImageSkia(); | |
610 if (activity_view_) | |
611 activity_view_->UpdateIcon(); | |
612 } | |
613 | |
614 void WebActivity::DidUpdateFaviconURL( | |
615 const std::vector<content::FaviconURL>& candidates) { | |
616 // Pick an arbitrary favicon of type FAVICON to use. | |
617 // TODO(pkotwicz): Do something better once the favicon code is componentized. | |
618 // (crbug.com/401997) | |
619 weak_ptr_factory_.InvalidateWeakPtrs(); | |
620 for (size_t i = 0; i < candidates.size(); ++i) { | |
621 if (candidates[i].icon_type == content::FaviconURL::FAVICON) { | |
622 web_view_->GetWebContents()->DownloadImage( | |
623 candidates[i].icon_url, | |
624 true, | |
625 0, | |
626 base::Bind(&WebActivity::OnDidDownloadFavicon, | |
627 weak_ptr_factory_.GetWeakPtr())); | |
628 break; | |
629 } | |
630 } | |
631 } | |
632 | |
633 void WebActivity::OnDidDownloadFavicon( | |
634 int id, | |
635 int http_status_code, | |
636 const GURL& url, | |
637 const std::vector<SkBitmap>& bitmaps, | |
638 const std::vector<gfx::Size>& original_bitmap_sizes) { | |
639 icon_ = CreateFaviconImageSkia( | |
640 bitmaps, original_bitmap_sizes, kIconSize, nullptr); | |
641 if (activity_view_) | |
642 activity_view_->UpdateIcon(); | |
643 } | |
644 | |
645 void WebActivity::DidChangeThemeColor(SkColor theme_color) { | |
646 title_color_ = theme_color; | |
647 if (activity_view_) | |
648 activity_view_->UpdateRepresentativeColor(); | |
649 } | |
650 | |
651 void WebActivity::HideContentProxy() { | |
652 if (content_proxy_.get()) | |
653 content_proxy_.reset(nullptr); | |
654 } | |
655 | |
656 void WebActivity::ShowContentProxy() { | |
657 if (!content_proxy_.get()) | |
658 content_proxy_.reset(new ContentProxy(web_view_)); | |
659 } | |
660 | |
661 } // namespace athena | |
OLD | NEW |