1 // Copyright 2021 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "pdf/post_message_receiver.h"
12 #include "base/check_op.h"
13 #include "base/functional/bind.h"
14 #include "base/location.h"
15 #include "base/memory/scoped_refptr.h"
16 #include "base/memory/weak_ptr.h"
17 #include "base/task/sequenced_task_runner.h"
18 #include "base/values.h"
19 #include "gin/function_template.h"
20 #include "gin/handle.h"
21 #include "gin/interceptor.h"
22 #include "gin/object_template_builder.h"
23 #include "gin/public/wrapper_info.h"
24 #include "gin/wrappable.h"
25 #include "pdf/v8_value_converter.h"
26 #include "v8/include/v8.h"
28 namespace chrome_pdf {
32 constexpr char kPropertyName[] = "postMessage";
37 gin::WrapperInfo PostMessageReceiver::kWrapperInfo = {gin::kEmbedderNativeGin};
40 v8::Local<v8::Object> PostMessageReceiver::Create(
42 base::WeakPtr<V8ValueConverter> v8_value_converter,
43 base::WeakPtr<Client> client,
44 scoped_refptr<base::SequencedTaskRunner> client_task_runner) {
45 return gin::CreateHandle(
46 isolate, new PostMessageReceiver(
47 isolate, std::move(v8_value_converter),
48 std::move(client), std::move(client_task_runner)))
53 PostMessageReceiver::~PostMessageReceiver() = default;
55 PostMessageReceiver::PostMessageReceiver(
57 base::WeakPtr<V8ValueConverter> v8_value_converter,
58 base::WeakPtr<Client> client,
59 scoped_refptr<base::SequencedTaskRunner> client_task_runner)
60 : gin::NamedPropertyInterceptor(isolate, this),
61 v8_value_converter_(std::move(v8_value_converter)),
63 client_(std::move(client)),
64 client_task_runner_(std::move(client_task_runner)) {}
66 gin::ObjectTemplateBuilder PostMessageReceiver::GetObjectTemplateBuilder(
67 v8::Isolate* isolate) {
68 // `gin::ObjectTemplateBuilder::SetMethod()` can't be used here because it
69 // would create a function template which expects the first parameter to a
70 // member function pointer to be the JavaScript `this` object corresponding
71 // to this scriptable object exposed through Blink. However, the actual
72 // receiving object for a plugin is an HTMLEmbedElement and Blink internally
73 // forwards the parameters to this scriptable object.
75 // Also, passing a callback would cause Gin to ignore the target. Because Gin
76 // creates the object template of a type only once per isolate, the member
77 // method of the first `PostMessageReceiver` instance would get effectively
78 // treated like a static method for all other instances.
80 // An interceptor allows for the creation of a function template per instance.
81 return gin::Wrappable<PostMessageReceiver>::GetObjectTemplateBuilder(isolate)
82 .AddNamedPropertyInterceptor();
85 const char* PostMessageReceiver::GetTypeName() {
86 return "ChromePdfPostMessageReceiver";
89 v8::Local<v8::Value> PostMessageReceiver::GetNamedProperty(
91 const std::string& property) {
92 DCHECK_EQ(isolate_, isolate);
94 if (property != kPropertyName)
95 return v8::Local<v8::Value>();
97 return GetFunctionTemplate()
98 ->GetFunction(isolate->GetCurrentContext())
102 std::vector<std::string> PostMessageReceiver::EnumerateNamedProperties(
103 v8::Isolate* isolate) {
104 DCHECK_EQ(isolate_, isolate);
105 return {kPropertyName};
108 v8::Local<v8::FunctionTemplate> PostMessageReceiver::GetFunctionTemplate() {
109 if (function_template_.IsEmpty()) {
110 function_template_.Reset(
112 gin::CreateFunctionTemplate(
113 isolate_, base::BindRepeating(&PostMessageReceiver::PostMessage,
114 weak_factory_.GetWeakPtr())));
117 return function_template_.Get(isolate_);
120 void PostMessageReceiver::PostMessage(v8::Local<v8::Value> message) {
121 if (!client_ || !v8_value_converter_)
124 std::unique_ptr<base::Value> converted_message =
125 v8_value_converter_->FromV8Value(message, isolate_->GetCurrentContext());
126 // The PDF Viewer UI should not be sending messages that cannot be converted.
127 DCHECK(converted_message);
128 DCHECK(converted_message->is_dict());
130 client_task_runner_->PostTask(
131 FROM_HERE, base::BindOnce(&Client::OnMessage, client_,
132 std::move(*converted_message).TakeDict()));
135 } // namespace chrome_pdf