Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/performance/PerformanceObserver.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 "PerformanceObserver.h"
8
9
#include "mozilla/dom/Performance.h"
10
#include "mozilla/dom/PerformanceBinding.h"
11
#include "mozilla/dom/PerformanceEntryBinding.h"
12
#include "mozilla/dom/PerformanceObserverBinding.h"
13
#include "mozilla/dom/WorkerPrivate.h"
14
#include "mozilla/dom/WorkerScope.h"
15
#include "nsIScriptError.h"
16
#include "nsPIDOMWindow.h"
17
#include "nsQueryObject.h"
18
#include "nsString.h"
19
#include "PerformanceEntry.h"
20
#include "PerformanceObserverEntryList.h"
21
22
using namespace mozilla;
23
using namespace mozilla::dom;
24
25
NS_IMPL_CYCLE_COLLECTION_CLASS(PerformanceObserver)
26
0
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(PerformanceObserver)
27
0
  tmp->Disconnect();
28
0
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mCallback)
29
0
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mPerformance)
30
0
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mOwner)
31
0
  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
32
0
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
33
0
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(PerformanceObserver)
34
0
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCallback)
35
0
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPerformance)
36
0
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwner)
37
0
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
38
NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(PerformanceObserver)
39
40
NS_IMPL_CYCLE_COLLECTING_ADDREF(PerformanceObserver)
41
NS_IMPL_CYCLE_COLLECTING_RELEASE(PerformanceObserver)
42
0
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PerformanceObserver)
43
0
  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
44
0
  NS_INTERFACE_MAP_ENTRY(nsISupports)
45
0
NS_INTERFACE_MAP_END
46
47
PerformanceObserver::PerformanceObserver(nsPIDOMWindowInner* aOwner,
48
                                         PerformanceObserverCallback& aCb)
49
  : mOwner(aOwner)
50
  , mCallback(&aCb)
51
  , mConnected(false)
52
0
{
53
0
  MOZ_ASSERT(mOwner);
54
0
  mPerformance = aOwner->GetPerformance();
55
0
}
56
57
PerformanceObserver::PerformanceObserver(WorkerPrivate* aWorkerPrivate,
58
                                         PerformanceObserverCallback& aCb)
59
  : mCallback(&aCb)
60
  , mConnected(false)
61
0
{
62
0
  MOZ_ASSERT(aWorkerPrivate);
63
0
  mPerformance = aWorkerPrivate->GlobalScope()->GetPerformance();
64
0
}
65
66
PerformanceObserver::~PerformanceObserver()
67
0
{
68
0
  Disconnect();
69
0
  MOZ_ASSERT(!mConnected);
70
0
}
71
72
// static
73
already_AddRefed<PerformanceObserver>
74
PerformanceObserver::Constructor(const GlobalObject& aGlobal,
75
                                 PerformanceObserverCallback& aCb,
76
                                 ErrorResult& aRv)
77
0
{
78
0
  if (NS_IsMainThread()) {
79
0
    nsCOMPtr<nsPIDOMWindowInner> ownerWindow =
80
0
      do_QueryInterface(aGlobal.GetAsSupports());
81
0
    if (!ownerWindow) {
82
0
      aRv.Throw(NS_ERROR_FAILURE);
83
0
      return nullptr;
84
0
    }
85
0
86
0
    RefPtr<PerformanceObserver> observer =
87
0
      new PerformanceObserver(ownerWindow, aCb);
88
0
    return observer.forget();
89
0
  }
90
0
91
0
  JSContext* cx = aGlobal.Context();
92
0
  WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(cx);
93
0
  MOZ_ASSERT(workerPrivate);
94
0
95
0
  RefPtr<PerformanceObserver> observer =
96
0
    new PerformanceObserver(workerPrivate, aCb);
97
0
  return observer.forget();
98
0
}
99
100
JSObject*
101
PerformanceObserver::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
102
0
{
103
0
  return PerformanceObserver_Binding::Wrap(aCx, this, aGivenProto);
104
0
}
105
106
void
107
PerformanceObserver::Notify()
108
0
{
109
0
  if (mQueuedEntries.IsEmpty()) {
110
0
    return;
111
0
  }
112
0
  RefPtr<PerformanceObserverEntryList> list =
113
0
    new PerformanceObserverEntryList(this, mQueuedEntries);
114
0
115
0
  mQueuedEntries.Clear();
116
0
117
0
  ErrorResult rv;
118
0
  mCallback->Call(this, *list, *this, rv);
119
0
  if (NS_WARN_IF(rv.Failed())) {
120
0
    rv.SuppressException();
121
0
  }
122
0
}
123
124
void
125
PerformanceObserver::QueueEntry(PerformanceEntry* aEntry)
126
0
{
127
0
  MOZ_ASSERT(aEntry);
128
0
129
0
  nsAutoString entryType;
130
0
  aEntry->GetEntryType(entryType);
131
0
  if (!mEntryTypes.Contains<nsString>(entryType)) {
132
0
    return;
133
0
  }
134
0
135
0
  mQueuedEntries.AppendElement(aEntry);
136
0
}
137
138
static const char16_t *const sValidTypeNames[4] = {
139
  u"navigation",
140
  u"mark",
141
  u"measure",
142
  u"resource",
143
};
144
145
void
146
PerformanceObserver::Observe(const PerformanceObserverInit& aOptions)
147
0
{
148
0
  if (aOptions.mEntryTypes.IsEmpty()) {
149
0
    return;
150
0
  }
151
0
152
0
  nsTArray<nsString> validEntryTypes;
153
0
154
0
  for (const char16_t* name : sValidTypeNames) {
155
0
    nsDependentString validTypeName(name);
156
0
    if (aOptions.mEntryTypes.Contains<nsString>(validTypeName) &&
157
0
        !validEntryTypes.Contains<nsString>(validTypeName)) {
158
0
      validEntryTypes.AppendElement(validTypeName);
159
0
    }
160
0
  }
161
0
162
0
  nsAutoString invalidTypesJoined;
163
0
  bool addComma = false;
164
0
  for (const auto& type : aOptions.mEntryTypes) {
165
0
    if (!validEntryTypes.Contains<nsString>(type)) {
166
0
      if (addComma) {
167
0
        invalidTypesJoined.AppendLiteral(", ");
168
0
      }
169
0
      addComma = true;
170
0
      invalidTypesJoined.Append(type);
171
0
    }
172
0
  }
173
0
174
0
  if (!invalidTypesJoined.IsEmpty()) {
175
0
    if (!NS_IsMainThread()) {
176
0
      nsTArray<nsString> params;
177
0
      params.AppendElement(invalidTypesJoined);
178
0
      WorkerPrivate::ReportErrorToConsole("UnsupportedEntryTypesIgnored",
179
0
                                          params);
180
0
    } else {
181
0
      nsCOMPtr<nsPIDOMWindowInner> ownerWindow =
182
0
        do_QueryInterface(mOwner);
183
0
      nsIDocument* document = ownerWindow->GetExtantDoc();
184
0
      const char16_t* params[] = { invalidTypesJoined.get() };
185
0
      nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
186
0
                                      NS_LITERAL_CSTRING("DOM"), document,
187
0
                                      nsContentUtils::eDOM_PROPERTIES,
188
0
                                      "UnsupportedEntryTypesIgnored", params, 1);
189
0
    }
190
0
  }
191
0
192
0
  if (validEntryTypes.IsEmpty()) {
193
0
    return;
194
0
  }
195
0
196
0
  mEntryTypes.SwapElements(validEntryTypes);
197
0
198
0
  mPerformance->AddObserver(this);
199
0
200
0
  if (aOptions.mBuffered) {
201
0
    for (auto entryType : mEntryTypes) {
202
0
      nsTArray<RefPtr<PerformanceEntry>> existingEntries;
203
0
      mPerformance->GetEntriesByType(entryType, existingEntries);
204
0
      if (!existingEntries.IsEmpty()) {
205
0
        mQueuedEntries.AppendElements(existingEntries);
206
0
      }
207
0
    }
208
0
  }
209
0
210
0
  mConnected = true;
211
0
}
212
213
void
214
PerformanceObserver::Disconnect()
215
0
{
216
0
  if (mConnected) {
217
0
    MOZ_ASSERT(mPerformance);
218
0
    mPerformance->RemoveObserver(this);
219
0
    mConnected = false;
220
0
  }
221
0
}
222
223
void
224
PerformanceObserver::TakeRecords(nsTArray<RefPtr<PerformanceEntry>>& aRetval)
225
0
{
226
0
  MOZ_ASSERT(aRetval.IsEmpty());
227
0
  aRetval.SwapElements(mQueuedEntries);
228
0
}