- add sources.
[platform/framework/web/crosswalk.git] / src / ui / views / controls / webview / webview.cc
1 // Copyright (c) 2012 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 "ui/views/controls/webview/webview.h"
6
7 #include "content/public/browser/browser_accessibility_state.h"
8 #include "content/public/browser/browser_context.h"
9 #include "content/public/browser/navigation_controller.h"
10 #include "content/public/browser/render_view_host.h"
11 #include "content/public/browser/render_widget_host_view.h"
12 #include "content/public/browser/web_contents.h"
13 #include "content/public/browser/web_contents_view.h"
14 #include "ipc/ipc_message.h"
15 #include "ui/base/accessibility/accessibility_types.h"
16 #include "ui/base/accessibility/accessible_view_state.h"
17 #include "ui/events/event.h"
18 #include "ui/views/accessibility/native_view_accessibility.h"
19 #include "ui/views/controls/native/native_view_host.h"
20 #include "ui/views/focus/focus_manager.h"
21 #include "ui/views/views_delegate.h"
22
23 namespace views {
24
25 // static
26 const char WebView::kViewClassName[] = "WebView";
27
28 ////////////////////////////////////////////////////////////////////////////////
29 // WebView, public:
30
31 WebView::WebView(content::BrowserContext* browser_context)
32     : wcv_holder_(new NativeViewHost),
33       web_contents_(NULL),
34       embed_fullscreen_widget_mode_enabled_(false),
35       is_embedding_fullscreen_widget_(false),
36       browser_context_(browser_context),
37       allow_accelerators_(false) {
38   AddChildView(wcv_holder_);
39   NativeViewAccessibility::RegisterWebView(this);
40 }
41
42 WebView::~WebView() {
43   NativeViewAccessibility::UnregisterWebView(this);
44 }
45
46 content::WebContents* WebView::GetWebContents() {
47   CreateWebContentsWithSiteInstance(NULL);
48   return web_contents_;
49 }
50
51 void WebView::CreateWebContentsWithSiteInstance(
52     content::SiteInstance* site_instance) {
53   if (!web_contents_) {
54     wc_owner_.reset(CreateWebContents(browser_context_, site_instance));
55     web_contents_ = wc_owner_.get();
56     web_contents_->SetDelegate(this);
57     AttachWebContents();
58   }
59 }
60
61 void WebView::SetWebContents(content::WebContents* web_contents) {
62   if (web_contents == web_contents_)
63     return;
64   DetachWebContents();
65   if (wc_owner_ != web_contents)
66     wc_owner_.reset();
67   web_contents_ = web_contents;
68   if (embed_fullscreen_widget_mode_enabled_) {
69     is_embedding_fullscreen_widget_ =
70         web_contents_ && web_contents_->GetFullscreenRenderWidgetHostView();
71   } else {
72     is_embedding_fullscreen_widget_ = false;
73   }
74   AttachWebContents();
75 }
76
77 void WebView::SetEmbedFullscreenWidgetMode(bool enable) {
78   bool should_be_embedded = enable;
79   if (!embed_fullscreen_widget_mode_enabled_ && enable) {
80     DCHECK(!is_embedding_fullscreen_widget_);
81     embed_fullscreen_widget_mode_enabled_ = true;
82     should_be_embedded =
83         web_contents_ && web_contents_->GetFullscreenRenderWidgetHostView();
84   } else if (embed_fullscreen_widget_mode_enabled_ && !enable) {
85     embed_fullscreen_widget_mode_enabled_ = false;
86   }
87   if (should_be_embedded != is_embedding_fullscreen_widget_)
88     ReattachForFullscreenChange(should_be_embedded);
89 }
90
91 void WebView::LoadInitialURL(const GURL& url) {
92   GetWebContents()->GetController().LoadURL(
93       url, content::Referrer(), content::PAGE_TRANSITION_AUTO_TOPLEVEL,
94       std::string());
95 }
96
97 void WebView::SetFastResize(bool fast_resize) {
98   wcv_holder_->set_fast_resize(fast_resize);
99 }
100
101 void WebView::OnWebContentsFocused(content::WebContents* web_contents) {
102   FocusManager* focus_manager = GetFocusManager();
103   if (focus_manager)
104     focus_manager->SetFocusedView(this);
105 }
106
107 void WebView::SetPreferredSize(const gfx::Size& preferred_size) {
108   preferred_size_ = preferred_size;
109   PreferredSizeChanged();
110 }
111
112 ////////////////////////////////////////////////////////////////////////////////
113 // WebView, View overrides:
114
115 const char* WebView::GetClassName() const {
116   return kViewClassName;
117 }
118
119 void WebView::OnBoundsChanged(const gfx::Rect& previous_bounds) {
120   wcv_holder_->SetSize(bounds().size());
121 }
122
123 void WebView::ViewHierarchyChanged(
124     const ViewHierarchyChangedDetails& details) {
125   if (details.is_add)
126     AttachWebContents();
127 }
128
129 bool WebView::SkipDefaultKeyEventProcessing(const ui::KeyEvent& event) {
130   if (allow_accelerators_)
131     return FocusManager::IsTabTraversalKeyEvent(event);
132
133   // Don't look-up accelerators or tab-traversal if we are showing a non-crashed
134   // TabContents.
135   // We'll first give the page a chance to process the key events.  If it does
136   // not process them, they'll be returned to us and we'll treat them as
137   // accelerators then.
138   return web_contents_ && !web_contents_->IsCrashed();
139 }
140
141 bool WebView::IsFocusable() const {
142   // We need to be focusable when our contents is not a view hierarchy, as
143   // clicking on the contents needs to focus us.
144   return !!web_contents_;
145 }
146
147 void WebView::OnFocus() {
148   if (!web_contents_)
149     return;
150   if (is_embedding_fullscreen_widget_) {
151     content::RenderWidgetHostView* const current_fs_view =
152         web_contents_->GetFullscreenRenderWidgetHostView();
153     if (current_fs_view)
154       current_fs_view->Focus();
155   } else {
156     web_contents_->GetView()->Focus();
157   }
158 }
159
160 void WebView::AboutToRequestFocusFromTabTraversal(bool reverse) {
161   if (web_contents_)
162     web_contents_->FocusThroughTabTraversal(reverse);
163 }
164
165 void WebView::GetAccessibleState(ui::AccessibleViewState* state) {
166   state->role = ui::AccessibilityTypes::ROLE_GROUPING;
167 }
168
169 gfx::NativeViewAccessible WebView::GetNativeViewAccessible() {
170   if (web_contents_) {
171     content::RenderWidgetHostView* host_view =
172         web_contents_->GetRenderWidgetHostView();
173     if (host_view)
174       return host_view->GetNativeViewAccessible();
175   }
176   return View::GetNativeViewAccessible();
177 }
178
179 gfx::Size WebView::GetPreferredSize() {
180   if (preferred_size_ == gfx::Size())
181     return View::GetPreferredSize();
182   else
183     return preferred_size_;
184 }
185
186 ////////////////////////////////////////////////////////////////////////////////
187 // WebView, content::WebContentsDelegate implementation:
188
189 void WebView::WebContentsFocused(content::WebContents* web_contents) {
190   DCHECK(wc_owner_.get());
191   // The WebView is only the delegate of WebContentses it creates itself.
192   OnWebContentsFocused(web_contents_);
193 }
194
195 bool WebView::EmbedsFullscreenWidget() const {
196   DCHECK(wc_owner_.get());
197   return embed_fullscreen_widget_mode_enabled_;
198 }
199
200 ////////////////////////////////////////////////////////////////////////////////
201 // WebView, content::WebContentsObserver implementation:
202
203 void WebView::RenderViewHostChanged(content::RenderViewHost* old_host,
204                                     content::RenderViewHost* new_host) {
205   FocusManager* const focus_manager = GetFocusManager();
206   if (focus_manager && focus_manager->GetFocusedView() == this)
207     OnFocus();
208 }
209
210 void WebView::WebContentsDestroyed(content::WebContents* web_contents) {
211   // We watch for destruction of WebContents that we host but do not own. If we
212   // own a WebContents that is being destroyed, we're doing the destroying, so
213   // we don't want to recursively tear it down while it's being torn down.
214   if (!wc_owner_.get())
215     SetWebContents(NULL);
216 }
217
218 void WebView::DidShowFullscreenWidget(int routing_id) {
219   if (embed_fullscreen_widget_mode_enabled_)
220     ReattachForFullscreenChange(true);
221 }
222
223 void WebView::DidDestroyFullscreenWidget(int routing_id) {
224   if (embed_fullscreen_widget_mode_enabled_)
225     ReattachForFullscreenChange(false);
226 }
227
228 ////////////////////////////////////////////////////////////////////////////////
229 // WebView, private:
230
231 void WebView::AttachWebContents() {
232   // Prevents attachment if the WebView isn't already in a Widget, or it's
233   // already attached.
234   if (!GetWidget() || !web_contents_)
235     return;
236
237   const gfx::NativeView view_to_attach = is_embedding_fullscreen_widget_ ?
238       web_contents_->GetFullscreenRenderWidgetHostView()->GetNativeView() :
239       web_contents_->GetView()->GetNativeView();
240   if (wcv_holder_->native_view() == view_to_attach)
241     return;
242   wcv_holder_->Attach(view_to_attach);
243
244   // The view will not be focused automatically when it is attached, so we need
245   // to pass on focus to it if the FocusManager thinks the view is focused. Note
246   // that not every Widget has a focus manager.
247   FocusManager* const focus_manager = GetFocusManager();
248   if (focus_manager && focus_manager->GetFocusedView() == this)
249     OnFocus();
250
251   WebContentsObserver::Observe(web_contents_);
252
253 #if defined(OS_WIN) && defined(USE_AURA)
254   if (!is_embedding_fullscreen_widget_) {
255     web_contents_->SetParentNativeViewAccessible(
256         parent()->GetNativeViewAccessible());
257   }
258 #endif
259 }
260
261 void WebView::DetachWebContents() {
262   if (web_contents_) {
263     wcv_holder_->Detach();
264 #if defined(OS_WIN)
265     if (!is_embedding_fullscreen_widget_) {
266 #if !defined(USE_AURA)
267       // TODO(beng): This should either not be necessary, or be done implicitly
268       // by NativeViewHostWin on Detach(). As it stands, this is needed so that
269       // the of the detached contents knows to tell the renderer it's been
270       // hidden.
271       //
272       // Moving this out of here would also mean we wouldn't be potentially
273       // calling member functions on a half-destroyed WebContents.
274       ShowWindow(web_contents_->GetView()->GetNativeView(), SW_HIDE);
275 #else
276       web_contents_->SetParentNativeViewAccessible(NULL);
277 #endif
278     }
279 #endif
280   }
281   WebContentsObserver::Observe(NULL);
282 }
283
284 void WebView::ReattachForFullscreenChange(bool enter_fullscreen) {
285   DetachWebContents();
286   is_embedding_fullscreen_widget_ = enter_fullscreen &&
287       web_contents_ && web_contents_->GetFullscreenRenderWidgetHostView();
288   AttachWebContents();
289 }
290
291 content::WebContents* WebView::CreateWebContents(
292       content::BrowserContext* browser_context,
293       content::SiteInstance* site_instance) {
294   content::WebContents* contents = NULL;
295   if (ViewsDelegate::views_delegate) {
296     contents = ViewsDelegate::views_delegate->CreateWebContents(
297         browser_context, site_instance);
298   }
299
300   if (!contents) {
301     content::WebContents::CreateParams create_params(
302         browser_context, site_instance);
303     return content::WebContents::Create(create_params);
304   }
305
306   return contents;
307 }
308
309 }  // namespace views