// Copyright (c) 2012 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. #include "libcef/browser_impl.h" #include "libcef/browser_devtools_scheme_handler.h" #include "libcef/browser_webkit_glue.h" #include "libcef/browser_zoom_map.h" #include "libcef/cef_context.h" #include "libcef/dom_document_impl.h" #include "libcef/request_impl.h" #include "libcef/stream_impl.h" #include "libcef/v8_impl.h" #include "base/bind.h" #include "base/files/file_path.h" #include "base/path_service.h" #include "base/stringprintf.h" #include "base/synchronization/waitable_event.h" #include "base/utf_string_conversions.h" #include "third_party/WebKit/Source/Platform/chromium/public/WebHTTPBody.h" #include "third_party/WebKit/Source/Platform/chromium/public/WebRect.h" #include "third_party/WebKit/Source/Platform/chromium/public/WebString.h" #include "third_party/WebKit/Source/Platform/chromium/public/WebURL.h" #include "third_party/WebKit/Source/Platform/chromium/public/WebURLRequest.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebPlugin.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebPluginDocument.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebRange.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebScriptSource.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h" #include "webkit/glue/glue_serialize.h" #include "webkit/plugins/npapi/webplugin_delegate.h" #include "webkit/plugins/npapi/webplugin_impl.h" #include "webkit/glue/webkit_glue.h" using WebKit::WebDocument; using WebKit::WebFrame; using WebKit::WebHTTPBody; using WebKit::WebPlugin; using WebKit::WebPluginDocument; using WebKit::WebRange; using WebKit::WebRect; using WebKit::WebScriptSource; using WebKit::WebString; using WebKit::WebURL; using WebKit::WebURLRequest; using WebKit::WebView; namespace { class CreateBrowserHelper { public: CreateBrowserHelper(CefWindowInfo& windowInfo, CefRefPtr client, const CefString& url, const CefBrowserSettings& settings) : window_info_(windowInfo), client_(client), url_(url), settings_(settings) {} CefWindowInfo window_info_; CefRefPtr client_; CefString url_; CefBrowserSettings settings_; }; void UIT_CreateBrowserWithHelper(CreateBrowserHelper* helper) { CefBrowser::CreateBrowserSync(helper->window_info_, helper->client_, helper->url_, helper->settings_); delete helper; } } // namespace CefBrowserImpl::PaintDelegate::PaintDelegate(CefBrowserImpl* browser) : browser_(browser) { } CefBrowserImpl::PaintDelegate::~PaintDelegate() { } void CefBrowserImpl::PaintDelegate::Paint( bool popup, const std::vector& dirtyRects, const void* buffer) { CefRefPtr client = browser_->GetClient(); if (!client.get()) return; CefRefPtr handler = client->GetRenderHandler(); if (!handler.get()) return; handler->OnPaint(browser_, (popup?PET_POPUP:PET_VIEW), dirtyRects, buffer); } // static bool CefBrowser::CreateBrowser(CefWindowInfo& windowInfo, CefRefPtr client, const CefString& url, const CefBrowserSettings& settings) { // Verify that the context is in a valid state. if (!CONTEXT_STATE_VALID()) { NOTREACHED() << "context not valid"; return false; } // Verify that the settings structure is a valid size. if (settings.size != sizeof(cef_browser_settings_t)) { NOTREACHED() << "invalid CefBrowserSettings structure size"; return false; } // Create the browser on the UI thread. CreateBrowserHelper* helper = new CreateBrowserHelper(windowInfo, client, url, settings); CefThread::PostTask(CefThread::UI, FROM_HERE, base::Bind(UIT_CreateBrowserWithHelper, helper)); return true; } // static CefRefPtr CefBrowser::CreateBrowserSync( CefWindowInfo& windowInfo, CefRefPtr client, const CefString& url, const CefBrowserSettings& settings) { // Verify that the context is in a valid state. if (!CONTEXT_STATE_VALID()) { NOTREACHED() << "context not valid"; return NULL; } // Verify that the settings structure is a valid size. if (settings.size != sizeof(cef_browser_settings_t)) { NOTREACHED() << "invalid CefBrowserSettings structure size"; return NULL; } // Verify that this method is being called on the UI thread. if (!CefThread::CurrentlyOn(CefThread::UI)) { NOTREACHED() << "called on invalid thread"; return NULL; } CefRefPtr browser( new CefBrowserImpl(windowInfo, settings, NULL, client)); if (!static_cast(browser.get())->UIT_CreateBrowser(url)) return NULL; return browser; } CefBrowserImpl::CefBrowserImpl(const CefWindowInfo& windowInfo, const CefBrowserSettings& settings, gfx::NativeView opener, CefRefPtr client) : window_info_(windowInfo), settings_(settings), opener_(opener), is_modal_(false), client_(client), webviewhost_(NULL), popuphost_(NULL), zoom_level_(0.0), can_go_back_(false), can_go_forward_(false), has_document_(false), is_dropping_(false), is_in_onsetfocus_(false), #if defined(OS_WIN) opener_was_disabled_by_modal_loop_(false), internal_modal_message_loop_is_active_(false), #elif defined(OS_LINUX) last_mouse_down_(NULL), #endif browser_id_(_Context->GetNextBrowserID()) { delegate_.reset(new BrowserWebViewDelegate(this)); popup_delegate_.reset(new BrowserWebViewDelegate(this)); nav_controller_.reset(new BrowserNavigationController(this)); // Create the singleton main frame reference. main_frame_ = new CefFrameImpl(this, 0, CefString(), CefString()); } void CefBrowserImpl::CloseBrowser() { CefThread::PostTask(CefThread::UI, FROM_HERE, base::Bind(&CefBrowserImpl::UIT_CloseBrowser, this)); } void CefBrowserImpl::GoBack() { CefThread::PostTask(CefThread::UI, FROM_HERE, base::Bind(&CefBrowserImpl::UIT_HandleActionView, this, MENU_ID_NAV_BACK)); } void CefBrowserImpl::GoForward() { CefThread::PostTask(CefThread::UI, FROM_HERE, base::Bind(&CefBrowserImpl::UIT_HandleActionView, this, MENU_ID_NAV_FORWARD)); } void CefBrowserImpl::Reload() { CefThread::PostTask(CefThread::UI, FROM_HERE, base::Bind(&CefBrowserImpl::UIT_HandleActionView, this, MENU_ID_NAV_RELOAD)); } void CefBrowserImpl::ReloadIgnoreCache() { CefThread::PostTask(CefThread::UI, FROM_HERE, base::Bind(&CefBrowserImpl::UIT_HandleActionView, this, MENU_ID_NAV_RELOAD_NOCACHE)); } void CefBrowserImpl::StopLoad() { CefThread::PostTask(CefThread::UI, FROM_HERE, base::Bind(&CefBrowserImpl::UIT_HandleActionView, this, MENU_ID_NAV_STOP)); } void CefBrowserImpl::SetFocus(bool enable) { if (CefThread::CurrentlyOn(CefThread::UI)) { // If SetFocus() is called from inside the OnSetFocus() callback do not re- // enter the callback. if (enable && !is_in_onsetfocus_) { WebViewHost* host = UIT_GetWebViewHost(); if (host) { CefRefPtr client = GetClient(); if (client.get()) { CefRefPtr handler = client->GetFocusHandler(); if (handler.get()) { is_in_onsetfocus_ = true; bool handled = handler->OnSetFocus(this, FOCUS_SOURCE_SYSTEM); is_in_onsetfocus_ = false; if (handled) return; } } } } UIT_SetFocus(UIT_GetWebViewHost(), enable); } else { CefThread::PostTask(CefThread::UI, FROM_HERE, base::Bind(&CefBrowserImpl::SetFocus, this, enable)); } } CefRefPtr CefBrowserImpl::GetMainFrame() { return GetMainCefFrame(0, GURL()).get(); } CefRefPtr CefBrowserImpl::GetFocusedFrame() { // Verify that this method is being called on the UI thread. if (!CefThread::CurrentlyOn(CefThread::UI)) { NOTREACHED() << "called on invalid thread"; return NULL; } WebView* view = UIT_GetWebView(); return view ? UIT_GetCefFrame(view->focusedFrame()) : NULL; } CefRefPtr CefBrowserImpl::GetFrame(const CefString& name) { // Verify that this method is being called on the UI thread. if (!CefThread::CurrentlyOn(CefThread::UI)) { NOTREACHED() << "called on invalid thread"; return NULL; } WebView* view = UIT_GetWebView(); if (!view) return NULL; WebFrame* frame = view->findFrameByName(string16(name)); if (frame) return UIT_GetCefFrame(frame); return NULL; } void CefBrowserImpl::GetFrameNames(std::vector& names) { // Verify that this method is being called on the UI thread. if (!CefThread::CurrentlyOn(CefThread::UI)) { NOTREACHED() << "called on invalid thread"; return; } WebView* view = UIT_GetWebView(); if (!view) return; WebFrame* main_frame = view->mainFrame(); WebFrame* it = main_frame; do { if (it != main_frame) { string16 str = it->uniqueName(); names.push_back(str); } it = it->traverseNext(true); } while (it != main_frame); } void CefBrowserImpl::Find(int identifier, const CefString& searchText, bool forward, bool matchCase, bool findNext) { WebKit::WebFindOptions options; options.forward = forward; options.matchCase = matchCase; options.findNext = findNext; // Execute the request on the UI thread. CefThread::PostTask(CefThread::UI, FROM_HERE, base::Bind(&CefBrowserImpl::UIT_Find, this, identifier, searchText, options)); } void CefBrowserImpl::StopFinding(bool clearSelection) { // Execute the request on the UI thread. CefThread::PostTask(CefThread::UI, FROM_HERE, base::Bind(&CefBrowserImpl::UIT_StopFinding, this, clearSelection)); } void CefBrowserImpl::SetZoomLevel(double zoomLevel) { CefThread::PostTask(CefThread::UI, FROM_HERE, base::Bind(&CefBrowserImpl::UIT_SetZoomLevel, this, zoomLevel)); } void CefBrowserImpl::ClearHistory() { if (CefThread::CurrentlyOn(CefThread::UI)) { if (!nav_controller_.get()) return; bool old_can_go_back = !nav_controller_->IsAtStart(); bool old_can_go_forward = !nav_controller_->IsAtEnd(); nav_controller_->Reset(); if (old_can_go_back || old_can_go_forward) { set_nav_state(false, false); if (client_.get()) { CefRefPtr handler = client_->GetDisplayHandler(); if (handler.get()) { // Notify the handler of a navigation state change handler->OnNavStateChange(this, false, false); } } } } else { CefThread::PostTask(CefThread::UI, FROM_HERE, base::Bind(&CefBrowserImpl::ClearHistory, this)); } } void CefBrowserImpl::ShowDevTools() { CefThread::PostTask(CefThread::UI, FROM_HERE, base::Bind(&CefBrowserImpl::UIT_ShowDevTools, this)); } void CefBrowserImpl::CloseDevTools() { CefThread::PostTask(CefThread::UI, FROM_HERE, base::Bind(&CefBrowserImpl::UIT_CloseDevTools, this)); } WebKit::WebGeolocationClient* CefBrowserImpl::UIT_GetGeolocationClient() { if (!geolocation_client_) geolocation_client_ = new CefGeolocationClient(this); return geolocation_client_; } bool CefBrowserImpl::GetSize(PaintElementType type, int& width, int& height) { if (!CefThread::CurrentlyOn(CefThread::UI)) { NOTREACHED() << "called on invalid thread"; return false; } width = height = 0; if (type == PET_VIEW) { WebViewHost* host = UIT_GetWebViewHost(); if (host) { host->GetSize(width, height); return true; } } else if (type == PET_POPUP) { if (popuphost_) { popuphost_->GetSize(width, height); return true; } } return false; } void CefBrowserImpl::SetSize(PaintElementType type, int width, int height) { // Intentially post event tasks in all cases so that painting tasks can be // handled at sane times. CefThread::PostTask(CefThread::UI, FROM_HERE, base::Bind(&CefBrowserImpl::UIT_SetSize, this, type, width, height)); } bool CefBrowserImpl::IsPopupVisible() { if (!CefThread::CurrentlyOn(CefThread::UI)) { NOTREACHED() << "called on invalid thread"; return false; } return (popuphost_ != NULL); } void CefBrowserImpl::HidePopup() { // Intentially post event tasks in all cases so that painting tasks can be // handled at sane times. CefThread::PostTask(CefThread::UI, FROM_HERE, base::Bind(&CefBrowserImpl::UIT_ClosePopupWidget, this)); } void CefBrowserImpl::Invalidate(const CefRect& dirtyRect) { // Intentially post event tasks in all cases so that painting tasks can be // handled at sane times. CefThread::PostTask(CefThread::UI, FROM_HERE, base::Bind(&CefBrowserImpl::UIT_Invalidate, this, dirtyRect)); } bool CefBrowserImpl::GetImage(PaintElementType type, int width, int height, void* buffer) { if (!CefThread::CurrentlyOn(CefThread::UI)) { NOTREACHED() << "called on invalid thread"; return false; } if (type == PET_VIEW) { WebViewHost* host = UIT_GetWebViewHost(); if (host) return host->GetImage(width, height, buffer); } else if (type == PET_POPUP) { if (popuphost_) return popuphost_->GetImage(width, height, buffer); } return false; } void CefBrowserImpl::SendKeyEvent(KeyType type, const CefKeyInfo& keyInfo, int modifiers) { // Intentially post event tasks in all cases so that painting tasks can be // handled at sane times. CefThread::PostTask(CefThread::UI, FROM_HERE, base::Bind(&CefBrowserImpl::UIT_SendKeyEvent, this, type, keyInfo, modifiers)); } void CefBrowserImpl::SendMouseClickEvent(int x, int y, MouseButtonType type, bool mouseUp, int clickCount) { // Intentially post event tasks in all cases so that painting tasks can be // handled at sane times. CefThread::PostTask(CefThread::UI, FROM_HERE, base::Bind(&CefBrowserImpl::UIT_SendMouseClickEvent, this, x, y, type, mouseUp, clickCount)); } void CefBrowserImpl::SendMouseMoveEvent(int x, int y, bool mouseLeave) { // Intentially post event tasks in all cases so that painting tasks can be // handled at sane times. CefThread::PostTask(CefThread::UI, FROM_HERE, base::Bind(&CefBrowserImpl::UIT_SendMouseMoveEvent, this, x, y, mouseLeave)); } void CefBrowserImpl::SendMouseWheelEvent(int x, int y, int deltaX, int deltaY) { // Intentially post event tasks in all cases so that painting tasks can be // handled at sane times. CefThread::PostTask(CefThread::UI, FROM_HERE, base::Bind(&CefBrowserImpl::UIT_SendMouseWheelEvent, this, x, y, deltaX, deltaY)); } void CefBrowserImpl::SendFocusEvent(bool setFocus) { // Intentially post event tasks in all cases so that painting tasks can be // handled at sane times. CefThread::PostTask(CefThread::UI, FROM_HERE, base::Bind(&CefBrowserImpl::UIT_SendFocusEvent, this, setFocus)); } void CefBrowserImpl::SendCaptureLostEvent() { // Intentially post event tasks in all cases so that painting tasks can be // handled at sane times. CefThread::PostTask(CefThread::UI, FROM_HERE, base::Bind(&CefBrowserImpl::UIT_SendCaptureLostEvent, this)); } void CefBrowserImpl::Undo(CefRefPtr frame) { CefThread::PostTask(CefThread::UI, FROM_HERE, base::Bind(&CefBrowserImpl::UIT_HandleAction, this, MENU_ID_UNDO, frame)); } void CefBrowserImpl::Redo(CefRefPtr frame) { CefThread::PostTask(CefThread::UI, FROM_HERE, base::Bind(&CefBrowserImpl::UIT_HandleAction, this, MENU_ID_REDO, frame)); } void CefBrowserImpl::Cut(CefRefPtr frame) { CefThread::PostTask(CefThread::UI, FROM_HERE, base::Bind(&CefBrowserImpl::UIT_HandleAction, this, MENU_ID_CUT, frame)); } void CefBrowserImpl::Copy(CefRefPtr frame) { CefThread::PostTask(CefThread::UI, FROM_HERE, base::Bind(&CefBrowserImpl::UIT_HandleAction, this, MENU_ID_COPY, frame)); } void CefBrowserImpl::Paste(CefRefPtr frame) { CefThread::PostTask(CefThread::UI, FROM_HERE, base::Bind(&CefBrowserImpl::UIT_HandleAction, this, MENU_ID_PASTE, frame)); } void CefBrowserImpl::Delete(CefRefPtr frame) { CefThread::PostTask(CefThread::UI, FROM_HERE, base::Bind(&CefBrowserImpl::UIT_HandleAction, this, MENU_ID_DELETE, frame)); } void CefBrowserImpl::SelectAll(CefRefPtr frame) { CefThread::PostTask(CefThread::UI, FROM_HERE, base::Bind(&CefBrowserImpl::UIT_HandleAction, this, MENU_ID_SELECTALL, frame)); } void CefBrowserImpl::Print(CefRefPtr frame) { CefThread::PostTask(CefThread::UI, FROM_HERE, base::Bind(&CefBrowserImpl::UIT_HandleAction, this, MENU_ID_PRINT, frame)); } void CefBrowserImpl::ViewSource(CefRefPtr frame) { CefThread::PostTask(CefThread::UI, FROM_HERE, base::Bind(&CefBrowserImpl::UIT_HandleAction, this, MENU_ID_VIEWSOURCE, frame)); } CefString CefBrowserImpl::GetSource(CefRefPtr frame) { // Verify that this method is being called on the UI thread. if (!CefThread::CurrentlyOn(CefThread::UI)) { NOTREACHED() << "called on invalid thread"; return CefString(); } // Retrieve the document string directly WebKit::WebFrame* web_frame = UIT_GetWebFrame(frame); if (web_frame) return string16(web_frame->contentAsMarkup()); return CefString(); } CefString CefBrowserImpl::GetText(CefRefPtr frame) { // Verify that this method is being called on the UI thread. if (!CefThread::CurrentlyOn(CefThread::UI)) { NOTREACHED() << "called on invalid thread"; return CefString(); } // Retrieve the document text directly WebKit::WebFrame* web_frame = UIT_GetWebFrame(frame); if (web_frame) return webkit_glue::DumpDocumentText(web_frame); return CefString(); } void CefBrowserImpl::LoadRequest(CefRefPtr frame, CefRefPtr request) { DCHECK(request.get() != NULL); CefThread::PostTask(CefThread::UI, FROM_HERE, base::Bind(&CefBrowserImpl::UIT_LoadURLForRequestRef, this, frame, request)); } void CefBrowserImpl::LoadURL(CefRefPtr frame, const CefString& url) { CefThread::PostTask(CefThread::UI, FROM_HERE, base::Bind(&CefBrowserImpl::UIT_LoadURL, this, frame, url)); } void CefBrowserImpl::LoadString(CefRefPtr frame, const CefString& string, const CefString& url) { CefThread::PostTask(CefThread::UI, FROM_HERE, base::Bind(&CefBrowserImpl::UIT_LoadHTML, this, frame, string, url)); } void CefBrowserImpl::LoadStream(CefRefPtr frame, CefRefPtr stream, const CefString& url) { DCHECK(stream.get() != NULL); CefThread::PostTask(CefThread::UI, FROM_HERE, base::Bind(&CefBrowserImpl::UIT_LoadHTMLForStreamRef, this, frame, stream, url)); } void CefBrowserImpl::ExecuteJavaScript(CefRefPtr frame, const CefString& jsCode, const CefString& scriptUrl, int startLine) { CefThread::PostTask(CefThread::UI, FROM_HERE, base::Bind(&CefBrowserImpl::UIT_ExecuteJavaScript, this, frame, jsCode, scriptUrl, startLine)); } CefRefPtr CefBrowserImpl::GetParent(CefRefPtr frame) { // Verify that this method is being called on the UI thread. if (!CefThread::CurrentlyOn(CefThread::UI)) { NOTREACHED() << "called on invalid thread"; return NULL; } WebFrame* web_frame = UIT_GetWebFrame(frame); if (web_frame) { if (web_frame->parent() == NULL) { // This is the main frame. return NULL; } return UIT_GetCefFrame(web_frame->parent()); } return NULL; } CefRefPtr CefBrowserImpl::GetCefFrame(int64 id) { AutoLock lock_scope(this); FrameMap::const_iterator it = frames_.find(id); if (it != frames_.end()) return it->second; return NULL; } CefRefPtr CefBrowserImpl::GetOrCreateCefFrame( int64 id, const CefString& name, const GURL& url) { CefRefPtr cef_frame; if (name.empty()) { // Use the single main frame reference. cef_frame = GetMainCefFrame(id, url); } else { // Locate or create the appropriate named reference. AutoLock lock_scope(this); FrameMap::const_iterator it = frames_.find(id); if (it != frames_.end()) { cef_frame = it->second; cef_frame->set_url(url.spec()); } else { cef_frame = new CefFrameImpl(this, id, name, url.spec()); frames_.insert(std::make_pair(id, cef_frame.get())); } } return cef_frame; } void CefBrowserImpl::RemoveCefFrame(int64 id) { AutoLock lock_scope(this); // Remove the appropriate reference. FrameMap::iterator it = frames_.find(id); if (it != frames_.end()) frames_.erase(it); } CefRefPtr CefBrowserImpl::GetMainCefFrame(int64 id, const GURL& url) { if (id != 0) main_frame_->set_id(id); if (!url.is_empty()) main_frame_->set_url(url.spec()); return main_frame_; } CefRefPtr CefBrowserImpl::UIT_GetCefFrame(WebFrame* frame) { REQUIRE_UIT(); CefRefPtr cef_frame; GURL url = frame->document().url(); if (frame->parent() == 0) { // Use the single main frame reference. cef_frame = GetMainCefFrame(frame->identifier(), url); } else { // Locate or create the appropriate reference. CefString name = string16(frame->uniqueName()); DCHECK(!name.empty()); cef_frame = GetOrCreateCefFrame(frame->identifier(), name, url); } return cef_frame.get(); } void CefBrowserImpl::UIT_UpdateCefFrame(WebKit::WebFrame* frame) { REQUIRE_UIT(); GURL url = frame->document().url(); if (frame->parent() == 0) { // Update the single main frame reference. GetMainCefFrame(frame->identifier(), url); } else { // Update the appropriate reference if it currently exists. CefRefPtr cef_frame = GetCefFrame(frame->identifier()); if (cef_frame.get()) cef_frame->set_url(url.spec()); } } WebFrame* CefBrowserImpl::UIT_GetMainWebFrame() { REQUIRE_UIT(); WebView* view = UIT_GetWebView(); if (view) return view ->mainFrame(); return NULL; } WebFrame* CefBrowserImpl::UIT_GetWebFrame(CefRefPtr frame) { REQUIRE_UIT(); WebView* view = UIT_GetWebView(); if (!view) return NULL; CefString name = frame->GetName(); if (name.empty()) return view ->mainFrame(); return view ->findFrameByName(string16(name)); } void CefBrowserImpl::UIT_DestroyBrowser() { if (client_.get()) { CefRefPtr handler = client_->GetLifeSpanHandler(); if (handler.get()) { // Notify the handler that the window is about to be closed. handler->OnBeforeClose(this); } } #if defined(OS_WIN) if (is_modal_) { // Exit our own internal modal message loop now. if (internal_modal_message_loop_is_active_) { MessageLoop* message_loop = MessageLoop::current(); message_loop->QuitNow(); } } UIT_GetWebViewDelegate()->RevokeDragDrop(); #endif // If the current browser window is a dev tools client then disconnect from // the agent and destroy the client before destroying the window. UIT_DestroyDevToolsClient(); if (dev_tools_agent_.get()) { BrowserDevToolsClient* client = dev_tools_agent_->client(); if (client) { CefBrowserImpl* browser = client->browser(); // Destroy the client before freeing the agent. browser->UIT_DestroyDevToolsClient(); if (!_Context->shutting_down()) { // Explicitly close the client browser window. browser->UIT_CloseBrowser(); } } // Free the agent. dev_tools_agent_.reset(); } if (frame_objects_.size() > 0) frame_objects_.clear(); // Clean up anything associated with the WebViewHost widget. if (webviewhost_.get()) { if (webviewhost_->webwidget()) webviewhost_->webwidget()->close(); webviewhost_.reset(); } delegate_.reset(NULL); popup_delegate_.reset(NULL); nav_controller_.reset(NULL); if (paint_delegate_.get()) paint_delegate_.reset(NULL); // Remove the reference to the window handle. UIT_ClearMainWndHandle(); main_frame_ = NULL; #if defined(OS_LINUX) set_last_mouse_down(NULL); #endif if (request_context_proxy_.get()) { // Delete the proxy on the IO thread. CefThread::DeleteSoon(CefThread::IO, FROM_HERE, request_context_proxy_.release()); } // Remove the browser from the list maintained by the context. _Context->RemoveBrowser(this); // Remove the reference added in UIT_CreateBrowser(). Release(); } void CefBrowserImpl::UIT_CloseBrowser() { REQUIRE_UIT(); if (IsWindowRenderingDisabled()) { UIT_DestroyBrowser(); } else { gfx::NativeView view = UIT_GetMainWndHandle(); if (view) UIT_CloseView(view); } } void CefBrowserImpl::UIT_LoadURL(CefRefPtr frame, const CefString& url) { UIT_LoadURLForRequest(frame, url, CefString(), WebHTTPBody(), CefRequest::HeaderMap()); } void CefBrowserImpl::UIT_LoadURLForRequestRef(CefRefPtr frame, CefRefPtr request) { CefString url = request->GetURL(); CefString method = request->GetMethod(); CefRequestImpl* impl = static_cast(request.get()); WebHTTPBody upload_data; CefRefPtr postdata = impl->GetPostData(); if (postdata.get()) { upload_data.initialize(); static_cast(postdata.get())->Get(upload_data); } CefRequest::HeaderMap headers; impl->GetHeaderMap(headers); UIT_LoadURLForRequest(frame, url, method, upload_data, headers); } void CefBrowserImpl::UIT_LoadURLForRequest( CefRefPtr frame, const CefString& url, const CefString& method, const WebKit::WebHTTPBody& upload_data, const CefRequest::HeaderMap& headers) { REQUIRE_UIT(); if (url.empty()) return; std::string urlStr(url); GURL gurl = GURL(urlStr); if (!gurl.is_valid() && !gurl.has_scheme()) { // Try to add "http://" at the beginning std::string new_url = std::string("http://") + urlStr; gurl = GURL(new_url); if (!gurl.is_valid()) return; } if (nav_controller_.get()) { nav_controller_->LoadEntry( new BrowserNavigationEntry(-1, gurl, CefString(), frame->GetName(), method, upload_data, headers)); } } void CefBrowserImpl::UIT_LoadHTML(CefRefPtr frame, const CefString& html, const CefString& url) { REQUIRE_UIT(); std::string urlStr(url); GURL gurl = GURL(urlStr); if (!gurl.is_valid() && !gurl.has_scheme()) { // Try to add "http://" at the beginning std::string new_url = std::string("http://") + urlStr; gurl = GURL(new_url); if (!gurl.is_valid()) return; } WebFrame* web_frame = UIT_GetWebFrame(frame); if (web_frame) web_frame->loadHTMLString(std::string(html), gurl); } void CefBrowserImpl::UIT_LoadHTMLForStreamRef(CefRefPtr frame, CefRefPtr stream, const CefString& url) { REQUIRE_UIT(); std::string urlStr(url); GURL gurl = GURL(urlStr); if (!gurl.is_valid() && !gurl.has_scheme()) { // Try to add "http://" at the beginning std::string new_url = std::string("http://") + urlStr; gurl = GURL(new_url); if (!gurl.is_valid()) return; } // read all of the stream data into a std::string. std::stringstream ss; char buff[BUFFER_SIZE]; size_t read; do { read = stream->Read(buff, sizeof(char), BUFFER_SIZE-1); if (read > 0) { buff[read] = 0; ss << buff; } } while (read > 0); WebFrame* web_frame = UIT_GetWebFrame(frame); if (web_frame) web_frame->loadHTMLString(ss.str(), gurl); } void CefBrowserImpl::UIT_ExecuteJavaScript(CefRefPtr frame, const CefString& js_code, const CefString& script_url, int start_line) { REQUIRE_UIT(); WebFrame* web_frame = UIT_GetWebFrame(frame); if (web_frame) { web_frame->executeScript(WebScriptSource(string16(js_code), WebURL(GURL(std::string(script_url))), start_line)); } } void CefBrowserImpl::UIT_GoBackOrForward(int offset) { REQUIRE_UIT(); if (nav_controller_.get()) nav_controller_->GoToOffset(offset); } void CefBrowserImpl::UIT_Reload(bool ignoreCache) { REQUIRE_UIT(); if (nav_controller_.get()) nav_controller_->Reload(ignoreCache); } bool CefBrowserImpl::UIT_Navigate(const BrowserNavigationEntry& entry, bool reload, bool ignoreCache) { REQUIRE_UIT(); WebView* view = UIT_GetWebView(); if (!view) return false; // Get the right target frame for the entry. WebFrame* frame; if (!entry.GetTargetFrame().empty()) frame = view->findFrameByName(string16(entry.GetTargetFrame())); else frame = view->mainFrame(); // TODO(mpcomplete): should we clear the target frame, or should // back/forward navigations maintain the target frame? // A navigation resulting from loading a javascript URL should not be // treated as a browser initiated event. Instead, we want it to look as if // the page initiated any load resulting from JS execution. if (!entry.GetURL().SchemeIs("javascript")) { delegate_->set_pending_extra_data( new BrowserExtraData(entry.GetPageID())); } // If we are reloading, then WebKit will use the state of the current page. // Otherwise, we give it the state to navigate to. if (reload) { frame->reload(ignoreCache); } else if (!entry.GetContentState().empty()) { DCHECK_NE(entry.GetPageID(), -1); frame->loadHistoryItem( webkit_glue::HistoryItemFromString(entry.GetContentState())); } else { DCHECK_EQ(entry.GetPageID(), -1); WebURLRequest request(entry.GetURL()); if (entry.GetMethod().length() > 0) request.setHTTPMethod(string16(entry.GetMethod())); if (entry.GetHeaders().size() > 0) CefRequestImpl::SetHeaderMap(entry.GetHeaders(), request); if (!entry.GetUploadData().isNull()) { string16 method = request.httpMethod(); if (method == ASCIIToUTF16("GET") || method == ASCIIToUTF16("HEAD")) request.setHTTPMethod(ASCIIToUTF16("POST")); if (request.httpHeaderField(ASCIIToUTF16("Content-Type")).length() == 0) { request.setHTTPHeaderField( ASCIIToUTF16("Content-Type"), ASCIIToUTF16("application/x-www-form-urlencoded")); } request.setHTTPBody(entry.GetUploadData()); } frame->loadRequest(request); } // In case LoadRequest failed before DidCreateDataSource was called. delegate_->set_pending_extra_data(NULL); if (client_.get()) { CefRefPtr handler = client_->GetFocusHandler(); if (!handler.get() || (handler.get() && !handler->OnSetFocus(this, FOCUS_SOURCE_NAVIGATION))) { // Restore focus to the main frame prior to loading new request. // This makes sure that we don't have a focused iframe. Otherwise, that // iframe would keep focus when the SetFocus called immediately after // LoadRequest, thus making some tests fail (see http://b/issue?id=845337 // for more details). // TODO(cef): The above comment may be wrong, or the below call to // setFocusedFrame() may be unnecessary or in the wrong place. See this // thread for additional details: // http://groups.google.com/group/chromium-dev/browse_thread/thread/42bcd31b59e3a168 view->setFocusedFrame(frame); // Give focus to the window if it is currently visible. if (!IsWindowRenderingDisabled() && UIT_IsViewVisible(UIT_GetMainWndHandle())) UIT_SetFocus(UIT_GetWebViewHost(), true); } } return true; } void CefBrowserImpl::UIT_SetSize(PaintElementType type, int width, int height) { if (type == PET_VIEW) { WebViewHost* host = UIT_GetWebViewHost(); if (host) host->SetSize(width, height); } else if (type == PET_POPUP) { if (popuphost_) popuphost_->SetSize(width, height); } } void CefBrowserImpl::UIT_Invalidate(const CefRect& dirtyRect) { REQUIRE_UIT(); WebViewHost* host = UIT_GetWebViewHost(); if (host) { gfx::Rect rect(dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height); // Cause WebWidget::Paint() to be called when next appropriate. host->InvalidateRect(rect); } } void CefBrowserImpl::UIT_SendKeyEvent(KeyType type, const CefKeyInfo& keyInfo, int modifiers) { REQUIRE_UIT(); if (popuphost_) { // Send the event to the popup. popuphost_->SendKeyEvent(type, keyInfo, modifiers); } else { WebViewHost* host = UIT_GetWebViewHost(); if (host) host->SendKeyEvent(type, keyInfo, modifiers); } } void CefBrowserImpl::UIT_SendMouseClickEvent(int x, int y, MouseButtonType type, bool mouseUp, int clickCount) { REQUIRE_UIT(); if (popuphost_ && popup_rect_.Contains(x, y)) { // Send the event to the popup. popuphost_->SendMouseClickEvent(x - popup_rect_.x(), y - popup_rect_.y(), type, mouseUp, clickCount); } else { WebViewHost* host = UIT_GetWebViewHost(); if (host) host->SendMouseClickEvent(x, y, type, mouseUp, clickCount); } } void CefBrowserImpl::UIT_SendMouseMoveEvent(int x, int y, bool mouseLeave) { REQUIRE_UIT(); if (popuphost_ && popup_rect_.Contains(x, y)) { // Send the event to the popup. popuphost_->SendMouseMoveEvent(x - popup_rect_.x(), y - popup_rect_.y(), mouseLeave); } else { WebViewHost* host = UIT_GetWebViewHost(); if (host) host->SendMouseMoveEvent(x, y, mouseLeave); } } void CefBrowserImpl::UIT_SendMouseWheelEvent(int x, int y, int deltaX, int deltaY) { REQUIRE_UIT(); if (popuphost_ && popup_rect_.Contains(x, y)) { // Send the event to the popup. popuphost_->SendMouseWheelEvent(x - popup_rect_.x(), y - popup_rect_.y(), deltaX, deltaY); } else { WebViewHost* host = UIT_GetWebViewHost(); if (host) host->SendMouseWheelEvent(x, y, deltaX, deltaY); } } void CefBrowserImpl::UIT_SendFocusEvent(bool setFocus) { REQUIRE_UIT(); WebViewHost* host = UIT_GetWebViewHost(); if (host) host->SendFocusEvent(setFocus); } void CefBrowserImpl::UIT_SendCaptureLostEvent() { REQUIRE_UIT(); WebViewHost* host = UIT_GetWebViewHost(); if (host) host->SendCaptureLostEvent(); } CefRefPtr CefBrowserImpl::UIT_CreatePopupWindow( const CefString& url, const CefPopupFeatures& features) { REQUIRE_UIT(); CefWindowInfo info; #if defined(OS_WIN) info.SetAsPopup(NULL, CefString()); #endif #if (defined(OS_WIN) || defined(OS_MACOSX)) // Default to the size from the popup features. if (features.xSet) info.m_x = features.x; if (features.ySet) info.m_y = features.y; if (features.widthSet) info.m_nWidth = features.width; if (features.heightSet) info.m_nHeight = features.height; #endif CefRefPtr client = client_; // Start with the current browser window's settings. CefBrowserSettings settings(settings_); if (client_.get()) { CefRefPtr handler = client_->GetLifeSpanHandler(); // Give the handler an opportunity to modify window attributes, handler, // or cancel the window creation. if (handler.get() && handler->OnBeforePopup(this, features, info, url, client, settings)) { return NULL; } } // Modal windows need to know which window is being suspended (the opener) // so that it can be disabled while the modal window is open. CefRefPtr browser( new CefBrowserImpl(info, settings, UIT_GetMainWndHandle(), client)); // Don't pass the URL to UIT_CreateBrowser for popup windows or the URL will // be loaded twice. if (!browser->UIT_CreateBrowser(CefString())) return NULL; return browser; } WebKit::WebWidget* CefBrowserImpl::UIT_CreatePopupWidget() { REQUIRE_UIT(); DCHECK(!popuphost_); popuphost_ = WebWidgetHost::Create( (IsWindowRenderingDisabled()?NULL:UIT_GetMainWndHandle()), popup_delegate_.get(), paint_delegate_.get()); popuphost_->set_popup(true); return popuphost_->webwidget(); } void CefBrowserImpl::UIT_ClosePopupWidget() { REQUIRE_UIT(); if (!popuphost_) return; #if !defined(OS_MACOSX) // Mac uses a WebPopupMenu for select lists so no closing is necessary. if (!IsWindowRenderingDisabled()) UIT_CloseView(UIT_GetPopupWndHandle()); #endif popuphost_ = NULL; popup_rect_ = gfx::Rect(); if (IsWindowRenderingDisabled() && client_.get()) { CefRefPtr handler = client_->GetRenderHandler(); if (handler.get()) { // Notify the handler of popup visibility change. handler->OnPopupShow(this, false); } } } void CefBrowserImpl::UIT_Show(WebKit::WebNavigationPolicy policy) { REQUIRE_UIT(); delegate_->show(policy); } void CefBrowserImpl::UIT_HandleActionView(cef_menu_id_t menuId) { return UIT_HandleAction(menuId, NULL); } void CefBrowserImpl::UIT_HandleAction(cef_menu_id_t menuId, CefRefPtr frame) { REQUIRE_UIT(); WebFrame* web_frame = NULL; if (frame) web_frame = UIT_GetWebFrame(frame); switch (menuId) { case MENU_ID_NAV_BACK: UIT_GoBackOrForward(-1); break; case MENU_ID_NAV_FORWARD: UIT_GoBackOrForward(1); break; case MENU_ID_NAV_RELOAD: UIT_Reload(false); break; case MENU_ID_NAV_RELOAD_NOCACHE: UIT_Reload(true); break; case MENU_ID_NAV_STOP: if (UIT_GetWebView()) UIT_GetWebView()->mainFrame()->stopLoading(); break; case MENU_ID_UNDO: if (web_frame) web_frame->executeCommand(WebString::fromUTF8("Undo")); break; case MENU_ID_REDO: if (web_frame) web_frame->executeCommand(WebString::fromUTF8("Redo")); break; case MENU_ID_CUT: if (web_frame) web_frame->executeCommand(WebString::fromUTF8("Cut")); break; case MENU_ID_COPY: if (web_frame) web_frame->executeCommand(WebString::fromUTF8("Copy")); break; case MENU_ID_PASTE: if (web_frame) web_frame->executeCommand(WebString::fromUTF8("Paste")); break; case MENU_ID_DELETE: if (web_frame) web_frame->executeCommand(WebString::fromUTF8("Delete")); break; case MENU_ID_SELECTALL: if (web_frame) web_frame->executeCommand(WebString::fromUTF8("SelectAll")); break; case MENU_ID_PRINT: if (web_frame) UIT_PrintPages(web_frame); break; case MENU_ID_VIEWSOURCE: if (web_frame) UIT_ViewDocumentString(web_frame); break; } } void CefBrowserImpl::UIT_Find(int identifier, const CefString& search_text, const WebKit::WebFindOptions& options) { WebView* view = UIT_GetWebView(); if (!view) return; WebFrame* main_frame = view->mainFrame(); string16 searchText(search_text); if (main_frame->document().isPluginDocument()) { WebPlugin* plugin = main_frame->document().to().plugin(); if (plugin) { if (options.findNext) { // Just navigate back/forward. plugin->selectFindResult(options.forward); } else { if (plugin->startFind(searchText, options.matchCase, identifier)) { } else { // No find results. UIT_NotifyFindStatus(identifier, 0, gfx::Rect(), 0, true); } } return; } } WebFrame* frame_after_main = main_frame->traverseNext(true); WebFrame* focused_frame = view->focusedFrame(); WebFrame* search_frame = focused_frame; // start searching focused frame. bool multi_frame = (frame_after_main != main_frame); // If we have multiple frames, we don't want to wrap the search within the // frame, so we check here if we only have main_frame in the chain. bool wrap_within_frame = !multi_frame; WebRect selection_rect; bool result = false; // If something is selected when we start searching it means we cannot just // increment the current match ordinal; we need to re-generate it. WebRange current_selection = focused_frame->selectionRange(); do { result = search_frame->find(identifier, searchText, options, wrap_within_frame, &selection_rect); if (!result) { // don't leave text selected as you move to the next frame. search_frame->executeCommand(WebString::fromUTF8("Unselect")); // Find the next frame, but skip the invisible ones. do { // What is the next frame to search? (we might be going backwards). Note // that we specify wrap=true so that search_frame never becomes NULL. search_frame = options.forward ? search_frame->traverseNext(true) : search_frame->traversePrevious(true); } while (!search_frame->hasVisibleContent() && search_frame != focused_frame); // Make sure selection doesn't affect the search operation in new frame. search_frame->executeCommand(WebString::fromUTF8("Unselect")); // If we have multiple frames and we have wrapped back around to the // focused frame, we need to search it once more allowing wrap within // the frame, otherwise it will report 'no match' if the focused frame has // reported matches, but no frames after the focused_frame contain a // match for the search word(s). if (multi_frame && search_frame == focused_frame) { result = search_frame->find( identifier, searchText, options, true, // Force wrapping. &selection_rect); } } view->setFocusedFrame(search_frame); } while (!result && search_frame != focused_frame); if (options.findNext && current_selection.isNull()) { // Force the main_frame to report the actual count. main_frame->increaseMatchCount(0, identifier); } else { // If nothing is found, set result to "0 of 0", otherwise, set it to // "-1 of 1" to indicate that we found at least one item, but we don't know // yet what is active. int ordinal = result ? -1 : 0; // -1 here means, we might know more later. int match_count = result ? 1 : 0; // 1 here means possibly more coming. // If we find no matches then this will be our last status update. // Otherwise the scoping effort will send more results. bool final_status_update = !result; // Send the search result. UIT_NotifyFindStatus(identifier, match_count, selection_rect, ordinal, final_status_update); // Scoping effort begins, starting with the mainframe. search_frame = main_frame; main_frame->resetMatchCount(); do { // Cancel all old scoping requests before starting a new one. search_frame->cancelPendingScopingEffort(); // We don't start another scoping effort unless at least one match has // been found. if (result) { // Start new scoping request. If the scoping function determines that it // needs to scope, it will defer until later. search_frame->scopeStringMatches(identifier, searchText, options, true); // reset the tickmarks } // Iterate to the next frame. The frame will not necessarily scope, for // example if it is not visible. search_frame = search_frame->traverseNext(true); } while (search_frame != main_frame); } } void CefBrowserImpl::UIT_StopFinding(bool clear_selection) { WebView* view = UIT_GetWebView(); if (!view) return; WebDocument doc = view->mainFrame()->document(); if (doc.isPluginDocument()) { WebPlugin* plugin = view->mainFrame()->document().to().plugin(); if (plugin) plugin->stopFind(); return; } if (clear_selection) view->focusedFrame()->executeCommand(WebString::fromUTF8("Unselect")); WebFrame* frame = view->mainFrame(); while (frame) { frame->stopFinding(clear_selection); frame = frame->traverseNext(false); } } void CefBrowserImpl::UIT_NotifyFindStatus(int identifier, int count, const WebKit::WebRect& selection_rect, int active_match_ordinal, bool final_update) { if (client_.get()) { CefRefPtr handler = client_->GetFindHandler(); if (handler.get()) { CefRect rect(selection_rect.x, selection_rect.y, selection_rect.width, selection_rect.height); handler->OnFindResult(this, identifier, count, rect, active_match_ordinal, final_update); } } } void CefBrowserImpl::UIT_SetZoomLevel(double zoomLevel) { REQUIRE_UIT(); WebKit::WebFrame* web_frame = UIT_GetMainWebFrame(); if (web_frame) { GURL url = web_frame->document().url(); web_frame->view()->setZoomLevel(false, zoomLevel); bool didHandleZoom = false; if (client_.get()) { CefRefPtr handler = client_->GetZoomHandler(); if (handler.get()) didHandleZoom = handler->OnSetZoomLevel(this, url.spec(), zoomLevel); } if (!didHandleZoom) ZoomMap::GetInstance()->set(url, zoomLevel); set_zoom_level(zoomLevel); } } void CefBrowserImpl::UIT_ShowDevTools() { REQUIRE_UIT(); if (!dev_tools_agent_.get()) return; BrowserDevToolsClient* client = dev_tools_agent_->client(); if (!client) { // Create the inspector window. CefString url(base::StringPrintf( "%sdevtools.html?docked=false&toolbarColor=rgba(223,223,223,1)&" "textColor=rgba(18,50,114,1)", kChromeDevToolsURL)); CefPopupFeatures features; CefRefPtr browser = UIT_CreatePopupWindow(url, features); if (browser.get()) { browser->UIT_CreateDevToolsClient(dev_tools_agent_.get()); browser->UIT_LoadURL(browser->GetMainFrame(), url); browser->UIT_Show(WebKit::WebNavigationPolicyNewWindow); } } else { // Give focus to the existing inspector window. client->browser()->UIT_Show(WebKit::WebNavigationPolicyNewWindow); } } void CefBrowserImpl::UIT_CloseDevTools() { REQUIRE_UIT(); if (!dev_tools_agent_.get()) return; BrowserDevToolsClient* client = dev_tools_agent_->client(); if (client) client->browser()->UIT_CloseBrowser(); } void CefBrowserImpl::UIT_VisitDOM(CefRefPtr frame, CefRefPtr visitor) { REQUIRE_UIT(); WebKit::WebFrame* web_frame = UIT_GetWebFrame(frame); if (!web_frame) return; // Create a CefDOMDocumentImpl object that is valid only for the scope of this // method. CefRefPtr documentImpl; const WebKit::WebDocument& document = web_frame->document(); if (!document.isNull()) documentImpl = new CefDOMDocumentImpl(this, web_frame); visitor->Visit(documentImpl.get()); if (documentImpl.get()) documentImpl->Detach(); } void CefBrowserImpl::UIT_AddFrameObject(WebKit::WebFrame* frame, CefTrackNode* tracked_object) { REQUIRE_UIT(); CefRefPtr manager; if (!frame_objects_.empty()) { FrameObjectMap::const_iterator it = frame_objects_.find(frame); if (it != frame_objects_.end()) manager = it->second; } if (!manager.get()) { manager = new CefTrackManager(); frame_objects_.insert(std::make_pair(frame, manager)); } manager->Add(tracked_object); } void CefBrowserImpl::UIT_BeforeFrameClosed(WebKit::WebFrame* frame) { REQUIRE_UIT(); if (!frame_objects_.empty()) { // Remove any tracked objects associated with the frame. FrameObjectMap::iterator it = frame_objects_.find(frame); if (it != frame_objects_.end()) frame_objects_.erase(it); } } void CefBrowserImpl::set_zoom_level(double zoomLevel) { AutoLock lock_scope(this); zoom_level_ = zoomLevel; } double CefBrowserImpl::zoom_level() { AutoLock lock_scope(this); return zoom_level_; } void CefBrowserImpl::set_nav_state(bool can_go_back, bool can_go_forward) { AutoLock lock_scope(this); can_go_back_ = can_go_back; can_go_forward_ = can_go_forward; } bool CefBrowserImpl::can_go_back() { AutoLock lock_scope(this); return can_go_back_; } bool CefBrowserImpl::can_go_forward() { AutoLock lock_scope(this); return can_go_forward_; } void CefBrowserImpl::set_has_document(bool has_document) { AutoLock lock_scope(this); has_document_ = has_document; } bool CefBrowserImpl::has_document() { AutoLock lock_scope(this); return has_document_; } void CefBrowserImpl::set_pending_url(const GURL& url) { AutoLock lock_scope(this); pending_url_ = url; } GURL CefBrowserImpl::pending_url() { AutoLock lock_scope(this); return pending_url_; } net::URLRequestContext* CefBrowserImpl::request_context_proxy() { DCHECK(CefThread::CurrentlyOn(CefThread::IO)); if (!request_context_proxy_.get()) { request_context_proxy_.reset( new BrowserRequestContextProxy(_Context->request_context(), this)); } return request_context_proxy_.get(); } void CefBrowserImpl::UIT_CreateDevToolsClient(BrowserDevToolsAgent *agent) { dev_tools_client_.reset(new BrowserDevToolsClient(this, agent)); _Context->UIT_DevToolsClientCreated(); } void CefBrowserImpl::UIT_DestroyDevToolsClient() { if (dev_tools_client_.get()) { // Free the client. This will cause the client to clear pending messages // and detach from the agent. dev_tools_client_.reset(); _Context->UIT_DevToolsClientDestroyed(); } } // CefFrameImpl CefFrameImpl::CefFrameImpl(CefBrowserImpl* browser, int64 id, const CefString& name, const CefString& url) : browser_(browser), name_(name), id_(id), url_(url) { } CefFrameImpl::~CefFrameImpl() { if (!IsMain()) browser_->RemoveCefFrame(id_); } bool CefFrameImpl::IsFocused() { // Verify that this method is being called on the UI thread. if (!CefThread::CurrentlyOn(CefThread::UI)) { NOTREACHED() << "called on invalid thread"; return false; } return (browser_->UIT_GetWebView() && (browser_->UIT_GetWebFrame(this) == browser_->UIT_GetWebView()->focusedFrame())); } int64 CefFrameImpl::GetIdentifier() { base::AutoLock lock_scope(lock_); return id_; } CefString CefFrameImpl::GetURL() { base::AutoLock lock_scope(lock_); return url_; } void CefFrameImpl::VisitDOM(CefRefPtr visitor) { if (!visitor.get()) { NOTREACHED() << "invalid parameter"; return; } CefRefPtr framePtr(this); CefThread::PostTask(CefThread::UI, FROM_HERE, base::Bind(&CefBrowserImpl::UIT_VisitDOM, browser_.get(), framePtr, visitor)); } CefRefPtr CefFrameImpl::GetV8Context() { // Verify that this method is being called on the UI thread. if (!CefThread::CurrentlyOn(CefThread::UI)) { NOTREACHED() << "called on invalid thread"; return NULL; } WebKit::WebFrame* frame = browser_->UIT_GetWebFrame(this); if (frame) { v8::HandleScope handle_scope; return new CefV8ContextImpl(webkit_glue::GetV8Context(frame)); } else { return NULL; } } void CefFrameImpl::set_id(int64 id) { base::AutoLock lock_scope(lock_); id_ = id; } void CefFrameImpl::set_url(const CefString& url) { base::AutoLock lock_scope(lock_); url_ = url; }