|did-frame-rendered| used for optimize launching time
[platform/framework/web/crosswalk-tizen.git] / atom / browser / api / atom_api_web_contents.cc
index 89e7a7d..fccae5a 100644 (file)
@@ -4,6 +4,7 @@
 
 #include "atom/browser/api/atom_api_web_contents.h"
 
+#include <Eina.h>
 #include <set>
 #include <string>
 
@@ -13,6 +14,7 @@
 #include "atom/browser/atom_browser_client.h"
 #include "atom/browser/atom_browser_context.h"
 #include "atom/browser/atom_browser_main_parts.h"
+#include "atom/browser/browser.h"
 #include "atom/browser/lib/bluetooth_chooser.h"
 #include "atom/browser/native_window.h"
 #include "atom/browser/net/atom_network_delegate.h"
@@ -46,6 +48,7 @@
 #include "chrome/browser/printing/print_preview_message_handler.h"
 #include "chrome/browser/printing/print_view_manager_basic.h"
 #include "chrome/browser/ssl/security_state_tab_helper.h"
+#include "content/browser/frame_host/navigation_entry_impl.h"
 #include "content/browser/renderer_host/render_widget_host_impl.h"
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/common/view_messages.h"
@@ -54,6 +57,9 @@
 #include "content/public/browser/navigation_details.h"
 #include "content/public/browser/navigation_entry.h"
 #include "content/public/browser/navigation_handle.h"
+#include "content/public/browser/notification_details.h"
+#include "content/public/browser/notification_source.h"
+#include "content/public/browser/notification_types.h"
 #include "content/public/browser/plugin_service.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_process_host.h"
 #include "net/url_request/url_request_context.h"
 #include "third_party/WebKit/public/platform/WebInputEvent.h"
 #include "third_party/WebKit/public/web/WebFindOptions.h"
+#include "tizen/common/env_variables.h"
 #include "ui/display/screen.h"
 
-#if !defined(OS_MACOSX)
+#if defined(USE_EFL)
+#include "tizen/extensions/common/xwalk_extension_server.h"
+#endif
+
+#if !defined(OS_MACOSX) && !defined(USE_EFL)
 #include "ui/aura/window.h"
 #endif
 
@@ -184,6 +195,7 @@ struct Converter<atom::api::WebContents::Type> {
     switch (val) {
       case Type::BACKGROUND_PAGE: type = "backgroundPage"; break;
       case Type::BROWSER_WINDOW: type = "window"; break;
+      case Type::BROWSER_VIEW: type = "browserView"; break;
       case Type::REMOTE: type = "remote"; break;
       case Type::WEB_VIEW: type = "webview"; break;
       case Type::OFF_SCREEN: type = "offscreen"; break;
@@ -198,10 +210,12 @@ struct Converter<atom::api::WebContents::Type> {
     std::string type;
     if (!ConvertFromV8(isolate, val, &type))
       return false;
-    if (type == "webview") {
-      *out = Type::WEB_VIEW;
-    } else if (type == "backgroundPage") {
+    if (type == "backgroundPage") {
       *out = Type::BACKGROUND_PAGE;
+    } else if (type == "browserView") {
+      *out = Type::BROWSER_VIEW;
+    } else if (type == "webview") {
+      *out = Type::WEB_VIEW;
     } else if (type == "offscreen") {
       *out = Type::OFF_SCREEN;
     } else {
@@ -236,12 +250,28 @@ content::ServiceWorkerContext* GetServiceWorkerContext(
 }
 
 // Called when CapturePage is done.
-void OnCapturePageDone(base::Callback<void(const gfx::Image&)> callback,
+void OnCapturePageDone(const base::Callback<void(const gfx::Image&)>& callback,
                        const SkBitmap& bitmap,
                        content::ReadbackResponse response) {
   callback.Run(gfx::Image::CreateFrom1xBitmap(bitmap));
 }
 
+// Set the background color of RenderWidgetHostView.
+void SetBackgroundColor(content::WebContents* web_contents) {
+  const auto view = web_contents->GetRenderWidgetHostView();
+  if (view) {
+    WebContentsPreferences* web_preferences =
+        WebContentsPreferences::FromWebContents(web_contents);
+    std::string color_name;
+    if (web_preferences->web_preferences()->GetString(options::kBackgroundColor,
+                                                      &color_name)) {
+      view->SetBackgroundColor(ParseHexColor(color_name));
+    } else {
+      view->SetBackgroundColor(SK_ColorTRANSPARENT);
+    }
+  }
+}
+
 }  // namespace
 
 WebContents::WebContents(v8::Isolate* isolate,
@@ -253,7 +283,8 @@ WebContents::WebContents(v8::Isolate* isolate,
       type_(type),
       request_id_(0),
       background_throttling_(true),
-      enable_devtools_(true) {
+      enable_devtools_(true),
+      notify_ready_state_(false) {
   if (type == REMOTE) {
     web_contents->SetUserAgentOverride(GetBrowserContext()->GetUserAgent());
     Init(isolate);
@@ -286,6 +317,8 @@ WebContents::WebContents(v8::Isolate* isolate, const mate::Dictionary& options)
     type_ = WEB_VIEW;
   else if (options.Get("isBackgroundPage", &b) && b)
     type_ = BACKGROUND_PAGE;
+  else if (options.Get("isBrowserView", &b) && b)
+    type_ = BROWSER_VIEW;
   else if (options.Get("offscreen", &b) && b)
     type_ = OFF_SCREEN;
 
@@ -338,7 +371,7 @@ void WebContents::InitWithSessionAndOptions(v8::Isolate* isolate,
                                             content::WebContents *web_contents,
                                             mate::Handle<api::Session> session,
                                             const mate::Dictionary& options) {
-  Observe(web_contents);
+  content::WebContentsObserver::Observe(web_contents);
   InitWithWebContents(web_contents, session->browser_context());
 
   managed_web_contents()->GetView()->SetDelegate(this);
@@ -374,6 +407,11 @@ void WebContents::InitWithSessionAndOptions(v8::Isolate* isolate,
       SetOwnerWindow(owner_window);
   }
 
+  const content::NavigationController* controller =
+      &web_contents->GetController();
+  registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_PENDING,
+                 content::Source<content::NavigationController>(controller));
+
   Init(isolate);
   AttachAsUserData(web_contents);
 }
@@ -386,21 +424,26 @@ WebContents::~WebContents() {
     if (type_ == WEB_VIEW)
       guest_delegate_->Destroy();
 
-    // The WebContentsDestroyed will not be called automatically because we
-    // unsubscribe from webContents before destroying it. So we have to manually
-    // call it here to make sure "destroyed" event is emitted.
     RenderViewDeleted(web_contents()->GetRenderViewHost());
-    WebContentsDestroyed();
+    DestroyWebContents();
   }
 }
 
+void WebContents::DestroyWebContents() {
+  // This event is only for internal use, which is emitted when WebContents is
+  // being destroyed.
+  Emit("will-destroy");
+  ResetManagedWebContents();
+}
+
 bool WebContents::DidAddMessageToConsole(content::WebContents* source,
                                          int32_t level,
                                          const base::string16& message,
                                          int32_t line_no,
                                          const base::string16& source_id) {
   if (type_ == BROWSER_WINDOW || type_ == OFF_SCREEN) {
-    return false;
+    LOG(ERROR) << "Console Message : " << message << ", source:" << source_id << " (" << line_no << ")";
+    return true;
   } else {
     Emit("console-message", level, message, line_no, source_id);
     return true;
@@ -425,7 +468,8 @@ void WebContents::WebContentsCreated(content::WebContents* source_contents,
                                      const std::string& frame_name,
                                      const GURL& target_url,
                                      content::WebContents* new_contents) {
-  v8::Locker locker(isolate());
+  if (!::tizen::is_single_process)
+    v8::Locker locker(isolate());
   v8::HandleScope handle_scope(isolate());
   auto api_web_contents = CreateFrom(isolate(), new_contents, BROWSER_WINDOW);
   Emit("-web-contents-created", api_web_contents, target_url, frame_name);
@@ -437,7 +481,8 @@ void WebContents::AddNewContents(content::WebContents* source,
                                  const gfx::Rect& initial_rect,
                                  bool user_gesture,
                                  bool* was_blocked) {
-  v8::Locker locker(isolate());
+  if (!::tizen::is_single_process)
+    v8::Locker locker(isolate());
   v8::HandleScope handle_scope(isolate());
   auto api_web_contents = CreateFrom(isolate(), new_contents);
   if (Emit("-add-new-contents", api_web_contents, disposition, user_gesture,
@@ -486,7 +531,7 @@ void WebContents::MoveContents(content::WebContents* source,
 
 void WebContents::CloseContents(content::WebContents* source) {
   Emit("close");
-
+  LOG(ERROR) << __FUNCTION__;
   if ((type_ == BROWSER_WINDOW || type_ == OFF_SCREEN) && owner_window())
     owner_window()->CloseContents(source);
 }
@@ -589,7 +634,8 @@ void WebContents::FindReply(content::WebContents* web_contents,
   if (!final_update)
     return;
 
-  v8::Locker locker(isolate());
+  if (!::tizen::is_single_process)
+    v8::Locker locker(isolate());
   v8::HandleScope handle_scope(isolate());
   mate::Dictionary result = mate::Dictionary::CreateEmpty(isolate());
   result.Set("requestId", request_id);
@@ -644,6 +690,7 @@ void WebContents::RenderViewCreated(content::RenderViewHost* render_view_host) {
       render_view_host->GetRoutingID());
   if (impl)
     impl->disable_hidden_ = !background_throttling_;
+  atom::Browser::Get()->RenderViewCreated(render_view_host);
 }
 
 void WebContents::RenderViewDeleted(content::RenderViewHost* render_view_host) {
@@ -700,7 +747,23 @@ void WebContents::DidFailLoad(content::RenderFrameHost* render_frame_host,
   Emit("did-fail-load", error_code, error_description, url, is_main_frame);
 }
 
+void WebContents::DidRenderFrame() {
+  if (!notify_ready_state_) {
+    notify_ready_state_ = true;
+    Emit("did-frame-rendered");
+  }
+}
+
 void WebContents::DidStartLoading() {
+  notify_ready_state_ = false;
+#if defined(OS_TIZEN)
+  if (owner_window() && !owner_window()->IsVisible()) {
+    std::string scheme = web_contents()->GetURL().scheme();
+    if (std::string::npos != scheme.find("http")) {
+      owner_window()->Show();
+    }
+  }
+#endif
   Emit("did-start-loading");
 }
 
@@ -733,6 +796,30 @@ void WebContents::DidGetRedirectForResourceRequest(
        details.headers.get());
 }
 
+void WebContents::DidStartNavigation(
+    content::NavigationHandle* navigation_handle) {
+  if (!navigation_handle->IsInMainFrame() || navigation_handle->IsSamePage())
+    return;
+
+  if (deferred_load_url_.id) {
+    auto web_contents = navigation_handle->GetWebContents();
+    auto& controller = web_contents->GetController();
+    int id = controller.GetPendingEntry()->GetUniqueID();
+    if (id == deferred_load_url_.id) {
+      if (!deferred_load_url_.params.url.is_empty()) {
+        auto params = deferred_load_url_.params;
+        deferred_load_url_.id = 0;
+        deferred_load_url_.params =
+            content::NavigationController::LoadURLParams(GURL());
+        controller.LoadURLWithParams(params);
+        SetBackgroundColor(web_contents);
+      } else {
+        deferred_load_url_.id = 0;
+      }
+    }
+  }
+}
+
 void WebContents::DidFinishNavigation(
     content::NavigationHandle* navigation_handle) {
   bool is_main_frame = navigation_handle->IsInMainFrame();
@@ -777,6 +864,32 @@ void WebContents::DidUpdateFaviconURL(
   Emit("page-favicon-updated", unique_urls);
 }
 
+void WebContents::Observe(int type,
+                          const content::NotificationSource& source,
+                          const content::NotificationDetails& details) {
+  switch (type) {
+    case content::NOTIFICATION_NAV_ENTRY_PENDING: {
+      content::NavigationEntry* entry =
+          content::Details<content::NavigationEntry>(details).ptr();
+      content::NavigationEntryImpl* entry_impl =
+          static_cast<content::NavigationEntryImpl*>(entry);
+      // In NavigatorImpl::DidStartMainFrameNavigation when there is no
+      // browser side pending entry available it creates a new one based
+      // on existing pending entry, hence we track the unique id here
+      // instead in WebContents::LoadURL with controller.GetPendingEntry()
+      // TODO(deepak1556): Remove once we have
+      // https://codereview.chromium.org/2661743002.
+      if (entry_impl->frame_tree_node_id() == -1) {
+        deferred_load_url_.id = entry->GetUniqueID();
+      }
+      break;
+    }
+    default:
+      NOTREACHED();
+      break;
+  }
+}
+
 void WebContents::DevToolsReloadPage() {
   Emit("devtools-reload-page");
 }
@@ -786,7 +899,8 @@ void WebContents::DevToolsFocused() {
 }
 
 void WebContents::DevToolsOpened() {
-  v8::Locker locker(isolate());
+  if (!::tizen::is_single_process)
+    v8::Locker locker(isolate());
   v8::HandleScope handle_scope(isolate());
   auto handle = WebContents::CreateFrom(
       isolate(), managed_web_contents()->GetDevToolsWebContents());
@@ -806,16 +920,57 @@ void WebContents::DevToolsOpened() {
 }
 
 void WebContents::DevToolsClosed() {
-  v8::Locker locker(isolate());
+  if (!::tizen::is_single_process)
+    v8::Locker locker(isolate());
   v8::HandleScope handle_scope(isolate());
   devtools_web_contents_.Reset();
 
   Emit("devtools-closed");
 }
 
+void WebContents::OnWrtPluginMessage(const Ewk_Wrt_Message_Data& data) {
+  Ewk_Wrt_Message_Data tmp = data;
+  HandleWrtPluginMessage(&tmp);
+}
+
+void WebContents::OnWrtPluginSyncMessage(const Ewk_Wrt_Message_Data& data,
+                                                    IPC::Message* reply) {
+  Ewk_Wrt_Message_Data tmp = data;
+  HandleWrtPluginMessage(&tmp);
+  AtomHostMsg_WrtSyncMessage::WriteReplyParams(reply, tmp.value);
+  Send(reply);
+}
+
+void WebContents::HandleWrtPluginMessage(Ewk_Wrt_Message_Data* msg) {
+  Eina_Stringshare* msg_type = ewk_ipc_wrt_message_data_type_get(msg);
+  LOG(INFO) << msg_type;
+#define TYPE_BEGIN(x) (!strncmp(msg_type, x, strlen(x)))
+#define TYPE_IS(x) (!strcmp(msg_type, x))
+  if (TYPE_BEGIN("xwalk://")) {
+    auto extension_server = extensions::XWalkExtensionServer::GetInstance();
+    extension_server->HandleIPCMessage(msg);
+  } else {
+    Eina_Stringshare* msg_id = msg->GetId();
+    Eina_Stringshare* msg_ref_id = msg->GetReferenceId();
+    Eina_Stringshare* msg_value = msg->GetValue();
+    if (TYPE_IS("tizen://exit")) {
+      atom::Browser::Get()->Quit();
+    }
+
+    eina_stringshare_del(msg_ref_id);
+    eina_stringshare_del(msg_id);
+    eina_stringshare_del(msg_value);
+  }
+#undef TYPE_IS
+#undef TYPE_BEGIN
+
+  eina_stringshare_del(msg_type);
+}
+
 bool WebContents::OnMessageReceived(const IPC::Message& message) {
   bool handled = true;
   IPC_BEGIN_MESSAGE_MAP(WebContents, message)
+    IPC_MESSAGE_HANDLER_DELAY_REPLY(WrtViewMsg_GetCSP, OnGetContentSecurityPolicy)
     IPC_MESSAGE_HANDLER(AtomViewHostMsg_Message, OnRendererMessage)
     IPC_MESSAGE_HANDLER_DELAY_REPLY(AtomViewHostMsg_Message_Sync,
                                     OnRendererMessageSync)
@@ -823,8 +978,11 @@ bool WebContents::OnMessageReceived(const IPC::Message& message) {
                                     OnSetTemporaryZoomLevel)
     IPC_MESSAGE_HANDLER_DELAY_REPLY(AtomViewHostMsg_GetZoomLevel,
                                     OnGetZoomLevel)
-    IPC_MESSAGE_HANDLER_CODE(ViewHostMsg_SetCursor, OnCursorChange,
-      handled = false)
+    IPC_MESSAGE_HANDLER(AtomHostMsg_WrtMessage, OnWrtPluginMessage)
+    IPC_MESSAGE_HANDLER_DELAY_REPLY(AtomHostMsg_WrtSyncMessage, OnWrtPluginSyncMessage)
+    // FIXME: Disable OnCursorChange due to stach_chk_fail crash.
+    // IPC_MESSAGE_HANDLER_CODE(ViewHostMsg_SetCursor, OnCursorChange,
+    //   handled = false)
     IPC_MESSAGE_UNHANDLED(handled = false)
   IPC_END_MESSAGE_MAP()
 
@@ -844,10 +1002,6 @@ bool WebContents::OnMessageReceived(const IPC::Message& message) {
 // be destroyed on close, and WebContentsDestroyed would be called for it, so
 // we need to make sure the api::WebContents is also deleted.
 void WebContents::WebContentsDestroyed() {
-  // This event is only for internal use, which is emitted when WebContents is
-  // being destroyed.
-  Emit("will-destroy");
-
   // Cleanup relationships with other parts.
   RemoveFromWeakMap();
 
@@ -897,6 +1051,10 @@ void WebContents::LoadURL(const GURL& url, const mate::Dictionary& options) {
     return;
   }
 
+  if (!atom::Browser::Get()->ShouldAllowNavigation(url.spec())) {
+    return;
+  }
+
   content::NavigationController::LoadURLParams params(url);
 
   GURL http_referrer;
@@ -918,26 +1076,25 @@ void WebContents::LoadURL(const GURL& url, const mate::Dictionary& options) {
     params.load_type = content::NavigationController::LOAD_TYPE_HTTP_POST;
   }
 
+  GURL base_url_for_data_url;
+  if (options.Get("baseURLForDataURL", &base_url_for_data_url)) {
+    params.base_url_for_data_url = base_url_for_data_url;
+    params.load_type = content::NavigationController::LOAD_TYPE_DATA;
+  }
+
   params.transition_type = ui::PAGE_TRANSITION_TYPED;
   params.should_clear_history_list = true;
   params.override_user_agent = content::NavigationController::UA_OVERRIDE_TRUE;
-  web_contents()->GetController().LoadURLWithParams(params);
 
-  // Set the background color of RenderWidgetHostView.
+  if (deferred_load_url_.id) {
+    deferred_load_url_.params = params;
+    return;
+  }
+
+  web_contents()->GetController().LoadURLWithParams(params);
   // We have to call it right after LoadURL because the RenderViewHost is only
   // created after loading a page.
-  const auto view = web_contents()->GetRenderWidgetHostView();
-  if (view) {
-    WebContentsPreferences* web_preferences =
-        WebContentsPreferences::FromWebContents(web_contents());
-    std::string color_name;
-    if (web_preferences->web_preferences()->GetString(options::kBackgroundColor,
-                                                      &color_name)) {
-      view->SetBackgroundColor(ParseHexColor(color_name));
-    } else {
-      view->SetBackgroundColor(SK_ColorTRANSPARENT);
-    }
-  }
+  SetBackgroundColor(web_contents());
 }
 
 void WebContents::DownloadURL(const GURL& url) {
@@ -975,6 +1132,7 @@ bool WebContents::IsWaitingForResponse() const {
 }
 
 void WebContents::Stop() {
+  LOG(ERROR) << __FUNCTION__;
   web_contents()->Stop();
 }
 
@@ -993,6 +1151,23 @@ void WebContents::GoToOffset(int offset) {
   web_contents()->GetController().GoToOffset(offset);
 }
 
+const std::string WebContents::GetWebRTCIPHandlingPolicy() const {
+  return web_contents()->
+    GetMutableRendererPrefs()->webrtc_ip_handling_policy;
+}
+
+void WebContents::SetWebRTCIPHandlingPolicy(
+    const std::string& webrtc_ip_handling_policy) {
+  if (GetWebRTCIPHandlingPolicy() == webrtc_ip_handling_policy)
+    return;
+  web_contents()->GetMutableRendererPrefs()->webrtc_ip_handling_policy =
+    webrtc_ip_handling_policy;
+
+  content::RenderViewHost* host = web_contents()->GetRenderViewHost();
+  if (host)
+    host->SyncRendererPrefs();
+}
+
 bool WebContents::IsCrashed() const {
   return web_contents()->IsCrashed();
 }
@@ -1263,11 +1438,15 @@ bool WebContents::IsFocused() const {
   auto view = web_contents()->GetRenderWidgetHostView();
   if (!view) return false;
 
+#if defined(USE_EFL)
+  NOTIMPLEMENTED();
+#else
   if (GetType() != BACKGROUND_PAGE) {
     auto window = web_contents()->GetNativeView()->GetToplevelWindow();
     if (window && !window->IsVisible())
       return false;
   }
+#endif
 
   return view->HasFocus();
 }
@@ -1543,6 +1722,14 @@ void WebContents::OnGetZoomLevel(IPC::Message* reply_msg) {
   Send(reply_msg);
 }
 
+void WebContents::OnGetContentSecurityPolicy(IPC::Message* reply_msg) {
+  std::string csp_rule;
+  std::string csp_report_rule;
+  atom::Browser::Get()->GetCSP(csp_rule, csp_report_rule);
+  WrtViewMsg_GetCSP::WriteReplyParams(reply_msg, csp_rule, csp_report_rule);
+  Send(reply_msg);
+}
+
 v8::Local<v8::Value> WebContents::GetWebPreferences(v8::Isolate* isolate) {
   WebContentsPreferences* web_preferences =
       WebContentsPreferences::FromWebContents(web_contents());
@@ -1691,6 +1878,10 @@ void WebContents::BuildPrototype(v8::Isolate* isolate,
       .SetMethod("copyImageAt", &WebContents::CopyImageAt)
       .SetMethod("capturePage", &WebContents::CapturePage)
       .SetMethod("setEmbedder", &WebContents::SetEmbedder)
+      .SetMethod("setWebRTCIPHandlingPolicy",
+                 &WebContents::SetWebRTCIPHandlingPolicy)
+      .SetMethod("getWebRTCIPHandlingPolicy",
+                 &WebContents::GetWebRTCIPHandlingPolicy)
       .SetProperty("id", &WebContents::ID)
       .SetProperty("session", &WebContents::Session)
       .SetProperty("hostWebContents", &WebContents::HostWebContents)