Add support for V8 ArrayBuffers (issue #244)

This commit is contained in:
Christopher Cifra
2018-04-10 15:37:33 -04:00
committed by Marshall Greenblatt
parent bb28b85bdd
commit 4315f3b724
16 changed files with 775 additions and 8 deletions

View File

@ -304,6 +304,74 @@ class V8TrackString : public CefTrackNode {
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_);
}
~V8TrackArrayBuffer() {
if (buffer_ != nullptr) {
release_callback_->ReleaseBuffer(buffer_);
}
isolate_->AdjustAmountOfExternalAllocatedMemory(
-static_cast<int>(sizeof(V8TrackArrayBuffer)));
}
CefRefPtr<CefV8ArrayBufferReleaseCallback> GetReleaseCallback() {
return release_callback_;
}
void Neuter() { buffer_ = nullptr; }
// 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;
}
// Attach this track object to the specified V8 object.
void AttachTo(v8::Local<v8::Context> context,
v8::Local<v8::ArrayBuffer> arrayBuffer) {
isolate_->AdjustAmountOfExternalAllocatedMemory(
static_cast<int>(sizeof(V8TrackArrayBuffer)));
SetPrivate(context, arrayBuffer, kCefTrackObject,
v8::External::New(isolate_, this));
handle_.Reset(isolate_, arrayBuffer);
handle_.SetWeak(this, FirstWeakCallback, v8::WeakCallbackType::kParameter);
handle_.MarkIndependent();
}
private:
static void FirstWeakCallback(
const v8::WeakCallbackInfo<V8TrackArrayBuffer>& data) {
V8TrackArrayBuffer* wrapper = data.GetParameter();
if (wrapper->buffer_ != nullptr) {
wrapper->release_callback_->ReleaseBuffer(wrapper->buffer_);
wrapper->buffer_ = nullptr;
}
wrapper->handle_.Reset();
}
v8::Isolate* isolate_;
void* buffer_;
CefRefPtr<CefV8ArrayBufferReleaseCallback> release_callback_;
v8::Persistent<v8::ArrayBuffer> handle_;
};
// Object wrapped in a v8::External and passed as the Data argument to
// v8::FunctionTemplate::New.
class V8FunctionData {
@ -1311,6 +1379,35 @@ CefRefPtr<CefV8Value> CefV8Value::CreateArray(int length) {
return impl.get();
}
// static
CefRefPtr<CefV8Value> CefV8Value::CreateArrayBuffer(
void* buffer,
size_t length,
CefRefPtr<CefV8ArrayBufferReleaseCallback> release_callback) {
CEF_V8_REQUIRE_ISOLATE_RETURN(NULL);
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 NULL;
}
// 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,
@ -1571,6 +1668,16 @@ bool CefV8ValueImpl::IsArray() {
}
}
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) {
@ -2091,6 +2198,60 @@ int CefV8ValueImpl::GetArrayLength() {
return arr->Length();
}
CefRefPtr<CefV8ArrayBufferReleaseCallback>
CefV8ValueImpl::GetArrayBufferReleaseCallback() {
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 NULL;
}
v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
if (!value->IsArrayBuffer()) {
NOTREACHED() << "V8 value is not an array buffer";
return NULL;
}
v8::Local<v8::Object> obj = value->ToObject();
V8TrackArrayBuffer* tracker = V8TrackArrayBuffer::Unwrap(context, obj);
if (tracker)
return tracker->GetReleaseCallback();
return NULL;
}
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();
v8::Local<v8::ArrayBuffer> arr = v8::Local<v8::ArrayBuffer>::Cast(obj);
if (!arr->IsNeuterable()) {
return false;
}
arr->Neuter();
V8TrackArrayBuffer* tracker = V8TrackArrayBuffer::Unwrap(context, obj);
tracker->Neuter();
return true;
}
CefString CefV8ValueImpl::GetFunctionName() {
CefString rv;
CEF_V8_REQUIRE_OBJECT_RETURN(rv);

View File

@ -227,6 +227,7 @@ class CefV8ValueImpl : public CefV8Value {
bool IsString() override;
bool IsObject() override;
bool IsArray() override;
bool IsArrayBuffer() override;
bool IsFunction() override;
bool IsSame(CefRefPtr<CefV8Value> value) override;
bool GetBoolValue() override;
@ -260,6 +261,9 @@ class CefV8ValueImpl : public CefV8Value {
int GetExternallyAllocatedMemory() override;
int AdjustExternallyAllocatedMemory(int change_in_bytes) override;
int GetArrayLength() override;
CefRefPtr<CefV8ArrayBufferReleaseCallback> GetArrayBufferReleaseCallback()
override;
bool NeuterArrayBuffer() override;
CefString GetFunctionName() override;
CefRefPtr<CefV8Handler> GetFunctionHandler() override;
CefRefPtr<CefV8Value> ExecuteFunction(