PerformanceEventTiming.cpp (7111B)
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 "PerformanceEventTiming.h" 8 9 #include <algorithm> 10 11 #include "PerformanceInteractionMetrics.h" 12 #include "PerformanceMainThread.h" 13 #include "mozilla/EventForwards.h" 14 #include "mozilla/MouseEvents.h" 15 #include "mozilla/StaticPrefs_dom.h" 16 #include "mozilla/TextEvents.h" 17 #include "mozilla/dom/Document.h" 18 #include "mozilla/dom/Event.h" 19 #include "mozilla/dom/Performance.h" 20 #include "mozilla/dom/PerformanceEventTimingBinding.h" 21 #include "nsContentUtils.h" 22 #include "nsGkAtoms.h" 23 #include "nsIDocShell.h" 24 25 namespace mozilla::dom { 26 27 NS_IMPL_CYCLE_COLLECTION_INHERITED(PerformanceEventTiming, PerformanceEntry, 28 mPerformance, mTarget) 29 30 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PerformanceEventTiming) 31 NS_INTERFACE_MAP_END_INHERITING(PerformanceEntry) 32 33 NS_IMPL_ADDREF_INHERITED(PerformanceEventTiming, PerformanceEntry) 34 NS_IMPL_RELEASE_INHERITED(PerformanceEventTiming, PerformanceEntry) 35 36 PerformanceEventTiming::PerformanceEventTiming(Performance* aPerformance, 37 const nsAString& aName, 38 const TimeStamp& aStartTime, 39 bool aIsCancelable, 40 EventMessage aMessage) 41 : PerformanceEntry(aPerformance->GetParentObject(), aName, 42 nsGkAtoms::event), 43 mPerformance(aPerformance), 44 mProcessingStart(aPerformance->NowUnclamped()), 45 mProcessingEnd(0), 46 mStartTime( 47 aPerformance->GetDOMTiming()->TimeStampToDOMHighRes(aStartTime)), 48 mCancelable(aIsCancelable), 49 mMessage(aMessage) {} 50 51 PerformanceEventTiming::PerformanceEventTiming( 52 const PerformanceEventTiming& aEventTimingEntry) 53 : PerformanceEntry(aEventTimingEntry.mPerformance->GetParentObject(), 54 nsDependentAtomString(aEventTimingEntry.GetName()), 55 aEventTimingEntry.GetEntryTypeAsStaticAtom()), 56 mPerformance(aEventTimingEntry.mPerformance), 57 mProcessingStart(aEventTimingEntry.mProcessingStart), 58 mProcessingEnd(aEventTimingEntry.mProcessingEnd), 59 mTarget(aEventTimingEntry.mTarget), 60 mStartTime(aEventTimingEntry.mStartTime), 61 mDuration(aEventTimingEntry.mDuration), 62 mCancelable(aEventTimingEntry.mCancelable), 63 mInteractionId(aEventTimingEntry.mInteractionId), 64 mMessage(aEventTimingEntry.mMessage) {} 65 66 JSObject* PerformanceEventTiming::WrapObject( 67 JSContext* cx, JS::Handle<JSObject*> aGivenProto) { 68 return PerformanceEventTiming_Binding::Wrap(cx, this, aGivenProto); 69 } 70 71 already_AddRefed<PerformanceEventTiming> 72 PerformanceEventTiming::TryGenerateEventTiming(const EventTarget* aTarget, 73 const WidgetEvent* aEvent) { 74 MOZ_ASSERT(NS_IsMainThread()); 75 if (!StaticPrefs::dom_enable_event_timing() || 76 aEvent->mFlags.mOnlyChromeDispatch) { 77 return nullptr; 78 } 79 80 if (!aEvent->IsTrusted()) { 81 return nullptr; 82 } 83 84 switch (aEvent->mMessage) { 85 case eContextMenu: 86 case eMouseDoubleClick: 87 case eMouseDown: 88 case eMouseEnter: 89 case eMouseLeave: 90 case eMouseOut: 91 case eMouseOver: 92 case eMouseUp: 93 case ePointerAuxClick: 94 case ePointerClick: 95 case ePointerOver: 96 case ePointerEnter: 97 case ePointerDown: 98 case ePointerUp: 99 case ePointerCancel: 100 case ePointerOut: 101 case ePointerLeave: 102 case ePointerGotCapture: 103 case ePointerLostCapture: 104 case eTouchStart: 105 case eTouchEnd: 106 case eTouchCancel: 107 case eKeyDown: 108 case eKeyPress: 109 case eKeyUp: 110 case eEditorBeforeInput: 111 case eEditorInput: 112 case eCompositionStart: 113 case eCompositionUpdate: 114 case eCompositionEnd: 115 case eDragStart: 116 case eDragEnd: 117 case eDragEnter: 118 case eDragLeave: 119 case eDragOver: 120 case eDrop: 121 break; 122 default: 123 return nullptr; 124 } 125 126 nsCOMPtr<nsPIDOMWindowInner> innerWindow = 127 do_QueryInterface(aTarget->GetOwnerGlobal()); 128 if (!innerWindow) { 129 return nullptr; 130 } 131 132 if (Performance* performance = innerWindow->GetPerformance()) { 133 const char16_t* eventName = Event::GetEventName(aEvent->mMessage); 134 MOZ_ASSERT(eventName, 135 "User defined events shouldn't be considered as event timing"); 136 auto eventTiming = 137 RefPtr<PerformanceEventTiming>(new PerformanceEventTiming( 138 performance, nsDependentString(eventName), aEvent->mTimeStamp, 139 aEvent->mFlags.mCancelable, aEvent->mMessage)); 140 performance->SetInteractionId(eventTiming, aEvent); 141 return eventTiming.forget(); 142 } 143 return nullptr; 144 } 145 146 bool PerformanceEventTiming::ShouldAddEntryToBuffer(double aDuration) const { 147 if (GetEntryType() == nsGkAtoms::firstInput) { 148 return true; 149 } 150 MOZ_ASSERT(GetEntryType() == nsGkAtoms::event); 151 return RawDuration().valueOr(0) >= aDuration; 152 } 153 154 bool PerformanceEventTiming::ShouldAddEntryToObserverBuffer( 155 PerformanceObserverInit& aOption) const { 156 if (!PerformanceEntry::ShouldAddEntryToObserverBuffer(aOption)) { 157 return false; 158 } 159 160 const double minDuration = 161 aOption.mDurationThreshold.WasPassed() 162 ? std::max(aOption.mDurationThreshold.Value(), 163 PerformanceMainThread::kDefaultEventTimingMinDuration) 164 : PerformanceMainThread::kDefaultEventTimingDurationThreshold; 165 166 return ShouldAddEntryToBuffer(minDuration); 167 } 168 169 void PerformanceEventTiming::BufferEntryIfNeeded() { 170 if (ShouldAddEntryToBuffer( 171 PerformanceMainThread::kDefaultEventTimingDurationThreshold)) { 172 if (GetEntryType() != nsGkAtoms::firstInput) { 173 MOZ_ASSERT(GetEntryType() == nsGkAtoms::event); 174 mPerformance->BufferEventTimingEntryIfNeeded(this); 175 } 176 } 177 } 178 179 nsINode* PerformanceEventTiming::GetTarget() const { 180 nsCOMPtr<Element> element = do_QueryReferent(mTarget); 181 if (!element) { 182 return nullptr; 183 } 184 185 nsCOMPtr<nsPIDOMWindowInner> global = 186 do_QueryInterface(element->GetOwnerGlobal()); 187 if (!global) { 188 return nullptr; 189 } 190 return nsContentUtils::GetAnElementForTiming(element, global->GetExtantDoc(), 191 mPerformance->GetParentObject()); 192 } 193 194 void PerformanceEventTiming::FinalizeEventTiming(const WidgetEvent* aEvent) { 195 MOZ_ASSERT(aEvent); 196 EventTarget* target = aEvent->mTarget; 197 if (!target) { 198 return; 199 } 200 nsCOMPtr<nsPIDOMWindowInner> global = 201 do_QueryInterface(target->GetOwnerGlobal()); 202 if (!global) { 203 return; 204 } 205 206 mProcessingEnd = mPerformance->NowUnclamped(); 207 208 Element* element = Element::FromEventTarget(target); 209 if (!element || element->ChromeOnlyAccess()) { 210 return; 211 } 212 213 mTarget = do_GetWeakReference(element); 214 215 mPerformance->InsertEventTimingEntry(this); 216 } 217 } // namespace mozilla::dom