1868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "content/child/npapi/npobject_stub.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "content/child/npapi/np_channel_base.h" 8ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "content/child/npapi/npobject_util.h" 9868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "content/child/plugin_messages.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/common/content_client.h" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/common/content_switches.h" 127d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "third_party/WebKit/public/web/WebBindings.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "third_party/npapi/bindings/npapi.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "third_party/npapi/bindings/npruntime.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN) 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/command_line.h" 18ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "content/common/plugin_constants_win.h" 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 21f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)using blink::WebBindings; 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace content { 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)NPObjectStub::NPObjectStub( 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NPObject* npobject, 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NPChannelBase* channel, 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int route_id, 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int render_view_id, 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const GURL& page_url) 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : npobject_(npobject), 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) channel_(channel), 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) route_id_(route_id), 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) render_view_id_(render_view_id), 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) page_url_(page_url) { 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) channel_->AddMappingForNPObjectStub(route_id, npobject); 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) channel_->AddRoute(route_id, this, this); 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We retain the object just as PluginHost does if everything was in-process. 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WebBindings::retainObject(npobject_); 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)NPObjectStub::~NPObjectStub() { 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) channel_->RemoveRoute(route_id_); 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!npobject_); 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NPObjectStub::DeleteSoon() { 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (npobject_) { 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) channel_->RemoveMappingForNPObjectStub(route_id_, npobject_); 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We need to NULL npobject_ prior to calling releaseObject() to avoid 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // problems with re-entrancy. See http://crbug.com/94179#c17 for more 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // details on how this can happen. 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NPObject* npobject = npobject_; 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) npobject_ = NULL; 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WebBindings::releaseObject(npobject); 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 60c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) base::MessageLoop::current()->DeleteSoon(FROM_HERE, this); 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool NPObjectStub::Send(IPC::Message* msg) { 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return channel_->Send(msg); 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)NPObject* NPObjectStub::GetUnderlyingNPObject() { 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return npobject_; 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)IPC::Listener* NPObjectStub::GetChannelListener() { 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return static_cast<IPC::Listener*>(this); 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool NPObjectStub::OnMessageReceived(const IPC::Message& msg) { 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetContentClient()->SetActiveURL(page_url_); 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!npobject_) { 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (msg.is_sync()) { 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The object could be garbage because the frame has gone away, so 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // just send an error reply to the caller. 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IPC::Message* reply = IPC::SyncMessage::GenerateReply(&msg); 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reply->set_reply_error(); 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Send(reply); 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool handled = true; 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IPC_BEGIN_MESSAGE_MAP(NPObjectStub, msg) 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IPC_MESSAGE_HANDLER_DELAY_REPLY(NPObjectMsg_Release, OnRelease); 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IPC_MESSAGE_HANDLER(NPObjectMsg_HasMethod, OnHasMethod); 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IPC_MESSAGE_HANDLER_DELAY_REPLY(NPObjectMsg_Invoke, OnInvoke); 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IPC_MESSAGE_HANDLER(NPObjectMsg_HasProperty, OnHasProperty); 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IPC_MESSAGE_HANDLER(NPObjectMsg_GetProperty, OnGetProperty); 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IPC_MESSAGE_HANDLER_DELAY_REPLY(NPObjectMsg_SetProperty, OnSetProperty); 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IPC_MESSAGE_HANDLER(NPObjectMsg_RemoveProperty, OnRemoveProperty); 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IPC_MESSAGE_HANDLER(NPObjectMsg_Invalidate, OnInvalidate); 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IPC_MESSAGE_HANDLER(NPObjectMsg_Enumeration, OnEnumeration); 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IPC_MESSAGE_HANDLER_DELAY_REPLY(NPObjectMsg_Construct, OnConstruct); 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IPC_MESSAGE_HANDLER_DELAY_REPLY(NPObjectMsg_Evaluate, OnEvaluate); 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IPC_MESSAGE_UNHANDLED(handled = false) 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IPC_END_MESSAGE_MAP() 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(handled); 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return handled; 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NPObjectStub::OnChannelError() { 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DeleteSoon(); 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NPObjectStub::OnRelease(IPC::Message* reply_msg) { 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Send(reply_msg); 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DeleteSoon(); 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NPObjectStub::OnHasMethod(const NPIdentifier_Param& name, 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool* result) { 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NPIdentifier id = CreateNPIdentifier(name); 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If we're in the plugin process, then the stub is holding onto an NPObject 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // from the plugin, so all function calls on it need to go through the 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // functions in NPClass. If we're in the renderer process, then we just call 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the NPN_ functions. 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (IsPluginProcess()) { 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (npobject_->_class->hasMethod) { 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *result = npobject_->_class->hasMethod(npobject_, id); 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *result = false; 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *result = WebBindings::hasMethod(0, npobject_, id); 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NPObjectStub::OnInvoke(bool is_default, 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const NPIdentifier_Param& method, 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::vector<NPVariant_Param>& args, 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IPC::Message* reply_msg) { 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool return_value = false; 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NPVariant_Param result_param; 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NPVariant result_var; 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VOID_TO_NPVARIANT(result_var); 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result_param.type = NPVARIANT_PARAM_VOID; 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int arg_count = static_cast<int>(args.size()); 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NPVariant* args_var = new NPVariant[arg_count]; 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < arg_count; ++i) { 150868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (!CreateNPVariant(args[i], 151868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) channel_.get(), 152868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) &(args_var[i]), 153868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) render_view_id_, 154868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) page_url_)) { 155868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) NPObjectMsg_Invoke::WriteReplyParams( 156868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) reply_msg, result_param, return_value); 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) channel_->Send(reply_msg); 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) delete[] args_var; 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (is_default) { 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (IsPluginProcess()) { 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (npobject_->_class->invokeDefault) { 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return_value = npobject_->_class->invokeDefault( 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) npobject_, args_var, arg_count, &result_var); 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return_value = false; 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return_value = WebBindings::invokeDefault( 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 0, npobject_, args_var, arg_count, &result_var); 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NPIdentifier id = CreateNPIdentifier(method); 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (IsPluginProcess()) { 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (npobject_->_class->invoke) { 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return_value = npobject_->_class->invoke( 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) npobject_, id, args_var, arg_count, &result_var); 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return_value = false; 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return_value = WebBindings::invoke( 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 0, npobject_, id, args_var, arg_count, &result_var); 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < arg_count; ++i) 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WebBindings::releaseVariantValue(&(args_var[i])); 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) delete[] args_var; 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 195868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) CreateNPVariantParam(result_var, 196868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) channel_.get(), 197868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) &result_param, 198868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) true, 199868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) render_view_id_, 200868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) page_url_); 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NPObjectMsg_Invoke::WriteReplyParams(reply_msg, result_param, return_value); 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) channel_->Send(reply_msg); 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NPObjectStub::OnHasProperty(const NPIdentifier_Param& name, 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool* result) { 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NPIdentifier id = CreateNPIdentifier(name); 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (IsPluginProcess()) { 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (npobject_->_class->hasProperty) { 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *result = npobject_->_class->hasProperty(npobject_, id); 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *result = false; 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *result = WebBindings::hasProperty(0, npobject_, id); 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NPObjectStub::OnGetProperty(const NPIdentifier_Param& name, 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NPVariant_Param* property, 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool* result) { 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NPVariant result_var; 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VOID_TO_NPVARIANT(result_var); 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NPIdentifier id = CreateNPIdentifier(name); 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (IsPluginProcess()) { 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (npobject_->_class->getProperty) { 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *result = npobject_->_class->getProperty(npobject_, id, &result_var); 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *result = false; 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *result = WebBindings::getProperty(0, npobject_, id, &result_var); 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CreateNPVariantParam( 237868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) result_var, channel_.get(), property, true, render_view_id_, page_url_); 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NPObjectStub::OnSetProperty(const NPIdentifier_Param& name, 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const NPVariant_Param& property, 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IPC::Message* reply_msg) { 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool result = false; 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NPIdentifier id = CreateNPIdentifier(name); 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NPVariant property_var; 246868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (!CreateNPVariant(property, 247868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) channel_.get(), 248868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) &property_var, 249868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) render_view_id_, 250868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) page_url_)) { 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NPObjectMsg_SetProperty::WriteReplyParams(reply_msg, result); 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) channel_->Send(reply_msg); 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (IsPluginProcess()) { 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (npobject_->_class->setProperty) { 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN) 2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) static base::FilePath plugin_path = 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CommandLine::ForCurrentProcess()->GetSwitchValuePath( 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switches::kPluginPath); 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static std::wstring filename = StringToLowerASCII( 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) plugin_path.BaseName().value()); 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static NPIdentifier fullscreen = 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WebBindings::getStringIdentifier("fullScreen"); 266ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch if (filename == kNewWMPPlugin && id == fullscreen) { 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Workaround for bug 15985, which is if Flash causes WMP to go 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // full screen a deadlock can occur when WMP calls SetFocus. 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NPObjectMsg_SetProperty::WriteReplyParams(reply_msg, true); 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Send(reply_msg); 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reply_msg = NULL; 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result = npobject_->_class->setProperty(npobject_, id, &property_var); 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result = false; 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result = WebBindings::setProperty(0, npobject_, id, &property_var); 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WebBindings::releaseVariantValue(&property_var); 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (reply_msg) { 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NPObjectMsg_SetProperty::WriteReplyParams(reply_msg, result); 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Send(reply_msg); 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NPObjectStub::OnRemoveProperty(const NPIdentifier_Param& name, 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool* result) { 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NPIdentifier id = CreateNPIdentifier(name); 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (IsPluginProcess()) { 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (npobject_->_class->removeProperty) { 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *result = npobject_->_class->removeProperty(npobject_, id); 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *result = false; 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *result = WebBindings::removeProperty(0, npobject_, id); 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NPObjectStub::OnInvalidate() { 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!IsPluginProcess()) { 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED() << "Should only be called on NPObjects in the plugin"; 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!npobject_->_class->invalidate) 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) npobject_->_class->invalidate(npobject_); 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NPObjectStub::OnEnumeration(std::vector<NPIdentifier_Param>* value, 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool* result) { 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NPIdentifier* value_np = NULL; 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned int count = 0; 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!IsPluginProcess()) { 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *result = WebBindings::enumerate(0, npobject_, &value_np, &count); 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (npobject_->_class->structVersion < NP_CLASS_STRUCT_VERSION_ENUM || 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !npobject_->_class->enumerate) { 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *result = false; 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *result = npobject_->_class->enumerate(npobject_, &value_np, &count); 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!*result) 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (unsigned int i = 0; i < count; ++i) { 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NPIdentifier_Param param; 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CreateNPIdentifierParam(value_np[i], ¶m); 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) value->push_back(param); 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 341bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch free(value_np); 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NPObjectStub::OnConstruct(const std::vector<NPVariant_Param>& args, 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IPC::Message* reply_msg) { 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool return_value = false; 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NPVariant_Param result_param; 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NPVariant result_var; 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VOID_TO_NPVARIANT(result_var); 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int arg_count = static_cast<int>(args.size()); 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NPVariant* args_var = new NPVariant[arg_count]; 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < arg_count; ++i) { 355868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (!CreateNPVariant(args[i], 356868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) channel_.get(), 357868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) &(args_var[i]), 358868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) render_view_id_, 359868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) page_url_)) { 360868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) NPObjectMsg_Invoke::WriteReplyParams( 361868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) reply_msg, result_param, return_value); 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) channel_->Send(reply_msg); 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) delete[] args_var; 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (IsPluginProcess()) { 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (npobject_->_class->structVersion >= NP_CLASS_STRUCT_VERSION_CTOR && 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) npobject_->_class->construct) { 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return_value = npobject_->_class->construct( 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) npobject_, args_var, arg_count, &result_var); 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return_value = false; 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return_value = WebBindings::construct( 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 0, npobject_, args_var, arg_count, &result_var); 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int i = 0; i < arg_count; ++i) 3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WebBindings::releaseVariantValue(&(args_var[i])); 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) delete[] args_var; 3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 386868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) CreateNPVariantParam(result_var, 387868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) channel_.get(), 388868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) &result_param, 389868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) true, 390868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) render_view_id_, 391868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) page_url_); 3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NPObjectMsg_Invoke::WriteReplyParams(reply_msg, result_param, return_value); 3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) channel_->Send(reply_msg); 3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NPObjectStub::OnEvaluate(const std::string& script, 3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool popups_allowed, 3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IPC::Message* reply_msg) { 3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (IsPluginProcess()) { 4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED() << "Should only be called on NPObjects in the renderer"; 4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NPVariant result_var; 4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NPString script_string; 4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) script_string.UTF8Characters = script.c_str(); 4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) script_string.UTF8Length = static_cast<unsigned int>(script.length()); 4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool return_value = WebBindings::evaluateHelper(0, popups_allowed, npobject_, 4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &script_string, &result_var); 4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NPVariant_Param result_param; 413868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) CreateNPVariantParam(result_var, 414868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) channel_.get(), 415868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) &result_param, 416868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) true, 417868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) render_view_id_, 418868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) page_url_); 4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NPObjectMsg_Evaluate::WriteReplyParams(reply_msg, result_param, return_value); 4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) channel_->Send(reply_msg); 4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace content 424