diff options
Diffstat (limited to 'dom/performance/PerformanceEventTiming.cpp')
-rw-r--r-- | dom/performance/PerformanceEventTiming.cpp | 207 |
1 files changed, 207 insertions, 0 deletions
diff --git a/dom/performance/PerformanceEventTiming.cpp b/dom/performance/PerformanceEventTiming.cpp new file mode 100644 index 0000000000..7a89329362 --- /dev/null +++ b/dom/performance/PerformanceEventTiming.cpp @@ -0,0 +1,207 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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 "PerformanceEventTiming.h" +#include "PerformanceMainThread.h" +#include "mozilla/StaticPrefs_dom.h" +#include "mozilla/dom/PerformanceEventTimingBinding.h" +#include "mozilla/dom/Document.h" +#include "mozilla/dom/Performance.h" +#include "mozilla/dom/Event.h" +#include "nsContentUtils.h" +#include "nsIDocShell.h" +#include <algorithm> + +namespace mozilla::dom { + +NS_IMPL_CYCLE_COLLECTION_INHERITED(PerformanceEventTiming, PerformanceEntry, + mPerformance, mTarget) + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PerformanceEventTiming) +NS_INTERFACE_MAP_END_INHERITING(PerformanceEntry) + +NS_IMPL_ADDREF_INHERITED(PerformanceEventTiming, PerformanceEntry) +NS_IMPL_RELEASE_INHERITED(PerformanceEventTiming, PerformanceEntry) + +PerformanceEventTiming::PerformanceEventTiming(Performance* aPerformance, + const nsAString& aName, + const TimeStamp& aStartTime, + bool aIsCacelable, + EventMessage aMessage) + : PerformanceEntry(aPerformance->GetParentObject(), aName, u"event"_ns), + mPerformance(aPerformance), + mProcessingStart(aPerformance->NowUnclamped()), + mProcessingEnd(0), + mStartTime( + aPerformance->GetDOMTiming()->TimeStampToDOMHighRes(aStartTime)), + mDuration(0), + mCancelable(aIsCacelable), + mMessage(aMessage) {} + +PerformanceEventTiming::PerformanceEventTiming( + const PerformanceEventTiming& aEventTimingEntry) + : PerformanceEntry(aEventTimingEntry.mPerformance->GetParentObject(), + nsDependentAtomString(aEventTimingEntry.GetName()), + nsDependentAtomString(aEventTimingEntry.GetEntryType())), + mPerformance(aEventTimingEntry.mPerformance), + mProcessingStart(aEventTimingEntry.mProcessingStart), + mProcessingEnd(aEventTimingEntry.mProcessingEnd), + mTarget(aEventTimingEntry.mTarget), + mStartTime(aEventTimingEntry.mStartTime), + mDuration(aEventTimingEntry.mDuration), + mCancelable(aEventTimingEntry.mCancelable), + mMessage(aEventTimingEntry.mMessage) {} + +JSObject* PerformanceEventTiming::WrapObject( + JSContext* cx, JS::Handle<JSObject*> aGivenProto) { + return PerformanceEventTiming_Binding::Wrap(cx, this, aGivenProto); +} + +already_AddRefed<PerformanceEventTiming> +PerformanceEventTiming::TryGenerateEventTiming(const EventTarget* aTarget, + const WidgetEvent* aEvent) { + MOZ_ASSERT(NS_IsMainThread()); + if (!StaticPrefs::dom_enable_event_timing() || + aEvent->mFlags.mOnlyChromeDispatch) { + return nullptr; + } + + if (!aEvent->IsTrusted()) { + return nullptr; + } + + switch (aEvent->mMessage) { + case eMouseAuxClick: + case eMouseClick: + case eContextMenu: + case eMouseDoubleClick: + case eMouseDown: + case eMouseEnter: + case eMouseLeave: + case eMouseOut: + case eMouseOver: + case eMouseUp: + case ePointerOver: + case ePointerEnter: + case ePointerDown: + case ePointerUp: + case ePointerCancel: + case ePointerOut: + case ePointerLeave: + case ePointerGotCapture: + case ePointerLostCapture: + case eTouchStart: + case eTouchEnd: + case eTouchCancel: + case eKeyDown: + case eKeyPress: + case eKeyUp: + case eEditorBeforeInput: + case eEditorInput: + case eCompositionStart: + case eCompositionUpdate: + case eCompositionEnd: + case eDragStart: + case eDragEnd: + case eDragEnter: + case eDragLeave: + case eDragOver: + case eDrop: + break; + default: + return nullptr; + } + + nsCOMPtr<nsPIDOMWindowInner> innerWindow = + do_QueryInterface(aTarget->GetOwnerGlobal()); + if (!innerWindow) { + return nullptr; + } + + if (Performance* performance = innerWindow->GetPerformance()) { + const char16_t* eventName = Event::GetEventName(aEvent->mMessage); + MOZ_ASSERT(eventName, + "User defined events shouldn't be considered as event timing"); + return RefPtr<PerformanceEventTiming>( + new PerformanceEventTiming( + performance, nsDependentString(eventName), + aEvent->mTimeStamp, aEvent->mFlags.mCancelable, + aEvent->mMessage)) + .forget(); + } + return nullptr; +} + +bool PerformanceEventTiming::ShouldAddEntryToBuffer(double aDuration) const { + if (GetEntryType() == nsGkAtoms::firstInput) { + return true; + } + MOZ_ASSERT(GetEntryType() == nsGkAtoms::event); + return RawDuration() >= aDuration; +} + +bool PerformanceEventTiming::ShouldAddEntryToObserverBuffer( + PerformanceObserverInit& aOption) const { + if (!PerformanceEntry::ShouldAddEntryToObserverBuffer(aOption)) { + return false; + } + + const double minDuration = + aOption.mDurationThreshold.WasPassed() + ? std::max(aOption.mDurationThreshold.Value(), + PerformanceMainThread::kDefaultEventTimingMinDuration) + : PerformanceMainThread::kDefaultEventTimingDurationThreshold; + + return ShouldAddEntryToBuffer(minDuration); +} + +void PerformanceEventTiming::BufferEntryIfNeeded() { + if (ShouldAddEntryToBuffer( + PerformanceMainThread::kDefaultEventTimingDurationThreshold)) { + if (GetEntryType() != nsGkAtoms::firstInput) { + MOZ_ASSERT(GetEntryType() == nsGkAtoms::event); + mPerformance->BufferEventTimingEntryIfNeeded(this); + } + } +} + +nsINode* PerformanceEventTiming::GetTarget() const { + nsCOMPtr<Element> element = do_QueryReferent(mTarget); + if (!element) { + return nullptr; + } + + nsCOMPtr<nsPIDOMWindowInner> global = + do_QueryInterface(element->GetOwnerGlobal()); + if (!global) { + return nullptr; + } + return nsContentUtils::GetAnElementForTiming(element, global->GetExtantDoc(), + mPerformance->GetParentObject()); +} + +void PerformanceEventTiming::FinalizeEventTiming(EventTarget* aTarget) { + if (!aTarget) { + return; + } + nsCOMPtr<nsPIDOMWindowInner> global = + do_QueryInterface(aTarget->GetOwnerGlobal()); + if (!global) { + return; + } + + mProcessingEnd = mPerformance->NowUnclamped(); + + Element* element = Element::FromEventTarget(aTarget); + if (!element || element->ChromeOnlyAccess()) { + return; + } + + mTarget = do_GetWeakReference(element); + + mPerformance->InsertEventTimingEntry(this); +} +} // namespace mozilla::dom |