OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "webkit/glue/plugins/pepper_var.h" | 5 #include "webkit/glue/plugins/pepper_var.h" |
6 | 6 |
7 #include "base/logging.h" | 7 #include "base/logging.h" |
8 #include "base/scoped_ptr.h" | 8 #include "base/scoped_ptr.h" |
9 #include "base/string_util.h" | 9 #include "base/string_util.h" |
10 #include "third_party/ppapi/c/pp_var.h" | 10 #include "third_party/ppapi/c/pp_var.h" |
11 #include "third_party/ppapi/c/ppb_var.h" | 11 #include "third_party/ppapi/c/ppb_var.h" |
| 12 #include "third_party/ppapi/c/ppp_class.h" |
12 #include "third_party/WebKit/WebKit/chromium/public/WebBindings.h" | 13 #include "third_party/WebKit/WebKit/chromium/public/WebBindings.h" |
13 #include "webkit/glue/plugins/pepper_string.h" | 14 #include "webkit/glue/plugins/pepper_string.h" |
14 #include "v8/include/v8.h" | 15 #include "v8/include/v8.h" |
15 | 16 |
16 // Uncomment to enable catching JS exceptions | 17 // Uncomment to enable catching JS exceptions |
17 // #define HAVE_WEBBINDINGS_EXCEPTION_HANDLER 1 | 18 // #define HAVE_WEBBINDINGS_EXCEPTION_HANDLER 1 |
18 | 19 |
19 using WebKit::WebBindings; | 20 using WebKit::WebBindings; |
20 | 21 |
21 namespace pepper { | 22 namespace pepper { |
22 | 23 |
23 namespace { | 24 namespace { |
24 | 25 |
| 26 void Release(PP_Var var); |
25 PP_Var VarFromUtf8(const char* data, uint32_t len); | 27 PP_Var VarFromUtf8(const char* data, uint32_t len); |
26 | 28 |
27 // --------------------------------------------------------------------------- | 29 // --------------------------------------------------------------------------- |
28 // Exceptions | 30 // Exceptions |
29 | 31 |
30 class TryCatch { | 32 class TryCatch { |
31 public: | 33 public: |
32 TryCatch(PP_Var* exception) : exception_(exception) { | 34 TryCatch(PP_Var* exception) : exception_(exception) { |
33 #ifdef HAVE_WEBBINDINGS_EXCEPTION_HANDLER | 35 #ifdef HAVE_WEBBINDINGS_EXCEPTION_HANDLER |
34 WebBindings::pushExceptionHandler(&TryCatch::Catch, this); | 36 WebBindings::pushExceptionHandler(&TryCatch::Catch, this); |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
71 const char kUnableToCallMethodException[] = "Error: Unable to call method"; | 73 const char kUnableToCallMethodException[] = "Error: Unable to call method"; |
72 const char kUnableToConstructException[] = "Error: Unable to construct"; | 74 const char kUnableToConstructException[] = "Error: Unable to construct"; |
73 | 75 |
74 // --------------------------------------------------------------------------- | 76 // --------------------------------------------------------------------------- |
75 // Utilities | 77 // Utilities |
76 | 78 |
77 String* GetStringUnchecked(PP_Var var) { | 79 String* GetStringUnchecked(PP_Var var) { |
78 return reinterpret_cast<String*>(var.value.as_id); | 80 return reinterpret_cast<String*>(var.value.as_id); |
79 } | 81 } |
80 | 82 |
| 83 String* GetString(PP_Var var) { |
| 84 if (var.type != PP_VarType_String) |
| 85 return NULL; |
| 86 return GetStringUnchecked(var); |
| 87 } |
| 88 |
81 NPObject* GetNPObjectUnchecked(PP_Var var) { | 89 NPObject* GetNPObjectUnchecked(PP_Var var) { |
82 return reinterpret_cast<NPObject*>(var.value.as_id); | 90 return reinterpret_cast<NPObject*>(var.value.as_id); |
83 } | 91 } |
84 | 92 |
85 NPObject* GetNPObject(PP_Var var) { | 93 NPObject* GetNPObject(PP_Var var) { |
86 if (var.type != PP_VarType_Object) | 94 if (var.type != PP_VarType_Object) |
87 return NULL; | 95 return NULL; |
88 return GetNPObjectUnchecked(var); | 96 return GetNPObjectUnchecked(var); |
89 } | 97 } |
90 | 98 |
91 // Returns a PP_Var that corresponds to the given NPVariant. The contents of | 99 // Returns a PP_Var that corresponds to the given NPVariant. The contents of |
92 // the NPVariant will be copied unless the NPVariant corresponds to an object. | 100 // the NPVariant will be copied unless the NPVariant corresponds to an object. |
93 PP_Var NPVariantToPPVar(NPVariant* variant) { | 101 PP_Var NPVariantToPPVar(const NPVariant* variant) { |
94 switch (variant->type) { | 102 switch (variant->type) { |
95 case NPVariantType_Void: | 103 case NPVariantType_Void: |
96 return PP_MakeVoid(); | 104 return PP_MakeVoid(); |
97 case NPVariantType_Null: | 105 case NPVariantType_Null: |
98 return PP_MakeNull(); | 106 return PP_MakeNull(); |
99 case NPVariantType_Bool: | 107 case NPVariantType_Bool: |
100 return PP_MakeBool(NPVARIANT_TO_BOOLEAN(*variant)); | 108 return PP_MakeBool(NPVARIANT_TO_BOOLEAN(*variant)); |
101 case NPVariantType_Int32: | 109 case NPVariantType_Int32: |
102 return PP_MakeInt32(NPVARIANT_TO_INT32(*variant)); | 110 return PP_MakeInt32(NPVARIANT_TO_INT32(*variant)); |
103 case NPVariantType_Double: | 111 case NPVariantType_Double: |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
188 case PP_VarType_String: | 196 case PP_VarType_String: |
189 return WebBindings::getStringIdentifier( | 197 return WebBindings::getStringIdentifier( |
190 GetStringUnchecked(var)->value().c_str()); | 198 GetStringUnchecked(var)->value().c_str()); |
191 case PP_VarType_Int32: | 199 case PP_VarType_Int32: |
192 return WebBindings::getIntIdentifier(var.value.as_int); | 200 return WebBindings::getIntIdentifier(var.value.as_int); |
193 default: | 201 default: |
194 return NULL; | 202 return NULL; |
195 } | 203 } |
196 } | 204 } |
197 | 205 |
| 206 PP_Var NPIdentifierToPPVar(NPIdentifier id) { |
| 207 const NPUTF8* string_value = NULL; |
| 208 int32_t int_value = 0; |
| 209 bool is_string = false; |
| 210 WebBindings::extractIdentifierData(id, string_value, int_value, is_string); |
| 211 if (is_string) |
| 212 return VarFromUtf8(string_value, strlen(string_value)); |
| 213 |
| 214 return PP_MakeInt32(int_value); |
| 215 } |
| 216 |
| 217 PP_Var NPIdentifierToPPVarString(NPIdentifier id) { |
| 218 PP_Var var = NPIdentifierToPPVar(id); |
| 219 if (var.type == PP_VarType_String) |
| 220 return var; |
| 221 DCHECK(var.type == PP_VarType_Int32); |
| 222 const std::string& str = IntToString(var.value.as_int); |
| 223 return VarFromUtf8(str.data(), str.size()); |
| 224 } |
| 225 |
| 226 void ThrowException(NPObject* object, PP_Var exception) { |
| 227 String* str = GetString(exception); |
| 228 if (str) |
| 229 WebBindings::setException(object, str->value().c_str()); |
| 230 } |
| 231 |
| 232 // --------------------------------------------------------------------------- |
| 233 // NPObject implementation in terms of PPP_Class |
| 234 |
| 235 struct WrapperObject : NPObject { |
| 236 const PPP_Class* ppp_class; |
| 237 void* ppp_class_data; |
| 238 }; |
| 239 |
| 240 static WrapperObject* ToWrapper(NPObject* object) { |
| 241 return static_cast<WrapperObject*>(object); |
| 242 } |
| 243 |
| 244 NPObject* WrapperClass_Allocate(NPP npp, NPClass* unused) { |
| 245 return new WrapperObject; |
| 246 } |
| 247 |
| 248 void WrapperClass_Deallocate(NPObject* object) { |
| 249 WrapperObject* wrapper = ToWrapper(object); |
| 250 wrapper->ppp_class->Deallocate(wrapper->ppp_class_data); |
| 251 delete object; |
| 252 } |
| 253 |
| 254 void WrapperClass_Invalidate(NPObject* object) { |
| 255 // TODO(darin): Do I need to do something here? |
| 256 } |
| 257 |
| 258 bool WrapperClass_HasMethod(NPObject* object, NPIdentifier method_name) { |
| 259 WrapperObject* wrapper = ToWrapper(object); |
| 260 |
| 261 PP_Var method_name_var = NPIdentifierToPPVarString(method_name); |
| 262 PP_Var exception = PP_MakeVoid(); |
| 263 bool rv = wrapper->ppp_class->HasMethod(wrapper->ppp_class_data, |
| 264 method_name_var, |
| 265 &exception); |
| 266 Release(method_name_var); |
| 267 |
| 268 if (exception.type != PP_VarType_Void) { |
| 269 ThrowException(object, exception); |
| 270 Release(exception); |
| 271 return false; |
| 272 } |
| 273 return rv; |
| 274 } |
| 275 |
| 276 bool WrapperClass_Invoke(NPObject* object, NPIdentifier method_name, |
| 277 const NPVariant* argv, uint32_t argc, |
| 278 NPVariant* result) { |
| 279 WrapperObject* wrapper = ToWrapper(object); |
| 280 |
| 281 scoped_array<PP_Var> args; |
| 282 if (argc) { |
| 283 args.reset(new PP_Var[argc]); |
| 284 for (uint32_t i = 0; i < argc; ++i) |
| 285 args[i] = NPVariantToPPVar(&argv[i]); |
| 286 } |
| 287 PP_Var method_name_var = NPIdentifierToPPVarString(method_name); |
| 288 PP_Var exception = PP_MakeVoid(); |
| 289 PP_Var result_var = wrapper->ppp_class->Call(wrapper->ppp_class_data, |
| 290 method_name_var, argc, |
| 291 args.get(), &exception); |
| 292 Release(method_name_var); |
| 293 for (uint32_t i = 0; i < argc; ++i) |
| 294 Release(args[i]); |
| 295 |
| 296 bool rv; |
| 297 if (exception.type == PP_VarType_Void) { |
| 298 rv = true; |
| 299 *result = PPVarToNPVariant(result_var); |
| 300 } else { |
| 301 rv = false; |
| 302 ThrowException(object, exception); |
| 303 Release(exception); |
| 304 } |
| 305 Release(result_var); |
| 306 return rv; |
| 307 } |
| 308 |
| 309 bool WrapperClass_InvokeDefault(NPObject* object, const NPVariant* argv, |
| 310 uint32_t argc, NPVariant* result) { |
| 311 WrapperObject* wrapper = ToWrapper(object); |
| 312 |
| 313 scoped_array<PP_Var> args; |
| 314 if (argc) { |
| 315 args.reset(new PP_Var[argc]); |
| 316 for (uint32_t i = 0; i < argc; ++i) |
| 317 args[i] = NPVariantToPPVar(&argv[i]); |
| 318 } |
| 319 PP_Var exception = PP_MakeVoid(); |
| 320 PP_Var result_var = wrapper->ppp_class->Call(wrapper->ppp_class_data, |
| 321 PP_MakeVoid(), argc, args.get(), |
| 322 &exception); |
| 323 for (uint32_t i = 0; i < argc; ++i) |
| 324 Release(args[i]); |
| 325 |
| 326 bool rv; |
| 327 if (exception.type == PP_VarType_Void) { |
| 328 rv = true; |
| 329 *result = PPVarToNPVariant(result_var); |
| 330 } else { |
| 331 rv = false; |
| 332 ThrowException(object, exception); |
| 333 Release(exception); |
| 334 } |
| 335 Release(result_var); |
| 336 return rv; |
| 337 } |
| 338 |
| 339 bool WrapperClass_HasProperty(NPObject* object, NPIdentifier property_name) { |
| 340 WrapperObject* wrapper = ToWrapper(object); |
| 341 |
| 342 PP_Var property_name_var = NPIdentifierToPPVar(property_name); |
| 343 PP_Var exception = PP_MakeVoid(); |
| 344 bool rv = wrapper->ppp_class->HasProperty(wrapper->ppp_class_data, |
| 345 property_name_var, |
| 346 &exception); |
| 347 Release(property_name_var); |
| 348 |
| 349 if (exception.type != PP_VarType_Void) { |
| 350 ThrowException(object, exception); |
| 351 Release(exception); |
| 352 return false; |
| 353 } |
| 354 return rv; |
| 355 } |
| 356 |
| 357 bool WrapperClass_GetProperty(NPObject* object, NPIdentifier property_name, |
| 358 NPVariant* result) { |
| 359 WrapperObject* wrapper = ToWrapper(object); |
| 360 |
| 361 PP_Var property_name_var = NPIdentifierToPPVar(property_name); |
| 362 PP_Var exception = PP_MakeVoid(); |
| 363 PP_Var result_var = wrapper->ppp_class->GetProperty(wrapper->ppp_class_data, |
| 364 property_name_var, |
| 365 &exception); |
| 366 Release(property_name_var); |
| 367 |
| 368 bool rv; |
| 369 if (exception.type == PP_VarType_Void) { |
| 370 rv = true; |
| 371 *result = PPVarToNPVariant(result_var); |
| 372 } else { |
| 373 rv = false; |
| 374 ThrowException(object, exception); |
| 375 Release(exception); |
| 376 } |
| 377 Release(result_var); |
| 378 return rv; |
| 379 } |
| 380 |
| 381 bool WrapperClass_SetProperty(NPObject* object, NPIdentifier property_name, |
| 382 const NPVariant* value) { |
| 383 WrapperObject* wrapper = ToWrapper(object); |
| 384 |
| 385 PP_Var property_name_var = NPIdentifierToPPVar(property_name); |
| 386 PP_Var value_var = NPVariantToPPVar(value); |
| 387 PP_Var exception = PP_MakeVoid(); |
| 388 wrapper->ppp_class->SetProperty(wrapper->ppp_class_data, property_name_var, |
| 389 value_var, &exception); |
| 390 Release(value_var); |
| 391 Release(property_name_var); |
| 392 |
| 393 if (exception.type != PP_VarType_Void) { |
| 394 ThrowException(object, exception); |
| 395 Release(exception); |
| 396 return false; |
| 397 } |
| 398 return true; |
| 399 } |
| 400 |
| 401 bool WrapperClass_RemoveProperty(NPObject* object, NPIdentifier property_name) { |
| 402 WrapperObject* wrapper = ToWrapper(object); |
| 403 |
| 404 PP_Var property_name_var = NPIdentifierToPPVar(property_name); |
| 405 PP_Var exception = PP_MakeVoid(); |
| 406 wrapper->ppp_class->RemoveProperty(wrapper->ppp_class_data, property_name_var, |
| 407 &exception); |
| 408 Release(property_name_var); |
| 409 |
| 410 if (exception.type != PP_VarType_Void) { |
| 411 ThrowException(object, exception); |
| 412 Release(exception); |
| 413 return false; |
| 414 } |
| 415 return true; |
| 416 } |
| 417 |
| 418 bool WrapperClass_Enumerate(NPObject* object, NPIdentifier** values, |
| 419 uint32_t* count) { |
| 420 // TODO(darin): Implement this method! |
| 421 WebBindings::setException(object, kUnableToGetAllPropertiesException); |
| 422 return false; |
| 423 } |
| 424 |
| 425 bool WrapperClass_Construct(NPObject* object, const NPVariant* argv, |
| 426 uint32_t argc, NPVariant* result) { |
| 427 WrapperObject* wrapper = ToWrapper(object); |
| 428 |
| 429 scoped_array<PP_Var> args; |
| 430 if (argc) { |
| 431 args.reset(new PP_Var[argc]); |
| 432 for (uint32_t i = 0; i < argc; ++i) |
| 433 args[i] = NPVariantToPPVar(&argv[i]); |
| 434 } |
| 435 |
| 436 PP_Var exception = PP_MakeVoid(); |
| 437 PP_Var result_var = wrapper->ppp_class->Construct(wrapper->ppp_class_data, |
| 438 argc, args.get(), |
| 439 &exception); |
| 440 for (uint32_t i = 0; i < argc; ++i) |
| 441 Release(args[i]); |
| 442 |
| 443 bool rv; |
| 444 if (exception.type == PP_VarType_Void) { |
| 445 rv = true; |
| 446 *result = PPVarToNPVariant(result_var); |
| 447 } else { |
| 448 rv = false; |
| 449 ThrowException(object, exception); |
| 450 Release(exception); |
| 451 } |
| 452 Release(result_var); |
| 453 return rv; |
| 454 } |
| 455 |
| 456 const NPClass wrapper_class = { |
| 457 NP_CLASS_STRUCT_VERSION, |
| 458 WrapperClass_Allocate, |
| 459 WrapperClass_Deallocate, |
| 460 WrapperClass_Invalidate, |
| 461 WrapperClass_HasMethod, |
| 462 WrapperClass_Invoke, |
| 463 WrapperClass_InvokeDefault, |
| 464 WrapperClass_HasProperty, |
| 465 WrapperClass_GetProperty, |
| 466 WrapperClass_SetProperty, |
| 467 WrapperClass_RemoveProperty, |
| 468 WrapperClass_Enumerate, |
| 469 WrapperClass_Construct |
| 470 }; |
| 471 |
198 // --------------------------------------------------------------------------- | 472 // --------------------------------------------------------------------------- |
199 // PPB_Var methods | 473 // PPB_Var methods |
200 | 474 |
201 void AddRef(PP_Var var) { | 475 void AddRef(PP_Var var) { |
202 if (var.type == PP_VarType_String) { | 476 if (var.type == PP_VarType_String) { |
203 GetStringUnchecked(var)->AddRef(); | 477 GetStringUnchecked(var)->AddRef(); |
204 } else if (var.type == PP_VarType_Object) { | 478 } else if (var.type == PP_VarType_Object) { |
205 // TODO(darin): Add thread safety check | 479 // TODO(darin): Add thread safety check |
206 WebBindings::retainObject(GetNPObjectUnchecked(var)); | 480 WebBindings::retainObject(GetNPObjectUnchecked(var)); |
207 } | 481 } |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
252 | 526 |
253 NPIdentifier identifier = PPVarToNPIdentifier(name); | 527 NPIdentifier identifier = PPVarToNPIdentifier(name); |
254 if (!identifier) { | 528 if (!identifier) { |
255 try_catch.SetException(kInvalidPropertyException); | 529 try_catch.SetException(kInvalidPropertyException); |
256 return false; | 530 return false; |
257 } | 531 } |
258 | 532 |
259 return WebBindings::hasProperty(NULL, object, identifier); | 533 return WebBindings::hasProperty(NULL, object, identifier); |
260 } | 534 } |
261 | 535 |
| 536 bool HasMethod(PP_Var var, |
| 537 PP_Var name, |
| 538 PP_Var* exception) { |
| 539 TryCatch try_catch(exception); |
| 540 if (try_catch.HasException()) |
| 541 return false; |
| 542 |
| 543 NPObject* object = GetNPObject(var); |
| 544 if (!object) { |
| 545 try_catch.SetException(kInvalidObjectException); |
| 546 return false; |
| 547 } |
| 548 |
| 549 NPIdentifier identifier = PPVarToNPIdentifier(name); |
| 550 if (!identifier) { |
| 551 try_catch.SetException(kInvalidPropertyException); |
| 552 return false; |
| 553 } |
| 554 |
| 555 return WebBindings::hasMethod(NULL, object, identifier); |
| 556 } |
| 557 |
262 PP_Var GetProperty(PP_Var var, | 558 PP_Var GetProperty(PP_Var var, |
263 PP_Var name, | 559 PP_Var name, |
264 PP_Var* exception) { | 560 PP_Var* exception) { |
265 TryCatch try_catch(exception); | 561 TryCatch try_catch(exception); |
266 if (try_catch.HasException()) | 562 if (try_catch.HasException()) |
267 return PP_MakeVoid(); | 563 return PP_MakeVoid(); |
268 | 564 |
269 NPObject* object = GetNPObject(var); | 565 NPObject* object = GetNPObject(var); |
270 if (!object) { | 566 if (!object) { |
271 try_catch.SetException(kInvalidObjectException); | 567 try_catch.SetException(kInvalidObjectException); |
(...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
437 if (!try_catch.HasException()) | 733 if (!try_catch.HasException()) |
438 try_catch.SetException(kUnableToConstructException); | 734 try_catch.SetException(kUnableToConstructException); |
439 return PP_MakeVoid(); | 735 return PP_MakeVoid(); |
440 } | 736 } |
441 | 737 |
442 PP_Var ret = NPVariantToPPVar(&result); | 738 PP_Var ret = NPVariantToPPVar(&result); |
443 WebBindings::releaseVariantValue(&result); | 739 WebBindings::releaseVariantValue(&result); |
444 return ret; | 740 return ret; |
445 } | 741 } |
446 | 742 |
447 PP_Var CreateObject(const PPP_Class* object_class, | 743 bool IsInstanceOf(PP_Var var, const PPP_Class* ppp_class, |
448 void* object_data) { | 744 void** ppp_class_data) { |
449 return PP_MakeVoid(); // TODO(darin): Implement this method! | 745 NPObject* object = GetNPObject(var); |
| 746 if (!object) |
| 747 return false; |
| 748 |
| 749 if (object->_class != &wrapper_class) |
| 750 return false; |
| 751 |
| 752 WrapperObject* wrapper = ToWrapper(object); |
| 753 if (wrapper->ppp_class != ppp_class) |
| 754 return false; |
| 755 |
| 756 if (ppp_class_data) |
| 757 *ppp_class_data = wrapper->ppp_class_data; |
| 758 return true; |
| 759 } |
| 760 |
| 761 PP_Var CreateObject(const PPP_Class* ppp_class, void* ppp_class_data) { |
| 762 NPObject* object = |
| 763 WebBindings::createObject(NULL, const_cast<NPClass*>(&wrapper_class)); |
| 764 static_cast<WrapperObject*>(object)->ppp_class = ppp_class; |
| 765 static_cast<WrapperObject*>(object)->ppp_class_data = ppp_class_data; |
| 766 PP_Var ret = NPObjectToPPVar(object); |
| 767 WebBindings::releaseObject(object); // Release reference from createObject |
| 768 return ret; |
450 } | 769 } |
451 | 770 |
452 const PPB_Var var_interface = { | 771 const PPB_Var var_interface = { |
453 &AddRef, | 772 &AddRef, |
454 &Release, | 773 &Release, |
455 &VarFromUtf8, | 774 &VarFromUtf8, |
456 &VarToUtf8, | 775 &VarToUtf8, |
457 &HasProperty, | 776 &HasProperty, |
| 777 &HasMethod, |
458 &GetProperty, | 778 &GetProperty, |
459 &GetAllPropertyNames, | 779 &GetAllPropertyNames, |
460 &SetProperty, | 780 &SetProperty, |
461 &RemoveProperty, | 781 &RemoveProperty, |
462 &Call, | 782 &Call, |
463 &Construct, | 783 &Construct, |
| 784 &IsInstanceOf, |
464 &CreateObject | 785 &CreateObject |
465 }; | 786 }; |
466 | 787 |
467 } // namespace | 788 } // namespace |
468 | 789 |
469 const PPB_Var* GetVarInterface() { | 790 const PPB_Var* GetVarInterface() { |
470 return &var_interface; | 791 return &var_interface; |
471 } | 792 } |
472 | 793 |
473 PP_Var NPObjectToPPVar(NPObject* object) { | 794 PP_Var NPObjectToPPVar(NPObject* object) { |
474 PP_Var ret; | 795 PP_Var ret; |
475 ret.type = PP_VarType_Object; | 796 ret.type = PP_VarType_Object; |
476 ret.value.as_id = reinterpret_cast<intptr_t>(object); | 797 ret.value.as_id = reinterpret_cast<intptr_t>(object); |
477 WebBindings::retainObject(object); | 798 WebBindings::retainObject(object); |
478 return ret; | 799 return ret; |
479 } | 800 } |
480 | 801 |
481 } // namespace pepper | 802 } // namespace pepper |
OLD | NEW |