summaryrefslogtreecommitdiff
path: root/dom/performance
diff options
context:
space:
mode:
authorFranklinDM <mrmineshafter17@gmail.com>2023-04-05 22:22:34 +0800
committerFranklinDM <mrmineshafter17@gmail.com>2023-04-10 18:22:53 +0800
commitd4138780ee267baf56250bb3a592419202553385 (patch)
treeeff468633e02e8277efc289c8694e826d0cc663a /dom/performance
parent5fc711ba17cd86a7f168c159b551acdb598dbf1f (diff)
downloaduxp-d4138780ee267baf56250bb3a592419202553385.tar.gz
Issue #2053 - Part 2: Update PerformanceMeasure to User Timing L3
There are a few minor differences between this and Mozilla's implementation: (a) The type error messages were not hardcoded to the Performance class and were moved to Errors.msg instead. (b) PerformanceMeasureOptions is used directly and doesn't use the the Maybe<> container class. I haven't found the reason yet, but PerformanceMeasureOptions is disallowed from having a copy constructor and without that, it isn't possible to use it with Maybe<>... There doesn't seem to be any problem with using it directly, though. (c) Resist fingerprinting-pref changes were skipped. Partially based on https://bugzilla.mozilla.org/show_bug.cgi?id=1762482
Diffstat (limited to 'dom/performance')
-rwxr-xr-xdom/performance/Performance.cpp207
-rw-r--r--dom/performance/Performance.h39
-rw-r--r--dom/performance/PerformanceMeasure.cpp45
-rw-r--r--dom/performance/PerformanceMeasure.h12
4 files changed, 261 insertions, 42 deletions
diff --git a/dom/performance/Performance.cpp b/dom/performance/Performance.cpp
index 020dc0d89a..ebdddeb835 100755
--- a/dom/performance/Performance.cpp
+++ b/dom/performance/Performance.cpp
@@ -20,6 +20,7 @@
#include "mozilla/dom/PerformanceNavigationBinding.h"
#include "mozilla/dom/PerformanceObserverBinding.h"
#include "mozilla/dom/PerformanceNavigationTiming.h"
+#include "mozilla/dom/MessagePortBinding.h"
#include "mozilla/IntegerPrintfMacros.h"
#include "mozilla/Preferences.h"
#include "mozilla/TimerClamping.h"
@@ -65,6 +66,12 @@ private:
} // anonymous namespace
+enum class Performance::ResolveTimestampAttribute {
+ Start,
+ End,
+ Duration,
+};
+
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(Performance)
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
@@ -257,8 +264,8 @@ Performance::ClearMarks(const Optional<nsAString>& aName)
}
DOMHighResTimeStamp
-Performance::ResolveTimestampFromName(const nsAString& aName,
- ErrorResult& aRv)
+Performance::ConvertMarkToTimestampWithString(const nsAString& aName,
+ ErrorResult& aRv)
{
AutoTArray<RefPtr<PerformanceEntry>, 1> arr;
DOMHighResTimeStamp ts;
@@ -272,7 +279,7 @@ Performance::ResolveTimestampFromName(const nsAString& aName,
}
if (!IsPerformanceTimingAttribute(aName)) {
- aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
+ aRv.ThrowTypeError<MSG_PMO_UNKNOWN_MARK_NAME>(aName);
return 0;
}
@@ -285,50 +292,192 @@ Performance::ResolveTimestampFromName(const nsAString& aName,
return ts - CreationTime();
}
-void
-Performance::Measure(const nsAString& aName,
- const Optional<nsAString>& aStartMark,
+DOMHighResTimeStamp
+Performance::ConvertMarkToTimestampWithDOMHighResTimeStamp(
+ const ResolveTimestampAttribute aAttribute,
+ const DOMHighResTimeStamp aTimestamp,
+ ErrorResult& aRv)
+{
+ if (aTimestamp < 0) {
+ nsAutoString attributeName;
+ switch (aAttribute) {
+ case ResolveTimestampAttribute::Start:
+ attributeName = NS_LITERAL_STRING("start");
+ break;
+ case ResolveTimestampAttribute::End:
+ attributeName = NS_LITERAL_STRING("end");
+ break;
+ case ResolveTimestampAttribute::Duration:
+ attributeName = NS_LITERAL_STRING("duration");
+ break;
+ }
+
+ aRv.ThrowTypeError<MSG_NO_NEGATIVE_ATTR>(attributeName);
+ }
+ return aTimestamp;
+}
+
+DOMHighResTimeStamp
+Performance::ConvertMarkToTimestamp(
+ const ResolveTimestampAttribute aAttribute,
+ const OwningStringOrDouble& aMarkNameOrTimestamp,
+ ErrorResult& aRv)
+{
+ if (aMarkNameOrTimestamp.IsString()) {
+ return ConvertMarkToTimestampWithString(aMarkNameOrTimestamp.GetAsString(),
+ aRv);
+ }
+ return ConvertMarkToTimestampWithDOMHighResTimeStamp(
+ aAttribute, aMarkNameOrTimestamp.GetAsDouble(), aRv);
+}
+
+DOMHighResTimeStamp
+Performance::ResolveEndTimeForMeasure(
+ const Optional<nsAString>& aEndMark,
+ const PerformanceMeasureOptions* aOptions,
+ ErrorResult& aRv)
+{
+ DOMHighResTimeStamp endTime;
+ if (aEndMark.WasPassed()) {
+ endTime = ConvertMarkToTimestampWithString(aEndMark.Value(), aRv);
+ } else if (aOptions != nullptr && aOptions->mEnd.WasPassed()) {
+ endTime = ConvertMarkToTimestamp(ResolveTimestampAttribute::End,
+ aOptions->mEnd.Value(), aRv);
+ } else if (aOptions != nullptr && aOptions->mStart.WasPassed() &&
+ aOptions->mDuration.WasPassed()) {
+ const DOMHighResTimeStamp start = ConvertMarkToTimestamp(
+ ResolveTimestampAttribute::Start, aOptions->mStart.Value(), aRv);
+ if (aRv.Failed()) {
+ return 0;
+ }
+ const DOMHighResTimeStamp duration =
+ ConvertMarkToTimestampWithDOMHighResTimeStamp(
+ ResolveTimestampAttribute::Duration,
+ aOptions->mDuration.Value(),
+ aRv);
+ if (aRv.Failed()) {
+ return 0;
+ }
+
+ endTime = start + duration;
+ } else {
+ endTime = Now();
+ }
+ return endTime;
+}
+
+DOMHighResTimeStamp
+Performance::ResolveStartTimeForMeasure(
+ const nsAString* aStartMark,
+ const PerformanceMeasureOptions* aOptions,
+ ErrorResult& aRv)
+{
+ DOMHighResTimeStamp startTime;
+ if (aOptions != nullptr && aOptions->mStart.WasPassed()) {
+ startTime = ConvertMarkToTimestamp(ResolveTimestampAttribute::Start,
+ aOptions->mStart.Value(),
+ aRv);
+ } else if (aOptions != nullptr && aOptions->mDuration.WasPassed() &&
+ aOptions->mEnd.WasPassed()) {
+ const DOMHighResTimeStamp duration =
+ ConvertMarkToTimestampWithDOMHighResTimeStamp(
+ ResolveTimestampAttribute::Duration,
+ aOptions->mDuration.Value(),
+ aRv);
+ if (aRv.Failed()) {
+ return 0;
+ }
+
+ const DOMHighResTimeStamp end = ConvertMarkToTimestamp(
+ ResolveTimestampAttribute::End, aOptions->mEnd.Value(), aRv);
+ if (aRv.Failed()) {
+ return 0;
+ }
+
+ startTime = end - duration;
+ } else if (aStartMark != nullptr) {
+ startTime = ConvertMarkToTimestampWithString(*aStartMark, aRv);
+ } else {
+ startTime = 0;
+ }
+
+ return startTime;
+}
+
+already_AddRefed<PerformanceMeasure>
+Performance::Measure(JSContext* aCx,
+ const nsAString& aName,
+ const StringOrPerformanceMeasureOptions& aStartOrMeasureOptions,
const Optional<nsAString>& aEndMark,
ErrorResult& aRv)
{
// Don't add the entry if the buffer is full. XXX should be removed by bug
// 1159003.
if (mUserEntries.Length() >= mResourceTimingBufferSize) {
- return;
+ return nullptr;
}
- DOMHighResTimeStamp startTime;
- DOMHighResTimeStamp endTime;
-
- if (IsPerformanceTimingAttribute(aName)) {
- aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
- return;
+ const PerformanceMeasureOptions* options = nullptr;
+ if (aStartOrMeasureOptions.IsPerformanceMeasureOptions()) {
+ options = &aStartOrMeasureOptions.GetAsPerformanceMeasureOptions();
}
- if (aStartMark.WasPassed()) {
- startTime = ResolveTimestampFromName(aStartMark.Value(), aRv);
- if (NS_WARN_IF(aRv.Failed())) {
- return;
+ const bool isOptionsNotEmpty =
+ (options != nullptr) &&
+ (!options->mDetail.isUndefined() || options->mStart.WasPassed() ||
+ options->mEnd.WasPassed() || options->mDuration.WasPassed());
+ if (isOptionsNotEmpty) {
+ if (aEndMark.WasPassed()) {
+ aRv.ThrowTypeError<MSG_PMO_NO_SEPARATE_ENDMARK>();
+ return nullptr;
+ }
+
+ if (!options->mStart.WasPassed() && !options->mEnd.WasPassed()) {
+ aRv.ThrowTypeError<MSG_PMO_MISSING_STARTENDMARK>();
+ return nullptr;
+ }
+
+ if (options->mStart.WasPassed() && options->mDuration.WasPassed() &&
+ options->mEnd.WasPassed()) {
+ aRv.ThrowTypeError<MSG_PMO_INVALID_MEMBERS>();
+ return nullptr;
}
- } else {
- // Navigation start is used in this case, but since DOMHighResTimeStamp is
- // in relation to navigation start, this will be zero if a name is not
- // passed.
- startTime = 0;
}
- if (aEndMark.WasPassed()) {
- endTime = ResolveTimestampFromName(aEndMark.Value(), aRv);
- if (NS_WARN_IF(aRv.Failed())) {
- return;
+ const DOMHighResTimeStamp endTime =
+ ResolveEndTimeForMeasure(aEndMark, options, aRv);
+ if (NS_WARN_IF(aRv.Failed())) {
+ return nullptr;
+ }
+
+ const nsAString* startMark = nullptr;
+ if (aStartOrMeasureOptions.IsString()) {
+ startMark = &aStartOrMeasureOptions.GetAsString();
+ }
+ const DOMHighResTimeStamp startTime =
+ ResolveStartTimeForMeasure(startMark, options, aRv);
+ if (NS_WARN_IF(aRv.Failed())) {
+ return nullptr;
+ }
+
+ JS::Rooted<JS::Value> detail(aCx);
+ if (options != nullptr && !options->mDetail.isNullOrUndefined()) {
+ StructuredSerializeOptions serializeOptions;
+ JS::Rooted<JS::Value> valueToClone(aCx, options->mDetail);
+ nsContentUtils::StructuredClone(aCx, GetParentObject(), valueToClone,
+ serializeOptions, &detail, aRv);
+ if (aRv.Failed()) {
+ return nullptr;
}
} else {
- endTime = Now();
+ detail.setNull();
}
- RefPtr<PerformanceMeasure> performanceMeasure =
- new PerformanceMeasure(GetAsISupports(), aName, startTime, endTime);
+ RefPtr<PerformanceMeasure> performanceMeasure = new PerformanceMeasure(
+ GetAsISupports(), aName, startTime, endTime, detail);
InsertUserEntry(performanceMeasure);
+
+ return performanceMeasure.forget();
}
void
diff --git a/dom/performance/Performance.h b/dom/performance/Performance.h
index 2574fcdd3e..772e88c6da 100644
--- a/dom/performance/Performance.h
+++ b/dom/performance/Performance.h
@@ -20,11 +20,16 @@ class ErrorResult;
namespace dom {
+class OwningStringOrDouble;
+class StringOrPerformanceMeasureOptions;
class PerformanceEntry;
+struct PerformanceMeasureOptions;
+class PerformanceMeasure;
class PerformanceNavigation;
class PerformanceObserver;
class PerformanceService;
class PerformanceTiming;
+struct StructuredSerializeOptions;
namespace workers {
class WorkerPrivate;
@@ -75,10 +80,10 @@ public:
void ClearMarks(const Optional<nsAString>& aName);
- void Measure(const nsAString& aName,
- const Optional<nsAString>& aStartMark,
- const Optional<nsAString>& aEndMark,
- ErrorResult& aRv);
+ already_AddRefed<PerformanceMeasure> Measure(
+ JSContext* aCx, const nsAString& aName,
+ const StringOrPerformanceMeasureOptions& aStartOrMeasureOptions,
+ const Optional<nsAString>& aEndMark, ErrorResult& aRv);
void ClearMeasures(const Optional<nsAString>& aName);
@@ -116,9 +121,6 @@ protected:
void ClearUserEntries(const Optional<nsAString>& aEntryName,
const nsAString& aEntryType);
- DOMHighResTimeStamp ResolveTimestampFromName(const nsAString& aName,
- ErrorResult& aRv);
-
virtual nsISupports* GetAsISupports() = 0;
virtual void DispatchBufferFullEvent() = 0;
@@ -163,6 +165,29 @@ protected:
bool mPendingNotificationObserversTask;
RefPtr<PerformanceService> mPerformanceService;
+
+private:
+ // The attributes of a PerformanceMeasureOptions that we call
+ // ResolveTimestamp* on.
+ enum class ResolveTimestampAttribute;
+
+ DOMHighResTimeStamp ConvertMarkToTimestampWithString(const nsAString& aName,
+ ErrorResult& aRv);
+ DOMHighResTimeStamp ConvertMarkToTimestampWithDOMHighResTimeStamp(
+ const ResolveTimestampAttribute aAttribute, const double aTimestamp,
+ ErrorResult& aRv);
+ DOMHighResTimeStamp ConvertMarkToTimestamp(
+ const ResolveTimestampAttribute aAttribute,
+ const OwningStringOrDouble& aMarkNameOrTimestamp, ErrorResult& aRv);
+
+ DOMHighResTimeStamp ResolveEndTimeForMeasure(
+ const Optional<nsAString>& aEndMark,
+ const PerformanceMeasureOptions* aOptions,
+ ErrorResult& aRv);
+ DOMHighResTimeStamp ResolveStartTimeForMeasure(
+ const nsAString* aStartMark,
+ const PerformanceMeasureOptions* aOptions,
+ ErrorResult& aRv);
};
} // namespace dom
diff --git a/dom/performance/PerformanceMeasure.cpp b/dom/performance/PerformanceMeasure.cpp
index 2e429e6814..3c6e73230f 100644
--- a/dom/performance/PerformanceMeasure.cpp
+++ b/dom/performance/PerformanceMeasure.cpp
@@ -12,10 +12,12 @@ using namespace mozilla::dom;
PerformanceMeasure::PerformanceMeasure(nsISupports* aParent,
const nsAString& aName,
DOMHighResTimeStamp aStartTime,
- DOMHighResTimeStamp aEndTime)
-: PerformanceEntry(aParent, aName, NS_LITERAL_STRING("measure")),
- mStartTime(aStartTime),
- mDuration(aEndTime - aStartTime)
+ DOMHighResTimeStamp aEndTime,
+ const JS::Handle<JS::Value>& aDetail)
+ : PerformanceEntry(aParent, aName, NS_LITERAL_STRING("measure"))
+ , mStartTime(aStartTime)
+ , mDuration(aEndTime - aStartTime)
+ , mDetail(aDetail)
{
// mParent is null in workers.
MOZ_ASSERT(mParent || !NS_IsMainThread());
@@ -23,10 +25,43 @@ PerformanceMeasure::PerformanceMeasure(nsISupports* aParent,
PerformanceMeasure::~PerformanceMeasure()
{
+ mozilla::DropJSObjects(this);
}
+NS_IMPL_CYCLE_COLLECTION_CLASS(PerformanceMeasure)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(PerformanceMeasure,
+ PerformanceEntry)
+ tmp->mDetail.setUndefined();
+ mozilla::DropJSObjects(tmp);
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(PerformanceMeasure,
+ PerformanceEntry)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(PerformanceMeasure,
+ PerformanceEntry)
+ NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mDetail)
+NS_IMPL_CYCLE_COLLECTION_TRACE_END
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PerformanceMeasure)
+NS_INTERFACE_MAP_END_INHERITING(PerformanceEntry)
+NS_IMPL_ADDREF_INHERITED(PerformanceMeasure, PerformanceEntry)
+NS_IMPL_RELEASE_INHERITED(PerformanceMeasure, PerformanceEntry)
+
JSObject*
-PerformanceMeasure::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
+PerformanceMeasure::WrapObject(JSContext* aCx,
+ JS::Handle<JSObject*> aGivenProto)
{
return PerformanceMeasureBinding::Wrap(aCx, this, aGivenProto);
}
+
+void
+PerformanceMeasure::GetDetail(JSContext* aCx,
+ JS::MutableHandle<JS::Value> aRv)
+{
+ // Return a copy so that this method always returns the value it is set to
+ // (i.e. it'll return the same value even if the caller assigns to it). Note
+ // that if detail is an object, its contents can be mutated and this is
+ // expected.
+ aRv.set(mDetail);
+}
diff --git a/dom/performance/PerformanceMeasure.h b/dom/performance/PerformanceMeasure.h
index 5e70420d96..83d2ba3406 100644
--- a/dom/performance/PerformanceMeasure.h
+++ b/dom/performance/PerformanceMeasure.h
@@ -15,10 +15,15 @@ namespace dom {
class PerformanceMeasure final : public PerformanceEntry
{
public:
+ NS_DECL_ISUPPORTS_INHERITED
+ NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(PerformanceMeasure,
+ PerformanceEntry);
+
PerformanceMeasure(nsISupports* aParent,
const nsAString& aName,
DOMHighResTimeStamp aStartTime,
- DOMHighResTimeStamp aEndTime);
+ DOMHighResTimeStamp aEndTime,
+ const JS::Handle<JS::Value>& aDetail);
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
@@ -32,10 +37,15 @@ public:
return mDuration;
}
+ void GetDetail(JSContext* aCx, JS::MutableHandle<JS::Value> aRv);
+
protected:
virtual ~PerformanceMeasure();
DOMHighResTimeStamp mStartTime;
DOMHighResTimeStamp mDuration;
+
+private:
+ JS::Heap<JS::Value> mDetail;
};
} // namespace dom