- add third_party src.
[platform/framework/web/crosswalk.git] / src / xwalk / runtime / browser / runtime.cc
1 // Copyright (c) 2013 Intel Corporation. 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 "xwalk/runtime/browser/runtime.h"
6
7 #include <string>
8 #include <utility>
9
10 #include "base/command_line.h"
11 #include "base/message_loop/message_loop.h"
12 #include "xwalk/runtime/browser/image_util.h"
13 #include "xwalk/runtime/browser/media/media_capture_devices_dispatcher.h"
14 #include "xwalk/runtime/browser/runtime_context.h"
15 #include "xwalk/runtime/browser/runtime_file_select_helper.h"
16 #include "xwalk/runtime/browser/ui/color_chooser.h"
17 #include "xwalk/runtime/browser/xwalk_runner.h"
18 #include "xwalk/runtime/common/xwalk_notification_types.h"
19 #include "xwalk/runtime/common/xwalk_switches.h"
20 #include "content/public/browser/navigation_entry.h"
21 #include "content/public/browser/notification_details.h"
22 #include "content/public/browser/notification_service.h"
23 #include "content/public/browser/notification_source.h"
24 #include "content/public/browser/notification_types.h"
25 #include "content/public/browser/render_view_host.h"
26 #include "content/public/browser/web_contents_view.h"
27 #include "content/public/browser/render_process_host.h"
28 #include "grit/xwalk_resources.h"
29 #include "ui/base/resource/resource_bundle.h"
30 #include "ui/gfx/image/image_skia.h"
31
32 using content::FaviconURL;
33 using content::WebContents;
34
35 namespace xwalk {
36
37 namespace {
38
39 // The default size for web content area size.
40 const int kDefaultWidth = 840;
41 const int kDefaultHeight = 600;
42
43 static Runtime::Observer* g_observer_for_testing;
44
45 }  // namespace
46
47 // static
48 Runtime* Runtime::Create(
49         RuntimeContext* runtime_context, const GURL& url, Observer* observer) {
50   WebContents::CreateParams params(runtime_context, NULL);
51   params.routing_id = MSG_ROUTING_NONE;
52   WebContents* web_contents = WebContents::Create(params);
53
54   Runtime* runtime = new Runtime(web_contents, observer);
55   runtime->LoadURL(url);
56   return runtime;
57 }
58
59 // static
60 Runtime* Runtime::CreateWithDefaultWindow(
61     RuntimeContext* runtime_context, const GURL& url, Observer* observer) {
62   Runtime* runtime = Runtime::Create(runtime_context, url, observer);
63   runtime->AttachDefaultWindow();
64   return runtime;
65 }
66
67 // static
68 Runtime* Runtime::Create(
69     RuntimeContext* runtime_context, Observer* observer) {
70   WebContents::CreateParams params(runtime_context, NULL);
71   params.routing_id = MSG_ROUTING_NONE;
72   WebContents* web_contents = WebContents::Create(params);
73
74   return new Runtime(web_contents, observer);
75 }
76
77 // static
78 void Runtime::SetGlobalObserverForTesting(Observer* observer) {
79   g_observer_for_testing = observer;
80 }
81
82 #define FOR_EACH_RUNTIME_OBSERVER(method) \
83   if (observer_)                          \
84     observer_->method;                    \
85   if (g_observer_for_testing)             \
86     g_observer_for_testing->method
87
88 Runtime::Runtime(content::WebContents* web_contents, Observer* observer)
89     : WebContentsObserver(web_contents),
90       web_contents_(web_contents),
91       window_(NULL),
92       weak_ptr_factory_(this),
93       fullscreen_options_(NO_FULLSCREEN),
94       observer_(observer) {
95   web_contents_->SetDelegate(this);
96   runtime_context_ = RuntimeContext::FromWebContents(web_contents);
97   content::NotificationService::current()->Notify(
98        xwalk::NOTIFICATION_RUNTIME_OPENED,
99        content::Source<Runtime>(this),
100        content::NotificationService::NoDetails());
101
102   FOR_EACH_RUNTIME_OBSERVER(OnRuntimeAdded(this));
103 }
104
105 Runtime::~Runtime() {
106   content::NotificationService::current()->Notify(
107           xwalk::NOTIFICATION_RUNTIME_CLOSED,
108           content::Source<Runtime>(this),
109           content::NotificationService::NoDetails());
110   FOR_EACH_RUNTIME_OBSERVER(OnRuntimeRemoved(this));
111 }
112
113 void Runtime::AttachDefaultWindow() {
114   NativeAppWindow::CreateParams params;
115   params.delegate = this;
116   params.web_contents = web_contents_.get();
117   params.bounds = gfx::Rect(0, 0, kDefaultWidth, kDefaultHeight);
118   CommandLine* cmd_line = CommandLine::ForCurrentProcess();
119   if (cmd_line->HasSwitch(switches::kFullscreen)) {
120     params.state = ui::SHOW_STATE_FULLSCREEN;
121     fullscreen_options_ |= FULLSCREEN_FOR_LAUNCH;
122   }
123   AttachWindow(params);
124 }
125
126 void Runtime::AttachWindow(const NativeAppWindow::CreateParams& params) {
127 #if defined(OS_ANDROID)
128   NOTIMPLEMENTED();
129 #else
130   CHECK(!window_);
131   // Set the app icon if it is passed from command line.
132   CommandLine* command_line = CommandLine::ForCurrentProcess();
133   if (command_line->HasSwitch(switches::kAppIcon)) {
134     base::FilePath icon_file =
135         command_line->GetSwitchValuePath(switches::kAppIcon);
136     app_icon_ = xwalk_utils::LoadImageFromFilePath(icon_file);
137   } else {
138     // Otherwise, use the default icon for Crosswalk app.
139     ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
140     app_icon_ = rb.GetNativeImageNamed(IDR_XWALK_ICON_48);
141   }
142
143   registrar_.Add(this,
144         content::NOTIFICATION_WEB_CONTENTS_TITLE_UPDATED,
145         content::Source<content::WebContents>(web_contents_.get()));
146
147   window_ = NativeAppWindow::Create(params);
148   if (!app_icon_.IsEmpty())
149     window_->UpdateIcon(app_icon_);
150   window_->Show();
151 #endif
152 }
153
154 void Runtime::LoadURL(const GURL& url) {
155   content::NavigationController::LoadURLParams params(url);
156   params.transition_type = content::PageTransitionFromInt(
157       content::PAGE_TRANSITION_TYPED |
158       content::PAGE_TRANSITION_FROM_ADDRESS_BAR);
159   web_contents_->GetController().LoadURLWithParams(params);
160   web_contents_->GetView()->Focus();
161 }
162
163 void Runtime::Close() {
164   delete this;
165 }
166
167 NativeAppWindow* Runtime::window() const {
168   return window_;
169 }
170
171 //////////////////////////////////////////////////////
172 // content::WebContentsDelegate:
173 //////////////////////////////////////////////////////
174 content::WebContents* Runtime::OpenURLFromTab(
175     content::WebContents* source, const content::OpenURLParams& params) {
176   // The only one disposition we would take into consideration.
177   DCHECK(params.disposition == CURRENT_TAB);
178   source->GetController().LoadURL(
179       params.url, params.referrer, params.transition, std::string());
180   return source;
181 }
182
183 void Runtime::LoadingStateChanged(content::WebContents* source) {
184 }
185
186 void Runtime::ToggleFullscreenModeForTab(content::WebContents* web_contents,
187                                          bool enter_fullscreen) {
188   if (enter_fullscreen)
189     fullscreen_options_ |= FULLSCREEN_FOR_TAB;
190   else
191     fullscreen_options_ &= ~FULLSCREEN_FOR_TAB;
192
193   if (enter_fullscreen) {
194     window_->SetFullscreen(true);
195   } else if (!fullscreen_options_ & FULLSCREEN_FOR_LAUNCH) {
196     window_->SetFullscreen(false);
197   }
198 }
199
200 bool Runtime::IsFullscreenForTabOrPending(
201     const content::WebContents* web_contents) const {
202   return (fullscreen_options_ & FULLSCREEN_FOR_TAB) != 0;
203 }
204
205 void Runtime::RequestToLockMouse(content::WebContents* web_contents,
206                                  bool user_gesture,
207                                  bool last_unlocked_by_target) {
208   web_contents->GotResponseToLockMouseRequest(true);
209 }
210
211 void Runtime::CloseContents(content::WebContents* source) {
212   window_->Close();
213 }
214
215 bool Runtime::CanOverscrollContent() const {
216   return false;
217 }
218
219 bool Runtime::PreHandleKeyboardEvent(
220       content::WebContents* source,
221       const content::NativeWebKeyboardEvent& event,
222       bool* is_keyboard_shortcut) {
223   // Escape exits tabbed fullscreen mode.
224   if (event.windowsKeyCode == 27 && IsFullscreenForTabOrPending(source)) {
225     ToggleFullscreenModeForTab(source, false);
226     return true;
227   }
228   return false;
229 }
230
231 void Runtime::HandleKeyboardEvent(
232       content::WebContents* source,
233       const content::NativeWebKeyboardEvent& event) {
234 }
235
236 void Runtime::WebContentsCreated(
237     content::WebContents* source_contents,
238     int64 source_frame_id,
239     const string16& frame_name,
240     const GURL& target_url,
241     content::WebContents* new_contents) {
242   Runtime* new_runtime = new Runtime(new_contents, observer_);
243   new_runtime->AttachDefaultWindow();
244 }
245
246 void Runtime::DidNavigateMainFramePostCommit(
247     content::WebContents* web_contents) {
248 }
249
250 content::JavaScriptDialogManager* Runtime::GetJavaScriptDialogManager() {
251   return NULL;
252 }
253
254 void Runtime::ActivateContents(content::WebContents* contents) {
255   contents->GetRenderViewHost()->Focus();
256 }
257
258 void Runtime::DeactivateContents(content::WebContents* contents) {
259   contents->GetRenderViewHost()->Blur();
260 }
261
262 content::ColorChooser* Runtime::OpenColorChooser(
263     content::WebContents* web_contents,
264     SkColor initial_color) {
265   return xwalk::ShowColorChooser(web_contents, initial_color);
266 }
267
268 void Runtime::RunFileChooser(
269     content::WebContents* web_contents,
270     const content::FileChooserParams& params) {
271 #if defined(USE_AURA) && defined(OS_LINUX)
272   NOTIMPLEMENTED();
273 #else
274   RuntimeFileSelectHelper::RunFileChooser(web_contents, params);
275 #endif
276 }
277
278 void Runtime::EnumerateDirectory(content::WebContents* web_contents,
279                                  int request_id,
280                                  const base::FilePath& path) {
281 #if defined(USE_AURA) && defined(OS_LINUX)
282   NOTIMPLEMENTED();
283 #else
284   RuntimeFileSelectHelper::EnumerateDirectory(web_contents, request_id, path);
285 #endif
286 }
287
288 void Runtime::DidUpdateFaviconURL(int32 page_id,
289                                   const std::vector<FaviconURL>& candidates) {
290   DLOG(INFO) << "Candidates: ";
291   for (size_t i = 0; i < candidates.size(); ++i)
292     DLOG(INFO) << candidates[i].icon_url.spec();
293
294   if (candidates.empty())
295     return;
296
297   // Avoid using any previous download.
298   weak_ptr_factory_.InvalidateWeakPtrs();
299
300   // We only select the first favicon as the window app icon.
301   FaviconURL favicon = candidates[0];
302   // Passing 0 as the |image_size| parameter results in only receiving the first
303   // bitmap, according to content/public/browser/web_contents.h
304   web_contents()->DownloadImage(
305       favicon.icon_url,
306       true,  // Is a favicon
307       0,     // No maximum size
308       base::Bind(
309           &Runtime::DidDownloadFavicon, weak_ptr_factory_.GetWeakPtr()));
310 }
311
312 void Runtime::DidDownloadFavicon(int id,
313                                  int http_status_code,
314                                  const GURL& image_url,
315                                  const std::vector<SkBitmap>& bitmaps,
316                                  const std::vector<gfx::Size>& sizes) {
317   if (bitmaps.empty())
318     return;
319   app_icon_ = gfx::Image::CreateFrom1xBitmap(bitmaps[0]);
320   window_->UpdateIcon(app_icon_);
321 }
322
323 void Runtime::Observe(int type,
324                       const content::NotificationSource& source,
325                       const content::NotificationDetails& details) {
326   if (type == content::NOTIFICATION_WEB_CONTENTS_TITLE_UPDATED) {
327     std::pair<content::NavigationEntry*, bool>* title =
328         content::Details<std::pair<content::NavigationEntry*, bool> >(
329             details).ptr();
330
331     if (title->first) {
332       string16 text = title->first->GetTitle();
333       window_->UpdateTitle(text);
334     }
335   }
336 }
337
338 void Runtime::OnWindowDestroyed() {
339   Close();
340 }
341
342 void Runtime::RequestMediaAccessPermission(
343     content::WebContents* web_contents,
344     const content::MediaStreamRequest& request,
345     const content::MediaResponseCallback& callback) {
346   XWalkMediaCaptureDevicesDispatcher::RunRequestMediaAccessPermission(
347       web_contents, request, callback);
348 }
349
350 void Runtime::RenderProcessGone(base::TerminationStatus status) {
351   content::RenderProcessHost* rph = web_contents_->GetRenderProcessHost();
352   VLOG(1) << "RenderProcess id: " << rph->GetID() << " is gone!";
353   XWalkRunner::GetInstance()->OnRenderProcessHostGone(rph);
354 }
355
356
357 }  // namespace xwalk