chrome-devtools-frontend 1.0.969345 → 1.0.970539
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.
- package/config/gni/devtools_grd_files.gni +64 -0
- package/front_end/core/common/ParsedURL.ts +25 -2
- package/front_end/core/i18n/locales/en-US.json +18 -3
- package/front_end/core/i18n/locales/en-XL.json +18 -3
- package/front_end/core/sdk/ChildTargetManager.ts +2 -2
- package/front_end/core/sdk/Connections.ts +6 -1
- package/front_end/core/sdk/DebuggerModel.ts +4 -0
- package/front_end/core/sdk/NetworkManager.ts +4 -3
- package/front_end/entrypoints/lighthouse_worker/LighthouseService.ts +84 -13
- package/front_end/models/persistence/Automapping.ts +2 -32
- package/front_end/models/persistence/FileSystemWorkspaceBinding.ts +9 -7
- package/front_end/models/persistence/IsolatedFileSystem.ts +20 -14
- package/front_end/models/persistence/NetworkPersistenceManager.ts +213 -45
- package/front_end/models/persistence/PlatformFileSystem.ts +3 -2
- package/front_end/models/timeline_model/TimelineFrameModel.ts +21 -7
- package/front_end/models/workspace/UISourceCode.ts +11 -14
- package/front_end/models/workspace/WorkspaceImpl.ts +5 -1
- package/front_end/panels/animation/animationTimeline.css +0 -3
- package/front_end/panels/application/components/ReportsGrid.ts +19 -4
- package/front_end/panels/application/components/trustTokensViewDeleteButton.css +0 -1
- package/front_end/panels/console/consolePinPane.css +0 -17
- package/front_end/panels/css_overview/cssOverviewCompletedView.css +0 -1
- package/front_end/panels/elements/components/adornerSettingsPane.css +0 -1
- package/front_end/panels/elements/components/computedStyleTrace.css +1 -1
- package/front_end/panels/elements/components/elementsBreadcrumbs.css +0 -1
- package/front_end/panels/elements/computedStyleWidgetTree.css +2 -2
- package/front_end/panels/elements/elementsTreeOutline.css +0 -2
- package/front_end/panels/emulation/deviceModeView.css +0 -1
- package/front_end/panels/event_listeners/eventListenersView.css +0 -1
- package/front_end/panels/issues/components/hideIssuesMenu.css +0 -1
- package/front_end/panels/lighthouse/LighthouseController.ts +25 -1
- package/front_end/panels/lighthouse/LighthouseProtocolService.ts +37 -5
- package/front_end/panels/lighthouse/LighthouseStartView.ts +1 -0
- package/front_end/panels/lighthouse/LighthouseStatusView.ts +5 -5
- package/front_end/panels/media/playerListView.css +0 -1
- package/front_end/panels/network/networkLogView.css +0 -4
- package/front_end/panels/network/requestPayloadTree.css +0 -2
- package/front_end/panels/network/signedExchangeInfoTree.css +0 -1
- package/front_end/panels/settings/emulation/components/userAgentClientHintsForm.css +0 -4
- package/front_end/panels/settings/emulation/devicesSettingsTab.css +0 -1
- package/front_end/panels/snippets/ScriptSnippetFileSystem.ts +4 -4
- package/front_end/panels/snippets/SnippetsQuickOpen.ts +1 -1
- package/front_end/panels/sources/TabbedEditorContainer.ts +9 -0
- package/front_end/panels/sources/watchExpressionsSidebarPane.css +0 -1
- package/front_end/panels/timeline/TimelineFlameChartDataProvider.ts +75 -3
- package/front_end/panels/webauthn/webauthnPane.css +0 -12
- package/front_end/services/puppeteer/PuppeteerConnection.ts +107 -0
- package/front_end/services/puppeteer/puppeteer.ts +9 -0
- package/front_end/third_party/codemirror/package/addon/fold/foldgutter.css +1 -5
- package/front_end/ui/components/adorners/adorner.css +0 -4
- package/front_end/ui/components/buttons/button.css +0 -4
- package/front_end/ui/components/data_grid/dataGrid.css +0 -4
- package/front_end/ui/components/icon_button/iconButton.css +0 -1
- package/front_end/ui/components/markdown_view/MarkdownLinksMap.ts +2 -2
- package/front_end/ui/legacy/TabbedPane.ts +1 -1
- package/front_end/ui/legacy/tabbedPane.css +0 -4
- package/front_end/ui/legacy/textButton.css +0 -1
- package/front_end/ui/legacy/toolbar.css +0 -1
- package/package.json +2 -2
- package/scripts/hosted_mode/server.js +5 -0
@@ -338,7 +338,6 @@ text.animation-timeline-grid-label {
|
|
338
338
|
background: var(--color-background-elevation-2);
|
339
339
|
opacity: 0%;
|
340
340
|
border-right: 1px solid var(--color-details-hairline);
|
341
|
-
cursor: pointer;
|
342
341
|
}
|
343
342
|
|
344
343
|
.animation-buffer-preview:focus-visible {
|
@@ -410,7 +409,6 @@ text.animation-timeline-grid-label {
|
|
410
409
|
background-color: transparent;
|
411
410
|
flex: 1 0 auto;
|
412
411
|
text-align: center;
|
413
|
-
cursor: pointer;
|
414
412
|
}
|
415
413
|
|
416
414
|
.animation-playback-rate-button:first-child {
|
@@ -454,7 +452,6 @@ text.animation-timeline-grid-label {
|
|
454
452
|
box-shadow: 0 1px 4px 0 var(--color-background-highlight);
|
455
453
|
z-index: 100;
|
456
454
|
display: none;
|
457
|
-
cursor: pointer;
|
458
455
|
font-weight: 700;
|
459
456
|
color: var(--color-background);
|
460
457
|
}
|
@@ -19,6 +19,21 @@ const UIStrings = {
|
|
19
19
|
*(https://developers.google.com/web/updates/2018/09/reportingapi#sending)
|
20
20
|
*/
|
21
21
|
noReportsToDisplay: 'No reports to display',
|
22
|
+
/**
|
23
|
+
*@description Column header for a table displaying Reporting API reports.
|
24
|
+
*Status is one of 'Queued', 'Pending', 'MarkedForRemoval' or 'Success'.
|
25
|
+
*/
|
26
|
+
status: 'Status',
|
27
|
+
/**
|
28
|
+
*@description Column header for a table displaying Reporting API reports.
|
29
|
+
*Destination is the name of the endpoint the report is being sent to.
|
30
|
+
*/
|
31
|
+
destination: 'Destination',
|
32
|
+
/**
|
33
|
+
*@description Column header for a table displaying Reporting API reports.
|
34
|
+
*The column contains the timestamp of when a report was generated.
|
35
|
+
*/
|
36
|
+
generatedAt: 'Generated at',
|
22
37
|
};
|
23
38
|
const str_ = i18n.i18n.registerUIStrings('panels/application/components/ReportsGrid.ts', UIStrings);
|
24
39
|
export const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
|
@@ -38,7 +53,7 @@ export class ReportsGridStatusHeader extends HTMLElement {
|
|
38
53
|
// Disabled until https://crbug.com/1079231 is fixed.
|
39
54
|
// clang-format off
|
40
55
|
render(html`
|
41
|
-
${
|
56
|
+
${i18nString(UIStrings.status)}
|
42
57
|
<x-link href="https://web.dev/reporting-api/#report-status">
|
43
58
|
<${IconButton.Icon.Icon.litTagName} class="inline-icon" .data=${{
|
44
59
|
iconName: 'help_outline',
|
@@ -93,7 +108,7 @@ export class ReportsGrid extends HTMLElement {
|
|
93
108
|
},
|
94
109
|
{
|
95
110
|
id: 'status',
|
96
|
-
title:
|
111
|
+
title: i18nString(UIStrings.status),
|
97
112
|
widthWeighting: 20,
|
98
113
|
hideable: false,
|
99
114
|
visible: true,
|
@@ -103,14 +118,14 @@ export class ReportsGrid extends HTMLElement {
|
|
103
118
|
},
|
104
119
|
{
|
105
120
|
id: 'destination',
|
106
|
-
title:
|
121
|
+
title: i18nString(UIStrings.destination),
|
107
122
|
widthWeighting: 20,
|
108
123
|
hideable: false,
|
109
124
|
visible: true,
|
110
125
|
},
|
111
126
|
{
|
112
127
|
id: 'timestamp',
|
113
|
-
title:
|
128
|
+
title: i18nString(UIStrings.generatedAt),
|
114
129
|
widthWeighting: 20,
|
115
130
|
hideable: false,
|
116
131
|
visible: true,
|
@@ -71,23 +71,6 @@
|
|
71
71
|
overflow: hidden;
|
72
72
|
}
|
73
73
|
|
74
|
-
.console-delete-pin {
|
75
|
-
position: absolute;
|
76
|
-
top: 8px;
|
77
|
-
left: 8px;
|
78
|
-
opacity: 70%;
|
79
|
-
cursor: pointer;
|
80
|
-
}
|
81
|
-
|
82
|
-
.console-delete-pin:hover,
|
83
|
-
.console-delete-pin:focus-visible {
|
84
|
-
opacity: 100%;
|
85
|
-
}
|
86
|
-
|
87
|
-
:host-context(.-theme-with-dark-background) .console-delete-pin {
|
88
|
-
filter: brightness(2);
|
89
|
-
}
|
90
|
-
|
91
74
|
.console-pin-name:focus-within {
|
92
75
|
background: var(--color-background);
|
93
76
|
box-shadow: var(--legacy-focus-ring-active-shadow) inset;
|
@@ -15,7 +15,7 @@
|
|
15
15
|
|
16
16
|
.tree-outline li:hover {
|
17
17
|
background-color: var(--legacy-focus-bg-color);
|
18
|
-
cursor:
|
18
|
+
cursor: text;
|
19
19
|
}
|
20
20
|
|
21
21
|
.tree-outline li::before {
|
@@ -35,7 +35,7 @@
|
|
35
35
|
margin: 1px 0 0;
|
36
36
|
padding: 1em 0;
|
37
37
|
width: 100%;
|
38
|
-
cursor:
|
38
|
+
cursor: text;
|
39
39
|
color: var(--color-text-secondary);
|
40
40
|
font-size: 11px;
|
41
41
|
font-weight: 400;
|
@@ -203,7 +203,6 @@ select {
|
|
203
203
|
border-radius: 5px;
|
204
204
|
border: 1px solid var(--issue-color-yellow);
|
205
205
|
background-color: var(--issue-color-yellow);
|
206
|
-
cursor: pointer;
|
207
206
|
}
|
208
207
|
|
209
208
|
.elements-gutter-decoration.elements-has-decorated-children {
|
@@ -278,7 +277,6 @@ select {
|
|
278
277
|
position: absolute;
|
279
278
|
top: 0;
|
280
279
|
left: 0;
|
281
|
-
cursor: pointer;
|
282
280
|
width: 15px;
|
283
281
|
height: 15px;
|
284
282
|
}
|
@@ -125,6 +125,14 @@ const UIStrings = {
|
|
125
125
|
*@description Text of checkbox to reset storage features prior to running audits in Lighthouse
|
126
126
|
*/
|
127
127
|
clearStorage: 'Clear storage',
|
128
|
+
/**
|
129
|
+
* @description Text of checkbox to use the legacy Lighthouse navigation mode
|
130
|
+
*/
|
131
|
+
legacyNavigation: 'Legacy navigation',
|
132
|
+
/**
|
133
|
+
* @description Tooltip text that appears when hovering over the 'Legacy navigation' checkbox in the settings pane opened by clicking the setting cog in the start view of the audits panel
|
134
|
+
*/
|
135
|
+
useLegacyNavigation: 'Audit the page using classic Lighthouse when in navigation mode.',
|
128
136
|
/**
|
129
137
|
* @description Tooltip text of checkbox to reset storage features prior to running audits in
|
130
138
|
* Lighthouse. Resetting the storage clears/empties it to a neutral state.
|
@@ -277,7 +285,11 @@ export class LighthouseController extends Common.ObjectWrapper.ObjectWrapper<Eve
|
|
277
285
|
return navigationEntry.url;
|
278
286
|
}
|
279
287
|
|
280
|
-
getFlags(): {
|
288
|
+
getFlags(): {
|
289
|
+
internalDisableDeviceScreenEmulation: boolean,
|
290
|
+
emulatedFormFactor: (string|undefined),
|
291
|
+
legacyNavigation: boolean,
|
292
|
+
} {
|
281
293
|
const flags = {
|
282
294
|
// DevTools handles all the emulation. This tells Lighthouse to not bother with emulation.
|
283
295
|
internalDisableDeviceScreenEmulation: true,
|
@@ -288,6 +300,7 @@ export class LighthouseController extends Common.ObjectWrapper.ObjectWrapper<Eve
|
|
288
300
|
return flags as {
|
289
301
|
internalDisableDeviceScreenEmulation: boolean,
|
290
302
|
emulatedFormFactor: (string | undefined),
|
303
|
+
legacyNavigation: boolean,
|
291
304
|
};
|
292
305
|
}
|
293
306
|
|
@@ -433,6 +446,17 @@ export const RuntimeSettings: RuntimeSetting[] = [
|
|
433
446
|
options: undefined,
|
434
447
|
learnMore: undefined,
|
435
448
|
},
|
449
|
+
{
|
450
|
+
setting: Common.Settings.Settings.instance().createSetting(
|
451
|
+
'lighthouse.legacy_navigation', true, Common.Settings.SettingStorageType.Synced),
|
452
|
+
title: i18nLazyString(UIStrings.legacyNavigation),
|
453
|
+
description: i18nLazyString(UIStrings.useLegacyNavigation),
|
454
|
+
setFlags: (flags: Flags, value: string|boolean): void => {
|
455
|
+
flags.legacyNavigation = value;
|
456
|
+
},
|
457
|
+
options: undefined,
|
458
|
+
learnMore: undefined,
|
459
|
+
},
|
436
460
|
];
|
437
461
|
|
438
462
|
// TODO(crbug.com/1167717): Make this a const enum again
|
@@ -11,6 +11,11 @@ import type * as ReportRenderer from './LighthouseReporterTypes.js';
|
|
11
11
|
let lastId = 1;
|
12
12
|
|
13
13
|
export class ProtocolService {
|
14
|
+
private targetInfo?: {
|
15
|
+
mainSessionId: string,
|
16
|
+
mainTargetId: string,
|
17
|
+
mainFrameId: string,
|
18
|
+
};
|
14
19
|
private rawConnection?: ProtocolClient.InspectorBackend.Connection;
|
15
20
|
private lighthouseWorkerPromise?: Promise<Worker>;
|
16
21
|
private lighthouseMessageUpdateCallback?: ((arg0: string) => void);
|
@@ -19,26 +24,53 @@ export class ProtocolService {
|
|
19
24
|
await SDK.TargetManager.TargetManager.instance().suspendAllTargets();
|
20
25
|
const mainTarget = SDK.TargetManager.TargetManager.instance().mainTarget();
|
21
26
|
if (!mainTarget) {
|
22
|
-
throw new Error('Unable to find main target required for
|
27
|
+
throw new Error('Unable to find main target required for Lighthouse');
|
23
28
|
}
|
24
29
|
const childTargetManager = mainTarget.model(SDK.ChildTargetManager.ChildTargetManager);
|
25
30
|
if (!childTargetManager) {
|
26
|
-
throw new Error('Unable to find child target manager required for
|
31
|
+
throw new Error('Unable to find child target manager required for Lighthouse');
|
27
32
|
}
|
28
|
-
|
33
|
+
const resourceTreeModel = mainTarget.model(SDK.ResourceTreeModel.ResourceTreeModel);
|
34
|
+
if (!resourceTreeModel) {
|
35
|
+
throw new Error('Unable to find resource tree model required for Lighthouse');
|
36
|
+
}
|
37
|
+
const mainFrame = resourceTreeModel.mainFrame;
|
38
|
+
if (!mainFrame) {
|
39
|
+
throw new Error('Unable to find main frame required for Lighthouse');
|
40
|
+
}
|
41
|
+
|
42
|
+
const {connection, sessionId} = await childTargetManager.createParallelConnection(message => {
|
29
43
|
if (typeof message === 'string') {
|
30
44
|
message = JSON.parse(message);
|
31
45
|
}
|
32
46
|
this.dispatchProtocolMessage(message);
|
33
47
|
});
|
48
|
+
|
49
|
+
this.rawConnection = connection;
|
50
|
+
this.targetInfo = {
|
51
|
+
mainTargetId: await childTargetManager.getParentTargetId(),
|
52
|
+
mainFrameId: mainFrame.id,
|
53
|
+
mainSessionId: sessionId,
|
54
|
+
};
|
34
55
|
}
|
35
56
|
|
36
57
|
getLocales(): readonly string[] {
|
37
58
|
return [i18n.DevToolsLocale.DevToolsLocale.instance().locale];
|
38
59
|
}
|
39
60
|
|
40
|
-
startLighthouse(auditURL: string, categoryIDs: string[], flags: Object):
|
41
|
-
|
61
|
+
async startLighthouse(auditURL: string, categoryIDs: string[], flags: Record<string, Object|undefined>):
|
62
|
+
Promise<ReportRenderer.RunnerResult> {
|
63
|
+
if (!this.targetInfo) {
|
64
|
+
throw new Error('Unable to get target info required for Lighthouse');
|
65
|
+
}
|
66
|
+
const mode = flags.legacyNavigation ? 'start' : 'navigate';
|
67
|
+
return this.sendWithResponse(mode, {
|
68
|
+
url: auditURL,
|
69
|
+
categoryIDs,
|
70
|
+
flags,
|
71
|
+
locales: this.getLocales(),
|
72
|
+
target: this.targetInfo,
|
73
|
+
});
|
42
74
|
}
|
43
75
|
|
44
76
|
async detach(): Promise<void> {
|
@@ -113,6 +113,7 @@ export class StartView extends UI.Widget.Widget {
|
|
113
113
|
}
|
114
114
|
|
115
115
|
private render(): void {
|
116
|
+
this.populateRuntimeSettingAsToolbarCheckbox('lighthouse.legacy_navigation', this.settingsToolbarInternal);
|
116
117
|
this.populateRuntimeSettingAsToolbarCheckbox('lighthouse.clear_storage', this.settingsToolbarInternal);
|
117
118
|
this.populateRuntimeSettingAsToolbarCheckbox('lighthouse.throttling', this.settingsToolbarInternal);
|
118
119
|
|
@@ -321,7 +321,7 @@ export class StatusView {
|
|
321
321
|
}
|
322
322
|
|
323
323
|
private getPhaseForMessage(message: string): StatusPhase|null {
|
324
|
-
return StatusPhases.find(phase =>
|
324
|
+
return StatusPhases.find(phase => phase.statusMessageRegex.test(message)) || null;
|
325
325
|
}
|
326
326
|
|
327
327
|
private resetProgressBarClasses(): void {
|
@@ -457,7 +457,7 @@ export interface StatusPhase {
|
|
457
457
|
id: string;
|
458
458
|
progressBarClass: string;
|
459
459
|
message: () => Common.UIString.LocalizedString;
|
460
|
-
|
460
|
+
statusMessageRegex: RegExp;
|
461
461
|
}
|
462
462
|
|
463
463
|
export const StatusPhases: StatusPhase[] = [
|
@@ -465,19 +465,19 @@ export const StatusPhases: StatusPhase[] = [
|
|
465
465
|
id: 'loading',
|
466
466
|
progressBarClass: 'loading',
|
467
467
|
message: i18nLazyString(UIStrings.lighthouseIsLoadingThePage),
|
468
|
-
|
468
|
+
statusMessageRegex: /^(Loading page|Navigating to)/,
|
469
469
|
},
|
470
470
|
{
|
471
471
|
id: 'gathering',
|
472
472
|
progressBarClass: 'gathering',
|
473
473
|
message: i18nLazyString(UIStrings.lighthouseIsGatheringInformation),
|
474
|
-
|
474
|
+
statusMessageRegex: /^(Gathering|Computing artifact)/,
|
475
475
|
},
|
476
476
|
{
|
477
477
|
id: 'auditing',
|
478
478
|
progressBarClass: 'auditing',
|
479
479
|
message: i18nLazyString(UIStrings.almostThereLighthouseIsNow),
|
480
|
-
|
480
|
+
statusMessageRegex: /^Auditing/,
|
481
481
|
},
|
482
482
|
];
|
483
483
|
|
@@ -71,7 +71,6 @@
|
|
71
71
|
|
72
72
|
.tree-outline li .header-toggle:hover {
|
73
73
|
color: var(--color-text-secondary);
|
74
|
-
cursor: pointer;
|
75
74
|
}
|
76
75
|
|
77
76
|
.tree-outline .payload-name {
|
@@ -105,7 +104,6 @@
|
|
105
104
|
display: inline-block;
|
106
105
|
font-size: 12px;
|
107
106
|
font-family: sans-serif;
|
108
|
-
cursor: pointer;
|
109
107
|
margin: 0 4px;
|
110
108
|
padding: 2px 4px;
|
111
109
|
}
|
@@ -28,12 +28,12 @@ const UIStrings = {
|
|
28
28
|
const str_ = i18n.i18n.registerUIStrings('panels/snippets/ScriptSnippetFileSystem.ts', UIStrings);
|
29
29
|
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
|
30
30
|
|
31
|
-
function escapeSnippetName(name: string):
|
32
|
-
return
|
31
|
+
function escapeSnippetName(name: string): Platform.DevToolsPath.EncodedPathString {
|
32
|
+
return Common.ParsedURL.ParsedURL.rawPathToEncodedPathString(name as Platform.DevToolsPath.RawPathString);
|
33
33
|
}
|
34
34
|
|
35
35
|
function unescapeSnippetName(name: string): string {
|
36
|
-
return
|
36
|
+
return Common.ParsedURL.ParsedURL.encodedPathToRawPathString(name as Platform.DevToolsPath.EncodedPathString);
|
37
37
|
}
|
38
38
|
|
39
39
|
export class SnippetFileSystem extends Persistence.PlatformFileSystem.PlatformFileSystem {
|
@@ -47,7 +47,7 @@ export class SnippetFileSystem extends Persistence.PlatformFileSystem.PlatformFi
|
|
47
47
|
this.snippetsSetting = Common.Settings.Settings.instance().createSetting('scriptSnippets', []);
|
48
48
|
}
|
49
49
|
|
50
|
-
initialFilePaths():
|
50
|
+
initialFilePaths(): Platform.DevToolsPath.EncodedPathString[] {
|
51
51
|
const savedSnippets: Snippet[] = this.snippetsSetting.get();
|
52
52
|
return savedSnippets.map(snippet => escapeSnippetName(snippet.name));
|
53
53
|
}
|
@@ -77,7 +77,7 @@ export class SnippetsQuickOpen extends QuickOpen.FilteredListWidget.Provider {
|
|
77
77
|
}
|
78
78
|
|
79
79
|
renderItem(itemIndex: number, query: string, titleElement: Element, _subtitleElement: Element): void {
|
80
|
-
titleElement.textContent =
|
80
|
+
titleElement.textContent = this.snippets[itemIndex].name();
|
81
81
|
titleElement.classList.add('monospace');
|
82
82
|
QuickOpen.FilteredListWidget.FilteredListWidget.highlightRanges(titleElement, query, true);
|
83
83
|
}
|
@@ -584,6 +584,15 @@ export class TabbedEditorContainer extends Common.ObjectWrapper.ObjectWrapper<Ev
|
|
584
584
|
const uiSourceCode = event.data;
|
585
585
|
this.updateFileTitle(uiSourceCode);
|
586
586
|
this.updateHistory();
|
587
|
+
|
588
|
+
// Remove from map under old url if it has changed.
|
589
|
+
for (const [k, v] of this.uriToUISourceCode) {
|
590
|
+
if (v === uiSourceCode && k !== v.url()) {
|
591
|
+
this.uriToUISourceCode.delete(k);
|
592
|
+
}
|
593
|
+
}
|
594
|
+
// Ensure it is mapped under current url.
|
595
|
+
this.canonicalUISourceCode(uiSourceCode);
|
587
596
|
}
|
588
597
|
|
589
598
|
private uiSourceCodeWorkingCopyChanged(
|
@@ -144,6 +144,10 @@ const UIStrings = {
|
|
144
144
|
*/
|
145
145
|
droppedFrame: 'Dropped Frame',
|
146
146
|
/**
|
147
|
+
*@description Text in Timeline Frame Chart Data Provider of the Performance panel
|
148
|
+
*/
|
149
|
+
partiallyPresentedFrame: 'Partially Presented Frame',
|
150
|
+
/**
|
147
151
|
*@description Text for a rendering frame
|
148
152
|
*/
|
149
153
|
frame: 'Frame',
|
@@ -164,6 +168,8 @@ const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
|
|
164
168
|
export class TimelineFlameChartDataProvider extends Common.ObjectWrapper.ObjectWrapper<EventTypes> implements
|
165
169
|
PerfUI.FlameChart.FlameChartDataProvider {
|
166
170
|
private readonly font: string;
|
171
|
+
private droppedFramePatternCanvas: HTMLCanvasElement;
|
172
|
+
private partialFramePatternCanvas: HTMLCanvasElement;
|
167
173
|
private timelineDataInternal: PerfUI.FlameChart.TimelineData|null;
|
168
174
|
private currentLevel: number;
|
169
175
|
private performanceModel: PerformanceModel|null;
|
@@ -206,6 +212,9 @@ export class TimelineFlameChartDataProvider extends Common.ObjectWrapper.ObjectW
|
|
206
212
|
super();
|
207
213
|
this.reset();
|
208
214
|
this.font = '11px ' + Host.Platform.fontFamily();
|
215
|
+
this.droppedFramePatternCanvas = document.createElement('canvas');
|
216
|
+
this.partialFramePatternCanvas = document.createElement('canvas');
|
217
|
+
this.preparePatternCanvas();
|
209
218
|
this.timelineDataInternal = null;
|
210
219
|
this.currentLevel = 0;
|
211
220
|
this.performanceModel = null;
|
@@ -1002,7 +1011,11 @@ export class TimelineFlameChartDataProvider extends Common.ObjectWrapper.ObjectW
|
|
1002
1011
|
if (frame.idle) {
|
1003
1012
|
title = i18nString(UIStrings.idleFrame);
|
1004
1013
|
} else if (frame.dropped) {
|
1005
|
-
|
1014
|
+
if (frame.isPartial) {
|
1015
|
+
title = i18nString(UIStrings.partiallyPresentedFrame);
|
1016
|
+
} else {
|
1017
|
+
title = i18nString(UIStrings.droppedFrame);
|
1018
|
+
}
|
1006
1019
|
nameSpanTimelineInfoTime = 'timeline-info-warning';
|
1007
1020
|
} else {
|
1008
1021
|
title = i18nString(UIStrings.frame);
|
@@ -1093,6 +1106,42 @@ export class TimelineFlameChartDataProvider extends Common.ObjectWrapper.ObjectW
|
|
1093
1106
|
return key ? `hsl(${Platform.StringUtilities.hashCode(key) % 300 + 30}, 40%, 70%)` : '#ccc';
|
1094
1107
|
}
|
1095
1108
|
|
1109
|
+
private preparePatternCanvas(): void {
|
1110
|
+
// Set the candy stripe pattern to 17px so it repeats well.
|
1111
|
+
const size = 17;
|
1112
|
+
this.droppedFramePatternCanvas.width = size;
|
1113
|
+
this.droppedFramePatternCanvas.height = size;
|
1114
|
+
|
1115
|
+
this.partialFramePatternCanvas.width = size;
|
1116
|
+
this.partialFramePatternCanvas.height = size;
|
1117
|
+
|
1118
|
+
const ctx = this.droppedFramePatternCanvas.getContext('2d');
|
1119
|
+
if (ctx) {
|
1120
|
+
// Make a dense solid-line pattern.
|
1121
|
+
ctx.translate(size * 0.5, size * 0.5);
|
1122
|
+
ctx.rotate(Math.PI * 0.25);
|
1123
|
+
ctx.translate(-size * 0.5, -size * 0.5);
|
1124
|
+
|
1125
|
+
ctx.fillStyle = 'rgb(255, 255, 255)';
|
1126
|
+
for (let x = -size; x < size * 2; x += 3) {
|
1127
|
+
ctx.fillRect(x, -size, 1, size * 3);
|
1128
|
+
}
|
1129
|
+
}
|
1130
|
+
|
1131
|
+
const ctx2 = this.partialFramePatternCanvas.getContext('2d');
|
1132
|
+
if (ctx2) {
|
1133
|
+
// Make a sparse dashed-line pattern.
|
1134
|
+
ctx2.strokeStyle = 'rgb(255, 255, 255)';
|
1135
|
+
ctx2.lineWidth = 2;
|
1136
|
+
ctx2.beginPath();
|
1137
|
+
ctx2.moveTo(17, 0);
|
1138
|
+
ctx2.lineTo(10, 7);
|
1139
|
+
ctx2.moveTo(8, 9);
|
1140
|
+
ctx2.lineTo(2, 15);
|
1141
|
+
ctx2.stroke();
|
1142
|
+
}
|
1143
|
+
}
|
1144
|
+
|
1096
1145
|
private drawFrame(
|
1097
1146
|
entryIndex: number, context: CanvasRenderingContext2D, text: string|null, barX: number, barY: number,
|
1098
1147
|
barWidth: number, barHeight: number): void {
|
@@ -1100,8 +1149,31 @@ export class TimelineFlameChartDataProvider extends Common.ObjectWrapper.ObjectW
|
|
1100
1149
|
const frame = (this.entryData[entryIndex] as TimelineModel.TimelineFrameModel.TimelineFrame);
|
1101
1150
|
barX += hPadding;
|
1102
1151
|
barWidth -= 2 * hPadding;
|
1103
|
-
|
1104
|
-
|
1152
|
+
if (frame.idle) {
|
1153
|
+
context.fillStyle = 'white';
|
1154
|
+
} else if (frame.dropped) {
|
1155
|
+
if (frame.isPartial) {
|
1156
|
+
// For partially presented frame boxes, paint a yellow background with
|
1157
|
+
// a sparse white dashed-line pattern overlay.
|
1158
|
+
context.fillStyle = '#f0e442';
|
1159
|
+
context.fillRect(barX, barY, barWidth, barHeight);
|
1160
|
+
|
1161
|
+
const overlay = context.createPattern(this.partialFramePatternCanvas, 'repeat');
|
1162
|
+
context.fillStyle = overlay || context.fillStyle;
|
1163
|
+
} else {
|
1164
|
+
// For dropped frame boxes, paint a red background with a dense white
|
1165
|
+
// solid-line pattern overlay.
|
1166
|
+
context.fillStyle = '#f08080';
|
1167
|
+
context.fillRect(barX, barY, barWidth, barHeight);
|
1168
|
+
|
1169
|
+
const overlay = context.createPattern(this.droppedFramePatternCanvas, 'repeat');
|
1170
|
+
context.fillStyle = overlay || context.fillStyle;
|
1171
|
+
}
|
1172
|
+
} else if (frame.hasWarnings()) {
|
1173
|
+
context.fillStyle = '#fad1d1';
|
1174
|
+
} else {
|
1175
|
+
context.fillStyle = '#d7f0d1';
|
1176
|
+
}
|
1105
1177
|
context.fillRect(barX, barY, barWidth, barHeight);
|
1106
1178
|
|
1107
1179
|
const frameDurationText = i18n.TimeUtilities.preciseMillisToString(frame.duration, 1);
|
@@ -120,18 +120,6 @@
|
|
120
120
|
padding: 5px 10px 0 0;
|
121
121
|
}
|
122
122
|
|
123
|
-
.text-button {
|
124
|
-
float: right;
|
125
|
-
white-space: nowrap;
|
126
|
-
overflow: hidden;
|
127
|
-
min-width: 28px;
|
128
|
-
background: transparent;
|
129
|
-
border: none;
|
130
|
-
color: var(--color-link);
|
131
|
-
text-decoration: underline;
|
132
|
-
cursor: pointer;
|
133
|
-
}
|
134
|
-
|
135
123
|
td .text-button {
|
136
124
|
min-width: 20px;
|
137
125
|
margin: auto;
|