1 // Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
2 // reserved. Use of this source code is governed by a BSD-style license that
3 // can be found in the LICENSE file.
4
5 // MSVC++ requires this to be set before any other includes to get M_PI.
6 // Otherwise there will be compile errors in wtf/MathExtras.h.
7 #define _USE_MATH_DEFINES
8
9 #include <map>
10 #include <string>
11
12 #include "base/command_line.h"
13 #include "base/compiler_specific.h"
14
15 // Enable deprecation warnings for MSVC and Clang. See http://crbug.com/585142.
16 #if BUILDFLAG(IS_WIN)
17 #if defined(__clang__)
18 #pragma GCC diagnostic push
19 #pragma GCC diagnostic error "-Wdeprecated-declarations"
20 #else
21 #pragma warning(push)
22 #pragma warning(default : 4996)
23 #endif
24 #endif
25
26 #include "libcef/renderer/v8_impl.h"
27
28 #include "libcef/common/app_manager.h"
29 #include "libcef/common/cef_switches.h"
30 #include "libcef/common/task_runner_impl.h"
31 #include "libcef/common/tracker.h"
32 #include "libcef/renderer/blink_glue.h"
33 #include "libcef/renderer/browser_impl.h"
34 #include "libcef/renderer/render_frame_util.h"
35 #include "libcef/renderer/thread_util.h"
36
37 #include "base/bind.h"
38 #include "base/lazy_instance.h"
39 #include "base/strings/string_number_conversions.h"
40 #include "base/threading/thread_local.h"
41 #include "third_party/blink/public/web/blink.h"
42 #include "third_party/blink/public/web/web_frame.h"
43 #include "third_party/blink/public/web/web_local_frame.h"
44 #include "url/gurl.h"
45
46 namespace {
47
48 static const char kCefTrackObject[] = "Cef::TrackObject";
49
50 void MessageListenerCallbackImpl(v8::Handle<v8::Message> message,
51 v8::Handle<v8::Value> data);
52
53 // The following *Private functions are convenience wrappers for methods on
54 // v8::Object with the corresponding names.
55 // Based on extensions/renderer/object_backed_native_handler.cc.
56
SetPrivate(v8::Local<v8::Context> context,v8::Local<v8::Object> obj,const char * key,v8::Local<v8::Value> value)57 void SetPrivate(v8::Local<v8::Context> context,
58 v8::Local<v8::Object> obj,
59 const char* key,
60 v8::Local<v8::Value> value) {
61 v8::Isolate* isolate = context->GetIsolate();
62 obj->SetPrivate(context,
63 v8::Private::ForApi(
64 isolate, v8::String::NewFromUtf8(
65 isolate, key, v8::NewStringType::kNormal)
66 .ToLocalChecked()),
67 value)
68 .FromJust();
69 }
70
GetPrivate(v8::Local<v8::Context> context,v8::Local<v8::Object> obj,const char * key,v8::Local<v8::Value> * result)71 bool GetPrivate(v8::Local<v8::Context> context,
72 v8::Local<v8::Object> obj,
73 const char* key,
74 v8::Local<v8::Value>* result) {
75 v8::Isolate* isolate = context->GetIsolate();
76 return obj
77 ->GetPrivate(context,
78 v8::Private::ForApi(
79 isolate, v8::String::NewFromUtf8(
80 isolate, key, v8::NewStringType::kNormal)
81 .ToLocalChecked()))
82 .ToLocal(result);
83 }
84
85 // Manages memory and state information associated with a single Isolate.
86 class CefV8IsolateManager {
87 public:
CefV8IsolateManager()88 CefV8IsolateManager()
89 : isolate_(v8::Isolate::GetCurrent()),
90 task_runner_(CEF_RENDER_TASK_RUNNER()),
91 message_listener_registered_(false),
92 worker_id_(0) {
93 DCHECK(isolate_);
94 DCHECK(task_runner_.get());
95 }
~CefV8IsolateManager()96 ~CefV8IsolateManager() {
97 DCHECK_EQ(isolate_, v8::Isolate::GetCurrent());
98 DCHECK(context_map_.empty());
99 }
100
GetContextState(v8::Local<v8::Context> context)101 scoped_refptr<CefV8ContextState> GetContextState(
102 v8::Local<v8::Context> context) {
103 DCHECK_EQ(isolate_, v8::Isolate::GetCurrent());
104 DCHECK(context.IsEmpty() || isolate_ == context->GetIsolate());
105
106 if (context.IsEmpty()) {
107 if (isolate_->InContext())
108 context = isolate_->GetCurrentContext();
109 else
110 return scoped_refptr<CefV8ContextState>();
111 }
112
113 int hash = context->Global()->GetIdentityHash();
114 ContextMap::const_iterator it = context_map_.find(hash);
115 if (it != context_map_.end())
116 return it->second;
117
118 scoped_refptr<CefV8ContextState> state = new CefV8ContextState();
119 context_map_.insert(std::make_pair(hash, state));
120
121 return state;
122 }
123
ReleaseContext(v8::Local<v8::Context> context)124 void ReleaseContext(v8::Local<v8::Context> context) {
125 DCHECK_EQ(isolate_, v8::Isolate::GetCurrent());
126 DCHECK_EQ(isolate_, context->GetIsolate());
127
128 int hash = context->Global()->GetIdentityHash();
129 ContextMap::iterator it = context_map_.find(hash);
130 if (it != context_map_.end()) {
131 it->second->Detach();
132 context_map_.erase(it);
133 }
134 }
135
AddGlobalTrackObject(CefTrackNode * object)136 void AddGlobalTrackObject(CefTrackNode* object) {
137 DCHECK_EQ(isolate_, v8::Isolate::GetCurrent());
138 global_manager_.Add(object);
139 }
140
DeleteGlobalTrackObject(CefTrackNode * object)141 void DeleteGlobalTrackObject(CefTrackNode* object) {
142 DCHECK_EQ(isolate_, v8::Isolate::GetCurrent());
143 global_manager_.Delete(object);
144 }
145
SetUncaughtExceptionStackSize(int stack_size)146 void SetUncaughtExceptionStackSize(int stack_size) {
147 if (stack_size <= 0)
148 return;
149
150 if (!message_listener_registered_) {
151 isolate_->AddMessageListener(&MessageListenerCallbackImpl);
152 message_listener_registered_ = true;
153 }
154
155 isolate_->SetCaptureStackTraceForUncaughtExceptions(
156 true, stack_size, v8::StackTrace::kDetailed);
157 }
158
SetWorkerAttributes(int worker_id,const GURL & worker_url)159 void SetWorkerAttributes(int worker_id, const GURL& worker_url) {
160 worker_id_ = worker_id;
161 worker_url_ = worker_url;
162 }
163
isolate() const164 v8::Isolate* isolate() const { return isolate_; }
task_runner() const165 scoped_refptr<base::SingleThreadTaskRunner> task_runner() const {
166 return task_runner_;
167 }
168
worker_id() const169 int worker_id() const { return worker_id_; }
170
worker_url() const171 const GURL& worker_url() const { return worker_url_; }
172
173 private:
174 v8::Isolate* isolate_;
175 scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
176
177 using ContextMap = std::map<int, scoped_refptr<CefV8ContextState>>;
178 ContextMap context_map_;
179
180 // Used for globally tracked objects that are not associated with a particular
181 // context.
182 CefTrackManager global_manager_;
183
184 // True if the message listener has been registered.
185 bool message_listener_registered_;
186
187 // Attributes associated with WebWorker threads.
188 int worker_id_;
189 GURL worker_url_;
190 };
191
192 // Chromium uses the default Isolate for the main render process thread and a
193 // new Isolate for each WebWorker thread. Continue this pattern by tracking
194 // Isolate information on a per-thread basis. This implementation will need to
195 // be re-worked (perhaps using a map keyed on v8::Isolate::GetCurrent()) if
196 // in the future Chromium begins using the same Isolate across multiple threads.
197 class CefV8StateManager {
198 public:
CefV8StateManager()199 CefV8StateManager() {}
200
CreateIsolateManager()201 void CreateIsolateManager() {
202 DCHECK(!current_tls_.Get());
203 current_tls_.Set(new CefV8IsolateManager());
204 }
205
DestroyIsolateManager()206 void DestroyIsolateManager() {
207 DCHECK(current_tls_.Get());
208 delete current_tls_.Get();
209 current_tls_.Set(nullptr);
210 }
211
GetIsolateManager()212 CefV8IsolateManager* GetIsolateManager() {
213 CefV8IsolateManager* manager = current_tls_.Get();
214 DCHECK(manager);
215 return manager;
216 }
217
218 private:
219 base::ThreadLocalPointer<CefV8IsolateManager> current_tls_;
220 };
221
222 base::LazyInstance<CefV8StateManager>::Leaky g_v8_state =
223 LAZY_INSTANCE_INITIALIZER;
224
GetIsolateManager()225 CefV8IsolateManager* GetIsolateManager() {
226 return g_v8_state.Pointer()->GetIsolateManager();
227 }
228
229 class V8TrackObject : public CefTrackNode {
230 public:
V8TrackObject(v8::Isolate * isolate)231 explicit V8TrackObject(v8::Isolate* isolate)
232 : isolate_(isolate), external_memory_(0) {
233 DCHECK(isolate_);
234 isolate_->AdjustAmountOfExternalAllocatedMemory(
235 static_cast<int>(sizeof(V8TrackObject)));
236 }
~V8TrackObject()237 ~V8TrackObject() {
238 isolate_->AdjustAmountOfExternalAllocatedMemory(
239 -static_cast<int>(sizeof(V8TrackObject)) - external_memory_);
240 }
241
GetExternallyAllocatedMemory()242 inline int GetExternallyAllocatedMemory() { return external_memory_; }
243
AdjustExternallyAllocatedMemory(int change_in_bytes)244 int AdjustExternallyAllocatedMemory(int change_in_bytes) {
245 int new_value = external_memory_ + change_in_bytes;
246 if (new_value < 0) {
247 NOTREACHED() << "External memory usage cannot be less than 0 bytes";
248 change_in_bytes = -(external_memory_);
249 new_value = 0;
250 }
251
252 if (change_in_bytes != 0)
253 isolate_->AdjustAmountOfExternalAllocatedMemory(change_in_bytes);
254 external_memory_ = new_value;
255
256 return new_value;
257 }
258
SetAccessor(CefRefPtr<CefV8Accessor> accessor)259 inline void SetAccessor(CefRefPtr<CefV8Accessor> accessor) {
260 accessor_ = accessor;
261 }
262
GetAccessor()263 inline CefRefPtr<CefV8Accessor> GetAccessor() { return accessor_; }
264
SetInterceptor(CefRefPtr<CefV8Interceptor> interceptor)265 inline void SetInterceptor(CefRefPtr<CefV8Interceptor> interceptor) {
266 interceptor_ = interceptor;
267 }
268
GetInterceptor()269 inline CefRefPtr<CefV8Interceptor> GetInterceptor() { return interceptor_; }
270
SetHandler(CefRefPtr<CefV8Handler> handler)271 inline void SetHandler(CefRefPtr<CefV8Handler> handler) {
272 handler_ = handler;
273 }
274
GetHandler()275 inline CefRefPtr<CefV8Handler> GetHandler() { return handler_; }
276
SetUserData(CefRefPtr<CefBaseRefCounted> user_data)277 inline void SetUserData(CefRefPtr<CefBaseRefCounted> user_data) {
278 user_data_ = user_data;
279 }
280
GetUserData()281 inline CefRefPtr<CefBaseRefCounted> GetUserData() { return user_data_; }
282
283 // Attach this track object to the specified V8 object.
AttachTo(v8::Local<v8::Context> context,v8::Local<v8::Object> object)284 void AttachTo(v8::Local<v8::Context> context, v8::Local<v8::Object> object) {
285 SetPrivate(context, object, kCefTrackObject,
286 v8::External::New(isolate_, this));
287 }
288
289 // Retrieve the track object for the specified V8 object.
Unwrap(v8::Local<v8::Context> context,v8::Local<v8::Object> object)290 static V8TrackObject* Unwrap(v8::Local<v8::Context> context,
291 v8::Local<v8::Object> object) {
292 v8::Local<v8::Value> value;
293 if (GetPrivate(context, object, kCefTrackObject, &value))
294 return static_cast<V8TrackObject*>(v8::External::Cast(*value)->Value());
295
296 return nullptr;
297 }
298
299 private:
300 v8::Isolate* isolate_;
301 CefRefPtr<CefV8Accessor> accessor_;
302 CefRefPtr<CefV8Interceptor> interceptor_;
303 CefRefPtr<CefV8Handler> handler_;
304 CefRefPtr<CefBaseRefCounted> user_data_;
305 int external_memory_;
306 };
307
308 class V8TrackString : public CefTrackNode {
309 public:
V8TrackString(const std::string & str)310 explicit V8TrackString(const std::string& str) : string_(str) {}
GetString()311 const char* GetString() { return string_.c_str(); }
312
313 private:
314 std::string string_;
315 };
316
317 class V8TrackArrayBuffer : public CefTrackNode {
318 public:
V8TrackArrayBuffer(v8::Isolate * isolate,CefRefPtr<CefV8ArrayBufferReleaseCallback> release_callback)319 explicit V8TrackArrayBuffer(
320 v8::Isolate* isolate,
321 CefRefPtr<CefV8ArrayBufferReleaseCallback> release_callback)
322 : isolate_(isolate), release_callback_(release_callback) {
323 DCHECK(isolate_);
324 isolate_->AdjustAmountOfExternalAllocatedMemory(
325 static_cast<int>(sizeof(V8TrackArrayBuffer)));
326 }
327
~V8TrackArrayBuffer()328 ~V8TrackArrayBuffer() {
329 isolate_->AdjustAmountOfExternalAllocatedMemory(
330 -static_cast<int>(sizeof(V8TrackArrayBuffer)));
331 }
332
GetReleaseCallback()333 CefRefPtr<CefV8ArrayBufferReleaseCallback> GetReleaseCallback() {
334 return release_callback_;
335 }
336
337 // Attach this track object to the specified V8 object.
AttachTo(v8::Local<v8::Context> context,v8::Local<v8::ArrayBuffer> arrayBuffer)338 void AttachTo(v8::Local<v8::Context> context,
339 v8::Local<v8::ArrayBuffer> arrayBuffer) {
340 SetPrivate(context, arrayBuffer, kCefTrackObject,
341 v8::External::New(isolate_, this));
342 }
343
344 // Retrieve the track object for the specified V8 object.
Unwrap(v8::Local<v8::Context> context,v8::Local<v8::Object> object)345 static V8TrackArrayBuffer* Unwrap(v8::Local<v8::Context> context,
346 v8::Local<v8::Object> object) {
347 v8::Local<v8::Value> value;
348 if (GetPrivate(context, object, kCefTrackObject, &value))
349 return static_cast<V8TrackArrayBuffer*>(
350 v8::External::Cast(*value)->Value());
351
352 return nullptr;
353 }
354
355 private:
356 v8::Isolate* isolate_;
357 CefRefPtr<CefV8ArrayBufferReleaseCallback> release_callback_;
358 };
359
360 // Object wrapped in a v8::External and passed as the Data argument to
361 // v8::FunctionTemplate::New.
362 class V8FunctionData {
363 public:
Create(v8::Isolate * isolate,const CefString & function_name,CefRefPtr<CefV8Handler> handler)364 static v8::Local<v8::External> Create(v8::Isolate* isolate,
365 const CefString& function_name,
366 CefRefPtr<CefV8Handler> handler) {
367 // |data| will be deleted if/when the returned v8::External is GC'd.
368 V8FunctionData* data = new V8FunctionData(isolate, function_name, handler);
369 return data->CreateExternal();
370 }
371
Unwrap(v8::Local<v8::Value> data)372 static V8FunctionData* Unwrap(v8::Local<v8::Value> data) {
373 DCHECK(data->IsExternal());
374 return static_cast<V8FunctionData*>(v8::External::Cast(*data)->Value());
375 }
376
function_name() const377 CefString function_name() const { return function_name_; }
378
handler() const379 CefV8Handler* handler() const {
380 if (!handler_)
381 return nullptr;
382 return handler_.get();
383 }
384
385 private:
V8FunctionData(v8::Isolate * isolate,const CefString & function_name,CefRefPtr<CefV8Handler> handler)386 V8FunctionData(v8::Isolate* isolate,
387 const CefString& function_name,
388 CefRefPtr<CefV8Handler> handler)
389 : isolate_(isolate), function_name_(function_name), handler_(handler) {
390 DCHECK(isolate_);
391 DCHECK(handler_);
392 }
393
~V8FunctionData()394 ~V8FunctionData() {
395 isolate_->AdjustAmountOfExternalAllocatedMemory(
396 -static_cast<int>(sizeof(V8FunctionData)));
397 handler_ = nullptr;
398 function_name_ = "FreedFunction";
399 }
400
CreateExternal()401 v8::Local<v8::External> CreateExternal() {
402 v8::Local<v8::External> external = v8::External::New(isolate_, this);
403
404 isolate_->AdjustAmountOfExternalAllocatedMemory(
405 static_cast<int>(sizeof(V8FunctionData)));
406
407 handle_.Reset(isolate_, external);
408 handle_.SetWeak(this, FirstWeakCallback, v8::WeakCallbackType::kParameter);
409
410 return external;
411 }
412
FirstWeakCallback(const v8::WeakCallbackInfo<V8FunctionData> & data)413 static void FirstWeakCallback(
414 const v8::WeakCallbackInfo<V8FunctionData>& data) {
415 V8FunctionData* wrapper = data.GetParameter();
416 wrapper->handle_.Reset();
417 data.SetSecondPassCallback(SecondWeakCallback);
418 }
419
SecondWeakCallback(const v8::WeakCallbackInfo<V8FunctionData> & data)420 static void SecondWeakCallback(
421 const v8::WeakCallbackInfo<V8FunctionData>& data) {
422 V8FunctionData* wrapper = data.GetParameter();
423 delete wrapper;
424 }
425
426 v8::Isolate* isolate_;
427 CefString function_name_;
428 CefRefPtr<CefV8Handler> handler_;
429 v8::Persistent<v8::External> handle_;
430 };
431
432 // Convert a CefString to a V8::String.
GetV8String(v8::Isolate * isolate,const CefString & str)433 v8::Local<v8::String> GetV8String(v8::Isolate* isolate, const CefString& str) {
434 #if defined(CEF_STRING_TYPE_UTF16)
435 // Already a UTF16 string.
436 return v8::String::NewFromTwoByte(
437 isolate,
438 reinterpret_cast<uint16_t*>(
439 const_cast<CefString::char_type*>(str.c_str())),
440 v8::NewStringType::kNormal, str.length())
441 .ToLocalChecked();
442 #elif defined(CEF_STRING_TYPE_UTF8)
443 // Already a UTF8 string.
444 return v8::String::NewFromUtf8(isolate, const_cast<char*>(str.c_str()),
445 v8::NewStringType::kNormal, str.length())
446 .ToLocalChecked();
447 #else
448 // Convert the string to UTF8.
449 std::string tmpStr = str;
450 return v8::String::NewFromUtf8(isolate, tmpStr.c_str(),
451 v8::NewStringType::kNormal, tmpStr.length())
452 .ToLocalChecked();
453 #endif
454 }
455
456 #if defined(CEF_STRING_TYPE_UTF16)
v8impl_string_dtor(char16 * str)457 void v8impl_string_dtor(char16* str) {
458 delete[] str;
459 }
460 #elif defined(CEF_STRING_TYPE_UTF8)
v8impl_string_dtor(char * str)461 void v8impl_string_dtor(char* str) {
462 delete[] str;
463 }
464 #endif
465
466 // Convert a v8::String to CefString.
GetCefString(v8::Isolate * isolate,v8::Local<v8::String> str,CefString & out)467 void GetCefString(v8::Isolate* isolate,
468 v8::Local<v8::String> str,
469 CefString& out) {
470 if (str.IsEmpty())
471 return;
472
473 #if defined(CEF_STRING_TYPE_WIDE)
474 // Allocate enough space for a worst-case conversion.
475 int len = str->Utf8Length();
476 if (len == 0)
477 return;
478 char* buf = new char[len + 1];
479 str->WriteUtf8(isolate, buf, len + 1);
480
481 // Perform conversion to the wide type.
482 cef_string_t* retws = out.GetWritableStruct();
483 cef_string_utf8_to_wide(buf, len, retws);
484
485 delete[] buf;
486 #else // !defined(CEF_STRING_TYPE_WIDE)
487 #if defined(CEF_STRING_TYPE_UTF16)
488 int len = str->Length();
489 if (len == 0)
490 return;
491 char16* buf = new char16[len + 1];
492 str->Write(isolate, reinterpret_cast<uint16_t*>(buf), 0, len + 1);
493 #else
494 // Allocate enough space for a worst-case conversion.
495 int len = str->Utf8Length();
496 if (len == 0)
497 return;
498 char* buf = new char[len + 1];
499 str->WriteUtf8(isolate, buf, len + 1);
500 #endif
501
502 // Don't perform an extra string copy.
503 out.clear();
504 cef_string_t* retws = out.GetWritableStruct();
505 retws->str = buf;
506 retws->length = len;
507 retws->dtor = v8impl_string_dtor;
508 #endif // !defined(CEF_STRING_TYPE_WIDE)
509 }
510
511 // V8 function callback.
FunctionCallbackImpl(const v8::FunctionCallbackInfo<v8::Value> & info)512 void FunctionCallbackImpl(const v8::FunctionCallbackInfo<v8::Value>& info) {
513 v8::Isolate* isolate = info.GetIsolate();
514 v8::Local<v8::Context> context = isolate->GetCurrentContext();
515
516 V8FunctionData* data = V8FunctionData::Unwrap(info.Data());
517 if (!data->handler()) {
518 // handler has gone away, bail!
519 info.GetReturnValue().SetUndefined();
520 return;
521 }
522 CefV8ValueList params;
523 for (int i = 0; i < info.Length(); i++)
524 params.push_back(new CefV8ValueImpl(isolate, context, info[i]));
525
526 CefRefPtr<CefV8Value> object =
527 new CefV8ValueImpl(isolate, context, info.This());
528 CefRefPtr<CefV8Value> retval;
529 CefString exception;
530
531 if (data->handler()->Execute(data->function_name(), object, params, retval,
532 exception)) {
533 if (!exception.empty()) {
534 info.GetReturnValue().Set(isolate->ThrowException(
535 v8::Exception::Error(GetV8String(isolate, exception))));
536 return;
537 } else {
538 CefV8ValueImpl* rv = static_cast<CefV8ValueImpl*>(retval.get());
539 if (rv && rv->IsValid()) {
540 info.GetReturnValue().Set(rv->GetV8Value(true));
541 return;
542 }
543 }
544 }
545
546 info.GetReturnValue().SetUndefined();
547 }
548
549 // V8 Accessor callbacks
AccessorNameGetterCallbackImpl(v8::Local<v8::Name> property,const v8::PropertyCallbackInfo<v8::Value> & info)550 void AccessorNameGetterCallbackImpl(
551 v8::Local<v8::Name> property,
552 const v8::PropertyCallbackInfo<v8::Value>& info) {
553 v8::Isolate* isolate = info.GetIsolate();
554 v8::Local<v8::Context> context = isolate->GetCurrentContext();
555
556 v8::Local<v8::Object> obj = info.This();
557
558 CefRefPtr<CefV8Accessor> accessorPtr;
559
560 V8TrackObject* tracker = V8TrackObject::Unwrap(context, obj);
561 if (tracker)
562 accessorPtr = tracker->GetAccessor();
563
564 if (accessorPtr.get()) {
565 CefRefPtr<CefV8Value> retval;
566 CefRefPtr<CefV8Value> object = new CefV8ValueImpl(isolate, context, obj);
567 CefString name, exception;
568 GetCefString(isolate, v8::Local<v8::String>::Cast(property), name);
569 if (accessorPtr->Get(name, object, retval, exception)) {
570 if (!exception.empty()) {
571 info.GetReturnValue().Set(isolate->ThrowException(
572 v8::Exception::Error(GetV8String(isolate, exception))));
573 return;
574 } else {
575 CefV8ValueImpl* rv = static_cast<CefV8ValueImpl*>(retval.get());
576 if (rv && rv->IsValid()) {
577 info.GetReturnValue().Set(rv->GetV8Value(true));
578 return;
579 }
580 }
581 }
582 }
583
584 return info.GetReturnValue().SetUndefined();
585 }
586
AccessorNameSetterCallbackImpl(v8::Local<v8::Name> property,v8::Local<v8::Value> value,const v8::PropertyCallbackInfo<void> & info)587 void AccessorNameSetterCallbackImpl(
588 v8::Local<v8::Name> property,
589 v8::Local<v8::Value> value,
590 const v8::PropertyCallbackInfo<void>& info) {
591 v8::Isolate* isolate = info.GetIsolate();
592 v8::Local<v8::Context> context = isolate->GetCurrentContext();
593
594 v8::Local<v8::Object> obj = info.This();
595
596 CefRefPtr<CefV8Accessor> accessorPtr;
597
598 V8TrackObject* tracker = V8TrackObject::Unwrap(context, obj);
599 if (tracker)
600 accessorPtr = tracker->GetAccessor();
601
602 if (accessorPtr.get()) {
603 CefRefPtr<CefV8Value> object = new CefV8ValueImpl(isolate, context, obj);
604 CefRefPtr<CefV8Value> cefValue =
605 new CefV8ValueImpl(isolate, context, value);
606 CefString name, exception;
607 GetCefString(isolate, v8::Local<v8::String>::Cast(property), name);
608 accessorPtr->Set(name, object, cefValue, exception);
609 if (!exception.empty()) {
610 isolate->ThrowException(
611 v8::Exception::Error(GetV8String(isolate, exception)));
612 return;
613 }
614 }
615 }
616
617 // Two helper functions for V8 Interceptor callbacks.
PropertyToIndex(v8::Isolate * isolate,v8::Local<v8::Name> property)618 CefString PropertyToIndex(v8::Isolate* isolate, v8::Local<v8::Name> property) {
619 CefString name;
620 GetCefString(isolate, property.As<v8::String>(), name);
621 return name;
622 }
623
PropertyToIndex(v8::Isolate * isolate,uint32_t index)624 int PropertyToIndex(v8::Isolate* isolate, uint32_t index) {
625 return static_cast<int>(index);
626 }
627
628 // V8 Interceptor callbacks.
629 // T == v8::Local<v8::Name> for named property handlers and
630 // T == uint32_t for indexed property handlers
631 template <typename T>
InterceptorGetterCallbackImpl(T property,const v8::PropertyCallbackInfo<v8::Value> & info)632 void InterceptorGetterCallbackImpl(
633 T property,
634 const v8::PropertyCallbackInfo<v8::Value>& info) {
635 v8::Isolate* isolate = info.GetIsolate();
636 v8::Local<v8::Context> context = isolate->GetCurrentContext();
637
638 v8::Handle<v8::Object> obj = info.This();
639 CefRefPtr<CefV8Interceptor> interceptorPtr;
640
641 V8TrackObject* tracker = V8TrackObject::Unwrap(context, obj);
642 if (tracker)
643 interceptorPtr = tracker->GetInterceptor();
644 if (!interceptorPtr.get())
645 return;
646
647 CefRefPtr<CefV8Value> object = new CefV8ValueImpl(isolate, context, obj);
648 CefRefPtr<CefV8Value> retval;
649 CefString exception;
650 interceptorPtr->Get(PropertyToIndex(isolate, property), object, retval,
651 exception);
652 if (!exception.empty()) {
653 info.GetReturnValue().Set(isolate->ThrowException(
654 v8::Exception::Error(GetV8String(isolate, exception))));
655 } else {
656 CefV8ValueImpl* retval_impl = static_cast<CefV8ValueImpl*>(retval.get());
657 if (retval_impl && retval_impl->IsValid()) {
658 info.GetReturnValue().Set(retval_impl->GetV8Value(true));
659 }
660 }
661 }
662
663 template <typename T>
InterceptorSetterCallbackImpl(T property,v8::Local<v8::Value> value,const v8::PropertyCallbackInfo<v8::Value> & info)664 void InterceptorSetterCallbackImpl(
665 T property,
666 v8::Local<v8::Value> value,
667 const v8::PropertyCallbackInfo<v8::Value>& info) {
668 v8::Isolate* isolate = info.GetIsolate();
669 v8::Local<v8::Context> context = isolate->GetCurrentContext();
670 v8::Handle<v8::Object> obj = info.This();
671 CefRefPtr<CefV8Interceptor> interceptorPtr;
672
673 V8TrackObject* tracker = V8TrackObject::Unwrap(context, obj);
674 if (tracker)
675 interceptorPtr = tracker->GetInterceptor();
676
677 if (!interceptorPtr.get())
678 return;
679 CefRefPtr<CefV8Value> object = new CefV8ValueImpl(isolate, context, obj);
680 CefRefPtr<CefV8Value> cefValue = new CefV8ValueImpl(isolate, context, value);
681 CefString exception;
682 interceptorPtr->Set(PropertyToIndex(isolate, property), object, cefValue,
683 exception);
684 if (!exception.empty()) {
685 isolate->ThrowException(
686 v8::Exception::Error(GetV8String(isolate, exception)));
687 }
688 }
689
690 // V8 extension registration.
691
692 class ExtensionWrapper : public v8::Extension {
693 public:
ExtensionWrapper(const char * extension_name,const char * javascript_code,CefV8Handler * handler)694 ExtensionWrapper(const char* extension_name,
695 const char* javascript_code,
696 CefV8Handler* handler)
697 : v8::Extension(extension_name, javascript_code), handler_(handler) {}
698
GetNativeFunctionTemplate(v8::Isolate * isolate,v8::Handle<v8::String> name)699 v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate(
700 v8::Isolate* isolate,
701 v8::Handle<v8::String> name) override {
702 if (!handler_)
703 return v8::Local<v8::FunctionTemplate>();
704
705 CefString func_name;
706 GetCefString(isolate, name, func_name);
707
708 v8::Local<v8::External> function_data =
709 V8FunctionData::Create(isolate, func_name, handler_);
710
711 return v8::FunctionTemplate::New(isolate, FunctionCallbackImpl,
712 function_data);
713 }
714
715 private:
716 CefV8Handler* handler_;
717 };
718
719 class CefV8ExceptionImpl : public CefV8Exception {
720 public:
CefV8ExceptionImpl(v8::Local<v8::Context> context,v8::Local<v8::Message> message)721 CefV8ExceptionImpl(v8::Local<v8::Context> context,
722 v8::Local<v8::Message> message)
723 : line_number_(0),
724 start_position_(0),
725 end_position_(0),
726 start_column_(0),
727 end_column_(0) {
728 if (message.IsEmpty())
729 return;
730
731 v8::Isolate* isolate = context->GetIsolate();
732 GetCefString(isolate, message->Get(), message_);
733 v8::MaybeLocal<v8::String> source_line = message->GetSourceLine(context);
734 if (!source_line.IsEmpty())
735 GetCefString(isolate, source_line.ToLocalChecked(), source_line_);
736
737 if (!message->GetScriptResourceName().IsEmpty()) {
738 GetCefString(
739 isolate,
740 message->GetScriptResourceName()->ToString(context).ToLocalChecked(),
741 script_);
742 }
743
744 v8::Maybe<int> line_number = message->GetLineNumber(context);
745 if (!line_number.IsNothing())
746 line_number_ = line_number.ToChecked();
747 start_position_ = message->GetStartPosition();
748 end_position_ = message->GetEndPosition();
749 start_column_ = message->GetStartColumn(context).FromJust();
750 end_column_ = message->GetEndColumn(context).FromJust();
751 }
752
GetMessage()753 CefString GetMessage() override { return message_; }
GetSourceLine()754 CefString GetSourceLine() override { return source_line_; }
GetScriptResourceName()755 CefString GetScriptResourceName() override { return script_; }
GetLineNumber()756 int GetLineNumber() override { return line_number_; }
GetStartPosition()757 int GetStartPosition() override { return start_position_; }
GetEndPosition()758 int GetEndPosition() override { return end_position_; }
GetStartColumn()759 int GetStartColumn() override { return start_column_; }
GetEndColumn()760 int GetEndColumn() override { return end_column_; }
761
762 protected:
763 CefString message_;
764 CefString source_line_;
765 CefString script_;
766 int line_number_;
767 int start_position_;
768 int end_position_;
769 int start_column_;
770 int end_column_;
771
772 IMPLEMENT_REFCOUNTING(CefV8ExceptionImpl);
773 };
774
MessageListenerCallbackImpl(v8::Handle<v8::Message> message,v8::Handle<v8::Value> data)775 void MessageListenerCallbackImpl(v8::Handle<v8::Message> message,
776 v8::Handle<v8::Value> data) {
777 CefRefPtr<CefApp> application = CefAppManager::Get()->GetApplication();
778 if (!application.get())
779 return;
780
781 CefRefPtr<CefRenderProcessHandler> handler =
782 application->GetRenderProcessHandler();
783 if (!handler.get())
784 return;
785
786 v8::Isolate* isolate = GetIsolateManager()->isolate();
787 CefRefPtr<CefV8Context> context = CefV8Context::GetCurrentContext();
788 v8::Local<v8::StackTrace> v8Stack = message->GetStackTrace();
789 CefRefPtr<CefV8StackTrace> stackTrace =
790 new CefV8StackTraceImpl(isolate, v8Stack);
791
792 CefRefPtr<CefV8Exception> exception = new CefV8ExceptionImpl(
793 static_cast<CefV8ContextImpl*>(context.get())->GetV8Context(), message);
794
795 CefRefPtr<CefBrowser> browser = context->GetBrowser();
796 if (browser) {
797 handler->OnUncaughtException(browser, context->GetFrame(), context,
798 exception, stackTrace);
799 }
800 }
801
802 } // namespace
803
804 // Global functions.
805
CefV8IsolateCreated()806 void CefV8IsolateCreated() {
807 g_v8_state.Pointer()->CreateIsolateManager();
808 }
809
CefV8IsolateDestroyed()810 void CefV8IsolateDestroyed() {
811 g_v8_state.Pointer()->DestroyIsolateManager();
812 }
813
CefV8ReleaseContext(v8::Local<v8::Context> context)814 void CefV8ReleaseContext(v8::Local<v8::Context> context) {
815 GetIsolateManager()->ReleaseContext(context);
816 }
817
CefV8SetUncaughtExceptionStackSize(int stack_size)818 void CefV8SetUncaughtExceptionStackSize(int stack_size) {
819 GetIsolateManager()->SetUncaughtExceptionStackSize(stack_size);
820 }
821
CefV8SetWorkerAttributes(int worker_id,const GURL & worker_url)822 void CefV8SetWorkerAttributes(int worker_id, const GURL& worker_url) {
823 GetIsolateManager()->SetWorkerAttributes(worker_id, worker_url);
824 }
825
CefRegisterExtension(const CefString & extension_name,const CefString & javascript_code,CefRefPtr<CefV8Handler> handler)826 bool CefRegisterExtension(const CefString& extension_name,
827 const CefString& javascript_code,
828 CefRefPtr<CefV8Handler> handler) {
829 // Verify that this method was called on the correct thread.
830 CEF_REQUIRE_RT_RETURN(false);
831
832 CefV8IsolateManager* isolate_manager = GetIsolateManager();
833
834 V8TrackString* name = new V8TrackString(extension_name);
835 isolate_manager->AddGlobalTrackObject(name);
836 V8TrackString* code = new V8TrackString(javascript_code);
837 isolate_manager->AddGlobalTrackObject(code);
838
839 if (handler.get()) {
840 // The reference will be released when the process exits.
841 V8TrackObject* object = new V8TrackObject(isolate_manager->isolate());
842 object->SetHandler(handler);
843 isolate_manager->AddGlobalTrackObject(object);
844 }
845
846 std::unique_ptr<v8::Extension> wrapper(new ExtensionWrapper(
847 name->GetString(), code->GetString(), handler.get()));
848
849 content::RenderThread::Get()->RegisterExtension(std::move(wrapper));
850 return true;
851 }
852
853 // Helper macros
854
855 #define CEF_V8_HAS_ISOLATE() (!!GetIsolateManager())
856 #define CEF_V8_REQUIRE_ISOLATE_RETURN(var) \
857 if (!CEF_V8_HAS_ISOLATE()) { \
858 NOTREACHED() << "V8 isolate is not valid"; \
859 return var; \
860 }
861
862 #define CEF_V8_CURRENTLY_ON_MLT() \
863 (!handle_.get() || handle_->BelongsToCurrentThread())
864 #define CEF_V8_REQUIRE_MLT_RETURN(var) \
865 CEF_V8_REQUIRE_ISOLATE_RETURN(var); \
866 if (!CEF_V8_CURRENTLY_ON_MLT()) { \
867 NOTREACHED() << "called on incorrect thread"; \
868 return var; \
869 }
870
871 #define CEF_V8_HANDLE_IS_VALID() (handle_.get() && handle_->IsValid())
872 #define CEF_V8_REQUIRE_VALID_HANDLE_RETURN(ret) \
873 CEF_V8_REQUIRE_MLT_RETURN(ret); \
874 if (!CEF_V8_HANDLE_IS_VALID()) { \
875 NOTREACHED() << "V8 handle is not valid"; \
876 return ret; \
877 }
878
879 #define CEF_V8_IS_VALID() \
880 (CEF_V8_HAS_ISOLATE() && CEF_V8_CURRENTLY_ON_MLT() && \
881 CEF_V8_HANDLE_IS_VALID())
882
883 #define CEF_V8_REQUIRE_OBJECT_RETURN(ret) \
884 CEF_V8_REQUIRE_VALID_HANDLE_RETURN(ret); \
885 if (type_ != TYPE_OBJECT) { \
886 NOTREACHED() << "V8 value is not an object"; \
887 return ret; \
888 }
889
890 // CefV8HandleBase
891
~CefV8HandleBase()892 CefV8HandleBase::~CefV8HandleBase() {
893 DCHECK(BelongsToCurrentThread());
894 }
895
BelongsToCurrentThread() const896 bool CefV8HandleBase::BelongsToCurrentThread() const {
897 return task_runner_->RunsTasksInCurrentSequence();
898 }
899
CefV8HandleBase(v8::Isolate * isolate,v8::Local<v8::Context> context)900 CefV8HandleBase::CefV8HandleBase(v8::Isolate* isolate,
901 v8::Local<v8::Context> context)
902 : isolate_(isolate) {
903 DCHECK(isolate_);
904
905 CefV8IsolateManager* manager = GetIsolateManager();
906 DCHECK(manager);
907 DCHECK_EQ(isolate_, manager->isolate());
908
909 task_runner_ = manager->task_runner();
910 context_state_ = manager->GetContextState(context);
911 }
912
913 // CefV8Context
914
915 // static
GetCurrentContext()916 CefRefPtr<CefV8Context> CefV8Context::GetCurrentContext() {
917 CefRefPtr<CefV8Context> context;
918 CEF_V8_REQUIRE_ISOLATE_RETURN(context);
919 v8::Isolate* isolate = GetIsolateManager()->isolate();
920 if (isolate->InContext()) {
921 v8::HandleScope handle_scope(isolate);
922 context = new CefV8ContextImpl(isolate, isolate->GetCurrentContext());
923 }
924 return context;
925 }
926
927 // static
GetEnteredContext()928 CefRefPtr<CefV8Context> CefV8Context::GetEnteredContext() {
929 CefRefPtr<CefV8Context> context;
930 CEF_V8_REQUIRE_ISOLATE_RETURN(context);
931 v8::Isolate* isolate = GetIsolateManager()->isolate();
932 if (isolate->InContext()) {
933 v8::HandleScope handle_scope(isolate);
934 context =
935 new CefV8ContextImpl(isolate, isolate->GetEnteredOrMicrotaskContext());
936 }
937 return context;
938 }
939
940 // static
InContext()941 bool CefV8Context::InContext() {
942 CEF_V8_REQUIRE_ISOLATE_RETURN(false);
943 v8::Isolate* isolate = GetIsolateManager()->isolate();
944 return isolate->InContext();
945 }
946
947 // CefV8ContextImpl
948
CefV8ContextImpl(v8::Isolate * isolate,v8::Local<v8::Context> context)949 CefV8ContextImpl::CefV8ContextImpl(v8::Isolate* isolate,
950 v8::Local<v8::Context> context)
951 : handle_(new Handle(isolate, context, context)), enter_count_(0) {}
952
~CefV8ContextImpl()953 CefV8ContextImpl::~CefV8ContextImpl() {
954 DLOG_ASSERT(0 == enter_count_);
955 }
956
GetTaskRunner()957 CefRefPtr<CefTaskRunner> CefV8ContextImpl::GetTaskRunner() {
958 return new CefTaskRunnerImpl(handle_->task_runner());
959 }
960
IsValid()961 bool CefV8ContextImpl::IsValid() {
962 return CEF_V8_IS_VALID();
963 }
964
GetBrowser()965 CefRefPtr<CefBrowser> CefV8ContextImpl::GetBrowser() {
966 CefRefPtr<CefBrowser> browser;
967 CEF_V8_REQUIRE_VALID_HANDLE_RETURN(browser);
968
969 blink::WebLocalFrame* webframe = GetWebFrame();
970 if (webframe)
971 browser = CefBrowserImpl::GetBrowserForMainFrame(webframe->Top());
972
973 return browser;
974 }
975
GetFrame()976 CefRefPtr<CefFrame> CefV8ContextImpl::GetFrame() {
977 CefRefPtr<CefFrame> frame;
978 CEF_V8_REQUIRE_VALID_HANDLE_RETURN(frame);
979
980 blink::WebLocalFrame* webframe = GetWebFrame();
981 if (webframe) {
982 CefRefPtr<CefBrowserImpl> browser =
983 CefBrowserImpl::GetBrowserForMainFrame(webframe->Top());
984 if (browser) {
985 frame = browser->GetFrame(render_frame_util::GetIdentifier(webframe));
986 }
987 }
988
989 return frame;
990 }
991
GetGlobal()992 CefRefPtr<CefV8Value> CefV8ContextImpl::GetGlobal() {
993 CEF_V8_REQUIRE_VALID_HANDLE_RETURN(nullptr);
994
995 if (blink_glue::IsScriptForbidden())
996 return nullptr;
997
998 v8::Isolate* isolate = handle_->isolate();
999 v8::HandleScope handle_scope(isolate);
1000 v8::Local<v8::Context> context = GetV8Context();
1001 v8::Context::Scope context_scope(context);
1002 return new CefV8ValueImpl(isolate, context, context->Global());
1003 }
1004
Enter()1005 bool CefV8ContextImpl::Enter() {
1006 CEF_V8_REQUIRE_VALID_HANDLE_RETURN(false);
1007
1008 if (blink_glue::IsScriptForbidden())
1009 return false;
1010
1011 v8::Isolate* isolate = handle_->isolate();
1012 v8::HandleScope handle_scope(isolate);
1013
1014 if (!microtasks_scope_) {
1015 // Increment the MicrotasksScope recursion level.
1016 microtasks_scope_.reset(
1017 new v8::MicrotasksScope(isolate, v8::MicrotasksScope::kRunMicrotasks));
1018 }
1019
1020 ++enter_count_;
1021 handle_->GetNewV8Handle()->Enter();
1022
1023 return true;
1024 }
1025
Exit()1026 bool CefV8ContextImpl::Exit() {
1027 CEF_V8_REQUIRE_VALID_HANDLE_RETURN(false);
1028
1029 if (blink_glue::IsScriptForbidden())
1030 return false;
1031
1032 if (enter_count_ <= 0) {
1033 LOG(ERROR) << "Call to CefV8Context::Exit() without matching call to "
1034 "CefV8Context::Enter()";
1035 return false;
1036 }
1037
1038 v8::HandleScope handle_scope(handle_->isolate());
1039
1040 handle_->GetNewV8Handle()->Exit();
1041
1042 if (--enter_count_ == 0) {
1043 // Decrement the MicrotasksScope recursion level.
1044 microtasks_scope_.reset(nullptr);
1045 }
1046
1047 return true;
1048 }
1049
IsSame(CefRefPtr<CefV8Context> that)1050 bool CefV8ContextImpl::IsSame(CefRefPtr<CefV8Context> that) {
1051 CEF_V8_REQUIRE_VALID_HANDLE_RETURN(false);
1052
1053 CefV8ContextImpl* impl = static_cast<CefV8ContextImpl*>(that.get());
1054 if (!impl || !impl->IsValid())
1055 return false;
1056
1057 return (handle_->GetPersistentV8Handle() ==
1058 impl->handle_->GetPersistentV8Handle());
1059 }
1060
Eval(const CefString & code,const CefString & script_url,int start_line,CefRefPtr<CefV8Value> & retval,CefRefPtr<CefV8Exception> & exception)1061 bool CefV8ContextImpl::Eval(const CefString& code,
1062 const CefString& script_url,
1063 int start_line,
1064 CefRefPtr<CefV8Value>& retval,
1065 CefRefPtr<CefV8Exception>& exception) {
1066 retval = nullptr;
1067 exception = nullptr;
1068
1069 CEF_V8_REQUIRE_VALID_HANDLE_RETURN(false);
1070
1071 if (blink_glue::IsScriptForbidden())
1072 return false;
1073
1074 if (code.empty()) {
1075 NOTREACHED() << "invalid input parameter";
1076 return false;
1077 }
1078
1079 v8::Isolate* isolate = handle_->isolate();
1080 v8::HandleScope handle_scope(isolate);
1081 v8::Local<v8::Context> context = GetV8Context();
1082 v8::Context::Scope context_scope(context);
1083
1084 const blink::WebString& source =
1085 blink::WebString::FromUTF16(code.ToString16());
1086 const blink::WebString& source_url =
1087 blink::WebString::FromUTF16(script_url.ToString16());
1088
1089 v8::TryCatch try_catch(isolate);
1090 try_catch.SetVerbose(true);
1091
1092 v8::Local<v8::Value> func_rv = blink_glue::ExecuteV8ScriptAndReturnValue(
1093 source, source_url, start_line, context, try_catch);
1094
1095 if (try_catch.HasCaught()) {
1096 exception = new CefV8ExceptionImpl(context, try_catch.Message());
1097 return false;
1098 } else if (!func_rv.IsEmpty()) {
1099 retval = new CefV8ValueImpl(isolate, context, func_rv);
1100 return true;
1101 }
1102
1103 NOTREACHED();
1104 return false;
1105 }
1106
GetV8Context()1107 v8::Local<v8::Context> CefV8ContextImpl::GetV8Context() {
1108 return handle_->GetNewV8Handle();
1109 }
1110
GetWebFrame()1111 blink::WebLocalFrame* CefV8ContextImpl::GetWebFrame() {
1112 CEF_REQUIRE_RT();
1113
1114 if (blink_glue::IsScriptForbidden())
1115 return nullptr;
1116
1117 v8::HandleScope handle_scope(handle_->isolate());
1118 v8::Local<v8::Context> context = GetV8Context();
1119 v8::Context::Scope context_scope(context);
1120 return blink::WebLocalFrame::FrameForContext(context);
1121 }
1122
1123 // CefV8ValueImpl::Handle
1124
Handle(v8::Isolate * isolate,v8::Local<v8::Context> context,handleType v,CefTrackNode * tracker)1125 CefV8ValueImpl::Handle::Handle(v8::Isolate* isolate,
1126 v8::Local<v8::Context> context,
1127 handleType v,
1128 CefTrackNode* tracker)
1129 : CefV8HandleBase(isolate, context),
1130 handle_(isolate, v),
1131 tracker_(tracker),
1132 should_persist_(false),
1133 is_set_weak_(false) {}
1134
~Handle()1135 CefV8ValueImpl::Handle::~Handle() {
1136 DCHECK(BelongsToCurrentThread());
1137
1138 if (tracker_) {
1139 if (is_set_weak_) {
1140 if (context_state_.get()) {
1141 // If the associated context is still valid then delete |tracker_|.
1142 // Otherwise, |tracker_| will already have been deleted.
1143 if (context_state_->IsValid())
1144 context_state_->DeleteTrackObject(tracker_);
1145 } else {
1146 GetIsolateManager()->DeleteGlobalTrackObject(tracker_);
1147 }
1148 } else {
1149 delete tracker_;
1150 }
1151 }
1152
1153 if (is_set_weak_) {
1154 isolate_->AdjustAmountOfExternalAllocatedMemory(
1155 -static_cast<int>(sizeof(Handle)));
1156 } else {
1157 // SetWeak was not called so reset now.
1158 handle_.Reset();
1159 }
1160 }
1161
GetNewV8Handle(bool should_persist)1162 CefV8ValueImpl::Handle::handleType CefV8ValueImpl::Handle::GetNewV8Handle(
1163 bool should_persist) {
1164 DCHECK(IsValid());
1165 if (should_persist && !should_persist_)
1166 should_persist_ = true;
1167 return handleType::New(isolate(), handle_);
1168 }
1169
1170 CefV8ValueImpl::Handle::persistentType&
GetPersistentV8Handle()1171 CefV8ValueImpl::Handle::GetPersistentV8Handle() {
1172 return handle_;
1173 }
1174
SetWeakIfNecessary()1175 void CefV8ValueImpl::Handle::SetWeakIfNecessary() {
1176 if (!BelongsToCurrentThread()) {
1177 task_runner()->PostTask(
1178 FROM_HERE,
1179 base::BindOnce(&CefV8ValueImpl::Handle::SetWeakIfNecessary, this));
1180 return;
1181 }
1182
1183 // Persist the handle (call SetWeak) if:
1184 // A. The handle has been passed into a V8 function or used as a return value
1185 // from a V8 callback, and
1186 // B. The associated context, if any, is still valid.
1187 if (should_persist_ && (!context_state_.get() || context_state_->IsValid())) {
1188 is_set_weak_ = true;
1189
1190 if (tracker_) {
1191 if (context_state_.get()) {
1192 // |tracker_| will be deleted when:
1193 // A. The associated context is released, or
1194 // B. SecondWeakCallback is called for the weak handle.
1195 DCHECK(context_state_->IsValid());
1196 context_state_->AddTrackObject(tracker_);
1197 } else {
1198 // |tracker_| will be deleted when:
1199 // A. The process shuts down, or
1200 // B. SecondWeakCallback is called for the weak handle.
1201 GetIsolateManager()->AddGlobalTrackObject(tracker_);
1202 }
1203 }
1204
1205 isolate_->AdjustAmountOfExternalAllocatedMemory(
1206 static_cast<int>(sizeof(Handle)));
1207
1208 // The added reference will be released in SecondWeakCallback.
1209 AddRef();
1210 handle_.SetWeak(this, FirstWeakCallback, v8::WeakCallbackType::kParameter);
1211 }
1212 }
1213
1214 // static
FirstWeakCallback(const v8::WeakCallbackInfo<Handle> & data)1215 void CefV8ValueImpl::Handle::FirstWeakCallback(
1216 const v8::WeakCallbackInfo<Handle>& data) {
1217 Handle* wrapper = data.GetParameter();
1218 wrapper->handle_.Reset();
1219 data.SetSecondPassCallback(SecondWeakCallback);
1220 }
1221
1222 // static
SecondWeakCallback(const v8::WeakCallbackInfo<Handle> & data)1223 void CefV8ValueImpl::Handle::SecondWeakCallback(
1224 const v8::WeakCallbackInfo<Handle>& data) {
1225 Handle* wrapper = data.GetParameter();
1226 wrapper->Release();
1227 }
1228
1229 // CefV8Value
1230
1231 // static
CreateUndefined()1232 CefRefPtr<CefV8Value> CefV8Value::CreateUndefined() {
1233 CEF_V8_REQUIRE_ISOLATE_RETURN(nullptr);
1234 v8::Isolate* isolate = GetIsolateManager()->isolate();
1235 CefRefPtr<CefV8ValueImpl> impl = new CefV8ValueImpl(isolate);
1236 impl->InitUndefined();
1237 return impl.get();
1238 }
1239
1240 // static
CreateNull()1241 CefRefPtr<CefV8Value> CefV8Value::CreateNull() {
1242 CEF_V8_REQUIRE_ISOLATE_RETURN(nullptr);
1243 v8::Isolate* isolate = GetIsolateManager()->isolate();
1244 CefRefPtr<CefV8ValueImpl> impl = new CefV8ValueImpl(isolate);
1245 impl->InitNull();
1246 return impl.get();
1247 }
1248
1249 // static
CreateBool(bool value)1250 CefRefPtr<CefV8Value> CefV8Value::CreateBool(bool value) {
1251 CEF_V8_REQUIRE_ISOLATE_RETURN(nullptr);
1252 v8::Isolate* isolate = GetIsolateManager()->isolate();
1253 CefRefPtr<CefV8ValueImpl> impl = new CefV8ValueImpl(isolate);
1254 impl->InitBool(value);
1255 return impl.get();
1256 }
1257
1258 // static
CreateInt(int32 value)1259 CefRefPtr<CefV8Value> CefV8Value::CreateInt(int32 value) {
1260 CEF_V8_REQUIRE_ISOLATE_RETURN(nullptr);
1261 v8::Isolate* isolate = GetIsolateManager()->isolate();
1262 CefRefPtr<CefV8ValueImpl> impl = new CefV8ValueImpl(isolate);
1263 impl->InitInt(value);
1264 return impl.get();
1265 }
1266
1267 // static
CreateUInt(uint32 value)1268 CefRefPtr<CefV8Value> CefV8Value::CreateUInt(uint32 value) {
1269 CEF_V8_REQUIRE_ISOLATE_RETURN(nullptr);
1270 v8::Isolate* isolate = GetIsolateManager()->isolate();
1271 CefRefPtr<CefV8ValueImpl> impl = new CefV8ValueImpl(isolate);
1272 impl->InitUInt(value);
1273 return impl.get();
1274 }
1275
1276 // static
CreateDouble(double value)1277 CefRefPtr<CefV8Value> CefV8Value::CreateDouble(double value) {
1278 CEF_V8_REQUIRE_ISOLATE_RETURN(nullptr);
1279 v8::Isolate* isolate = GetIsolateManager()->isolate();
1280 CefRefPtr<CefV8ValueImpl> impl = new CefV8ValueImpl(isolate);
1281 impl->InitDouble(value);
1282 return impl.get();
1283 }
1284
1285 // static
CreateDate(const CefTime & value)1286 CefRefPtr<CefV8Value> CefV8Value::CreateDate(const CefTime& value) {
1287 CEF_V8_REQUIRE_ISOLATE_RETURN(nullptr);
1288 v8::Isolate* isolate = GetIsolateManager()->isolate();
1289 CefRefPtr<CefV8ValueImpl> impl = new CefV8ValueImpl(isolate);
1290 impl->InitDate(value);
1291 return impl.get();
1292 }
1293
1294 // static
CreateString(const CefString & value)1295 CefRefPtr<CefV8Value> CefV8Value::CreateString(const CefString& value) {
1296 CEF_V8_REQUIRE_ISOLATE_RETURN(nullptr);
1297 v8::Isolate* isolate = GetIsolateManager()->isolate();
1298 CefRefPtr<CefV8ValueImpl> impl = new CefV8ValueImpl(isolate);
1299 CefString str(value);
1300 impl->InitString(str);
1301 return impl.get();
1302 }
1303
1304 // static
CreateObject(CefRefPtr<CefV8Accessor> accessor,CefRefPtr<CefV8Interceptor> interceptor)1305 CefRefPtr<CefV8Value> CefV8Value::CreateObject(
1306 CefRefPtr<CefV8Accessor> accessor,
1307 CefRefPtr<CefV8Interceptor> interceptor) {
1308 CEF_V8_REQUIRE_ISOLATE_RETURN(nullptr);
1309
1310 v8::Isolate* isolate = GetIsolateManager()->isolate();
1311 v8::HandleScope handle_scope(isolate);
1312
1313 v8::Local<v8::Context> context = isolate->GetCurrentContext();
1314 if (context.IsEmpty()) {
1315 NOTREACHED() << "not currently in a V8 context";
1316 return nullptr;
1317 }
1318
1319 // Create the new V8 object. If an interceptor is passed, create object from
1320 // template and set property handlers.
1321 v8::Local<v8::Object> obj;
1322 if (interceptor.get()) {
1323 v8::Local<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New(isolate);
1324 tmpl->SetHandler(v8::NamedPropertyHandlerConfiguration(
1325 InterceptorGetterCallbackImpl<v8::Local<v8::Name>>,
1326 InterceptorSetterCallbackImpl<v8::Local<v8::Name>>, nullptr, nullptr,
1327 nullptr, v8::Local<v8::Value>(),
1328 v8::PropertyHandlerFlags::kOnlyInterceptStrings));
1329
1330 tmpl->SetIndexedPropertyHandler(InterceptorGetterCallbackImpl<uint32_t>,
1331 InterceptorSetterCallbackImpl<uint32_t>);
1332
1333 v8::MaybeLocal<v8::Object> maybe_object = tmpl->NewInstance(context);
1334 if (!maybe_object.ToLocal<v8::Object>(&obj)) {
1335 NOTREACHED() << "Failed to create V8 Object with interceptor";
1336 return nullptr;
1337 }
1338 } else {
1339 obj = v8::Object::New(isolate);
1340 }
1341
1342 // Create a tracker object that will cause the user data and/or accessor
1343 // and/or interceptor reference to be released when the V8 object is
1344 // destroyed.
1345 V8TrackObject* tracker = new V8TrackObject(isolate);
1346 tracker->SetAccessor(accessor);
1347 tracker->SetInterceptor(interceptor);
1348
1349 // Attach the tracker object.
1350 tracker->AttachTo(context, obj);
1351
1352 CefRefPtr<CefV8ValueImpl> impl = new CefV8ValueImpl(isolate);
1353 impl->InitObject(obj, tracker);
1354 return impl.get();
1355 }
1356
1357 // static
CreateArray(int length)1358 CefRefPtr<CefV8Value> CefV8Value::CreateArray(int length) {
1359 CEF_V8_REQUIRE_ISOLATE_RETURN(nullptr);
1360
1361 v8::Isolate* isolate = GetIsolateManager()->isolate();
1362 v8::HandleScope handle_scope(isolate);
1363
1364 v8::Local<v8::Context> context = isolate->GetCurrentContext();
1365 if (context.IsEmpty()) {
1366 NOTREACHED() << "not currently in a V8 context";
1367 return nullptr;
1368 }
1369
1370 // Create a tracker object that will cause the user data reference to be
1371 // released when the V8 object is destroyed.
1372 V8TrackObject* tracker = new V8TrackObject(isolate);
1373
1374 // Create the new V8 array.
1375 v8::Local<v8::Array> arr = v8::Array::New(isolate, length);
1376
1377 // Attach the tracker object.
1378 tracker->AttachTo(context, arr);
1379
1380 CefRefPtr<CefV8ValueImpl> impl = new CefV8ValueImpl(isolate);
1381 impl->InitObject(arr, tracker);
1382 return impl.get();
1383 }
1384
1385 // static
CreateArrayBuffer(void * buffer,size_t length,CefRefPtr<CefV8ArrayBufferReleaseCallback> release_callback)1386 CefRefPtr<CefV8Value> CefV8Value::CreateArrayBuffer(
1387 void* buffer,
1388 size_t length,
1389 CefRefPtr<CefV8ArrayBufferReleaseCallback> release_callback) {
1390 CEF_V8_REQUIRE_ISOLATE_RETURN(nullptr);
1391
1392 v8::Isolate* isolate = GetIsolateManager()->isolate();
1393 v8::HandleScope handle_scope(isolate);
1394 v8::Local<v8::Context> context = isolate->GetCurrentContext();
1395 if (context.IsEmpty()) {
1396 NOTREACHED() << "not currently in a V8 context";
1397 return nullptr;
1398 }
1399
1400 // Create a tracker object that will cause the user data reference to be
1401 // released when the V8 object is destroyed.
1402 V8TrackArrayBuffer* tracker =
1403 new V8TrackArrayBuffer(isolate, release_callback);
1404
1405 if (release_callback)
1406 release_callback->AddRef();
1407
1408 auto deleter = [](void* data, size_t length, void* deleter_data) {
1409 auto* release_callback =
1410 reinterpret_cast<CefV8ArrayBufferReleaseCallback*>(deleter_data);
1411 if (release_callback) {
1412 release_callback->ReleaseBuffer(data);
1413 release_callback->Release();
1414 }
1415 };
1416
1417 std::unique_ptr<v8::BackingStore> backing = v8::ArrayBuffer::NewBackingStore(
1418 buffer, length, deleter, release_callback.get());
1419 v8::Local<v8::ArrayBuffer> ab =
1420 v8::ArrayBuffer::New(isolate, std::move(backing));
1421
1422 // Attach the tracker object.
1423 tracker->AttachTo(context, ab);
1424
1425 CefRefPtr<CefV8ValueImpl> impl = new CefV8ValueImpl(isolate);
1426 impl->InitObject(ab, tracker);
1427 return impl.get();
1428 }
1429
1430 // static
CreateFunction(const CefString & name,CefRefPtr<CefV8Handler> handler)1431 CefRefPtr<CefV8Value> CefV8Value::CreateFunction(
1432 const CefString& name,
1433 CefRefPtr<CefV8Handler> handler) {
1434 CEF_V8_REQUIRE_ISOLATE_RETURN(nullptr);
1435
1436 if (!handler.get()) {
1437 NOTREACHED() << "invalid parameter";
1438 return nullptr;
1439 }
1440
1441 v8::Isolate* isolate = GetIsolateManager()->isolate();
1442 v8::HandleScope handle_scope(isolate);
1443
1444 v8::Local<v8::Context> context = isolate->GetCurrentContext();
1445 if (context.IsEmpty()) {
1446 NOTREACHED() << "not currently in a V8 context";
1447 return nullptr;
1448 }
1449
1450 v8::Local<v8::External> function_data =
1451 V8FunctionData::Create(isolate, name, handler);
1452
1453 // Create a new V8 function template.
1454 v8::Local<v8::FunctionTemplate> tmpl =
1455 v8::FunctionTemplate::New(isolate, FunctionCallbackImpl, function_data);
1456
1457 // Retrieve the function object and set the name.
1458 v8::MaybeLocal<v8::Function> maybe_func = tmpl->GetFunction(context);
1459 v8::Local<v8::Function> func;
1460 if (!maybe_func.ToLocal(&func)) {
1461 NOTREACHED() << "failed to create V8 function";
1462 return nullptr;
1463 }
1464
1465 func->SetName(GetV8String(isolate, name));
1466
1467 // Create a tracker object that will cause the user data and/or handler
1468 // reference to be released when the V8 object is destroyed.
1469 V8TrackObject* tracker = new V8TrackObject(isolate);
1470 tracker->SetHandler(handler);
1471
1472 // Attach the tracker object.
1473 tracker->AttachTo(context, func);
1474
1475 // Create the CefV8ValueImpl and provide a tracker object that will cause
1476 // the handler reference to be released when the V8 object is destroyed.
1477 CefRefPtr<CefV8ValueImpl> impl = new CefV8ValueImpl(isolate);
1478 impl->InitObject(func, tracker);
1479 return impl.get();
1480 }
1481
1482 // CefV8ValueImpl
1483
CefV8ValueImpl(v8::Isolate * isolate)1484 CefV8ValueImpl::CefV8ValueImpl(v8::Isolate* isolate)
1485 : isolate_(isolate), type_(TYPE_INVALID), rethrow_exceptions_(false) {
1486 DCHECK(isolate_);
1487 }
1488
CefV8ValueImpl(v8::Isolate * isolate,v8::Local<v8::Context> context,v8::Local<v8::Value> value)1489 CefV8ValueImpl::CefV8ValueImpl(v8::Isolate* isolate,
1490 v8::Local<v8::Context> context,
1491 v8::Local<v8::Value> value)
1492 : isolate_(isolate), type_(TYPE_INVALID), rethrow_exceptions_(false) {
1493 DCHECK(isolate_);
1494 InitFromV8Value(context, value);
1495 }
1496
~CefV8ValueImpl()1497 CefV8ValueImpl::~CefV8ValueImpl() {
1498 if (type_ == TYPE_STRING)
1499 cef_string_clear(&string_value_);
1500 if (handle_.get())
1501 handle_->SetWeakIfNecessary();
1502 }
1503
InitFromV8Value(v8::Local<v8::Context> context,v8::Local<v8::Value> value)1504 void CefV8ValueImpl::InitFromV8Value(v8::Local<v8::Context> context,
1505 v8::Local<v8::Value> value) {
1506 if (value->IsUndefined()) {
1507 InitUndefined();
1508 } else if (value->IsNull()) {
1509 InitNull();
1510 } else if (value->IsTrue()) {
1511 InitBool(true);
1512 } else if (value->IsFalse()) {
1513 InitBool(false);
1514 } else if (value->IsBoolean()) {
1515 InitBool(value->ToBoolean(context->GetIsolate())->Value());
1516 } else if (value->IsInt32()) {
1517 InitInt(value->ToInt32(context).ToLocalChecked()->Value());
1518 } else if (value->IsUint32()) {
1519 InitUInt(value->ToUint32(context).ToLocalChecked()->Value());
1520 } else if (value->IsNumber()) {
1521 InitDouble(value->ToNumber(context).ToLocalChecked()->Value());
1522 } else if (value->IsDate()) {
1523 // Convert from milliseconds to seconds.
1524 InitDate(
1525 CefTime(value->ToNumber(context).ToLocalChecked()->Value() / 1000));
1526 } else if (value->IsString()) {
1527 CefString rv;
1528 GetCefString(context->GetIsolate(),
1529 value->ToString(context).ToLocalChecked(), rv);
1530 InitString(rv);
1531 } else if (value->IsObject()) {
1532 InitObject(value, nullptr);
1533 }
1534 }
1535
InitUndefined()1536 void CefV8ValueImpl::InitUndefined() {
1537 DCHECK_EQ(type_, TYPE_INVALID);
1538 type_ = TYPE_UNDEFINED;
1539 }
1540
InitNull()1541 void CefV8ValueImpl::InitNull() {
1542 DCHECK_EQ(type_, TYPE_INVALID);
1543 type_ = TYPE_NULL;
1544 }
1545
InitBool(bool value)1546 void CefV8ValueImpl::InitBool(bool value) {
1547 DCHECK_EQ(type_, TYPE_INVALID);
1548 type_ = TYPE_BOOL;
1549 bool_value_ = value;
1550 }
1551
InitInt(int32 value)1552 void CefV8ValueImpl::InitInt(int32 value) {
1553 DCHECK_EQ(type_, TYPE_INVALID);
1554 type_ = TYPE_INT;
1555 int_value_ = value;
1556 }
1557
InitUInt(uint32 value)1558 void CefV8ValueImpl::InitUInt(uint32 value) {
1559 DCHECK_EQ(type_, TYPE_INVALID);
1560 type_ = TYPE_UINT;
1561 uint_value_ = value;
1562 }
1563
InitDouble(double value)1564 void CefV8ValueImpl::InitDouble(double value) {
1565 DCHECK_EQ(type_, TYPE_INVALID);
1566 type_ = TYPE_DOUBLE;
1567 double_value_ = value;
1568 }
1569
InitDate(const CefTime & value)1570 void CefV8ValueImpl::InitDate(const CefTime& value) {
1571 DCHECK_EQ(type_, TYPE_INVALID);
1572 type_ = TYPE_DATE;
1573 date_value_ = value;
1574 }
1575
InitString(CefString & value)1576 void CefV8ValueImpl::InitString(CefString& value) {
1577 DCHECK_EQ(type_, TYPE_INVALID);
1578 type_ = TYPE_STRING;
1579 // Take ownership of the underling string value.
1580 const cef_string_t* str = value.GetStruct();
1581 if (str) {
1582 string_value_ = *str;
1583 cef_string_t* writable_struct = value.GetWritableStruct();
1584 writable_struct->str = nullptr;
1585 writable_struct->length = 0;
1586 } else {
1587 string_value_.str = nullptr;
1588 string_value_.length = 0;
1589 }
1590 }
1591
InitObject(v8::Local<v8::Value> value,CefTrackNode * tracker)1592 void CefV8ValueImpl::InitObject(v8::Local<v8::Value> value,
1593 CefTrackNode* tracker) {
1594 DCHECK_EQ(type_, TYPE_INVALID);
1595 type_ = TYPE_OBJECT;
1596 handle_ = new Handle(isolate_, v8::Local<v8::Context>(), value, tracker);
1597 }
1598
GetV8Value(bool should_persist)1599 v8::Local<v8::Value> CefV8ValueImpl::GetV8Value(bool should_persist) {
1600 switch (type_) {
1601 case TYPE_UNDEFINED:
1602 return v8::Undefined(isolate_);
1603 case TYPE_NULL:
1604 return v8::Null(isolate_);
1605 case TYPE_BOOL:
1606 return v8::Boolean::New(isolate_, bool_value_);
1607 case TYPE_INT:
1608 return v8::Int32::New(isolate_, int_value_);
1609 case TYPE_UINT:
1610 return v8::Uint32::New(isolate_, uint_value_);
1611 case TYPE_DOUBLE:
1612 return v8::Number::New(isolate_, double_value_);
1613 case TYPE_DATE:
1614 // Convert from seconds to milliseconds.
1615 return v8::Date::New(isolate_->GetCurrentContext(),
1616 CefTime(date_value_).GetDoubleT() * 1000)
1617 .ToLocalChecked();
1618 case TYPE_STRING:
1619 return GetV8String(isolate_, CefString(&string_value_));
1620 case TYPE_OBJECT:
1621 return handle_->GetNewV8Handle(should_persist);
1622 default:
1623 break;
1624 }
1625
1626 NOTREACHED() << "Invalid type for CefV8ValueImpl";
1627 return v8::Local<v8::Value>();
1628 }
1629
IsValid()1630 bool CefV8ValueImpl::IsValid() {
1631 if (!CEF_V8_HAS_ISOLATE() || type_ == TYPE_INVALID ||
1632 (type_ == TYPE_OBJECT &&
1633 (!handle_->BelongsToCurrentThread() || !handle_->IsValid()))) {
1634 return false;
1635 }
1636 return true;
1637 }
1638
IsUndefined()1639 bool CefV8ValueImpl::IsUndefined() {
1640 CEF_V8_REQUIRE_ISOLATE_RETURN(false);
1641 return (type_ == TYPE_UNDEFINED);
1642 }
1643
IsNull()1644 bool CefV8ValueImpl::IsNull() {
1645 CEF_V8_REQUIRE_ISOLATE_RETURN(false);
1646 return (type_ == TYPE_NULL);
1647 }
1648
IsBool()1649 bool CefV8ValueImpl::IsBool() {
1650 CEF_V8_REQUIRE_ISOLATE_RETURN(false);
1651 return (type_ == TYPE_BOOL);
1652 }
1653
IsInt()1654 bool CefV8ValueImpl::IsInt() {
1655 CEF_V8_REQUIRE_ISOLATE_RETURN(false);
1656 return (type_ == TYPE_INT || type_ == TYPE_UINT);
1657 }
1658
IsUInt()1659 bool CefV8ValueImpl::IsUInt() {
1660 CEF_V8_REQUIRE_ISOLATE_RETURN(false);
1661 return (type_ == TYPE_INT || type_ == TYPE_UINT);
1662 }
1663
IsDouble()1664 bool CefV8ValueImpl::IsDouble() {
1665 CEF_V8_REQUIRE_ISOLATE_RETURN(false);
1666 return (type_ == TYPE_INT || type_ == TYPE_UINT || type_ == TYPE_DOUBLE);
1667 }
1668
IsDate()1669 bool CefV8ValueImpl::IsDate() {
1670 CEF_V8_REQUIRE_ISOLATE_RETURN(false);
1671 return (type_ == TYPE_DATE);
1672 }
1673
IsString()1674 bool CefV8ValueImpl::IsString() {
1675 CEF_V8_REQUIRE_ISOLATE_RETURN(false);
1676 return (type_ == TYPE_STRING);
1677 }
1678
IsObject()1679 bool CefV8ValueImpl::IsObject() {
1680 CEF_V8_REQUIRE_ISOLATE_RETURN(false);
1681 return (type_ == TYPE_OBJECT);
1682 }
1683
IsArray()1684 bool CefV8ValueImpl::IsArray() {
1685 CEF_V8_REQUIRE_MLT_RETURN(false);
1686 if (type_ == TYPE_OBJECT) {
1687 v8::HandleScope handle_scope(handle_->isolate());
1688 return handle_->GetNewV8Handle(false)->IsArray();
1689 } else {
1690 return false;
1691 }
1692 }
1693
IsArrayBuffer()1694 bool CefV8ValueImpl::IsArrayBuffer() {
1695 CEF_V8_REQUIRE_MLT_RETURN(false);
1696 if (type_ == TYPE_OBJECT) {
1697 v8::HandleScope handle_scope(handle_->isolate());
1698 return handle_->GetNewV8Handle(false)->IsArrayBuffer();
1699 } else {
1700 return false;
1701 }
1702 }
1703
IsFunction()1704 bool CefV8ValueImpl::IsFunction() {
1705 CEF_V8_REQUIRE_MLT_RETURN(false);
1706 if (type_ == TYPE_OBJECT) {
1707 v8::HandleScope handle_scope(handle_->isolate());
1708 return handle_->GetNewV8Handle(false)->IsFunction();
1709 } else {
1710 return false;
1711 }
1712 }
1713
IsSame(CefRefPtr<CefV8Value> that)1714 bool CefV8ValueImpl::IsSame(CefRefPtr<CefV8Value> that) {
1715 CEF_V8_REQUIRE_MLT_RETURN(false);
1716
1717 CefV8ValueImpl* thatValue = static_cast<CefV8ValueImpl*>(that.get());
1718 if (!thatValue || !thatValue->IsValid() || type_ != thatValue->type_)
1719 return false;
1720
1721 switch (type_) {
1722 case TYPE_UNDEFINED:
1723 case TYPE_NULL:
1724 return true;
1725 case TYPE_BOOL:
1726 return (bool_value_ == thatValue->bool_value_);
1727 case TYPE_INT:
1728 return (int_value_ == thatValue->int_value_);
1729 case TYPE_UINT:
1730 return (uint_value_ == thatValue->uint_value_);
1731 case TYPE_DOUBLE:
1732 return (double_value_ == thatValue->double_value_);
1733 case TYPE_DATE:
1734 return (CefTime(date_value_).GetTimeT() ==
1735 CefTime(thatValue->date_value_).GetTimeT());
1736 case TYPE_STRING:
1737 return (CefString(&string_value_) ==
1738 CefString(&thatValue->string_value_));
1739 case TYPE_OBJECT: {
1740 return (handle_->GetPersistentV8Handle() ==
1741 thatValue->handle_->GetPersistentV8Handle());
1742 }
1743 default:
1744 break;
1745 }
1746
1747 return false;
1748 }
1749
GetBoolValue()1750 bool CefV8ValueImpl::GetBoolValue() {
1751 CEF_V8_REQUIRE_ISOLATE_RETURN(false);
1752 if (type_ == TYPE_BOOL)
1753 return bool_value_;
1754 return false;
1755 }
1756
GetIntValue()1757 int32 CefV8ValueImpl::GetIntValue() {
1758 CEF_V8_REQUIRE_ISOLATE_RETURN(0);
1759 if (type_ == TYPE_INT || type_ == TYPE_UINT)
1760 return int_value_;
1761 return 0;
1762 }
1763
GetUIntValue()1764 uint32 CefV8ValueImpl::GetUIntValue() {
1765 CEF_V8_REQUIRE_ISOLATE_RETURN(0);
1766 if (type_ == TYPE_INT || type_ == TYPE_UINT)
1767 return uint_value_;
1768 return 0;
1769 }
1770
GetDoubleValue()1771 double CefV8ValueImpl::GetDoubleValue() {
1772 CEF_V8_REQUIRE_ISOLATE_RETURN(0.);
1773 if (type_ == TYPE_DOUBLE)
1774 return double_value_;
1775 else if (type_ == TYPE_INT)
1776 return int_value_;
1777 else if (type_ == TYPE_UINT)
1778 return uint_value_;
1779 return 0.;
1780 }
1781
GetDateValue()1782 CefTime CefV8ValueImpl::GetDateValue() {
1783 CEF_V8_REQUIRE_ISOLATE_RETURN(CefTime(0.));
1784 if (type_ == TYPE_DATE)
1785 return date_value_;
1786 return CefTime(0.);
1787 }
1788
GetStringValue()1789 CefString CefV8ValueImpl::GetStringValue() {
1790 CefString rv;
1791 CEF_V8_REQUIRE_ISOLATE_RETURN(rv);
1792 if (type_ == TYPE_STRING)
1793 rv = CefString(&string_value_);
1794 return rv;
1795 }
1796
IsUserCreated()1797 bool CefV8ValueImpl::IsUserCreated() {
1798 CEF_V8_REQUIRE_OBJECT_RETURN(false);
1799
1800 v8::Isolate* isolate = handle_->isolate();
1801 v8::HandleScope handle_scope(isolate);
1802
1803 v8::Local<v8::Context> context = isolate->GetCurrentContext();
1804 if (context.IsEmpty()) {
1805 NOTREACHED() << "not currently in a V8 context";
1806 return false;
1807 }
1808
1809 v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
1810 v8::Local<v8::Object> obj = value->ToObject(context).ToLocalChecked();
1811
1812 V8TrackObject* tracker = V8TrackObject::Unwrap(context, obj);
1813 return (tracker != nullptr);
1814 }
1815
HasException()1816 bool CefV8ValueImpl::HasException() {
1817 CEF_V8_REQUIRE_OBJECT_RETURN(false);
1818
1819 return (last_exception_.get() != nullptr);
1820 }
1821
GetException()1822 CefRefPtr<CefV8Exception> CefV8ValueImpl::GetException() {
1823 CEF_V8_REQUIRE_OBJECT_RETURN(nullptr);
1824
1825 return last_exception_;
1826 }
1827
ClearException()1828 bool CefV8ValueImpl::ClearException() {
1829 CEF_V8_REQUIRE_OBJECT_RETURN(false);
1830
1831 last_exception_ = nullptr;
1832 return true;
1833 }
1834
WillRethrowExceptions()1835 bool CefV8ValueImpl::WillRethrowExceptions() {
1836 CEF_V8_REQUIRE_OBJECT_RETURN(false);
1837
1838 return rethrow_exceptions_;
1839 }
1840
SetRethrowExceptions(bool rethrow)1841 bool CefV8ValueImpl::SetRethrowExceptions(bool rethrow) {
1842 CEF_V8_REQUIRE_OBJECT_RETURN(false);
1843
1844 rethrow_exceptions_ = rethrow;
1845 return true;
1846 }
1847
HasValue(const CefString & key)1848 bool CefV8ValueImpl::HasValue(const CefString& key) {
1849 CEF_V8_REQUIRE_OBJECT_RETURN(false);
1850
1851 v8::Isolate* isolate = handle_->isolate();
1852 v8::HandleScope handle_scope(isolate);
1853
1854 v8::Local<v8::Context> context = isolate->GetCurrentContext();
1855 if (context.IsEmpty()) {
1856 NOTREACHED() << "not currently in a V8 context";
1857 return false;
1858 }
1859
1860 v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
1861 v8::Local<v8::Object> obj = value->ToObject(context).ToLocalChecked();
1862 return obj->Has(context, GetV8String(isolate, key)).FromJust();
1863 }
1864
HasValue(int index)1865 bool CefV8ValueImpl::HasValue(int index) {
1866 CEF_V8_REQUIRE_OBJECT_RETURN(false);
1867
1868 if (index < 0) {
1869 NOTREACHED() << "invalid input parameter";
1870 return false;
1871 }
1872
1873 v8::Isolate* isolate = handle_->isolate();
1874 v8::HandleScope handle_scope(isolate);
1875
1876 v8::Local<v8::Context> context = isolate->GetCurrentContext();
1877 if (context.IsEmpty()) {
1878 NOTREACHED() << "not currently in a V8 context";
1879 return false;
1880 }
1881
1882 v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
1883 v8::Local<v8::Object> obj = value->ToObject(context).ToLocalChecked();
1884 return obj->Has(context, index).FromJust();
1885 }
1886
DeleteValue(const CefString & key)1887 bool CefV8ValueImpl::DeleteValue(const CefString& key) {
1888 CEF_V8_REQUIRE_OBJECT_RETURN(false);
1889
1890 v8::Isolate* isolate = handle_->isolate();
1891 v8::HandleScope handle_scope(isolate);
1892
1893 v8::Local<v8::Context> context = isolate->GetCurrentContext();
1894 if (context.IsEmpty()) {
1895 NOTREACHED() << "not currently in a V8 context";
1896 return false;
1897 }
1898
1899 v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
1900 v8::Local<v8::Object> obj = value->ToObject(context).ToLocalChecked();
1901
1902 v8::TryCatch try_catch(isolate);
1903 try_catch.SetVerbose(true);
1904 v8::Maybe<bool> del = obj->Delete(context, GetV8String(isolate, key));
1905 return (!HasCaught(context, try_catch) && del.FromJust());
1906 }
1907
DeleteValue(int index)1908 bool CefV8ValueImpl::DeleteValue(int index) {
1909 CEF_V8_REQUIRE_OBJECT_RETURN(false);
1910
1911 if (index < 0) {
1912 NOTREACHED() << "invalid input parameter";
1913 return false;
1914 }
1915
1916 v8::Isolate* isolate = handle_->isolate();
1917 v8::HandleScope handle_scope(isolate);
1918
1919 v8::Local<v8::Context> context = isolate->GetCurrentContext();
1920 if (context.IsEmpty()) {
1921 NOTREACHED() << "not currently in a V8 context";
1922 return false;
1923 }
1924
1925 v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
1926 v8::Local<v8::Object> obj = value->ToObject(context).ToLocalChecked();
1927
1928 v8::TryCatch try_catch(isolate);
1929 try_catch.SetVerbose(true);
1930 v8::Maybe<bool> del = obj->Delete(context, index);
1931 return (!HasCaught(context, try_catch) && del.FromJust());
1932 }
1933
GetValue(const CefString & key)1934 CefRefPtr<CefV8Value> CefV8ValueImpl::GetValue(const CefString& key) {
1935 CEF_V8_REQUIRE_OBJECT_RETURN(nullptr);
1936
1937 v8::Isolate* isolate = handle_->isolate();
1938 v8::HandleScope handle_scope(isolate);
1939
1940 v8::Local<v8::Context> context = isolate->GetCurrentContext();
1941 if (context.IsEmpty()) {
1942 NOTREACHED() << "not currently in a V8 context";
1943 return nullptr;
1944 }
1945
1946 v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
1947 v8::Local<v8::Object> obj = value->ToObject(context).ToLocalChecked();
1948
1949 v8::TryCatch try_catch(isolate);
1950 try_catch.SetVerbose(true);
1951 v8::MaybeLocal<v8::Value> ret_value =
1952 obj->Get(context, GetV8String(isolate, key));
1953 if (!HasCaught(context, try_catch) && !ret_value.IsEmpty()) {
1954 return new CefV8ValueImpl(isolate, context, ret_value.ToLocalChecked());
1955 }
1956 return nullptr;
1957 }
1958
GetValue(int index)1959 CefRefPtr<CefV8Value> CefV8ValueImpl::GetValue(int index) {
1960 CEF_V8_REQUIRE_OBJECT_RETURN(nullptr);
1961
1962 if (index < 0) {
1963 NOTREACHED() << "invalid input parameter";
1964 return nullptr;
1965 }
1966
1967 v8::Isolate* isolate = handle_->isolate();
1968 v8::HandleScope handle_scope(isolate);
1969
1970 v8::Local<v8::Context> context = isolate->GetCurrentContext();
1971 if (context.IsEmpty()) {
1972 NOTREACHED() << "not currently in a V8 context";
1973 return nullptr;
1974 }
1975
1976 v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
1977 v8::Local<v8::Object> obj = value->ToObject(context).ToLocalChecked();
1978
1979 v8::TryCatch try_catch(isolate);
1980 try_catch.SetVerbose(true);
1981 v8::MaybeLocal<v8::Value> ret_value =
1982 obj->Get(context, v8::Number::New(isolate, index));
1983 if (!HasCaught(context, try_catch) && !ret_value.IsEmpty()) {
1984 return new CefV8ValueImpl(isolate, context, ret_value.ToLocalChecked());
1985 }
1986 return nullptr;
1987 }
1988
SetValue(const CefString & key,CefRefPtr<CefV8Value> value,PropertyAttribute attribute)1989 bool CefV8ValueImpl::SetValue(const CefString& key,
1990 CefRefPtr<CefV8Value> value,
1991 PropertyAttribute attribute) {
1992 CEF_V8_REQUIRE_OBJECT_RETURN(false);
1993
1994 CefV8ValueImpl* impl = static_cast<CefV8ValueImpl*>(value.get());
1995 if (impl && impl->IsValid()) {
1996 v8::Isolate* isolate = handle_->isolate();
1997 v8::HandleScope handle_scope(isolate);
1998
1999 v8::Local<v8::Context> context = isolate->GetCurrentContext();
2000 if (context.IsEmpty()) {
2001 NOTREACHED() << "not currently in a V8 context";
2002 return false;
2003 }
2004
2005 v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
2006 v8::Local<v8::Object> obj = value->ToObject(context).ToLocalChecked();
2007
2008 v8::TryCatch try_catch(isolate);
2009 try_catch.SetVerbose(true);
2010 // TODO(cef): This usage may not exactly match the previous implementation.
2011 // Set will trigger interceptors and/or accessors whereas DefineOwnProperty
2012 // will not. It might be better to split this functionality into separate
2013 // methods.
2014 if (attribute == V8_PROPERTY_ATTRIBUTE_NONE) {
2015 v8::Maybe<bool> set =
2016 obj->Set(context, GetV8String(isolate, key), impl->GetV8Value(true));
2017 return (!HasCaught(context, try_catch) && set.FromJust());
2018 } else {
2019 v8::Maybe<bool> set = obj->DefineOwnProperty(
2020 context, GetV8String(isolate, key), impl->GetV8Value(true),
2021 static_cast<v8::PropertyAttribute>(attribute));
2022 return (!HasCaught(context, try_catch) && set.FromJust());
2023 }
2024 } else {
2025 NOTREACHED() << "invalid input parameter";
2026 return false;
2027 }
2028 }
2029
SetValue(int index,CefRefPtr<CefV8Value> value)2030 bool CefV8ValueImpl::SetValue(int index, CefRefPtr<CefV8Value> value) {
2031 CEF_V8_REQUIRE_OBJECT_RETURN(false);
2032
2033 if (index < 0) {
2034 NOTREACHED() << "invalid input parameter";
2035 return false;
2036 }
2037
2038 CefV8ValueImpl* impl = static_cast<CefV8ValueImpl*>(value.get());
2039 if (impl && impl->IsValid()) {
2040 v8::Isolate* isolate = handle_->isolate();
2041 v8::HandleScope handle_scope(isolate);
2042
2043 v8::Local<v8::Context> context = isolate->GetCurrentContext();
2044 if (context.IsEmpty()) {
2045 NOTREACHED() << "not currently in a V8 context";
2046 return false;
2047 }
2048
2049 v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
2050 v8::Local<v8::Object> obj = value->ToObject(context).ToLocalChecked();
2051
2052 v8::TryCatch try_catch(isolate);
2053 try_catch.SetVerbose(true);
2054 v8::Maybe<bool> set = obj->Set(context, index, impl->GetV8Value(true));
2055 return (!HasCaught(context, try_catch) && set.FromJust());
2056 } else {
2057 NOTREACHED() << "invalid input parameter";
2058 return false;
2059 }
2060 }
2061
SetValue(const CefString & key,AccessControl settings,PropertyAttribute attribute)2062 bool CefV8ValueImpl::SetValue(const CefString& key,
2063 AccessControl settings,
2064 PropertyAttribute attribute) {
2065 CEF_V8_REQUIRE_OBJECT_RETURN(false);
2066
2067 v8::Isolate* isolate = handle_->isolate();
2068 v8::HandleScope handle_scope(isolate);
2069
2070 v8::Local<v8::Context> context = isolate->GetCurrentContext();
2071 if (context.IsEmpty()) {
2072 NOTREACHED() << "not currently in a V8 context";
2073 return false;
2074 }
2075
2076 v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
2077 v8::Local<v8::Object> obj = value->ToObject(context).ToLocalChecked();
2078
2079 CefRefPtr<CefV8Accessor> accessorPtr;
2080
2081 V8TrackObject* tracker = V8TrackObject::Unwrap(context, obj);
2082 if (tracker)
2083 accessorPtr = tracker->GetAccessor();
2084
2085 // Verify that an accessor exists for this object.
2086 if (!accessorPtr.get())
2087 return false;
2088
2089 v8::AccessorNameGetterCallback getter = AccessorNameGetterCallbackImpl;
2090 v8::AccessorNameSetterCallback setter =
2091 (attribute & V8_PROPERTY_ATTRIBUTE_READONLY)
2092 ? nullptr
2093 : AccessorNameSetterCallbackImpl;
2094
2095 v8::TryCatch try_catch(isolate);
2096 try_catch.SetVerbose(true);
2097 v8::Maybe<bool> set =
2098 obj->SetAccessor(context, GetV8String(isolate, key), getter, setter, obj,
2099 static_cast<v8::AccessControl>(settings),
2100 static_cast<v8::PropertyAttribute>(attribute));
2101 return (!HasCaught(context, try_catch) && set.FromJust());
2102 }
2103
GetKeys(std::vector<CefString> & keys)2104 bool CefV8ValueImpl::GetKeys(std::vector<CefString>& keys) {
2105 CEF_V8_REQUIRE_OBJECT_RETURN(false);
2106
2107 v8::Isolate* isolate = handle_->isolate();
2108 v8::HandleScope handle_scope(isolate);
2109
2110 v8::Local<v8::Context> context = isolate->GetCurrentContext();
2111 if (context.IsEmpty()) {
2112 NOTREACHED() << "not currently in a V8 context";
2113 return false;
2114 }
2115
2116 v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
2117 v8::Local<v8::Object> obj = value->ToObject(context).ToLocalChecked();
2118 v8::Local<v8::Array> arr_keys =
2119 obj->GetPropertyNames(context).ToLocalChecked();
2120
2121 uint32_t len = arr_keys->Length();
2122 for (uint32_t i = 0; i < len; ++i) {
2123 v8::Local<v8::Value> value =
2124 arr_keys->Get(context, v8::Integer::New(isolate, i)).ToLocalChecked();
2125 CefString str;
2126 GetCefString(isolate, value->ToString(context).ToLocalChecked(), str);
2127 keys.push_back(str);
2128 }
2129 return true;
2130 }
2131
SetUserData(CefRefPtr<CefBaseRefCounted> user_data)2132 bool CefV8ValueImpl::SetUserData(CefRefPtr<CefBaseRefCounted> user_data) {
2133 CEF_V8_REQUIRE_OBJECT_RETURN(false);
2134
2135 v8::Isolate* isolate = handle_->isolate();
2136 v8::HandleScope handle_scope(isolate);
2137
2138 v8::Local<v8::Context> context = isolate->GetCurrentContext();
2139 if (context.IsEmpty()) {
2140 NOTREACHED() << "not currently in a V8 context";
2141 return false;
2142 }
2143
2144 v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
2145 v8::Local<v8::Object> obj = value->ToObject(context).ToLocalChecked();
2146
2147 V8TrackObject* tracker = V8TrackObject::Unwrap(context, obj);
2148 if (tracker) {
2149 tracker->SetUserData(user_data);
2150 return true;
2151 }
2152
2153 return false;
2154 }
2155
GetUserData()2156 CefRefPtr<CefBaseRefCounted> CefV8ValueImpl::GetUserData() {
2157 CEF_V8_REQUIRE_OBJECT_RETURN(nullptr);
2158
2159 v8::Isolate* isolate = handle_->isolate();
2160 v8::HandleScope handle_scope(isolate);
2161
2162 v8::Local<v8::Context> context = isolate->GetCurrentContext();
2163 if (context.IsEmpty()) {
2164 NOTREACHED() << "not currently in a V8 context";
2165 return nullptr;
2166 }
2167
2168 v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
2169 v8::Local<v8::Object> obj = value->ToObject(context).ToLocalChecked();
2170
2171 V8TrackObject* tracker = V8TrackObject::Unwrap(context, obj);
2172 if (tracker)
2173 return tracker->GetUserData();
2174
2175 return nullptr;
2176 }
2177
GetExternallyAllocatedMemory()2178 int CefV8ValueImpl::GetExternallyAllocatedMemory() {
2179 CEF_V8_REQUIRE_OBJECT_RETURN(0);
2180
2181 v8::Isolate* isolate = handle_->isolate();
2182 v8::HandleScope handle_scope(isolate);
2183
2184 v8::Local<v8::Context> context = isolate->GetCurrentContext();
2185 if (context.IsEmpty()) {
2186 NOTREACHED() << "not currently in a V8 context";
2187 return 0;
2188 }
2189
2190 v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
2191 v8::Local<v8::Object> obj = value->ToObject(context).ToLocalChecked();
2192
2193 V8TrackObject* tracker = V8TrackObject::Unwrap(context, obj);
2194 if (tracker)
2195 return tracker->GetExternallyAllocatedMemory();
2196
2197 return 0;
2198 }
2199
AdjustExternallyAllocatedMemory(int change_in_bytes)2200 int CefV8ValueImpl::AdjustExternallyAllocatedMemory(int change_in_bytes) {
2201 CEF_V8_REQUIRE_OBJECT_RETURN(0);
2202
2203 v8::Isolate* isolate = handle_->isolate();
2204 v8::HandleScope handle_scope(isolate);
2205
2206 v8::Local<v8::Context> context = isolate->GetCurrentContext();
2207 if (context.IsEmpty()) {
2208 NOTREACHED() << "not currently in a V8 context";
2209 return 0;
2210 }
2211
2212 v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
2213 v8::Local<v8::Object> obj = value->ToObject(context).ToLocalChecked();
2214
2215 V8TrackObject* tracker = V8TrackObject::Unwrap(context, obj);
2216 if (tracker)
2217 return tracker->AdjustExternallyAllocatedMemory(change_in_bytes);
2218
2219 return 0;
2220 }
2221
GetArrayLength()2222 int CefV8ValueImpl::GetArrayLength() {
2223 CEF_V8_REQUIRE_OBJECT_RETURN(0);
2224
2225 v8::Isolate* isolate = handle_->isolate();
2226 v8::HandleScope handle_scope(isolate);
2227
2228 v8::Local<v8::Context> context = isolate->GetCurrentContext();
2229 if (context.IsEmpty()) {
2230 NOTREACHED() << "not currently in a V8 context";
2231 return 0;
2232 }
2233
2234 v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
2235 if (!value->IsArray()) {
2236 NOTREACHED() << "V8 value is not an array";
2237 return 0;
2238 }
2239
2240 v8::Local<v8::Object> obj = value->ToObject(context).ToLocalChecked();
2241 v8::Local<v8::Array> arr = v8::Local<v8::Array>::Cast(obj);
2242 return arr->Length();
2243 }
2244
2245 CefRefPtr<CefV8ArrayBufferReleaseCallback>
GetArrayBufferReleaseCallback()2246 CefV8ValueImpl::GetArrayBufferReleaseCallback() {
2247 CEF_V8_REQUIRE_OBJECT_RETURN(nullptr);
2248
2249 v8::Isolate* isolate = handle_->isolate();
2250 v8::HandleScope handle_scope(isolate);
2251
2252 v8::Local<v8::Context> context = isolate->GetCurrentContext();
2253 if (context.IsEmpty()) {
2254 NOTREACHED() << "not currently in a V8 context";
2255 return nullptr;
2256 }
2257
2258 v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
2259 if (!value->IsArrayBuffer()) {
2260 NOTREACHED() << "V8 value is not an array buffer";
2261 return nullptr;
2262 }
2263
2264 v8::Local<v8::Object> obj = value->ToObject(context).ToLocalChecked();
2265
2266 V8TrackArrayBuffer* tracker = V8TrackArrayBuffer::Unwrap(context, obj);
2267 if (tracker)
2268 return tracker->GetReleaseCallback();
2269
2270 return nullptr;
2271 }
2272
NeuterArrayBuffer()2273 bool CefV8ValueImpl::NeuterArrayBuffer() {
2274 CEF_V8_REQUIRE_OBJECT_RETURN(0);
2275
2276 v8::Isolate* isolate = handle_->isolate();
2277 v8::HandleScope handle_scope(isolate);
2278
2279 v8::Local<v8::Context> context = isolate->GetCurrentContext();
2280 if (context.IsEmpty()) {
2281 NOTREACHED() << "not currently in a V8 context";
2282 return false;
2283 }
2284
2285 v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
2286 if (!value->IsArrayBuffer()) {
2287 NOTREACHED() << "V8 value is not an array buffer";
2288 return false;
2289 }
2290 v8::Local<v8::Object> obj = value->ToObject(context).ToLocalChecked();
2291 v8::Local<v8::ArrayBuffer> arr = v8::Local<v8::ArrayBuffer>::Cast(obj);
2292 if (!arr->IsDetachable()) {
2293 return false;
2294 }
2295 arr->Detach();
2296
2297 return true;
2298 }
2299
GetFunctionName()2300 CefString CefV8ValueImpl::GetFunctionName() {
2301 CefString rv;
2302 CEF_V8_REQUIRE_OBJECT_RETURN(rv);
2303
2304 v8::Isolate* isolate = handle_->isolate();
2305 v8::HandleScope handle_scope(isolate);
2306
2307 v8::Local<v8::Context> context = isolate->GetCurrentContext();
2308 if (context.IsEmpty()) {
2309 NOTREACHED() << "not currently in a V8 context";
2310 return rv;
2311 }
2312
2313 v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
2314 if (!value->IsFunction()) {
2315 NOTREACHED() << "V8 value is not a function";
2316 return rv;
2317 }
2318
2319 v8::Local<v8::Object> obj = value->ToObject(context).ToLocalChecked();
2320 v8::Local<v8::Function> func = v8::Local<v8::Function>::Cast(obj);
2321 GetCefString(handle_->isolate(),
2322 v8::Handle<v8::String>::Cast(func->GetName()), rv);
2323 return rv;
2324 }
2325
GetFunctionHandler()2326 CefRefPtr<CefV8Handler> CefV8ValueImpl::GetFunctionHandler() {
2327 CEF_V8_REQUIRE_OBJECT_RETURN(nullptr);
2328
2329 v8::Isolate* isolate = handle_->isolate();
2330 v8::HandleScope handle_scope(isolate);
2331
2332 v8::Local<v8::Context> context = isolate->GetCurrentContext();
2333 if (context.IsEmpty()) {
2334 NOTREACHED() << "not currently in a V8 context";
2335 return nullptr;
2336 }
2337
2338 v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
2339 if (!value->IsFunction()) {
2340 NOTREACHED() << "V8 value is not a function";
2341 return nullptr;
2342 }
2343
2344 v8::Local<v8::Object> obj = value->ToObject(context).ToLocalChecked();
2345 V8TrackObject* tracker = V8TrackObject::Unwrap(context, obj);
2346 if (tracker)
2347 return tracker->GetHandler();
2348
2349 return nullptr;
2350 }
2351
ExecuteFunction(CefRefPtr<CefV8Value> object,const CefV8ValueList & arguments)2352 CefRefPtr<CefV8Value> CefV8ValueImpl::ExecuteFunction(
2353 CefRefPtr<CefV8Value> object,
2354 const CefV8ValueList& arguments) {
2355 // An empty context value defaults to the current context.
2356 CefRefPtr<CefV8Context> context;
2357 return ExecuteFunctionWithContext(context, object, arguments);
2358 }
2359
ExecuteFunctionWithContext(CefRefPtr<CefV8Context> context,CefRefPtr<CefV8Value> object,const CefV8ValueList & arguments)2360 CefRefPtr<CefV8Value> CefV8ValueImpl::ExecuteFunctionWithContext(
2361 CefRefPtr<CefV8Context> context,
2362 CefRefPtr<CefV8Value> object,
2363 const CefV8ValueList& arguments) {
2364 CEF_V8_REQUIRE_OBJECT_RETURN(nullptr);
2365
2366 v8::Isolate* isolate = handle_->isolate();
2367 v8::HandleScope handle_scope(isolate);
2368 v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
2369 if (!value->IsFunction()) {
2370 NOTREACHED() << "V8 value is not a function";
2371 return nullptr;
2372 }
2373
2374 if (context.get() && !context->IsValid()) {
2375 NOTREACHED() << "invalid V8 context parameter";
2376 return nullptr;
2377 }
2378 if (object.get() && (!object->IsValid() || !object->IsObject())) {
2379 NOTREACHED() << "invalid V8 object parameter";
2380 return nullptr;
2381 }
2382
2383 int argc = arguments.size();
2384 if (argc > 0) {
2385 for (int i = 0; i < argc; ++i) {
2386 if (!arguments[i].get() || !arguments[i]->IsValid()) {
2387 NOTREACHED() << "invalid V8 arguments parameter";
2388 return nullptr;
2389 }
2390 }
2391 }
2392
2393 v8::Local<v8::Context> context_local;
2394 if (context.get()) {
2395 CefV8ContextImpl* context_impl =
2396 static_cast<CefV8ContextImpl*>(context.get());
2397 context_local = context_impl->GetV8Context();
2398 } else {
2399 context_local = isolate->GetCurrentContext();
2400 }
2401
2402 v8::Context::Scope context_scope(context_local);
2403
2404 v8::Local<v8::Object> obj = value->ToObject(context_local).ToLocalChecked();
2405 v8::Local<v8::Function> func = v8::Local<v8::Function>::Cast(obj);
2406 v8::Local<v8::Object> recv;
2407
2408 // Default to the global object if no object was provided.
2409 if (object.get()) {
2410 CefV8ValueImpl* recv_impl = static_cast<CefV8ValueImpl*>(object.get());
2411 recv = v8::Local<v8::Object>::Cast(recv_impl->GetV8Value(true));
2412 } else {
2413 recv = context_local->Global();
2414 }
2415
2416 v8::Local<v8::Value>* argv = nullptr;
2417 if (argc > 0) {
2418 argv = new v8::Local<v8::Value>[argc];
2419 for (int i = 0; i < argc; ++i) {
2420 argv[i] =
2421 static_cast<CefV8ValueImpl*>(arguments[i].get())->GetV8Value(true);
2422 }
2423 }
2424
2425 CefRefPtr<CefV8Value> retval;
2426
2427 {
2428 v8::TryCatch try_catch(isolate);
2429 try_catch.SetVerbose(true);
2430
2431 v8::MaybeLocal<v8::Value> func_rv = blink_glue::CallV8Function(
2432 context_local, func, recv, argc, argv, handle_->isolate());
2433
2434 if (!HasCaught(context_local, try_catch) && !func_rv.IsEmpty()) {
2435 retval =
2436 new CefV8ValueImpl(isolate, context_local, func_rv.ToLocalChecked());
2437 }
2438 }
2439
2440 if (argv)
2441 delete[] argv;
2442
2443 return retval;
2444 }
2445
HasCaught(v8::Local<v8::Context> context,v8::TryCatch & try_catch)2446 bool CefV8ValueImpl::HasCaught(v8::Local<v8::Context> context,
2447 v8::TryCatch& try_catch) {
2448 if (try_catch.HasCaught()) {
2449 last_exception_ = new CefV8ExceptionImpl(context, try_catch.Message());
2450 if (rethrow_exceptions_)
2451 try_catch.ReThrow();
2452 return true;
2453 } else {
2454 if (last_exception_.get())
2455 last_exception_ = nullptr;
2456 return false;
2457 }
2458 }
2459
2460 // CefV8StackTrace
2461
2462 // static
GetCurrent(int frame_limit)2463 CefRefPtr<CefV8StackTrace> CefV8StackTrace::GetCurrent(int frame_limit) {
2464 CEF_V8_REQUIRE_ISOLATE_RETURN(nullptr);
2465
2466 v8::Isolate* isolate = GetIsolateManager()->isolate();
2467 v8::HandleScope handle_scope(isolate);
2468 v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
2469 isolate, frame_limit, v8::StackTrace::kDetailed);
2470 if (stackTrace.IsEmpty())
2471 return nullptr;
2472 return new CefV8StackTraceImpl(isolate, stackTrace);
2473 }
2474
2475 // CefV8StackTraceImpl
2476
CefV8StackTraceImpl(v8::Isolate * isolate,v8::Local<v8::StackTrace> handle)2477 CefV8StackTraceImpl::CefV8StackTraceImpl(v8::Isolate* isolate,
2478 v8::Local<v8::StackTrace> handle) {
2479 if (!handle.IsEmpty()) {
2480 int frame_count = handle->GetFrameCount();
2481 if (frame_count > 0) {
2482 frames_.reserve(frame_count);
2483 for (int i = 0; i < frame_count; ++i)
2484 frames_.push_back(
2485 new CefV8StackFrameImpl(isolate, handle->GetFrame(isolate, i)));
2486 }
2487 }
2488 }
2489
~CefV8StackTraceImpl()2490 CefV8StackTraceImpl::~CefV8StackTraceImpl() {}
2491
IsValid()2492 bool CefV8StackTraceImpl::IsValid() {
2493 return true;
2494 }
2495
GetFrameCount()2496 int CefV8StackTraceImpl::GetFrameCount() {
2497 return frames_.size();
2498 }
2499
GetFrame(int index)2500 CefRefPtr<CefV8StackFrame> CefV8StackTraceImpl::GetFrame(int index) {
2501 if (index < 0 || index >= static_cast<int>(frames_.size()))
2502 return nullptr;
2503 return frames_[index];
2504 }
2505
2506 // CefV8StackFrameImpl
2507
CefV8StackFrameImpl(v8::Isolate * isolate,v8::Local<v8::StackFrame> handle)2508 CefV8StackFrameImpl::CefV8StackFrameImpl(v8::Isolate* isolate,
2509 v8::Local<v8::StackFrame> handle)
2510 : line_number_(0), column_(0), is_eval_(false), is_constructor_(false) {
2511 if (handle.IsEmpty())
2512 return;
2513 GetCefString(isolate, handle->GetScriptName(), script_name_);
2514 GetCefString(isolate, handle->GetScriptNameOrSourceURL(),
2515 script_name_or_source_url_);
2516 GetCefString(isolate, handle->GetFunctionName(), function_name_);
2517 line_number_ = handle->GetLineNumber();
2518 column_ = handle->GetColumn();
2519 is_eval_ = handle->IsEval();
2520 is_constructor_ = handle->IsConstructor();
2521 }
2522
~CefV8StackFrameImpl()2523 CefV8StackFrameImpl::~CefV8StackFrameImpl() {}
2524
IsValid()2525 bool CefV8StackFrameImpl::IsValid() {
2526 return true;
2527 }
2528
GetScriptName()2529 CefString CefV8StackFrameImpl::GetScriptName() {
2530 return script_name_;
2531 }
2532
GetScriptNameOrSourceURL()2533 CefString CefV8StackFrameImpl::GetScriptNameOrSourceURL() {
2534 return script_name_or_source_url_;
2535 }
2536
GetFunctionName()2537 CefString CefV8StackFrameImpl::GetFunctionName() {
2538 return function_name_;
2539 }
2540
GetLineNumber()2541 int CefV8StackFrameImpl::GetLineNumber() {
2542 return line_number_;
2543 }
2544
GetColumn()2545 int CefV8StackFrameImpl::GetColumn() {
2546 return column_;
2547 }
2548
IsEval()2549 bool CefV8StackFrameImpl::IsEval() {
2550 return is_eval_;
2551 }
2552
IsConstructor()2553 bool CefV8StackFrameImpl::IsConstructor() {
2554 return is_constructor_;
2555 }
2556
2557 // Enable deprecation warnings on Windows. See http://crbug.com/585142.
2558 #if BUILDFLAG(IS_WIN)
2559 #if defined(__clang__)
2560 #pragma GCC diagnostic pop
2561 #else
2562 #pragma warning(pop)
2563 #endif
2564 #endif
2565