devtools-tracing 1.0.1 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (132) hide show
  1. package/generate.ts +32 -26
  2. package/index.ts +2 -1
  3. package/lib/extension-api/ExtensionAPI.d.ts +357 -0
  4. package/lib/front_end/models/bindings/CSSWorkspaceBinding.ts +318 -0
  5. package/lib/front_end/models/bindings/CompilerScriptMapping.ts +536 -0
  6. package/lib/front_end/models/bindings/ContentProviderBasedProject.ts +187 -0
  7. package/lib/front_end/models/bindings/DebuggerLanguagePlugins.ts +1197 -0
  8. package/lib/front_end/models/bindings/DebuggerWorkspaceBinding.ts +733 -0
  9. package/lib/front_end/models/bindings/DefaultScriptMapping.ts +141 -0
  10. package/lib/front_end/models/bindings/FileUtils.ts +228 -0
  11. package/lib/front_end/models/bindings/LiveLocation.ts +81 -0
  12. package/lib/front_end/models/bindings/NetworkProject.ts +157 -0
  13. package/lib/front_end/models/bindings/PresentationConsoleMessageHelper.ts +312 -0
  14. package/lib/front_end/models/bindings/ResourceMapping.ts +539 -0
  15. package/lib/front_end/models/bindings/ResourceScriptMapping.ts +491 -0
  16. package/lib/front_end/models/bindings/ResourceUtils.ts +103 -0
  17. package/lib/front_end/models/bindings/SASSSourceMapping.ts +222 -0
  18. package/lib/front_end/models/bindings/StylesSourceMapping.ts +316 -0
  19. package/lib/front_end/models/bindings/TempFile.ts +67 -0
  20. package/lib/front_end/models/bindings/bindings.ts +39 -0
  21. package/lib/front_end/models/source_map_scopes/NamesResolver.ts +765 -0
  22. package/lib/front_end/models/source_map_scopes/ScopeChainModel.ts +84 -0
  23. package/lib/front_end/models/source_map_scopes/source_map_scopes.ts +11 -0
  24. package/lib/front_end/models/stack_trace/StackTrace.ts +53 -0
  25. package/lib/front_end/models/stack_trace/StackTraceImpl.ts +85 -0
  26. package/lib/front_end/models/stack_trace/StackTraceModel.ts +128 -0
  27. package/lib/front_end/models/stack_trace/Trie.ts +163 -0
  28. package/lib/front_end/models/stack_trace/stack_trace.ts +9 -0
  29. package/lib/front_end/models/stack_trace/stack_trace_impl.ts +13 -0
  30. package/lib/front_end/models/trace_source_maps_resolver/SourceMapsResolver.ts +240 -0
  31. package/lib/front_end/models/trace_source_maps_resolver/trace_source_maps_resolver.ts +5 -0
  32. package/lib/front_end/models/workspace/FileManager.ts +97 -0
  33. package/lib/front_end/models/workspace/IgnoreListManager.ts +628 -0
  34. package/lib/front_end/models/workspace/SearchConfig.ts +149 -0
  35. package/lib/front_end/models/workspace/UISourceCode.ts +698 -0
  36. package/lib/front_end/models/workspace/WorkspaceImpl.ts +339 -0
  37. package/lib/front_end/models/workspace/workspace.ts +17 -0
  38. package/lib/front_end/panels/timeline/TimelineUIUtils.ts +1029 -0
  39. package/lib/front_end/panels/timeline/extensions/ExtensionUI.ts +49 -0
  40. package/lib/front_end/panels/timeline/extensions/extensions.ts +9 -0
  41. package/lib/front_end/third_party/codemirror.next/LICENSE +21 -0
  42. package/lib/front_end/third_party/codemirror.next/README.chromium +30 -0
  43. package/lib/front_end/third_party/codemirror.next/bundle-tsconfig.json +24 -0
  44. package/lib/front_end/third_party/codemirror.next/bundle.ts +135 -0
  45. package/lib/front_end/third_party/codemirror.next/chunk/angular.js +2 -0
  46. package/lib/front_end/third_party/codemirror.next/chunk/angular.js.map +1 -0
  47. package/lib/front_end/third_party/codemirror.next/chunk/codemirror.js +2 -0
  48. package/lib/front_end/third_party/codemirror.next/chunk/codemirror.js.map +1 -0
  49. package/lib/front_end/third_party/codemirror.next/chunk/cpp.js +2 -0
  50. package/lib/front_end/third_party/codemirror.next/chunk/cpp.js.map +1 -0
  51. package/lib/front_end/third_party/codemirror.next/chunk/css.js +2 -0
  52. package/lib/front_end/third_party/codemirror.next/chunk/html.js +4 -0
  53. package/lib/front_end/third_party/codemirror.next/chunk/java.js +2 -0
  54. package/lib/front_end/third_party/codemirror.next/chunk/java.js.map +1 -0
  55. package/lib/front_end/third_party/codemirror.next/chunk/javascript.js +2 -0
  56. package/lib/front_end/third_party/codemirror.next/chunk/legacy.js +2 -0
  57. package/lib/front_end/third_party/codemirror.next/chunk/legacy.js.map +1 -0
  58. package/lib/front_end/third_party/codemirror.next/chunk/less.js +2 -0
  59. package/lib/front_end/third_party/codemirror.next/chunk/less.js.map +1 -0
  60. package/lib/front_end/third_party/codemirror.next/chunk/markdown.js +2 -0
  61. package/lib/front_end/third_party/codemirror.next/chunk/markdown.js.map +1 -0
  62. package/lib/front_end/third_party/codemirror.next/chunk/php.js +2 -0
  63. package/lib/front_end/third_party/codemirror.next/chunk/php.js.map +1 -0
  64. package/lib/front_end/third_party/codemirror.next/chunk/python.js +2 -0
  65. package/lib/front_end/third_party/codemirror.next/chunk/python.js.map +1 -0
  66. package/lib/front_end/third_party/codemirror.next/chunk/sass.js +2 -0
  67. package/lib/front_end/third_party/codemirror.next/chunk/sass.js.map +1 -0
  68. package/lib/front_end/third_party/codemirror.next/chunk/svelte.js +2 -0
  69. package/lib/front_end/third_party/codemirror.next/chunk/svelte.js.map +1 -0
  70. package/lib/front_end/third_party/codemirror.next/chunk/vue.js +2 -0
  71. package/lib/front_end/third_party/codemirror.next/chunk/vue.js.map +1 -0
  72. package/lib/front_end/third_party/codemirror.next/chunk/wast.js +2 -0
  73. package/lib/front_end/third_party/codemirror.next/chunk/wast.js.map +1 -0
  74. package/lib/front_end/third_party/codemirror.next/chunk/xml.js +2 -0
  75. package/lib/front_end/third_party/codemirror.next/chunk/xml.js.map +1 -0
  76. package/lib/front_end/third_party/codemirror.next/codemirror.next.d.ts +8057 -0
  77. package/lib/front_end/third_party/codemirror.next/codemirror.next.js +2 -0
  78. package/lib/front_end/third_party/codemirror.next/codemirror.next.js.map +1 -0
  79. package/lib/front_end/third_party/codemirror.next/package.json +43 -0
  80. package/lib/front_end/third_party/codemirror.next/rebuild.sh +6 -0
  81. package/lib/front_end/third_party/codemirror.next/rollup.config.mjs +49 -0
  82. package/lib/front_end/third_party/source-map-scopes-codec/LICENSE +26 -0
  83. package/lib/front_end/third_party/source-map-scopes-codec/README.chromium +31 -0
  84. package/lib/front_end/third_party/source-map-scopes-codec/package/CONTRIBUTING.md +33 -0
  85. package/lib/front_end/third_party/source-map-scopes-codec/package/LICENSE +26 -0
  86. package/lib/front_end/third_party/source-map-scopes-codec/package/README.md +64 -0
  87. package/lib/front_end/third_party/source-map-scopes-codec/package/_dist/src/builder/builder.d.ts +62 -0
  88. package/lib/front_end/third_party/source-map-scopes-codec/package/_dist/src/builder/builder.d.ts.map +1 -0
  89. package/lib/front_end/third_party/source-map-scopes-codec/package/_dist/src/builder/safe_builder.d.ts +37 -0
  90. package/lib/front_end/third_party/source-map-scopes-codec/package/_dist/src/builder/safe_builder.d.ts.map +1 -0
  91. package/lib/front_end/third_party/source-map-scopes-codec/package/_dist/src/decode/decode.d.ts +29 -0
  92. package/lib/front_end/third_party/source-map-scopes-codec/package/_dist/src/decode/decode.d.ts.map +1 -0
  93. package/lib/front_end/third_party/source-map-scopes-codec/package/_dist/src/encode/encode.d.ts +8 -0
  94. package/lib/front_end/third_party/source-map-scopes-codec/package/_dist/src/encode/encode.d.ts.map +1 -0
  95. package/lib/front_end/third_party/source-map-scopes-codec/package/_dist/src/mod.d.ts +6 -0
  96. package/lib/front_end/third_party/source-map-scopes-codec/package/_dist/src/mod.d.ts.map +1 -0
  97. package/lib/front_end/third_party/source-map-scopes-codec/package/deno.json +21 -0
  98. package/lib/front_end/third_party/source-map-scopes-codec/package/package.json +14 -0
  99. package/lib/front_end/third_party/source-map-scopes-codec/package/src/builder/builder.js +196 -0
  100. package/lib/front_end/third_party/source-map-scopes-codec/package/src/builder/builder.js.map +1 -0
  101. package/lib/front_end/third_party/source-map-scopes-codec/package/src/builder/builder.ts +262 -0
  102. package/lib/front_end/third_party/source-map-scopes-codec/package/src/builder/safe_builder.js +235 -0
  103. package/lib/front_end/third_party/source-map-scopes-codec/package/src/builder/safe_builder.js.map +1 -0
  104. package/lib/front_end/third_party/source-map-scopes-codec/package/src/builder/safe_builder.ts +359 -0
  105. package/lib/front_end/third_party/source-map-scopes-codec/package/src/codec.js +39 -0
  106. package/lib/front_end/third_party/source-map-scopes-codec/package/src/codec.js.map +1 -0
  107. package/lib/front_end/third_party/source-map-scopes-codec/package/src/codec.ts +53 -0
  108. package/lib/front_end/third_party/source-map-scopes-codec/package/src/decode/decode.js +438 -0
  109. package/lib/front_end/third_party/source-map-scopes-codec/package/src/decode/decode.js.map +1 -0
  110. package/lib/front_end/third_party/source-map-scopes-codec/package/src/decode/decode.ts +539 -0
  111. package/lib/front_end/third_party/source-map-scopes-codec/package/src/encode/encode.js +23 -0
  112. package/lib/front_end/third_party/source-map-scopes-codec/package/src/encode/encode.js.map +1 -0
  113. package/lib/front_end/third_party/source-map-scopes-codec/package/src/encode/encode.ts +35 -0
  114. package/lib/front_end/third_party/source-map-scopes-codec/package/src/encode/encoder.js +257 -0
  115. package/lib/front_end/third_party/source-map-scopes-codec/package/src/encode/encoder.js.map +1 -0
  116. package/lib/front_end/third_party/source-map-scopes-codec/package/src/encode/encoder.ts +348 -0
  117. package/lib/front_end/third_party/source-map-scopes-codec/package/src/mod.js +8 -0
  118. package/lib/front_end/third_party/source-map-scopes-codec/package/src/mod.js.map +1 -0
  119. package/lib/front_end/third_party/source-map-scopes-codec/package/src/mod.ts +20 -0
  120. package/lib/front_end/third_party/source-map-scopes-codec/package/src/scopes-tsconfig.json +8 -0
  121. package/lib/front_end/third_party/source-map-scopes-codec/package/src/scopes.d.ts +184 -0
  122. package/lib/front_end/third_party/source-map-scopes-codec/package/src/util.js +9 -0
  123. package/lib/front_end/third_party/source-map-scopes-codec/package/src/util.js.map +1 -0
  124. package/lib/front_end/third_party/source-map-scopes-codec/package/src/util.ts +12 -0
  125. package/lib/front_end/third_party/source-map-scopes-codec/package/src/vlq.js +82 -0
  126. package/lib/front_end/third_party/source-map-scopes-codec/package/src/vlq.js.map +1 -0
  127. package/lib/front_end/third_party/source-map-scopes-codec/package/src/vlq.ts +99 -0
  128. package/lib/front_end/third_party/source-map-scopes-codec/source-map-scopes-codec.ts +5 -0
  129. package/lib/front_end/ui/legacy/theme_support/ThemeSupport.ts +222 -0
  130. package/lib/front_end/ui/legacy/theme_support/theme_support.ts +5 -0
  131. package/package.json +4 -3
  132. package/patches/chrome-devtools-frontend+1.0.1533544.patch +1549 -20
@@ -47,21 +47,951 @@ index 62c5773..ff07f89 100644
47
47
  const unrecognizedEntity = {
48
48
  name: rootDomain,
49
49
  diff --git a/node_modules/chrome-devtools-frontend/front_end/panels/timeline/TimelineUIUtils.ts b/node_modules/chrome-devtools-frontend/front_end/panels/timeline/TimelineUIUtils.ts
50
- index 4fe7b92..573e0d3 100644
50
+ index 4fe7b92..9e9664b 100644
51
51
  --- a/node_modules/chrome-devtools-frontend/front_end/panels/timeline/TimelineUIUtils.ts
52
52
  +++ b/node_modules/chrome-devtools-frontend/front_end/panels/timeline/TimelineUIUtils.ts
53
- @@ -48,7 +48,6 @@ import * as Tracing from '../../services/tracing/tracing.js';
54
- import * as CodeHighlighter from '../../ui/components/code_highlighter/code_highlighter.js';
55
- // eslint-disable-next-line @devtools/es-modules-import
56
- import codeHighlighterStyles from '../../ui/components/code_highlighter/codeHighlighter.css.js';
53
+ @@ -38,32 +38,12 @@ import * as Common from '../../core/common/common.js';
54
+ import * as i18n from '../../core/i18n/i18n.js';
55
+ import * as Platform from '../../core/platform/platform.js';
56
+ import * as Root from '../../core/root/root.js';
57
+ -import * as SDK from '../../core/sdk/sdk.js';
58
+ import type * as Protocol from '../../generated/protocol.js';
59
+ -import * as TextUtils from '../../models/text_utils/text_utils.js';
60
+ import * as Trace from '../../models/trace/trace.js';
61
+ import * as SourceMapsResolver from '../../models/trace_source_maps_resolver/trace_source_maps_resolver.js';
62
+ -import * as TraceBounds from '../../services/trace_bounds/trace_bounds.js';
63
+ -import * as Tracing from '../../services/tracing/tracing.js';
64
+ -import * as CodeHighlighter from '../../ui/components/code_highlighter/code_highlighter.js';
65
+ -// eslint-disable-next-line @devtools/es-modules-import
66
+ -import codeHighlighterStyles from '../../ui/components/code_highlighter/codeHighlighter.css.js';
57
67
  -import * as PerfUI from '../../ui/legacy/components/perf_ui/perf_ui.js';
58
- // eslint-disable-next-line @devtools/es-modules-import
59
- import imagePreviewStyles from '../../ui/legacy/components/utils/imagePreview.css.js';
60
- import * as LegacyComponents from '../../ui/legacy/components/utils/utils.js';
61
- @@ -1531,14 +1530,6 @@ export class TimelineUIUtils {
62
- TimelineUIUtils.renderEventJson(event, contentHelper);
63
- }
68
+ -// eslint-disable-next-line @devtools/es-modules-import
69
+ -import imagePreviewStyles from '../../ui/legacy/components/utils/imagePreview.css.js';
70
+ -import * as LegacyComponents from '../../ui/legacy/components/utils/utils.js';
71
+ -import * as UI from '../../ui/legacy/legacy.js';
72
+ import * as ThemeSupport from '../../ui/legacy/theme_support/theme_support.js';
73
+
74
+ -import {getDurationString} from './AppenderUtils.js';
75
+ -import * as TimelineComponents from './components/components.js';
76
+ import * as Extensions from './extensions/extensions.js';
77
+ -import {ModificationsManager} from './ModificationsManager.js';
78
+ -import {targetForEvent} from './TargetForEvent.js';
79
+ -import * as ThirdPartyTreeView from './ThirdPartyTreeView.js';
80
+ -import {TimelinePanel} from './TimelinePanel.js';
81
+ -import {selectionFromEvent} from './TimelineSelection.js';
82
+ -import * as Utils from './utils/utils.js';
83
+
84
+ const UIStrings = {
85
+ /**
86
+ @@ -487,17 +467,6 @@ let eventDispatchDesciptors: EventDispatchTypeDescriptor[];
87
+
88
+ let colorGenerator: Common.Color.Generator;
89
+
90
+ -interface LinkifyLocationOptions {
91
+ - scriptId: Protocol.Runtime.ScriptId|null;
92
+ - url: string;
93
+ - lineNumber: number;
94
+ - target: SDK.Target.Target|null;
95
+ - linkifier: LegacyComponents.Linkifier.Linkifier;
96
+ - isFreshOrEnhanced?: boolean;
97
+ - columnNumber?: number;
98
+ - omitOrigin?: boolean;
99
+ -}
100
+ -
101
+ type TimeRangeCategoryStats = Record<string, number>;
64
102
 
103
+ const {SamplesIntegrator} = Trace.Helpers.SamplesIntegrator;
104
+ @@ -517,9 +486,6 @@ export class TimelineUIUtils {
105
+ static frameDisplayName(frame: Protocol.Runtime.CallFrame): string {
106
+ const maybeResolvedData = SourceMapsResolver.SourceMapsResolver.resolvedCodeLocationForCallFrame(frame);
107
+ const functionName = maybeResolvedData?.name || frame.functionName;
108
+ - if (!SamplesIntegrator.isNativeRuntimeFrame(frame)) {
109
+ - return UI.UIUtils.beautifyFunctionName(functionName);
110
+ - }
111
+ const nativeGroup = SamplesIntegrator.nativeGroup(functionName);
112
+ switch (nativeGroup) {
113
+ case SamplesIntegrator.NativeGroups.COMPILE:
114
+ @@ -654,894 +620,6 @@ export class TimelineUIUtils {
115
+ return frame.scriptId !== '0' && !(frame.url?.startsWith('native '));
116
+ }
117
+
118
+ - static async buildDetailsNodeForTraceEvent(
119
+ - event: Trace.Types.Events.Event, target: SDK.Target.Target|null, linkifier: LegacyComponents.Linkifier.Linkifier,
120
+ - isFreshOrEnhanced = false, parsedTrace: Trace.TraceModel.ParsedTrace): Promise<Node|null> {
121
+ - let details: HTMLElement|HTMLSpanElement|(Element | null)|Text|null = null;
122
+ - let detailsText;
123
+ - // TODO(40287735): update this code with type-safe data checks.
124
+ - // eslint-disable-next-line @typescript-eslint/no-explicit-any
125
+ - const unsafeEventArgs = event.args as Record<string, any>;
126
+ - // TODO(40287735): update this code with type-safe data checks.
127
+ - // eslint-disable-next-line @typescript-eslint/no-explicit-any
128
+ - const unsafeEventData = event.args?.data as Record<string, any>;
129
+ -
130
+ - switch (event.name) {
131
+ - case Trace.Types.Events.Name.PAINT_IMAGE:
132
+ - case Trace.Types.Events.Name.DECODE_IMAGE:
133
+ - case Trace.Types.Events.Name.DECODE_LAZY_PIXEL_REF:
134
+ - case Trace.Types.Events.Name.XHR_READY_STATE_CHANGED:
135
+ - case Trace.Types.Events.Name.XHR_LOAD:
136
+ - case Trace.Types.Events.Name.RESOURCE_WILL_SEND_REQUEST:
137
+ - case Trace.Types.Events.Name.RESOURCE_SEND_REQUEST:
138
+ - case Trace.Types.Events.Name.RESOURCE_RECEIVE_DATA:
139
+ - case Trace.Types.Events.Name.RESOURCE_RECEIVE_RESPONSE:
140
+ - case Trace.Types.Events.Name.RESOURCE_FINISH: {
141
+ - const url = Trace.Handlers.Helpers.getNonResolvedURL(event, parsedTrace.data);
142
+ - if (url) {
143
+ - const options = {
144
+ - tabStop: true,
145
+ - showColumnNumber: false,
146
+ - inlineFrameIndex: 0,
147
+ - };
148
+ - details = LegacyComponents.Linkifier.Linkifier.linkifyURL(url, options);
149
+ - }
150
+ - break;
151
+ - }
152
+ -
153
+ - case Trace.Types.Events.Name.FUNCTION_CALL: {
154
+ - details = document.createElement('span');
155
+ -
156
+ - // FunctionCall events have an args.data that could be a CallFrame, if all the details are present, so we check for that.
157
+ - const callFrame = Trace.Helpers.Trace.getZeroIndexedStackTraceInEventPayload(event)?.at(0);
158
+ - if (Trace.Types.Events.isFunctionCall(event) && callFrame) {
159
+ - UI.UIUtils.createTextChild(
160
+ - details,
161
+ - TimelineUIUtils.frameDisplayName(
162
+ - {...callFrame, scriptId: String(callFrame.scriptId) as Protocol.Runtime.ScriptId}));
163
+ - }
164
+ - const location = this.linkifyLocation({
165
+ - scriptId: unsafeEventData['scriptId'],
166
+ - url: unsafeEventData['url'],
167
+ - lineNumber: callFrame?.lineNumber || 0,
168
+ - columnNumber: callFrame?.columnNumber,
169
+ - target,
170
+ - isFreshOrEnhanced,
171
+ - linkifier,
172
+ - omitOrigin: true,
173
+ - });
174
+ - if (location) {
175
+ - UI.UIUtils.createTextChild(details, ' @ ');
176
+ - details.appendChild(location);
177
+ - }
178
+ - break;
179
+ - }
180
+ -
181
+ - case Trace.Types.Events.Name.COMPILE_MODULE:
182
+ - case Trace.Types.Events.Name.CACHE_MODULE: {
183
+ - details = this.linkifyLocation({
184
+ - scriptId: null,
185
+ - url: unsafeEventArgs['fileName'],
186
+ - lineNumber: 0,
187
+ - columnNumber: 0,
188
+ - target,
189
+ - isFreshOrEnhanced,
190
+ - linkifier,
191
+ - });
192
+ - break;
193
+ - }
194
+ -
195
+ - case Trace.Types.Events.Name.COMPILE_SCRIPT:
196
+ - case Trace.Types.Events.Name.CACHE_SCRIPT:
197
+ - case Trace.Types.Events.Name.EVALUATE_SCRIPT: {
198
+ - const url = unsafeEventData['url'];
199
+ - if (url) {
200
+ - const {lineNumber} = Trace.Helpers.Trace.getZeroIndexedLineAndColumnForEvent(event);
201
+ - details = this.linkifyLocation({
202
+ - scriptId: null,
203
+ - url,
204
+ - lineNumber: lineNumber || 0,
205
+ - columnNumber: 0,
206
+ - target,
207
+ - isFreshOrEnhanced,
208
+ - linkifier,
209
+ - omitOrigin: true,
210
+ - });
211
+ - }
212
+ - break;
213
+ - }
214
+ -
215
+ - case Trace.Types.Events.Name.BACKGROUND_DESERIALIZE:
216
+ - case Trace.Types.Events.Name.STREAMING_COMPILE_SCRIPT: {
217
+ - const url = unsafeEventData['url'];
218
+ - if (url) {
219
+ - details = this.linkifyLocation({
220
+ - scriptId: null,
221
+ - url,
222
+ - lineNumber: 0,
223
+ - columnNumber: 0,
224
+ - target,
225
+ - isFreshOrEnhanced,
226
+ - linkifier,
227
+ - omitOrigin: true,
228
+ - });
229
+ - }
230
+ - break;
231
+ - }
232
+ -
233
+ - default: {
234
+ - /**
235
+ - * Some events have a stack trace which is extracted by default at @see TimelineUIUtils.generateCauses
236
+ - * thus, we prevent extracting the stack trace again here.
237
+ - */
238
+ - if (Trace.Helpers.Trace.eventHasCategory(event, Trace.Types.Events.Categories.Console) ||
239
+ - Trace.Types.Events.isUserTiming(event) || Trace.Types.Extensions.isSyntheticExtensionEntry(event) ||
240
+ - Trace.Types.Events.isProfileCall(event)) {
241
+ - detailsText = null;
242
+ - } else {
243
+ - details = this.linkifyTopCallFrame(event, target, linkifier, isFreshOrEnhanced) ?? null;
244
+ - }
245
+ - break;
246
+ - }
247
+ - }
248
+ -
249
+ - if (!details && detailsText) {
250
+ - details = document.createTextNode(detailsText);
251
+ - }
252
+ - return details;
253
+ - }
254
+ -
255
+ - static linkifyLocation(linkifyOptions: LinkifyLocationOptions): Element|null {
256
+ - const {scriptId, url, lineNumber, columnNumber, isFreshOrEnhanced, linkifier, target, omitOrigin} = linkifyOptions;
257
+ - const options = {
258
+ - lineNumber,
259
+ - columnNumber,
260
+ - showColumnNumber: true,
261
+ - inlineFrameIndex: 0,
262
+ - className: 'timeline-details',
263
+ - tabStop: true,
264
+ - omitOrigin,
265
+ - };
266
+ - if (isFreshOrEnhanced) {
267
+ - return linkifier.linkifyScriptLocation(
268
+ - target, scriptId, url as Platform.DevToolsPath.UrlString, lineNumber, options);
269
+ - }
270
+ - return LegacyComponents.Linkifier.Linkifier.linkifyURL(url as Platform.DevToolsPath.UrlString, options);
271
+ - }
272
+ -
273
+ - static linkifyTopCallFrame(
274
+ - event: Trace.Types.Events.Event, target: SDK.Target.Target|null, linkifier: LegacyComponents.Linkifier.Linkifier,
275
+ - isFreshOrEnhanced = false): Element|null {
276
+ - let frame = Trace.Helpers.Trace.getZeroIndexedStackTraceInEventPayload(event)?.[0];
277
+ - if (Trace.Types.Events.isProfileCall(event)) {
278
+ - frame = event.callFrame;
279
+ - }
280
+ - if (!frame) {
281
+ - return null;
282
+ - }
283
+ - const options = {
284
+ - className: 'timeline-details',
285
+ - tabStop: true,
286
+ - inlineFrameIndex: 0,
287
+ - showColumnNumber: true,
288
+ - columnNumber: frame.columnNumber,
289
+ - lineNumber: frame.lineNumber,
290
+ - };
291
+ - if (isFreshOrEnhanced) {
292
+ - return linkifier.maybeLinkifyConsoleCallFrame(target, frame, {showColumnNumber: true, inlineFrameIndex: 0});
293
+ - }
294
+ - return LegacyComponents.Linkifier.Linkifier.linkifyURL(frame.url as Platform.DevToolsPath.UrlString, options);
295
+ - }
296
+ -
297
+ - static buildDetailsNodeForMarkerEvents(event: Trace.Types.Events.MarkerEvent): HTMLElement {
298
+ - let link = 'https://web.dev/user-centric-performance-metrics/';
299
+ - let name = 'page performance metrics';
300
+ - switch (event.name) {
301
+ - case Trace.Types.Events.Name.MARK_LCP_CANDIDATE:
302
+ - link = 'https://web.dev/lcp/';
303
+ - name = 'largest contentful paint';
304
+ - break;
305
+ - case Trace.Types.Events.Name.MARK_FCP:
306
+ - link = 'https://web.dev/first-contentful-paint/';
307
+ - name = 'first contentful paint';
308
+ - break;
309
+ - default:
310
+ - break;
311
+ - }
312
+ -
313
+ - const html = UI.Fragment.html`<div>${
314
+ - UI.XLink.XLink.create(
315
+ - link, i18nString(UIStrings.learnMore), undefined, undefined, 'learn-more')} about ${name}.</div>`;
316
+ - return html as HTMLElement;
317
+ - }
318
+ -
319
+ - static buildConsumeCacheDetails(
320
+ - eventData: {
321
+ - consumedCacheSize?: number,
322
+ - cacheRejected?: boolean,
323
+ - cacheKind?: string,
324
+ - },
325
+ - contentHelper: TimelineDetailsContentHelper): void {
326
+ - if (typeof eventData.consumedCacheSize === 'number') {
327
+ - contentHelper.appendTextRow(
328
+ - i18nString(UIStrings.compilationCacheStatus), i18nString(UIStrings.scriptLoadedFromCache));
329
+ - contentHelper.appendTextRow(
330
+ - i18nString(UIStrings.compilationCacheSize), i18n.ByteUtilities.bytesToString(eventData.consumedCacheSize));
331
+ - const cacheKind = eventData.cacheKind;
332
+ - if (cacheKind) {
333
+ - contentHelper.appendTextRow(i18nString(UIStrings.compilationCacheKind), cacheKind);
334
+ - }
335
+ - } else if ('cacheRejected' in eventData && eventData['cacheRejected']) {
336
+ - // Version mismatch or similar.
337
+ - contentHelper.appendTextRow(
338
+ - i18nString(UIStrings.compilationCacheStatus), i18nString(UIStrings.failedToLoadScriptFromCache));
339
+ - } else {
340
+ - contentHelper.appendTextRow(
341
+ - i18nString(UIStrings.compilationCacheStatus), i18nString(UIStrings.scriptNotEligibleToBeLoadedFromCache));
342
+ - }
343
+ - }
344
+ -
345
+ - static maybeCreateLinkElement(url: string): Element|null {
346
+ - const parsedURL = new Common.ParsedURL.ParsedURL(url);
347
+ - if (!parsedURL.scheme) {
348
+ - return null;
349
+ - }
350
+ -
351
+ - const splitResult = Common.ParsedURL.ParsedURL.splitLineAndColumn(url);
352
+ - if (!splitResult) {
353
+ - return null;
354
+ - }
355
+ - const {url: rawURL, lineNumber, columnNumber} = splitResult;
356
+ -
357
+ - const options = {
358
+ - lineNumber,
359
+ - columnNumber,
360
+ - showColumnNumber: true,
361
+ - omitOrigin: true,
362
+ - };
363
+ -
364
+ - return LegacyComponents.Linkifier.Linkifier.linkifyURL(rawURL as Platform.DevToolsPath.UrlString, options);
365
+ - }
366
+ -
367
+ - /**
368
+ - * Takes an input string and parses it to look for links. It does this by
369
+ - * looking for URLs in the input string. The returned fragment will contain
370
+ - * the same string but with any links wrapped in clickable links. The text
371
+ - * of the link is the URL, so the visible string to the user is unchanged.
372
+ - */
373
+ - static parseStringForLinks(rawString: string): DocumentFragment {
374
+ - const results = TextUtils.TextUtils.Utils.splitStringByRegexes(rawString, [URL_REGEX]);
375
+ - const nodes = results.map(result => {
376
+ - if (result.regexIndex === -1) {
377
+ - return result.value;
378
+ - }
379
+ - return TimelineUIUtils.maybeCreateLinkElement(result.value) ?? result.value;
380
+ - });
381
+ -
382
+ - const frag = document.createDocumentFragment();
383
+ - frag.append(...nodes);
384
+ - return frag;
385
+ - }
386
+ -
387
+ - static async buildTraceEventDetails(
388
+ - parsedTrace: Trace.TraceModel.ParsedTrace,
389
+ - event: Trace.Types.Events.Event,
390
+ - linkifier: LegacyComponents.Linkifier.Linkifier,
391
+ - canShowPieChart: boolean,
392
+ - entityMapper: Trace.EntityMapper.EntityMapper|null,
393
+ - ): Promise<DocumentFragment> {
394
+ - const maybeTarget = targetForEvent(parsedTrace, event);
395
+ - const {duration} = Trace.Helpers.Timing.eventTimingsMicroSeconds(event);
396
+ - const selfTime = getEventSelfTime(event, parsedTrace);
397
+ - const relatedNodesMap = await Utils.EntryNodes.relatedDOMNodesForEvent(
398
+ - parsedTrace,
399
+ - event,
400
+ - );
401
+ - let entityAppended = false;
402
+ -
403
+ - if (maybeTarget) {
404
+ - // @ts-expect-error TODO(crbug.com/1011811): Remove symbol usage.
405
+ - if (typeof event[previewElementSymbol] === 'undefined') {
406
+ - let previewElement: (Element|null)|null = null;
407
+ - const url = Trace.Handlers.Helpers.getNonResolvedURL(event, parsedTrace.data);
408
+ - if (url) {
409
+ - previewElement = await LegacyComponents.ImagePreview.ImagePreview.build(url, false, {
410
+ - imageAltText: LegacyComponents.ImagePreview.ImagePreview.defaultAltTextForImageURL(url),
411
+ - precomputedFeatures: undefined,
412
+ - align: LegacyComponents.ImagePreview.Align.START,
413
+ - });
414
+ - } else if (Trace.Types.Events.isPaint(event)) {
415
+ - previewElement = await TimelineUIUtils.buildPicturePreviewContent(parsedTrace, event, maybeTarget);
416
+ - }
417
+ - // @ts-expect-error TODO(crbug.com/1011811): Remove symbol usage.
418
+ - event[previewElementSymbol] = previewElement;
419
+ - }
420
+ - }
421
+ -
422
+ - // This message may vary per event.name;
423
+ - let relatedNodeLabel;
424
+ -
425
+ - const contentHelper = new TimelineDetailsContentHelper(targetForEvent(parsedTrace, event), linkifier);
426
+ -
427
+ - const defaultColorForEvent = this.eventColor(event);
428
+ - const isMarker = parsedTrace && isMarkerEvent(parsedTrace, event);
429
+ - const color = isMarker ? TimelineUIUtils.markerStyleForEvent(event).color : defaultColorForEvent;
430
+ -
431
+ - contentHelper.addSection(TimelineUIUtils.eventTitle(event), color, event);
432
+ -
433
+ - // TODO: as part of the removal of the old engine, produce a typesafe way
434
+ - // to look up args and data for events.
435
+ - // eslint-disable-next-line @typescript-eslint/no-explicit-any
436
+ - const unsafeEventArgs = event.args as Record<string, any>;
437
+ - // eslint-disable-next-line @typescript-eslint/no-explicit-any
438
+ - const unsafeEventData = event.args?.data as Record<string, any>;
439
+ - const initiator = parsedTrace.data.Initiators.eventToInitiator.get(event) ?? null;
440
+ - const initiatorFor = parsedTrace.data.Initiators.initiatorToEvents.get(event) ?? null;
441
+ -
442
+ - let url: Platform.DevToolsPath.UrlString|null = null;
443
+ -
444
+ - if (parsedTrace) {
445
+ - const warnings = TimelineComponents.DetailsView.buildWarningElementsForEvent(event, parsedTrace);
446
+ - for (const warning of warnings) {
447
+ - contentHelper.appendElementRow(i18nString(UIStrings.warning), warning, true);
448
+ - }
449
+ - }
450
+ -
451
+ - // Add timestamp to user timings, including custom extensibility markers
452
+ - if (Trace.Helpers.Trace.eventHasCategory(event, Trace.Types.Events.Categories.UserTiming) ||
453
+ - Trace.Types.Extensions.isSyntheticExtensionEntry(event)) {
454
+ - const adjustedEventTimeStamp = timeStampForEventAdjustedForClosestNavigationIfPossible(
455
+ - event,
456
+ - parsedTrace,
457
+ - );
458
+ - contentHelper.appendTextRow(
459
+ - i18nString(UIStrings.timestamp), i18n.TimeUtilities.preciseMillisToString(adjustedEventTimeStamp, 1));
460
+ - }
461
+ -
462
+ - // Only show total time and self time for events with non-zero durations.
463
+ - if (duration !== 0 && !Number.isNaN(duration)) {
464
+ - const timeStr = getDurationString(duration, selfTime);
465
+ - contentHelper.appendTextRow(i18nString(UIStrings.duration), timeStr);
466
+ - }
467
+ -
468
+ - if (Trace.Types.Events.isPerformanceMark(event) && event.args.data?.detail) {
469
+ - const detailContainer = TimelineUIUtils.renderObjectJson(JSON.parse(event.args.data?.detail));
470
+ - contentHelper.appendElementRow(i18nString(UIStrings.details), detailContainer);
471
+ - }
472
+ - if (Trace.Types.Events.isSyntheticUserTiming(event) && event.args?.data?.beginEvent.args.detail) {
473
+ - const detailContainer = TimelineUIUtils.renderObjectJson(JSON.parse(event.args?.data?.beginEvent.args.detail));
474
+ - contentHelper.appendElementRow(i18nString(UIStrings.details), detailContainer);
475
+ - }
476
+ -
477
+ - if (parsedTrace.data.Meta.traceIsGeneric) {
478
+ - TimelineUIUtils.renderEventJson(event, contentHelper);
479
+ - return contentHelper.fragment;
480
+ - }
481
+ -
482
+ - if (Trace.Types.Events.isV8Compile(event)) {
483
+ - url = event.args.data?.url as Platform.DevToolsPath.UrlString;
484
+ - if (url) {
485
+ - const {lineNumber, columnNumber} = Trace.Helpers.Trace.getZeroIndexedLineAndColumnForEvent(event);
486
+ - contentHelper.appendLocationRow(
487
+ - i18nString(UIStrings.script), url, lineNumber || 0, columnNumber, undefined, true);
488
+ - const originWithEntity = this.getOriginWithEntity(entityMapper, parsedTrace, event);
489
+ - if (originWithEntity) {
490
+ - contentHelper.appendElementRow(i18nString(UIStrings.origin), originWithEntity);
491
+ - }
492
+ - entityAppended = true;
493
+ - }
494
+ - const isEager = Boolean(event.args.data?.eager);
495
+ - if (isEager) {
496
+ - contentHelper.appendTextRow(i18nString(UIStrings.eagerCompile), true);
497
+ - }
498
+ -
499
+ - const isStreamed = Boolean(event.args.data?.streamed);
500
+ - contentHelper.appendTextRow(
501
+ - i18nString(UIStrings.streamed),
502
+ - isStreamed + (isStreamed ? '' : `: ${event.args.data?.notStreamedReason || ''}`));
503
+ - if (event.args.data) {
504
+ - TimelineUIUtils.buildConsumeCacheDetails(event.args.data, contentHelper);
505
+ - }
506
+ - }
507
+ -
508
+ - if (Trace.Types.Extensions.isSyntheticExtensionEntry(event)) {
509
+ - // isSyntheticExtensionEntries can be any of: perf.measure, perf.mark or console.timeStamp.
510
+ - const userDetail = structuredClone(event.userDetail) as Record<string, Trace.Types.Extensions.JsonValue>;
511
+ - if (userDetail && Object.keys(userDetail).length) {
512
+ - // E.g. console.timeStamp(name, start, end, track, trackGroup, color,
513
+ - // {url: 'foo-extension://node/1', description: 'Node'});
514
+ - const hasExclusiveLink = typeof userDetail === 'object' && typeof userDetail.url === 'string' &&
515
+ - typeof userDetail.description === 'string';
516
+ - if (hasExclusiveLink && Boolean(Root.Runtime.hostConfig.devToolsDeepLinksViaExtensibilityApi?.enabled)) {
517
+ - const linkElement = this.maybeCreateLinkElement(String(userDetail.url));
518
+ - if (linkElement) {
519
+ - contentHelper.appendElementRow(String(userDetail.description), linkElement);
520
+ - // Now remove so we don't render them in renderObjectJson.
521
+ - delete userDetail.url;
522
+ - delete userDetail.description;
523
+ - }
524
+ - }
525
+ - if (Object.keys(userDetail).length) {
526
+ - // E.g., performance.measure(name, {detail: {important: 42, devtools: {}}})
527
+ - const detailContainer = TimelineUIUtils.renderObjectJson(userDetail);
528
+ - contentHelper.appendElementRow(i18nString(UIStrings.details), detailContainer);
529
+ - }
530
+ - }
531
+ -
532
+ - // E.g. performance.measure(name, {detail: {devtools: {properties: ['Key', 'Value']}}})
533
+ - if (event.devtoolsObj.properties) {
534
+ - for (const [key, value] of event.devtoolsObj.properties || []) {
535
+ - const renderedValue = typeof value === 'string' ? TimelineUIUtils.parseStringForLinks(value) :
536
+ - TimelineUIUtils.renderObjectJson(value);
537
+ - contentHelper.appendElementRow(key, renderedValue);
538
+ - }
539
+ - }
540
+ - }
541
+ -
542
+ - const isFreshOrEnhanced =
543
+ - Boolean(parsedTrace && Tracing.FreshRecording.Tracker.instance().recordingIsFreshOrEnhanced(parsedTrace));
544
+ -
545
+ - switch (event.name) {
546
+ - case Trace.Types.Events.Name.GC:
547
+ - case Trace.Types.Events.Name.MAJOR_GC:
548
+ - case Trace.Types.Events.Name.MINOR_GC: {
549
+ - const delta = unsafeEventArgs['usedHeapSizeBefore'] - unsafeEventArgs['usedHeapSizeAfter'];
550
+ - contentHelper.appendTextRow(i18nString(UIStrings.collected), i18n.ByteUtilities.bytesToString(delta));
551
+ - break;
552
+ - }
553
+ -
554
+ - case Trace.Types.Events.Name.PROFILE_CALL: {
555
+ - const profileCall = event as Trace.Types.Events.SyntheticProfileCall;
556
+ - const resolvedURL = SourceMapsResolver.SourceMapsResolver.resolvedURLForEntry(parsedTrace, profileCall);
557
+ - if (!resolvedURL) {
558
+ - break;
559
+ - }
560
+ - const callFrame = profileCall.callFrame;
561
+ - // Render the URL with its location content.
562
+ - contentHelper.appendLocationRow(
563
+ - i18nString(UIStrings.source), resolvedURL, callFrame.lineNumber || 0, callFrame.columnNumber, undefined,
564
+ - true);
565
+ - const originWithEntity = this.getOriginWithEntity(entityMapper, parsedTrace, profileCall);
566
+ - if (originWithEntity) {
567
+ - contentHelper.appendElementRow(i18nString(UIStrings.origin), originWithEntity);
568
+ - }
569
+ - entityAppended = true;
570
+ - break;
571
+ - }
572
+ - case Trace.Types.Events.Name.FUNCTION_CALL: {
573
+ - const detailsNode = await TimelineUIUtils.buildDetailsNodeForTraceEvent(
574
+ - event, targetForEvent(parsedTrace, event), linkifier, isFreshOrEnhanced, parsedTrace);
575
+ - if (detailsNode) {
576
+ - contentHelper.appendElementRow(i18nString(UIStrings.function), detailsNode);
577
+ - const originWithEntity = this.getOriginWithEntity(entityMapper, parsedTrace, event);
578
+ - if (originWithEntity) {
579
+ - contentHelper.appendElementRow(i18nString(UIStrings.origin), originWithEntity);
580
+ - }
581
+ - entityAppended = true;
582
+ - }
583
+ - break;
584
+ - }
585
+ -
586
+ - case Trace.Types.Events.Name.TIMER_FIRE:
587
+ - case Trace.Types.Events.Name.TIMER_INSTALL:
588
+ - case Trace.Types.Events.Name.TIMER_REMOVE: {
589
+ - contentHelper.appendTextRow(i18nString(UIStrings.timerId), unsafeEventData.timerId);
590
+ -
591
+ - if (event.name === Trace.Types.Events.Name.TIMER_INSTALL) {
592
+ - contentHelper.appendTextRow(
593
+ - i18nString(UIStrings.timeout), i18n.TimeUtilities.millisToString(unsafeEventData['timeout']));
594
+ - contentHelper.appendTextRow(i18nString(UIStrings.repeats), !unsafeEventData['singleShot']);
595
+ - }
596
+ - break;
597
+ - }
598
+ -
599
+ - case Trace.Types.Events.Name.SCHEDULE_POST_TASK_CALLBACK:
600
+ - case Trace.Types.Events.Name.RUN_POST_TASK_CALLBACK: {
601
+ - contentHelper.appendTextRow(
602
+ - i18nString(UIStrings.delay), i18n.TimeUtilities.millisToString(unsafeEventData['delay']));
603
+ - contentHelper.appendTextRow(i18nString(UIStrings.priority), unsafeEventData['priority']);
604
+ - break;
605
+ - }
606
+ -
607
+ - case Trace.Types.Events.Name.FIRE_ANIMATION_FRAME: {
608
+ - contentHelper.appendTextRow(i18nString(UIStrings.callbackId), unsafeEventData['id']);
609
+ - break;
610
+ - }
611
+ -
612
+ - case Trace.Types.Events.Name.COMPILE_MODULE: {
613
+ - contentHelper.appendLocationRow(i18nString(UIStrings.module), unsafeEventArgs['fileName'], 0);
614
+ - break;
615
+ - }
616
+ - case Trace.Types.Events.Name.COMPILE_SCRIPT: {
617
+ - // This case is handled above
618
+ - break;
619
+ - }
620
+ -
621
+ - case Trace.Types.Events.Name.CACHE_MODULE: {
622
+ - url = unsafeEventData && unsafeEventData['url'] as Platform.DevToolsPath.UrlString;
623
+ - contentHelper.appendTextRow(
624
+ - i18nString(UIStrings.compilationCacheSize),
625
+ - i18n.ByteUtilities.bytesToString(unsafeEventData['producedCacheSize']));
626
+ - break;
627
+ - }
628
+ -
629
+ - case Trace.Types.Events.Name.CACHE_SCRIPT: {
630
+ - url = unsafeEventData && unsafeEventData['url'] as Platform.DevToolsPath.UrlString;
631
+ - if (url) {
632
+ - const {lineNumber, columnNumber} = Trace.Helpers.Trace.getZeroIndexedLineAndColumnForEvent(event);
633
+ - contentHelper.appendLocationRow(
634
+ - i18nString(UIStrings.script), url, lineNumber || 0, columnNumber, undefined, true);
635
+ - const originWithEntity = this.getOriginWithEntity(entityMapper, parsedTrace, event);
636
+ - if (originWithEntity) {
637
+ - contentHelper.appendElementRow(i18nString(UIStrings.origin), originWithEntity);
638
+ - }
639
+ - entityAppended = true;
640
+ - }
641
+ - contentHelper.appendTextRow(
642
+ - i18nString(UIStrings.compilationCacheSize),
643
+ - i18n.ByteUtilities.bytesToString(unsafeEventData['producedCacheSize']));
644
+ - break;
645
+ - }
646
+ -
647
+ - case Trace.Types.Events.Name.EVALUATE_SCRIPT: {
648
+ - url = unsafeEventData && unsafeEventData['url'] as Platform.DevToolsPath.UrlString;
649
+ - if (url) {
650
+ - const {lineNumber, columnNumber} = Trace.Helpers.Trace.getZeroIndexedLineAndColumnForEvent(event);
651
+ - contentHelper.appendLocationRow(
652
+ - i18nString(UIStrings.script), url, lineNumber || 0, columnNumber, undefined, true);
653
+ - const originWithEntity = this.getOriginWithEntity(entityMapper, parsedTrace, event);
654
+ - if (originWithEntity) {
655
+ - contentHelper.appendElementRow(i18nString(UIStrings.origin), originWithEntity);
656
+ - }
657
+ - entityAppended = true;
658
+ - }
659
+ - break;
660
+ - }
661
+ -
662
+ - case Trace.Types.Events.Name.WASM_STREAM_FROM_RESPONSE_CALLBACK:
663
+ - case Trace.Types.Events.Name.WASM_COMPILED_MODULE:
664
+ - case Trace.Types.Events.Name.WASM_CACHED_MODULE:
665
+ - case Trace.Types.Events.Name.WASM_MODULE_CACHE_HIT:
666
+ - case Trace.Types.Events.Name.WASM_MODULE_CACHE_INVALID: {
667
+ - if (unsafeEventData) {
668
+ - url = unsafeEventArgs['url'] as Platform.DevToolsPath.UrlString;
669
+ - if (url) {
670
+ - contentHelper.appendTextRow(i18nString(UIStrings.url), url);
671
+ - }
672
+ - const producedCachedSize = unsafeEventArgs['producedCachedSize'];
673
+ - if (producedCachedSize) {
674
+ - contentHelper.appendTextRow(i18nString(UIStrings.producedCacheSize), producedCachedSize);
675
+ - }
676
+ - const consumedCachedSize = unsafeEventArgs['consumedCachedSize'];
677
+ - if (consumedCachedSize) {
678
+ - contentHelper.appendTextRow(i18nString(UIStrings.consumedCacheSize), consumedCachedSize);
679
+ - }
680
+ - }
681
+ - break;
682
+ - }
683
+ -
684
+ - case Trace.Types.Events.Name.PAINT:
685
+ - case Trace.Types.Events.Name.PAINT_SETUP:
686
+ - case Trace.Types.Events.Name.RASTERIZE:
687
+ - case Trace.Types.Events.Name.SCROLL_LAYER: {
688
+ - relatedNodeLabel = i18nString(UIStrings.layerRoot);
689
+ - break;
690
+ - }
691
+ -
692
+ - case Trace.Types.Events.Name.PAINT_IMAGE:
693
+ - case Trace.Types.Events.Name.DECODE_LAZY_PIXEL_REF:
694
+ - case Trace.Types.Events.Name.DECODE_IMAGE:
695
+ - case Trace.Types.Events.Name.DRAW_LAZY_PIXEL_REF: {
696
+ - relatedNodeLabel = i18nString(UIStrings.ownerElement);
697
+ - url = Trace.Handlers.Helpers.getNonResolvedURL(event, parsedTrace.data);
698
+ - if (url) {
699
+ - const options = {
700
+ - tabStop: true,
701
+ - showColumnNumber: false,
702
+ - inlineFrameIndex: 0,
703
+ - };
704
+ - contentHelper.appendElementRow(
705
+ - i18nString(UIStrings.imageUrl), LegacyComponents.Linkifier.Linkifier.linkifyURL(url, options));
706
+ - }
707
+ - break;
708
+ - }
709
+ -
710
+ - case Trace.Types.Events.Name.PARSE_AUTHOR_STYLE_SHEET: {
711
+ - url = unsafeEventData['styleSheetUrl'] as Platform.DevToolsPath.UrlString;
712
+ - if (url) {
713
+ - const options = {
714
+ - tabStop: true,
715
+ - showColumnNumber: false,
716
+ - inlineFrameIndex: 0,
717
+ - };
718
+ - contentHelper.appendElementRow(
719
+ - i18nString(UIStrings.stylesheetUrl), LegacyComponents.Linkifier.Linkifier.linkifyURL(url, options));
720
+ - }
721
+ - break;
722
+ - }
723
+ -
724
+ - case Trace.Types.Events.Name.RECALC_STYLE: {
725
+ - contentHelper.appendTextRow(i18nString(UIStrings.elementsAffected), unsafeEventArgs['elementCount']);
726
+ -
727
+ - const selectorStatsSetting =
728
+ - Common.Settings.Settings.instance().createSetting('timeline-capture-selector-stats', false);
729
+ - if (!selectorStatsSetting.get()) {
730
+ - const note = document.createElement('span');
731
+ - note.textContent = i18nString(UIStrings.sSelectorStatsInfo, {PH1: selectorStatsSetting.title()});
732
+ - contentHelper.appendElementRow(i18nString(UIStrings.selectorStatsTitle), note);
733
+ - }
734
+ -
735
+ - break;
736
+ - }
737
+ -
738
+ - case Trace.Types.Events.Name.LAYOUT: {
739
+ - const beginData = unsafeEventArgs['beginData'];
740
+ - contentHelper.appendTextRow(
741
+ - i18nString(UIStrings.nodesThatNeedLayout),
742
+ - i18nString(UIStrings.sOfS, {PH1: beginData['dirtyObjects'], PH2: beginData['totalObjects']}));
743
+ - relatedNodeLabel = i18nString(UIStrings.layoutRoot);
744
+ - break;
745
+ - }
746
+ -
747
+ - case Trace.Types.Events.Name.CONSOLE_TIME: {
748
+ - contentHelper.appendTextRow(i18nString(UIStrings.message), event.name);
749
+ - break;
750
+ - }
751
+ -
752
+ - case Trace.Types.Events.Name.WEB_SOCKET_CREATE:
753
+ - case Trace.Types.Events.Name.WEB_SOCKET_SEND_HANDSHAKE_REQUEST:
754
+ - case Trace.Types.Events.Name.WEB_SOCKET_RECEIVE_HANDSHAKE_REQUEST:
755
+ - case Trace.Types.Events.Name.WEB_SOCKET_SEND:
756
+ - case Trace.Types.Events.Name.WEB_SOCKET_RECEIVE:
757
+ - case Trace.Types.Events.Name.WEB_SOCKET_DESTROY: {
758
+ - if (Trace.Types.Events.isWebSocketTraceEvent(event)) {
759
+ - const rows = TimelineComponents.DetailsView.buildRowsForWebSocketEvent(event, parsedTrace);
760
+ - for (const {key, value} of rows) {
761
+ - contentHelper.appendTextRow(key, value);
762
+ - }
763
+ - }
764
+ - break;
765
+ - }
766
+ -
767
+ - case Trace.Types.Events.Name.EMBEDDER_CALLBACK: {
768
+ - contentHelper.appendTextRow(i18nString(UIStrings.callbackFunction), unsafeEventData['callbackName']);
769
+ - break;
770
+ - }
771
+ -
772
+ - case Trace.Types.Events.Name.ANIMATION: {
773
+ - if (!Trace.Types.Events.isSyntheticAnimation(event)) {
774
+ - break;
775
+ - }
776
+ - const {displayName, nodeName} = event.args.data.beginEvent.args.data;
777
+ - displayName && contentHelper.appendTextRow(i18nString(UIStrings.animating), displayName);
778
+ - // If relatedNodes is empty (maybe saved trace), then print the text description of the DOM node.
779
+ - if (!relatedNodesMap?.size && nodeName) {
780
+ - contentHelper.appendTextRow(i18nString(UIStrings.relatedNode), nodeName);
781
+ - }
782
+ -
783
+ - const CLSInsight = Trace.Insights.Models.CLSCulprits;
784
+ - const failures = CLSInsight.getNonCompositedFailure(event);
785
+ - if (!failures.length) {
786
+ - break;
787
+ - }
788
+ -
789
+ - const failureReasons = new Set(failures.map(f => f.failureReasons).flat().filter(Boolean));
790
+ - const unsupportedProperties =
791
+ - new Set(failures.map(f => f.unsupportedProperties).flat().filter(Boolean)) as Set<string>;
792
+ -
793
+ - // The failureReasons can be empty when Blink added a new failure reason that is
794
+ - // not supported by DevTools yet
795
+ - if (failureReasons.size === 0) {
796
+ - contentHelper.appendElementRow(
797
+ - i18nString(UIStrings.compositingFailed), i18nString(UIStrings.compositingFailedUnknownReason), true);
798
+ - } else {
799
+ - for (const reason of failureReasons) {
800
+ - let str;
801
+ - switch (reason) {
802
+ - case CLSInsight.AnimationFailureReasons.ACCELERATED_ANIMATIONS_DISABLED:
803
+ - str = i18nString(UIStrings.compositingFailedAcceleratedAnimationsDisabled);
804
+ - break;
805
+ - case CLSInsight.AnimationFailureReasons.EFFECT_SUPPRESSED_BY_DEVTOOLS:
806
+ - str = i18nString(UIStrings.compositingFailedEffectSuppressedByDevtools);
807
+ - break;
808
+ - case CLSInsight.AnimationFailureReasons.INVALID_ANIMATION_OR_EFFECT:
809
+ - str = i18nString(UIStrings.compositingFailedInvalidAnimationOrEffect);
810
+ - break;
811
+ - case CLSInsight.AnimationFailureReasons.EFFECT_HAS_UNSUPPORTED_TIMING_PARAMS:
812
+ - str = i18nString(UIStrings.compositingFailedEffectHasUnsupportedTimingParams);
813
+ - break;
814
+ - case CLSInsight.AnimationFailureReasons.EFFECT_HAS_NON_REPLACE_COMPOSITE_MODE:
815
+ - str = i18nString(UIStrings.compositingFailedEffectHasNonReplaceCompositeMode);
816
+ - break;
817
+ - case CLSInsight.AnimationFailureReasons.TARGET_HAS_INVALID_COMPOSITING_STATE:
818
+ - str = i18nString(UIStrings.compositingFailedTargetHasInvalidCompositingState);
819
+ - break;
820
+ - case CLSInsight.AnimationFailureReasons.TARGET_HAS_INCOMPATIBLE_ANIMATIONS:
821
+ - str = i18nString(UIStrings.compositingFailedTargetHasIncompatibleAnimations);
822
+ - break;
823
+ - case CLSInsight.AnimationFailureReasons.TARGET_HAS_CSS_OFFSET:
824
+ - str = i18nString(UIStrings.compositingFailedTargetHasCSSOffset);
825
+ - break;
826
+ - case CLSInsight.AnimationFailureReasons.ANIMATION_AFFECTS_NON_CSS_PROPERTIES:
827
+ - str = i18nString(UIStrings.compositingFailedAnimationAffectsNonCSSProperties);
828
+ - break;
829
+ - case CLSInsight.AnimationFailureReasons.TRANSFORM_RELATED_PROPERTY_CANNOT_BE_ACCELERATED_ON_TARGET:
830
+ - str = i18nString(UIStrings.compositingFailedTransformRelatedPropertyCannotBeAcceleratedOnTarget);
831
+ - break;
832
+ - case CLSInsight.AnimationFailureReasons.TRANSFROM_BOX_SIZE_DEPENDENT:
833
+ - str = i18nString(UIStrings.compositingFailedTransformDependsBoxSize);
834
+ - break;
835
+ - case CLSInsight.AnimationFailureReasons.FILTER_RELATED_PROPERTY_MAY_MOVE_PIXELS:
836
+ - str = i18nString(UIStrings.compositingFailedFilterRelatedPropertyMayMovePixels);
837
+ - break;
838
+ - case CLSInsight.AnimationFailureReasons.UNSUPPORTED_CSS_PROPERTY:
839
+ - str = i18nString(UIStrings.compositingFailedUnsupportedCSSProperty, {
840
+ - propertyCount: unsupportedProperties.size,
841
+ - properties: new Intl.ListFormat(undefined, {style: 'short', type: 'conjunction'})
842
+ - .format(unsupportedProperties),
843
+ - });
844
+ - break;
845
+ - case CLSInsight.AnimationFailureReasons.MIXED_KEYFRAME_VALUE_TYPES:
846
+ - str = i18nString(UIStrings.compositingFailedMixedKeyframeValueTypes);
847
+ - break;
848
+ - case CLSInsight.AnimationFailureReasons.TIMELINE_SOURCE_HAS_INVALID_COMPOSITING_STATE:
849
+ - str = i18nString(UIStrings.compositingFailedTimelineSourceHasInvalidCompositingState);
850
+ - break;
851
+ - case CLSInsight.AnimationFailureReasons.ANIMATION_HAS_NO_VISIBLE_CHANGE:
852
+ - str = i18nString(UIStrings.compositingFailedAnimationHasNoVisibleChange);
853
+ - break;
854
+ - case CLSInsight.AnimationFailureReasons.AFFECTS_IMPORTANT_PROPERTY:
855
+ - str = i18nString(UIStrings.compositingFailedAffectsImportantProperty);
856
+ - break;
857
+ - case CLSInsight.AnimationFailureReasons.SVG_TARGET_HAS_INDEPENDENT_TRANSFORM_PROPERTY:
858
+ - str = i18nString(UIStrings.compositingFailedSVGTargetHasIndependentTransformProperty);
859
+ - break;
860
+ - default:
861
+ - // We should never actually end up here, as adding a new AnimationFailureReason
862
+ - // should also require adding a UIString that describes it
863
+ - str = i18nString(UIStrings.compositingFailedUnknownReason);
864
+ - break;
865
+ - }
866
+ - str && contentHelper.appendElementRow(i18nString(UIStrings.compositingFailed), str, true);
867
+ - }
868
+ - }
869
+ -
870
+ - break;
871
+ - }
872
+ -
873
+ - case Trace.Types.Events.Name.PARSE_HTML: {
874
+ - const beginData = unsafeEventArgs['beginData'];
875
+ - const startLine = beginData['startLine'] - 1;
876
+ - const endLine = unsafeEventArgs['endData'] ? unsafeEventArgs['endData']['endLine'] - 1 : undefined;
877
+ - url = beginData['url'];
878
+ - if (url) {
879
+ - contentHelper.appendLocationRange(i18nString(UIStrings.range), url, startLine, endLine);
880
+ - }
881
+ - break;
882
+ - }
883
+ -
884
+ - // @ts-expect-error Fall-through intended.
885
+ - case Trace.Types.Events.Name.FIRE_IDLE_CALLBACK: {
886
+ - contentHelper.appendTextRow(
887
+ - i18nString(UIStrings.allottedTime),
888
+ - i18n.TimeUtilities.millisToString(unsafeEventData['allottedMilliseconds']));
889
+ - contentHelper.appendTextRow(i18nString(UIStrings.invokedByTimeout), unsafeEventData['timedOut']);
890
+ - }
891
+ -
892
+ - case Trace.Types.Events.Name.REQUEST_IDLE_CALLBACK:
893
+ - case Trace.Types.Events.Name.CANCEL_IDLE_CALLBACK: {
894
+ - contentHelper.appendTextRow(i18nString(UIStrings.callbackId), unsafeEventData['id']);
895
+ -
896
+ - if (Trace.Types.Events.isRequestIdleCallback(event)) {
897
+ - contentHelper.appendTextRow(
898
+ - i18nString(UIStrings.requestIdleCallbackTimeout),
899
+ - i18n.TimeUtilities.preciseMillisToString(event.args.data.timeout));
900
+ - }
901
+ - break;
902
+ - }
903
+ -
904
+ - case Trace.Types.Events.Name.EVENT_DISPATCH: {
905
+ - contentHelper.appendTextRow(i18nString(UIStrings.type), unsafeEventData['type']);
906
+ - break;
907
+ - }
908
+ -
909
+ - // @ts-expect-error Fall-through intended.
910
+ - case Trace.Types.Events.Name.MARK_LCP_CANDIDATE: {
911
+ - contentHelper.appendTextRow(i18nString(UIStrings.type), String(unsafeEventData['type']));
912
+ - contentHelper.appendTextRow(i18nString(UIStrings.size), String(unsafeEventData['size']));
913
+ - }
914
+ -
915
+ - case Trace.Types.Events.Name.MARK_FIRST_PAINT:
916
+ - case Trace.Types.Events.Name.MARK_FCP:
917
+ - case Trace.Types.Events.Name.MARK_LOAD:
918
+ - case Trace.Types.Events.Name.MARK_DOM_CONTENT: {
919
+ - const adjustedEventTimeStamp = timeStampForEventAdjustedForClosestNavigationIfPossible(
920
+ - event,
921
+ - parsedTrace,
922
+ - );
923
+ -
924
+ - contentHelper.appendTextRow(
925
+ - i18nString(UIStrings.timestamp), i18n.TimeUtilities.preciseMillisToString(adjustedEventTimeStamp, 1));
926
+ -
927
+ - if (Trace.Types.Events.isMarkerEvent(event)) {
928
+ - contentHelper.appendElementRow(
929
+ - i18nString(UIStrings.details), TimelineUIUtils.buildDetailsNodeForMarkerEvents(event));
930
+ - }
931
+ -
932
+ - break;
933
+ - }
934
+ -
935
+ - case Trace.Types.Events.Name.EVENT_TIMING: {
936
+ - const detailsNode = await TimelineUIUtils.buildDetailsNodeForTraceEvent(
937
+ - event, targetForEvent(parsedTrace, event), linkifier, isFreshOrEnhanced, parsedTrace);
938
+ - if (detailsNode) {
939
+ - contentHelper.appendElementRow(i18nString(UIStrings.details), detailsNode);
940
+ - }
941
+ - if (Trace.Types.Events.isSyntheticInteraction(event)) {
942
+ - const inputDelay = i18n.TimeUtilities.formatMicroSecondsAsMillisFixed(event.inputDelay);
943
+ - const mainThreadTime = i18n.TimeUtilities.formatMicroSecondsAsMillisFixed(event.mainThreadHandling);
944
+ - const presentationDelay = i18n.TimeUtilities.formatMicroSecondsAsMillisFixed(event.presentationDelay);
945
+ - contentHelper.appendTextRow(i18nString(UIStrings.interactionID), event.interactionId);
946
+ - contentHelper.appendTextRow(i18nString(UIStrings.inputDelay), inputDelay);
947
+ - contentHelper.appendTextRow(i18nString(UIStrings.processingDuration), mainThreadTime);
948
+ - contentHelper.appendTextRow(i18nString(UIStrings.presentationDelay), presentationDelay);
949
+ - }
950
+ - break;
951
+ - }
952
+ -
953
+ - default: {
954
+ - const detailsNode = await TimelineUIUtils.buildDetailsNodeForTraceEvent(
955
+ - event, targetForEvent(parsedTrace, event), linkifier, isFreshOrEnhanced, parsedTrace);
956
+ - if (detailsNode) {
957
+ - contentHelper.appendElementRow(i18nString(UIStrings.details), detailsNode);
958
+ - }
959
+ - break;
960
+ - }
961
+ - }
962
+ - const relatedNodes = relatedNodesMap?.values() || [];
963
+ - for (const relatedNode of relatedNodes) {
964
+ - if (relatedNode) {
965
+ - const nodeSpan = await Common.Linkifier.Linkifier.linkify(relatedNode);
966
+ - contentHelper.appendElementRow(relatedNodeLabel || i18nString(UIStrings.relatedNode), nodeSpan);
967
+ - }
968
+ - }
969
+ -
970
+ - // @ts-expect-error TODO(crbug.com/1011811): Remove symbol usage.
971
+ - if (event[previewElementSymbol]) {
972
+ - contentHelper.addSection(i18nString(UIStrings.preview));
973
+ - // @ts-expect-error TODO(crbug.com/1011811): Remove symbol usage.
974
+ - contentHelper.appendElementRow('', event[previewElementSymbol]);
975
+ - }
976
+ -
977
+ - if (!entityAppended) {
978
+ - const originWithEntity = this.getOriginWithEntity(entityMapper, parsedTrace, event);
979
+ - if (originWithEntity) {
980
+ - contentHelper.appendElementRow(i18nString(UIStrings.origin), originWithEntity);
981
+ - }
982
+ - }
983
+ -
984
+ - const hasStackTrace = Boolean(Trace.Helpers.Trace.getStackTraceTopCallFrameInEventPayload(event));
985
+ - if (Trace.Types.Events.isUserTiming(event) || Trace.Types.Extensions.isSyntheticExtensionEntry(event) ||
986
+ - Trace.Types.Events.isProfileCall(event) || initiator || initiatorFor || hasStackTrace ||
987
+ - parsedTrace?.data.Invalidations.invalidationsForEvent.get(event)) {
988
+ - await TimelineUIUtils.generateCauses(event, contentHelper, parsedTrace);
989
+ - }
990
+ -
991
+ - if (Root.Runtime.experiments.isEnabled(Root.Runtime.ExperimentName.TIMELINE_DEBUG_MODE)) {
992
+ - TimelineUIUtils.renderEventJson(event, contentHelper);
993
+ - }
994
+ -
65
995
  - const stats: TimeRangeCategoryStats = {};
66
996
  - const showPieChart = canShowPieChart && TimelineUIUtils.aggregatedStatsForTraceEvent(stats, parsedTrace, event);
67
997
  - if (showPieChart) {
@@ -70,10 +1000,346 @@ index 4fe7b92..573e0d3 100644
70
1000
  - contentHelper.appendElementRow('', pieChart);
71
1001
  - }
72
1002
  -
73
- return contentHelper.fragment;
1003
+ - return contentHelper.fragment;
1004
+ - }
1005
+ -
1006
+ static statsForTimeRange(
1007
+ events: Trace.Types.Events.Event[], startTime: Trace.Types.Timing.Milli,
1008
+ endTime: Trace.Types.Timing.Milli): TimeRangeCategoryStats {
1009
+ @@ -1660,264 +738,6 @@ export class TimelineUIUtils {
1010
+ }
74
1011
  }
75
1012
 
76
- @@ -2048,79 +2039,6 @@ export class TimelineUIUtils {
1013
+ - private static renderEventJson(event: Trace.Types.Events.Event, contentHelper: TimelineDetailsContentHelper): void {
1014
+ - contentHelper.addSection(i18nString(UIStrings.traceEvent));
1015
+ -
1016
+ - const eventWithArgsFirst = {
1017
+ - ...{args: event.args},
1018
+ - ...event,
1019
+ - };
1020
+ - const highlightContainer = TimelineUIUtils.renderObjectJson(eventWithArgsFirst);
1021
+ - contentHelper.appendElementRow('', highlightContainer);
1022
+ - }
1023
+ -
1024
+ - private static renderObjectJson(obj: Object|Trace.Types.Extensions.JsonValue): HTMLDivElement {
1025
+ - const indentLength = Common.Settings.Settings.instance().moduleSetting('text-editor-indent').get().length;
1026
+ - // Elide if the data is huge. Then remove the initial new-line for a denser UI
1027
+ - const eventStr = JSON.stringify(obj, null, indentLength).slice(0, 10_000).replace(/{\n /, '{ ');
1028
+ -
1029
+ - // Use CodeHighlighter for syntax highlighting.
1030
+ - const highlightContainer = document.createElement('div');
1031
+ - const shadowRoot = UI.UIUtils.createShadowRootWithCoreStyles(highlightContainer, {cssFile: codeHighlighterStyles});
1032
+ - const elem = shadowRoot.createChild('div');
1033
+ - elem.classList.add('monospace', 'source-code');
1034
+ - elem.textContent = eventStr;
1035
+ - // Highlighting is done async (shrug), but we'll return the container immediately.
1036
+ - void CodeHighlighter.CodeHighlighter.highlightNode(elem, 'text/javascript').then(() => {
1037
+ - /**
1038
+ - * Linkify any URLs within the text nodes.
1039
+ - * Use a TreeWalker to find all our text nodes
1040
+ - **/
1041
+ - function* iterateTreeWalker(walker: TreeWalker): IterableIterator<Node> {
1042
+ - while (walker.nextNode()) {
1043
+ - yield walker.currentNode;
1044
+ - }
1045
+ - }
1046
+ - const walker = document.createTreeWalker(elem, NodeFilter.SHOW_TEXT);
1047
+ - // Gather all the nodes first, then we'll potentially replace them.
1048
+ - for (const node of Array.from(iterateTreeWalker(walker))) {
1049
+ - const frag = TimelineUIUtils.parseStringForLinks(node.textContent || '');
1050
+ - node.parentNode?.replaceChild(frag, node);
1051
+ - }
1052
+ - });
1053
+ -
1054
+ - return highlightContainer;
1055
+ - }
1056
+ -
1057
+ - static stackTraceFromCallFrames(callFrames: Protocol.Runtime.CallFrame[]|Trace.Types.Events.CallFrame[]):
1058
+ - Protocol.Runtime.StackTrace {
1059
+ - return {callFrames} as Protocol.Runtime.StackTrace;
1060
+ - }
1061
+ -
1062
+ - static async generateCauses(
1063
+ - event: Trace.Types.Events.Event, contentHelper: TimelineDetailsContentHelper,
1064
+ - parsedTrace: Trace.TraceModel.ParsedTrace): Promise<void> {
1065
+ - const {startTime} = Trace.Helpers.Timing.eventTimingsMilliSeconds(event);
1066
+ - let initiatorStackLabel = i18nString(UIStrings.initiatorStackTrace);
1067
+ - let stackLabel = i18nString(UIStrings.functionStack);
1068
+ - const stackTraceForEvent = Trace.Extras.StackTraceForEvent.get(event, parsedTrace.data);
1069
+ - if (stackTraceForEvent?.callFrames.length || stackTraceForEvent?.description || stackTraceForEvent?.parent) {
1070
+ - contentHelper.addSection(i18nString(UIStrings.functionStack));
1071
+ - contentHelper.createChildStackTraceElement(stackTraceForEvent);
1072
+ - // TODO(andoli): also build stack trace component for other events
1073
+ - // that have a stack trace using the StackTraceForEvent helper.
1074
+ - } else {
1075
+ - const stackTrace = Trace.Helpers.Trace.getZeroIndexedStackTraceInEventPayload(event);
1076
+ - if (stackTrace?.length) {
1077
+ - contentHelper.addSection(stackLabel);
1078
+ - contentHelper.createChildStackTraceElement(TimelineUIUtils.stackTraceFromCallFrames(stackTrace));
1079
+ - }
1080
+ - }
1081
+ - switch (event.name) {
1082
+ - case Trace.Types.Events.Name.TIMER_FIRE:
1083
+ - initiatorStackLabel = i18nString(UIStrings.timerInstalled);
1084
+ - break;
1085
+ - case Trace.Types.Events.Name.FIRE_ANIMATION_FRAME:
1086
+ - initiatorStackLabel = i18nString(UIStrings.animationFrameRequested);
1087
+ - break;
1088
+ - case Trace.Types.Events.Name.FIRE_IDLE_CALLBACK:
1089
+ - initiatorStackLabel = i18nString(UIStrings.idleCallbackRequested);
1090
+ - break;
1091
+ - case Trace.Types.Events.Name.RECALC_STYLE:
1092
+ - initiatorStackLabel = i18nString(UIStrings.firstInvalidated);
1093
+ - stackLabel = i18nString(UIStrings.recalculationForced);
1094
+ - break;
1095
+ - case Trace.Types.Events.Name.LAYOUT:
1096
+ - initiatorStackLabel = i18nString(UIStrings.firstLayoutInvalidation);
1097
+ - stackLabel = i18nString(UIStrings.layoutForced);
1098
+ - break;
1099
+ - }
1100
+ -
1101
+ - const initiator = parsedTrace.data.Initiators.eventToInitiator.get(event);
1102
+ - const initiatorFor = parsedTrace.data.Initiators.initiatorToEvents.get(event);
1103
+ - const invalidations = parsedTrace.data.Invalidations.invalidationsForEvent.get(event);
1104
+ -
1105
+ - if (initiator) {
1106
+ - // If we have an initiator for the event, we can show its stack trace, a link to reveal the initiator,
1107
+ - // and the time since the initiator (Pending For).
1108
+ - const stackTrace = Trace.Helpers.Trace.getZeroIndexedStackTraceInEventPayload(initiator);
1109
+ - if (stackTrace) {
1110
+ - contentHelper.addSection(initiatorStackLabel);
1111
+ - contentHelper.createChildStackTraceElement(TimelineUIUtils.stackTraceFromCallFrames(stackTrace.map(frame => {
1112
+ - return {
1113
+ - ...frame,
1114
+ - scriptId: String(frame.scriptId) as Protocol.Runtime.ScriptId,
1115
+ - };
1116
+ - })));
1117
+ - }
1118
+ -
1119
+ - const link = this.createEntryLink(initiator);
1120
+ - contentHelper.appendElementRow(i18nString(UIStrings.initiatedBy), link);
1121
+ -
1122
+ - const {startTime: initiatorStartTime} = Trace.Helpers.Timing.eventTimingsMilliSeconds(initiator);
1123
+ - const delay = startTime - initiatorStartTime;
1124
+ - contentHelper.appendTextRow(i18nString(UIStrings.pendingFor), i18n.TimeUtilities.preciseMillisToString(delay, 1));
1125
+ - }
1126
+ -
1127
+ - if (initiatorFor) {
1128
+ - // If the event is an initiator for some entries, add links to reveal them.
1129
+ - const links = document.createElement('div');
1130
+ - initiatorFor.map((initiator, i) => {
1131
+ - links.appendChild(this.createEntryLink(initiator));
1132
+ - // Add space between each link if it's not last
1133
+ - if (i < initiatorFor.length - 1) {
1134
+ - links.append(' ');
1135
+ - }
1136
+ - });
1137
+ - contentHelper.appendElementRow(UIStrings.initiatorFor, links);
1138
+ - }
1139
+ -
1140
+ - if (invalidations?.length) {
1141
+ - const totalInvalidations = parsedTrace.data.Invalidations.invalidationCountForEvent.get(event) ??
1142
+ - 0; // Won't be 0, but saves us dealing with undefined.
1143
+ - contentHelper.addSection(i18nString(UIStrings.invalidations, {PH1: totalInvalidations}));
1144
+ - await TimelineUIUtils.generateInvalidationsList(invalidations, contentHelper);
1145
+ - }
1146
+ - }
1147
+ -
1148
+ - private static createEntryLink(entry: Trace.Types.Events.Event): HTMLElement {
1149
+ - const link = document.createElement('span');
1150
+ -
1151
+ - const traceBoundsState = TraceBounds.TraceBounds.BoundsManager.instance().state();
1152
+ -
1153
+ - if (!traceBoundsState) {
1154
+ - console.error('Tried to link to an entry without any traceBoundsState. This should never happen.');
1155
+ - return link;
1156
+ - }
1157
+ -
1158
+ - // Check is the entry is outside of the current breadcrumb. If it is, don't create a link to navigate to it because there is no way to navigate outside breadcrumb without removing it. Instead, just display the name and "outside breadcrumb" text
1159
+ - // Consider entry outside breadcrumb only if it is fully outside. If a part of it is visible, we can still select it.
1160
+ - const isEntryOutsideBreadcrumb = traceBoundsState.micro.minimapTraceBounds.min > entry.ts + (entry.dur || 0) ||
1161
+ - traceBoundsState.micro.minimapTraceBounds.max < entry.ts;
1162
+ -
1163
+ - // Check if it is in the hidden array
1164
+ - const isEntryHidden = ModificationsManager.activeManager()?.getEntriesFilter().entryIsInvisible(entry);
1165
+ -
1166
+ - if (!isEntryOutsideBreadcrumb) {
1167
+ - link.classList.add('timeline-link');
1168
+ - UI.ARIAUtils.markAsLink(link);
1169
+ - link.tabIndex = 0;
1170
+ - link.addEventListener('click', () => {
1171
+ - TimelinePanel.instance().select(selectionFromEvent(entry));
1172
+ - });
1173
+ -
1174
+ - link.addEventListener('keydown', event => {
1175
+ - if (event.key === Platform.KeyboardUtilities.ENTER_KEY) {
1176
+ - TimelinePanel.instance().select(selectionFromEvent(entry));
1177
+ - event.consume(true);
1178
+ - }
1179
+ - });
1180
+ - }
1181
+ -
1182
+ - if (isEntryHidden) {
1183
+ - link.textContent = this.eventTitle(entry) + ' ' + i18nString(UIStrings.entryIsHidden);
1184
+ - } else if (isEntryOutsideBreadcrumb) {
1185
+ - link.textContent = this.eventTitle(entry) + ' ' + i18nString(UIStrings.outsideBreadcrumbRange);
1186
+ - } else {
1187
+ - link.textContent = this.eventTitle(entry);
1188
+ - }
1189
+ -
1190
+ - return link;
1191
+ - }
1192
+ -
1193
+ - private static async generateInvalidationsList(
1194
+ - invalidations: Trace.Types.Events.InvalidationTrackingEvent[],
1195
+ - contentHelper: TimelineDetailsContentHelper): Promise<void> {
1196
+ - const {groupedByReason, backendNodeIds} = TimelineComponents.DetailsView.generateInvalidationsList(invalidations);
1197
+ -
1198
+ - let relatedNodesMap: Map<number, SDK.DOMModel.DOMNode|null>|null = null;
1199
+ - const target = SDK.TargetManager.TargetManager.instance().primaryPageTarget();
1200
+ - const domModel = target?.model(SDK.DOMModel.DOMModel);
1201
+ - if (domModel) {
1202
+ - relatedNodesMap = await domModel.pushNodesByBackendIdsToFrontend(backendNodeIds);
1203
+ - }
1204
+ -
1205
+ - Object.keys(groupedByReason).forEach(reason => {
1206
+ - TimelineUIUtils.generateInvalidationsForReason(reason, groupedByReason[reason], relatedNodesMap, contentHelper);
1207
+ - });
1208
+ - }
1209
+ -
1210
+ - private static generateInvalidationsForReason(
1211
+ - reason: string, invalidations: Trace.Types.Events.InvalidationTrackingEvent[],
1212
+ - relatedNodesMap: Map<number, SDK.DOMModel.DOMNode|null>|null, contentHelper: TimelineDetailsContentHelper): void {
1213
+ - function createLinkForInvalidationNode(invalidation: Trace.Types.Events.InvalidationTrackingEvent):
1214
+ - HTMLSpanElement {
1215
+ - const node = (invalidation.args.data.nodeId && relatedNodesMap) ?
1216
+ - relatedNodesMap.get(invalidation.args.data.nodeId) :
1217
+ - null;
1218
+ - if (node) {
1219
+ - const nodeSpan = document.createElement('span');
1220
+ - void Common.Linkifier.Linkifier.linkify(node).then(link => nodeSpan.appendChild(link));
1221
+ - return nodeSpan;
1222
+ - }
1223
+ - if (invalidation.args.data.nodeName) {
1224
+ - const nodeSpan = document.createElement('span');
1225
+ - nodeSpan.textContent = invalidation.args.data.nodeName;
1226
+ - return nodeSpan;
1227
+ - }
1228
+ - const nodeSpan = document.createElement('span');
1229
+ - UI.UIUtils.createTextChild(nodeSpan, i18nString(UIStrings.UnknownNode));
1230
+ - return nodeSpan;
1231
+ - }
1232
+ -
1233
+ - const generatedItems = new Set<string>();
1234
+ -
1235
+ - for (const invalidation of invalidations) {
1236
+ - const stackTrace = Trace.Helpers.Trace.getZeroIndexedStackTraceInEventPayload(invalidation);
1237
+ - let scriptLink: HTMLElement|null = null;
1238
+ - const callFrame = stackTrace?.at(0);
1239
+ - if (callFrame) {
1240
+ - scriptLink = contentHelper.linkifier()?.maybeLinkifyScriptLocation(
1241
+ - SDK.TargetManager.TargetManager.instance().rootTarget(),
1242
+ - callFrame.scriptId as Protocol.Runtime.ScriptId,
1243
+ - callFrame.url as Platform.DevToolsPath.UrlString,
1244
+ - callFrame.lineNumber,
1245
+ - ) ||
1246
+ - null;
1247
+ - }
1248
+ -
1249
+ - const niceNodeLink = createLinkForInvalidationNode(invalidation);
1250
+ -
1251
+ - const text = scriptLink ?
1252
+ - i18n.i18n.getFormatLocalizedString(
1253
+ - str_, UIStrings.invalidationWithCallFrame, {PH1: niceNodeLink, PH2: scriptLink}) as HTMLElement :
1254
+ - niceNodeLink;
1255
+ -
1256
+ - // Sometimes we can get different Invalidation events which cause
1257
+ - // the same text for the same element for the same reason to be
1258
+ - // generated. Rather than show the user duplicates, if we have
1259
+ - // generated text that looks identical to this before, we will
1260
+ - // bail.
1261
+ - const generatedText: string = (typeof text === 'string' ? text : text.innerText);
1262
+ - if (generatedItems.has(generatedText)) {
1263
+ - continue;
1264
+ - }
1265
+ -
1266
+ - generatedItems.add(generatedText);
1267
+ - contentHelper.appendElementRow(reason, text);
1268
+ - }
1269
+ - }
1270
+ -
1271
+ /** Populates the passed object then returns true/false if it makes sense to show the pie chart */
1272
+ private static aggregatedStatsForTraceEvent(
1273
+ total: TimeRangeCategoryStats, parsedTrace: Trace.TraceModel.ParsedTrace,
1274
+ @@ -1970,67 +790,12 @@ export class TimelineUIUtils {
1275
+ return true;
1276
+ }
1277
+
1278
+ - static async buildPicturePreviewContent(
1279
+ - parsedTrace: Trace.TraceModel.ParsedTrace, event: Trace.Types.Events.Paint,
1280
+ - target: SDK.Target.Target): Promise<Element|null> {
1281
+ - const snapshotEvent = parsedTrace.data.LayerTree.paintsToSnapshots.get(event);
1282
+ - if (!snapshotEvent) {
1283
+ - return null;
1284
+ - }
1285
+ -
1286
+ - const paintProfilerModel = target.model(SDK.PaintProfiler.PaintProfilerModel);
1287
+ - if (!paintProfilerModel) {
1288
+ - return null;
1289
+ - }
1290
+ - const snapshot = await paintProfilerModel.loadSnapshot(snapshotEvent.args.snapshot.skp64);
1291
+ - if (!snapshot) {
1292
+ - return null;
1293
+ - }
1294
+ -
1295
+ - const snapshotWithRect = {
1296
+ - snapshot,
1297
+ - rect: snapshotEvent.args.snapshot.params?.layer_rect,
1298
+ - };
1299
+ -
1300
+ - if (!snapshotWithRect) {
1301
+ - return null;
1302
+ - }
1303
+ - const imageURLPromise = snapshotWithRect.snapshot.replay();
1304
+ - snapshotWithRect.snapshot.release();
1305
+ - const imageURL = await imageURLPromise as Platform.DevToolsPath.UrlString;
1306
+ - if (!imageURL) {
1307
+ - return null;
1308
+ - }
1309
+ - const stylesContainer = document.createElement('div');
1310
+ - const shadowRoot = stylesContainer.attachShadow({mode: 'open'});
1311
+ - shadowRoot.createChild('style').textContent = imagePreviewStyles;
1312
+ - const container = shadowRoot.createChild('div');
1313
+ - container.classList.add('image-preview-container', 'vbox', 'link');
1314
+ - const img = container.createChild('img');
1315
+ - img.src = imageURL;
1316
+ - img.alt = LegacyComponents.ImagePreview.ImagePreview.defaultAltTextForImageURL(imageURL);
1317
+ - const paintProfilerButton = container.createChild('a');
1318
+ - paintProfilerButton.textContent = i18nString(UIStrings.paintProfiler);
1319
+ - UI.ARIAUtils.markAsLink(container);
1320
+ - container.tabIndex = 0;
1321
+ - container.addEventListener('click', () => TimelinePanel.instance().select(selectionFromEvent(event)), false);
1322
+ - container.addEventListener('keydown', keyEvent => {
1323
+ - if (keyEvent.key === Platform.KeyboardUtilities.ENTER_KEY) {
1324
+ - TimelinePanel.instance().select(selectionFromEvent(event));
1325
+ - keyEvent.consume(true);
1326
+ - }
1327
+ - });
1328
+ - return stylesContainer;
1329
+ - }
1330
+ -
1331
+ static createEventDivider(event: Trace.Types.Events.Event, zeroTime: number): HTMLDivElement {
1332
+ const eventDivider = document.createElement('div');
1333
+ eventDivider.classList.add('resources-event-divider');
1334
+ const {startTime: eventStartTime} = Trace.Helpers.Timing.eventTimingsMilliSeconds(event);
1335
+
1336
+ const startTime = i18n.TimeUtilities.millisToString(eventStartTime - zeroTime);
1337
+ - UI.Tooltip.Tooltip.install(
1338
+ - eventDivider, i18nString(UIStrings.sAtS, {PH1: TimelineUIUtils.eventTitle(event), PH2: startTime}));
1339
+ const style = TimelineUIUtils.markerStyleForEvent(event);
1340
+ if (style.tall) {
1341
+ eventDivider.style.backgroundColor = style.color;
1342
+ @@ -2048,157 +813,6 @@ export class TimelineUIUtils {
77
1343
  return Trace.Styles.getCategoryStyles();
78
1344
  }
79
1345
 
@@ -150,13 +1416,59 @@ index 4fe7b92..573e0d3 100644
150
1416
  -
151
1417
  - return element;
152
1418
  - }
153
- // Generates a Summary component given a aggregated stats for categories.
154
- static generateSummaryDetails(
155
- aggregatedStats: Record<string, number>, rangeStart: number, rangeEnd: number,
156
- @@ -2174,31 +2092,6 @@ export class TimelineUIUtils {
157
- return element;
158
- }
159
-
1419
+ - // Generates a Summary component given a aggregated stats for categories.
1420
+ - static generateSummaryDetails(
1421
+ - aggregatedStats: Record<string, number>, rangeStart: number, rangeEnd: number,
1422
+ - selectedEvents: Trace.Types.Events.Event[],
1423
+ - thirdPartyTree: ThirdPartyTreeView.ThirdPartyTreeViewWidget): Element {
1424
+ - const element = document.createElement('div');
1425
+ - element.classList.add('timeline-details-range-summary', 'hbox');
1426
+ -
1427
+ - // First, the category bar chart.
1428
+ - let total = 0;
1429
+ - let categories: TimelineComponents.TimelineSummary.CategoryData[] = [];
1430
+ - // Calculate total of all categories.
1431
+ - for (const categoryName in aggregatedStats) {
1432
+ - total += aggregatedStats[categoryName];
1433
+ - }
1434
+ -
1435
+ - // Get stats values from categories.
1436
+ - for (const categoryName in Trace.Styles.getCategoryStyles()) {
1437
+ - const category = Trace.Styles.getCategoryStyles()[categoryName as keyof Trace.Styles.CategoryPalette];
1438
+ - if (category.name === Trace.Styles.EventCategory.IDLE) {
1439
+ - continue;
1440
+ - }
1441
+ - const value = aggregatedStats[category.name];
1442
+ - if (!value) {
1443
+ - continue;
1444
+ - }
1445
+ - const title = category.title;
1446
+ - const color = category.getCSSValue();
1447
+ - categories.push({value, color, title});
1448
+ - }
1449
+ -
1450
+ - // Keeps the most useful categories on top.
1451
+ - categories = categories.sort((a, b) => b.value - a.value);
1452
+ - const start = Trace.Types.Timing.Milli(rangeStart);
1453
+ - const end = Trace.Types.Timing.Milli(rangeEnd);
1454
+ - const categorySummaryTable = new TimelineComponents.TimelineSummary.CategorySummary();
1455
+ - categorySummaryTable.data = {
1456
+ - rangeStart: start,
1457
+ - rangeEnd: end,
1458
+ - total,
1459
+ - categories,
1460
+ - selectedEvents,
1461
+ - };
1462
+ - element.append(categorySummaryTable);
1463
+ - // Add the 3p datagrid
1464
+ - const treeView = new ThirdPartyTreeView.ThirdPartyTreeElement();
1465
+ - treeView.treeView = thirdPartyTree;
1466
+ - UI.ARIAUtils.setLabel(treeView, i18nString(UIStrings.thirdPartyTable));
1467
+ - element.append(treeView);
1468
+ -
1469
+ - return element;
1470
+ - }
1471
+ -
160
1472
  - static generateDetailsContentForFrame(
161
1473
  - frame: Trace.Types.Events.LegacyTimelineFrame, filmStrip: Trace.Extras.FilmStrip.Data|null,
162
1474
  - filmStripFrame: Trace.Extras.FilmStrip.Frame|null): DocumentFragment {
@@ -185,3 +1497,220 @@ index 4fe7b92..573e0d3 100644
185
1497
  static frameDuration(frame: Trace.Types.Events.LegacyTimelineFrame): Element {
186
1498
  const offsetMilli = Trace.Helpers.Timing.microToMilli(frame.startTimeOffset);
187
1499
  const durationMilli = Trace.Helpers.Timing.microToMilli(Trace.Types.Timing.Micro(frame.endTime - frame.startTime));
1500
+ @@ -2318,27 +932,6 @@ export class TimelineUIUtils {
1501
+ return Common.ParsedURL.schemeIs(url, 'about:') ? `"${Platform.StringUtilities.trimMiddle(frame.name, trimAt)}"` :
1502
+ frame.url.slice(0, trimAt);
1503
+ }
1504
+ -
1505
+ - static getOriginWithEntity(
1506
+ - entityMapper: Trace.EntityMapper.EntityMapper|null, parsedTrace: Trace.TraceModel.ParsedTrace,
1507
+ - event: Trace.Types.Events.Event): string|null {
1508
+ - const resolvedURL = SourceMapsResolver.SourceMapsResolver.resolvedURLForEntry(parsedTrace, event);
1509
+ - if (!resolvedURL) {
1510
+ - return null;
1511
+ - }
1512
+ - const parsedUrl = URL.parse(resolvedURL);
1513
+ - if (!parsedUrl) {
1514
+ - return null;
1515
+ - }
1516
+ -
1517
+ - const entity = entityMapper?.entityForEvent(event) ?? null;
1518
+ - if (!entity) {
1519
+ - return null;
1520
+ - }
1521
+ -
1522
+ - const originWithEntity = Utils.Helpers.formatOriginWithEntity(parsedUrl, entity, true);
1523
+ - return originWithEntity;
1524
+ - }
1525
+ }
1526
+
1527
+ export const aggregatedStatsKey = Symbol('aggregatedStats');
1528
+ @@ -2357,147 +950,6 @@ export class EventDispatchTypeDescriptor {
1529
+ }
1530
+ }
1531
+
1532
+ -export class TimelineDetailsContentHelper {
1533
+ - fragment: DocumentFragment;
1534
+ - #linkifier: LegacyComponents.Linkifier.Linkifier|null;
1535
+ - private target: SDK.Target.Target|null;
1536
+ - element: HTMLDivElement;
1537
+ - private tableElement: HTMLElement;
1538
+ -
1539
+ - constructor(target: SDK.Target.Target|null, linkifier: LegacyComponents.Linkifier.Linkifier|null) {
1540
+ - this.fragment = document.createDocumentFragment();
1541
+ -
1542
+ - this.#linkifier = linkifier;
1543
+ - this.target = target;
1544
+ -
1545
+ - this.element = document.createElement('div');
1546
+ - this.element.classList.add('timeline-details-view-block');
1547
+ - this.tableElement = this.element.createChild('div', 'vbox timeline-details-chip-body');
1548
+ - this.fragment.appendChild(this.element);
1549
+ - }
1550
+ -
1551
+ - addSection(title: string, swatchColor?: string, event?: Trace.Types.Events.Event): void {
1552
+ - if (!this.tableElement.hasChildNodes()) {
1553
+ - this.element.removeChildren();
1554
+ - } else {
1555
+ - this.element = document.createElement('div');
1556
+ - this.element.classList.add('timeline-details-view-block');
1557
+ - this.fragment.appendChild(this.element);
1558
+ - }
1559
+ -
1560
+ - if (title) {
1561
+ - const titleElement = this.element.createChild('div', 'timeline-details-chip-title');
1562
+ - if (swatchColor) {
1563
+ - titleElement.createChild('div').style.backgroundColor = swatchColor;
1564
+ - }
1565
+ -
1566
+ - const textChild = titleElement.createChild('span');
1567
+ - textChild.textContent = title;
1568
+ -
1569
+ - if (event) {
1570
+ - textChild.classList.add('timeline-details-chip-title-reveal-entry');
1571
+ - textChild.addEventListener('click', function() {
1572
+ - TimelinePanel.instance().zoomEvent(event);
1573
+ - });
1574
+ - }
1575
+ - }
1576
+ -
1577
+ - this.tableElement = this.element.createChild('div', 'vbox timeline-details-chip-body');
1578
+ - this.fragment.appendChild(this.element);
1579
+ - }
1580
+ -
1581
+ - linkifier(): LegacyComponents.Linkifier.Linkifier|null {
1582
+ - return this.#linkifier;
1583
+ - }
1584
+ -
1585
+ - appendTextRow(title: string, value: string|number|boolean): void {
1586
+ - const rowElement = this.tableElement.createChild('div', 'timeline-details-view-row');
1587
+ - rowElement.createChild('div', 'timeline-details-view-row-title').textContent = title;
1588
+ - rowElement.createChild('div', 'timeline-details-view-row-value').textContent = value.toString();
1589
+ - }
1590
+ -
1591
+ - appendElementRow(title: string, content: string|Node, isWarning?: boolean, isStacked?: boolean): void {
1592
+ - const rowElement = this.tableElement.createChild('div', 'timeline-details-view-row');
1593
+ - rowElement.setAttribute('data-row-title', title);
1594
+ - if (isWarning) {
1595
+ - rowElement.classList.add('timeline-details-warning');
1596
+ - }
1597
+ - if (isStacked) {
1598
+ - rowElement.classList.add('timeline-details-stack-values');
1599
+ - }
1600
+ - const titleElement = rowElement.createChild('div', 'timeline-details-view-row-title');
1601
+ - titleElement.textContent = title;
1602
+ - const valueElement = rowElement.createChild('div', 'timeline-details-view-row-value');
1603
+ - if (content instanceof Node) {
1604
+ - valueElement.appendChild(content);
1605
+ - } else {
1606
+ - UI.UIUtils.createTextChild(valueElement, content || '');
1607
+ - }
1608
+ - }
1609
+ -
1610
+ - appendLocationRow(
1611
+ - title: string, url: string, startLine: number, startColumn?: number, text?: string, omitOrigin?: boolean): void {
1612
+ - if (!this.#linkifier) {
1613
+ - return;
1614
+ - }
1615
+ -
1616
+ - const options = {
1617
+ - tabStop: true,
1618
+ - columnNumber: startColumn,
1619
+ - showColumnNumber: true,
1620
+ - inlineFrameIndex: 0,
1621
+ - text,
1622
+ - omitOrigin,
1623
+ - };
1624
+ - const link = this.#linkifier.maybeLinkifyScriptLocation(
1625
+ - this.target, null, url as Platform.DevToolsPath.UrlString, startLine, options);
1626
+ - if (!link) {
1627
+ - return;
1628
+ - }
1629
+ - this.appendElementRow(title, link);
1630
+ - }
1631
+ -
1632
+ - appendLocationRange(title: string, url: Platform.DevToolsPath.UrlString, startLine: number, endLine?: number): void {
1633
+ - if (!this.#linkifier || !this.target) {
1634
+ - return;
1635
+ - }
1636
+ - const locationContent = document.createElement('span');
1637
+ - const link = this.#linkifier.maybeLinkifyScriptLocation(
1638
+ - this.target, null, url, startLine, {tabStop: true, inlineFrameIndex: 0});
1639
+ - if (!link) {
1640
+ - return;
1641
+ - }
1642
+ - locationContent.appendChild(link);
1643
+ - UI.UIUtils.createTextChild(
1644
+ - locationContent, Platform.StringUtilities.sprintf(' [%s…%s]', startLine + 1, (endLine || 0) + 1 || ''));
1645
+ - this.appendElementRow(title, locationContent);
1646
+ - }
1647
+ -
1648
+ - createChildStackTraceElement(stackTrace: Protocol.Runtime.StackTrace): void {
1649
+ - if (!this.#linkifier) {
1650
+ - return;
1651
+ - }
1652
+ - const resolvedStackTrace: Protocol.Runtime.StackTrace = structuredClone(stackTrace);
1653
+ - let currentResolvedStackTrace: Protocol.Runtime.StackTrace|undefined = resolvedStackTrace;
1654
+ - while (currentResolvedStackTrace) {
1655
+ - currentResolvedStackTrace.callFrames = currentResolvedStackTrace.callFrames.map(
1656
+ - callFrame => ({
1657
+ - ...callFrame,
1658
+ - functionName: SourceMapsResolver.SourceMapsResolver.resolvedCodeLocationForCallFrame(callFrame)?.name ||
1659
+ - callFrame.functionName,
1660
+ - }));
1661
+ - currentResolvedStackTrace = currentResolvedStackTrace.parent;
1662
+ - }
1663
+ - const stackTraceElement =
1664
+ - this.tableElement.createChild('div', 'timeline-details-view-row timeline-details-stack-values');
1665
+ - const callFrameContents = new LegacyComponents.JSPresentationUtils.StackTracePreviewContent(
1666
+ - undefined, this.target ?? undefined, this.#linkifier,
1667
+ - {stackTrace: resolvedStackTrace, tabStops: true, showColumnNumber: true});
1668
+ - callFrameContents.markAsRoot();
1669
+ - callFrameContents.show(stackTraceElement);
1670
+ - }
1671
+ -}
1672
+ -
1673
+ export const categoryBreakdownCacheSymbol = Symbol('categoryBreakdownCache');
1674
+ export interface TimelineMarkerStyle {
1675
+ title: string;
1676
+ diff --git a/node_modules/chrome-devtools-frontend/front_end/ui/legacy/components/utils/Linkifier.ts b/node_modules/chrome-devtools-frontend/front_end/ui/legacy/components/utils/Linkifier.ts
1677
+ index 7d19eae..e073846 100644
1678
+ --- a/node_modules/chrome-devtools-frontend/front_end/ui/legacy/components/utils/Linkifier.ts
1679
+ +++ b/node_modules/chrome-devtools-frontend/front_end/ui/legacy/components/utils/Linkifier.ts
1680
+ @@ -16,7 +16,6 @@ import * as TextUtils from '../../../../models/text_utils/text_utils.js';
1681
+ import type * as Trace from '../../../../models/trace/trace.js';
1682
+ import * as Workspace from '../../../../models/workspace/workspace.js';
1683
+ import type * as IconButton from '../../../components/icon_button/icon_button.js';
1684
+ -import * as VisualLogging from '../../../visual_logging/visual_logging.js';
1685
+ import * as UI from '../../legacy.js';
1686
+
1687
+ const UIStrings = {
1688
+ @@ -601,7 +600,6 @@ export class Linkifier extends Common.ObjectWrapper.ObjectWrapper<EventTypes> im
1689
+ // @ts-expect-error
1690
+ link.href = href;
1691
+ }
1692
+ - link.setAttribute('jslog', `${VisualLogging.link(jslogContext).track({click: true})}`);
1693
+
1694
+ if (text instanceof HTMLElement) {
1695
+ link.appendChild(text);
1696
+ diff --git a/node_modules/chrome-devtools-frontend/front_end/ui/legacy/components/utils/utils.ts b/node_modules/chrome-devtools-frontend/front_end/ui/legacy/components/utils/utils.ts
1697
+ index 2f98cde..cb95b85 100644
1698
+ --- a/node_modules/chrome-devtools-frontend/front_end/ui/legacy/components/utils/utils.ts
1699
+ +++ b/node_modules/chrome-devtools-frontend/front_end/ui/legacy/components/utils/utils.ts
1700
+ @@ -2,16 +2,8 @@
1701
+ // Use of this source code is governed by a BSD-style license that can be
1702
+ // found in the LICENSE file.
1703
+
1704
+ -import * as ImagePreview from './ImagePreview.js';
1705
+ -import * as JSPresentationUtils from './JSPresentationUtils.js';
1706
+ import * as Linkifier from './Linkifier.js';
1707
+ -import * as Reload from './Reload.js';
1708
+ -import * as TargetDetachedDialog from './TargetDetachedDialog.js';
1709
+
1710
+ export {
1711
+ - ImagePreview,
1712
+ - JSPresentationUtils,
1713
+ Linkifier,
1714
+ - Reload,
1715
+ - TargetDetachedDialog,
1716
+ };