xpcom/glue/nsIClassInfoImpl.h

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/xpcom/glue/nsIClassInfoImpl.h	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,176 @@
     1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.7 +
     1.8 +#ifndef nsIClassInfoImpl_h__
     1.9 +#define nsIClassInfoImpl_h__
    1.10 +
    1.11 +#include "mozilla/Alignment.h"
    1.12 +#include "mozilla/Assertions.h"
    1.13 +#include "mozilla/MacroArgs.h"
    1.14 +#include "mozilla/MacroForEach.h"
    1.15 +#include "nsIClassInfo.h"
    1.16 +#include "nsISupportsImpl.h"
    1.17 +
    1.18 +#include <new>
    1.19 +
    1.20 +/**
    1.21 + * This header file provides macros which help you make your class implement
    1.22 + * nsIClassInfo.  Implementing nsIClassInfo is particularly helpful if you have
    1.23 + * a C++ class which implements multiple interfaces and which you access from
    1.24 + * JavaScript.  If that class implements nsIClassInfo, the JavaScript code
    1.25 + * won't have to call QueryInterface on instances of the class; all methods
    1.26 + * from all interfaces returned by GetInterfaces() will be available
    1.27 + * automagically.
    1.28 + *
    1.29 + * Here's all you need to do.  Given a class
    1.30 + *
    1.31 + *   class nsFooBar : public nsIFoo, public nsIBar { };
    1.32 + *
    1.33 + * you should already have the following nsISupports implementation in its cpp
    1.34 + * file:
    1.35 + *
    1.36 + *   NS_IMPL_ISUPPORTS(nsFooBar, nsIFoo, nsIBar).
    1.37 + *
    1.38 + * Change this to
    1.39 + *
    1.40 + *   NS_IMPL_CLASSINFO(nsFooBar, nullptr, 0, NS_FOOBAR_CID)
    1.41 + *   NS_IMPL_ISUPPORTS_CI(nsFooBar, nsIFoo, nsIBar)
    1.42 + *
    1.43 + * If nsFooBar is threadsafe, change the 0 above to nsIClassInfo::THREADSAFE.
    1.44 + * If it's a singleton, use nsIClassInfo::SINGLETON.  The full list of flags is
    1.45 + * in nsIClassInfo.idl.
    1.46 + *
    1.47 + * The nullptr parameter is there so you can pass a function for converting
    1.48 + * from an XPCOM object to a scriptable helper.  Unless you're doing
    1.49 + * specialized JS work, you can probably leave this as nullptr.
    1.50 + *
    1.51 + * This file also defines the NS_IMPL_QUERY_INTERFACE_CI macro, which you can
    1.52 + * use to replace NS_IMPL_QUERY_INTERFACE, if you use that instead of
    1.53 + * NS_IMPL_ISUPPORTS.
    1.54 + *
    1.55 + * That's it!  The rest is gory details.
    1.56 + *
    1.57 + *
    1.58 + * Notice that nsFooBar didn't need to inherit from nsIClassInfo in order to
    1.59 + * "implement" it.  However, after adding these macros to nsFooBar, you you can
    1.60 + * QueryInterface an instance of nsFooBar to nsIClassInfo.  How can this be?
    1.61 + *
    1.62 + * The answer lies in the NS_IMPL_ISUPPORTS_CI macro.  It modifies nsFooBar's
    1.63 + * QueryInterface implementation such that, if we ask to QI to nsIClassInfo, it
    1.64 + * returns a singleton object associated with the class.  (That singleton is
    1.65 + * defined by NS_IMPL_CLASSINFO.)  So all nsFooBar instances will return the
    1.66 + * same object when QI'ed to nsIClassInfo.  (You can see this in
    1.67 + * NS_IMPL_QUERY_CLASSINFO below.)
    1.68 + *
    1.69 + * This hack breaks XPCOM's rules, since if you take an instance of nsFooBar,
    1.70 + * QI it to nsIClassInfo, and then try to QI to nsIFoo, that will fail.  On the
    1.71 + * upside, implementing nsIClassInfo doesn't add a vtable pointer to instances
    1.72 + * of your class.
    1.73 + *
    1.74 + * In principal, you can also implement nsIClassInfo by inheriting from the
    1.75 + * interface.  But some code expects that when it QI's an object to
    1.76 + * nsIClassInfo, it gets back a singleton which isn't attached to any
    1.77 + * particular object.  If a class were to implement nsIClassInfo through
    1.78 + * inheritance, that code might QI to nsIClassInfo and keep the resulting
    1.79 + * object alive, thinking it was only keeping alive the classinfo singleton,
    1.80 + * but in fact keeping a whole instance of the class alive.  See, e.g., bug
    1.81 + * 658632.
    1.82 + *
    1.83 + * Unless you specifically need to have a different nsIClassInfo instance for
    1.84 + * each instance of your class, you should probably just implement nsIClassInfo
    1.85 + * as a singleton.
    1.86 + */
    1.87 +
    1.88 +class NS_COM_GLUE GenericClassInfo : public nsIClassInfo
    1.89 +{
    1.90 +public:
    1.91 +  struct ClassInfoData
    1.92 +  {
    1.93 +    typedef NS_CALLBACK(GetInterfacesProc)(uint32_t* countp,
    1.94 +                                           nsIID*** array);
    1.95 +    typedef NS_CALLBACK(GetLanguageHelperProc)(uint32_t language,
    1.96 +                                               nsISupports** helper);
    1.97 +
    1.98 +    GetInterfacesProc getinterfaces;
    1.99 +    GetLanguageHelperProc getlanguagehelper;
   1.100 +    uint32_t flags;
   1.101 +    nsCID cid;
   1.102 +  };
   1.103 +
   1.104 +  NS_DECL_ISUPPORTS_INHERITED
   1.105 +  NS_DECL_NSICLASSINFO
   1.106 +
   1.107 +  GenericClassInfo(const ClassInfoData* data)
   1.108 +    : mData(data)
   1.109 +  { }
   1.110 +
   1.111 +private:
   1.112 +  const ClassInfoData* mData;
   1.113 +};
   1.114 +
   1.115 +#define NS_CLASSINFO_NAME(_class) g##_class##_classInfoGlobal
   1.116 +#define NS_CI_INTERFACE_GETTER_NAME(_class) _class##_GetInterfacesHelper
   1.117 +#define NS_DECL_CI_INTERFACE_GETTER(_class)                                   \
   1.118 +  extern NS_IMETHODIMP NS_CI_INTERFACE_GETTER_NAME(_class)                    \
   1.119 +     (uint32_t *, nsIID ***);
   1.120 +
   1.121 +#define NS_IMPL_CLASSINFO(_class, _getlanguagehelper, _flags, _cid)     \
   1.122 +  NS_DECL_CI_INTERFACE_GETTER(_class)                                   \
   1.123 +  static const GenericClassInfo::ClassInfoData k##_class##ClassInfoData = { \
   1.124 +    NS_CI_INTERFACE_GETTER_NAME(_class),                                \
   1.125 +    _getlanguagehelper,                                                 \
   1.126 +    _flags | nsIClassInfo::SINGLETON_CLASSINFO,                         \
   1.127 +    _cid,                                                               \
   1.128 +  };                                                                    \
   1.129 +  mozilla::AlignedStorage2<GenericClassInfo> k##_class##ClassInfoDataPlace;   \
   1.130 +  nsIClassInfo* NS_CLASSINFO_NAME(_class) = nullptr;
   1.131 +
   1.132 +#define NS_IMPL_QUERY_CLASSINFO(_class)                                       \
   1.133 +  if ( aIID.Equals(NS_GET_IID(nsIClassInfo)) ) {                              \
   1.134 +    if (!NS_CLASSINFO_NAME(_class))                                           \
   1.135 +      NS_CLASSINFO_NAME(_class) = new (k##_class##ClassInfoDataPlace.addr())  \
   1.136 +        GenericClassInfo(&k##_class##ClassInfoData);                          \
   1.137 +    foundInterface = NS_CLASSINFO_NAME(_class);                               \
   1.138 +  } else
   1.139 +
   1.140 +#define NS_CLASSINFO_HELPER_BEGIN(_class, _c)                                 \
   1.141 +NS_IMETHODIMP                                                                 \
   1.142 +NS_CI_INTERFACE_GETTER_NAME(_class)(uint32_t *count, nsIID ***array)          \
   1.143 +{                                                                             \
   1.144 +    *count = _c;                                                              \
   1.145 +    *array = (nsIID **)nsMemory::Alloc(sizeof (nsIID *) * _c);                \
   1.146 +    uint32_t i = 0;
   1.147 +
   1.148 +#define NS_CLASSINFO_HELPER_ENTRY(_interface)                                 \
   1.149 +    (*array)[i++] = (nsIID*)nsMemory::Clone(&NS_GET_IID(_interface),          \
   1.150 +                                            sizeof(nsIID));
   1.151 +
   1.152 +#define NS_CLASSINFO_HELPER_END                                               \
   1.153 +    MOZ_ASSERT(i == *count, "Incorrent number of entries");                   \
   1.154 +    return NS_OK;                                                             \
   1.155 +}
   1.156 +
   1.157 +#define NS_IMPL_CI_INTERFACE_GETTER(aClass, ...)                              \
   1.158 +  MOZ_STATIC_ASSERT_VALID_ARG_COUNT(__VA_ARGS__);                             \
   1.159 +  NS_CLASSINFO_HELPER_BEGIN(aClass,                                           \
   1.160 +                            MOZ_PASTE_PREFIX_AND_ARG_COUNT(/* No prefix */,   \
   1.161 +                                                           __VA_ARGS__))      \
   1.162 +    MOZ_FOR_EACH(NS_CLASSINFO_HELPER_ENTRY, (), (__VA_ARGS__))                \
   1.163 +  NS_CLASSINFO_HELPER_END
   1.164 +
   1.165 +#define NS_IMPL_QUERY_INTERFACE_CI(aClass, ...)                               \
   1.166 +  MOZ_STATIC_ASSERT_VALID_ARG_COUNT(__VA_ARGS__);                             \
   1.167 +  NS_INTERFACE_MAP_BEGIN(aClass)                                              \
   1.168 +    MOZ_FOR_EACH(NS_INTERFACE_MAP_ENTRY, (), (__VA_ARGS__))                   \
   1.169 +    NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, MOZ_ARG_1(__VA_ARGS__))     \
   1.170 +    NS_IMPL_QUERY_CLASSINFO(aClass)                                           \
   1.171 +  NS_INTERFACE_MAP_END
   1.172 +
   1.173 +#define NS_IMPL_ISUPPORTS_CI(aClass, ...)                                     \
   1.174 +  NS_IMPL_ADDREF(aClass)                                                      \
   1.175 +  NS_IMPL_RELEASE(aClass)                                                     \
   1.176 +  NS_IMPL_QUERY_INTERFACE_CI(aClass, __VA_ARGS__)                             \
   1.177 +  NS_IMPL_CI_INTERFACE_GETTER(aClass, __VA_ARGS__)
   1.178 +
   1.179 +#endif // nsIClassInfoImpl_h__

mercurial