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