summaryrefslogtreecommitdiffstats
path: root/ppapi/cpp/module.cc
blob: 505991d6e58fd4151b94a2b53208cd2dcabe1343 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Note that the single accessor, Module::Get(), is not actually implemented
// in this file.  This is an intentional hook that allows users of ppapi's
// C++ wrapper objects to provide different semantics for how the singleton
// object is accessed.
//
// In general, users of ppapi will also link in ppp_entrypoints.cc, which
// provides a simple default implementation of Module::Get().
//
// A notable exception where the default ppp_entrypoints will not work is
// when implementing "internal plugins" that are statically linked into the
// browser. In this case, the process may actually have multiple Modules
// loaded at once making a traditional "singleton" unworkable.  To get around
// this, the users of ppapi need to get creative about how to properly
// implement the Module::Get() so that ppapi's C++ wrappers can find the
// right Module object.  One example solution is to use thread local storage
// to change the Module* returned based on which thread is invoking the
// function. Leaving Module::Get() unimplemented provides a hook for
// implementing such behavior.

#include "ppapi/cpp/module.h"

#include <string.h>

#include "ppapi/c/pp_instance.h"
#include "ppapi/c/pp_var.h"
#include "ppapi/c/ppp_input_event.h"
#include "ppapi/c/ppp_instance.h"
#include "ppapi/c/ppp_messaging.h"
#include "ppapi/cpp/input_event.h"
#include "ppapi/cpp/instance.h"
#include "ppapi/cpp/rect.h"
#include "ppapi/cpp/resource.h"
#include "ppapi/cpp/url_loader.h"
#include "ppapi/cpp/var.h"
#include "ppapi/cpp/view.h"

namespace pp {

// PPP_InputEvent implementation -----------------------------------------------

PP_Bool InputEvent_HandleEvent(PP_Instance pp_instance, PP_Resource resource) {
  Module* module_singleton = Module::Get();
  if (!module_singleton)
    return PP_FALSE;
  Instance* instance = module_singleton->InstanceForPPInstance(pp_instance);
  if (!instance)
    return PP_FALSE;

  return PP_FromBool(instance->HandleInputEvent(InputEvent(resource)));
}

const PPP_InputEvent input_event_interface = {
  &InputEvent_HandleEvent
};

// PPP_Instance implementation -------------------------------------------------

PP_Bool Instance_DidCreate(PP_Instance pp_instance,
                           uint32_t argc,
                           const char* argn[],
                           const char* argv[]) {
  Module* module_singleton = Module::Get();
  if (!module_singleton)
    return PP_FALSE;

  Instance* instance = module_singleton->CreateInstance(pp_instance);
  if (!instance)
    return PP_FALSE;
  module_singleton->current_instances_[pp_instance] = instance;
  return PP_FromBool(instance->Init(argc, argn, argv));
}

void Instance_DidDestroy(PP_Instance instance) {
  Module* module_singleton = Module::Get();
  if (!module_singleton)
    return;
  Module::InstanceMap::iterator found =
      module_singleton->current_instances_.find(instance);
  if (found == module_singleton->current_instances_.end())
    return;

  // Remove it from the map before deleting to try to catch reentrancy.
  Instance* obj = found->second;
  module_singleton->current_instances_.erase(found);
  delete obj;
}

void Instance_DidChangeView(PP_Instance pp_instance,
                            PP_Resource view_resource) {
  Module* module_singleton = Module::Get();
  if (!module_singleton)
    return;
  Instance* instance = module_singleton->InstanceForPPInstance(pp_instance);
  if (!instance)
    return;
  instance->DidChangeView(View(view_resource));
}

void Instance_DidChangeFocus(PP_Instance pp_instance, PP_Bool has_focus) {
  Module* module_singleton = Module::Get();
  if (!module_singleton)
    return;
  Instance* instance = module_singleton->InstanceForPPInstance(pp_instance);
  if (!instance)
    return;
  instance->DidChangeFocus(PP_ToBool(has_focus));
}

PP_Bool Instance_HandleDocumentLoad(PP_Instance pp_instance,
                                    PP_Resource pp_url_loader) {
  Module* module_singleton = Module::Get();
  if (!module_singleton)
    return PP_FALSE;
  Instance* instance = module_singleton->InstanceForPPInstance(pp_instance);
  if (!instance)
    return PP_FALSE;
  return PP_FromBool(instance->HandleDocumentLoad(URLLoader(pp_url_loader)));
}

static PPP_Instance instance_interface = {
  &Instance_DidCreate,
  &Instance_DidDestroy,
  &Instance_DidChangeView,
  &Instance_DidChangeFocus,
  &Instance_HandleDocumentLoad
};

// PPP_Messaging implementation ------------------------------------------------

void Messaging_HandleMessage(PP_Instance pp_instance, PP_Var var) {
  Module* module_singleton = Module::Get();
  if (!module_singleton)
    return;
  Instance* instance = module_singleton->InstanceForPPInstance(pp_instance);
  if (!instance)
    return;
  instance->HandleMessage(Var(PASS_REF, var));
}

static PPP_Messaging instance_messaging_interface = {
  &Messaging_HandleMessage
};

// Module ----------------------------------------------------------------------

Module::Module() : pp_module_(0), get_browser_interface_(NULL), core_(NULL) {
}

Module::~Module() {
  delete core_;
  core_ = NULL;
}

bool Module::Init() {
  return true;
}

const void* Module::GetPluginInterface(const char* interface_name) {
  if (strcmp(interface_name, PPP_INPUT_EVENT_INTERFACE) == 0)
    return &input_event_interface;
  if (strcmp(interface_name, PPP_INSTANCE_INTERFACE) == 0)
    return &instance_interface;
  if (strcmp(interface_name, PPP_MESSAGING_INTERFACE) == 0)
    return &instance_messaging_interface;

  // Now see if anything was dynamically registered.
  InterfaceMap::const_iterator found = additional_interfaces_.find(
      std::string(interface_name));
  if (found != additional_interfaces_.end())
    return found->second;

  return NULL;
}

const void* Module::GetBrowserInterface(const char* interface_name) {
  return get_browser_interface_(interface_name);
}

Instance* Module::InstanceForPPInstance(PP_Instance instance) {
  InstanceMap::iterator found = current_instances_.find(instance);
  if (found == current_instances_.end())
    return NULL;
  return found->second;
}

void Module::AddPluginInterface(const std::string& interface_name,
                                const void* vtable) {
  // Verify that we're not trying to register an interface that's already
  // handled, and if it is, that we're re-registering with the same vtable.
  // Calling GetPluginInterface rather than looking it up in the map allows
  // us to also catch "internal" ones in addition to just previously added ones.
  const void* existing_interface = GetPluginInterface(interface_name.c_str());
  if (existing_interface) {
    PP_DCHECK(vtable == existing_interface);
    return;
  }
  additional_interfaces_[interface_name] = vtable;
}

bool Module::InternalInit(PP_Module mod,
                          PPB_GetInterface get_browser_interface) {
  pp_module_ = mod;
  get_browser_interface_ = get_browser_interface;

  // Get the core interface which we require to run.
  const PPB_Core* core = reinterpret_cast<const PPB_Core*>(GetBrowserInterface(
      PPB_CORE_INTERFACE));
  if (!core)
    return false;
  core_ = new Core(core);

  return Init();
}

}  // namespace pp