diff --git a/cef.gyp b/cef.gyp index 2740fc673..6c4cdaade 100644 --- a/cef.gyp +++ b/cef.gyp @@ -316,6 +316,8 @@ 'libcef_dll/cpptoc/stream_reader_cpptoc.h', 'libcef_dll/cpptoc/stream_writer_cpptoc.cc', 'libcef_dll/cpptoc/stream_writer_cpptoc.h', + 'libcef_dll/cpptoc/v8context_cpptoc.cc', + 'libcef_dll/cpptoc/v8context_cpptoc.h', 'libcef_dll/cpptoc/v8value_cpptoc.cc', 'libcef_dll/cpptoc/v8value_cpptoc.h', 'libcef_dll/cpptoc/web_urlrequest_cpptoc.cc', @@ -423,6 +425,8 @@ 'libcef_dll/ctocpp/stream_reader_ctocpp.h', 'libcef_dll/ctocpp/stream_writer_ctocpp.cc', 'libcef_dll/ctocpp/stream_writer_ctocpp.h', + 'libcef_dll/ctocpp/v8context_ctocpp.cc', + 'libcef_dll/ctocpp/v8context_ctocpp.h', 'libcef_dll/ctocpp/v8value_ctocpp.cc', 'libcef_dll/ctocpp/v8value_ctocpp.h', 'libcef_dll/ctocpp/web_urlrequest_ctocpp.cc', diff --git a/include/cef.h b/include/cef.h index 251d4b697..9c1eece7b 100644 --- a/include/cef.h +++ b/include/cef.h @@ -61,6 +61,7 @@ class CefStreamReader; class CefStreamWriter; class CefTask; class CefURLParts; +class CefV8Context; class CefV8Handler; class CefV8Value; class CefWebURLRequest; @@ -565,10 +566,14 @@ public: /*--cef()--*/ virtual CefString GetName() =0; - // Return the URL currently loaded in this frame. This method should only be + // Returns the URL currently loaded in this frame. This method should only be // called on the UI thread. /*--cef()--*/ virtual CefString GetURL() =0; + + // Returns the browser that this frame belongs to. + /*--cef()--*/ + virtual CefRefPtr GetBrowser() =0; }; @@ -1190,6 +1195,33 @@ public: }; +// Class that encapsulates a V8 context handle. +/*--cef(source=library)--*/ +class CefV8Context : public CefBase +{ +public: + // Returns the current (top) context object in the V8 context stack. + /*--cef()--*/ + static CefRefPtr GetCurrentContext(); + + // Returns the entered (bottom) context object in the V8 context stack. + /*--cef()--*/ + static CefRefPtr GetEnteredContext(); + + // Returns the browser for this context. + /*--cef()--*/ + virtual CefRefPtr GetBrowser() =0; + + // Returns the frame for this context. + /*--cef()--*/ + virtual CefRefPtr GetFrame() =0; + + // Returns the global object for this context. + /*--cef()--*/ + virtual CefRefPtr GetGlobal() =0; +}; + + typedef std::vector > CefV8ValueList; // Interface that should be implemented to handle V8 function calls. The methods @@ -1198,8 +1230,10 @@ typedef std::vector > CefV8ValueList; class CefV8Handler : public CefBase { public: - // Execute with the specified argument list and return value. Return true if - // the method was handled. + // Execute with the specified argument list and return value. Return true if + // the method was handled. To invoke V8 callback functions outside the scope + // of this method you need to keep references to the current V8 context + // (CefV8Context) along with any necessary callback objects. /*--cef()--*/ virtual bool Execute(const CefString& name, CefRefPtr object, @@ -1215,10 +1249,7 @@ public: class CefV8Value : public CefBase { public: - // Create a new CefV8Value object of the specified type. These methods - // should only be called from within the JavaScript context -- either in a - // CefV8Handler::Execute() callback or a CefHandler::HandleJSBinding() - // callback. + // Create a new CefV8Value object of the specified type. /*--cef()--*/ static CefRefPtr CreateUndefined(); /*--cef()--*/ @@ -1327,12 +1358,21 @@ public: /*--cef()--*/ virtual CefRefPtr GetFunctionHandler() =0; - // Execute the function. + // Execute the function using the current V8 context. /*--cef()--*/ virtual bool ExecuteFunction(CefRefPtr object, const CefV8ValueList& arguments, CefRefPtr& retval, CefString& exception) =0; + + // Execute the function using the specified V8 context. + /*--cef()--*/ + virtual bool ExecuteFunctionWithContext(CefRefPtr context, + CefRefPtr object, + const CefV8ValueList& arguments, + CefRefPtr& retval, + CefString& exception) =0; + }; diff --git a/include/cef_capi.h b/include/cef_capi.h index 82d86b23d..05e75ab17 100644 --- a/include/cef_capi.h +++ b/include/cef_capi.h @@ -390,11 +390,14 @@ typedef struct _cef_frame_t // The resulting string must be freed by calling cef_string_userfree_free(). cef_string_userfree_t (CEF_CALLBACK *get_name)(struct _cef_frame_t* self); - // Return the URL currently loaded in this frame. This function should only be - // called on the UI thread. + // Returns the URL currently loaded in this frame. This function should only + // be called on the UI thread. // The resulting string must be freed by calling cef_string_userfree_free(). cef_string_userfree_t (CEF_CALLBACK *get_url)(struct _cef_frame_t* self); + // Returns the browser that this frame belongs to. + struct _cef_browser_t* (CEF_CALLBACK *get_browser)(struct _cef_frame_t* self); + } cef_frame_t; @@ -949,6 +952,33 @@ CEF_EXPORT cef_stream_writer_t* cef_stream_writer_create_for_handler( cef_write_handler_t* handler); +// Structure that encapsulates a V8 context handle. +typedef struct _cef_v8context_t +{ + // Base structure. + cef_base_t base; + + // Returns the browser for this context. + struct _cef_browser_t* (CEF_CALLBACK *get_browser)( + struct _cef_v8context_t* self); + + // Returns the frame for this context. + struct _cef_frame_t* (CEF_CALLBACK *get_frame)(struct _cef_v8context_t* self); + + // Returns the global object for this context. + struct _cef_v8value_t* (CEF_CALLBACK *get_global)( + struct _cef_v8context_t* self); + +} cef_v8context_t; + + +// Returns the current (top) context object in the V8 context stack. +CEF_EXPORT cef_v8context_t* cef_v8context_get_current_context(); + +// Returns the entered (bottom) context object in the V8 context stack. +CEF_EXPORT cef_v8context_t* cef_v8context_get_entered_context(); + + // Structure that should be implemented to handle V8 function calls. The // functions of this structure will always be called on the UI thread. typedef struct _cef_v8handler_t @@ -956,8 +986,10 @@ typedef struct _cef_v8handler_t // Base structure. cef_base_t base; - // Execute with the specified argument list and return value. Return true (1) - // if the function was handled. + // Execute with the specified argument list and return value. Return true (1) + // if the function was handled. To invoke V8 callback functions outside the + // scope of this function you need to keep references to the current V8 + // context (cef_v8context_t) along with any necessary callback objects. int (CEF_CALLBACK *execute)(struct _cef_v8handler_t* self, const cef_string_t* name, struct _cef_v8value_t* object, size_t argumentCount, struct _cef_v8value_t* const* arguments, @@ -1049,19 +1081,22 @@ typedef struct _cef_v8value_t struct _cef_v8handler_t* (CEF_CALLBACK *get_function_handler)( struct _cef_v8value_t* self); - // Execute the function. + // Execute the function using the current V8 context. int (CEF_CALLBACK *execute_function)(struct _cef_v8value_t* self, struct _cef_v8value_t* object, size_t argumentCount, struct _cef_v8value_t* const* arguments, struct _cef_v8value_t** retval, cef_string_t* exception); + // Execute the function using the specified V8 context. + int (CEF_CALLBACK *execute_function_with_context)(struct _cef_v8value_t* self, + struct _cef_v8context_t* context, struct _cef_v8value_t* object, + size_t argumentCount, struct _cef_v8value_t* const* arguments, + struct _cef_v8value_t** retval, cef_string_t* exception); + } cef_v8value_t; -// Create a new cef_v8value_t object of the specified type. These functions -// should only be called from within the JavaScript context -- either in a -// cef_v8handler_t::execute() callback or a cef_handler_t::handle_jsbinding() -// callback. +// Create a new cef_v8value_t object of the specified type. CEF_EXPORT cef_v8value_t* cef_v8value_create_undefined(); CEF_EXPORT cef_v8value_t* cef_v8value_create_null(); CEF_EXPORT cef_v8value_t* cef_v8value_create_bool(int value); diff --git a/libcef/browser_impl.h b/libcef/browser_impl.h index af98173a3..d93b52d0d 100644 --- a/libcef/browser_impl.h +++ b/libcef/browser_impl.h @@ -349,6 +349,7 @@ public: virtual bool IsFocused(); virtual CefString GetName() { return name_; } virtual CefString GetURL() { return browser_->GetURL(this); } + virtual CefRefPtr GetBrowser() { return browser_.get(); } private: CefRefPtr browser_; diff --git a/libcef/v8_impl.cc b/libcef/v8_impl.cc index 986891fba..1acc27bb0 100644 --- a/libcef/v8_impl.cc +++ b/libcef/v8_impl.cc @@ -1,14 +1,31 @@ -// Copyright (c) 2009 The Chromium Embedded Framework Authors. All rights +// Copyright (c) 2011 The Chromium Embedded Framework 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 "browser_impl.h" #include "v8_impl.h" #include "cef_context.h" #include "tracker.h" #include "base/lazy_instance.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebKit.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebScriptController.h" +#define CEF_REQUIRE_UI_THREAD(var) \ + if (!CefThread::CurrentlyOn(CefThread::UI)) { \ + NOTREACHED(); \ + return var; \ + } + +#define CEF_REQUIRE_VALID_CONTEXT(var) \ + if (!CONTEXT_STATE_VALID()) { \ + NOTREACHED(); \ + return var; \ + } + + +namespace { + // Memory manager. base::LazyInstance g_v8_tracker(base::LINKER_INITIALIZED); @@ -32,20 +49,18 @@ private: std::string string_; }; - -static void TrackAdd(CefTrackObject* object) +void TrackAdd(CefTrackObject* object) { g_v8_tracker.Pointer()->Add(object); } -static void TrackDelete(CefTrackObject* object) +void TrackDelete(CefTrackObject* object) { g_v8_tracker.Pointer()->Delete(object); } // Callback for weak persistent reference destruction. -static void TrackDestructor(v8::Persistent object, - void* parameter) +void TrackDestructor(v8::Persistent object, void* parameter) { if(parameter) TrackDelete(static_cast(parameter)); @@ -54,15 +69,36 @@ static void TrackDestructor(v8::Persistent object, } +// Return the browser associated with the specified WebFrame. +CefRefPtr FindBrowserForFrame(WebKit::WebFrame *frame) +{ + CefRefPtr browser; + + CefContext::BrowserList *list; + CefContext::BrowserList::const_iterator i; + _Context->Lock(); + list = _Context->GetBrowserList(); + i = list->begin(); + for (; i != list->end(); ++i) { + WebKit::WebFrame* thisframe = i->get()->UIT_GetMainWebFrame(); + if (thisframe == frame) { + browser = i->get(); + break; + } + } + _Context->Unlock(); + return browser; +} + // Convert a wide string to a V8 string. -static v8::Handle GetV8String(const CefString& str) +v8::Handle GetV8String(const CefString& str) { std::string tmpStr = str; return v8::String::New(tmpStr.c_str(), tmpStr.length()); } // Convert a V8 string to a UTF8 string. -static std::string GetString(v8::Handle str) +std::string GetString(v8::Handle str) { // Allocate enough space for a worst-case conversion. int len = str->Utf8Length(); @@ -73,8 +109,8 @@ static std::string GetString(v8::Handle str) return ret; } -// V8 function callback -static v8::Handle FunctionCallbackImpl(const v8::Arguments& args) +// V8 function callback. +v8::Handle FunctionCallbackImpl(const v8::Arguments& args) { v8::HandleScope handle_scope; CefV8Handler* handler = @@ -97,7 +133,7 @@ static v8::Handle FunctionCallbackImpl(const v8::Arguments& args) else { CefV8ValueImpl* rv = static_cast(retval.get()); if(rv) - value = rv->GetValue(); + value = rv->GetHandle(); } } @@ -139,15 +175,14 @@ private: CefV8Handler* handler_; }; +} // namespace + bool CefRegisterExtension(const CefString& extension_name, const CefString& javascript_code, CefRefPtr handler) { // Verify that the context is in a valid state. - if (!CONTEXT_STATE_VALID()) { - NOTREACHED(); - return false; - } + CEF_REQUIRE_VALID_CONTEXT(false); if(!handler.get()) { NOTREACHED(); @@ -157,7 +192,7 @@ bool CefRegisterExtension(const CefString& extension_name, TrackString* name = new TrackString(extension_name); TrackAdd(name); TrackString* code = new TrackString(javascript_code); - TrackAdd(name); + TrackAdd(code); ExtensionWrapper* wrapper = new ExtensionWrapper(name->GetString(), code->GetString(), handler.get()); @@ -168,11 +203,113 @@ bool CefRegisterExtension(const CefString& extension_name, } +// CefV8Context + +// static +CefRefPtr CefV8Context::GetCurrentContext() +{ + CefRefPtr context; + CEF_REQUIRE_VALID_CONTEXT(context); + CEF_REQUIRE_UI_THREAD(context); + if (v8::Context::InContext()) + context = new CefV8ContextImpl( v8::Context::GetCurrent() ); + return context; +} + +// static +CefRefPtr CefV8Context::GetEnteredContext() +{ + CefRefPtr context; + CEF_REQUIRE_VALID_CONTEXT(context); + CEF_REQUIRE_UI_THREAD(context); + if (v8::Context::InContext()) + context = new CefV8ContextImpl( v8::Context::GetEntered() ); + return context; +} + + +// CefV8ContextImpl + +CefV8ContextImpl::CefV8ContextImpl(v8::Handle context) +{ + v8_context_ = new CefV8ContextHandle(context); +} + +CefV8ContextImpl::~CefV8ContextImpl() +{ +} + +CefRefPtr CefV8ContextImpl::GetBrowser() +{ + CefRefPtr browser; + CEF_REQUIRE_UI_THREAD(browser); + + WebKit::WebFrame* webframe = GetWebFrame(); + if (webframe) + browser = FindBrowserForFrame(webframe->top()); + + return browser; +} + +CefRefPtr CefV8ContextImpl::GetFrame() +{ + CefRefPtr frame; + CEF_REQUIRE_UI_THREAD(frame); + + WebKit::WebFrame* webframe = GetWebFrame(); + if (webframe) { + CefRefPtr browser; + browser = FindBrowserForFrame(webframe->top()); + if (browser.get()) + frame = browser->UIT_GetCefFrame(webframe); + } + + return frame; +} + +CefRefPtr CefV8ContextImpl::GetGlobal() +{ + CEF_REQUIRE_UI_THREAD(NULL); + + v8::HandleScope handle_scope; + v8::Context::Scope context_scope(v8_context_->GetHandle()); + return new CefV8ValueImpl(v8_context_->GetHandle()->Global()); +} + +v8::Local CefV8ContextImpl::GetContext() +{ + return v8::Local::New(v8_context_->GetHandle()); +} + +WebKit::WebFrame* CefV8ContextImpl::GetWebFrame() +{ + v8::HandleScope handle_scope; + v8::Context::Scope context_scope(v8_context_->GetHandle()); + WebKit::WebFrame* frame = WebKit::WebFrame::frameForCurrentContext(); + return frame; +} + + +// CefV8ValueHandle + +// Custom destructor for a v8 value handle which gets called only on the UI +// thread. +CefV8ValueHandle::~CefV8ValueHandle() +{ + if(tracker_) + TrackAdd(tracker_); + v8_handle_.MakeWeak(tracker_, TrackDestructor); + tracker_ = NULL; +} + + // CefV8Value // static CefRefPtr CefV8Value::CreateUndefined() { + CEF_REQUIRE_VALID_CONTEXT(NULL); + CEF_REQUIRE_UI_THREAD(NULL); v8::HandleScope handle_scope; return new CefV8ValueImpl(v8::Undefined()); } @@ -180,6 +317,8 @@ CefRefPtr CefV8Value::CreateUndefined() // static CefRefPtr CefV8Value::CreateNull() { + CEF_REQUIRE_VALID_CONTEXT(NULL); + CEF_REQUIRE_UI_THREAD(NULL); v8::HandleScope handle_scope; return new CefV8ValueImpl(v8::Null()); } @@ -187,6 +326,8 @@ CefRefPtr CefV8Value::CreateNull() // static CefRefPtr CefV8Value::CreateBool(bool value) { + CEF_REQUIRE_VALID_CONTEXT(NULL); + CEF_REQUIRE_UI_THREAD(NULL); v8::HandleScope handle_scope; return new CefV8ValueImpl(v8::Boolean::New(value)); } @@ -194,6 +335,8 @@ CefRefPtr CefV8Value::CreateBool(bool value) // static CefRefPtr CefV8Value::CreateInt(int value) { + CEF_REQUIRE_VALID_CONTEXT(NULL); + CEF_REQUIRE_UI_THREAD(NULL); v8::HandleScope handle_scope; return new CefV8ValueImpl(v8::Int32::New(value)); } @@ -201,6 +344,8 @@ CefRefPtr CefV8Value::CreateInt(int value) // static CefRefPtr CefV8Value::CreateDouble(double value) { + CEF_REQUIRE_VALID_CONTEXT(NULL); + CEF_REQUIRE_UI_THREAD(NULL); v8::HandleScope handle_scope; return new CefV8ValueImpl(v8::Number::New(value)); } @@ -208,6 +353,8 @@ CefRefPtr CefV8Value::CreateDouble(double value) // static CefRefPtr CefV8Value::CreateString(const CefString& value) { + CEF_REQUIRE_VALID_CONTEXT(NULL); + CEF_REQUIRE_UI_THREAD(NULL); v8::HandleScope handle_scope; return new CefV8ValueImpl(GetV8String(value)); } @@ -215,14 +362,16 @@ CefRefPtr CefV8Value::CreateString(const CefString& value) // static CefRefPtr CefV8Value::CreateObject(CefRefPtr user_data) { + CEF_REQUIRE_VALID_CONTEXT(NULL); + CEF_REQUIRE_UI_THREAD(NULL); + v8::HandleScope handle_scope; - CefV8ValueImpl* impl = new CefV8ValueImpl(); // Create the new V8 object. v8::Local obj = v8::Object::New(); TrackBase *tracker = NULL; - if(user_data.get()) { + if (user_data.get()) { // Attach the user data to the V8 object. v8::Local data = v8::External::Wrap(user_data.get()); obj->Set(v8::String::New("Cef::UserData"), data); @@ -232,24 +381,27 @@ CefRefPtr CefV8Value::CreateObject(CefRefPtr user_data) tracker = new TrackBase(user_data); } - // Attach to the CefV8ValueImpl. - impl->Attach(obj, tracker); - return impl; + return new CefV8ValueImpl(obj, tracker); } // static CefRefPtr CefV8Value::CreateArray() { + CEF_REQUIRE_VALID_CONTEXT(NULL); + CEF_REQUIRE_UI_THREAD(NULL); + v8::HandleScope handle_scope; return new CefV8ValueImpl(v8::Array::New()); } // static CefRefPtr CefV8Value::CreateFunction(const CefString& name, - CefRefPtr handler) + CefRefPtr handler) { + CEF_REQUIRE_VALID_CONTEXT(NULL); + CEF_REQUIRE_UI_THREAD(NULL); + v8::HandleScope handle_scope; - CefV8ValueImpl* impl = new CefV8ValueImpl(); // Create a new V8 function template with one internal field. v8::Local tmpl = v8::FunctionTemplate::New(); @@ -266,393 +418,324 @@ CefRefPtr CefV8Value::CreateFunction(const CefString& name, // Attach the handler instance to the V8 object. func->Set(v8::String::New("Cef::Handler"), data); - // Attach to the CefV8ValueImpl and provide a tracker object that will cause + // Create the CefV8ValueImpl and provide a tracker object that will cause // the handler reference to be released when the V8 object is destroyed. - impl->Attach(func, new TrackBase(handler)); - return impl; + return new CefV8ValueImpl(func, new TrackBase(handler)); } // CefV8ValueImpl -CefV8ValueImpl::CefV8ValueImpl() - : tracker_(NULL) -{ -} - CefV8ValueImpl::CefV8ValueImpl(v8::Handle value, CefTrackObject* tracker) { - Attach(value, tracker); + v8_value_ = new CefV8ValueHandle(value, tracker); } CefV8ValueImpl::~CefV8ValueImpl() { - Detach(); -} - -bool CefV8ValueImpl::Attach(v8::Handle value, - CefTrackObject* tracker) -{ - bool rv = false; - Lock(); - if(v8_value_.IsEmpty()) { - v8_value_ = v8::Persistent::New(value); - tracker_ = tracker; - rv = true; - } - Unlock(); - return rv; -} - -void CefV8ValueImpl::Detach() -{ - Lock(); - if(tracker_) - TrackAdd(tracker_); - v8_value_.MakeWeak(tracker_, TrackDestructor); - tracker_ = NULL; - Unlock(); -} - -v8::Handle CefV8ValueImpl::GetValue() -{ - v8::HandleScope handle_scope; - v8::Handle rv; - Lock(); - rv = v8_value_; - Unlock(); - return rv; -} - -bool CefV8ValueImpl::IsReservedKey(const CefString& key) -{ - std::string str = key; - return (str.find("Cef::") == 0 || str.find("v8::") == 0); } bool CefV8ValueImpl::IsUndefined() { - Lock(); - bool rv = v8_value_->IsUndefined(); - Unlock(); - return rv; + CEF_REQUIRE_UI_THREAD(false); + return GetHandle()->IsUndefined(); } bool CefV8ValueImpl::IsNull() { - Lock(); - bool rv = v8_value_->IsNull(); - Unlock(); - return rv; + CEF_REQUIRE_UI_THREAD(false); + return GetHandle()->IsNull(); } bool CefV8ValueImpl::IsBool() { - Lock(); - bool rv = (v8_value_->IsBoolean() || v8_value_->IsTrue() - || v8_value_->IsFalse()); - Unlock(); - return rv; + CEF_REQUIRE_UI_THREAD(false); + return (GetHandle()->IsBoolean() || GetHandle()->IsTrue() + || GetHandle()->IsFalse()); } bool CefV8ValueImpl::IsInt() { - Lock(); - bool rv = v8_value_->IsInt32(); - Unlock(); - return rv; + CEF_REQUIRE_UI_THREAD(false); + return GetHandle()->IsInt32(); } bool CefV8ValueImpl::IsDouble() { - Lock(); - bool rv = (v8_value_->IsNumber() || v8_value_->IsDate()); - Unlock(); - return rv; + CEF_REQUIRE_UI_THREAD(false); + return (GetHandle()->IsNumber() || GetHandle()->IsDate()); } bool CefV8ValueImpl::IsString() { - Lock(); - bool rv = v8_value_->IsString(); - Unlock(); - return rv; + CEF_REQUIRE_UI_THREAD(false); + return GetHandle()->IsString(); } bool CefV8ValueImpl::IsObject() { - Lock(); - bool rv = v8_value_->IsObject(); - Unlock(); - return rv; + CEF_REQUIRE_UI_THREAD(false); + return GetHandle()->IsObject(); } bool CefV8ValueImpl::IsArray() { - Lock(); - bool rv = v8_value_->IsArray(); - Unlock(); - return rv; + CEF_REQUIRE_UI_THREAD(false); + return GetHandle()->IsArray(); } bool CefV8ValueImpl::IsFunction() { - Lock(); - bool rv = v8_value_->IsFunction(); - Unlock(); - return rv; + CEF_REQUIRE_UI_THREAD(false); + return GetHandle()->IsFunction(); } bool CefV8ValueImpl::GetBoolValue() { - bool rv = false; - Lock(); - if(v8_value_->IsTrue()) - rv = true; - else if(v8_value_->IsFalse()) - rv = false; - else { + CEF_REQUIRE_UI_THREAD(false); + if (GetHandle()->IsTrue()) { + return true; + } else if(GetHandle()->IsFalse()) { + return false; + } else { v8::HandleScope handle_scope; - v8::Local val = v8_value_->ToBoolean(); - rv = val->Value(); + v8::Local val = GetHandle()->ToBoolean(); + return val->Value(); } - Unlock(); - return rv; } int CefV8ValueImpl::GetIntValue() { - int rv = 0; - Lock(); + CEF_REQUIRE_UI_THREAD(0); v8::HandleScope handle_scope; - v8::Local val = v8_value_->ToInt32(); - rv = val->Value(); - Unlock(); - return rv; + v8::Local val = GetHandle()->ToInt32(); + return val->Value(); } double CefV8ValueImpl::GetDoubleValue() { - double rv = 0.; - Lock(); + CEF_REQUIRE_UI_THREAD(0.); v8::HandleScope handle_scope; - v8::Local val = v8_value_->ToNumber(); - rv = val->Value(); - Unlock(); - return rv; + v8::Local val = GetHandle()->ToNumber(); + return val->Value(); } CefString CefV8ValueImpl::GetStringValue() { CefString rv; - Lock(); + CEF_REQUIRE_UI_THREAD(rv); v8::HandleScope handle_scope; - rv = GetString(v8_value_->ToString()); - Unlock(); + rv = GetString(GetHandle()->ToString()); return rv; } bool CefV8ValueImpl::HasValue(const CefString& key) { + CEF_REQUIRE_UI_THREAD(false); if(IsReservedKey(key)) return false; - - bool rv = false; - Lock(); - if(v8_value_->IsObject()) { - v8::HandleScope handle_scope; - v8::Local obj = v8_value_->ToObject(); - rv = obj->Has(GetV8String(key)); + if(!GetHandle()->IsObject()) { + NOTREACHED(); + return false; } - Unlock(); - return rv; + + v8::HandleScope handle_scope; + v8::Local obj = GetHandle()->ToObject(); + return obj->Has(GetV8String(key)); } bool CefV8ValueImpl::HasValue(int index) { - bool rv = false; - Lock(); - if(v8_value_->IsObject()) { - v8::HandleScope handle_scope; - v8::Local obj = v8_value_->ToObject(); - rv = obj->Has(index); + CEF_REQUIRE_UI_THREAD(false); + if(!GetHandle()->IsObject()) { + NOTREACHED(); + return false; } - Unlock(); - return rv; + + v8::HandleScope handle_scope; + v8::Local obj = GetHandle()->ToObject(); + return obj->Has(index); } bool CefV8ValueImpl::DeleteValue(const CefString& key) { + CEF_REQUIRE_UI_THREAD(false); if(IsReservedKey(key)) return false; - - bool rv = false; - Lock(); - if(v8_value_->IsObject()) { - v8::HandleScope handle_scope; - v8::Local obj = v8_value_->ToObject(); - rv = obj->Delete(GetV8String(key)); + if(!GetHandle()->IsObject()) { + NOTREACHED(); + return false; } - Unlock(); - return rv; + + v8::HandleScope handle_scope; + v8::Local obj = GetHandle()->ToObject(); + return obj->Delete(GetV8String(key)); } bool CefV8ValueImpl::DeleteValue(int index) { - bool rv = false; - Lock(); - if(v8_value_->IsObject()) { - v8::HandleScope handle_scope; - v8::Local obj = v8_value_->ToObject(); - rv = obj->Delete(index); + CEF_REQUIRE_UI_THREAD(false); + if(!GetHandle()->IsObject()) { + NOTREACHED(); + return false; } - Unlock(); - return rv; + + v8::HandleScope handle_scope; + v8::Local obj = GetHandle()->ToObject(); + return obj->Delete(index); } CefRefPtr CefV8ValueImpl::GetValue(const CefString& key) { + CEF_REQUIRE_UI_THREAD(NULL); if(IsReservedKey(key)) + return NULL; + if(!GetHandle()->IsObject()) { + NOTREACHED(); return false; - - CefRefPtr rv; - Lock(); - if(v8_value_->IsObject()) { - v8::HandleScope handle_scope; - v8::Local obj = v8_value_->ToObject(); - rv = new CefV8ValueImpl(obj->Get(GetV8String(key))); } - Unlock(); - return rv; + + v8::HandleScope handle_scope; + v8::Local obj = GetHandle()->ToObject(); + return new CefV8ValueImpl(obj->Get(GetV8String(key))); } CefRefPtr CefV8ValueImpl::GetValue(int index) { - CefRefPtr rv; - Lock(); - if(v8_value_->IsObject()) { - v8::HandleScope handle_scope; - v8::Local obj = v8_value_->ToObject(); - rv = new CefV8ValueImpl(obj->Get(v8::Number::New(index))); + CEF_REQUIRE_UI_THREAD(NULL); + if(!GetHandle()->IsObject()) { + NOTREACHED(); + return false; } - Unlock(); - return rv; + + v8::HandleScope handle_scope; + v8::Local obj = GetHandle()->ToObject(); + return new CefV8ValueImpl(obj->Get(v8::Number::New(index))); } bool CefV8ValueImpl::SetValue(const CefString& key, CefRefPtr value) { + CEF_REQUIRE_UI_THREAD(false); if(IsReservedKey(key)) return false; - - bool rv = false; - Lock(); - if(v8_value_->IsObject()) { - CefV8ValueImpl *impl = static_cast(value.get()); - if(impl) { - v8::HandleScope handle_scope; - v8::Local obj = v8_value_->ToObject(); - rv = obj->Set(GetV8String(key), impl->GetValue()); - } + if(!GetHandle()->IsObject()) { + NOTREACHED(); + return false; + } + + CefV8ValueImpl *impl = static_cast(value.get()); + if(impl) { + v8::HandleScope handle_scope; + v8::Local obj = GetHandle()->ToObject(); + return obj->Set(GetV8String(key), impl->GetHandle()); + } else { + NOTREACHED(); + return false; } - Unlock(); - return rv; } bool CefV8ValueImpl::SetValue(int index, CefRefPtr value) { - bool rv = false; - Lock(); - if(v8_value_->IsObject()) { - CefV8ValueImpl *impl = static_cast(value.get()); - if(impl) { - v8::HandleScope handle_scope; - v8::Local obj = v8_value_->ToObject(); - rv = obj->Set(v8::Number::New(index), impl->GetValue()); - } + CEF_REQUIRE_UI_THREAD(false); + if(!GetHandle()->IsObject()) { + NOTREACHED(); + return false; + } + + CefV8ValueImpl *impl = static_cast(value.get()); + if(impl) { + v8::HandleScope handle_scope; + v8::Local obj = GetHandle()->ToObject(); + return obj->Set(v8::Number::New(index), impl->GetHandle()); + } else { + NOTREACHED(); + return false; } - Unlock(); - return rv; } bool CefV8ValueImpl::GetKeys(std::vector& keys) { - bool rv = false; - Lock(); - if(v8_value_->IsObject()) { - v8::HandleScope handle_scope; - v8::Local obj = v8_value_->ToObject(); - v8::Local arr_keys = obj->GetPropertyNames(); - uint32_t len = arr_keys->Length(); - for(uint32_t i = 0; i < len; ++i) { - v8::Local value = arr_keys->Get(v8::Integer::New(i)); - CefString str = GetString(value->ToString()); - if(!IsReservedKey(str)) - keys.push_back(str); - } - rv = true; + CEF_REQUIRE_UI_THREAD(false); + if(!GetHandle()->IsObject()) { + NOTREACHED(); + return false; } - Unlock(); - return rv; + + v8::HandleScope handle_scope; + v8::Local obj = GetHandle()->ToObject(); + v8::Local arr_keys = obj->GetPropertyNames(); + uint32_t len = arr_keys->Length(); + for(uint32_t i = 0; i < len; ++i) { + v8::Local value = arr_keys->Get(v8::Integer::New(i)); + CefString str = GetString(value->ToString()); + if(!IsReservedKey(str)) + keys.push_back(str); + } + return true; } CefRefPtr CefV8ValueImpl::GetUserData() { - CefRefPtr rv; - Lock(); - if(v8_value_->IsObject()) { - v8::HandleScope handle_scope; - v8::Local obj = v8_value_->ToObject(); - v8::Local key = v8::String::New("Cef::UserData"); - if(obj->Has(key)) - rv = static_cast(v8::External::Unwrap(obj->Get(key))); + CEF_REQUIRE_UI_THREAD(NULL); + if(!GetHandle()->IsObject()) { + NOTREACHED(); + return NULL; } - Unlock(); - return rv; + + v8::HandleScope handle_scope; + v8::Local obj = GetHandle()->ToObject(); + v8::Local key = v8::String::New("Cef::UserData"); + if(obj->Has(key)) + return static_cast(v8::External::Unwrap(obj->Get(key))); + return NULL; } int CefV8ValueImpl::GetArrayLength() { - int rv = 0; - Lock(); - if(v8_value_->IsArray()) { - v8::HandleScope handle_scope; - v8::Local obj = v8_value_->ToObject(); - v8::Local arr = v8::Local::Cast(obj); - rv = arr->Length(); + CEF_REQUIRE_UI_THREAD(0); + if(!GetHandle()->IsArray()) { + NOTREACHED(); + return 0; } - Unlock(); - return rv; + + v8::HandleScope handle_scope; + v8::Local obj = GetHandle()->ToObject(); + v8::Local arr = v8::Local::Cast(obj); + return arr->Length(); } CefString CefV8ValueImpl::GetFunctionName() { CefString rv; - Lock(); - if(v8_value_->IsFunction()) { - v8::HandleScope handle_scope; - v8::Local obj = v8_value_->ToObject(); - v8::Local func = v8::Local::Cast(obj); - rv = GetString(v8::Handle::Cast(func->GetName())); + CEF_REQUIRE_UI_THREAD(rv); + if(!GetHandle()->IsFunction()) { + NOTREACHED(); + return rv; } - Unlock(); + + v8::HandleScope handle_scope; + v8::Local obj = GetHandle()->ToObject(); + v8::Local func = v8::Local::Cast(obj); + rv = GetString(v8::Handle::Cast(func->GetName())); return rv; } CefRefPtr CefV8ValueImpl::GetFunctionHandler() { - CefRefPtr rv; - Lock(); - if(v8_value_->IsFunction()) { - v8::HandleScope handle_scope; - v8::Local obj = v8_value_->ToObject(); - v8::Local key = v8::String::New("Cef::Handler"); - if(obj->Has(key)) - rv = static_cast(v8::External::Unwrap(obj->Get(key))); + CEF_REQUIRE_UI_THREAD(NULL); + if(!GetHandle()->IsFunction()) { + NOTREACHED(); + return NULL; } - Unlock(); - return rv; + + v8::HandleScope handle_scope; + v8::Local obj = GetHandle()->ToObject(); + v8::Local key = v8::String::New("Cef::Handler"); + if (obj->Has(key)) + return static_cast(v8::External::Unwrap(obj->Get(key))); + return NULL; } bool CefV8ValueImpl::ExecuteFunction(CefRefPtr object, @@ -660,36 +743,70 @@ bool CefV8ValueImpl::ExecuteFunction(CefRefPtr object, CefRefPtr& retval, CefString& exception) { - bool rv = false; - Lock(); - if(v8_value_->IsFunction() && object.get() && object->IsObject()) { - v8::HandleScope handle_scope; - v8::Local obj = v8_value_->ToObject(); - v8::Local func = v8::Local::Cast(obj); - - CefV8ValueImpl* recv_impl = static_cast(object.get()); - v8::Handle recv = - v8::Handle::Cast(recv_impl->GetValue()); - - int argc = arguments.size(); - v8::Handle *argv = NULL; - if(argc > 0) { - argv = new v8::Handle[argc]; - for(int i = 0; i < argc; ++i) { - argv[i] = - static_cast(arguments[i].get())->GetValue(); - } - } - - v8::TryCatch try_catch; - v8::Local func_rv = func->Call(recv, argc, argv); - if (try_catch.HasCaught()) - exception = GetString(try_catch.Message()->Get()); - else - retval = new CefV8ValueImpl(func_rv); - - rv = true; - } - Unlock(); - return rv; + // An empty context value defaults to the current context. + CefRefPtr context; + return ExecuteFunctionWithContext(context, object, arguments, retval, + exception); +} + +bool CefV8ValueImpl::ExecuteFunctionWithContext( + CefRefPtr context, + CefRefPtr object, + const CefV8ValueList& arguments, + CefRefPtr& retval, + CefString& exception) +{ + CEF_REQUIRE_UI_THREAD(false); + if(!GetHandle()->IsFunction()) { + NOTREACHED(); + return false; + } + + v8::HandleScope handle_scope; + + v8::Local context_local; + if (context.get()) { + CefV8ContextImpl* context_impl = + static_cast(context.get()); + context_local = context_impl->GetContext(); + } else { + context_local = v8::Context::GetCurrent(); + } + + v8::Context::Scope context_scope(context_local); + + v8::Local obj = GetHandle()->ToObject(); + v8::Local func = v8::Local::Cast(obj); + v8::Handle recv; + + // Default to the global object if no object or a non-object was provided. + if (object.get() && object->IsObject()) { + CefV8ValueImpl* recv_impl = static_cast(object.get()); + recv = v8::Handle::Cast(recv_impl->GetHandle()); + } else { + recv = context_local->Global(); + } + + int argc = arguments.size(); + v8::Handle *argv = NULL; + if (argc > 0) { + argv = new v8::Handle[argc]; + for (int i = 0; i < argc; ++i) + argv[i] = static_cast(arguments[i].get())->GetHandle(); + } + + v8::TryCatch try_catch; + v8::Local func_rv = func->Call(recv, argc, argv); + if (try_catch.HasCaught()) + exception = GetString(try_catch.Message()->Get()); + else + retval = new CefV8ValueImpl(func_rv); + + return true; +} + +bool CefV8ValueImpl::IsReservedKey(const CefString& key) +{ + std::string str = key; + return (str.find("Cef::") == 0 || str.find("v8::") == 0); } diff --git a/libcef/v8_impl.h b/libcef/v8_impl.h index 676631305..5526dc6e4 100644 --- a/libcef/v8_impl.h +++ b/libcef/v8_impl.h @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Embedded Framework Authors. All rights +// Copyright (c) 2011 The Chromium Embedded Framework Authors. All rights // reserved. Use of this source code is governed by a BSD-style license that // can be found in the LICENSE file. @@ -10,18 +10,96 @@ class CefTrackObject; +namespace WebKit { +class WebFrame; +}; + +// Template for V8 Handle types. This class is used to ensure that V8 objects +// are only released on the UI thread. +template +class CefReleaseV8HandleOnUIThread: + public base::RefCountedThreadSafe, + CefThread::DeleteOnUIThread> +{ +public: + typedef v8::Handle handleType; + typedef v8::Persistent persistentType; + typedef CefReleaseV8HandleOnUIThread superType; + + CefReleaseV8HandleOnUIThread(handleType v) + { + v8_handle_ = persistentType::New(v); + } + virtual ~CefReleaseV8HandleOnUIThread() + { + } + + handleType GetHandle() + { + return v8_handle_; + } + + persistentType v8_handle_; +}; + +// Special class for a v8::Context to ensure that it is deleted from the UI +// thread. +class CefV8ContextHandle : public CefReleaseV8HandleOnUIThread +{ +public: + CefV8ContextHandle(handleType context): superType(context) + { + } + + // Context handles are disposed rather than makeweak. + ~CefV8ContextHandle() + { + v8_handle_.Dispose(); + v8_handle_.Clear(); + } +}; + +class CefV8ContextImpl : public CefThreadSafeBase +{ +public: + CefV8ContextImpl(v8::Handle context); + virtual ~CefV8ContextImpl(); + + virtual CefRefPtr GetBrowser(); + virtual CefRefPtr GetFrame(); + virtual CefRefPtr GetGlobal(); + + v8::Local GetContext(); + WebKit::WebFrame* GetWebFrame(); + +protected: + scoped_refptr v8_context_; +}; + +// Special class for a v8::Value to ensure that it is deleted from the UI +// thread. +class CefV8ValueHandle: public CefReleaseV8HandleOnUIThread +{ +public: + CefV8ValueHandle(handleType value, CefTrackObject* tracker) + : superType(value), tracker_(tracker) + { + } + // Destructor implementation is provided in v8_impl.cc. + ~CefV8ValueHandle(); + +private: + // For Object and Function types, we need to hold on to a reference to their + // internal data or function handler objects that are reference counted. + CefTrackObject *tracker_; +}; + class CefV8ValueImpl : public CefThreadSafeBase { public: - CefV8ValueImpl(); CefV8ValueImpl(v8::Handle value, CefTrackObject* tracker = NULL); virtual ~CefV8ValueImpl(); - bool Attach(v8::Handle value, CefTrackObject* tracker = NULL); - void Detach(); - v8::Handle GetValue(); - bool IsReservedKey(const CefString& key); - virtual bool IsUndefined(); virtual bool IsNull(); virtual bool IsBool(); @@ -52,10 +130,23 @@ public: const CefV8ValueList& arguments, CefRefPtr& retval, CefString& exception); + virtual bool ExecuteFunctionWithContext( + CefRefPtr context, + CefRefPtr object, + const CefV8ValueList& arguments, + CefRefPtr& retval, + CefString& exception); + + inline v8::Handle GetHandle() + { + DCHECK(v8_value_.get()); + return v8_value_->GetHandle(); + } + + bool IsReservedKey(const CefString& key); protected: - v8::Persistent v8_value_; - CefTrackObject* tracker_; + scoped_refptr v8_value_; }; #endif //_V8_IMPL_H diff --git a/libcef_dll/cpptoc/frame_cpptoc.cc b/libcef_dll/cpptoc/frame_cpptoc.cc index 425f5d093..e873832eb 100644 --- a/libcef_dll/cpptoc/frame_cpptoc.cc +++ b/libcef_dll/cpptoc/frame_cpptoc.cc @@ -10,6 +10,7 @@ // for more information. // +#include "libcef_dll/cpptoc/browser_cpptoc.h" #include "libcef_dll/cpptoc/frame_cpptoc.h" #include "libcef_dll/cpptoc/request_cpptoc.h" #include "libcef_dll/cpptoc/stream_reader_cpptoc.h" @@ -211,6 +212,19 @@ cef_string_userfree_t CEF_CALLBACK frame_get_url(struct _cef_frame_t* self) return urlStr.DetachToUserFree(); } +cef_browser_t* CEF_CALLBACK frame_get_browser(struct _cef_frame_t* self) +{ + DCHECK(self); + if(!self) + return NULL; + + CefRefPtr browserPtr = + CefFrameCppToC::Get(self)->GetBrowser(); + if(browserPtr.get()) + return CefBrowserCppToC::Wrap(browserPtr); + return NULL; +} + // CONSTRUCTOR - Do not edit by hand. @@ -237,6 +251,7 @@ CefFrameCppToC::CefFrameCppToC(CefFrame* cls) struct_.struct_.is_focused = frame_is_focused; struct_.struct_.get_name = frame_get_name; struct_.struct_.get_url = frame_get_url; + struct_.struct_.get_browser = frame_get_browser; } #ifdef _DEBUG diff --git a/libcef_dll/cpptoc/v8context_cpptoc.cc b/libcef_dll/cpptoc/v8context_cpptoc.cc new file mode 100644 index 000000000..e38111887 --- /dev/null +++ b/libcef_dll/cpptoc/v8context_cpptoc.cc @@ -0,0 +1,97 @@ +// Copyright (c) 2010 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. +// +// --------------------------------------------------------------------------- +// +// A portion of this file was generated by the CEF translator tool. When +// making changes by hand only do so within the body of existing function +// implementations. See the translator.README.txt file in the tools directory +// for more information. +// + +#include "libcef_dll/cpptoc/browser_cpptoc.h" +#include "libcef_dll/cpptoc/frame_cpptoc.h" +#include "libcef_dll/cpptoc/v8context_cpptoc.h" +#include "libcef_dll/cpptoc/v8value_cpptoc.h" + + +// GLOBAL FUNCTIONS - Body may be edited by hand. + +CEF_EXPORT cef_v8context_t* cef_v8context_get_current_context() +{ + CefRefPtr + contextPtr( CefV8Context::GetCurrentContext() ); + if(contextPtr.get()) + return CefV8ContextCppToC::Wrap(contextPtr); + return NULL; +} + +CEF_EXPORT cef_v8context_t* cef_v8context_get_entered_context() +{ + CefRefPtr + contextPtr( CefV8Context::GetEnteredContext() ); + if(contextPtr.get()) + return CefV8ContextCppToC::Wrap(contextPtr); + return NULL; +} + + +// MEMBER FUNCTIONS - Body may be edited by hand. + +cef_browser_t* CEF_CALLBACK v8context_get_browser(struct _cef_v8context_t* self) +{ + DCHECK(self); + if(!self) + return NULL; + + CefRefPtr contextPtr = CefV8ContextCppToC::Get(self); + CefRefPtr browserPtr = contextPtr->GetBrowser(); + if(browserPtr.get()) + return CefBrowserCppToC::Wrap(browserPtr); + return NULL; +} + +cef_frame_t* CEF_CALLBACK v8context_get_frame(struct _cef_v8context_t* self) +{ + DCHECK(self); + if(!self) + return NULL; + + CefRefPtr contextPtr = CefV8ContextCppToC::Get(self); + CefRefPtr framePtr = contextPtr->GetFrame(); + if(framePtr.get()) + return CefFrameCppToC::Wrap(framePtr); + return NULL; +} + +struct _cef_v8value_t* CEF_CALLBACK v8context_get_global( + struct _cef_v8context_t* self) +{ + DCHECK(self); + if(!self) + return NULL; + + CefRefPtr contextPtr = CefV8ContextCppToC::Get(self); + CefRefPtr globalPtr = contextPtr->GetGlobal(); + if(globalPtr.get()) + return CefV8ValueCppToC::Wrap(globalPtr); + return NULL; +} + + +// CONSTRUCTOR - Do not edit by hand. + +CefV8ContextCppToC::CefV8ContextCppToC(CefV8Context* cls) + : CefCppToC(cls) +{ + struct_.struct_.get_browser = v8context_get_browser; + struct_.struct_.get_frame = v8context_get_frame; + struct_.struct_.get_global = v8context_get_global; +} + +#ifdef _DEBUG +template<> long CefCppToC::DebugObjCt = 0; +#endif + diff --git a/libcef_dll/cpptoc/v8context_cpptoc.h b/libcef_dll/cpptoc/v8context_cpptoc.h new file mode 100644 index 000000000..259825418 --- /dev/null +++ b/libcef_dll/cpptoc/v8context_cpptoc.h @@ -0,0 +1,34 @@ +// Copyright (c) 2010 The Chromium Embedded Framework 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 was generated by the CEF translator tool and should not edited +// by hand. See the translator.README.txt file in the tools directory for +// more information. +// +#ifndef _V8CONTEXT_CPPTOC_H +#define _V8CONTEXT_CPPTOC_H + +#ifndef BUILDING_CEF_SHARED +#pragma message("Warning: "__FILE__" may be accessed DLL-side only") +#else // BUILDING_CEF_SHARED + +#include "include/cef.h" +#include "include/cef_capi.h" +#include "libcef_dll/cpptoc/cpptoc.h" + +// Wrap a C++ class with a C structure. +// This class may be instantiated and accessed DLL-side only. +class CefV8ContextCppToC + : public CefCppToC +{ +public: + CefV8ContextCppToC(CefV8Context* cls); + virtual ~CefV8ContextCppToC() {} +}; + +#endif // BUILDING_CEF_SHARED +#endif // _V8CONTEXT_CPPTOC_H + diff --git a/libcef_dll/cpptoc/v8value_cpptoc.cc b/libcef_dll/cpptoc/v8value_cpptoc.cc index 839f7102b..e68aea670 100644 --- a/libcef_dll/cpptoc/v8value_cpptoc.cc +++ b/libcef_dll/cpptoc/v8value_cpptoc.cc @@ -10,6 +10,7 @@ // for more information. // +#include "libcef_dll/cpptoc/v8context_cpptoc.h" #include "libcef_dll/cpptoc/v8value_cpptoc.h" #include "libcef_dll/ctocpp/base_ctocpp.h" #include "libcef_dll/ctocpp/v8handler_ctocpp.h" @@ -374,11 +375,12 @@ int CEF_CALLBACK v8value_execute_function(struct _cef_v8value_t* self, cef_string_t* exception) { DCHECK(self); - DCHECK(object); - if(!self || !object) + if(!self) return 0; - CefRefPtr objectPtr = CefV8ValueCppToC::Unwrap(object); + CefRefPtr objectPtr; + if(object) + objectPtr = CefV8ValueCppToC::Unwrap(object); CefV8ValueList argsList; for(size_t i = 0; i < argumentCount; i++) { argsList.push_back(CefV8ValueCppToC::Unwrap(arguments[i])); @@ -394,6 +396,37 @@ int CEF_CALLBACK v8value_execute_function(struct _cef_v8value_t* self, return rv; } +int CEF_CALLBACK v8value_execute_function_with_context( + struct _cef_v8value_t* self, cef_v8context_t* context, + struct _cef_v8value_t* object, size_t argumentCount, + struct _cef_v8value_t* const* arguments, struct _cef_v8value_t** retval, + cef_string_t* exception) +{ + DCHECK(self); + if(!self) + return 0; + + CefRefPtr contextPtr; + if(context) + contextPtr = CefV8ContextCppToC::Unwrap(context); + CefRefPtr objectPtr; + if(object) + objectPtr = CefV8ValueCppToC::Unwrap(object); + CefV8ValueList argsList; + for(size_t i = 0; i < argumentCount; i++) { + argsList.push_back(CefV8ValueCppToC::Unwrap(arguments[i])); + } + CefRefPtr retvalPtr; + + CefString exceptionStr(exception); + bool rv = CefV8ValueCppToC::Get(self)->ExecuteFunctionWithContext( + contextPtr, objectPtr, argsList, retvalPtr, exceptionStr); + if(retvalPtr.get() && retval) + *retval = CefV8ValueCppToC::Wrap(retvalPtr); + + return rv; +} + // CONSTRUCTOR - Do not edit by hand. @@ -427,6 +460,8 @@ CefV8ValueCppToC::CefV8ValueCppToC(CefV8Value* cls) struct_.struct_.get_function_name = v8value_get_function_name; struct_.struct_.get_function_handler = v8value_get_function_handler; struct_.struct_.execute_function = v8value_execute_function; + struct_.struct_.execute_function_with_context = + v8value_execute_function_with_context; } #ifdef _DEBUG diff --git a/libcef_dll/ctocpp/frame_ctocpp.cc b/libcef_dll/ctocpp/frame_ctocpp.cc index d563219bd..d56701f5d 100644 --- a/libcef_dll/ctocpp/frame_ctocpp.cc +++ b/libcef_dll/ctocpp/frame_ctocpp.cc @@ -10,6 +10,7 @@ // tools directory for more information. // +#include "libcef_dll/ctocpp/browser_ctocpp.h" #include "libcef_dll/ctocpp/frame_ctocpp.h" #include "libcef_dll/ctocpp/request_ctocpp.h" #include "libcef_dll/ctocpp/stream_reader_ctocpp.h" @@ -193,6 +194,19 @@ CefString CefFrameCToCpp::GetURL() return str; } +CefRefPtr CefFrameCToCpp::GetBrowser() +{ + CefRefPtr browser; + if(CEF_MEMBER_MISSING(struct_, get_browser)) + return browser; + + cef_browser_t* browserStruct = struct_->get_browser(struct_); + if(browserStruct) + return CefBrowserCToCpp::Wrap(browserStruct); + + return browser; +} + #ifdef _DEBUG template<> long CefCToCpp::DebugObjCt = diff --git a/libcef_dll/ctocpp/frame_ctocpp.h b/libcef_dll/ctocpp/frame_ctocpp.h index 5e4accecb..ec6b5eefa 100644 --- a/libcef_dll/ctocpp/frame_ctocpp.h +++ b/libcef_dll/ctocpp/frame_ctocpp.h @@ -53,6 +53,7 @@ public: virtual bool IsFocused(); virtual CefString GetName(); virtual CefString GetURL(); + virtual CefRefPtr GetBrowser(); }; #endif // USING_CEF_SHARED diff --git a/libcef_dll/ctocpp/v8context_ctocpp.cc b/libcef_dll/ctocpp/v8context_ctocpp.cc new file mode 100644 index 000000000..2555ada2d --- /dev/null +++ b/libcef_dll/ctocpp/v8context_ctocpp.cc @@ -0,0 +1,81 @@ +// Copyright (c) 2010 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. +// +// --------------------------------------------------------------------------- +// +// A portion of this file was generated by the CEF translator tool. When +// making changes by hand only do so within the body of existing static and +// virtual method implementations. See the translator.README.txt file in the +// tools directory for more information. +// + +#include "libcef_dll/ctocpp/browser_ctocpp.h" +#include "libcef_dll/ctocpp/frame_ctocpp.h" +#include "libcef_dll/ctocpp/v8context_ctocpp.h" +#include "libcef_dll/ctocpp/v8value_ctocpp.h" + + +// STATIC METHODS - Body may be edited by hand. + +CefRefPtr CefV8Context::GetCurrentContext() +{ + cef_v8context_t* impl = cef_v8context_get_current_context(); + if(impl) + return CefV8ContextCToCpp::Wrap(impl); + return NULL; +} + +CefRefPtr CefV8Context::GetEnteredContext() +{ + cef_v8context_t* impl = cef_v8context_get_entered_context(); + if(impl) + return CefV8ContextCToCpp::Wrap(impl); + return NULL; +} + + +// VIRTUAL METHODS - Body may be edited by hand. + +CefRefPtr CefV8ContextCToCpp::GetBrowser() +{ + if(CEF_MEMBER_MISSING(struct_, get_browser)) + return NULL; + + cef_browser_t* browserStruct = struct_->get_browser(struct_); + if(browserStruct) + return CefBrowserCToCpp::Wrap(browserStruct); + + return NULL; +} + +CefRefPtr CefV8ContextCToCpp::GetFrame() +{ + if(CEF_MEMBER_MISSING(struct_, get_frame)) + return NULL; + + cef_frame_t* frameStruct = struct_->get_frame(struct_); + if(frameStruct) + return CefFrameCToCpp::Wrap(frameStruct); + + return NULL; +} + +CefRefPtr CefV8ContextCToCpp::GetGlobal() +{ + if(CEF_MEMBER_MISSING(struct_, get_global)) + return NULL; + + cef_v8value_t* v8valueStruct = struct_->get_global(struct_); + if(v8valueStruct) + return CefV8ValueCToCpp::Wrap(v8valueStruct); + + return NULL; +} + + +#ifdef _DEBUG +template<> long CefCToCpp::DebugObjCt = 0; +#endif + diff --git a/libcef_dll/ctocpp/v8context_ctocpp.h b/libcef_dll/ctocpp/v8context_ctocpp.h new file mode 100644 index 000000000..a000e1dc4 --- /dev/null +++ b/libcef_dll/ctocpp/v8context_ctocpp.h @@ -0,0 +1,41 @@ +// Copyright (c) 2010 The Chromium Embedded Framework 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 was generated by the CEF translator tool and should not edited +// by hand. See the translator.README.txt file in the tools directory for +// more information. +// + +#ifndef _V8CONTEXT_CTOCPP_H +#define _V8CONTEXT_CTOCPP_H + +#ifndef USING_CEF_SHARED +#pragma message("Warning: "__FILE__" may be accessed wrapper-side only") +#else // USING_CEF_SHARED + +#include "include/cef.h" +#include "include/cef_capi.h" +#include "libcef_dll/ctocpp/ctocpp.h" + +// Wrap a C structure with a C++ class. +// This class may be instantiated and accessed wrapper-side only. +class CefV8ContextCToCpp + : public CefCToCpp +{ +public: + CefV8ContextCToCpp(cef_v8context_t* str) + : CefCToCpp(str) {} + virtual ~CefV8ContextCToCpp() {} + + // CefV8Context methods + virtual CefRefPtr GetBrowser(); + virtual CefRefPtr GetFrame(); + virtual CefRefPtr GetGlobal(); +}; + +#endif // USING_CEF_SHARED +#endif // _V8CONTEXT_CTOCPP_H + diff --git a/libcef_dll/ctocpp/v8value_ctocpp.cc b/libcef_dll/ctocpp/v8value_ctocpp.cc index bf8a25ecb..4047e23f9 100644 --- a/libcef_dll/ctocpp/v8value_ctocpp.cc +++ b/libcef_dll/ctocpp/v8value_ctocpp.cc @@ -12,6 +12,7 @@ #include "libcef_dll/cpptoc/base_cpptoc.h" #include "libcef_dll/cpptoc/v8handler_cpptoc.h" +#include "libcef_dll/ctocpp/v8context_ctocpp.h" #include "libcef_dll/ctocpp/v8value_ctocpp.h" #include "libcef_dll/transfer_util.h" @@ -344,7 +345,7 @@ bool CefV8ValueCToCpp::ExecuteFunction(CefRefPtr object, CefString& exception) { if(CEF_MEMBER_MISSING(struct_, execute_function)) - return RV_CONTINUE; + return false; cef_v8value_t** argsStructPtr = NULL; int argsSize = arguments.size(); @@ -356,7 +357,8 @@ bool CefV8ValueCToCpp::ExecuteFunction(CefRefPtr object, cef_v8value_t* retvalStruct = NULL; - int rv = struct_->execute_function(struct_, CefV8ValueCToCpp::Unwrap(object), + int rv = struct_->execute_function(struct_, + object.get() ? CefV8ValueCToCpp::Unwrap(object): NULL, argsSize, argsStructPtr, &retvalStruct, exception.GetWritableStruct()); if(retvalStruct) retval = CefV8ValueCToCpp::Wrap(retvalStruct); @@ -367,6 +369,38 @@ bool CefV8ValueCToCpp::ExecuteFunction(CefRefPtr object, return rv?true:false; } +bool CefV8ValueCToCpp::ExecuteFunctionWithContext( + CefRefPtr context, CefRefPtr object, + const CefV8ValueList& arguments, CefRefPtr& retval, + CefString& exception) +{ + if(CEF_MEMBER_MISSING(struct_, execute_function_with_context)) + return false; + + cef_v8value_t** argsStructPtr = NULL; + int argsSize = arguments.size(); + if(argsSize > 0) { + argsStructPtr = new cef_v8value_t*[argsSize]; + for(int i = 0; i < argsSize; ++i) + argsStructPtr[i] = CefV8ValueCToCpp::Unwrap(arguments[i]); + } + + cef_v8value_t* retvalStruct = NULL; + + int rv = struct_->execute_function_with_context(struct_, + context.get() ? CefV8ContextCToCpp::Unwrap(context): NULL, + object.get() ? CefV8ValueCToCpp::Unwrap(object): NULL, + argsSize, argsStructPtr, &retvalStruct, exception.GetWritableStruct()); + + if(retvalStruct) + retval = CefV8ValueCToCpp::Wrap(retvalStruct); + + if(argsStructPtr) + delete [] argsStructPtr; + + return rv?true:false; +} + #ifdef _DEBUG template<> long CefCToCpp object, const CefV8ValueList& arguments, CefRefPtr& retval, CefString& exception); + virtual bool ExecuteFunctionWithContext(CefRefPtr context, + CefRefPtr object, const CefV8ValueList& arguments, + CefRefPtr& retval, CefString& exception); }; #endif // USING_CEF_SHARED diff --git a/libcef_dll/wrapper/libcef_dll_wrapper.cc b/libcef_dll/wrapper/libcef_dll_wrapper.cc index 8f51f77ed..3eb50878f 100644 --- a/libcef_dll/wrapper/libcef_dll_wrapper.cc +++ b/libcef_dll/wrapper/libcef_dll_wrapper.cc @@ -22,6 +22,7 @@ #include "libcef_dll/ctocpp/stream_reader_ctocpp.h" #include "libcef_dll/ctocpp/stream_writer_ctocpp.h" #include "libcef_dll/ctocpp/v8value_ctocpp.h" +#include "libcef_dll/ctocpp/v8context_ctocpp.h" #include "libcef_dll/ctocpp/web_urlrequest_ctocpp.h" #include "libcef_dll/ctocpp/xml_reader_ctocpp.h" #include "libcef_dll/ctocpp/zip_reader_ctocpp.h" @@ -52,6 +53,7 @@ void CefShutdown() DCHECK(CefPostDataElementCToCpp::DebugObjCt == 0); DCHECK(CefStreamReaderCToCpp::DebugObjCt == 0); DCHECK(CefStreamWriterCToCpp::DebugObjCt == 0); + DCHECK(CefV8ContextCToCpp::DebugObjCt == 0); DCHECK(CefV8ValueCToCpp::DebugObjCt == 0); DCHECK(CefWebURLRequestCToCpp::DebugObjCt == 0); DCHECK(CefXmlReaderCToCpp::DebugObjCt == 0); diff --git a/tests/unittests/test_handler.h b/tests/unittests/test_handler.h index 1b3e432ca..d9b4e2fd0 100644 --- a/tests/unittests/test_handler.h +++ b/tests/unittests/test_handler.h @@ -9,6 +9,17 @@ #include "base/synchronization/waitable_event.h" #include "testing/gtest/include/gtest/gtest.h" +class TrackCallback +{ +public: + TrackCallback(): gotit_(false) {} + void yes() { gotit_ = true; } + bool isSet() { return gotit_; } + operator bool() const { return gotit_; } +protected: + bool gotit_; +}; + // Base implementation of CefHandler for unit tests. class TestHandler : public CefThreadSafeBase { diff --git a/tests/unittests/v8_unittest.cc b/tests/unittests/v8_unittest.cc index d19838b38..581341a7a 100644 --- a/tests/unittests/v8_unittest.cc +++ b/tests/unittests/v8_unittest.cc @@ -3,6 +3,7 @@ // can be found in the LICENSE file. #include "include/cef.h" +#include "include/cef_runnable.h" #include "testing/gtest/include/gtest/gtest.h" #include "test_handler.h" @@ -352,3 +353,358 @@ TEST(V8Test, Extension) ASSERT_TRUE(g_V8TestV8HandlerExecuteCalled); ASSERT_TRUE(g_V8TestV8HandlerExecute2Called); } + +// Using a delegate so that the code below can remain inline. +class CefV8HandlerDelegate +{ +public: + virtual bool Execute(const CefString& name, + CefRefPtr object, + const CefV8ValueList& arguments, + CefRefPtr& retval, + CefString& exception) = 0; +}; + +// Verify context works to allow async v8 callbacks +TEST(V8Test, Context) +{ + class DelegatingV8Handler : public CefThreadSafeBase + { + public: + DelegatingV8Handler(CefV8HandlerDelegate *delegate): + delegate_(delegate) { } + + ~DelegatingV8Handler() + { + } + + bool Execute(const CefString& name, + CefRefPtr object, + const CefV8ValueList& arguments, + CefRefPtr& retval, + CefString& exception) + { + return delegate_->Execute(name, object, arguments, retval, exception); + } + + private: + CefV8HandlerDelegate *delegate_; + }; + + class TestContextHandler: public TestHandler, public CefV8HandlerDelegate + { + public: + TestContextHandler() {} + + virtual void RunTest() + { + // Test Flow: + // load main.html. + // 1. main.html calls hello("main", callIFrame) in the execute handler. + // The excute handler checks that "main" was called and saves + // the callIFrame function, context, and receiver object. + // 2. iframe.html calls hello("iframe") in the execute handler. + // The execute handler checks that "iframe" was called. if both main + // and iframe were called, it calls CallIFrame() + // 3. CallIFrame calls "callIFrame" in main.html + // 4. which calls iframe.html "calledFromMain()". + // 5. which calls "fromIFrame()" in execute handler. + // The execute handler checks that the entered and current urls are + // what we expect: "main.html" and "iframe.html", respectively + // 6. It then posts a task to call AsyncTestContext + // you can validate the entered and current context are still the + // same here, but it is not checked by this test case. + // 7. AsyncTestContext tests to make sure that no context is set at + // this point and loads "begin.html" + // 8. begin.html calls "begin(func1, func2)" in the execute handler + // The execute handler posts a tasks to call both of those functions + // when no context is defined. Both should work with the specified + // context. AsyncTestException should run first, followed by + // AsyncTestNavigate() which calls the func2 to do a document.location + // based loading of "end.html". + // 9. end.html calls "end()" in the execute handler. + // which concludes the test. + + std::stringstream mainHtml; + mainHtml << + "" + "

Hello From Main Frame

" + "" + "" + ""; + + AddResource("http://tests/main.html", mainHtml.str(), "text/html"); + + std::stringstream iframeHtml; + iframeHtml << + "" + "

Hello From IFRAME

" + "" + ""; + + AddResource("http://tests/iframe.html", iframeHtml.str(), "text/html"); + + std::stringstream beginHtml; + beginHtml << + "" + "

V8 Context Test

" + "" + ""; + + AddResource("http://tests/begin.html", beginHtml.str(), "text/html"); + + std::stringstream endHtml; + endHtml << + "" + "

Navigation Succeeded!

" + "" + ""; + + AddResource("http://tests/end.html", endHtml.str(), "text/html"); + + CreateBrowser("http://tests/main.html"); + } + + virtual RetVal HandleLoadEnd(CefRefPtr browser, + CefRefPtr frame, + bool isMainContent, + int httpStatusCode) + { + return RV_CONTINUE; + } + + virtual RetVal HandleJSBinding(CefRefPtr browser, + CefRefPtr frame, + CefRefPtr object) + { + CefRefPtr cc = CefV8Context::GetCurrentContext(); + CefRefPtr currentBrowser = cc->GetBrowser(); + CefRefPtr currentFrame = cc->GetFrame(); + CefString currentURL = currentFrame->GetURL(); + + CefRefPtr ec = CefV8Context::GetEnteredContext(); + CefRefPtr enteredBrowser = ec->GetBrowser(); + CefRefPtr enteredFrame = ec->GetFrame(); + CefString enteredURL = enteredFrame->GetURL(); + + CefRefPtr funcHandler(new DelegatingV8Handler(this)); + CefRefPtr helloFunc = + CefV8Value::CreateFunction("hello", funcHandler); + object->SetValue("hello", helloFunc); + + CefRefPtr fromIFrameFunc = + CefV8Value::CreateFunction("fromIFrame", funcHandler); + object->SetValue("fromIFrame", fromIFrameFunc); + + CefRefPtr goFunc = + CefV8Value::CreateFunction("begin", funcHandler); + object->SetValue("begin", goFunc); + + CefRefPtr doneFunc = + CefV8Value::CreateFunction("end", funcHandler); + object->SetValue("end", doneFunc); + + return RV_HANDLED; + } + + void CallIFrame() + { + CefV8ValueList args; + CefRefPtr rv; + CefString exception; + CefRefPtr empty; + ASSERT_TRUE(funcIFrame_->ExecuteFunctionWithContext( + contextIFrame_, empty, args, rv, exception)); + } + + void AsyncTestContext(CefRefPtr ec, + CefRefPtr cc) + { + // we should not be in a context in this call. + CefRefPtr noContext = CefV8Context::GetCurrentContext(); + if (!noContext.get()) + got_no_context_.yes(); + + CefRefPtr enteredBrowser = ec->GetBrowser(); + CefRefPtr enteredFrame = ec->GetFrame(); + CefString enteredURL = enteredFrame->GetURL(); + CefString enteredName = enteredFrame->GetName(); + CefRefPtr enteredMainFrame = enteredBrowser->GetMainFrame(); + CefString enteredMainURL = enteredMainFrame->GetURL(); + CefString enteredMainName = enteredMainFrame->GetName(); + + CefRefPtr currentBrowser = cc->GetBrowser(); + CefRefPtr currentFrame = cc->GetFrame(); + CefString currentURL = currentFrame->GetURL(); + CefString currentName = currentFrame->GetName(); + CefRefPtr currentMainFrame = currentBrowser->GetMainFrame(); + CefString currentMainURL = currentMainFrame->GetURL(); + CefString currentMainName = currentMainFrame->GetName(); + + CefRefPtr copyFromMainFrame = + currentMainFrame->GetBrowser(); + + currentMainFrame->LoadURL("http://tests/begin.html"); + } + + void AsyncTestException( + CefRefPtr context, + CefRefPtr func) + { + CefV8ValueList args; + CefRefPtr rv; + CefString exception; + CefRefPtr empty; + ASSERT_TRUE(func->ExecuteFunctionWithContext( + context, empty, args, rv, exception)); + if(exception == "Uncaught My Exception") + got_exception_.yes(); + } + + void AsyncTestNavigation( + CefRefPtr context, + CefRefPtr func) + { + CefV8ValueList args; + args.push_back(CefV8Value::CreateString("http://tests/end.html")); + CefRefPtr rv; + CefString exception; + CefRefPtr global = context->GetGlobal(); + ASSERT_TRUE(func->ExecuteFunctionWithContext( + context, global, args, rv, exception)); + if(exception.empty()) + got_navigation_.yes(); + } + + bool Execute(const CefString& name, + CefRefPtr object, + const CefV8ValueList& arguments, + CefRefPtr& retval, + CefString& exception) + { + CefRefPtr cc = CefV8Context::GetCurrentContext(); + CefRefPtr ec = CefV8Context::GetEnteredContext(); + + CefRefPtr enteredBrowser = ec->GetBrowser(); + CefRefPtr enteredFrame = ec->GetFrame(); + CefString enteredURL = enteredFrame->GetURL(); + CefString enteredName = enteredFrame->GetName(); + CefRefPtr enteredMainFrame = enteredBrowser->GetMainFrame(); + CefString enteredMainURL = enteredMainFrame->GetURL(); + CefString enteredMainName = enteredMainFrame->GetName(); + + CefRefPtr currentBrowser = cc->GetBrowser(); + CefRefPtr currentFrame = cc->GetFrame(); + CefString currentURL = currentFrame->GetURL(); + CefString currentName = currentFrame->GetName(); + CefRefPtr currentMainFrame = currentBrowser->GetMainFrame(); + CefString currentMainURL = currentMainFrame->GetURL(); + CefString currentMainName = currentMainFrame->GetName(); + + if (name == "hello") { + if(arguments.size() == 2 && arguments[0]->IsString() && + arguments[1]->IsFunction()) { + CefString msg = arguments[0]->GetStringValue(); + if(msg == "main") { + got_hello_main_.yes(); + contextIFrame_ = cc; + funcIFrame_ = arguments[1]; + } + } else if(arguments.size() == 1 && arguments[0]->IsString()) { + CefString msg = arguments[0]->GetStringValue(); + if(msg == "iframe") + got_hello_iframe_.yes(); + } + else + return false; + + if(got_hello_main_ && got_hello_iframe_ && funcIFrame_->IsFunction()) + { + // NB: At this point, enteredURL == http://tests/iframe.html which is + // expected since the iframe made the call on its own. The unexpected + // behavior is that in the call to fromIFrame (below) the enteredURL + // == http://tests/main.html even though the iframe.html context was + // entered first. + // -- Perhaps WebKit does something other than look at the bottom + // of stack for the entered context. + if(enteredURL == "http://tests/iframe.html") + got_iframe_as_entered_url_.yes(); + CallIFrame(); + } + return true; + } else if(name == "fromIFrame") { + if(enteredURL == "http://tests/main.html") + got_correct_entered_url_.yes(); + if(currentURL == "http://tests/iframe.html") + got_correct_current_url_.yes(); + CefPostTask(TID_UI, NewCefRunnableMethod(this, + &TestContextHandler::AsyncTestContext, ec, cc)); + return true; + } else if(name == "begin") { + if(arguments.size() == 2 && arguments[0]->IsFunction() && + arguments[1]->IsFunction()) { + CefRefPtr funcException = arguments[0]; + CefRefPtr funcNavigate = arguments[1]; + CefPostTask(TID_UI, NewCefRunnableMethod(this, + &TestContextHandler::AsyncTestException, + cc, funcException)); + CefPostTask(TID_UI, NewCefRunnableMethod(this, + &TestContextHandler::AsyncTestNavigation, + cc, funcNavigate)); + return true; + } + } else if (name == "end") { + got_testcomplete_.yes(); + DestroyTest(); + return true; + } + return false; + } + + // This function we will be called later to make it call into the + // IFRAME, which then calls "fromIFrame" so that we can check the + // entered vs current contexts are working as expected. + CefRefPtr contextIFrame_; + CefRefPtr funcIFrame_; + + TrackCallback got_hello_main_; + TrackCallback got_hello_iframe_; + TrackCallback got_correct_entered_url_; + TrackCallback got_correct_current_url_; + TrackCallback got_iframe_as_entered_url_; + TrackCallback got_no_context_; + TrackCallback got_exception_; + TrackCallback got_navigation_; + TrackCallback got_testcomplete_; + }; + + CefRefPtr handler = new TestContextHandler(); + handler->ExecuteTest(); + + EXPECT_TRUE(handler->got_hello_main_); + EXPECT_TRUE(handler->got_hello_iframe_); + EXPECT_TRUE(handler->got_no_context_); + EXPECT_TRUE(handler->got_iframe_as_entered_url_); + EXPECT_TRUE(handler->got_correct_entered_url_); + EXPECT_TRUE(handler->got_correct_current_url_); + EXPECT_TRUE(handler->got_exception_); + EXPECT_TRUE(handler->got_navigation_); + EXPECT_TRUE(handler->got_testcomplete_); +} diff --git a/tests/unittests/web_urlrequest_unittest.cc b/tests/unittests/web_urlrequest_unittest.cc index 7c216054a..6cbd45e56 100644 --- a/tests/unittests/web_urlrequest_unittest.cc +++ b/tests/unittests/web_urlrequest_unittest.cc @@ -6,17 +6,6 @@ //#define WEB_URLREQUEST_DEBUG -class TrackCallback -{ -public: - TrackCallback(): gotit_(false) {} - void yes() { gotit_ = true; } - bool isSet() { return gotit_; } - operator bool() const { return gotit_; } -protected: - bool gotit_; -}; - class TestResults { public: