From 591d2a2e0246f69d46b577550d3d5139d3ed1cf9 Mon Sep 17 00:00:00 2001 From: Caio Marcelo de Oliveira Filho Date: Fri, 20 Sep 2013 13:30:41 -0300 Subject: [PATCH] [common] Create C++ wrapper to replace ExtensionAdapater Current ExtensionAdapter ends up merging the concept of extension and instance (before called Context) together, and this causes confusion understanding the execution of the code. The new approach is to create a C++ pair of classes that represent Extension and Instance. This mimics what we have inside Crosswalk, and also is pretty much the same approach PPAPI constructs its C++ API as well. One nice consequence is that the subclass of Extension can be used to store objects shared by all instances -- since it have the correct lifetime. We can get rid of most ad-hoc singleton implementations in the code. One downside is that we resort to virtual methods in this new approach. Even though the overhead is low, if this proves to be a bottleneck for a specific extension, it's easy to fallback to using the C API directly instead of the convenience. --- common/extension.cc | 161 ++++++++++++++++++++++++++++++++++++++++++++++++++++ common/extension.h | 82 ++++++++++++++++++++++++++ 2 files changed, 243 insertions(+) create mode 100644 common/extension.cc create mode 100644 common/extension.h diff --git a/common/extension.cc b/common/extension.cc new file mode 100644 index 0000000..1659ad1 --- /dev/null +++ b/common/extension.cc @@ -0,0 +1,161 @@ +// Copyright (c) 2013 Intel Corporation. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "common/extension.h" + +#include +#include + +namespace { + +common::Extension* g_extension = NULL; +XW_Extension g_xw_extension = 0; + +const XW_CoreInterface* g_core = NULL; +const XW_MessagingInterface* g_messaging = NULL; +const XW_Internal_SyncMessagingInterface* g_sync_messaging = NULL; + +bool InitializeInterfaces(XW_GetInterface get_interface) { + g_core = reinterpret_cast( + get_interface(XW_CORE_INTERFACE)); + if (!g_core) { + std::cerr << "Can't initialize extension: error getting Core interface.\n"; + return false; + } + + g_messaging = reinterpret_cast( + get_interface(XW_MESSAGING_INTERFACE)); + if (!g_messaging) { + std::cerr << + "Can't initialize extension: error getting Messaging interface.\n"; + return false; + } + + g_sync_messaging = + reinterpret_cast( + get_interface(XW_INTERNAL_SYNC_MESSAGING_INTERFACE)); + if (!g_sync_messaging) { + std::cerr << + "Can't initialize extension: error getting SyncMessaging interface.\n"; + return false; + } + + return true; +} + +} // namespace + +int32_t XW_Initialize(XW_Extension extension, XW_GetInterface get_interface) { + assert(extension); + g_xw_extension = extension; + + if (!InitializeInterfaces(get_interface)) + return XW_ERROR; + + g_extension = CreateExtension(); + if (!g_extension) { + std::cerr << "Can't initialize extension: " + << "create extension returned NULL.\n"; + return XW_ERROR; + } + + using common::Extension; + g_core->RegisterShutdownCallback(g_xw_extension, Extension::OnShutdown); + g_core->RegisterInstanceCallbacks( + g_xw_extension, Extension::OnInstanceCreated, + Extension::OnInstanceDestroyed); + g_messaging->Register(g_xw_extension, Extension::HandleMessage); + g_sync_messaging->Register(g_xw_extension, Extension::HandleSyncMessage); + return XW_OK; +} + +namespace common { + +Extension::Extension() {} + +Extension::~Extension() {} + +void Extension::SetExtensionName(const char* name) { + g_core->SetExtensionName(g_xw_extension, name); +} + +void Extension::SetJavaScriptAPI(const char* api) { + g_core->SetJavaScriptAPI(g_xw_extension, api); +} + +Instance* Extension::CreateInstance() { + return NULL; +} + +// static +void Extension::OnShutdown(XW_Extension) { + delete g_extension; + g_extension = NULL; +} + +// static +void Extension::OnInstanceCreated(XW_Instance xw_instance) { + assert(!g_core->GetInstanceData(xw_instance)); + Instance* instance = g_extension->CreateInstance(); + if (!instance) + return; + instance->xw_instance_ = xw_instance; + g_core->SetInstanceData(xw_instance, instance); + instance->Initialize(); +} + +// static +void Extension::OnInstanceDestroyed(XW_Instance xw_instance) { + Instance* instance = + reinterpret_cast(g_core->GetInstanceData(xw_instance)); + if (!instance) + return; + instance->xw_instance_ = 0; + delete instance; +} + +// static +void Extension::HandleMessage(XW_Instance xw_instance, const char* msg) { + Instance* instance = + reinterpret_cast(g_core->GetInstanceData(xw_instance)); + if (!instance) + return; + instance->HandleMessage(msg); +} + +// static +void Extension::HandleSyncMessage(XW_Instance xw_instance, const char* msg) { + Instance* instance = + reinterpret_cast(g_core->GetInstanceData(xw_instance)); + if (!instance) + return; + instance->HandleSyncMessage(msg); +} + +Instance::Instance() + : xw_instance_(0) {} + +Instance::~Instance() { + assert(xw_instance_ == 0); +} + +void Instance::PostMessage(const char* msg) { + if (!xw_instance_) { + std::cerr << "Ignoring PostMessage() in the constructor or after the " + << "instance was destroyed."; + return; + } + g_messaging->PostMessage(xw_instance_, msg); +} + +void Instance::SendSyncReply(const char* reply) { + if (!xw_instance_) { + std::cerr << "Ignoring SendSyncReply() in the constructor or after the " + << "instance was destroyed."; + return; + } + g_sync_messaging->SetSyncReply(xw_instance_, reply); +} + +} // namespace common diff --git a/common/extension.h b/common/extension.h new file mode 100644 index 0000000..81f0012 --- /dev/null +++ b/common/extension.h @@ -0,0 +1,82 @@ +// Copyright (c) 2013 Intel Corporation. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMMON_EXTENSION_H_ +#define COMMON_EXTENSION_H_ + +// This is a C++ wrapper over Crosswalk Extension C API. It implements once the +// boilerplate for the common case of mapping XW_Extension and XW_Instance to +// objects of their own. The wrapper deals automatically with creating and +// destroying the objects. +// +// Extension object lives during the lifetime of the extension, and when the +// extension process is properly shutdown, it's destructor will be +// called. Instance objects (there can be many) live during the lifetime of a +// script context associated with a frame in the page. These objects serves as +// storage points for extension specific objects, use them for that. + +#include "common/XW_Extension.h" +#include "common/XW_Extension_SyncMessage.h" + +namespace common { + +class Instance; +class Extension; + +} // namespace common + + +// This function should be implemented by each extension and should return +// an appropriate Extension subclass. +common::Extension* CreateExtension(); + + +namespace common { + +class Extension { + public: + Extension(); + virtual ~Extension(); + + // These should be called in the subclass constructor. + void SetExtensionName(const char* name); + void SetJavaScriptAPI(const char* api); + + virtual Instance* CreateInstance(); + + private: + friend int32_t ::XW_Initialize(XW_Extension extension, + XW_GetInterface get_interface); + + // XW_Extension callbacks. + static void OnShutdown(XW_Extension xw_extension); + static void OnInstanceCreated(XW_Instance xw_instance); + static void OnInstanceDestroyed(XW_Instance xw_instance); + static void HandleMessage(XW_Instance xw_instance, const char* msg); + static void HandleSyncMessage(XW_Instance xw_instance, const char* msg); +}; + +class Instance { + public: + Instance(); + virtual ~Instance(); + + void PostMessage(const char* msg); + void SendSyncReply(const char* reply); + + virtual void Initialize() {} + virtual void HandleMessage(const char* msg) = 0; + virtual void HandleSyncMessage(const char* msg) {} + + XW_Instance xw_instance() const { return xw_instance_; } + + private: + friend class Extension; + + XW_Instance xw_instance_; +}; + +} // namespace common + +#endif // COMMON_EXTENSION_H_ -- 2.7.4