/* -*- 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/dom/PerformanceEventTimingBinding.h" #include "mozilla/dom/Document.h" #include "mozilla/dom/Performance.h" #include "mozilla/dom/Event.h" #include "nsIDocShell.h" #include 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 aGivenProto) { return PerformanceEventTiming_Binding::Wrap(cx, this, aGivenProto); } already_AddRefed 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 innerWindow = do_QueryInterface(aTarget->GetOwnerGlobal()); if (!innerWindow) { return nullptr; } if (Performance* performance = innerWindow->GetPerformance()) { const char* eventName = Event::GetEventName(aEvent->mMessage); MOZ_ASSERT(eventName, "User defined events shouldn't be considered as event timing"); return RefPtr( new PerformanceEventTiming( performance, NS_ConvertUTF8toUTF16(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 { if (!mTarget) { return nullptr; } nsCOMPtr target = do_QueryReferent(mTarget); if (!target || !target->IsInUncomposedDoc()) { return nullptr; } return target; } void PerformanceEventTiming::FinalizeEventTiming(EventTarget* aTarget) { if (!aTarget) { return; } nsCOMPtr global = do_QueryInterface(aTarget->GetOwnerGlobal()); if (!global) { return; } mProcessingEnd = mPerformance->NowUnclamped(); nsCOMPtr node = do_QueryInterface(aTarget); if (!node || node->ChromeOnlyAccess()) { return; } mTarget = do_GetWeakReference(GetAnElement(node, global->GetExtantDoc())); mPerformance->InsertEventTimingEntry(this); } nsINode* PerformanceEventTiming::GetAnElement(nsINode* aTarget, const Document* aDocument) { if (!aTarget->IsInUncomposedDoc()) { return nullptr; } if (!aDocument) { nsCOMPtr inner = do_QueryInterface(mPerformance->GetParentObject()); MOZ_ASSERT(inner); aDocument = inner->GetExtantDoc(); } MOZ_ASSERT(aDocument); if (aTarget->GetComposedDoc() != aDocument || !aDocument->IsCurrentActiveDocument()) { return nullptr; } return aTarget; } } // namespace mozilla::dom