DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Mercurial (d38398e5144e)

VCS Links

ClassInfoData

GenericClassInfo

Macros

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef nsIClassInfoImpl_h__
#define nsIClassInfoImpl_h__

#include "mozilla/Alignment.h"
#include "mozilla/Assertions.h"
#include "mozilla/MacroArgs.h"
#include "mozilla/MacroForEach.h"
#include "nsIClassInfo.h"
#include "nsISupportsImpl.h"

#include <new>

/**
 * This header file provides macros which help you make your class implement
 * nsIClassInfo.  Implementing nsIClassInfo is particularly helpful if you have
 * a C++ class which implements multiple interfaces and which you access from
 * JavaScript.  If that class implements nsIClassInfo, the JavaScript code
 * won't have to call QueryInterface on instances of the class; all methods
 * from all interfaces returned by GetInterfaces() will be available
 * automagically.
 *
 * Here's all you need to do.  Given a class
 *
 *   class nsFooBar : public nsIFoo, public nsIBar { };
 *
 * you should already have the following nsISupports implementation in its cpp
 * file:
 *
 *   NS_IMPL_ISUPPORTS(nsFooBar, nsIFoo, nsIBar).
 *
 * Change this to
 *
 *   NS_IMPL_CLASSINFO(nsFooBar, nullptr, 0, NS_FOOBAR_CID)
 *   NS_IMPL_ISUPPORTS_CI(nsFooBar, nsIFoo, nsIBar)
 *
 * If nsFooBar is threadsafe, change the 0 above to nsIClassInfo::THREADSAFE.
 * If it's a singleton, use nsIClassInfo::SINGLETON.  The full list of flags is
 * in nsIClassInfo.idl.
 *
 * The nullptr parameter is there so you can pass a function for converting
 * from an XPCOM object to a scriptable helper.  Unless you're doing
 * specialized JS work, you can probably leave this as nullptr.
 *
 * This file also defines the NS_IMPL_QUERY_INTERFACE_CI macro, which you can
 * use to replace NS_IMPL_QUERY_INTERFACE, if you use that instead of
 * NS_IMPL_ISUPPORTS.
 *
 * That's it!  The rest is gory details.
 *
 *
 * Notice that nsFooBar didn't need to inherit from nsIClassInfo in order to
 * "implement" it.  However, after adding these macros to nsFooBar, you you can
 * QueryInterface an instance of nsFooBar to nsIClassInfo.  How can this be?
 *
 * The answer lies in the NS_IMPL_ISUPPORTS_CI macro.  It modifies nsFooBar's
 * QueryInterface implementation such that, if we ask to QI to nsIClassInfo, it
 * returns a singleton object associated with the class.  (That singleton is
 * defined by NS_IMPL_CLASSINFO.)  So all nsFooBar instances will return the
 * same object when QI'ed to nsIClassInfo.  (You can see this in
 * NS_IMPL_QUERY_CLASSINFO below.)
 *
 * This hack breaks XPCOM's rules, since if you take an instance of nsFooBar,
 * QI it to nsIClassInfo, and then try to QI to nsIFoo, that will fail.  On the
 * upside, implementing nsIClassInfo doesn't add a vtable pointer to instances
 * of your class.
 *
 * In principal, you can also implement nsIClassInfo by inheriting from the
 * interface.  But some code expects that when it QI's an object to
 * nsIClassInfo, it gets back a singleton which isn't attached to any
 * particular object.  If a class were to implement nsIClassInfo through
 * inheritance, that code might QI to nsIClassInfo and keep the resulting
 * object alive, thinking it was only keeping alive the classinfo singleton,
 * but in fact keeping a whole instance of the class alive.  See, e.g., bug
 * 658632.
 *
 * Unless you specifically need to have a different nsIClassInfo instance for
 * each instance of your class, you should probably just implement nsIClassInfo
 * as a singleton.
 */

class GenericClassInfo : public nsIClassInfo
{
public:
  struct ClassInfoData
  {
    // This function pointer uses NS_CALLBACK_ because it's always set to an
    // NS_IMETHOD function, which uses __stdcall on Win32.
    typedef NS_CALLBACK_(nsresult, GetInterfacesProc)(uint32_t* aCountP,
                                                      nsIID*** aArray);
    GetInterfacesProc getinterfaces;

    // This function pointer doesn't use NS_CALLBACK_ because it's always set to
    // a vanilla function.
    typedef nsresult (*GetScriptableHelperProc)(nsIXPCScriptable** aHelper);
    GetScriptableHelperProc getscriptablehelper;

    uint32_t flags;
    nsCID cid;
  };

  NS_DECL_ISUPPORTS_INHERITED
  NS_DECL_NSICLASSINFO

  explicit GenericClassInfo(const ClassInfoData* aData) : mData(aData) {}

private:
  const ClassInfoData* mData;
};

#define NS_CLASSINFO_NAME(_class) g##_class##_classInfoGlobal
#define NS_CI_INTERFACE_GETTER_NAME(_class) _class##_GetInterfacesHelper
#define NS_DECL_CI_INTERFACE_GETTER(_class)                                   \
  extern NS_IMETHODIMP NS_CI_INTERFACE_GETTER_NAME(_class)                    \
     (uint32_t *, nsIID ***);

#define NS_IMPL_CLASSINFO(_class, _getscriptablehelper, _flags, _cid)   \
  NS_DECL_CI_INTERFACE_GETTER(_class)                                   \
  static const GenericClassInfo::ClassInfoData k##_class##ClassInfoData = { \
    NS_CI_INTERFACE_GETTER_NAME(_class),                                \
    _getscriptablehelper,                                               \
    _flags | nsIClassInfo::SINGLETON_CLASSINFO,                         \
    _cid,                                                               \
  };                                                                    \
  mozilla::AlignedStorage2<GenericClassInfo> k##_class##ClassInfoDataPlace;   \
  nsIClassInfo* NS_CLASSINFO_NAME(_class) = nullptr;

#define NS_IMPL_QUERY_CLASSINFO(_class)                                       \
  if ( aIID.Equals(NS_GET_IID(nsIClassInfo)) ) {                              \
    if (!NS_CLASSINFO_NAME(_class))                                           \
      NS_CLASSINFO_NAME(_class) = new (k##_class##ClassInfoDataPlace.addr())  \
        GenericClassInfo(&k##_class##ClassInfoData);                          \
    foundInterface = NS_CLASSINFO_NAME(_class);                               \
  } else

#define NS_CLASSINFO_HELPER_BEGIN(_class, _c)                                 \
NS_IMETHODIMP                                                                 \
NS_CI_INTERFACE_GETTER_NAME(_class)(uint32_t *count, nsIID ***array)          \
{                                                                             \
    *count = _c;                                                              \
    *array = (nsIID **)moz_xmalloc(sizeof (nsIID *) * _c);                \
    uint32_t i = 0;

#define NS_CLASSINFO_HELPER_ENTRY(_interface)                                 \
    (*array)[i++] = (nsIID*)nsMemory::Clone(&NS_GET_IID(_interface),          \
                                            sizeof(nsIID));

#define NS_CLASSINFO_HELPER_END                                               \
    MOZ_ASSERT(i == *count, "Incorrent number of entries");                   \
    return NS_OK;                                                             \
}

#define NS_IMPL_CI_INTERFACE_GETTER(aClass, ...)                              \
  MOZ_STATIC_ASSERT_VALID_ARG_COUNT(__VA_ARGS__);                             \
  NS_CLASSINFO_HELPER_BEGIN(aClass,                                           \
                            MOZ_PASTE_PREFIX_AND_ARG_COUNT(/* No prefix */,   \
                                                           __VA_ARGS__))      \
    MOZ_FOR_EACH(NS_CLASSINFO_HELPER_ENTRY, (), (__VA_ARGS__))                \
  NS_CLASSINFO_HELPER_END

#define NS_IMPL_QUERY_INTERFACE_CI(aClass, ...)                               \
  MOZ_STATIC_ASSERT_VALID_ARG_COUNT(__VA_ARGS__);                             \
  NS_INTERFACE_MAP_BEGIN(aClass)                                              \
    MOZ_FOR_EACH(NS_INTERFACE_MAP_ENTRY, (), (__VA_ARGS__))                   \
    NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, MOZ_ARG_1(__VA_ARGS__))     \
    NS_IMPL_QUERY_CLASSINFO(aClass)                                           \
  NS_INTERFACE_MAP_END

#define NS_IMPL_ISUPPORTS_CI(aClass, ...)                                     \
  NS_IMPL_ADDREF(aClass)                                                      \
  NS_IMPL_RELEASE(aClass)                                                     \
  NS_IMPL_QUERY_INTERFACE_CI(aClass, __VA_ARGS__)                             \
  NS_IMPL_CI_INTERFACE_GETTER(aClass, __VA_ARGS__)

#endif // nsIClassInfoImpl_h__