Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/presentation/PresentationAvailability.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
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 "PresentationAvailability.h"
8
9
#include "mozilla/dom/PresentationAvailabilityBinding.h"
10
#include "mozilla/dom/Promise.h"
11
#include "mozilla/Unused.h"
12
#include "nsContentUtils.h"
13
#include "nsCycleCollectionParticipant.h"
14
#include "nsIPresentationDeviceManager.h"
15
#include "nsIPresentationService.h"
16
#include "nsServiceManagerUtils.h"
17
#include "PresentationLog.h"
18
19
using namespace mozilla;
20
using namespace mozilla::dom;
21
22
NS_IMPL_CYCLE_COLLECTION_CLASS(PresentationAvailability)
23
24
0
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(PresentationAvailability, DOMEventTargetHelper)
25
0
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPromises)
26
0
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
27
28
0
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(PresentationAvailability, DOMEventTargetHelper)
29
0
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mPromises);
30
0
  tmp->Shutdown();
31
0
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
32
33
NS_IMPL_ADDREF_INHERITED(PresentationAvailability, DOMEventTargetHelper)
34
NS_IMPL_RELEASE_INHERITED(PresentationAvailability, DOMEventTargetHelper)
35
36
0
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PresentationAvailability)
37
0
  NS_INTERFACE_MAP_ENTRY(nsIPresentationAvailabilityListener)
38
0
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
39
40
/* static */ already_AddRefed<PresentationAvailability>
41
PresentationAvailability::Create(nsPIDOMWindowInner* aWindow,
42
                                 const nsTArray<nsString>& aUrls,
43
                                 RefPtr<Promise>& aPromise)
44
0
{
45
0
  RefPtr<PresentationAvailability> availability =
46
0
    new PresentationAvailability(aWindow, aUrls);
47
0
  return NS_WARN_IF(!availability->Init(aPromise)) ? nullptr
48
0
                                                   : availability.forget();
49
0
}
50
51
PresentationAvailability::PresentationAvailability(nsPIDOMWindowInner* aWindow,
52
                                                   const nsTArray<nsString>& aUrls)
53
  : DOMEventTargetHelper(aWindow)
54
  , mIsAvailable(false)
55
  , mUrls(aUrls)
56
0
{
57
0
  for (uint32_t i = 0; i < mUrls.Length(); ++i) {
58
0
    mAvailabilityOfUrl.AppendElement(false);
59
0
  }
60
0
}
61
62
PresentationAvailability::~PresentationAvailability()
63
0
{
64
0
  Shutdown();
65
0
}
66
67
bool
68
PresentationAvailability::Init(RefPtr<Promise>& aPromise)
69
0
{
70
0
  nsCOMPtr<nsIPresentationService> service =
71
0
    do_GetService(PRESENTATION_SERVICE_CONTRACTID);
72
0
  if (NS_WARN_IF(!service)) {
73
0
    return false;
74
0
  }
75
0
76
0
  nsresult rv = service->RegisterAvailabilityListener(mUrls, this);
77
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
78
0
    // If the user agent is unable to monitor available device,
79
0
    // Resolve promise with |value| set to false.
80
0
    mIsAvailable = false;
81
0
    aPromise->MaybeResolve(this);
82
0
    return true;
83
0
  }
84
0
85
0
  EnqueuePromise(aPromise);
86
0
87
0
  AvailabilityCollection* collection = AvailabilityCollection::GetSingleton();
88
0
  if (collection) {
89
0
    collection->Add(this);
90
0
  }
91
0
92
0
  return true;
93
0
}
94
95
void PresentationAvailability::Shutdown()
96
0
{
97
0
  AvailabilityCollection* collection = AvailabilityCollection::GetSingleton();
98
0
  if (collection ) {
99
0
    collection->Remove(this);
100
0
  }
101
0
102
0
  nsCOMPtr<nsIPresentationService> service =
103
0
    do_GetService(PRESENTATION_SERVICE_CONTRACTID);
104
0
  if (NS_WARN_IF(!service)) {
105
0
    return;
106
0
  }
107
0
108
0
  Unused <<
109
0
    NS_WARN_IF(NS_FAILED(service->UnregisterAvailabilityListener(mUrls,
110
0
                                                                 this)));
111
0
}
112
113
/* virtual */ void
114
PresentationAvailability::DisconnectFromOwner()
115
0
{
116
0
  Shutdown();
117
0
  DOMEventTargetHelper::DisconnectFromOwner();
118
0
}
119
120
/* virtual */ JSObject*
121
PresentationAvailability::WrapObject(JSContext* aCx,
122
                                     JS::Handle<JSObject*> aGivenProto)
123
0
{
124
0
  return PresentationAvailability_Binding::Wrap(aCx, this, aGivenProto);
125
0
}
126
127
bool
128
PresentationAvailability::Equals(const uint64_t aWindowID,
129
                                 const nsTArray<nsString>& aUrls) const
130
0
{
131
0
  if (GetOwner() && GetOwner()->WindowID() == aWindowID &&
132
0
      mUrls.Length() == aUrls.Length()) {
133
0
    for (const auto& url : aUrls) {
134
0
      if (!mUrls.Contains(url)) {
135
0
        return false;
136
0
      }
137
0
    }
138
0
    return true;
139
0
  }
140
0
141
0
  return false;
142
0
}
143
144
bool
145
PresentationAvailability::IsCachedValueReady()
146
0
{
147
0
  // All pending promises will be solved when cached value is ready and
148
0
  // no promise should be enqueued afterward.
149
0
  return mPromises.IsEmpty();
150
0
}
151
152
void
153
PresentationAvailability::EnqueuePromise(RefPtr<Promise>& aPromise)
154
0
{
155
0
  mPromises.AppendElement(aPromise);
156
0
}
157
158
bool
159
PresentationAvailability::Value() const
160
0
{
161
0
  if (nsContentUtils::ShouldResistFingerprinting()) {
162
0
    return false;
163
0
  }
164
0
165
0
  return mIsAvailable;
166
0
}
167
168
NS_IMETHODIMP
169
PresentationAvailability::NotifyAvailableChange(const nsTArray<nsString>& aAvailabilityUrls,
170
                                                bool aIsAvailable)
171
0
{
172
0
  bool available = false;
173
0
  for (uint32_t i = 0; i < mUrls.Length(); ++i) {
174
0
    if (aAvailabilityUrls.Contains(mUrls[i])) {
175
0
      mAvailabilityOfUrl[i] = aIsAvailable;
176
0
    }
177
0
    available |= mAvailabilityOfUrl[i];
178
0
  }
179
0
180
0
  return NS_DispatchToCurrentThread(NewRunnableMethod<bool>(
181
0
    "dom::PresentationAvailability::UpdateAvailabilityAndDispatchEvent",
182
0
    this,
183
0
    &PresentationAvailability::UpdateAvailabilityAndDispatchEvent,
184
0
    available));
185
0
}
186
187
void
188
PresentationAvailability::UpdateAvailabilityAndDispatchEvent(bool aIsAvailable)
189
0
{
190
0
  PRES_DEBUG("%s\n", __func__);
191
0
  bool isChanged = (aIsAvailable != mIsAvailable);
192
0
193
0
  mIsAvailable = aIsAvailable;
194
0
195
0
  if (!mPromises.IsEmpty()) {
196
0
    // Use the first availability change notification to resolve promise.
197
0
    do {
198
0
      nsTArray<RefPtr<Promise>> promises = std::move(mPromises);
199
0
200
0
      if (nsContentUtils::ShouldResistFingerprinting()) {
201
0
        continue;
202
0
      }
203
0
204
0
      for (auto& promise : promises) {
205
0
        promise->MaybeResolve(this);
206
0
      }
207
0
      // more promises may have been added to mPromises, at least in theory
208
0
    } while (!mPromises.IsEmpty());
209
0
210
0
    return;
211
0
  }
212
0
213
0
  if (nsContentUtils::ShouldResistFingerprinting()) {
214
0
    return;
215
0
  }
216
0
217
0
  if (isChanged) {
218
0
    Unused <<
219
0
      NS_WARN_IF(NS_FAILED(DispatchTrustedEvent(NS_LITERAL_STRING("change"))));
220
0
  }
221
0
}