// Copyright (c) 2008-2009 The Chromium Embedded Framework Authors. // Portions copyright (c) 2006-2008 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // This file contains the implementation of BrowserWebViewDelegate, which serves // as the WebViewDelegate for the BrowserWebHost. The host is expected to // have initialized a MessageLoop before these methods are called. #include "browser_webview_delegate.h" #include "browser_appcache_system.h" #include "browser_file_system.h" #include "browser_impl.h" #include "browser_navigation_controller.h" #include "browser_webkit_glue.h" #include "browser_webstoragenamespace_impl.h" #include "browser_zoom_map.h" #include "cef_context.h" #include "dom_document_impl.h" #include "request_impl.h" #include "v8_impl.h" #include "base/debug/trace_event.h" #include "base/file_util.h" #include "base/message_loop.h" #include "base/process_util.h" #include "base/string_util.h" #include "base/stringprintf.h" #include "media/base/filter_collection.h" #include "media/base/media_log.h" #include "media/base/message_loop_factory_impl.h" #include "media/filters/reference_audio_renderer.h" #include "net/base/net_errors.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebConsoleMessage.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebContextMenuData.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebCString.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebData.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebDataSource.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebFileError.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebFileSystemCallbacks.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebHistoryItem.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebKit.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebKitPlatformSupport.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebNode.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebPoint.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebPluginParams.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebRange.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebScreenInfo.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebStorageNamespace.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebString.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebURL.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebURLError.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebURLRequest.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebURLResponse.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebVector.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebWindowFeatures.h" #include "ui/gfx/native_widget_types.h" #include "ui/gfx/point.h" #include "webkit/appcache/web_application_cache_host_impl.h" #include "webkit/glue/glue_serialize.h" #include "webkit/glue/webpreferences.h" #include "webkit/glue/webkit_glue.h" #include "webkit/glue/window_open_disposition.h" #include "webkit/media/video_renderer_impl.h" #include "webkit/media/webmediaplayer_impl.h" #include "webkit/plugins/npapi/plugin_list.h" #include "webkit/plugins/npapi/webplugin_delegate_impl.h" #include "webkit/plugins/npapi/webplugin_impl.h" #if defined(OS_WIN) #include "browser_drag_delegate_win.h" #include "web_drop_target_win.h" #endif using appcache::WebApplicationCacheHostImpl; using WebKit::WebApplicationCacheHost; using WebKit::WebApplicationCacheHostClient; using WebKit::WebConsoleMessage; using WebKit::WebContextMenuData; using WebKit::WebCookieJar; using WebKit::WebData; using WebKit::WebDataSource; using WebKit::WebEditingAction; using WebKit::WebFileChooserParams; using WebKit::WebFileSystem; using WebKit::WebFileSystemCallbacks; using WebKit::WebFormElement; using WebKit::WebFrame; using WebKit::WebHistoryItem; using WebKit::WebMediaPlayer; using WebKit::WebMediaPlayerClient; using WebKit::WebNavigationType; using WebKit::WebNavigationPolicy; using WebKit::WebNode; using WebKit::WebPlugin; using WebKit::WebPluginParams; using WebKit::WebPoint; using WebKit::WebPopupType; using WebKit::WebRange; using WebKit::WebRect; using WebKit::WebScreenInfo; using WebKit::WebSecurityOrigin; using WebKit::WebSize; using WebKit::WebStorageNamespace; using WebKit::WebString; using WebKit::WebTextAffinity; using WebKit::WebTextDirection; using WebKit::WebURL; using WebKit::WebURLError; using WebKit::WebURLRequest; using WebKit::WebURLResponse; using WebKit::WebVector; using WebKit::WebView; using WebKit::WebWidget; using WebKit::WebWindowFeatures; using WebKit::WebKeyboardEvent; namespace { int next_page_id_ = 1; void TranslatePopupFeatures(const WebWindowFeatures& webKitFeatures, CefPopupFeatures& features) { features.x = static_cast(webKitFeatures.x); features.xSet = webKitFeatures.xSet; features.y = static_cast(webKitFeatures.y); features.ySet = webKitFeatures.ySet; features.width = static_cast(webKitFeatures.width); features.widthSet = webKitFeatures.widthSet; features.height = static_cast(webKitFeatures.height); features.heightSet = webKitFeatures.heightSet; features.menuBarVisible = webKitFeatures.menuBarVisible; features.statusBarVisible = webKitFeatures.statusBarVisible; features.toolBarVisible = webKitFeatures.toolBarVisible; features.locationBarVisible = webKitFeatures.locationBarVisible; features.scrollbarsVisible = webKitFeatures.scrollbarsVisible; features.resizable = webKitFeatures.resizable; features.fullscreen = webKitFeatures.fullscreen; features.dialog = webKitFeatures.dialog; features.additionalFeatures = NULL; if (webKitFeatures.additionalFeatures.size() > 0) features.additionalFeatures = cef_string_list_alloc(); CefString str; for(unsigned int i = 0; i < webKitFeatures.additionalFeatures.size(); ++i) { str = string16(webKitFeatures.additionalFeatures[i]); cef_string_list_append(features.additionalFeatures, str.GetStruct()); } } } // namespace // WebViewClient ------------------------------------------------------------- WebView* BrowserWebViewDelegate::createView(WebFrame* creator, const WebURLRequest& request, const WebWindowFeatures& features, const WebString& name) { CefString url; if (!request.isNull()) url = request.url().spec().utf16(); CefPopupFeatures cefFeatures; TranslatePopupFeatures(features, cefFeatures); CefRefPtr browser = browser_->UIT_CreatePopupWindow(url, cefFeatures); return browser.get() ? browser->UIT_GetWebView() : NULL; } WebWidget* BrowserWebViewDelegate::createPopupMenu(WebPopupType popup_type) { // TODO(darin): Should we take into account |popup_type| (for activation // purpose)? return browser_->UIT_CreatePopupWidget(); } WebStorageNamespace* BrowserWebViewDelegate::createSessionStorageNamespace( unsigned quota) { // Ignore the quota parameter from WebCore as in Chrome. return new BrowserWebStorageNamespaceImpl(DOM_STORAGE_SESSION, kLocalStorageNamespaceId + 1); } void BrowserWebViewDelegate::didAddMessageToConsole( const WebConsoleMessage& message, const WebString& source_name, unsigned source_line) { std::string messageStr = message.text.utf8(); std::string sourceStr = source_name.utf8(); bool handled = false; CefRefPtr client = browser_->GetClient(); if (client.get()) { CefRefPtr handler = client->GetDisplayHandler(); if (handler.get()) { handled = handler->OnConsoleMessage(browser_, messageStr, sourceStr, source_line); } } if(!handled) { logging::LogMessage("CONSOLE", 0).stream() << "\"" << messageStr << ",\" source: " << sourceStr << "(" << source_line << ")"; } } void BrowserWebViewDelegate::printPage(WebFrame* frame) { if (!frame) { WebView* view = browser_->UIT_GetWebView(); if (view) frame = view->mainFrame(); } if (frame) browser_->UIT_PrintPages(frame); } bool BrowserWebViewDelegate::shouldBeginEditing(const WebRange& range) { return browser_->UIT_AllowEditing(); } bool BrowserWebViewDelegate::shouldEndEditing(const WebRange& range) { return browser_->UIT_AllowEditing(); } bool BrowserWebViewDelegate::shouldInsertNode(const WebNode& node, const WebRange& range, WebEditingAction action) { return browser_->UIT_AllowEditing(); } bool BrowserWebViewDelegate::shouldInsertText(const WebString& text, const WebRange& range, WebEditingAction action) { return browser_->UIT_AllowEditing(); } bool BrowserWebViewDelegate::shouldChangeSelectedRange( const WebRange& from_range, const WebRange& to_range, WebTextAffinity affinity, bool still_selecting) { return browser_->UIT_AllowEditing(); } bool BrowserWebViewDelegate::shouldDeleteRange(const WebRange& range) { return browser_->UIT_AllowEditing(); } bool BrowserWebViewDelegate::shouldApplyStyle(const WebString& style, const WebRange& range) { return browser_->UIT_AllowEditing(); } bool BrowserWebViewDelegate::isSmartInsertDeleteEnabled() { return smart_insert_delete_enabled_; } bool BrowserWebViewDelegate::isSelectTrailingWhitespaceEnabled() { return select_trailing_whitespace_enabled_; } bool BrowserWebViewDelegate::handleCurrentKeyboardEvent() { WebWidgetHost* host = GetWidgetHost(); if (host && OnKeyboardEvent(host->GetLastKeyEvent(), true)) return true; if (edit_command_name_.empty()) return false; WebView* view = browser_->UIT_GetWebView(); WebFrame* frame = NULL; if (view) frame = view->focusedFrame(); if (!frame) return false; return frame->executeCommand(WebString::fromUTF8(edit_command_name_), WebString::fromUTF8(edit_command_value_)); } bool BrowserWebViewDelegate::runFileChooser( const WebFileChooserParams& params, WebKit::WebFileChooserCompletion* chooser_completion) { // Support file open dialog. std::vector file_names; if(!ShowFileChooser(file_names, params.multiSelect, params.title, webkit_glue::WebStringToFilePath(params.initialValue))) { return false; } WebVector ws_file_names(file_names.size()); for (size_t i = 0; i < file_names.size(); ++i) { ws_file_names[i] = webkit_glue::FilePathToWebString(file_names[i]); } chooser_completion->didChooseFile(ws_file_names); return true; } void BrowserWebViewDelegate::runModalAlertDialog( WebFrame* frame, const WebString& message) { CefString messageStr = string16(message); bool handled = false; CefRefPtr client = browser_->GetClient(); CefRefPtr handler; if (client.get()) handler = client->GetJSDialogHandler(); if (handler.get()) { handled = handler->OnJSAlert(browser_, browser_->UIT_GetCefFrame(frame), messageStr); } if (!handled) ShowJavaScriptAlert(frame, messageStr); } bool BrowserWebViewDelegate::runModalConfirmDialog( WebFrame* frame, const WebString& message) { CefString messageStr = string16(message); bool retval = false; bool handled = false; CefRefPtr client = browser_->GetClient(); CefRefPtr handler; if (client.get()) handler = client->GetJSDialogHandler(); if (handler.get()) { handled = handler->OnJSConfirm(browser_, browser_->UIT_GetCefFrame(frame), messageStr, retval); } if (!handled) retval = ShowJavaScriptConfirm(frame, messageStr); return retval; } bool BrowserWebViewDelegate::runModalPromptDialog( WebFrame* frame, const WebString& message, const WebString& default_value, WebString* actual_value) { CefString messageStr = string16(message); CefString defaultValueStr = string16(default_value); CefString actualValueStr; if(actual_value) actualValueStr = string16(*actual_value); bool retval = false; bool handled = false; CefRefPtr client = browser_->GetClient(); CefRefPtr handler; if (client.get()) handler = client->GetJSDialogHandler(); if (handler.get()) { handled = handler->OnJSPrompt(browser_, browser_->UIT_GetCefFrame(frame), messageStr, defaultValueStr, retval, actualValueStr); } if (!handled) { retval = ShowJavaScriptPrompt(frame, messageStr, defaultValueStr, &actualValueStr); } if (actual_value) *actual_value = string16(actualValueStr); return retval; } bool BrowserWebViewDelegate::runModalBeforeUnloadDialog( WebFrame* frame, const WebString& message) { return true; // Allow window closure. } void BrowserWebViewDelegate::setStatusText(const WebString& text) { ShowStatus(text, STATUSTYPE_TEXT); } void BrowserWebViewDelegate::setMouseOverURL(const WebURL& url) { ShowStatus(url.spec().utf16(), STATUSTYPE_MOUSEOVER_URL); } void BrowserWebViewDelegate::setKeyboardFocusURL(const WebKit::WebURL& url) { ShowStatus(url.spec().utf16(), STATUSTYPE_KEYBOARD_FOCUS_URL); } void BrowserWebViewDelegate::setToolTipText( const WebString& text, WebTextDirection hint) { CefString tooltipStr = string16(text); bool handled = false; CefRefPtr client = browser_->GetClient(); if (client.get()) { CefRefPtr handler = client->GetDisplayHandler(); if (handler.get()) handled = handler->OnTooltip(browser_, tooltipStr); } if (!handled) GetWidgetHost()->SetTooltipText(tooltipStr); } bool BrowserWebViewDelegate::acceptsLoadDrops() { return !browser_->settings().load_drops_disabled; } void BrowserWebViewDelegate::focusNext() { CefRefPtr client = browser_->GetClient(); if (client.get()) { CefRefPtr handler = client->GetFocusHandler(); if (handler.get()) { // Notify the handler that it should take a focus handler->OnTakeFocus(browser_, true); } } } void BrowserWebViewDelegate::focusPrevious() { CefRefPtr client = browser_->GetClient(); if (client.get()) { CefRefPtr handler = client->GetFocusHandler(); if (handler.get()) { // Notify the handler that it should take a focus handler->OnTakeFocus(browser_, false); } } } void BrowserWebViewDelegate::focusedNodeChanged(const WebKit::WebNode& node) { CefRefPtr client = browser_->GetClient(); if (client.get()) { CefRefPtr handler = client->GetFocusHandler(); if (handler.get()) { if (node.isNull()) { handler->OnFocusedNodeChanged(browser_, browser_->GetFocusedFrame(), NULL); } else { const WebKit::WebDocument& document = node.document(); if (!document.isNull()) { WebKit::WebFrame* frame = document.frame(); CefRefPtr documentImpl = new CefDOMDocumentImpl(browser_, frame); handler->OnFocusedNodeChanged(browser_, browser_->UIT_GetCefFrame(frame), documentImpl->GetOrCreateNode(node)); documentImpl->Detach(); } } } } } void BrowserWebViewDelegate::navigateBackForwardSoon(int offset) { browser_->UIT_GetNavigationController()->GoToOffset(offset); } int BrowserWebViewDelegate::historyBackListCount() { int current_index = browser_->UIT_GetNavigationController()->GetLastCommittedEntryIndex(); return current_index; } int BrowserWebViewDelegate::historyForwardListCount() { int current_index = browser_->UIT_GetNavigationController()->GetLastCommittedEntryIndex(); return browser_->UIT_GetNavigationController()->GetEntryCount() - current_index - 1; } // WebPluginPageDelegate ----------------------------------------------------- WebCookieJar* BrowserWebViewDelegate::GetCookieJar() { return WebKit::webKitPlatformSupport()->cookieJar(); } // WebWidgetClient ----------------------------------------------------------- void BrowserWebViewDelegate::didInvalidateRect(const WebRect& rect) { if (WebWidgetHost* host = GetWidgetHost()) host->DidInvalidateRect(rect); } void BrowserWebViewDelegate::didScrollRect(int dx, int dy, const WebRect& clip_rect) { if (WebWidgetHost* host = GetWidgetHost()) host->DidScrollRect(dx, dy, clip_rect); } void BrowserWebViewDelegate::scheduleComposite() { if (WebWidgetHost* host = GetWidgetHost()) host->ScheduleComposite(); } void BrowserWebViewDelegate::scheduleAnimation() { if (WebWidgetHost* host = GetWidgetHost()) host->ScheduleAnimation(); } // This method is called when: // A. A request is loaded in a window other than the source window // (FrameLoader::loadFrameRequest), or // B. A request is loaded in an already existing popup window // (FrameLoader::createWindow), or // C. A DOM window receives a focus event (DOMWindow::focus) void BrowserWebViewDelegate::didFocus() { if (WebWidgetHost* host = GetWidgetHost()) { bool handled = false; CefRefPtr client = browser_->GetClient(); if (client.get()) { CefRefPtr handler = client->GetFocusHandler(); if (handler.get()) handled = handler->OnSetFocus(browser_, FOCUS_SOURCE_WIDGET); } if (!handled) browser_->UIT_SetFocus(host, true); } } // This method is called when a DOM window receives a blur event // (DOMWindow::blur). void BrowserWebViewDelegate::didBlur() { if (WebWidgetHost* host = GetWidgetHost()) browser_->UIT_SetFocus(host, false); } void BrowserWebViewDelegate::closeWidgetSoon() { if (this == browser_->UIT_GetWebViewDelegate()) { browser_->UIT_CloseBrowser(); } else if (this == browser_->UIT_GetPopupDelegate()) { browser_->UIT_ClosePopupWidget(); } } WebScreenInfo BrowserWebViewDelegate::screenInfo() { if (WebWidgetHost* host = GetWidgetHost()) { WebScreenInfo info = host->GetScreenInfo(); if (browser_->IsWindowRenderingDisabled()) { // Retrieve the screen rectangle from the handler. CefRefPtr client = browser_->GetClient(); if (client.get()) { CefRefPtr handler = client->GetRenderHandler(); if (handler.get()) { CefRect rect(info.rect.x, info.rect.y, info.rect.width, info.rect.height); if (handler->GetScreenRect(browser_, rect)) { info.rect = WebRect(rect.x, rect.y, rect.width, rect.height); info.availableRect = info.rect; } } } } return info; } return WebScreenInfo(); } // WebFrameClient ------------------------------------------------------------ WebPlugin* BrowserWebViewDelegate::createPlugin( WebFrame* frame, const WebPluginParams& params) { bool allow_wildcard = true; std::vector plugins; std::vector mime_types; webkit::npapi::PluginList::Singleton()->GetPluginInfoArray( params.url, params.mimeType.utf8(), allow_wildcard, NULL, &plugins, &mime_types); if (plugins.empty()) return NULL; #if defined(OS_MACOSX) // Mac does not supported windowed plugins. bool force_windowless = true; #else bool force_windowless = browser_->IsWindowRenderingDisabled(); #endif if (force_windowless) { WebPluginParams params_copy = params; params_copy.mimeType = WebString::fromUTF8(mime_types.front()); bool flash = LowerCaseEqualsASCII(params_copy.mimeType.utf8(), "application/x-shockwave-flash"); bool silverlight = StartsWithASCII(params_copy.mimeType.utf8(), "application/x-silverlight", false); if (flash || silverlight) { // Force Flash and Silverlight plugins to use windowless mode. DCHECK(params_copy.attributeNames.size() == params_copy.attributeValues.size()); size_t size = params_copy.attributeNames.size(); WebVector new_names(size+1), new_values(size+1); for (size_t i = 0; i < size; ++i) { new_names[i] = params_copy.attributeNames[i]; new_values[i] = params_copy.attributeValues[i]; } if (flash) { new_names[size] = "wmode"; new_values[size] = "opaque"; } else if (silverlight) { new_names[size] = "windowless"; new_values[size] = "true"; } params_copy.attributeNames.swap(new_names); params_copy.attributeValues.swap(new_values); return new webkit::npapi::WebPluginImpl( frame, params_copy, plugins.front().path, AsWeakPtr()); } } return new webkit::npapi::WebPluginImpl( frame, params, plugins.front().path, AsWeakPtr()); } WebMediaPlayer* BrowserWebViewDelegate::createMediaPlayer( WebFrame* frame, WebMediaPlayerClient* client) { scoped_ptr message_loop_factory( new media::MessageLoopFactoryImpl()); scoped_ptr collection( new media::FilterCollection()); scoped_refptr video_renderer( new webkit_media::VideoRendererImpl(false)); collection->AddVideoRenderer(video_renderer); // Add the audio renderer. collection->AddAudioRenderer(new media::ReferenceAudioRenderer()); scoped_ptr result( new webkit_media::WebMediaPlayerImpl( client, base::WeakPtr(), collection.release(), message_loop_factory.release(), NULL, new media::MediaLog())); if (!result->Initialize(frame, false, video_renderer)) return NULL; return result.release(); } WebApplicationCacheHost* BrowserWebViewDelegate::createApplicationCacheHost( WebFrame* frame, WebApplicationCacheHostClient* client) { return BrowserAppCacheSystem::CreateApplicationCacheHost(client); } void BrowserWebViewDelegate::willClose(WebFrame* frame) { browser_->UIT_BeforeFrameClosed(frame); } void BrowserWebViewDelegate::loadURLExternally( WebFrame* frame, const WebURLRequest& request, WebNavigationPolicy policy) { DCHECK_NE(policy, WebKit::WebNavigationPolicyCurrentTab); std::string url = request.url().spec().data(); CefRefPtr newBrowser = browser_->UIT_CreatePopupWindow(url, CefPopupFeatures()); if (newBrowser.get() && !url.empty()) newBrowser->GetMainFrame()->LoadURL(url); } WebNavigationPolicy BrowserWebViewDelegate::decidePolicyForNavigation( WebFrame* frame, const WebURLRequest& request, WebNavigationType type, const WebNode& originating_node, WebNavigationPolicy default_policy, bool is_redirect) { CefRefPtr client = browser_->GetClient(); if (client.get()) { CefRefPtr handler = client->GetRequestHandler(); if (handler.get()) { // Gather browse request information CefRefPtr req(CefRequest::CreateRequest()); GURL request_url = request.url(); if (!request_url.is_valid()) return WebKit::WebNavigationPolicyIgnore; req->SetURL(request_url.spec()); req->SetMethod(string16(request.httpMethod())); const WebKit::WebHTTPBody& httpBody = request.httpBody(); if(!httpBody.isNull()) { CefRefPtr postdata(CefPostData::CreatePostData()); static_cast(postdata.get())->Set(httpBody); req->SetPostData(postdata); } CefRequest::HeaderMap map; CefRequestImpl::GetHeaderMap(request, map); if(map.size() > 0) static_cast(req.get())->SetHeaderMap(map); cef_handler_navtype_t navType; if (browser_->is_dropping()) navType = NAVTYPE_LINKDROPPED; else navType = (cef_handler_navtype_t)type; // Notify the handler of a browse request bool handled = handler->OnBeforeBrowse(browser_, browser_->UIT_GetCefFrame(frame), req, navType, is_redirect); if(handled) return WebKit::WebNavigationPolicyIgnore; } } WebNavigationPolicy result; if (policy_delegate_enabled_) { if (policy_delegate_is_permissive_) { result = WebKit::WebNavigationPolicyCurrentTab; } else { result = WebKit::WebNavigationPolicyIgnore; } } else { result = default_policy; } return result; } WebURLError BrowserWebViewDelegate::cannotHandleRequestError( WebFrame* frame, const WebURLRequest& request) { WebURLError error; error.domain = WebString::fromUTF8(net::kErrorDomain); error.reason = net::ERR_ABORTED; error.unreachableURL = request.url(); return error; } WebURLError BrowserWebViewDelegate::cancelledError( WebFrame* frame, const WebURLRequest& request) { WebURLError error; error.domain = WebString::fromUTF8(net::kErrorDomain); error.reason = net::ERR_ABORTED; error.unreachableURL = request.url(); return error; } void BrowserWebViewDelegate::didCreateDataSource( WebFrame* frame, WebDataSource* ds) { ds->setExtraData(pending_extra_data_.release()); } void BrowserWebViewDelegate::didStartProvisionalLoad(WebFrame* frame) { } void BrowserWebViewDelegate::didReceiveServerRedirectForProvisionalLoad( WebFrame* frame) { } void BrowserWebViewDelegate::didFailProvisionalLoad( WebFrame* frame, const WebURLError& error) { // error codes are defined in net\base\net_error_list.h // Don't display an error page if this is simply a cancelled load. Aside // from being dumb, WebCore doesn't expect it and it will cause a crash. if (error.reason == net::ERR_ABORTED) return; const WebDataSource* failed_ds = frame->provisionalDataSource(); BrowserExtraData* extra_data = static_cast(failed_ds->extraData()); if (extra_data && !extra_data->request_committed) { // Set the pending extra_data for our error page as the same pending_page_id // to keep the history from getting messed up. set_pending_extra_data(new BrowserExtraData(extra_data->pending_page_id)); } std::string error_text; CefString errorStr; bool handled = false; CefRefPtr client = browser_->GetClient(); if (client.get()) { CefRefPtr handler = client->GetLoadHandler(); if (handler.get()) { // give the handler an opportunity to generate a custom error message handled = handler->OnLoadError(browser_, browser_->UIT_GetCefFrame(frame), static_cast(error.reason), std::string(failed_ds->request().url().spec().data()), errorStr); } } if(handled && !errorStr.empty()) { error_text = errorStr; } else { error_text = base::StringPrintf("Error %d when loading url %s", error.reason, failed_ds->request().url().spec().data()); } // Make sure we never show errors in view source mode. frame->enableViewSourceMode(false); frame->loadHTMLString( error_text, GURL("cef-error:"), error.unreachableURL, false); // In case loadHTMLString failed before DidCreateDataSource was called. set_pending_extra_data(NULL); } void BrowserWebViewDelegate::didCommitProvisionalLoad( WebFrame* frame, bool is_new_navigation) { bool is_main_frame = (frame->parent() == 0); if (is_main_frame) { // Clear the title so we can tell if it wasn't provided by the page. browser_->UIT_SetTitle(std::wstring()); } UpdateForCommittedLoad(frame, is_new_navigation); CefRefPtr client = browser_->GetClient(); if (client.get()) { CefRefPtr handler = client->GetLoadHandler(); if (handler.get()) { // Notify the handler that loading has started. handler->OnLoadStart(browser_, browser_->UIT_GetCefFrame(frame)); } } // Apply zoom settings only on top-level frames. if (is_main_frame) { // Restore the zoom value that we have for this URL, if any. double zoomLevel = 0.0; ZoomMap::GetInstance()->get(frame->document().url(), zoomLevel); frame->view()->setZoomLevel(false, zoomLevel); browser_->set_zoom_level(zoomLevel); } } void BrowserWebViewDelegate::didCreateScriptContext( WebFrame* frame, v8::Handle context, int worldId) { CefRefPtr client = browser_->GetClient(); if (!client.get()) return; CefRefPtr handler = client->GetV8ContextHandler(); if (!handler.get()) return; v8::HandleScope handle_scope; v8::Context::Scope scope(context); CefRefPtr framePtr(browser_->UIT_GetCefFrame(frame)); CefRefPtr contextPtr(new CefV8ContextImpl(context)); handler->OnContextCreated(browser_, framePtr, contextPtr); } void BrowserWebViewDelegate::willReleaseScriptContext( WebFrame* frame, v8::Handle context, int worldId) { CefRefPtr client = browser_->GetClient(); if (!client.get()) return; CefRefPtr handler = client->GetV8ContextHandler(); if (!handler.get()) return; v8::HandleScope handle_scope; v8::Context::Scope scope(context); CefRefPtr framePtr(browser_->UIT_GetCefFrame(frame)); CefRefPtr contextPtr(new CefV8ContextImpl(context)); handler->OnContextReleased(browser_, framePtr, contextPtr); } void BrowserWebViewDelegate::didReceiveTitle( WebFrame* frame, const WebString& title, WebTextDirection direction) { bool is_main_frame = (frame->parent() == 0); if (is_main_frame) { CefString titleStr = string16(title); browser_->UIT_SetTitle(titleStr); CefRefPtr client = browser_->GetClient(); if (client.get()) { CefRefPtr handler = client->GetDisplayHandler(); if (handler.get()) { // Notify the handler of a page title change handler->OnTitleChange(browser_, titleStr); } } } } void BrowserWebViewDelegate::didFailLoad( WebFrame* frame, const WebURLError& error) { LocationChangeDone(frame); } void BrowserWebViewDelegate::didFinishLoad(WebFrame* frame) { LocationChangeDone(frame); } void BrowserWebViewDelegate::didNavigateWithinPage( WebFrame* frame, bool is_new_navigation) { frame->dataSource()->setExtraData(pending_extra_data_.release()); UpdateForCommittedLoad(frame, is_new_navigation); } void BrowserWebViewDelegate::willSendRequest( WebFrame* frame, unsigned identifier, WebURLRequest& request, const WebURLResponse& redirect_response) { if (!redirect_response.isNull() && block_redirects_) { // To block the request, we set its URL to an empty one. request.setURL(WebURL()); return; } // The requestor ID is used by the resource loader bridge to locate the // browser that originated the request. request.setRequestorID(browser_->UIT_GetUniqueID()); } void BrowserWebViewDelegate::didChangeContentsSize( WebFrame* frame, const WebSize& size) { CefRefPtr client = browser_->GetClient(); if (client.get()) { CefRefPtr handler = client->GetDisplayHandler(); if (handler.get()) { handler->OnContentsSizeChange(browser_, browser_->UIT_GetCefFrame(frame), size.width, size.height); } } } void BrowserWebViewDelegate::reportFindInPageMatchCount( int request_id, int count, bool final_update) { browser_->UIT_NotifyFindStatus(request_id, count, gfx::Rect(), -1, // Don't update active match ordinal. final_update); } void BrowserWebViewDelegate::reportFindInPageSelection( int request_id, int active_match_ordinal, const WebKit::WebRect& sel) { browser_->UIT_NotifyFindStatus(request_id, -1, sel, active_match_ordinal, false); } void BrowserWebViewDelegate::openFileSystem( WebFrame* frame, WebFileSystem::Type type, long long size, bool create, WebFileSystemCallbacks* callbacks) { BrowserFileSystem* fileSystem = static_cast( WebKit::webKitPlatformSupport()->fileSystem()); fileSystem->OpenFileSystem(frame, type, size, create, callbacks); } // Public methods ------------------------------------------------------------ BrowserWebViewDelegate::BrowserWebViewDelegate(CefBrowserImpl* browser) : policy_delegate_enabled_(false), policy_delegate_is_permissive_(false), policy_delegate_should_notify_done_(false), browser_(browser), page_id_(-1), last_page_id_updated_(-1), smart_insert_delete_enabled_(true), #if defined(OS_WIN) select_trailing_whitespace_enabled_(true), #else select_trailing_whitespace_enabled_(false), #endif block_redirects_(false) { } BrowserWebViewDelegate::~BrowserWebViewDelegate() { } void BrowserWebViewDelegate::Reset() { // Do a little placement new dance... CefBrowserImpl* browser = browser_; this->~BrowserWebViewDelegate(); new (this) BrowserWebViewDelegate(browser); } void BrowserWebViewDelegate::SetSmartInsertDeleteEnabled(bool enabled) { smart_insert_delete_enabled_ = enabled; // In upstream WebKit, smart insert/delete is mutually exclusive with select // trailing whitespace, however, we allow both because Chromium on Windows // allows both. } void BrowserWebViewDelegate::SetSelectTrailingWhitespaceEnabled(bool enabled) { select_trailing_whitespace_enabled_ = enabled; // In upstream WebKit, smart insert/delete is mutually exclusive with select // trailing whitespace, however, we allow both because Chromium on Windows // allows both. } void BrowserWebViewDelegate::SetCustomPolicyDelegate(bool is_custom, bool is_permissive) { policy_delegate_enabled_ = is_custom; policy_delegate_is_permissive_ = is_permissive; } void BrowserWebViewDelegate::WaitForPolicyDelegate() { policy_delegate_enabled_ = true; policy_delegate_should_notify_done_ = true; } // Private methods ----------------------------------------------------------- bool BrowserWebViewDelegate::OnKeyboardEvent( const WebKit::WebKeyboardEvent& event, bool isAfterJavaScript) { CefRefPtr client = browser_->GetClient(); CefRefPtr handler; if (client.get()) handler = client->GetKeyboardHandler(); if (!handler.get()) return false; CefKeyboardHandler::KeyEventType eventType; switch (event.type) { case WebKeyboardEvent::RawKeyDown: eventType = KEYEVENT_RAWKEYDOWN; break; case WebKeyboardEvent::KeyDown: eventType = KEYEVENT_KEYDOWN; break; case WebKeyboardEvent::KeyUp: eventType = KEYEVENT_KEYUP; break; case WebKeyboardEvent::Char: eventType = KEYEVENT_CHAR; break; default: return false; } return handler->OnKeyEvent(browser_, eventType, event.windowsKeyCode, event.modifiers, event.isSystemKey?true:false, isAfterJavaScript); } void BrowserWebViewDelegate::ShowStatus(const WebString& text, cef_handler_statustype_t type) { CefRefPtr client = browser_->GetClient(); if (client.get()) { CefRefPtr handler = client->GetDisplayHandler(); if (handler.get()) { CefString textStr = string16(text); handler->OnStatusMessage(browser_, textStr, type); } } } void BrowserWebViewDelegate::LocationChangeDone(WebFrame* frame) { CefRefPtr client = browser_->GetClient(); if (!client.get()) return; bool is_main_frame = (frame->parent() == 0); if (is_main_frame) { CefString title = browser_->UIT_GetTitle(); if (title.empty()) { // No title was provided by the page, so send a blank string to the // client. CefRefPtr handler = client->GetDisplayHandler(); if (handler.get()) handler->OnTitleChange(browser_, title); } } CefRefPtr handler = client->GetLoadHandler(); if (handler.get()) { // Notify the handler that loading has ended. int httpStatusCode = frame->dataSource()->response().httpStatusCode(); handler->OnLoadEnd(browser_, browser_->UIT_GetCefFrame(frame), httpStatusCode); } } WebWidgetHost* BrowserWebViewDelegate::GetWidgetHost() { if (this == browser_->UIT_GetWebViewDelegate()) return browser_->UIT_GetWebViewHost(); if (this == browser_->UIT_GetPopupDelegate()) return browser_->UIT_GetPopupHost(); return NULL; } void BrowserWebViewDelegate::UpdateForCommittedLoad(WebFrame* frame, bool is_new_navigation) { // Code duplicated from RenderView::DidCommitLoadForFrame. BrowserExtraData* extra_data = static_cast( frame->dataSource()->extraData()); if (is_new_navigation) { // New navigation. UpdateSessionHistory(frame); page_id_ = next_page_id_++; } else if (extra_data && extra_data->pending_page_id != -1 && !extra_data->request_committed) { // This is a successful session history navigation! UpdateSessionHistory(frame); page_id_ = extra_data->pending_page_id; } // Don't update session history multiple times. if (extra_data) extra_data->request_committed = true; UpdateURL(frame); } void BrowserWebViewDelegate::UpdateURL(WebFrame* frame) { WebDataSource* ds = frame->dataSource(); DCHECK(ds); const WebURLRequest& request = ds->request(); BrowserNavigationController* controller = browser_->UIT_GetNavigationController(); if (controller->GetEntryCount() == 0) { // This is the first navigation for the browser. Indicate that the browser // now has a document. browser_->set_has_document(true); } // Type is unused. scoped_ptr entry(new BrowserNavigationEntry); // Bug 654101: the referrer will be empty on https->http transitions. It // would be nice if we could get the real referrer from somewhere. entry->SetPageID(page_id_); if (ds->hasUnreachableURL()) { entry->SetURL(ds->unreachableURL()); } else { entry->SetURL(request.url()); } bool is_main_frame = (frame->parent() == 0); CefRefPtr client = browser_->GetClient(); if (is_main_frame && client.get()) { CefRefPtr handler = client->GetDisplayHandler(); if (handler.get()) { // Notify the handler of an address change std::string url = std::string(entry->GetURL().spec().c_str()); handler->OnAddressChange(browser_, browser_->UIT_GetCefFrame(frame), url); } } const WebHistoryItem& history_item = frame->currentHistoryItem(); if (!history_item.isNull()) entry->SetContentState(webkit_glue::HistoryItemToString(history_item)); bool old_can_go_back = !controller->IsAtStart(); bool old_can_go_forward = !controller->IsAtEnd(); controller->DidNavigateToEntry(entry.release()); bool new_can_go_back = !controller->IsAtStart(); bool new_can_go_forward = !controller->IsAtEnd(); last_page_id_updated_ = std::max(last_page_id_updated_, page_id_); if (old_can_go_back != new_can_go_back || old_can_go_forward != new_can_go_forward) { browser_->set_nav_state(new_can_go_back, new_can_go_forward); CefRefPtr handler = client->GetDisplayHandler(); if (handler.get()) { // Notify the handler of a navigation state change handler->OnNavStateChange(browser_, new_can_go_back, new_can_go_forward); } } } void BrowserWebViewDelegate::UpdateSessionHistory(WebFrame* frame) { // If we have a valid page ID at this point, then it corresponds to the page // we are navigating away from. Otherwise, this is the first navigation, so // there is no past session history to record. if (page_id_ == -1) return; BrowserNavigationEntry* entry = static_cast( browser_->UIT_GetNavigationController()->GetEntryWithPageID(page_id_)); if (!entry) return; WebView* view = browser_->UIT_GetWebView(); if (!view) return; const WebHistoryItem& history_item = view->mainFrame()->previousHistoryItem(); if (history_item.isNull()) return; entry->SetContentState(webkit_glue::HistoryItemToString(history_item)); } bool BrowserWebViewDelegate::OnBeforeMenu( const WebKit::WebContextMenuData& data, int mouse_x, int mouse_y, int& edit_flags, int& type_flags) { // Populate the edit flags values. edit_flags = data.editFlags; if(browser_->UIT_CanGoBack()) edit_flags |= MENU_CAN_GO_BACK; if(browser_->UIT_CanGoForward()) edit_flags |= MENU_CAN_GO_FORWARD; // Populate the type flags values. type_flags = MENUTYPE_NONE; if(!data.pageURL.isEmpty()) type_flags |= MENUTYPE_PAGE; if(!data.frameURL.isEmpty()) type_flags |= MENUTYPE_FRAME; if(!data.linkURL.isEmpty()) type_flags |= MENUTYPE_LINK; if(data.mediaType == WebContextMenuData::MediaTypeImage) type_flags |= MENUTYPE_IMAGE; if(!data.selectedText.isEmpty()) type_flags |= MENUTYPE_SELECTION; if(data.isEditable) type_flags |= MENUTYPE_EDITABLE; if(data.isSpellCheckingEnabled && !data.misspelledWord.isEmpty()) type_flags |= MENUTYPE_MISSPELLED_WORD; if(data.mediaType == WebContextMenuData::MediaTypeVideo) type_flags |= MENUTYPE_VIDEO; if(data.mediaType == WebContextMenuData::MediaTypeAudio) type_flags |= MENUTYPE_AUDIO; CefRefPtr client = browser_->GetClient(); CefRefPtr handler; if (client.get()) handler = client->GetMenuHandler(); if (handler.get()) { // Gather menu information. cef_handler_menuinfo_t menuInfo; memset(&menuInfo, 0, sizeof(menuInfo)); CefString linkStr(std::string(data.linkURL.spec())); CefString imageStr(std::string(data.srcURL.spec())); CefString pageStr(std::string(data.pageURL.spec())); CefString frameStr(std::string(data.frameURL.spec())); CefString selectedTextStr(string16(data.selectedText)); CefString misspelledWordStr(string16(data.misspelledWord)); CefString securityInfoStr(std::string(data.securityInfo)); menuInfo.typeFlags = type_flags; menuInfo.x = mouse_x; menuInfo.y = mouse_y; cef_string_set(linkStr.c_str(), linkStr.length(), &menuInfo.linkUrl, false); cef_string_set(imageStr.c_str(), imageStr.length(), &menuInfo.imageUrl, false); cef_string_set(pageStr.c_str(), pageStr.length(), &menuInfo.pageUrl, false); cef_string_set(frameStr.c_str(), frameStr.length(), &menuInfo.frameUrl, false); cef_string_set(selectedTextStr.c_str(), selectedTextStr.length(), &menuInfo.selectionText, false); cef_string_set(misspelledWordStr.c_str(), misspelledWordStr.length(), &menuInfo.misspelledWord, false); menuInfo.editFlags = edit_flags; cef_string_set(securityInfoStr.c_str(), securityInfoStr.length(), &menuInfo.securityInfo, false); // Notify the handler that a context menu is requested. if (handler->OnBeforeMenu(browser_, menuInfo)) return true; } return false; }