Bug 792649 - Make the simplest of Web Audio tests work without audio playback for now; r=bzbarsky
authorEhsan Akhgari <ehsan@mozilla.com>
Mon, 24 Sep 2012 23:31:58 -0400
changeset 109106 7a4d62a24e050b1e4b59006919ddd3862f479679
parent 109105 c43aeb9b844478c69d66d9795ca5341cb72277e7
child 109107 c9a2c26e6ea6f1827fca456f992632c827df39cd
push id82
push usershu@rfrn.org
push dateFri, 05 Oct 2012 13:20:22 +0000
reviewersbzbarsky
bugs792649
milestone18.0a1
Bug 792649 - Make the simplest of Web Audio tests work without audio playback for now; r=bzbarsky
content/media/webaudio/AudioBufferSourceNode.cpp
content/media/webaudio/AudioBufferSourceNode.h
content/media/webaudio/AudioDestinationNode.h
content/media/webaudio/AudioNode.cpp
content/media/webaudio/AudioNode.h
content/media/webaudio/AudioSourceNode.h
content/media/webaudio/test/Makefile.in
content/media/webaudio/test/test_badConnect.html
content/media/webaudio/test/test_singleSourceDest.html
dom/webidl/AudioBufferSourceNode.webidl
dom/webidl/AudioContext.webidl
dom/webidl/AudioNode.webidl
xpcom/glue/nsCycleCollectionParticipant.h
--- a/content/media/webaudio/AudioBufferSourceNode.cpp
+++ b/content/media/webaudio/AudioBufferSourceNode.cpp
@@ -5,25 +5,37 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "AudioBufferSourceNode.h"
 #include "mozilla/dom/AudioBufferSourceNodeBinding.h"
 
 namespace mozilla {
 namespace dom {
 
-NS_IMPL_ISUPPORTS_INHERITED0(AudioBufferSourceNode, AudioSourceNode)
+NS_IMPL_CYCLE_COLLECTION_INHERITED_1(AudioBufferSourceNode, AudioSourceNode, mBuffer)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(AudioBufferSourceNode)
+NS_INTERFACE_MAP_END_INHERITING(AudioSourceNode)
+
+NS_IMPL_ADDREF_INHERITED(AudioBufferSourceNode, AudioSourceNode)
+NS_IMPL_RELEASE_INHERITED(AudioBufferSourceNode, AudioSourceNode)
 
 AudioBufferSourceNode::AudioBufferSourceNode(AudioContext* aContext)
   : AudioSourceNode(aContext)
 {
 }
 
 JSObject*
 AudioBufferSourceNode::WrapObject(JSContext* aCx, JSObject* aScope,
                                   bool* aTriedToWrap)
 {
   return AudioBufferSourceNodeBinding::Wrap(aCx, aScope, this, aTriedToWrap);
 }
 
+void
+AudioBufferSourceNode::SetBuffer(AudioBuffer* aBuffer)
+{
+  mBuffer = aBuffer;
+}
+
 }
 }
 
--- a/content/media/webaudio/AudioBufferSourceNode.h
+++ b/content/media/webaudio/AudioBufferSourceNode.h
@@ -2,30 +2,40 @@
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* 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/. */
 
 #pragma once
 
 #include "AudioSourceNode.h"
+#include "AudioBuffer.h"
 
 namespace mozilla {
 namespace dom {
 
 class AudioBufferSourceNode : public AudioSourceNode
 {
 public:
   explicit AudioBufferSourceNode(AudioContext* aContext);
 
   NS_DECL_ISUPPORTS_INHERITED
+  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(AudioBufferSourceNode, AudioSourceNode)
+
+  virtual JSObject* WrapObject(JSContext* aCx, JSObject* aScope,
+                               bool* aTriedToWrap);
 
   void NoteOn(double) { /* no-op for now */ }
   void NoteOff(double) { /* no-op for now */ }
 
-  virtual JSObject* WrapObject(JSContext* aCx, JSObject* aScope,
-                               bool* aTriedToWrap);
+  AudioBuffer* GetBuffer() const
+  {
+    return mBuffer;
+  }
+  void SetBuffer(AudioBuffer* aBuffer);
 
+private:
+  nsRefPtr<AudioBuffer> mBuffer;
 };
 
 }
 }
 
--- a/content/media/webaudio/AudioDestinationNode.h
+++ b/content/media/webaudio/AudioDestinationNode.h
@@ -18,13 +18,22 @@ class AudioDestinationNode : public Audi
 public:
   explicit AudioDestinationNode(AudioContext* aContext);
 
   NS_DECL_ISUPPORTS_INHERITED
 
   virtual JSObject* WrapObject(JSContext* aCx, JSObject* aScope,
                                bool* aTriedToWrap);
 
+  virtual uint32_t MaxNumberOfInputs() const MOZ_FINAL MOZ_OVERRIDE
+  {
+    return 1;
+  }
+  virtual uint32_t MaxNumberOfOutputs() const MOZ_FINAL MOZ_OVERRIDE
+  {
+    return 0;
+  }
+
 };
 
 }
 }
 
--- a/content/media/webaudio/AudioNode.cpp
+++ b/content/media/webaudio/AudioNode.cpp
@@ -2,30 +2,115 @@
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* 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/. */
 
 #include "AudioNode.h"
 #include "AudioContext.h"
 #include "nsContentUtils.h"
+#include "mozilla/ErrorResult.h"
 
 namespace mozilla {
 namespace dom {
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(AudioNode, mContext)
+template <typename T>
+static void
+TraverseElements(nsCycleCollectionTraversalCallback& cb,
+                 const nsTArray<T>& array,
+                 const char* name)
+{
+  for (uint32_t i = 0, length = array.Length(); i < length; ++i) {
+    NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, name);
+    AudioNode* node = array[i].get();
+    cb.NoteXPCOMChild(node);
+  }
+}
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(AudioNode)
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(AudioNode)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mContext)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSTARRAY(mInputs)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSTARRAY(mOutputs)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(AudioNode)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mContext)
+  TraverseElements(cb, tmp->mInputs, "mInputs[i]");
+  TraverseElements(cb, tmp->mOutputs, "mOutputs[i]");
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(AudioNode)
+
 NS_IMPL_CYCLE_COLLECTING_ADDREF(AudioNode)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(AudioNode)
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(AudioNode)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
 AudioNode::AudioNode(AudioContext* aContext)
   : mContext(aContext)
 {
   MOZ_ASSERT(aContext);
   SetIsDOMBinding();
 }
 
+void
+AudioNode::Connect(AudioNode& aDestination, uint32_t aOutput,
+                   uint32_t aInput, ErrorResult& aRv)
+{
+  if (aOutput >= MaxNumberOfOutputs() ||
+      aInput >= aDestination.MaxNumberOfInputs()) {
+    aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
+    return;
+  }
+
+  if (Context() != aDestination.Context()) {
+    aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
+    return;
+  }
+
+  // XXX handle cycle detection per spec
+
+  Output output(&aDestination, aInput);
+  mOutputs.EnsureLengthAtLeast(aOutput + 1);
+  mOutputs.ReplaceElementAt(aOutput, output);
+  Input input(this, aOutput);
+  aDestination.mInputs.EnsureLengthAtLeast(aInput + 1);
+  aDestination.mInputs.ReplaceElementAt(aInput, input);
+}
+
+void
+AudioNode::Disconnect(uint32_t aOutput, ErrorResult& aRv)
+{
+  if (aOutput >= NumberOfOutputs()) {
+    aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
+    return;
+  }
+
+  // We do a copy of the objects to AddRef source and destination
+  // objects so that they don't go away before we're done here.
+  const Output output = mOutputs[aOutput];
+  if (!output) {
+    aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
+    return;
+  }
+  const Input input = output.mDestination->mInputs[output.mInput];
+
+  MOZ_ASSERT(Context() == output.mDestination->Context());
+  MOZ_ASSERT(aOutput == input.mOutput);
+
+  if (!input || input.mSource != this) {
+    aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
+    return;
+  }
+
+  output.mDestination->mInputs.ReplaceElementAt(output.mInput, Input());
+  mOutputs.ReplaceElementAt(input.mOutput, Output());
+}
+
 }
 }
 
--- a/content/media/webaudio/AudioNode.h
+++ b/content/media/webaudio/AudioNode.h
@@ -6,21 +6,25 @@
 
 #pragma once
 
 #include "nsWrapperCache.h"
 #include "nsCycleCollectionParticipant.h"
 #include "mozilla/Attributes.h"
 #include "EnableWebAudioCheck.h"
 #include "nsAutoPtr.h"
+#include "nsTArray.h"
 #include "AudioContext.h"
 
 struct JSContext;
 
 namespace mozilla {
+
+class ErrorResult;
+
 namespace dom {
 
 class AudioNode : public nsISupports,
                   public nsWrapperCache,
                   public EnableWebAudioCheck
 {
 public:
   explicit AudioNode(AudioContext* aContext);
@@ -35,21 +39,92 @@ public:
   }
 
   AudioContext* Context() const
   {
     return mContext;
   }
 
   void Connect(AudioNode& aDestination, uint32_t aOutput,
-               uint32_t aInput)
-  { /* no-op for now */ }
+               uint32_t aInput, ErrorResult& aRv);
+
+  void Disconnect(uint32_t aOutput, ErrorResult& aRv);
+
+  uint32_t NumberOfInputs() const
+  {
+    return mInputs.Length();
+  }
+  uint32_t NumberOfOutputs() const
+  {
+    return mOutputs.Length();
+  }
+
+  // The following two virtual methods must be implemented by each node type
+  // to provide the maximum number of input and outputs they accept.
+  virtual uint32_t MaxNumberOfInputs() const = 0;
+  virtual uint32_t MaxNumberOfOutputs() const = 0;
+
+  struct Output {
+    enum { InvalidIndex = 0xffffffff };
+    Output()
+      : mInput(InvalidIndex)
+    {
+    }
+    Output(AudioNode* aDestination, uint32_t aInput)
+      : mDestination(aDestination),
+        mInput(aInput)
+    {
+    }
+
+    // Check whether the slot is valid
+    typedef void**** ConvertibleToBool;
+    operator ConvertibleToBool() const {
+      return ConvertibleToBool(mDestination && mInput != InvalidIndex);
+    }
 
-  void Disconnect(uint32_t aOutput)
-  { /* no-op for now */ }
+    // Needed for the CC traversal
+    AudioNode* get() const {
+      return mDestination;
+    }
+
+    nsRefPtr<AudioNode> mDestination;
+    // This is an index into mDestination->mInputs which specifies the Input
+    // object corresponding to this Output node.
+    const uint32_t mInput;
+  };
+  struct Input {
+    enum { InvalidIndex = 0xffffffff };
+    Input()
+      : mOutput(InvalidIndex)
+    {
+    }
+    Input(AudioNode* aSource, uint32_t aOutput)
+      : mSource(aSource),
+        mOutput(aOutput)
+    {
+    }
+
+    // Check whether the slot is valid
+    typedef void**** ConvertibleToBool;
+    operator ConvertibleToBool() const {
+      return ConvertibleToBool(mSource && mOutput != InvalidIndex);
+    }
+
+    // Needed for the CC traversal
+    AudioNode* get() const {
+      return mSource;
+    }
+
+    nsRefPtr<AudioNode> mSource;
+    // This is an index into mSource->mOutputs which specifies the Output
+    // object corresponding to this Input node.
+    const uint32_t mOutput;
+  };
 
 private:
   nsRefPtr<AudioContext> mContext;
+  nsTArray<Input> mInputs;
+  nsTArray<Output> mOutputs;
 };
 
 }
 }
 
--- a/content/media/webaudio/AudioSourceNode.h
+++ b/content/media/webaudio/AudioSourceNode.h
@@ -13,13 +13,22 @@ namespace dom {
 
 class AudioSourceNode : public AudioNode
 {
 public:
   explicit AudioSourceNode(AudioContext* aContext);
 
   NS_DECL_ISUPPORTS_INHERITED
 
+  virtual uint32_t MaxNumberOfInputs() const MOZ_FINAL MOZ_OVERRIDE
+  {
+    return 0;
+  }
+  virtual uint32_t MaxNumberOfOutputs() const MOZ_FINAL MOZ_OVERRIDE
+  {
+    return 1;
+  }
+
 };
 
 }
 }
 
--- a/content/media/webaudio/test/Makefile.in
+++ b/content/media/webaudio/test/Makefile.in
@@ -8,11 +8,13 @@ srcdir         := @srcdir@
 VPATH          := @srcdir@
 relativesrcdir := @relativesrcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 MOCHITEST_FILES := \
   test_AudioBuffer.html \
   test_AudioContext.html \
+  test_badConnect.html \
+  test_singleSourceDest.html \
   $(NULL)
 
 include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/content/media/webaudio/test/test_badConnect.html
@@ -0,0 +1,62 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test whether we can create an AudioContext interface</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+function expectException(func, exceptionCode) {
+  var threw = false;
+  try {
+    func();
+  } catch (ex) {
+    threw = true;
+    ok(ex instanceof DOMException, "Expect a DOM exception");
+    ok(ex.code, exceptionCode, "Expect the correct exception code");
+  }
+  ok(threw, "The exception was thrown");
+}
+
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(function() {
+  SpecialPowers.setBoolPref("media.webaudio.enabled", true);
+
+  var context1 = new mozAudioContext();
+  var context2 = new mozAudioContext();
+
+  var destination1 = context1.destination;
+  var destination2 = context2.destination;
+
+  isnot(destination1, destination2, "Destination nodes should not be the same");
+  isnot(destination1.context, destination2.context, "Destination nodes should not have the same context");
+
+  var source1 = context1.createBufferSource();
+
+  expectException(function() {
+    source1.connect(destination1, 1);
+  }, DOMException.INDEX_SIZE_ERR);
+  expectException(function() {
+    source1.connect(destination1, 0, 1);
+  }, DOMException.INDEX_SIZE_ERR);
+  expectException(function() {
+    source1.connect(destination2);
+  }, DOMException.SYNTAX_ERR);
+
+  source1.connect(destination1);
+
+  expectException(function() {
+    source1.disconnect(1);
+  }, DOMException.INDEX_SIZE_ERR);
+
+  SpecialPowers.clearUserPref("media.webaudio.enabled");
+  SimpleTest.finish();
+});
+
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/media/webaudio/test/test_singleSourceDest.html
@@ -0,0 +1,57 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test whether we can create an AudioContext interface</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(function() {
+  SpecialPowers.setBoolPref("media.webaudio.enabled", true);
+
+  var context = new mozAudioContext();
+  var buffer = context.createBuffer(1, 2048, 44100);
+  for (var i = 0; i < 2048; ++i) {
+    buffer.getChannelData(0)[i] = Math.sin(440 * 2 * Math.PI * i / 44100);
+  }
+
+  var destination = context.destination;
+  is(destination.context, context, "Destination node has proper context");
+  is(destination.context, context, "Destination node has proper context");
+  is(destination.numberOfInputs, 0, "Destination node has 0 inputs");
+  is(destination.numberOfOutputs, 0, "Destination node has 0 outputs");
+
+  var source = context.createBufferSource();
+  is(source.context, context, "Source node has proper context");
+  is(source.numberOfInputs, 0, "Source node has 0 inputs");
+  is(source.numberOfOutputs, 0, "Source node has 0 outputs");
+  ok(!source.buffer, "Source node should not have a buffer when it's created");
+
+  source.buffer = buffer;
+  ok(source.buffer, "Source node should have a buffer now");
+
+  source.connect(destination);
+
+  is(source.numberOfInputs, 0, "Source node has 0 inputs");
+  is(source.numberOfOutputs, 1, "Source node has 0 outputs");
+  is(destination.numberOfInputs, 1, "Destination node has 0 inputs");
+  is(destination.numberOfOutputs, 0, "Destination node has 0 outputs");
+
+  source.noteOn(0);
+  SimpleTest.executeSoon(function() {
+    source.noteOff(0);
+    source.disconnect();
+
+    SpecialPowers.clearUserPref("media.webaudio.enabled");
+    SimpleTest.finish();
+  });
+});
+
+</script>
+</pre>
+</body>
+</html>
--- a/dom/webidl/AudioBufferSourceNode.webidl
+++ b/dom/webidl/AudioBufferSourceNode.webidl
@@ -17,17 +17,17 @@ interface AudioBufferSourceNode : AudioS
     const unsigned short SCHEDULED_STATE = 1;
     const unsigned short PLAYING_STATE = 2;
     const unsigned short FINISHED_STATE = 3;
 
     //readonly attribute unsigned short playbackState;
 
     // Playback this in-memory audio asset  
     // Many sources can share the same buffer  
-    //attribute AudioBuffer buffer;
+    attribute AudioBuffer? buffer;
 
     //attribute AudioParam playbackRate;
     //attribute boolean loop;
 
     void noteOn(double when);
     //void noteGrainOn(double when, double grainOffset, double grainDuration);
     void noteOff(double when);
 
--- a/dom/webidl/AudioContext.webidl
+++ b/dom/webidl/AudioContext.webidl
@@ -17,14 +17,15 @@ interface mozAudioContext {
 
     [Creator, Throws]
     AudioBuffer createBuffer(unsigned long numberOfChannels, unsigned long length, float sampleRate);
 
     // [Creator, Throws]
     // AudioBuffer createBuffer(ArrayBuffer buffer, boolean mixToMono);
 
     // AudioNode creation 
+    [Creator]
     AudioBufferSourceNode createBufferSource();
 
 };
 
 typedef mozAudioContext AudioContext;
 
--- a/dom/webidl/AudioNode.webidl
+++ b/dom/webidl/AudioNode.webidl
@@ -8,20 +8,23 @@
  *
  * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
  * liability, trademark and document use rules apply.
  */
 
 [PrefControlled]
 interface AudioNode {
 
+    [Throws]
     void connect(AudioNode destination, optional unsigned long output = 0, optional unsigned long input = 0);
 
-    //void connect(AudioParam destination, optional unsigned long output = 0);
+    // [Throws]
+    // void connect(AudioParam destination, optional unsigned long output = 0);
 
+    [Throws]
     void disconnect(optional unsigned long output = 0);
 
     readonly attribute AudioContext context;
-    //readonly attribute unsigned long numberOfInputs;
-    //readonly attribute unsigned long numberOfOutputs;
+    readonly attribute unsigned long numberOfInputs;
+    readonly attribute unsigned long numberOfOutputs;
 
 };
 
--- a/xpcom/glue/nsCycleCollectionParticipant.h
+++ b/xpcom/glue/nsCycleCollectionParticipant.h
@@ -1071,9 +1071,144 @@ struct Skippable
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(_f3)                               \
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(_f4)                               \
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(_f5)                               \
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(_f6)                               \
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(_f7)                               \
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(_f8)                               \
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
+#define NS_IMPL_CYCLE_COLLECTION_INHERITED_0(_class, _base)                    \
+ NS_IMPL_CYCLE_COLLECTION_CLASS(_class)                                        \
+ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(_class, _base)                \
+ NS_IMPL_CYCLE_COLLECTION_UNLINK_END                                           \
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(_class, _base)              \
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+#define NS_IMPL_CYCLE_COLLECTION_INHERITED_1(_class, _base, _f1)               \
+ NS_IMPL_CYCLE_COLLECTION_CLASS(_class)                                        \
+ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(_class, _base)                \
+ NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(_f1)                                 \
+ NS_IMPL_CYCLE_COLLECTION_UNLINK_END                                           \
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(_class, _base)              \
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(_f1)                               \
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+#define NS_IMPL_CYCLE_COLLECTION_INHERITED_2(_class, _base, _f1, _f2)          \
+ NS_IMPL_CYCLE_COLLECTION_CLASS(_class)                                        \
+ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(_class, _base)                \
+ NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(_f1)                                 \
+ NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(_f2)                                 \
+ NS_IMPL_CYCLE_COLLECTION_UNLINK_END                                           \
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(_class, _base)              \
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(_f1)                               \
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(_f2)                               \
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+#define NS_IMPL_CYCLE_COLLECTION_INHERITED_3(_class, _base, _f1, _f2, _f3)     \
+ NS_IMPL_CYCLE_COLLECTION_CLASS(_class)                                        \
+ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(_class, _base)                \
+ NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(_f1)                                 \
+ NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(_f2)                                 \
+ NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(_f3)                                 \
+ NS_IMPL_CYCLE_COLLECTION_UNLINK_END                                           \
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(_class, _base)              \
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(_f1)                               \
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(_f2)                               \
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(_f3)                               \
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+#define NS_IMPL_CYCLE_COLLECTION_INHERITED_4(_class, _base, _f1, _f2, _f3, _f4) \
+ NS_IMPL_CYCLE_COLLECTION_CLASS(_class)                                        \
+ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(_class, _base)                \
+ NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(_f1)                                 \
+ NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(_f2)                                 \
+ NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(_f3)                                 \
+ NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(_f4)                                 \
+ NS_IMPL_CYCLE_COLLECTION_UNLINK_END                                           \
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(_class, _base)              \
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(_f1)                               \
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(_f2)                               \
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(_f3)                               \
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(_f4)                               \
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+#define NS_IMPL_CYCLE_COLLECTION_INHERITED_5(_class, _base, _f1, _f2, _f3, _f4, _f5) \
+ NS_IMPL_CYCLE_COLLECTION_CLASS(_class)                                        \
+ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(_class, _base)                \
+ NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(_f1)                                 \
+ NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(_f2)                                 \
+ NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(_f3)                                 \
+ NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(_f4)                                 \
+ NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(_f5)                                 \
+ NS_IMPL_CYCLE_COLLECTION_UNLINK_END                                           \
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(_class, _base)              \
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(_f1)                               \
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(_f2)                               \
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(_f3)                               \
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(_f4)                               \
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(_f5)                               \
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+#define NS_IMPL_CYCLE_COLLECTION_INHERITED_6(_class, _base, _f1, _f2, _f3, _f4, _f5, _f6) \
+ NS_IMPL_CYCLE_COLLECTION_CLASS(_class)                                        \
+ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(_class, _base)                \
+ NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(_f1)                                 \
+ NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(_f2)                                 \
+ NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(_f3)                                 \
+ NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(_f4)                                 \
+ NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(_f5)                                 \
+ NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(_f6)                                 \
+ NS_IMPL_CYCLE_COLLECTION_UNLINK_END                                           \
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(_class, _base)              \
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(_f1)                               \
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(_f2)                               \
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(_f3)                               \
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(_f4)                               \
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(_f5)                               \
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(_f6)                               \
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+#define NS_IMPL_CYCLE_COLLECTION_INHERITED_7(_class, _base, _f1, _f2, _f3, _f4, _f5, _f6, _f7) \
+ NS_IMPL_CYCLE_COLLECTION_CLASS(_class)                                        \
+ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(_class, _base)                \
+ NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(_f1)                                 \
+ NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(_f2)                                 \
+ NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(_f3)                                 \
+ NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(_f4)                                 \
+ NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(_f5)                                 \
+ NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(_f6)                                 \
+ NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(_f7)                                 \
+ NS_IMPL_CYCLE_COLLECTION_UNLINK_END                                           \
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(_class, _base)              \
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(_f1)                               \
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(_f2)                               \
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(_f3)                               \
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(_f4)                               \
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(_f5)                               \
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(_f6)                               \
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(_f7)                               \
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+#define NS_IMPL_CYCLE_COLLECTION_INHERITED_8(_class, _base, _f1, _f2, _f3, _f4, _f5, _f6, _f7, _f8) \
+ NS_IMPL_CYCLE_COLLECTION_CLASS(_class)                                        \
+ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(_class, _base)                \
+ NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(_f1)                                 \
+ NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(_f2)                                 \
+ NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(_f3)                                 \
+ NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(_f4)                                 \
+ NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(_f5)                                 \
+ NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(_f6)                                 \
+ NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(_f7)                                 \
+ NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(_f8)                                 \
+ NS_IMPL_CYCLE_COLLECTION_UNLINK_END                                           \
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(_class, _base)              \
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(_f1)                               \
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(_f2)                               \
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(_f3)                               \
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(_f4)                               \
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(_f5)                               \
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(_f6)                               \
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(_f7)                               \
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(_f8)                               \
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
 #endif // nsCycleCollectionParticipant_h__