Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/midi/MIDIPort.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim:set ts=2 sw=2 sts=2 et cindent: */
3
/* This Source Code Form is subject to the terms of the Mozilla Public
4
 * License, v. 2.0. If a copy of the MPL was not distributed with this
5
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#include "mozilla/dom/MIDIPort.h"
8
#include "mozilla/dom/MIDIPortChild.h"
9
#include "mozilla/dom/MIDIAccess.h"
10
#include "mozilla/dom/MIDITypes.h"
11
#include "mozilla/ipc/PBackgroundChild.h"
12
#include "mozilla/ipc/BackgroundChild.h"
13
#include "mozilla/dom/Promise.h"
14
#include "mozilla/dom/MIDITypes.h"
15
#include "mozilla/Unused.h"
16
#include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, MOZ_COUNT_DTOR
17
18
using namespace mozilla::ipc;
19
20
namespace mozilla {
21
namespace dom {
22
23
NS_IMPL_CYCLE_COLLECTION_INHERITED(MIDIPort,
24
                                   DOMEventTargetHelper,
25
                                   mOpeningPromise,
26
                                   mClosingPromise)
27
28
0
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(MIDIPort,
29
0
                                               DOMEventTargetHelper)
30
0
NS_IMPL_CYCLE_COLLECTION_TRACE_END
31
32
0
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MIDIPort)
33
0
  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
34
0
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
35
36
NS_IMPL_ADDREF_INHERITED(MIDIPort, DOMEventTargetHelper)
37
NS_IMPL_RELEASE_INHERITED(MIDIPort, DOMEventTargetHelper)
38
39
MIDIPort::MIDIPort(nsPIDOMWindowInner* aWindow, MIDIAccess* aMIDIAccessParent) :
40
  DOMEventTargetHelper(aWindow),
41
  mMIDIAccessParent(aMIDIAccessParent)
42
0
{
43
0
  MOZ_ASSERT(aWindow);
44
0
  MOZ_ASSERT(aMIDIAccessParent);
45
0
}
46
47
MIDIPort::~MIDIPort()
48
0
{
49
0
  if (mMIDIAccessParent) {
50
0
    mMIDIAccessParent->RemovePortListener(this);
51
0
    mMIDIAccessParent = nullptr;
52
0
  }
53
0
  if (mPort) {
54
0
    // If the IPC port channel is still alive at this point, it means we're
55
0
    // probably CC'ing this port object. Send the shutdown message to also clean
56
0
    // up the IPC channel.
57
0
    mPort->SendShutdown();
58
0
    // This will unset the IPC Port pointer. Don't call anything after this.
59
0
    mPort->Teardown();
60
0
  }
61
0
}
62
63
bool
64
MIDIPort::Initialize(const MIDIPortInfo& aPortInfo, bool aSysexEnabled)
65
0
{
66
0
  RefPtr<MIDIPortChild> port = new MIDIPortChild(aPortInfo, aSysexEnabled, this);
67
0
  PBackgroundChild* b = BackgroundChild::GetForCurrentThread();
68
0
  MOZ_ASSERT(b, "Should always have a valid BackgroundChild when creating a port object!");
69
0
  if (!b->SendPMIDIPortConstructor(port, aPortInfo, aSysexEnabled)) {
70
0
    return false;
71
0
  }
72
0
  mPort = port;
73
0
  // Make sure to increase the ref count for the port, so it can be cleaned up
74
0
  // by the IPC manager.
75
0
  mPort->SetActorAlive();
76
0
  return true;
77
0
}
78
79
void
80
MIDIPort::UnsetIPCPort()
81
0
{
82
0
  mPort = nullptr;
83
0
}
84
85
JSObject*
86
MIDIPort::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
87
0
{
88
0
  return MIDIPort_Binding::Wrap(aCx, this, aGivenProto);
89
0
}
90
91
void
92
MIDIPort::GetId(nsString& aRetVal) const
93
0
{
94
0
  MOZ_ASSERT(mPort);
95
0
  aRetVal = mPort->MIDIPortInterface::Id();
96
0
}
97
98
void
99
MIDIPort::GetManufacturer(nsString& aRetVal) const
100
0
{
101
0
  MOZ_ASSERT(mPort);
102
0
  aRetVal = mPort->Manufacturer();
103
0
}
104
105
void
106
MIDIPort::GetName(nsString& aRetVal) const
107
0
{
108
0
  MOZ_ASSERT(mPort);
109
0
  aRetVal = mPort->Name();
110
0
}
111
112
void
113
MIDIPort::GetVersion(nsString& aRetVal) const
114
0
{
115
0
  MOZ_ASSERT(mPort);
116
0
  aRetVal = mPort->Version();
117
0
}
118
119
MIDIPortType
120
MIDIPort::Type() const
121
0
{
122
0
  MOZ_ASSERT(mPort);
123
0
  return mPort->Type();
124
0
}
125
126
MIDIPortConnectionState
127
MIDIPort::Connection() const
128
0
{
129
0
  MOZ_ASSERT(mPort);
130
0
  return mPort->ConnectionState();
131
0
}
132
133
MIDIPortDeviceState
134
MIDIPort::State() const
135
0
{
136
0
  MOZ_ASSERT(mPort);
137
0
  return mPort->DeviceState();
138
0
}
139
140
bool
141
MIDIPort::SysexEnabled() const
142
0
{
143
0
  MOZ_ASSERT(mPort);
144
0
  return mPort->SysexEnabled();
145
0
}
146
147
already_AddRefed<Promise>
148
MIDIPort::Open()
149
0
{
150
0
  MOZ_ASSERT(mPort);
151
0
  RefPtr<Promise> p;
152
0
  if (mOpeningPromise) {
153
0
    p = mOpeningPromise;
154
0
    return p.forget();
155
0
  }
156
0
  ErrorResult rv;
157
0
  nsCOMPtr<nsIGlobalObject> go = do_QueryInterface(GetOwner());
158
0
  p = Promise::Create(go, rv);
159
0
  if (rv.Failed()) {
160
0
    return nullptr;
161
0
  }
162
0
  mOpeningPromise = p;
163
0
  mPort->SendOpen();
164
0
  return p.forget();
165
0
}
166
167
already_AddRefed<Promise>
168
MIDIPort::Close()
169
0
{
170
0
  MOZ_ASSERT(mPort);
171
0
  RefPtr<Promise> p;
172
0
  if (mClosingPromise) {
173
0
    p = mClosingPromise;
174
0
    return p.forget();
175
0
  }
176
0
  ErrorResult rv;
177
0
  nsCOMPtr<nsIGlobalObject> go = do_QueryInterface(GetOwner());
178
0
  p = Promise::Create(go, rv);
179
0
  if (rv.Failed()) {
180
0
    return nullptr;
181
0
  }
182
0
  mClosingPromise = p;
183
0
  mPort->SendClose();
184
0
  return p.forget();
185
0
}
186
187
void
188
MIDIPort::Notify(const void_t& aVoid)
189
0
{
190
0
  // If we're getting notified, it means the MIDIAccess parent object is dead. Nullify our copy.
191
0
  mMIDIAccessParent = nullptr;
192
0
}
193
194
void
195
MIDIPort::FireStateChangeEvent()
196
0
{
197
0
  MOZ_ASSERT(mPort);
198
0
  if (mPort->ConnectionState() == MIDIPortConnectionState::Open ||
199
0
      mPort->ConnectionState() == MIDIPortConnectionState::Pending) {
200
0
    if (mOpeningPromise) {
201
0
      mOpeningPromise->MaybeResolve(this);
202
0
      mOpeningPromise = nullptr;
203
0
    }
204
0
  } else if (mPort->ConnectionState() == MIDIPortConnectionState::Closed) {
205
0
    if (mOpeningPromise) {
206
0
      mOpeningPromise->MaybeReject(NS_ERROR_DOM_INVALID_ACCESS_ERR);
207
0
      mOpeningPromise = nullptr;
208
0
    }
209
0
    if (mClosingPromise) {
210
0
      mClosingPromise->MaybeResolve(this);
211
0
      mClosingPromise = nullptr;
212
0
    }
213
0
  }
214
0
  if (mPort->DeviceState() == MIDIPortDeviceState::Connected &&
215
0
      mPort->ConnectionState() == MIDIPortConnectionState::Pending) {
216
0
    mPort->SendOpen();
217
0
  }
218
0
  // Fire MIDIAccess events first so that the port is no longer in the port maps.
219
0
  if (mMIDIAccessParent) {
220
0
    mMIDIAccessParent->FireConnectionEvent(this);
221
0
  }
222
0
223
0
  MIDIConnectionEventInit init;
224
0
  init.mPort = this;
225
0
  RefPtr<MIDIConnectionEvent> event(
226
0
    MIDIConnectionEvent::Constructor(this, NS_LITERAL_STRING("statechange"), init));
227
0
  DispatchTrustedEvent(event);
228
0
}
229
230
void
231
MIDIPort::Receive(const nsTArray<MIDIMessage>& aMsg)
232
0
{
233
0
  MOZ_CRASH("We should never get here!");
234
0
}
235
236
}
237
}