| // Copyright 2019 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chromecast/renderer/native_bindings_helper.h" |
| |
| #include "base/logging.h" |
| #include "content/public/renderer/render_frame.h" |
| #include "gin/converter.h" |
| #include "third_party/blink/public/platform/scheduler/web_agent_group_scheduler.h" |
| #include "third_party/blink/public/web/web_local_frame.h" |
| |
| namespace chromecast { |
| |
| namespace { |
| const char kCastObjectName[] = "cast"; |
| const char kCastPlatformObjectKey[] = "__platform__"; |
| } // namespace |
| |
| v8::Local<v8::Object> GetOrCreateCastPlatformObject( |
| v8::Isolate* isolate, |
| v8::Local<v8::Object> global) { |
| v8::Local<v8::Object> cast = |
| EnsureObjectExists(isolate, global, kCastObjectName); |
| return EnsureObjectExists(isolate, cast, kCastPlatformObjectKey); |
| } |
| |
| v8::Local<v8::Object> EnsureObjectExists(v8::Isolate* isolate, |
| v8::Local<v8::Object> parent, |
| const std::string& key) { |
| v8::Local<v8::Context> context = isolate->GetCurrentContext(); |
| v8::MaybeLocal<v8::Value> child = |
| parent->Get(context, gin::StringToV8(isolate, key)); |
| v8::Local<v8::Value> child_local; |
| v8::Local<v8::Object> child_object; |
| if (child.ToLocal(&child_local) && child_local->IsObject() && |
| child_local->ToObject(context).ToLocal(&child_object)) |
| return child_object; |
| |
| if (!child_local.IsEmpty() && !child_local->IsUndefined()) |
| LOG(WARNING) << "Overwriting non-empty non-object with key " << key; |
| |
| v8::Local<v8::Object> new_child_object = v8::Object::New(isolate); |
| v8::Maybe<bool> result = |
| parent->Set(context, gin::StringToSymbol(isolate, key), new_child_object); |
| if (result.IsNothing() || !result.FromJust()) |
| LOG(ERROR) << "Failed to set new object with key " << key; |
| |
| return new_child_object; |
| } |
| |
| CastBinding::CastBinding(content::RenderFrame* render_frame) |
| : content::RenderFrameObserver(render_frame) {} |
| |
| CastBinding::~CastBinding() {} |
| |
| void CastBinding::DidClearWindowObject() { |
| TryInstall(); |
| } |
| |
| void CastBinding::OnDestruct() { |
| delete this; |
| } |
| |
| void CastBinding::TryInstall() { |
| blink::WebLocalFrame* web_frame = render_frame()->GetWebFrame(); |
| if (!web_frame) |
| return; |
| |
| v8::Isolate* isolate = web_frame->GetAgentGroupScheduler()->Isolate(); |
| if (!isolate) |
| return; |
| |
| // The HandleScope must be created before MainWorldScriptContext is called. |
| v8::HandleScope handle_scope(isolate); |
| v8::Local<v8::Context> context = web_frame->MainWorldScriptContext(); |
| v8::MicrotasksScope microtasks(context, |
| v8::MicrotasksScope::kDoNotRunMicrotasks); |
| if (context.IsEmpty()) |
| return; |
| |
| v8::Context::Scope context_scope(context); |
| v8::Local<v8::Object> global = context->Global(); |
| v8::Local<v8::Object> cast_platform = |
| GetOrCreateCastPlatformObject(isolate, global); |
| Install(cast_platform, isolate); |
| } |
| |
| } // namespace chromecast |