post_message_receiver.cc 4.5 KB

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