1 // Copyright (c) 2011 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.
5 #include "webkit/plugins/ppapi/npapi_glue.h"
7 #include "base/logging.h"
8 #include "base/memory/ref_counted.h"
9 #include "base/string_util.h"
10 #include "webkit/plugins/ppapi/host_array_buffer_var.h"
11 #include "webkit/plugins/ppapi/host_globals.h"
12 #include "webkit/plugins/ppapi/host_var_tracker.h"
13 #include "webkit/plugins/ppapi/npobject_var.h"
14 #include "webkit/plugins/ppapi/plugin_module.h"
15 #include "webkit/plugins/ppapi/plugin_object.h"
16 #include "webkit/plugins/ppapi/ppapi_plugin_instance.h"
17 #include "third_party/npapi/bindings/npapi.h"
18 #include "third_party/npapi/bindings/npruntime.h"
19 #include "third_party/WebKit/Source/WebKit/chromium/public/WebBindings.h"
21 using ppapi::NPObjectVar
;
22 using ppapi::PpapiGlobals
;
23 using ppapi::StringVar
;
25 using WebKit::WebArrayBuffer
;
26 using WebKit::WebBindings
;
33 const char kInvalidPluginValue
[] = "Error: Plugin returned invalid value.";
37 // Utilities -------------------------------------------------------------------
39 bool PPVarToNPVariant(PP_Var var
, NPVariant
* result
) {
41 case PP_VARTYPE_UNDEFINED
:
42 VOID_TO_NPVARIANT(*result
);
45 NULL_TO_NPVARIANT(*result
);
48 BOOLEAN_TO_NPVARIANT(var
.value
.as_bool
, *result
);
50 case PP_VARTYPE_INT32
:
51 INT32_TO_NPVARIANT(var
.value
.as_int
, *result
);
53 case PP_VARTYPE_DOUBLE
:
54 DOUBLE_TO_NPVARIANT(var
.value
.as_double
, *result
);
56 case PP_VARTYPE_STRING
: {
57 StringVar
* string
= StringVar::FromPPVar(var
);
59 VOID_TO_NPVARIANT(*result
);
62 const std::string
& value
= string
->value();
63 char* c_string
= static_cast<char*>(malloc(value
.size()));
64 memcpy(c_string
, value
.data(), value
.size());
65 STRINGN_TO_NPVARIANT(c_string
, value
.size(), *result
);
68 case PP_VARTYPE_OBJECT
: {
69 scoped_refptr
<NPObjectVar
> object(NPObjectVar::FromPPVar(var
));
71 VOID_TO_NPVARIANT(*result
);
74 OBJECT_TO_NPVARIANT(WebBindings::retainObject(object
->np_object()),
78 // The following types are not supported for use with PPB_Var_Deprecated,
79 // because PPB_Var_Deprecated is only for trusted plugins, and the trusted
80 // plugins we have don't need these types. We can add support in the future
81 // if it becomes necessary.
82 case PP_VARTYPE_ARRAY
:
83 case PP_VARTYPE_DICTIONARY
:
84 case PP_VARTYPE_ARRAY_BUFFER
:
85 VOID_TO_NPVARIANT(*result
);
91 PP_Var
NPVariantToPPVar(PluginInstance
* instance
, const NPVariant
* variant
) {
92 switch (variant
->type
) {
93 case NPVariantType_Void
:
94 return PP_MakeUndefined();
95 case NPVariantType_Null
:
97 case NPVariantType_Bool
:
98 return PP_MakeBool(PP_FromBool(NPVARIANT_TO_BOOLEAN(*variant
)));
99 case NPVariantType_Int32
:
100 return PP_MakeInt32(NPVARIANT_TO_INT32(*variant
));
101 case NPVariantType_Double
:
102 return PP_MakeDouble(NPVARIANT_TO_DOUBLE(*variant
));
103 case NPVariantType_String
:
104 return StringVar::StringToPPVar(
105 NPVARIANT_TO_STRING(*variant
).UTF8Characters
,
106 NPVARIANT_TO_STRING(*variant
).UTF8Length
);
107 case NPVariantType_Object
:
108 return NPObjectToPPVar(instance
, NPVARIANT_TO_OBJECT(*variant
));
111 return PP_MakeUndefined();
114 NPIdentifier
PPVarToNPIdentifier(PP_Var var
) {
116 case PP_VARTYPE_STRING
: {
117 StringVar
* string
= StringVar::FromPPVar(var
);
120 return WebBindings::getStringIdentifier(string
->value().c_str());
122 case PP_VARTYPE_INT32
:
123 return WebBindings::getIntIdentifier(var
.value
.as_int
);
129 PP_Var
NPIdentifierToPPVar(NPIdentifier id
) {
130 const NPUTF8
* string_value
= NULL
;
131 int32_t int_value
= 0;
132 bool is_string
= false;
133 WebBindings::extractIdentifierData(id
, string_value
, int_value
, is_string
);
135 return StringVar::StringToPPVar(string_value
);
137 return PP_MakeInt32(int_value
);
140 PP_Var
NPObjectToPPVar(PluginInstance
* instance
, NPObject
* object
) {
142 WebArrayBuffer buffer
;
143 // TODO(dmichael): Should I protect against duplicate Vars representing the
144 // same array buffer? It's probably not worth the trouble, since it will only
145 // affect in-process plugins.
146 if (WebBindings::getArrayBuffer(object
, &buffer
)) {
147 scoped_refptr
<HostArrayBufferVar
> buffer_var(
148 new HostArrayBufferVar(buffer
));
149 return buffer_var
->GetPPVar();
151 scoped_refptr
<NPObjectVar
> object_var(
152 HostGlobals::Get()->host_var_tracker()->NPObjectVarForNPObject(
153 instance
->pp_instance(), object
));
154 if (!object_var
) { // No object for this module yet, make a new one.
155 object_var
= new NPObjectVar(instance
->pp_instance(), object
);
157 return object_var
->GetPPVar();
160 // PPResultAndExceptionToNPResult ----------------------------------------------
162 PPResultAndExceptionToNPResult::PPResultAndExceptionToNPResult(
163 NPObject
* object_var
,
164 NPVariant
* np_result
)
165 : object_var_(object_var
),
166 np_result_(np_result
),
167 exception_(PP_MakeUndefined()),
169 checked_exception_(false) {
172 PPResultAndExceptionToNPResult::~PPResultAndExceptionToNPResult() {
173 // The user should have called SetResult or CheckExceptionForNoResult
174 // before letting this class go out of scope, or the exception will have
176 DCHECK(checked_exception_
);
178 PpapiGlobals::Get()->GetVarTracker()->ReleaseVar(exception_
);
181 // Call this with the return value of the PPAPI function. It will convert
182 // the result to the NPVariant output parameter and pass any exception on to
183 // the JS engine. It will update the success flag and return it.
184 bool PPResultAndExceptionToNPResult::SetResult(PP_Var result
) {
185 DCHECK(!checked_exception_
); // Don't call more than once.
186 DCHECK(np_result_
); // Should be expecting a result.
188 checked_exception_
= true;
190 if (has_exception()) {
193 } else if (!PPVarToNPVariant(result
, np_result_
)) {
194 WebBindings::setException(object_var_
, kInvalidPluginValue
);
200 // No matter what happened, we need to release the reference to the
201 // value passed in. On success, a reference to this value will be in
203 PpapiGlobals::Get()->GetVarTracker()->ReleaseVar(result
);
207 // Call this after calling a PPAPI function that could have set the
208 // exception. It will pass the exception on to the JS engine and update
211 // The success flag will be returned.
212 bool PPResultAndExceptionToNPResult::CheckExceptionForNoResult() {
213 DCHECK(!checked_exception_
); // Don't call more than once.
214 DCHECK(!np_result_
); // Can't have a result when doing this.
216 checked_exception_
= true;
218 if (has_exception()) {
227 // Call this to ignore any exception. This prevents the DCHECK from failing
228 // in the destructor.
229 void PPResultAndExceptionToNPResult::IgnoreException() {
230 checked_exception_
= true;
233 // Throws the current exception to JS. The exception must be set.
234 void PPResultAndExceptionToNPResult::ThrowException() {
235 StringVar
* string
= StringVar::FromPPVar(exception_
);
237 WebBindings::setException(object_var_
, string
->value().c_str());
240 // PPVarArrayFromNPVariantArray ------------------------------------------------
242 PPVarArrayFromNPVariantArray::PPVarArrayFromNPVariantArray(
243 PluginInstance
* instance
,
245 const NPVariant
* variants
)
248 array_
.reset(new PP_Var
[size_
]);
249 for (size_t i
= 0; i
< size_
; i
++)
250 array_
[i
] = NPVariantToPPVar(instance
, &variants
[i
]);
254 PPVarArrayFromNPVariantArray::~PPVarArrayFromNPVariantArray() {
255 ::ppapi::VarTracker
* var_tracker
= PpapiGlobals::Get()->GetVarTracker();
256 for (size_t i
= 0; i
< size_
; i
++)
257 var_tracker
->ReleaseVar(array_
[i
]);
260 // PPVarFromNPObject -----------------------------------------------------------
262 PPVarFromNPObject::PPVarFromNPObject(PluginInstance
* instance
, NPObject
* object
)
263 : var_(NPObjectToPPVar(instance
, object
)) {
266 PPVarFromNPObject::~PPVarFromNPObject() {
267 PpapiGlobals::Get()->GetVarTracker()->ReleaseVar(var_
);
270 // NPObjectAccessorWithIdentifier ----------------------------------------------
272 NPObjectAccessorWithIdentifier::NPObjectAccessorWithIdentifier(
274 NPIdentifier identifier
,
275 bool allow_integer_identifier
)
276 : object_(PluginObject::FromNPObject(object
)),
277 identifier_(PP_MakeUndefined()) {
279 identifier_
= NPIdentifierToPPVar(identifier
);
280 if (identifier_
.type
== PP_VARTYPE_INT32
&& !allow_integer_identifier
)
281 identifier_
.type
= PP_VARTYPE_UNDEFINED
; // Mark it invalid.
285 NPObjectAccessorWithIdentifier::~NPObjectAccessorWithIdentifier() {
286 PpapiGlobals::Get()->GetVarTracker()->ReleaseVar(identifier_
);
289 // TryCatch --------------------------------------------------------------------
291 TryCatch::TryCatch(PP_Var
* exception
)
292 : has_exception_(exception
&& exception
->type
!= PP_VARTYPE_UNDEFINED
),
293 exception_(exception
) {
294 WebBindings::pushExceptionHandler(&TryCatch::Catch
, this);
297 TryCatch::~TryCatch() {
298 WebBindings::popExceptionHandler();
301 void TryCatch::SetException(const char* message
) {
302 if (!has_exception()) {
303 has_exception_
= true;
305 *exception_
= ::ppapi::StringVar::StringToPPVar(message
, strlen(message
));
311 void TryCatch::Catch(void* self
, const char* message
) {
312 static_cast<TryCatch
*>(self
)->SetException(message
);
316 } // namespace webkit