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