diff --git a/include/cef.h b/include/cef.h index 25b4c5a20..49d027731 100644 --- a/include/cef.h +++ b/include/cef.h @@ -1022,6 +1022,13 @@ public: /// /*--cef()--*/ virtual void VisitDOM(CefRefPtr visitor) =0; + + /// + // Get the V8 context associated with the frame. This method should only be + // called on the UI thread. + /// + /*--cef()--*/ + virtual CefRefPtr GetV8Context() =0; }; diff --git a/include/cef_capi.h b/include/cef_capi.h index ba4ab37f3..d0116a933 100644 --- a/include/cef_capi.h +++ b/include/cef_capi.h @@ -854,6 +854,13 @@ typedef struct _cef_frame_t void (CEF_CALLBACK *visit_dom)(struct _cef_frame_t* self, struct _cef_domvisitor_t* visitor); + /// + // Get the V8 context associated with the frame. This function should only be + // called on the UI thread. + /// + struct _cef_v8context_t* (CEF_CALLBACK *get_v8context)( + struct _cef_frame_t* self); + } cef_frame_t; diff --git a/libcef/browser_impl.cc b/libcef/browser_impl.cc index 4db65d875..2dbf5b573 100644 --- a/libcef/browser_impl.cc +++ b/libcef/browser_impl.cc @@ -11,6 +11,7 @@ #include "dom_document_impl.h" #include "request_impl.h" #include "stream_impl.h" +#include "v8_impl.h" #include "base/file_path.h" #include "base/path_service.h" @@ -110,13 +111,13 @@ bool CefBrowser::CreateBrowser(CefWindowInfo& windowInfo, { // Verify that the context is in a valid state. if (!CONTEXT_STATE_VALID()) { - NOTREACHED(); + NOTREACHED() << "context not valid"; return false; } // Verify that the settings structure is a valid size. if (settings.size != sizeof(cef_browser_settings_t)) { - NOTREACHED(); + NOTREACHED() << "invalid CefBrowserSettings structure size"; return false; } @@ -135,19 +136,19 @@ CefRefPtr CefBrowser::CreateBrowserSync( { // Verify that the context is in a valid state. if (!CONTEXT_STATE_VALID()) { - NOTREACHED(); + NOTREACHED() << "context not valid"; return NULL; } // Verify that the settings structure is a valid size. if (settings.size != sizeof(cef_browser_settings_t)) { - NOTREACHED(); + NOTREACHED() << "invalid CefBrowserSettings structure size"; return NULL; } // Verify that this method is being called on the UI thread. if (!CefThread::CurrentlyOn(CefThread::UI)) { - NOTREACHED(); + NOTREACHED() << "called on invalid thread"; return NULL; } @@ -243,7 +244,7 @@ CefRefPtr CefBrowserImpl::GetFocusedFrame() { // Verify that this method is being called on the UI thread. if (!CefThread::CurrentlyOn(CefThread::UI)) { - NOTREACHED(); + NOTREACHED() << "called on invalid thread"; return NULL; } @@ -255,7 +256,7 @@ CefRefPtr CefBrowserImpl::GetFrame(const CefString& name) { // Verify that this method is being called on the UI thread. if (!CefThread::CurrentlyOn(CefThread::UI)) { - NOTREACHED(); + NOTREACHED() << "called on invalid thread"; return NULL; } @@ -273,7 +274,7 @@ void CefBrowserImpl::GetFrameNames(std::vector& names) { // Verify that this method is being called on the UI thread. if (!CefThread::CurrentlyOn(CefThread::UI)) { - NOTREACHED(); + NOTREACHED() << "called on invalid thread"; return; } @@ -356,7 +357,7 @@ void CefBrowserImpl::CloseDevTools() bool CefBrowserImpl::GetSize(PaintElementType type, int& width, int& height) { if (!CefThread::CurrentlyOn(CefThread::UI)) { - NOTREACHED(); + NOTREACHED() << "called on invalid thread"; return false; } @@ -389,7 +390,7 @@ void CefBrowserImpl::SetSize(PaintElementType type, int width, int height) bool CefBrowserImpl::IsPopupVisible() { if (!CefThread::CurrentlyOn(CefThread::UI)) { - NOTREACHED(); + NOTREACHED() << "called on invalid thread"; return false; } @@ -416,7 +417,7 @@ bool CefBrowserImpl::GetImage(PaintElementType type, int width, int height, void* buffer) { if (!CefThread::CurrentlyOn(CefThread::UI)) { - NOTREACHED(); + NOTREACHED() << "called on invalid thread"; return false; } @@ -543,7 +544,7 @@ CefString CefBrowserImpl::GetSource(CefRefPtr frame) { // Verify that this method is being called on the UI thread. if (!CefThread::CurrentlyOn(CefThread::UI)) { - NOTREACHED(); + NOTREACHED() << "called on invalid thread"; return CefString(); } @@ -558,7 +559,7 @@ CefString CefBrowserImpl::GetText(CefRefPtr frame) { // Verify that this method is being called on the UI thread. if (!CefThread::CurrentlyOn(CefThread::UI)) { - NOTREACHED(); + NOTREACHED() << "called on invalid thread"; return CefString(); } @@ -615,7 +616,7 @@ CefString CefBrowserImpl::GetURL(CefRefPtr frame) { // Verify that this method is being called on the UI thread. if (!CefThread::CurrentlyOn(CefThread::UI)) { - NOTREACHED(); + NOTREACHED() << "called on invalid thread"; return CefString(); } @@ -1607,7 +1608,7 @@ bool CefFrameImpl::IsFocused() { // Verify that this method is being called on the UI thread. if (!CefThread::CurrentlyOn(CefThread::UI)) { - NOTREACHED(); + NOTREACHED() << "called on invalid thread"; return false; } @@ -1619,10 +1620,27 @@ bool CefFrameImpl::IsFocused() void CefFrameImpl::VisitDOM(CefRefPtr visitor) { if(!visitor.get()) { - NOTREACHED(); + NOTREACHED() << "invalid parameter"; return; } CefRefPtr framePtr(this); CefThread::PostTask(CefThread::UI, FROM_HERE, NewRunnableMethod( browser_.get(), &CefBrowserImpl::UIT_VisitDOM, 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; + } +} diff --git a/libcef/browser_impl.h b/libcef/browser_impl.h index 0d39ccc0e..c58fd2122 100644 --- a/libcef/browser_impl.h +++ b/libcef/browser_impl.h @@ -447,6 +447,7 @@ public: virtual CefString GetURL() OVERRIDE { return browser_->GetURL(this); } virtual CefRefPtr GetBrowser() OVERRIDE { return browser_.get(); } virtual void VisitDOM(CefRefPtr visitor) OVERRIDE; + virtual CefRefPtr GetV8Context() OVERRIDE; private: CefRefPtr browser_; diff --git a/libcef_dll/cpptoc/frame_cpptoc.cc b/libcef_dll/cpptoc/frame_cpptoc.cc index 609671041..bc7789f44 100644 --- a/libcef_dll/cpptoc/frame_cpptoc.cc +++ b/libcef_dll/cpptoc/frame_cpptoc.cc @@ -14,6 +14,7 @@ #include "libcef_dll/cpptoc/frame_cpptoc.h" #include "libcef_dll/cpptoc/request_cpptoc.h" #include "libcef_dll/cpptoc/stream_reader_cpptoc.h" +#include "libcef_dll/cpptoc/v8context_cpptoc.h" #include "libcef_dll/ctocpp/domvisitor_ctocpp.h" @@ -237,6 +238,21 @@ void CEF_CALLBACK frame_visit_dom(struct _cef_frame_t* self, CefFrameCppToC::Get(self)->VisitDOM(CefDOMVisitorCToCpp::Wrap(visitor)); } +struct _cef_v8context_t* CEF_CALLBACK frame_get_v8context( + struct _cef_frame_t* self) +{ + DCHECK(self); + if (!self) + return NULL; + + CefRefPtr framePtr = CefFrameCppToC::Get(self); + CefRefPtr v8ContextPtr = framePtr->GetV8Context(); + if (v8ContextPtr.get()) + return CefV8ContextCppToC::Wrap(v8ContextPtr); + + return NULL; +} + // CONSTRUCTOR - Do not edit by hand. @@ -265,6 +281,7 @@ CefFrameCppToC::CefFrameCppToC(CefFrame* cls) struct_.struct_.get_url = frame_get_url; struct_.struct_.get_browser = frame_get_browser; struct_.struct_.visit_dom = frame_visit_dom; + struct_.struct_.get_v8context = frame_get_v8context; } #ifndef NDEBUG diff --git a/libcef_dll/ctocpp/frame_ctocpp.cc b/libcef_dll/ctocpp/frame_ctocpp.cc index a0ee725bc..e502c3cde 100644 --- a/libcef_dll/ctocpp/frame_ctocpp.cc +++ b/libcef_dll/ctocpp/frame_ctocpp.cc @@ -15,6 +15,7 @@ #include "libcef_dll/ctocpp/frame_ctocpp.h" #include "libcef_dll/ctocpp/request_ctocpp.h" #include "libcef_dll/ctocpp/stream_reader_ctocpp.h" +#include "libcef_dll/ctocpp/v8context_ctocpp.h" // VIRTUAL METHODS - Body may be edited by hand. @@ -216,6 +217,18 @@ void CefFrameCToCpp::VisitDOM(CefRefPtr visitor) struct_->visit_dom(struct_, CefDOMVisitorCppToC::Wrap(visitor)); } +CefRefPtr CefFrameCToCpp::GetV8Context() +{ + if (CEF_MEMBER_MISSING(struct_, get_v8context)) + return NULL; + + cef_v8context_t* v8ContextStruct = struct_->get_v8context(struct_); + if (v8ContextStruct) + return CefV8ContextCToCpp::Wrap(v8ContextStruct); + + return NULL; +} + #ifndef NDEBUG template<> long CefCToCpp::DebugObjCt = diff --git a/libcef_dll/ctocpp/frame_ctocpp.h b/libcef_dll/ctocpp/frame_ctocpp.h index c90f87a16..2f457153a 100644 --- a/libcef_dll/ctocpp/frame_ctocpp.h +++ b/libcef_dll/ctocpp/frame_ctocpp.h @@ -56,6 +56,7 @@ public: virtual CefString GetURL() OVERRIDE; virtual CefRefPtr GetBrowser() OVERRIDE; virtual void VisitDOM(CefRefPtr visitor) OVERRIDE; + virtual CefRefPtr GetV8Context() OVERRIDE; }; #endif // USING_CEF_SHARED diff --git a/tests/cefclient/cefclient.cpp b/tests/cefclient/cefclient.cpp index 800acfe1c..f760115a8 100644 --- a/tests/cefclient/cefclient.cpp +++ b/tests/cefclient/cefclient.cpp @@ -14,6 +14,54 @@ #include #include +namespace { + +void UIT_InvokeScript(CefRefPtr browser) +{ + REQUIRE_UI_THREAD(); + + CefRefPtr frame = browser->GetMainFrame(); + CefRefPtr v8Context = frame->GetV8Context(); + CefString url = frame->GetURL(); + + if (!v8Context.get()) { + frame->ExecuteJavaScript("alert('Failed to get V8 context!');", url, 0); + } else if (v8Context->Enter()) { + CefRefPtr globalObj = v8Context->GetGlobal(); + CefRefPtr evalFunc = globalObj->GetValue("eval"); + + CefRefPtr arg0 = CefV8Value::CreateString("1+2"); + + CefV8ValueList args; + args.push_back(arg0); + + CefRefPtr retVal; + CefString exception; + if (evalFunc->ExecuteFunctionWithContext(v8Context, globalObj, args, retVal, + exception)) { + if (retVal.get()) { + frame->ExecuteJavaScript( + std::string("alert('InvokeScript returns ") + + retVal->GetStringValue().ToString() + "!');", + url, 0); + } else { + frame->ExecuteJavaScript( + std::string("alert('InvokeScript returns exception: ") + + exception.ToString() + "!');", + url, 0); + } + } else { + frame->ExecuteJavaScript("alert('Failed to execute function!');", url, 0); + } + + v8Context->Exit(); + } else { + frame->ExecuteJavaScript("alert('Failed to enter into V8 context!');", + url, 0); + } +} + +} // namespace CefRefPtr g_handler; @@ -102,6 +150,16 @@ void RunJavaScriptExecuteTest(CefRefPtr browser) "alert('JavaScript execute works!');", "about:blank", 0); } +void RunJavaScriptInvokeTest(CefRefPtr browser) +{ + if (CefCurrentlyOn(TID_UI)) { + UIT_InvokeScript(browser); + } else { + // Execute on the UI thread. + CefPostTask(TID_UI, NewCefRunnableFunction(&UIT_InvokeScript, browser)); + } +} + void RunPopupTest(CefRefPtr browser) { browser->GetMainFrame()->ExecuteJavaScript( diff --git a/tests/cefclient/cefclient.h b/tests/cefclient/cefclient.h index 1fcfccbd8..abdc97200 100644 --- a/tests/cefclient/cefclient.h +++ b/tests/cefclient/cefclient.h @@ -21,6 +21,7 @@ void RunGetSourceTest(CefRefPtr browser); void RunGetTextTest(CefRefPtr browser); void RunRequestTest(CefRefPtr browser); void RunJavaScriptExecuteTest(CefRefPtr browser); +void RunJavaScriptInvokeTest(CefRefPtr browser); void RunPopupTest(CefRefPtr browser); void RunLocalStorageTest(CefRefPtr browser); void RunAccelerated2DCanvasTest(CefRefPtr browser); diff --git a/tests/cefclient/cefclient.rc b/tests/cefclient/cefclient.rc index 95b852d6e..e525fb965 100644 --- a/tests/cefclient/cefclient.rc +++ b/tests/cefclient/cefclient.rc @@ -77,6 +77,7 @@ BEGIN MENUITEM "JavaScript Extension Handler",ID_TESTS_JAVASCRIPT_EXTENSION MENUITEM "JavaScript Extension Performance",ID_TESTS_JAVASCRIPT_PERFORMANCE MENUITEM "JavaScript Execute", ID_TESTS_JAVASCRIPT_EXECUTE + MENUITEM "JavaScript Invoke", ID_TESTS_JAVASCRIPT_INVOKE MENUITEM "Plugin", ID_TESTS_PLUGIN MENUITEM "Popup Window", ID_TESTS_POPUP MENUITEM "Transparent Popup Window", ID_TESTS_TRANSPARENT_POPUP diff --git a/tests/cefclient/cefclient_mac.mm b/tests/cefclient/cefclient_mac.mm index f5e1795ed..ba9b71b65 100644 --- a/tests/cefclient/cefclient_mac.mm +++ b/tests/cefclient/cefclient_mac.mm @@ -190,6 +190,7 @@ NSButton* MakeButton(NSRect* rect, NSString* title, NSView* parent) { - (IBAction)testJSExtension:(id)sender; - (IBAction)testJSExtensionPerf:(id)sender; - (IBAction)testJSExecute:(id)sender; +- (IBAction)testJSInvoke:(id)sender; - (IBAction)testRequest:(id)sender; - (IBAction)testLocalStorage:(id)sender; - (IBAction)testXMLHttpRequest:(id)sender; @@ -243,6 +244,9 @@ NSButton* MakeButton(NSRect* rect, NSString* title, NSView* parent) { [testMenu addItemWithTitle:@"JavaScript Execute" action:@selector(testJSExecute:) keyEquivalent:@""]; + [testMenu addItemWithTitle:@"JavaScript Invoke" + action:@selector(testJSInvoke:) + keyEquivalent:@""]; [testMenu addItemWithTitle:@"Popup Window" action:@selector(testPopupWindow:) keyEquivalent:@""]; @@ -411,6 +415,11 @@ NSButton* MakeButton(NSRect* rect, NSString* title, NSView* parent) { RunJavaScriptExecuteTest(g_handler->GetBrowser()); } +- (IBAction)testJSInvoke:(id)sender { + if(g_handler.get() && g_handler->GetBrowserHwnd()) + RunJavaScriptInvokeTest(g_handler->GetBrowser()); +} + - (IBAction)testRequest:(id)sender { if(g_handler.get() && g_handler->GetBrowserHwnd()) RunRequestTest(g_handler->GetBrowser()); diff --git a/tests/cefclient/cefclient_win.cpp b/tests/cefclient/cefclient_win.cpp index 7172fa1cb..20cb01108 100644 --- a/tests/cefclient/cefclient_win.cpp +++ b/tests/cefclient/cefclient_win.cpp @@ -487,6 +487,10 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) if(browser.get()) RunJavaScriptExecuteTest(browser); return 0; + case ID_TESTS_JAVASCRIPT_INVOKE: + if(browser.get()) + RunJavaScriptInvokeTest(browser); + return 0; case ID_TESTS_PLUGIN: // Test the custom plugin if(browser.get()) RunPluginTest(browser); diff --git a/tests/cefclient/resource.h b/tests/cefclient/resource.h index 402b1f10b..80a0eb80d 100644 --- a/tests/cefclient/resource.h +++ b/tests/cefclient/resource.h @@ -55,6 +55,7 @@ #define ID_TESTS_JAVASCRIPT_PERFORMANCE 32795 #define ID_TESTS_TRANSPARENT_POPUP 32796 #define ID_TESTS_TRANSPARENT_OSRAPP 32797 +#define ID_TESTS_JAVASCRIPT_INVOKE 32798 #define IDC_STATIC -1 #define IDS_LOGO 1000 #define IDS_UIPLUGIN 1001