mirror of
https://bitbucket.org/chromiumembedded/cef
synced 2025-01-22 15:29:56 +01:00
b3a8da9b25
This is the first pass in removing direct dependencies on the Alloy runtime from code that can potentially be shared between runtimes. CefBrowserHost and CefRequestContext APIs (including CefCookieManager, CefURLRequest, etc.) are not yet implemented for the Chrome runtime. Assert early if these API methods are called while the Chrome runtime is enabled.
2561 lines
76 KiB
C++
2561 lines
76 KiB
C++
// Copyright (c) 2013 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.
|
|
|
|
// MSVC++ requires this to be set before any other includes to get M_PI.
|
|
// Otherwise there will be compile errors in wtf/MathExtras.h.
|
|
#define _USE_MATH_DEFINES
|
|
|
|
#include <map>
|
|
#include <string>
|
|
|
|
#include "base/command_line.h"
|
|
#include "base/compiler_specific.h"
|
|
|
|
// Enable deprecation warnings for MSVC and Clang. See http://crbug.com/585142.
|
|
#if defined(OS_WIN)
|
|
#if defined(__clang__)
|
|
#pragma GCC diagnostic push
|
|
#pragma GCC diagnostic error "-Wdeprecated-declarations"
|
|
#else
|
|
#pragma warning(push)
|
|
#pragma warning(default : 4996)
|
|
#endif
|
|
#endif
|
|
|
|
#include "libcef/renderer/v8_impl.h"
|
|
|
|
#include "libcef/common/app_manager.h"
|
|
#include "libcef/common/cef_switches.h"
|
|
#include "libcef/common/task_runner_impl.h"
|
|
#include "libcef/common/tracker.h"
|
|
#include "libcef/renderer/blink_glue.h"
|
|
#include "libcef/renderer/browser_impl.h"
|
|
#include "libcef/renderer/render_frame_util.h"
|
|
#include "libcef/renderer/thread_util.h"
|
|
|
|
#include "base/bind.h"
|
|
#include "base/lazy_instance.h"
|
|
#include "base/strings/string_number_conversions.h"
|
|
#include "base/threading/thread_local.h"
|
|
#include "third_party/blink/public/web/blink.h"
|
|
#include "third_party/blink/public/web/web_frame.h"
|
|
#include "third_party/blink/public/web/web_local_frame.h"
|
|
#include "url/gurl.h"
|
|
|
|
namespace {
|
|
|
|
static const char kCefTrackObject[] = "Cef::TrackObject";
|
|
|
|
void MessageListenerCallbackImpl(v8::Handle<v8::Message> message,
|
|
v8::Handle<v8::Value> data);
|
|
|
|
// The following *Private functions are convenience wrappers for methods on
|
|
// v8::Object with the corresponding names.
|
|
// Based on extensions/renderer/object_backed_native_handler.cc.
|
|
|
|
void SetPrivate(v8::Local<v8::Context> context,
|
|
v8::Local<v8::Object> obj,
|
|
const char* key,
|
|
v8::Local<v8::Value> value) {
|
|
v8::Isolate* isolate = context->GetIsolate();
|
|
obj->SetPrivate(context,
|
|
v8::Private::ForApi(
|
|
isolate, v8::String::NewFromUtf8(
|
|
isolate, key, v8::NewStringType::kNormal)
|
|
.ToLocalChecked()),
|
|
value)
|
|
.FromJust();
|
|
}
|
|
|
|
bool GetPrivate(v8::Local<v8::Context> context,
|
|
v8::Local<v8::Object> obj,
|
|
const char* key,
|
|
v8::Local<v8::Value>* result) {
|
|
v8::Isolate* isolate = context->GetIsolate();
|
|
return obj
|
|
->GetPrivate(context,
|
|
v8::Private::ForApi(
|
|
isolate, v8::String::NewFromUtf8(
|
|
isolate, key, v8::NewStringType::kNormal)
|
|
.ToLocalChecked()))
|
|
.ToLocal(result);
|
|
}
|
|
|
|
// Manages memory and state information associated with a single Isolate.
|
|
class CefV8IsolateManager {
|
|
public:
|
|
CefV8IsolateManager()
|
|
: isolate_(v8::Isolate::GetCurrent()),
|
|
task_runner_(CEF_RENDER_TASK_RUNNER()),
|
|
message_listener_registered_(false),
|
|
worker_id_(0) {
|
|
DCHECK(isolate_);
|
|
DCHECK(task_runner_.get());
|
|
}
|
|
~CefV8IsolateManager() {
|
|
DCHECK_EQ(isolate_, v8::Isolate::GetCurrent());
|
|
DCHECK(context_map_.empty());
|
|
}
|
|
|
|
scoped_refptr<CefV8ContextState> GetContextState(
|
|
v8::Local<v8::Context> context) {
|
|
DCHECK_EQ(isolate_, v8::Isolate::GetCurrent());
|
|
DCHECK(context.IsEmpty() || isolate_ == context->GetIsolate());
|
|
|
|
if (context.IsEmpty()) {
|
|
if (isolate_->InContext())
|
|
context = isolate_->GetCurrentContext();
|
|
else
|
|
return scoped_refptr<CefV8ContextState>();
|
|
}
|
|
|
|
int hash = context->Global()->GetIdentityHash();
|
|
ContextMap::const_iterator it = context_map_.find(hash);
|
|
if (it != context_map_.end())
|
|
return it->second;
|
|
|
|
scoped_refptr<CefV8ContextState> state = new CefV8ContextState();
|
|
context_map_.insert(std::make_pair(hash, state));
|
|
|
|
return state;
|
|
}
|
|
|
|
void ReleaseContext(v8::Local<v8::Context> context) {
|
|
DCHECK_EQ(isolate_, v8::Isolate::GetCurrent());
|
|
DCHECK_EQ(isolate_, context->GetIsolate());
|
|
|
|
int hash = context->Global()->GetIdentityHash();
|
|
ContextMap::iterator it = context_map_.find(hash);
|
|
if (it != context_map_.end()) {
|
|
it->second->Detach();
|
|
context_map_.erase(it);
|
|
}
|
|
}
|
|
|
|
void AddGlobalTrackObject(CefTrackNode* object) {
|
|
DCHECK_EQ(isolate_, v8::Isolate::GetCurrent());
|
|
global_manager_.Add(object);
|
|
}
|
|
|
|
void DeleteGlobalTrackObject(CefTrackNode* object) {
|
|
DCHECK_EQ(isolate_, v8::Isolate::GetCurrent());
|
|
global_manager_.Delete(object);
|
|
}
|
|
|
|
void SetUncaughtExceptionStackSize(int stack_size) {
|
|
if (stack_size <= 0)
|
|
return;
|
|
|
|
if (!message_listener_registered_) {
|
|
isolate_->AddMessageListener(&MessageListenerCallbackImpl);
|
|
message_listener_registered_ = true;
|
|
}
|
|
|
|
isolate_->SetCaptureStackTraceForUncaughtExceptions(
|
|
true, stack_size, v8::StackTrace::kDetailed);
|
|
}
|
|
|
|
void SetWorkerAttributes(int worker_id, const GURL& worker_url) {
|
|
worker_id_ = worker_id;
|
|
worker_url_ = worker_url;
|
|
}
|
|
|
|
v8::Isolate* isolate() const { return isolate_; }
|
|
scoped_refptr<base::SingleThreadTaskRunner> task_runner() const {
|
|
return task_runner_;
|
|
}
|
|
|
|
int worker_id() const { return worker_id_; }
|
|
|
|
const GURL& worker_url() const { return worker_url_; }
|
|
|
|
private:
|
|
v8::Isolate* isolate_;
|
|
scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
|
|
|
|
typedef std::map<int, scoped_refptr<CefV8ContextState>> ContextMap;
|
|
ContextMap context_map_;
|
|
|
|
// Used for globally tracked objects that are not associated with a particular
|
|
// context.
|
|
CefTrackManager global_manager_;
|
|
|
|
// True if the message listener has been registered.
|
|
bool message_listener_registered_;
|
|
|
|
// Attributes associated with WebWorker threads.
|
|
int worker_id_;
|
|
GURL worker_url_;
|
|
};
|
|
|
|
// Chromium uses the default Isolate for the main render process thread and a
|
|
// new Isolate for each WebWorker thread. Continue this pattern by tracking
|
|
// Isolate information on a per-thread basis. This implementation will need to
|
|
// be re-worked (perhaps using a map keyed on v8::Isolate::GetCurrent()) if
|
|
// in the future Chromium begins using the same Isolate across multiple threads.
|
|
class CefV8StateManager {
|
|
public:
|
|
CefV8StateManager() {}
|
|
|
|
void CreateIsolateManager() {
|
|
DCHECK(!current_tls_.Get());
|
|
current_tls_.Set(new CefV8IsolateManager());
|
|
}
|
|
|
|
void DestroyIsolateManager() {
|
|
DCHECK(current_tls_.Get());
|
|
delete current_tls_.Get();
|
|
current_tls_.Set(nullptr);
|
|
}
|
|
|
|
CefV8IsolateManager* GetIsolateManager() {
|
|
CefV8IsolateManager* manager = current_tls_.Get();
|
|
DCHECK(manager);
|
|
return manager;
|
|
}
|
|
|
|
private:
|
|
base::ThreadLocalPointer<CefV8IsolateManager> current_tls_;
|
|
};
|
|
|
|
base::LazyInstance<CefV8StateManager>::Leaky g_v8_state =
|
|
LAZY_INSTANCE_INITIALIZER;
|
|
|
|
CefV8IsolateManager* GetIsolateManager() {
|
|
return g_v8_state.Pointer()->GetIsolateManager();
|
|
}
|
|
|
|
class V8TrackObject : public CefTrackNode {
|
|
public:
|
|
explicit V8TrackObject(v8::Isolate* isolate)
|
|
: isolate_(isolate), external_memory_(0) {
|
|
DCHECK(isolate_);
|
|
isolate_->AdjustAmountOfExternalAllocatedMemory(
|
|
static_cast<int>(sizeof(V8TrackObject)));
|
|
}
|
|
~V8TrackObject() {
|
|
isolate_->AdjustAmountOfExternalAllocatedMemory(
|
|
-static_cast<int>(sizeof(V8TrackObject)) - external_memory_);
|
|
}
|
|
|
|
inline int GetExternallyAllocatedMemory() { return external_memory_; }
|
|
|
|
int AdjustExternallyAllocatedMemory(int change_in_bytes) {
|
|
int new_value = external_memory_ + change_in_bytes;
|
|
if (new_value < 0) {
|
|
NOTREACHED() << "External memory usage cannot be less than 0 bytes";
|
|
change_in_bytes = -(external_memory_);
|
|
new_value = 0;
|
|
}
|
|
|
|
if (change_in_bytes != 0)
|
|
isolate_->AdjustAmountOfExternalAllocatedMemory(change_in_bytes);
|
|
external_memory_ = new_value;
|
|
|
|
return new_value;
|
|
}
|
|
|
|
inline void SetAccessor(CefRefPtr<CefV8Accessor> accessor) {
|
|
accessor_ = accessor;
|
|
}
|
|
|
|
inline CefRefPtr<CefV8Accessor> GetAccessor() { return accessor_; }
|
|
|
|
inline void SetInterceptor(CefRefPtr<CefV8Interceptor> interceptor) {
|
|
interceptor_ = interceptor;
|
|
}
|
|
|
|
inline CefRefPtr<CefV8Interceptor> GetInterceptor() { return interceptor_; }
|
|
|
|
inline void SetHandler(CefRefPtr<CefV8Handler> handler) {
|
|
handler_ = handler;
|
|
}
|
|
|
|
inline CefRefPtr<CefV8Handler> GetHandler() { return handler_; }
|
|
|
|
inline void SetUserData(CefRefPtr<CefBaseRefCounted> user_data) {
|
|
user_data_ = user_data;
|
|
}
|
|
|
|
inline CefRefPtr<CefBaseRefCounted> GetUserData() { return user_data_; }
|
|
|
|
// Attach this track object to the specified V8 object.
|
|
void AttachTo(v8::Local<v8::Context> context, v8::Local<v8::Object> object) {
|
|
SetPrivate(context, object, kCefTrackObject,
|
|
v8::External::New(isolate_, this));
|
|
}
|
|
|
|
// Retrieve the track object for the specified V8 object.
|
|
static V8TrackObject* Unwrap(v8::Local<v8::Context> context,
|
|
v8::Local<v8::Object> object) {
|
|
v8::Local<v8::Value> value;
|
|
if (GetPrivate(context, object, kCefTrackObject, &value))
|
|
return static_cast<V8TrackObject*>(v8::External::Cast(*value)->Value());
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
private:
|
|
v8::Isolate* isolate_;
|
|
CefRefPtr<CefV8Accessor> accessor_;
|
|
CefRefPtr<CefV8Interceptor> interceptor_;
|
|
CefRefPtr<CefV8Handler> handler_;
|
|
CefRefPtr<CefBaseRefCounted> user_data_;
|
|
int external_memory_;
|
|
};
|
|
|
|
class V8TrackString : public CefTrackNode {
|
|
public:
|
|
explicit V8TrackString(const std::string& str) : string_(str) {}
|
|
const char* GetString() { return string_.c_str(); }
|
|
|
|
private:
|
|
std::string string_;
|
|
};
|
|
|
|
class V8TrackArrayBuffer : public CefTrackNode {
|
|
public:
|
|
explicit V8TrackArrayBuffer(
|
|
v8::Isolate* isolate,
|
|
void* buffer,
|
|
CefRefPtr<CefV8ArrayBufferReleaseCallback> release_callback)
|
|
: isolate_(isolate),
|
|
buffer_(buffer),
|
|
release_callback_(release_callback) {
|
|
DCHECK(isolate_);
|
|
isolate_->AdjustAmountOfExternalAllocatedMemory(
|
|
static_cast<int>(sizeof(V8TrackArrayBuffer)));
|
|
}
|
|
|
|
~V8TrackArrayBuffer() {
|
|
if (buffer_ != nullptr) {
|
|
release_callback_->ReleaseBuffer(buffer_);
|
|
}
|
|
isolate_->AdjustAmountOfExternalAllocatedMemory(
|
|
-static_cast<int>(sizeof(V8TrackArrayBuffer)));
|
|
}
|
|
|
|
CefRefPtr<CefV8ArrayBufferReleaseCallback> GetReleaseCallback() {
|
|
return release_callback_;
|
|
}
|
|
|
|
void Detach() { buffer_ = nullptr; }
|
|
|
|
// Attach this track object to the specified V8 object.
|
|
void AttachTo(v8::Local<v8::Context> context,
|
|
v8::Local<v8::ArrayBuffer> arrayBuffer) {
|
|
SetPrivate(context, arrayBuffer, kCefTrackObject,
|
|
v8::External::New(isolate_, this));
|
|
}
|
|
|
|
// Retrieve the track object for the specified V8 object.
|
|
static V8TrackArrayBuffer* Unwrap(v8::Local<v8::Context> context,
|
|
v8::Local<v8::Object> object) {
|
|
v8::Local<v8::Value> value;
|
|
if (GetPrivate(context, object, kCefTrackObject, &value))
|
|
return static_cast<V8TrackArrayBuffer*>(
|
|
v8::External::Cast(*value)->Value());
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
private:
|
|
v8::Isolate* isolate_;
|
|
void* buffer_;
|
|
CefRefPtr<CefV8ArrayBufferReleaseCallback> release_callback_;
|
|
};
|
|
|
|
// Object wrapped in a v8::External and passed as the Data argument to
|
|
// v8::FunctionTemplate::New.
|
|
class V8FunctionData {
|
|
public:
|
|
static v8::Local<v8::External> Create(v8::Isolate* isolate,
|
|
const CefString& function_name,
|
|
CefRefPtr<CefV8Handler> handler) {
|
|
// |data| will be deleted if/when the returned v8::External is GC'd.
|
|
V8FunctionData* data = new V8FunctionData(isolate, function_name, handler);
|
|
return data->CreateExternal();
|
|
}
|
|
|
|
static V8FunctionData* Unwrap(v8::Local<v8::Value> data) {
|
|
DCHECK(data->IsExternal());
|
|
return static_cast<V8FunctionData*>(v8::External::Cast(*data)->Value());
|
|
}
|
|
|
|
CefString function_name() const { return function_name_; }
|
|
|
|
CefV8Handler* handler() const {
|
|
if (!handler_)
|
|
return nullptr;
|
|
return handler_.get();
|
|
}
|
|
|
|
private:
|
|
V8FunctionData(v8::Isolate* isolate,
|
|
const CefString& function_name,
|
|
CefRefPtr<CefV8Handler> handler)
|
|
: isolate_(isolate), function_name_(function_name), handler_(handler) {
|
|
DCHECK(isolate_);
|
|
DCHECK(handler_);
|
|
}
|
|
|
|
~V8FunctionData() {
|
|
isolate_->AdjustAmountOfExternalAllocatedMemory(
|
|
-static_cast<int>(sizeof(V8FunctionData)));
|
|
handler_ = nullptr;
|
|
function_name_ = "FreedFunction";
|
|
}
|
|
|
|
v8::Local<v8::External> CreateExternal() {
|
|
v8::Local<v8::External> external = v8::External::New(isolate_, this);
|
|
|
|
isolate_->AdjustAmountOfExternalAllocatedMemory(
|
|
static_cast<int>(sizeof(V8FunctionData)));
|
|
|
|
handle_.Reset(isolate_, external);
|
|
handle_.SetWeak(this, FirstWeakCallback, v8::WeakCallbackType::kParameter);
|
|
|
|
return external;
|
|
}
|
|
|
|
static void FirstWeakCallback(
|
|
const v8::WeakCallbackInfo<V8FunctionData>& data) {
|
|
V8FunctionData* wrapper = data.GetParameter();
|
|
wrapper->handle_.Reset();
|
|
data.SetSecondPassCallback(SecondWeakCallback);
|
|
}
|
|
|
|
static void SecondWeakCallback(
|
|
const v8::WeakCallbackInfo<V8FunctionData>& data) {
|
|
V8FunctionData* wrapper = data.GetParameter();
|
|
delete wrapper;
|
|
}
|
|
|
|
v8::Isolate* isolate_;
|
|
CefString function_name_;
|
|
CefRefPtr<CefV8Handler> handler_;
|
|
v8::Persistent<v8::External> handle_;
|
|
};
|
|
|
|
// Convert a CefString to a V8::String.
|
|
v8::Local<v8::String> GetV8String(v8::Isolate* isolate, const CefString& str) {
|
|
#if defined(CEF_STRING_TYPE_UTF16)
|
|
// Already a UTF16 string.
|
|
return v8::String::NewFromTwoByte(
|
|
isolate,
|
|
reinterpret_cast<uint16_t*>(
|
|
const_cast<CefString::char_type*>(str.c_str())),
|
|
v8::NewStringType::kNormal, str.length())
|
|
.ToLocalChecked();
|
|
#elif defined(CEF_STRING_TYPE_UTF8)
|
|
// Already a UTF8 string.
|
|
return v8::String::NewFromUtf8(isolate, const_cast<char*>(str.c_str()),
|
|
v8::NewStringType::kNormal, str.length())
|
|
.ToLocalChecked();
|
|
#else
|
|
// Convert the string to UTF8.
|
|
std::string tmpStr = str;
|
|
return v8::String::NewFromUtf8(isolate, tmpStr.c_str(),
|
|
v8::NewStringType::kNormal, tmpStr.length())
|
|
.ToLocalChecked();
|
|
#endif
|
|
}
|
|
|
|
#if defined(CEF_STRING_TYPE_UTF16)
|
|
void v8impl_string_dtor(char16* str) {
|
|
delete[] str;
|
|
}
|
|
#elif defined(CEF_STRING_TYPE_UTF8)
|
|
void v8impl_string_dtor(char* str) {
|
|
delete[] str;
|
|
}
|
|
#endif
|
|
|
|
// Convert a v8::String to CefString.
|
|
void GetCefString(v8::Isolate* isolate,
|
|
v8::Local<v8::String> str,
|
|
CefString& out) {
|
|
if (str.IsEmpty())
|
|
return;
|
|
|
|
#if defined(CEF_STRING_TYPE_WIDE)
|
|
// Allocate enough space for a worst-case conversion.
|
|
int len = str->Utf8Length();
|
|
if (len == 0)
|
|
return;
|
|
char* buf = new char[len + 1];
|
|
str->WriteUtf8(isolate, buf, len + 1);
|
|
|
|
// Perform conversion to the wide type.
|
|
cef_string_t* retws = out.GetWritableStruct();
|
|
cef_string_utf8_to_wide(buf, len, retws);
|
|
|
|
delete[] buf;
|
|
#else // !defined(CEF_STRING_TYPE_WIDE)
|
|
#if defined(CEF_STRING_TYPE_UTF16)
|
|
int len = str->Length();
|
|
if (len == 0)
|
|
return;
|
|
char16* buf = new char16[len + 1];
|
|
str->Write(isolate, reinterpret_cast<uint16_t*>(buf), 0, len + 1);
|
|
#else
|
|
// Allocate enough space for a worst-case conversion.
|
|
int len = str->Utf8Length();
|
|
if (len == 0)
|
|
return;
|
|
char* buf = new char[len + 1];
|
|
str->WriteUtf8(isolate, buf, len + 1);
|
|
#endif
|
|
|
|
// Don't perform an extra string copy.
|
|
out.clear();
|
|
cef_string_t* retws = out.GetWritableStruct();
|
|
retws->str = buf;
|
|
retws->length = len;
|
|
retws->dtor = v8impl_string_dtor;
|
|
#endif // !defined(CEF_STRING_TYPE_WIDE)
|
|
}
|
|
|
|
// V8 function callback.
|
|
void FunctionCallbackImpl(const v8::FunctionCallbackInfo<v8::Value>& info) {
|
|
v8::Isolate* isolate = info.GetIsolate();
|
|
v8::Local<v8::Context> context = isolate->GetCurrentContext();
|
|
|
|
V8FunctionData* data = V8FunctionData::Unwrap(info.Data());
|
|
if (!data->handler()) {
|
|
// handler has gone away, bail!
|
|
info.GetReturnValue().SetUndefined();
|
|
return;
|
|
}
|
|
CefV8ValueList params;
|
|
for (int i = 0; i < info.Length(); i++)
|
|
params.push_back(new CefV8ValueImpl(isolate, context, info[i]));
|
|
|
|
CefRefPtr<CefV8Value> object =
|
|
new CefV8ValueImpl(isolate, context, info.This());
|
|
CefRefPtr<CefV8Value> retval;
|
|
CefString exception;
|
|
|
|
if (data->handler()->Execute(data->function_name(), object, params, retval,
|
|
exception)) {
|
|
if (!exception.empty()) {
|
|
info.GetReturnValue().Set(isolate->ThrowException(
|
|
v8::Exception::Error(GetV8String(isolate, exception))));
|
|
return;
|
|
} else {
|
|
CefV8ValueImpl* rv = static_cast<CefV8ValueImpl*>(retval.get());
|
|
if (rv && rv->IsValid()) {
|
|
info.GetReturnValue().Set(rv->GetV8Value(true));
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
info.GetReturnValue().SetUndefined();
|
|
}
|
|
|
|
// V8 Accessor callbacks
|
|
void AccessorNameGetterCallbackImpl(
|
|
v8::Local<v8::Name> property,
|
|
const v8::PropertyCallbackInfo<v8::Value>& info) {
|
|
v8::Isolate* isolate = info.GetIsolate();
|
|
v8::Local<v8::Context> context = isolate->GetCurrentContext();
|
|
|
|
v8::Local<v8::Object> obj = info.This();
|
|
|
|
CefRefPtr<CefV8Accessor> accessorPtr;
|
|
|
|
V8TrackObject* tracker = V8TrackObject::Unwrap(context, obj);
|
|
if (tracker)
|
|
accessorPtr = tracker->GetAccessor();
|
|
|
|
if (accessorPtr.get()) {
|
|
CefRefPtr<CefV8Value> retval;
|
|
CefRefPtr<CefV8Value> object = new CefV8ValueImpl(isolate, context, obj);
|
|
CefString name, exception;
|
|
GetCefString(isolate, v8::Local<v8::String>::Cast(property), name);
|
|
if (accessorPtr->Get(name, object, retval, exception)) {
|
|
if (!exception.empty()) {
|
|
info.GetReturnValue().Set(isolate->ThrowException(
|
|
v8::Exception::Error(GetV8String(isolate, exception))));
|
|
return;
|
|
} else {
|
|
CefV8ValueImpl* rv = static_cast<CefV8ValueImpl*>(retval.get());
|
|
if (rv && rv->IsValid()) {
|
|
info.GetReturnValue().Set(rv->GetV8Value(true));
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return info.GetReturnValue().SetUndefined();
|
|
}
|
|
|
|
void AccessorNameSetterCallbackImpl(
|
|
v8::Local<v8::Name> property,
|
|
v8::Local<v8::Value> value,
|
|
const v8::PropertyCallbackInfo<void>& info) {
|
|
v8::Isolate* isolate = info.GetIsolate();
|
|
v8::Local<v8::Context> context = isolate->GetCurrentContext();
|
|
|
|
v8::Local<v8::Object> obj = info.This();
|
|
|
|
CefRefPtr<CefV8Accessor> accessorPtr;
|
|
|
|
V8TrackObject* tracker = V8TrackObject::Unwrap(context, obj);
|
|
if (tracker)
|
|
accessorPtr = tracker->GetAccessor();
|
|
|
|
if (accessorPtr.get()) {
|
|
CefRefPtr<CefV8Value> object = new CefV8ValueImpl(isolate, context, obj);
|
|
CefRefPtr<CefV8Value> cefValue =
|
|
new CefV8ValueImpl(isolate, context, value);
|
|
CefString name, exception;
|
|
GetCefString(isolate, v8::Local<v8::String>::Cast(property), name);
|
|
accessorPtr->Set(name, object, cefValue, exception);
|
|
if (!exception.empty()) {
|
|
isolate->ThrowException(
|
|
v8::Exception::Error(GetV8String(isolate, exception)));
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Two helper functions for V8 Interceptor callbacks.
|
|
CefString PropertyToIndex(v8::Isolate* isolate, v8::Local<v8::Name> property) {
|
|
CefString name;
|
|
GetCefString(isolate, property.As<v8::String>(), name);
|
|
return name;
|
|
}
|
|
|
|
int PropertyToIndex(v8::Isolate* isolate, uint32_t index) {
|
|
return static_cast<int>(index);
|
|
}
|
|
|
|
// V8 Interceptor callbacks.
|
|
// T == v8::Local<v8::Name> for named property handlers and
|
|
// T == uint32_t for indexed property handlers
|
|
template <typename T>
|
|
void InterceptorGetterCallbackImpl(
|
|
T property,
|
|
const v8::PropertyCallbackInfo<v8::Value>& info) {
|
|
v8::Isolate* isolate = info.GetIsolate();
|
|
v8::Local<v8::Context> context = isolate->GetCurrentContext();
|
|
|
|
v8::Handle<v8::Object> obj = info.This();
|
|
CefRefPtr<CefV8Interceptor> interceptorPtr;
|
|
|
|
V8TrackObject* tracker = V8TrackObject::Unwrap(context, obj);
|
|
if (tracker)
|
|
interceptorPtr = tracker->GetInterceptor();
|
|
if (!interceptorPtr.get())
|
|
return;
|
|
|
|
CefRefPtr<CefV8Value> object = new CefV8ValueImpl(isolate, context, obj);
|
|
CefRefPtr<CefV8Value> retval;
|
|
CefString exception;
|
|
interceptorPtr->Get(PropertyToIndex(isolate, property), object, retval,
|
|
exception);
|
|
if (!exception.empty()) {
|
|
info.GetReturnValue().Set(isolate->ThrowException(
|
|
v8::Exception::Error(GetV8String(isolate, exception))));
|
|
} else {
|
|
CefV8ValueImpl* retval_impl = static_cast<CefV8ValueImpl*>(retval.get());
|
|
if (retval_impl && retval_impl->IsValid()) {
|
|
info.GetReturnValue().Set(retval_impl->GetV8Value(true));
|
|
}
|
|
}
|
|
}
|
|
|
|
template <typename T>
|
|
void InterceptorSetterCallbackImpl(
|
|
T property,
|
|
v8::Local<v8::Value> value,
|
|
const v8::PropertyCallbackInfo<v8::Value>& info) {
|
|
v8::Isolate* isolate = info.GetIsolate();
|
|
v8::Local<v8::Context> context = isolate->GetCurrentContext();
|
|
v8::Handle<v8::Object> obj = info.This();
|
|
CefRefPtr<CefV8Interceptor> interceptorPtr;
|
|
|
|
V8TrackObject* tracker = V8TrackObject::Unwrap(context, obj);
|
|
if (tracker)
|
|
interceptorPtr = tracker->GetInterceptor();
|
|
|
|
if (!interceptorPtr.get())
|
|
return;
|
|
CefRefPtr<CefV8Value> object = new CefV8ValueImpl(isolate, context, obj);
|
|
CefRefPtr<CefV8Value> cefValue = new CefV8ValueImpl(isolate, context, value);
|
|
CefString exception;
|
|
interceptorPtr->Set(PropertyToIndex(isolate, property), object, cefValue,
|
|
exception);
|
|
if (!exception.empty()) {
|
|
isolate->ThrowException(
|
|
v8::Exception::Error(GetV8String(isolate, exception)));
|
|
}
|
|
}
|
|
|
|
// V8 extension registration.
|
|
|
|
class ExtensionWrapper : public v8::Extension {
|
|
public:
|
|
ExtensionWrapper(const char* extension_name,
|
|
const char* javascript_code,
|
|
CefV8Handler* handler)
|
|
: v8::Extension(extension_name, javascript_code), handler_(handler) {}
|
|
|
|
v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate(
|
|
v8::Isolate* isolate,
|
|
v8::Handle<v8::String> name) override {
|
|
if (!handler_)
|
|
return v8::Local<v8::FunctionTemplate>();
|
|
|
|
CefString func_name;
|
|
GetCefString(isolate, name, func_name);
|
|
|
|
v8::Local<v8::External> function_data =
|
|
V8FunctionData::Create(isolate, func_name, handler_);
|
|
|
|
return v8::FunctionTemplate::New(isolate, FunctionCallbackImpl,
|
|
function_data);
|
|
}
|
|
|
|
private:
|
|
CefV8Handler* handler_;
|
|
};
|
|
|
|
class CefV8ExceptionImpl : public CefV8Exception {
|
|
public:
|
|
CefV8ExceptionImpl(v8::Local<v8::Context> context,
|
|
v8::Local<v8::Message> message)
|
|
: line_number_(0),
|
|
start_position_(0),
|
|
end_position_(0),
|
|
start_column_(0),
|
|
end_column_(0) {
|
|
if (message.IsEmpty())
|
|
return;
|
|
|
|
v8::Isolate* isolate = context->GetIsolate();
|
|
GetCefString(isolate, message->Get(), message_);
|
|
v8::MaybeLocal<v8::String> source_line = message->GetSourceLine(context);
|
|
if (!source_line.IsEmpty())
|
|
GetCefString(isolate, source_line.ToLocalChecked(), source_line_);
|
|
|
|
if (!message->GetScriptResourceName().IsEmpty()) {
|
|
GetCefString(
|
|
isolate,
|
|
message->GetScriptResourceName()->ToString(context).ToLocalChecked(),
|
|
script_);
|
|
}
|
|
|
|
v8::Maybe<int> line_number = message->GetLineNumber(context);
|
|
if (!line_number.IsNothing())
|
|
line_number_ = line_number.ToChecked();
|
|
start_position_ = message->GetStartPosition();
|
|
end_position_ = message->GetEndPosition();
|
|
start_column_ = message->GetStartColumn(context).FromJust();
|
|
end_column_ = message->GetEndColumn(context).FromJust();
|
|
}
|
|
|
|
CefString GetMessage() override { return message_; }
|
|
CefString GetSourceLine() override { return source_line_; }
|
|
CefString GetScriptResourceName() override { return script_; }
|
|
int GetLineNumber() override { return line_number_; }
|
|
int GetStartPosition() override { return start_position_; }
|
|
int GetEndPosition() override { return end_position_; }
|
|
int GetStartColumn() override { return start_column_; }
|
|
int GetEndColumn() override { return end_column_; }
|
|
|
|
protected:
|
|
CefString message_;
|
|
CefString source_line_;
|
|
CefString script_;
|
|
int line_number_;
|
|
int start_position_;
|
|
int end_position_;
|
|
int start_column_;
|
|
int end_column_;
|
|
|
|
IMPLEMENT_REFCOUNTING(CefV8ExceptionImpl);
|
|
};
|
|
|
|
void MessageListenerCallbackImpl(v8::Handle<v8::Message> message,
|
|
v8::Handle<v8::Value> data) {
|
|
CefRefPtr<CefApp> application = CefAppManager::Get()->GetApplication();
|
|
if (!application.get())
|
|
return;
|
|
|
|
CefRefPtr<CefRenderProcessHandler> handler =
|
|
application->GetRenderProcessHandler();
|
|
if (!handler.get())
|
|
return;
|
|
|
|
v8::Isolate* isolate = GetIsolateManager()->isolate();
|
|
CefRefPtr<CefV8Context> context = CefV8Context::GetCurrentContext();
|
|
v8::Local<v8::StackTrace> v8Stack = message->GetStackTrace();
|
|
CefRefPtr<CefV8StackTrace> stackTrace =
|
|
new CefV8StackTraceImpl(isolate, v8Stack);
|
|
|
|
CefRefPtr<CefV8Exception> exception = new CefV8ExceptionImpl(
|
|
static_cast<CefV8ContextImpl*>(context.get())->GetV8Context(), message);
|
|
|
|
CefRefPtr<CefBrowser> browser = context->GetBrowser();
|
|
if (browser) {
|
|
handler->OnUncaughtException(browser, context->GetFrame(), context,
|
|
exception, stackTrace);
|
|
}
|
|
}
|
|
|
|
} // namespace
|
|
|
|
// Global functions.
|
|
|
|
void CefV8IsolateCreated() {
|
|
g_v8_state.Pointer()->CreateIsolateManager();
|
|
}
|
|
|
|
void CefV8IsolateDestroyed() {
|
|
g_v8_state.Pointer()->DestroyIsolateManager();
|
|
}
|
|
|
|
void CefV8ReleaseContext(v8::Local<v8::Context> context) {
|
|
GetIsolateManager()->ReleaseContext(context);
|
|
}
|
|
|
|
void CefV8SetUncaughtExceptionStackSize(int stack_size) {
|
|
GetIsolateManager()->SetUncaughtExceptionStackSize(stack_size);
|
|
}
|
|
|
|
void CefV8SetWorkerAttributes(int worker_id, const GURL& worker_url) {
|
|
GetIsolateManager()->SetWorkerAttributes(worker_id, worker_url);
|
|
}
|
|
|
|
bool CefRegisterExtension(const CefString& extension_name,
|
|
const CefString& javascript_code,
|
|
CefRefPtr<CefV8Handler> handler) {
|
|
// Verify that this method was called on the correct thread.
|
|
CEF_REQUIRE_RT_RETURN(false);
|
|
|
|
CefV8IsolateManager* isolate_manager = GetIsolateManager();
|
|
|
|
V8TrackString* name = new V8TrackString(extension_name);
|
|
isolate_manager->AddGlobalTrackObject(name);
|
|
V8TrackString* code = new V8TrackString(javascript_code);
|
|
isolate_manager->AddGlobalTrackObject(code);
|
|
|
|
if (handler.get()) {
|
|
// The reference will be released when the process exits.
|
|
V8TrackObject* object = new V8TrackObject(isolate_manager->isolate());
|
|
object->SetHandler(handler);
|
|
isolate_manager->AddGlobalTrackObject(object);
|
|
}
|
|
|
|
std::unique_ptr<v8::Extension> wrapper(new ExtensionWrapper(
|
|
name->GetString(), code->GetString(), handler.get()));
|
|
|
|
content::RenderThread::Get()->RegisterExtension(std::move(wrapper));
|
|
return true;
|
|
}
|
|
|
|
// Helper macros
|
|
|
|
#define CEF_V8_HAS_ISOLATE() (!!GetIsolateManager())
|
|
#define CEF_V8_REQUIRE_ISOLATE_RETURN(var) \
|
|
if (!CEF_V8_HAS_ISOLATE()) { \
|
|
NOTREACHED() << "V8 isolate is not valid"; \
|
|
return var; \
|
|
}
|
|
|
|
#define CEF_V8_CURRENTLY_ON_MLT() \
|
|
(!handle_.get() || handle_->BelongsToCurrentThread())
|
|
#define CEF_V8_REQUIRE_MLT_RETURN(var) \
|
|
CEF_V8_REQUIRE_ISOLATE_RETURN(var); \
|
|
if (!CEF_V8_CURRENTLY_ON_MLT()) { \
|
|
NOTREACHED() << "called on incorrect thread"; \
|
|
return var; \
|
|
}
|
|
|
|
#define CEF_V8_HANDLE_IS_VALID() (handle_.get() && handle_->IsValid())
|
|
#define CEF_V8_REQUIRE_VALID_HANDLE_RETURN(ret) \
|
|
CEF_V8_REQUIRE_MLT_RETURN(ret); \
|
|
if (!CEF_V8_HANDLE_IS_VALID()) { \
|
|
NOTREACHED() << "V8 handle is not valid"; \
|
|
return ret; \
|
|
}
|
|
|
|
#define CEF_V8_IS_VALID() \
|
|
(CEF_V8_HAS_ISOLATE() && CEF_V8_CURRENTLY_ON_MLT() && \
|
|
CEF_V8_HANDLE_IS_VALID())
|
|
|
|
#define CEF_V8_REQUIRE_OBJECT_RETURN(ret) \
|
|
CEF_V8_REQUIRE_VALID_HANDLE_RETURN(ret); \
|
|
if (type_ != TYPE_OBJECT) { \
|
|
NOTREACHED() << "V8 value is not an object"; \
|
|
return ret; \
|
|
}
|
|
|
|
// CefV8HandleBase
|
|
|
|
CefV8HandleBase::~CefV8HandleBase() {
|
|
DCHECK(BelongsToCurrentThread());
|
|
}
|
|
|
|
bool CefV8HandleBase::BelongsToCurrentThread() const {
|
|
return task_runner_->RunsTasksInCurrentSequence();
|
|
}
|
|
|
|
CefV8HandleBase::CefV8HandleBase(v8::Isolate* isolate,
|
|
v8::Local<v8::Context> context)
|
|
: isolate_(isolate) {
|
|
DCHECK(isolate_);
|
|
|
|
CefV8IsolateManager* manager = GetIsolateManager();
|
|
DCHECK(manager);
|
|
DCHECK_EQ(isolate_, manager->isolate());
|
|
|
|
task_runner_ = manager->task_runner();
|
|
context_state_ = manager->GetContextState(context);
|
|
}
|
|
|
|
// CefV8Context
|
|
|
|
// static
|
|
CefRefPtr<CefV8Context> CefV8Context::GetCurrentContext() {
|
|
CefRefPtr<CefV8Context> context;
|
|
CEF_V8_REQUIRE_ISOLATE_RETURN(context);
|
|
v8::Isolate* isolate = GetIsolateManager()->isolate();
|
|
if (isolate->InContext()) {
|
|
v8::HandleScope handle_scope(isolate);
|
|
context = new CefV8ContextImpl(isolate, isolate->GetCurrentContext());
|
|
}
|
|
return context;
|
|
}
|
|
|
|
// static
|
|
CefRefPtr<CefV8Context> CefV8Context::GetEnteredContext() {
|
|
CefRefPtr<CefV8Context> context;
|
|
CEF_V8_REQUIRE_ISOLATE_RETURN(context);
|
|
v8::Isolate* isolate = GetIsolateManager()->isolate();
|
|
if (isolate->InContext()) {
|
|
v8::HandleScope handle_scope(isolate);
|
|
context =
|
|
new CefV8ContextImpl(isolate, isolate->GetEnteredOrMicrotaskContext());
|
|
}
|
|
return context;
|
|
}
|
|
|
|
// static
|
|
bool CefV8Context::InContext() {
|
|
CEF_V8_REQUIRE_ISOLATE_RETURN(false);
|
|
v8::Isolate* isolate = GetIsolateManager()->isolate();
|
|
return isolate->InContext();
|
|
}
|
|
|
|
// CefV8ContextImpl
|
|
|
|
CefV8ContextImpl::CefV8ContextImpl(v8::Isolate* isolate,
|
|
v8::Local<v8::Context> context)
|
|
: handle_(new Handle(isolate, context, context)), enter_count_(0) {}
|
|
|
|
CefV8ContextImpl::~CefV8ContextImpl() {
|
|
DLOG_ASSERT(0 == enter_count_);
|
|
}
|
|
|
|
CefRefPtr<CefTaskRunner> CefV8ContextImpl::GetTaskRunner() {
|
|
return new CefTaskRunnerImpl(handle_->task_runner());
|
|
}
|
|
|
|
bool CefV8ContextImpl::IsValid() {
|
|
return CEF_V8_IS_VALID();
|
|
}
|
|
|
|
CefRefPtr<CefBrowser> CefV8ContextImpl::GetBrowser() {
|
|
CefRefPtr<CefBrowser> browser;
|
|
CEF_V8_REQUIRE_VALID_HANDLE_RETURN(browser);
|
|
|
|
blink::WebLocalFrame* webframe = GetWebFrame();
|
|
if (webframe)
|
|
browser = CefBrowserImpl::GetBrowserForMainFrame(webframe->Top());
|
|
|
|
return browser;
|
|
}
|
|
|
|
CefRefPtr<CefFrame> CefV8ContextImpl::GetFrame() {
|
|
CefRefPtr<CefFrame> frame;
|
|
CEF_V8_REQUIRE_VALID_HANDLE_RETURN(frame);
|
|
|
|
blink::WebLocalFrame* webframe = GetWebFrame();
|
|
if (webframe) {
|
|
CefRefPtr<CefBrowserImpl> browser =
|
|
CefBrowserImpl::GetBrowserForMainFrame(webframe->Top());
|
|
if (browser) {
|
|
frame = browser->GetFrame(render_frame_util::GetIdentifier(webframe));
|
|
}
|
|
}
|
|
|
|
return frame;
|
|
}
|
|
|
|
CefRefPtr<CefV8Value> CefV8ContextImpl::GetGlobal() {
|
|
CEF_V8_REQUIRE_VALID_HANDLE_RETURN(nullptr);
|
|
|
|
if (blink_glue::IsScriptForbidden())
|
|
return nullptr;
|
|
|
|
v8::Isolate* isolate = handle_->isolate();
|
|
v8::HandleScope handle_scope(isolate);
|
|
v8::Local<v8::Context> context = GetV8Context();
|
|
v8::Context::Scope context_scope(context);
|
|
return new CefV8ValueImpl(isolate, context, context->Global());
|
|
}
|
|
|
|
bool CefV8ContextImpl::Enter() {
|
|
CEF_V8_REQUIRE_VALID_HANDLE_RETURN(false);
|
|
|
|
if (blink_glue::IsScriptForbidden())
|
|
return false;
|
|
|
|
v8::Isolate* isolate = handle_->isolate();
|
|
v8::HandleScope handle_scope(isolate);
|
|
|
|
if (!microtasks_scope_) {
|
|
// Increment the MicrotasksScope recursion level.
|
|
microtasks_scope_.reset(
|
|
new v8::MicrotasksScope(isolate, v8::MicrotasksScope::kRunMicrotasks));
|
|
}
|
|
|
|
++enter_count_;
|
|
handle_->GetNewV8Handle()->Enter();
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CefV8ContextImpl::Exit() {
|
|
CEF_V8_REQUIRE_VALID_HANDLE_RETURN(false);
|
|
|
|
if (blink_glue::IsScriptForbidden())
|
|
return false;
|
|
|
|
if (enter_count_ <= 0) {
|
|
LOG(ERROR) << "Call to CefV8Context::Exit() without matching call to "
|
|
"CefV8Context::Enter()";
|
|
return false;
|
|
}
|
|
|
|
v8::HandleScope handle_scope(handle_->isolate());
|
|
|
|
handle_->GetNewV8Handle()->Exit();
|
|
|
|
if (--enter_count_ == 0) {
|
|
// Decrement the MicrotasksScope recursion level.
|
|
microtasks_scope_.reset(nullptr);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CefV8ContextImpl::IsSame(CefRefPtr<CefV8Context> that) {
|
|
CEF_V8_REQUIRE_VALID_HANDLE_RETURN(false);
|
|
|
|
CefV8ContextImpl* impl = static_cast<CefV8ContextImpl*>(that.get());
|
|
if (!impl || !impl->IsValid())
|
|
return false;
|
|
|
|
return (handle_->GetPersistentV8Handle() ==
|
|
impl->handle_->GetPersistentV8Handle());
|
|
}
|
|
|
|
bool CefV8ContextImpl::Eval(const CefString& code,
|
|
const CefString& script_url,
|
|
int start_line,
|
|
CefRefPtr<CefV8Value>& retval,
|
|
CefRefPtr<CefV8Exception>& exception) {
|
|
retval = nullptr;
|
|
exception = nullptr;
|
|
|
|
CEF_V8_REQUIRE_VALID_HANDLE_RETURN(false);
|
|
|
|
if (blink_glue::IsScriptForbidden())
|
|
return false;
|
|
|
|
if (code.empty()) {
|
|
NOTREACHED() << "invalid input parameter";
|
|
return false;
|
|
}
|
|
|
|
v8::Isolate* isolate = handle_->isolate();
|
|
v8::HandleScope handle_scope(isolate);
|
|
v8::Local<v8::Context> context = GetV8Context();
|
|
v8::Context::Scope context_scope(context);
|
|
|
|
const blink::WebString& source =
|
|
blink::WebString::FromUTF16(code.ToString16());
|
|
const blink::WebString& source_url =
|
|
blink::WebString::FromUTF16(script_url.ToString16());
|
|
|
|
v8::TryCatch try_catch(isolate);
|
|
try_catch.SetVerbose(true);
|
|
|
|
v8::MaybeLocal<v8::Value> func_rv = blink_glue::ExecuteV8ScriptAndReturnValue(
|
|
source, source_url, start_line, context, isolate, try_catch,
|
|
blink::SanitizeScriptErrors::kSanitize);
|
|
|
|
if (try_catch.HasCaught()) {
|
|
exception = new CefV8ExceptionImpl(context, try_catch.Message());
|
|
return false;
|
|
} else if (!func_rv.IsEmpty()) {
|
|
retval = new CefV8ValueImpl(isolate, context, func_rv.ToLocalChecked());
|
|
return true;
|
|
}
|
|
|
|
NOTREACHED();
|
|
return false;
|
|
}
|
|
|
|
v8::Local<v8::Context> CefV8ContextImpl::GetV8Context() {
|
|
return handle_->GetNewV8Handle();
|
|
}
|
|
|
|
blink::WebLocalFrame* CefV8ContextImpl::GetWebFrame() {
|
|
CEF_REQUIRE_RT();
|
|
|
|
if (blink_glue::IsScriptForbidden())
|
|
return nullptr;
|
|
|
|
v8::HandleScope handle_scope(handle_->isolate());
|
|
v8::Local<v8::Context> context = GetV8Context();
|
|
v8::Context::Scope context_scope(context);
|
|
return blink::WebLocalFrame::FrameForContext(context);
|
|
}
|
|
|
|
// CefV8ValueImpl::Handle
|
|
|
|
CefV8ValueImpl::Handle::Handle(v8::Isolate* isolate,
|
|
v8::Local<v8::Context> context,
|
|
handleType v,
|
|
CefTrackNode* tracker)
|
|
: CefV8HandleBase(isolate, context),
|
|
handle_(isolate, v),
|
|
tracker_(tracker),
|
|
should_persist_(false),
|
|
is_set_weak_(false) {}
|
|
|
|
CefV8ValueImpl::Handle::~Handle() {
|
|
DCHECK(BelongsToCurrentThread());
|
|
|
|
if (tracker_) {
|
|
if (is_set_weak_) {
|
|
if (context_state_.get()) {
|
|
// If the associated context is still valid then delete |tracker_|.
|
|
// Otherwise, |tracker_| will already have been deleted.
|
|
if (context_state_->IsValid())
|
|
context_state_->DeleteTrackObject(tracker_);
|
|
} else {
|
|
GetIsolateManager()->DeleteGlobalTrackObject(tracker_);
|
|
}
|
|
} else {
|
|
delete tracker_;
|
|
}
|
|
}
|
|
|
|
if (is_set_weak_) {
|
|
isolate_->AdjustAmountOfExternalAllocatedMemory(
|
|
-static_cast<int>(sizeof(Handle)));
|
|
} else {
|
|
// SetWeak was not called so reset now.
|
|
handle_.Reset();
|
|
}
|
|
}
|
|
|
|
CefV8ValueImpl::Handle::handleType CefV8ValueImpl::Handle::GetNewV8Handle(
|
|
bool should_persist) {
|
|
DCHECK(IsValid());
|
|
if (should_persist && !should_persist_)
|
|
should_persist_ = true;
|
|
return handleType::New(isolate(), handle_);
|
|
}
|
|
|
|
CefV8ValueImpl::Handle::persistentType&
|
|
CefV8ValueImpl::Handle::GetPersistentV8Handle() {
|
|
return handle_;
|
|
}
|
|
|
|
void CefV8ValueImpl::Handle::SetWeakIfNecessary() {
|
|
if (!BelongsToCurrentThread()) {
|
|
task_runner()->PostTask(
|
|
FROM_HERE,
|
|
base::Bind(&CefV8ValueImpl::Handle::SetWeakIfNecessary, this));
|
|
return;
|
|
}
|
|
|
|
// Persist the handle (call SetWeak) if:
|
|
// A. The handle has been passed into a V8 function or used as a return value
|
|
// from a V8 callback, and
|
|
// B. The associated context, if any, is still valid.
|
|
if (should_persist_ && (!context_state_.get() || context_state_->IsValid())) {
|
|
is_set_weak_ = true;
|
|
|
|
if (tracker_) {
|
|
if (context_state_.get()) {
|
|
// |tracker_| will be deleted when:
|
|
// A. The associated context is released, or
|
|
// B. SecondWeakCallback is called for the weak handle.
|
|
DCHECK(context_state_->IsValid());
|
|
context_state_->AddTrackObject(tracker_);
|
|
} else {
|
|
// |tracker_| will be deleted when:
|
|
// A. The process shuts down, or
|
|
// B. SecondWeakCallback is called for the weak handle.
|
|
GetIsolateManager()->AddGlobalTrackObject(tracker_);
|
|
}
|
|
}
|
|
|
|
isolate_->AdjustAmountOfExternalAllocatedMemory(
|
|
static_cast<int>(sizeof(Handle)));
|
|
|
|
// The added reference will be released in SecondWeakCallback.
|
|
AddRef();
|
|
handle_.SetWeak(this, FirstWeakCallback, v8::WeakCallbackType::kParameter);
|
|
}
|
|
}
|
|
|
|
// static
|
|
void CefV8ValueImpl::Handle::FirstWeakCallback(
|
|
const v8::WeakCallbackInfo<Handle>& data) {
|
|
Handle* wrapper = data.GetParameter();
|
|
wrapper->handle_.Reset();
|
|
data.SetSecondPassCallback(SecondWeakCallback);
|
|
}
|
|
|
|
// static
|
|
void CefV8ValueImpl::Handle::SecondWeakCallback(
|
|
const v8::WeakCallbackInfo<Handle>& data) {
|
|
Handle* wrapper = data.GetParameter();
|
|
wrapper->Release();
|
|
}
|
|
|
|
// CefV8Value
|
|
|
|
// static
|
|
CefRefPtr<CefV8Value> CefV8Value::CreateUndefined() {
|
|
CEF_V8_REQUIRE_ISOLATE_RETURN(nullptr);
|
|
v8::Isolate* isolate = GetIsolateManager()->isolate();
|
|
CefRefPtr<CefV8ValueImpl> impl = new CefV8ValueImpl(isolate);
|
|
impl->InitUndefined();
|
|
return impl.get();
|
|
}
|
|
|
|
// static
|
|
CefRefPtr<CefV8Value> CefV8Value::CreateNull() {
|
|
CEF_V8_REQUIRE_ISOLATE_RETURN(nullptr);
|
|
v8::Isolate* isolate = GetIsolateManager()->isolate();
|
|
CefRefPtr<CefV8ValueImpl> impl = new CefV8ValueImpl(isolate);
|
|
impl->InitNull();
|
|
return impl.get();
|
|
}
|
|
|
|
// static
|
|
CefRefPtr<CefV8Value> CefV8Value::CreateBool(bool value) {
|
|
CEF_V8_REQUIRE_ISOLATE_RETURN(nullptr);
|
|
v8::Isolate* isolate = GetIsolateManager()->isolate();
|
|
CefRefPtr<CefV8ValueImpl> impl = new CefV8ValueImpl(isolate);
|
|
impl->InitBool(value);
|
|
return impl.get();
|
|
}
|
|
|
|
// static
|
|
CefRefPtr<CefV8Value> CefV8Value::CreateInt(int32 value) {
|
|
CEF_V8_REQUIRE_ISOLATE_RETURN(nullptr);
|
|
v8::Isolate* isolate = GetIsolateManager()->isolate();
|
|
CefRefPtr<CefV8ValueImpl> impl = new CefV8ValueImpl(isolate);
|
|
impl->InitInt(value);
|
|
return impl.get();
|
|
}
|
|
|
|
// static
|
|
CefRefPtr<CefV8Value> CefV8Value::CreateUInt(uint32 value) {
|
|
CEF_V8_REQUIRE_ISOLATE_RETURN(nullptr);
|
|
v8::Isolate* isolate = GetIsolateManager()->isolate();
|
|
CefRefPtr<CefV8ValueImpl> impl = new CefV8ValueImpl(isolate);
|
|
impl->InitUInt(value);
|
|
return impl.get();
|
|
}
|
|
|
|
// static
|
|
CefRefPtr<CefV8Value> CefV8Value::CreateDouble(double value) {
|
|
CEF_V8_REQUIRE_ISOLATE_RETURN(nullptr);
|
|
v8::Isolate* isolate = GetIsolateManager()->isolate();
|
|
CefRefPtr<CefV8ValueImpl> impl = new CefV8ValueImpl(isolate);
|
|
impl->InitDouble(value);
|
|
return impl.get();
|
|
}
|
|
|
|
// static
|
|
CefRefPtr<CefV8Value> CefV8Value::CreateDate(const CefTime& value) {
|
|
CEF_V8_REQUIRE_ISOLATE_RETURN(nullptr);
|
|
v8::Isolate* isolate = GetIsolateManager()->isolate();
|
|
CefRefPtr<CefV8ValueImpl> impl = new CefV8ValueImpl(isolate);
|
|
impl->InitDate(value);
|
|
return impl.get();
|
|
}
|
|
|
|
// static
|
|
CefRefPtr<CefV8Value> CefV8Value::CreateString(const CefString& value) {
|
|
CEF_V8_REQUIRE_ISOLATE_RETURN(nullptr);
|
|
v8::Isolate* isolate = GetIsolateManager()->isolate();
|
|
CefRefPtr<CefV8ValueImpl> impl = new CefV8ValueImpl(isolate);
|
|
CefString str(value);
|
|
impl->InitString(str);
|
|
return impl.get();
|
|
}
|
|
|
|
// static
|
|
CefRefPtr<CefV8Value> CefV8Value::CreateObject(
|
|
CefRefPtr<CefV8Accessor> accessor,
|
|
CefRefPtr<CefV8Interceptor> interceptor) {
|
|
CEF_V8_REQUIRE_ISOLATE_RETURN(nullptr);
|
|
|
|
v8::Isolate* isolate = GetIsolateManager()->isolate();
|
|
v8::HandleScope handle_scope(isolate);
|
|
|
|
v8::Local<v8::Context> context = isolate->GetCurrentContext();
|
|
if (context.IsEmpty()) {
|
|
NOTREACHED() << "not currently in a V8 context";
|
|
return nullptr;
|
|
}
|
|
|
|
// Create the new V8 object. If an interceptor is passed, create object from
|
|
// template and set property handlers.
|
|
v8::Local<v8::Object> obj;
|
|
if (interceptor.get()) {
|
|
v8::Local<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New(isolate);
|
|
tmpl->SetHandler(v8::NamedPropertyHandlerConfiguration(
|
|
InterceptorGetterCallbackImpl<v8::Local<v8::Name>>,
|
|
InterceptorSetterCallbackImpl<v8::Local<v8::Name>>, nullptr, nullptr,
|
|
nullptr, v8::Local<v8::Value>(),
|
|
v8::PropertyHandlerFlags::kOnlyInterceptStrings));
|
|
|
|
tmpl->SetIndexedPropertyHandler(InterceptorGetterCallbackImpl<uint32_t>,
|
|
InterceptorSetterCallbackImpl<uint32_t>);
|
|
|
|
v8::MaybeLocal<v8::Object> maybe_object = tmpl->NewInstance(context);
|
|
if (!maybe_object.ToLocal<v8::Object>(&obj)) {
|
|
NOTREACHED() << "Failed to create V8 Object with interceptor";
|
|
return nullptr;
|
|
}
|
|
} else {
|
|
obj = v8::Object::New(isolate);
|
|
}
|
|
|
|
// Create a tracker object that will cause the user data and/or accessor
|
|
// and/or interceptor reference to be released when the V8 object is
|
|
// destroyed.
|
|
V8TrackObject* tracker = new V8TrackObject(isolate);
|
|
tracker->SetAccessor(accessor);
|
|
tracker->SetInterceptor(interceptor);
|
|
|
|
// Attach the tracker object.
|
|
tracker->AttachTo(context, obj);
|
|
|
|
CefRefPtr<CefV8ValueImpl> impl = new CefV8ValueImpl(isolate);
|
|
impl->InitObject(obj, tracker);
|
|
return impl.get();
|
|
}
|
|
|
|
// static
|
|
CefRefPtr<CefV8Value> CefV8Value::CreateArray(int length) {
|
|
CEF_V8_REQUIRE_ISOLATE_RETURN(nullptr);
|
|
|
|
v8::Isolate* isolate = GetIsolateManager()->isolate();
|
|
v8::HandleScope handle_scope(isolate);
|
|
|
|
v8::Local<v8::Context> context = isolate->GetCurrentContext();
|
|
if (context.IsEmpty()) {
|
|
NOTREACHED() << "not currently in a V8 context";
|
|
return nullptr;
|
|
}
|
|
|
|
// Create a tracker object that will cause the user data reference to be
|
|
// released when the V8 object is destroyed.
|
|
V8TrackObject* tracker = new V8TrackObject(isolate);
|
|
|
|
// Create the new V8 array.
|
|
v8::Local<v8::Array> arr = v8::Array::New(isolate, length);
|
|
|
|
// Attach the tracker object.
|
|
tracker->AttachTo(context, arr);
|
|
|
|
CefRefPtr<CefV8ValueImpl> impl = new CefV8ValueImpl(isolate);
|
|
impl->InitObject(arr, tracker);
|
|
return impl.get();
|
|
}
|
|
|
|
// static
|
|
CefRefPtr<CefV8Value> CefV8Value::CreateArrayBuffer(
|
|
void* buffer,
|
|
size_t length,
|
|
CefRefPtr<CefV8ArrayBufferReleaseCallback> release_callback) {
|
|
CEF_V8_REQUIRE_ISOLATE_RETURN(nullptr);
|
|
|
|
v8::Isolate* isolate = GetIsolateManager()->isolate();
|
|
v8::HandleScope handle_scope(isolate);
|
|
v8::Local<v8::Context> context = isolate->GetCurrentContext();
|
|
if (context.IsEmpty()) {
|
|
NOTREACHED() << "not currently in a V8 context";
|
|
return nullptr;
|
|
}
|
|
|
|
// Create a tracker object that will cause the user data reference to be
|
|
// released when the V8 object is destroyed.
|
|
V8TrackArrayBuffer* tracker =
|
|
new V8TrackArrayBuffer(isolate, buffer, release_callback);
|
|
v8::Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, buffer, length);
|
|
|
|
// Attach the tracker object.
|
|
tracker->AttachTo(context, ab);
|
|
|
|
CefRefPtr<CefV8ValueImpl> impl = new CefV8ValueImpl(isolate);
|
|
impl->InitObject(ab, tracker);
|
|
return impl.get();
|
|
}
|
|
|
|
// static
|
|
CefRefPtr<CefV8Value> CefV8Value::CreateFunction(
|
|
const CefString& name,
|
|
CefRefPtr<CefV8Handler> handler) {
|
|
CEF_V8_REQUIRE_ISOLATE_RETURN(nullptr);
|
|
|
|
if (!handler.get()) {
|
|
NOTREACHED() << "invalid parameter";
|
|
return nullptr;
|
|
}
|
|
|
|
v8::Isolate* isolate = GetIsolateManager()->isolate();
|
|
v8::HandleScope handle_scope(isolate);
|
|
|
|
v8::Local<v8::Context> context = isolate->GetCurrentContext();
|
|
if (context.IsEmpty()) {
|
|
NOTREACHED() << "not currently in a V8 context";
|
|
return nullptr;
|
|
}
|
|
|
|
v8::Local<v8::External> function_data =
|
|
V8FunctionData::Create(isolate, name, handler);
|
|
|
|
// Create a new V8 function template.
|
|
v8::Local<v8::FunctionTemplate> tmpl =
|
|
v8::FunctionTemplate::New(isolate, FunctionCallbackImpl, function_data);
|
|
|
|
// Retrieve the function object and set the name.
|
|
v8::MaybeLocal<v8::Function> maybe_func = tmpl->GetFunction(context);
|
|
v8::Local<v8::Function> func;
|
|
if (!maybe_func.ToLocal(&func)) {
|
|
NOTREACHED() << "failed to create V8 function";
|
|
return nullptr;
|
|
}
|
|
|
|
func->SetName(GetV8String(isolate, name));
|
|
|
|
// Create a tracker object that will cause the user data and/or handler
|
|
// reference to be released when the V8 object is destroyed.
|
|
V8TrackObject* tracker = new V8TrackObject(isolate);
|
|
tracker->SetHandler(handler);
|
|
|
|
// Attach the tracker object.
|
|
tracker->AttachTo(context, func);
|
|
|
|
// Create the CefV8ValueImpl and provide a tracker object that will cause
|
|
// the handler reference to be released when the V8 object is destroyed.
|
|
CefRefPtr<CefV8ValueImpl> impl = new CefV8ValueImpl(isolate);
|
|
impl->InitObject(func, tracker);
|
|
return impl.get();
|
|
}
|
|
|
|
// CefV8ValueImpl
|
|
|
|
CefV8ValueImpl::CefV8ValueImpl(v8::Isolate* isolate)
|
|
: isolate_(isolate), type_(TYPE_INVALID), rethrow_exceptions_(false) {
|
|
DCHECK(isolate_);
|
|
}
|
|
|
|
CefV8ValueImpl::CefV8ValueImpl(v8::Isolate* isolate,
|
|
v8::Local<v8::Context> context,
|
|
v8::Local<v8::Value> value)
|
|
: isolate_(isolate), type_(TYPE_INVALID), rethrow_exceptions_(false) {
|
|
DCHECK(isolate_);
|
|
InitFromV8Value(context, value);
|
|
}
|
|
|
|
CefV8ValueImpl::~CefV8ValueImpl() {
|
|
if (type_ == TYPE_STRING)
|
|
cef_string_clear(&string_value_);
|
|
if (handle_.get())
|
|
handle_->SetWeakIfNecessary();
|
|
}
|
|
|
|
void CefV8ValueImpl::InitFromV8Value(v8::Local<v8::Context> context,
|
|
v8::Local<v8::Value> value) {
|
|
if (value->IsUndefined()) {
|
|
InitUndefined();
|
|
} else if (value->IsNull()) {
|
|
InitNull();
|
|
} else if (value->IsTrue()) {
|
|
InitBool(true);
|
|
} else if (value->IsFalse()) {
|
|
InitBool(false);
|
|
} else if (value->IsBoolean()) {
|
|
InitBool(value->ToBoolean(context->GetIsolate())->Value());
|
|
} else if (value->IsInt32()) {
|
|
InitInt(value->ToInt32(context).ToLocalChecked()->Value());
|
|
} else if (value->IsUint32()) {
|
|
InitUInt(value->ToUint32(context).ToLocalChecked()->Value());
|
|
} else if (value->IsNumber()) {
|
|
InitDouble(value->ToNumber(context).ToLocalChecked()->Value());
|
|
} else if (value->IsDate()) {
|
|
// Convert from milliseconds to seconds.
|
|
InitDate(
|
|
CefTime(value->ToNumber(context).ToLocalChecked()->Value() / 1000));
|
|
} else if (value->IsString()) {
|
|
CefString rv;
|
|
GetCefString(context->GetIsolate(),
|
|
value->ToString(context).ToLocalChecked(), rv);
|
|
InitString(rv);
|
|
} else if (value->IsObject()) {
|
|
InitObject(value, nullptr);
|
|
}
|
|
}
|
|
|
|
void CefV8ValueImpl::InitUndefined() {
|
|
DCHECK_EQ(type_, TYPE_INVALID);
|
|
type_ = TYPE_UNDEFINED;
|
|
}
|
|
|
|
void CefV8ValueImpl::InitNull() {
|
|
DCHECK_EQ(type_, TYPE_INVALID);
|
|
type_ = TYPE_NULL;
|
|
}
|
|
|
|
void CefV8ValueImpl::InitBool(bool value) {
|
|
DCHECK_EQ(type_, TYPE_INVALID);
|
|
type_ = TYPE_BOOL;
|
|
bool_value_ = value;
|
|
}
|
|
|
|
void CefV8ValueImpl::InitInt(int32 value) {
|
|
DCHECK_EQ(type_, TYPE_INVALID);
|
|
type_ = TYPE_INT;
|
|
int_value_ = value;
|
|
}
|
|
|
|
void CefV8ValueImpl::InitUInt(uint32 value) {
|
|
DCHECK_EQ(type_, TYPE_INVALID);
|
|
type_ = TYPE_UINT;
|
|
uint_value_ = value;
|
|
}
|
|
|
|
void CefV8ValueImpl::InitDouble(double value) {
|
|
DCHECK_EQ(type_, TYPE_INVALID);
|
|
type_ = TYPE_DOUBLE;
|
|
double_value_ = value;
|
|
}
|
|
|
|
void CefV8ValueImpl::InitDate(const CefTime& value) {
|
|
DCHECK_EQ(type_, TYPE_INVALID);
|
|
type_ = TYPE_DATE;
|
|
date_value_ = value;
|
|
}
|
|
|
|
void CefV8ValueImpl::InitString(CefString& value) {
|
|
DCHECK_EQ(type_, TYPE_INVALID);
|
|
type_ = TYPE_STRING;
|
|
// Take ownership of the underling string value.
|
|
const cef_string_t* str = value.GetStruct();
|
|
if (str) {
|
|
string_value_ = *str;
|
|
cef_string_t* writable_struct = value.GetWritableStruct();
|
|
writable_struct->str = nullptr;
|
|
writable_struct->length = 0;
|
|
} else {
|
|
string_value_.str = nullptr;
|
|
string_value_.length = 0;
|
|
}
|
|
}
|
|
|
|
void CefV8ValueImpl::InitObject(v8::Local<v8::Value> value,
|
|
CefTrackNode* tracker) {
|
|
DCHECK_EQ(type_, TYPE_INVALID);
|
|
type_ = TYPE_OBJECT;
|
|
handle_ = new Handle(isolate_, v8::Local<v8::Context>(), value, tracker);
|
|
}
|
|
|
|
v8::Local<v8::Value> CefV8ValueImpl::GetV8Value(bool should_persist) {
|
|
switch (type_) {
|
|
case TYPE_UNDEFINED:
|
|
return v8::Undefined(isolate_);
|
|
case TYPE_NULL:
|
|
return v8::Null(isolate_);
|
|
case TYPE_BOOL:
|
|
return v8::Boolean::New(isolate_, bool_value_);
|
|
case TYPE_INT:
|
|
return v8::Int32::New(isolate_, int_value_);
|
|
case TYPE_UINT:
|
|
return v8::Uint32::New(isolate_, uint_value_);
|
|
case TYPE_DOUBLE:
|
|
return v8::Number::New(isolate_, double_value_);
|
|
case TYPE_DATE:
|
|
// Convert from seconds to milliseconds.
|
|
return v8::Date::New(isolate_->GetCurrentContext(),
|
|
CefTime(date_value_).GetDoubleT() * 1000)
|
|
.ToLocalChecked();
|
|
case TYPE_STRING:
|
|
return GetV8String(isolate_, CefString(&string_value_));
|
|
case TYPE_OBJECT:
|
|
return handle_->GetNewV8Handle(should_persist);
|
|
default:
|
|
break;
|
|
}
|
|
|
|
NOTREACHED() << "Invalid type for CefV8ValueImpl";
|
|
return v8::Local<v8::Value>();
|
|
}
|
|
|
|
bool CefV8ValueImpl::IsValid() {
|
|
if (!CEF_V8_HAS_ISOLATE() || type_ == TYPE_INVALID ||
|
|
(type_ == TYPE_OBJECT &&
|
|
(!handle_->BelongsToCurrentThread() || !handle_->IsValid()))) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool CefV8ValueImpl::IsUndefined() {
|
|
CEF_V8_REQUIRE_ISOLATE_RETURN(false);
|
|
return (type_ == TYPE_UNDEFINED);
|
|
}
|
|
|
|
bool CefV8ValueImpl::IsNull() {
|
|
CEF_V8_REQUIRE_ISOLATE_RETURN(false);
|
|
return (type_ == TYPE_NULL);
|
|
}
|
|
|
|
bool CefV8ValueImpl::IsBool() {
|
|
CEF_V8_REQUIRE_ISOLATE_RETURN(false);
|
|
return (type_ == TYPE_BOOL);
|
|
}
|
|
|
|
bool CefV8ValueImpl::IsInt() {
|
|
CEF_V8_REQUIRE_ISOLATE_RETURN(false);
|
|
return (type_ == TYPE_INT || type_ == TYPE_UINT);
|
|
}
|
|
|
|
bool CefV8ValueImpl::IsUInt() {
|
|
CEF_V8_REQUIRE_ISOLATE_RETURN(false);
|
|
return (type_ == TYPE_INT || type_ == TYPE_UINT);
|
|
}
|
|
|
|
bool CefV8ValueImpl::IsDouble() {
|
|
CEF_V8_REQUIRE_ISOLATE_RETURN(false);
|
|
return (type_ == TYPE_INT || type_ == TYPE_UINT || type_ == TYPE_DOUBLE);
|
|
}
|
|
|
|
bool CefV8ValueImpl::IsDate() {
|
|
CEF_V8_REQUIRE_ISOLATE_RETURN(false);
|
|
return (type_ == TYPE_DATE);
|
|
}
|
|
|
|
bool CefV8ValueImpl::IsString() {
|
|
CEF_V8_REQUIRE_ISOLATE_RETURN(false);
|
|
return (type_ == TYPE_STRING);
|
|
}
|
|
|
|
bool CefV8ValueImpl::IsObject() {
|
|
CEF_V8_REQUIRE_ISOLATE_RETURN(false);
|
|
return (type_ == TYPE_OBJECT);
|
|
}
|
|
|
|
bool CefV8ValueImpl::IsArray() {
|
|
CEF_V8_REQUIRE_MLT_RETURN(false);
|
|
if (type_ == TYPE_OBJECT) {
|
|
v8::HandleScope handle_scope(handle_->isolate());
|
|
return handle_->GetNewV8Handle(false)->IsArray();
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool CefV8ValueImpl::IsArrayBuffer() {
|
|
CEF_V8_REQUIRE_MLT_RETURN(false);
|
|
if (type_ == TYPE_OBJECT) {
|
|
v8::HandleScope handle_scope(handle_->isolate());
|
|
return handle_->GetNewV8Handle(false)->IsArrayBuffer();
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool CefV8ValueImpl::IsFunction() {
|
|
CEF_V8_REQUIRE_MLT_RETURN(false);
|
|
if (type_ == TYPE_OBJECT) {
|
|
v8::HandleScope handle_scope(handle_->isolate());
|
|
return handle_->GetNewV8Handle(false)->IsFunction();
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool CefV8ValueImpl::IsSame(CefRefPtr<CefV8Value> that) {
|
|
CEF_V8_REQUIRE_MLT_RETURN(false);
|
|
|
|
CefV8ValueImpl* thatValue = static_cast<CefV8ValueImpl*>(that.get());
|
|
if (!thatValue || !thatValue->IsValid() || type_ != thatValue->type_)
|
|
return false;
|
|
|
|
switch (type_) {
|
|
case TYPE_UNDEFINED:
|
|
case TYPE_NULL:
|
|
return true;
|
|
case TYPE_BOOL:
|
|
return (bool_value_ == thatValue->bool_value_);
|
|
case TYPE_INT:
|
|
return (int_value_ == thatValue->int_value_);
|
|
case TYPE_UINT:
|
|
return (uint_value_ == thatValue->uint_value_);
|
|
case TYPE_DOUBLE:
|
|
return (double_value_ == thatValue->double_value_);
|
|
case TYPE_DATE:
|
|
return (CefTime(date_value_).GetTimeT() ==
|
|
CefTime(thatValue->date_value_).GetTimeT());
|
|
case TYPE_STRING:
|
|
return (CefString(&string_value_) ==
|
|
CefString(&thatValue->string_value_));
|
|
case TYPE_OBJECT: {
|
|
return (handle_->GetPersistentV8Handle() ==
|
|
thatValue->handle_->GetPersistentV8Handle());
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool CefV8ValueImpl::GetBoolValue() {
|
|
CEF_V8_REQUIRE_ISOLATE_RETURN(false);
|
|
if (type_ == TYPE_BOOL)
|
|
return bool_value_;
|
|
return false;
|
|
}
|
|
|
|
int32 CefV8ValueImpl::GetIntValue() {
|
|
CEF_V8_REQUIRE_ISOLATE_RETURN(0);
|
|
if (type_ == TYPE_INT || type_ == TYPE_UINT)
|
|
return int_value_;
|
|
return 0;
|
|
}
|
|
|
|
uint32 CefV8ValueImpl::GetUIntValue() {
|
|
CEF_V8_REQUIRE_ISOLATE_RETURN(0);
|
|
if (type_ == TYPE_INT || type_ == TYPE_UINT)
|
|
return uint_value_;
|
|
return 0;
|
|
}
|
|
|
|
double CefV8ValueImpl::GetDoubleValue() {
|
|
CEF_V8_REQUIRE_ISOLATE_RETURN(0.);
|
|
if (type_ == TYPE_DOUBLE)
|
|
return double_value_;
|
|
else if (type_ == TYPE_INT)
|
|
return int_value_;
|
|
else if (type_ == TYPE_UINT)
|
|
return uint_value_;
|
|
return 0.;
|
|
}
|
|
|
|
CefTime CefV8ValueImpl::GetDateValue() {
|
|
CEF_V8_REQUIRE_ISOLATE_RETURN(CefTime(0.));
|
|
if (type_ == TYPE_DATE)
|
|
return date_value_;
|
|
return CefTime(0.);
|
|
}
|
|
|
|
CefString CefV8ValueImpl::GetStringValue() {
|
|
CefString rv;
|
|
CEF_V8_REQUIRE_ISOLATE_RETURN(rv);
|
|
if (type_ == TYPE_STRING)
|
|
rv = CefString(&string_value_);
|
|
return rv;
|
|
}
|
|
|
|
bool CefV8ValueImpl::IsUserCreated() {
|
|
CEF_V8_REQUIRE_OBJECT_RETURN(false);
|
|
|
|
v8::Isolate* isolate = handle_->isolate();
|
|
v8::HandleScope handle_scope(isolate);
|
|
|
|
v8::Local<v8::Context> context = isolate->GetCurrentContext();
|
|
if (context.IsEmpty()) {
|
|
NOTREACHED() << "not currently in a V8 context";
|
|
return false;
|
|
}
|
|
|
|
v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
|
|
v8::Local<v8::Object> obj = value->ToObject(context).ToLocalChecked();
|
|
|
|
V8TrackObject* tracker = V8TrackObject::Unwrap(context, obj);
|
|
return (tracker != nullptr);
|
|
}
|
|
|
|
bool CefV8ValueImpl::HasException() {
|
|
CEF_V8_REQUIRE_OBJECT_RETURN(false);
|
|
|
|
return (last_exception_.get() != nullptr);
|
|
}
|
|
|
|
CefRefPtr<CefV8Exception> CefV8ValueImpl::GetException() {
|
|
CEF_V8_REQUIRE_OBJECT_RETURN(nullptr);
|
|
|
|
return last_exception_;
|
|
}
|
|
|
|
bool CefV8ValueImpl::ClearException() {
|
|
CEF_V8_REQUIRE_OBJECT_RETURN(false);
|
|
|
|
last_exception_ = nullptr;
|
|
return true;
|
|
}
|
|
|
|
bool CefV8ValueImpl::WillRethrowExceptions() {
|
|
CEF_V8_REQUIRE_OBJECT_RETURN(false);
|
|
|
|
return rethrow_exceptions_;
|
|
}
|
|
|
|
bool CefV8ValueImpl::SetRethrowExceptions(bool rethrow) {
|
|
CEF_V8_REQUIRE_OBJECT_RETURN(false);
|
|
|
|
rethrow_exceptions_ = rethrow;
|
|
return true;
|
|
}
|
|
|
|
bool CefV8ValueImpl::HasValue(const CefString& key) {
|
|
CEF_V8_REQUIRE_OBJECT_RETURN(false);
|
|
|
|
v8::Isolate* isolate = handle_->isolate();
|
|
v8::HandleScope handle_scope(isolate);
|
|
|
|
v8::Local<v8::Context> context = isolate->GetCurrentContext();
|
|
if (context.IsEmpty()) {
|
|
NOTREACHED() << "not currently in a V8 context";
|
|
return false;
|
|
}
|
|
|
|
v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
|
|
v8::Local<v8::Object> obj = value->ToObject(context).ToLocalChecked();
|
|
return obj->Has(context, GetV8String(isolate, key)).FromJust();
|
|
}
|
|
|
|
bool CefV8ValueImpl::HasValue(int index) {
|
|
CEF_V8_REQUIRE_OBJECT_RETURN(false);
|
|
|
|
if (index < 0) {
|
|
NOTREACHED() << "invalid input parameter";
|
|
return false;
|
|
}
|
|
|
|
v8::Isolate* isolate = handle_->isolate();
|
|
v8::HandleScope handle_scope(isolate);
|
|
|
|
v8::Local<v8::Context> context = isolate->GetCurrentContext();
|
|
if (context.IsEmpty()) {
|
|
NOTREACHED() << "not currently in a V8 context";
|
|
return false;
|
|
}
|
|
|
|
v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
|
|
v8::Local<v8::Object> obj = value->ToObject(context).ToLocalChecked();
|
|
return obj->Has(context, index).FromJust();
|
|
}
|
|
|
|
bool CefV8ValueImpl::DeleteValue(const CefString& key) {
|
|
CEF_V8_REQUIRE_OBJECT_RETURN(false);
|
|
|
|
v8::Isolate* isolate = handle_->isolate();
|
|
v8::HandleScope handle_scope(isolate);
|
|
|
|
v8::Local<v8::Context> context = isolate->GetCurrentContext();
|
|
if (context.IsEmpty()) {
|
|
NOTREACHED() << "not currently in a V8 context";
|
|
return false;
|
|
}
|
|
|
|
v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
|
|
v8::Local<v8::Object> obj = value->ToObject(context).ToLocalChecked();
|
|
|
|
v8::TryCatch try_catch(isolate);
|
|
try_catch.SetVerbose(true);
|
|
v8::Maybe<bool> del = obj->Delete(context, GetV8String(isolate, key));
|
|
return (!HasCaught(context, try_catch) && del.FromJust());
|
|
}
|
|
|
|
bool CefV8ValueImpl::DeleteValue(int index) {
|
|
CEF_V8_REQUIRE_OBJECT_RETURN(false);
|
|
|
|
if (index < 0) {
|
|
NOTREACHED() << "invalid input parameter";
|
|
return false;
|
|
}
|
|
|
|
v8::Isolate* isolate = handle_->isolate();
|
|
v8::HandleScope handle_scope(isolate);
|
|
|
|
v8::Local<v8::Context> context = isolate->GetCurrentContext();
|
|
if (context.IsEmpty()) {
|
|
NOTREACHED() << "not currently in a V8 context";
|
|
return false;
|
|
}
|
|
|
|
v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
|
|
v8::Local<v8::Object> obj = value->ToObject(context).ToLocalChecked();
|
|
|
|
v8::TryCatch try_catch(isolate);
|
|
try_catch.SetVerbose(true);
|
|
v8::Maybe<bool> del = obj->Delete(context, index);
|
|
return (!HasCaught(context, try_catch) && del.FromJust());
|
|
}
|
|
|
|
CefRefPtr<CefV8Value> CefV8ValueImpl::GetValue(const CefString& key) {
|
|
CEF_V8_REQUIRE_OBJECT_RETURN(nullptr);
|
|
|
|
v8::Isolate* isolate = handle_->isolate();
|
|
v8::HandleScope handle_scope(isolate);
|
|
|
|
v8::Local<v8::Context> context = isolate->GetCurrentContext();
|
|
if (context.IsEmpty()) {
|
|
NOTREACHED() << "not currently in a V8 context";
|
|
return nullptr;
|
|
}
|
|
|
|
v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
|
|
v8::Local<v8::Object> obj = value->ToObject(context).ToLocalChecked();
|
|
|
|
v8::TryCatch try_catch(isolate);
|
|
try_catch.SetVerbose(true);
|
|
v8::MaybeLocal<v8::Value> ret_value =
|
|
obj->Get(context, GetV8String(isolate, key));
|
|
if (!HasCaught(context, try_catch) && !ret_value.IsEmpty()) {
|
|
return new CefV8ValueImpl(isolate, context, ret_value.ToLocalChecked());
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
CefRefPtr<CefV8Value> CefV8ValueImpl::GetValue(int index) {
|
|
CEF_V8_REQUIRE_OBJECT_RETURN(nullptr);
|
|
|
|
if (index < 0) {
|
|
NOTREACHED() << "invalid input parameter";
|
|
return nullptr;
|
|
}
|
|
|
|
v8::Isolate* isolate = handle_->isolate();
|
|
v8::HandleScope handle_scope(isolate);
|
|
|
|
v8::Local<v8::Context> context = isolate->GetCurrentContext();
|
|
if (context.IsEmpty()) {
|
|
NOTREACHED() << "not currently in a V8 context";
|
|
return nullptr;
|
|
}
|
|
|
|
v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
|
|
v8::Local<v8::Object> obj = value->ToObject(context).ToLocalChecked();
|
|
|
|
v8::TryCatch try_catch(isolate);
|
|
try_catch.SetVerbose(true);
|
|
v8::MaybeLocal<v8::Value> ret_value =
|
|
obj->Get(context, v8::Number::New(isolate, index));
|
|
if (!HasCaught(context, try_catch) && !ret_value.IsEmpty()) {
|
|
return new CefV8ValueImpl(isolate, context, ret_value.ToLocalChecked());
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
bool CefV8ValueImpl::SetValue(const CefString& key,
|
|
CefRefPtr<CefV8Value> value,
|
|
PropertyAttribute attribute) {
|
|
CEF_V8_REQUIRE_OBJECT_RETURN(false);
|
|
|
|
CefV8ValueImpl* impl = static_cast<CefV8ValueImpl*>(value.get());
|
|
if (impl && impl->IsValid()) {
|
|
v8::Isolate* isolate = handle_->isolate();
|
|
v8::HandleScope handle_scope(isolate);
|
|
|
|
v8::Local<v8::Context> context = isolate->GetCurrentContext();
|
|
if (context.IsEmpty()) {
|
|
NOTREACHED() << "not currently in a V8 context";
|
|
return false;
|
|
}
|
|
|
|
v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
|
|
v8::Local<v8::Object> obj = value->ToObject(context).ToLocalChecked();
|
|
|
|
v8::TryCatch try_catch(isolate);
|
|
try_catch.SetVerbose(true);
|
|
// TODO(cef): This usage may not exactly match the previous implementation.
|
|
// Set will trigger interceptors and/or accessors whereas DefineOwnProperty
|
|
// will not. It might be better to split this functionality into separate
|
|
// methods.
|
|
if (attribute == V8_PROPERTY_ATTRIBUTE_NONE) {
|
|
v8::Maybe<bool> set =
|
|
obj->Set(context, GetV8String(isolate, key), impl->GetV8Value(true));
|
|
return (!HasCaught(context, try_catch) && set.FromJust());
|
|
} else {
|
|
v8::Maybe<bool> set = obj->DefineOwnProperty(
|
|
context, GetV8String(isolate, key), impl->GetV8Value(true),
|
|
static_cast<v8::PropertyAttribute>(attribute));
|
|
return (!HasCaught(context, try_catch) && set.FromJust());
|
|
}
|
|
} else {
|
|
NOTREACHED() << "invalid input parameter";
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool CefV8ValueImpl::SetValue(int index, CefRefPtr<CefV8Value> value) {
|
|
CEF_V8_REQUIRE_OBJECT_RETURN(false);
|
|
|
|
if (index < 0) {
|
|
NOTREACHED() << "invalid input parameter";
|
|
return false;
|
|
}
|
|
|
|
CefV8ValueImpl* impl = static_cast<CefV8ValueImpl*>(value.get());
|
|
if (impl && impl->IsValid()) {
|
|
v8::Isolate* isolate = handle_->isolate();
|
|
v8::HandleScope handle_scope(isolate);
|
|
|
|
v8::Local<v8::Context> context = isolate->GetCurrentContext();
|
|
if (context.IsEmpty()) {
|
|
NOTREACHED() << "not currently in a V8 context";
|
|
return false;
|
|
}
|
|
|
|
v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
|
|
v8::Local<v8::Object> obj = value->ToObject(context).ToLocalChecked();
|
|
|
|
v8::TryCatch try_catch(isolate);
|
|
try_catch.SetVerbose(true);
|
|
v8::Maybe<bool> set = obj->Set(context, index, impl->GetV8Value(true));
|
|
return (!HasCaught(context, try_catch) && set.FromJust());
|
|
} else {
|
|
NOTREACHED() << "invalid input parameter";
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool CefV8ValueImpl::SetValue(const CefString& key,
|
|
AccessControl settings,
|
|
PropertyAttribute attribute) {
|
|
CEF_V8_REQUIRE_OBJECT_RETURN(false);
|
|
|
|
v8::Isolate* isolate = handle_->isolate();
|
|
v8::HandleScope handle_scope(isolate);
|
|
|
|
v8::Local<v8::Context> context = isolate->GetCurrentContext();
|
|
if (context.IsEmpty()) {
|
|
NOTREACHED() << "not currently in a V8 context";
|
|
return false;
|
|
}
|
|
|
|
v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
|
|
v8::Local<v8::Object> obj = value->ToObject(context).ToLocalChecked();
|
|
|
|
CefRefPtr<CefV8Accessor> accessorPtr;
|
|
|
|
V8TrackObject* tracker = V8TrackObject::Unwrap(context, obj);
|
|
if (tracker)
|
|
accessorPtr = tracker->GetAccessor();
|
|
|
|
// Verify that an accessor exists for this object.
|
|
if (!accessorPtr.get())
|
|
return false;
|
|
|
|
v8::AccessorNameGetterCallback getter = AccessorNameGetterCallbackImpl;
|
|
v8::AccessorNameSetterCallback setter =
|
|
(attribute & V8_PROPERTY_ATTRIBUTE_READONLY)
|
|
? nullptr
|
|
: AccessorNameSetterCallbackImpl;
|
|
|
|
v8::TryCatch try_catch(isolate);
|
|
try_catch.SetVerbose(true);
|
|
v8::Maybe<bool> set =
|
|
obj->SetAccessor(context, GetV8String(isolate, key), getter, setter, obj,
|
|
static_cast<v8::AccessControl>(settings),
|
|
static_cast<v8::PropertyAttribute>(attribute));
|
|
return (!HasCaught(context, try_catch) && set.FromJust());
|
|
}
|
|
|
|
bool CefV8ValueImpl::GetKeys(std::vector<CefString>& keys) {
|
|
CEF_V8_REQUIRE_OBJECT_RETURN(false);
|
|
|
|
v8::Isolate* isolate = handle_->isolate();
|
|
v8::HandleScope handle_scope(isolate);
|
|
|
|
v8::Local<v8::Context> context = isolate->GetCurrentContext();
|
|
if (context.IsEmpty()) {
|
|
NOTREACHED() << "not currently in a V8 context";
|
|
return false;
|
|
}
|
|
|
|
v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
|
|
v8::Local<v8::Object> obj = value->ToObject(context).ToLocalChecked();
|
|
v8::Local<v8::Array> arr_keys =
|
|
obj->GetPropertyNames(context).ToLocalChecked();
|
|
|
|
uint32_t len = arr_keys->Length();
|
|
for (uint32_t i = 0; i < len; ++i) {
|
|
v8::Local<v8::Value> value =
|
|
arr_keys->Get(context, v8::Integer::New(isolate, i)).ToLocalChecked();
|
|
CefString str;
|
|
GetCefString(isolate, value->ToString(context).ToLocalChecked(), str);
|
|
keys.push_back(str);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool CefV8ValueImpl::SetUserData(CefRefPtr<CefBaseRefCounted> user_data) {
|
|
CEF_V8_REQUIRE_OBJECT_RETURN(false);
|
|
|
|
v8::Isolate* isolate = handle_->isolate();
|
|
v8::HandleScope handle_scope(isolate);
|
|
|
|
v8::Local<v8::Context> context = isolate->GetCurrentContext();
|
|
if (context.IsEmpty()) {
|
|
NOTREACHED() << "not currently in a V8 context";
|
|
return false;
|
|
}
|
|
|
|
v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
|
|
v8::Local<v8::Object> obj = value->ToObject(context).ToLocalChecked();
|
|
|
|
V8TrackObject* tracker = V8TrackObject::Unwrap(context, obj);
|
|
if (tracker) {
|
|
tracker->SetUserData(user_data);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
CefRefPtr<CefBaseRefCounted> CefV8ValueImpl::GetUserData() {
|
|
CEF_V8_REQUIRE_OBJECT_RETURN(nullptr);
|
|
|
|
v8::Isolate* isolate = handle_->isolate();
|
|
v8::HandleScope handle_scope(isolate);
|
|
|
|
v8::Local<v8::Context> context = isolate->GetCurrentContext();
|
|
if (context.IsEmpty()) {
|
|
NOTREACHED() << "not currently in a V8 context";
|
|
return nullptr;
|
|
}
|
|
|
|
v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
|
|
v8::Local<v8::Object> obj = value->ToObject(context).ToLocalChecked();
|
|
|
|
V8TrackObject* tracker = V8TrackObject::Unwrap(context, obj);
|
|
if (tracker)
|
|
return tracker->GetUserData();
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
int CefV8ValueImpl::GetExternallyAllocatedMemory() {
|
|
CEF_V8_REQUIRE_OBJECT_RETURN(0);
|
|
|
|
v8::Isolate* isolate = handle_->isolate();
|
|
v8::HandleScope handle_scope(isolate);
|
|
|
|
v8::Local<v8::Context> context = isolate->GetCurrentContext();
|
|
if (context.IsEmpty()) {
|
|
NOTREACHED() << "not currently in a V8 context";
|
|
return 0;
|
|
}
|
|
|
|
v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
|
|
v8::Local<v8::Object> obj = value->ToObject(context).ToLocalChecked();
|
|
|
|
V8TrackObject* tracker = V8TrackObject::Unwrap(context, obj);
|
|
if (tracker)
|
|
return tracker->GetExternallyAllocatedMemory();
|
|
|
|
return 0;
|
|
}
|
|
|
|
int CefV8ValueImpl::AdjustExternallyAllocatedMemory(int change_in_bytes) {
|
|
CEF_V8_REQUIRE_OBJECT_RETURN(0);
|
|
|
|
v8::Isolate* isolate = handle_->isolate();
|
|
v8::HandleScope handle_scope(isolate);
|
|
|
|
v8::Local<v8::Context> context = isolate->GetCurrentContext();
|
|
if (context.IsEmpty()) {
|
|
NOTREACHED() << "not currently in a V8 context";
|
|
return 0;
|
|
}
|
|
|
|
v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
|
|
v8::Local<v8::Object> obj = value->ToObject(context).ToLocalChecked();
|
|
|
|
V8TrackObject* tracker = V8TrackObject::Unwrap(context, obj);
|
|
if (tracker)
|
|
return tracker->AdjustExternallyAllocatedMemory(change_in_bytes);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int CefV8ValueImpl::GetArrayLength() {
|
|
CEF_V8_REQUIRE_OBJECT_RETURN(0);
|
|
|
|
v8::Isolate* isolate = handle_->isolate();
|
|
v8::HandleScope handle_scope(isolate);
|
|
|
|
v8::Local<v8::Context> context = isolate->GetCurrentContext();
|
|
if (context.IsEmpty()) {
|
|
NOTREACHED() << "not currently in a V8 context";
|
|
return 0;
|
|
}
|
|
|
|
v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
|
|
if (!value->IsArray()) {
|
|
NOTREACHED() << "V8 value is not an array";
|
|
return 0;
|
|
}
|
|
|
|
v8::Local<v8::Object> obj = value->ToObject(context).ToLocalChecked();
|
|
v8::Local<v8::Array> arr = v8::Local<v8::Array>::Cast(obj);
|
|
return arr->Length();
|
|
}
|
|
|
|
CefRefPtr<CefV8ArrayBufferReleaseCallback>
|
|
CefV8ValueImpl::GetArrayBufferReleaseCallback() {
|
|
CEF_V8_REQUIRE_OBJECT_RETURN(nullptr);
|
|
|
|
v8::Isolate* isolate = handle_->isolate();
|
|
v8::HandleScope handle_scope(isolate);
|
|
|
|
v8::Local<v8::Context> context = isolate->GetCurrentContext();
|
|
if (context.IsEmpty()) {
|
|
NOTREACHED() << "not currently in a V8 context";
|
|
return nullptr;
|
|
}
|
|
|
|
v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
|
|
if (!value->IsArrayBuffer()) {
|
|
NOTREACHED() << "V8 value is not an array buffer";
|
|
return nullptr;
|
|
}
|
|
|
|
v8::Local<v8::Object> obj = value->ToObject(context).ToLocalChecked();
|
|
|
|
V8TrackArrayBuffer* tracker = V8TrackArrayBuffer::Unwrap(context, obj);
|
|
if (tracker)
|
|
return tracker->GetReleaseCallback();
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
bool CefV8ValueImpl::NeuterArrayBuffer() {
|
|
CEF_V8_REQUIRE_OBJECT_RETURN(0);
|
|
|
|
v8::Isolate* isolate = handle_->isolate();
|
|
v8::HandleScope handle_scope(isolate);
|
|
|
|
v8::Local<v8::Context> context = isolate->GetCurrentContext();
|
|
if (context.IsEmpty()) {
|
|
NOTREACHED() << "not currently in a V8 context";
|
|
return false;
|
|
}
|
|
|
|
v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
|
|
if (!value->IsArrayBuffer()) {
|
|
NOTREACHED() << "V8 value is not an array buffer";
|
|
return false;
|
|
}
|
|
v8::Local<v8::Object> obj = value->ToObject(context).ToLocalChecked();
|
|
v8::Local<v8::ArrayBuffer> arr = v8::Local<v8::ArrayBuffer>::Cast(obj);
|
|
if (!arr->IsDetachable()) {
|
|
return false;
|
|
}
|
|
arr->Detach();
|
|
V8TrackArrayBuffer* tracker = V8TrackArrayBuffer::Unwrap(context, obj);
|
|
tracker->Detach();
|
|
|
|
return true;
|
|
}
|
|
|
|
CefString CefV8ValueImpl::GetFunctionName() {
|
|
CefString rv;
|
|
CEF_V8_REQUIRE_OBJECT_RETURN(rv);
|
|
|
|
v8::Isolate* isolate = handle_->isolate();
|
|
v8::HandleScope handle_scope(isolate);
|
|
|
|
v8::Local<v8::Context> context = isolate->GetCurrentContext();
|
|
if (context.IsEmpty()) {
|
|
NOTREACHED() << "not currently in a V8 context";
|
|
return rv;
|
|
}
|
|
|
|
v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
|
|
if (!value->IsFunction()) {
|
|
NOTREACHED() << "V8 value is not a function";
|
|
return rv;
|
|
}
|
|
|
|
v8::Local<v8::Object> obj = value->ToObject(context).ToLocalChecked();
|
|
v8::Local<v8::Function> func = v8::Local<v8::Function>::Cast(obj);
|
|
GetCefString(handle_->isolate(),
|
|
v8::Handle<v8::String>::Cast(func->GetName()), rv);
|
|
return rv;
|
|
}
|
|
|
|
CefRefPtr<CefV8Handler> CefV8ValueImpl::GetFunctionHandler() {
|
|
CEF_V8_REQUIRE_OBJECT_RETURN(nullptr);
|
|
|
|
v8::Isolate* isolate = handle_->isolate();
|
|
v8::HandleScope handle_scope(isolate);
|
|
|
|
v8::Local<v8::Context> context = isolate->GetCurrentContext();
|
|
if (context.IsEmpty()) {
|
|
NOTREACHED() << "not currently in a V8 context";
|
|
return nullptr;
|
|
}
|
|
|
|
v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
|
|
if (!value->IsFunction()) {
|
|
NOTREACHED() << "V8 value is not a function";
|
|
return nullptr;
|
|
}
|
|
|
|
v8::Local<v8::Object> obj = value->ToObject(context).ToLocalChecked();
|
|
V8TrackObject* tracker = V8TrackObject::Unwrap(context, obj);
|
|
if (tracker)
|
|
return tracker->GetHandler();
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
CefRefPtr<CefV8Value> CefV8ValueImpl::ExecuteFunction(
|
|
CefRefPtr<CefV8Value> object,
|
|
const CefV8ValueList& arguments) {
|
|
// An empty context value defaults to the current context.
|
|
CefRefPtr<CefV8Context> context;
|
|
return ExecuteFunctionWithContext(context, object, arguments);
|
|
}
|
|
|
|
CefRefPtr<CefV8Value> CefV8ValueImpl::ExecuteFunctionWithContext(
|
|
CefRefPtr<CefV8Context> context,
|
|
CefRefPtr<CefV8Value> object,
|
|
const CefV8ValueList& arguments) {
|
|
CEF_V8_REQUIRE_OBJECT_RETURN(nullptr);
|
|
|
|
v8::Isolate* isolate = handle_->isolate();
|
|
v8::HandleScope handle_scope(isolate);
|
|
v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
|
|
if (!value->IsFunction()) {
|
|
NOTREACHED() << "V8 value is not a function";
|
|
return nullptr;
|
|
}
|
|
|
|
if (context.get() && !context->IsValid()) {
|
|
NOTREACHED() << "invalid V8 context parameter";
|
|
return nullptr;
|
|
}
|
|
if (object.get() && (!object->IsValid() || !object->IsObject())) {
|
|
NOTREACHED() << "invalid V8 object parameter";
|
|
return nullptr;
|
|
}
|
|
|
|
int argc = arguments.size();
|
|
if (argc > 0) {
|
|
for (int i = 0; i < argc; ++i) {
|
|
if (!arguments[i].get() || !arguments[i]->IsValid()) {
|
|
NOTREACHED() << "invalid V8 arguments parameter";
|
|
return nullptr;
|
|
}
|
|
}
|
|
}
|
|
|
|
v8::Local<v8::Context> context_local;
|
|
if (context.get()) {
|
|
CefV8ContextImpl* context_impl =
|
|
static_cast<CefV8ContextImpl*>(context.get());
|
|
context_local = context_impl->GetV8Context();
|
|
} else {
|
|
context_local = isolate->GetCurrentContext();
|
|
}
|
|
|
|
v8::Context::Scope context_scope(context_local);
|
|
|
|
v8::Local<v8::Object> obj = value->ToObject(context_local).ToLocalChecked();
|
|
v8::Local<v8::Function> func = v8::Local<v8::Function>::Cast(obj);
|
|
v8::Local<v8::Object> recv;
|
|
|
|
// Default to the global object if no object was provided.
|
|
if (object.get()) {
|
|
CefV8ValueImpl* recv_impl = static_cast<CefV8ValueImpl*>(object.get());
|
|
recv = v8::Local<v8::Object>::Cast(recv_impl->GetV8Value(true));
|
|
} else {
|
|
recv = context_local->Global();
|
|
}
|
|
|
|
v8::Local<v8::Value>* argv = nullptr;
|
|
if (argc > 0) {
|
|
argv = new v8::Local<v8::Value>[argc];
|
|
for (int i = 0; i < argc; ++i) {
|
|
argv[i] =
|
|
static_cast<CefV8ValueImpl*>(arguments[i].get())->GetV8Value(true);
|
|
}
|
|
}
|
|
|
|
CefRefPtr<CefV8Value> retval;
|
|
|
|
{
|
|
v8::TryCatch try_catch(isolate);
|
|
try_catch.SetVerbose(true);
|
|
|
|
v8::MaybeLocal<v8::Value> func_rv = blink_glue::CallV8Function(
|
|
context_local, func, recv, argc, argv, handle_->isolate());
|
|
|
|
if (!HasCaught(context_local, try_catch) && !func_rv.IsEmpty()) {
|
|
retval =
|
|
new CefV8ValueImpl(isolate, context_local, func_rv.ToLocalChecked());
|
|
}
|
|
}
|
|
|
|
if (argv)
|
|
delete[] argv;
|
|
|
|
return retval;
|
|
}
|
|
|
|
bool CefV8ValueImpl::HasCaught(v8::Local<v8::Context> context,
|
|
v8::TryCatch& try_catch) {
|
|
if (try_catch.HasCaught()) {
|
|
last_exception_ = new CefV8ExceptionImpl(context, try_catch.Message());
|
|
if (rethrow_exceptions_)
|
|
try_catch.ReThrow();
|
|
return true;
|
|
} else {
|
|
if (last_exception_.get())
|
|
last_exception_ = nullptr;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// CefV8StackTrace
|
|
|
|
// static
|
|
CefRefPtr<CefV8StackTrace> CefV8StackTrace::GetCurrent(int frame_limit) {
|
|
CEF_V8_REQUIRE_ISOLATE_RETURN(nullptr);
|
|
|
|
v8::Isolate* isolate = GetIsolateManager()->isolate();
|
|
v8::HandleScope handle_scope(isolate);
|
|
v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
|
|
isolate, frame_limit, v8::StackTrace::kDetailed);
|
|
if (stackTrace.IsEmpty())
|
|
return nullptr;
|
|
return new CefV8StackTraceImpl(isolate, stackTrace);
|
|
}
|
|
|
|
// CefV8StackTraceImpl
|
|
|
|
CefV8StackTraceImpl::CefV8StackTraceImpl(v8::Isolate* isolate,
|
|
v8::Local<v8::StackTrace> handle) {
|
|
if (!handle.IsEmpty()) {
|
|
int frame_count = handle->GetFrameCount();
|
|
if (frame_count > 0) {
|
|
frames_.reserve(frame_count);
|
|
for (int i = 0; i < frame_count; ++i)
|
|
frames_.push_back(
|
|
new CefV8StackFrameImpl(isolate, handle->GetFrame(isolate, i)));
|
|
}
|
|
}
|
|
}
|
|
|
|
CefV8StackTraceImpl::~CefV8StackTraceImpl() {}
|
|
|
|
bool CefV8StackTraceImpl::IsValid() {
|
|
return true;
|
|
}
|
|
|
|
int CefV8StackTraceImpl::GetFrameCount() {
|
|
return frames_.size();
|
|
}
|
|
|
|
CefRefPtr<CefV8StackFrame> CefV8StackTraceImpl::GetFrame(int index) {
|
|
if (index < 0 || index >= static_cast<int>(frames_.size()))
|
|
return nullptr;
|
|
return frames_[index];
|
|
}
|
|
|
|
// CefV8StackFrameImpl
|
|
|
|
CefV8StackFrameImpl::CefV8StackFrameImpl(v8::Isolate* isolate,
|
|
v8::Local<v8::StackFrame> handle)
|
|
: line_number_(0), column_(0), is_eval_(false), is_constructor_(false) {
|
|
if (handle.IsEmpty())
|
|
return;
|
|
GetCefString(isolate, handle->GetScriptName(), script_name_);
|
|
GetCefString(isolate, handle->GetScriptNameOrSourceURL(),
|
|
script_name_or_source_url_);
|
|
GetCefString(isolate, handle->GetFunctionName(), function_name_);
|
|
line_number_ = handle->GetLineNumber();
|
|
column_ = handle->GetColumn();
|
|
is_eval_ = handle->IsEval();
|
|
is_constructor_ = handle->IsConstructor();
|
|
}
|
|
|
|
CefV8StackFrameImpl::~CefV8StackFrameImpl() {}
|
|
|
|
bool CefV8StackFrameImpl::IsValid() {
|
|
return true;
|
|
}
|
|
|
|
CefString CefV8StackFrameImpl::GetScriptName() {
|
|
return script_name_;
|
|
}
|
|
|
|
CefString CefV8StackFrameImpl::GetScriptNameOrSourceURL() {
|
|
return script_name_or_source_url_;
|
|
}
|
|
|
|
CefString CefV8StackFrameImpl::GetFunctionName() {
|
|
return function_name_;
|
|
}
|
|
|
|
int CefV8StackFrameImpl::GetLineNumber() {
|
|
return line_number_;
|
|
}
|
|
|
|
int CefV8StackFrameImpl::GetColumn() {
|
|
return column_;
|
|
}
|
|
|
|
bool CefV8StackFrameImpl::IsEval() {
|
|
return is_eval_;
|
|
}
|
|
|
|
bool CefV8StackFrameImpl::IsConstructor() {
|
|
return is_constructor_;
|
|
}
|
|
|
|
// Enable deprecation warnings on Windows. See http://crbug.com/585142.
|
|
#if defined(OS_WIN)
|
|
#if defined(__clang__)
|
|
#pragma GCC diagnostic pop
|
|
#else
|
|
#pragma warning(pop)
|
|
#endif
|
|
#endif
|