chrome-devtools-frontend 1.0.1672557 → 1.0.1675430

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 (177) hide show
  1. package/.agents/skills/devtools-ux-writing-refactor/SKILL.md +26 -9
  2. package/front_end/core/common/ParsedURL.ts +5 -1
  3. package/front_end/core/common/SettingRegistration.ts +30 -34
  4. package/front_end/core/common/Settings.ts +4 -64
  5. package/front_end/core/host/UserMetrics.ts +127 -117
  6. package/front_end/core/protocol_client/PuppeteerDevToolsConnection.ts +42 -9
  7. package/front_end/core/root/Runtime.ts +14 -0
  8. package/front_end/core/sdk/NetworkManager.ts +0 -35
  9. package/front_end/core/sdk/SourceMap.ts +1 -19
  10. package/front_end/core/sdk/SourceMapManager.ts +75 -48
  11. package/front_end/core/sdk/SourceMapScopesInfo.ts +0 -62
  12. package/front_end/core/sdk/TargetManager.ts +18 -0
  13. package/front_end/devtools_compatibility.js +1 -1
  14. package/front_end/entrypoints/main/MainImpl.ts +1 -0
  15. package/front_end/foundation/Universe.ts +44 -29
  16. package/front_end/generated/InspectorBackendCommands.ts +4 -3
  17. package/front_end/generated/SupportedCSSProperties.ts +16 -1
  18. package/front_end/generated/protocol-mapping.d.ts +8 -0
  19. package/front_end/generated/protocol-proxy-api.d.ts +6 -0
  20. package/front_end/generated/protocol.ts +16 -2
  21. package/front_end/models/ai_assistance/AiSetting.ts +66 -3
  22. package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +15 -5
  23. package/front_end/models/bindings/CompilerScriptMapping.ts +1 -1
  24. package/front_end/models/emulation/DeviceModeModel.ts +82 -102
  25. package/front_end/models/emulation/EmulatedDevices.ts +18 -66
  26. package/front_end/models/javascript_metadata/NativeFunctions.js +4 -4
  27. package/front_end/models/persistence/AutomaticFileSystemManager.ts +2 -2
  28. package/front_end/models/persistence/IsolatedFileSystemManager.ts +20 -29
  29. package/front_end/models/trace/ModelImpl.ts +5 -0
  30. package/front_end/models/trace/Processor.ts +5 -0
  31. package/front_end/models/trace/handlers/LayoutShiftsHandler.ts +7 -1
  32. package/front_end/models/trace/handlers/MetaHandler.ts +8 -4
  33. package/front_end/models/trace/handlers/PageLoadMetricsHandler.ts +11 -0
  34. package/front_end/models/workspace/FileManager.ts +13 -6
  35. package/front_end/panels/ai_assistance/AiAssistancePanel.ts +11 -10
  36. package/front_end/panels/ai_assistance/ai_assistance-meta.ts +3 -45
  37. package/front_end/panels/application/BackgroundServiceView.ts +42 -40
  38. package/front_end/panels/application/KeyValueStorageItemsView.ts +1 -0
  39. package/front_end/panels/application/WebMCPView.ts +13 -5
  40. package/front_end/panels/application/components/AdsView.ts +24 -1
  41. package/front_end/panels/application/components/adsView.css +27 -21
  42. package/front_end/panels/autofill/AutofillView.ts +12 -12
  43. package/front_end/panels/autofill/autofill-meta.ts +2 -2
  44. package/front_end/panels/common/ExtensionServer.ts +7 -1
  45. package/front_end/panels/common/common.ts +0 -1
  46. package/front_end/panels/console/ConsoleInsightTeaser.ts +7 -6
  47. package/front_end/panels/console/ConsoleViewMessage.ts +1 -1
  48. package/front_end/panels/elements/ClassesPaneWidget.ts +2 -2
  49. package/front_end/panels/elements/ElementsTreeElement.ts +602 -327
  50. package/front_end/panels/elements/ElementsTreeOutline.ts +1 -1
  51. package/front_end/panels/elements/StylesSidebarPane.ts +1 -1
  52. package/front_end/panels/elements/components/AdornerManager.ts +1 -0
  53. package/front_end/panels/emulation/AdvancedApp.ts +3 -3
  54. package/front_end/panels/emulation/DeviceModeToolbar.ts +2 -11
  55. package/front_end/panels/emulation/DeviceModeView.ts +234 -75
  56. package/front_end/panels/emulation/InspectedPagePlaceholder.ts +1 -1
  57. package/front_end/panels/emulation/deviceModeView.css +4 -21
  58. package/front_end/panels/emulation/emulation-meta.ts +4 -30
  59. package/front_end/panels/emulation/emulation.ts +0 -3
  60. package/front_end/panels/explain/components/ConsoleInsight.ts +11 -7
  61. package/front_end/panels/js_timeline/js_timeline-meta.ts +8 -8
  62. package/front_end/panels/layer_viewer/LayerDetailsView.ts +30 -30
  63. package/front_end/panels/layer_viewer/LayerTreeOutline.ts +6 -6
  64. package/front_end/panels/layer_viewer/LayerViewHost.ts +1 -1
  65. package/front_end/panels/layer_viewer/Layers3DView.ts +11 -11
  66. package/front_end/panels/layer_viewer/PaintProfilerView.ts +8 -8
  67. package/front_end/panels/layer_viewer/TransformController.ts +3 -3
  68. package/front_end/panels/layer_viewer/layer_viewer-meta.ts +11 -11
  69. package/front_end/panels/layers/LayersPanel.ts +2 -2
  70. package/front_end/panels/layers/layers-meta.ts +2 -2
  71. package/front_end/panels/lighthouse/LighthouseController.ts +3 -7
  72. package/front_end/panels/mobile_throttling/CPUThrottlingSelector.ts +313 -0
  73. package/front_end/panels/mobile_throttling/NetworkPanelIndicator.ts +0 -10
  74. package/front_end/panels/mobile_throttling/NetworkThrottlingSelector.ts +21 -10
  75. package/front_end/panels/mobile_throttling/ThrottlingManager.ts +1 -58
  76. package/front_end/panels/mobile_throttling/mobile_throttling.ts +2 -9
  77. package/front_end/panels/network/NetworkConfigView.ts +1 -71
  78. package/front_end/panels/network/networkConfigView.css +1 -2
  79. package/front_end/panels/profiler/HeapDetachedElementsDataGrid.ts +3 -3
  80. package/front_end/panels/profiler/HeapDetachedElementsView.ts +5 -5
  81. package/front_end/panels/profiler/HeapProfileView.ts +32 -32
  82. package/front_end/panels/profiler/HeapProfilerPanel.ts +2 -2
  83. package/front_end/panels/profiler/HeapSnapshotDataGrids.ts +33 -37
  84. package/front_end/panels/profiler/HeapSnapshotGridNodes.ts +26 -27
  85. package/front_end/panels/profiler/HeapSnapshotView.ts +48 -48
  86. package/front_end/panels/profiler/IsolateSelector.ts +10 -10
  87. package/front_end/panels/profiler/ModuleUIStrings.ts +25 -25
  88. package/front_end/panels/profiler/ProfileLauncherView.ts +6 -6
  89. package/front_end/panels/profiler/ProfilesPanel.ts +6 -6
  90. package/front_end/panels/profiler/WritableProfileHeader.ts +6 -6
  91. package/front_end/panels/profiler/profiler-meta.ts +7 -7
  92. package/front_end/panels/protocol_monitor/ProtocolMonitor.ts +7 -0
  93. package/front_end/panels/recorder/RecorderPanel.ts +1 -1
  94. package/front_end/panels/settings/AISettingsTab.ts +27 -23
  95. package/front_end/panels/settings/emulation/DevicesSettingsTab.ts +1 -2
  96. package/front_end/panels/timeline/TimelineFlameChartNetworkDataProvider.ts +12 -17
  97. package/front_end/panels/timeline/TimelinePanel.ts +20 -35
  98. package/front_end/panels/timeline/components/LiveMetricsView.ts +27 -6
  99. package/front_end/panels/timeline/components/NetworkTrackWidget.ts +1 -1
  100. package/front_end/panels/timeline/components/components.ts +0 -4
  101. package/front_end/panels/timeline/components/liveMetricsView.css +7 -0
  102. package/front_end/third_party/chromium/README.chromium +1 -1
  103. package/front_end/third_party/source-map-scopes-codec/package/CONTRIBUTING.md +0 -0
  104. package/front_end/third_party/source-map-scopes-codec/package/LICENSE +0 -0
  105. package/front_end/third_party/source-map-scopes-codec/package/README.md +0 -0
  106. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/builder/builder.d.ts +0 -0
  107. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/builder/builder.d.ts.map +1 -1
  108. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/builder/safe_builder.d.ts +0 -0
  109. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/builder/safe_builder.d.ts.map +0 -0
  110. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/decode/decode.d.ts +0 -0
  111. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/decode/decode.d.ts.map +0 -0
  112. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/encode/encode.d.ts +0 -0
  113. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/encode/encode.d.ts.map +0 -0
  114. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/mod.d.ts +0 -0
  115. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/mod.d.ts.map +0 -0
  116. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/scopes.d.ts +0 -0
  117. package/front_end/third_party/source-map-scopes-codec/package/_dist/src/scopes.d.ts.map +0 -0
  118. package/front_end/third_party/source-map-scopes-codec/package/deno.json +1 -1
  119. package/front_end/third_party/source-map-scopes-codec/package/package.json +1 -1
  120. package/front_end/third_party/source-map-scopes-codec/package/src/builder/builder.js +2 -0
  121. package/front_end/third_party/source-map-scopes-codec/package/src/builder/builder.js.map +1 -1
  122. package/front_end/third_party/source-map-scopes-codec/package/src/builder/builder.ts +2 -0
  123. package/front_end/third_party/source-map-scopes-codec/package/src/builder/safe_builder.js +0 -0
  124. package/front_end/third_party/source-map-scopes-codec/package/src/builder/safe_builder.js.map +0 -0
  125. package/front_end/third_party/source-map-scopes-codec/package/src/builder/safe_builder.ts +0 -0
  126. package/front_end/third_party/source-map-scopes-codec/package/src/codec.js +0 -0
  127. package/front_end/third_party/source-map-scopes-codec/package/src/codec.js.map +0 -0
  128. package/front_end/third_party/source-map-scopes-codec/package/src/codec.ts +0 -0
  129. package/front_end/third_party/source-map-scopes-codec/package/src/decode/decode.js +0 -0
  130. package/front_end/third_party/source-map-scopes-codec/package/src/decode/decode.js.map +0 -0
  131. package/front_end/third_party/source-map-scopes-codec/package/src/decode/decode.ts +0 -0
  132. package/front_end/third_party/source-map-scopes-codec/package/src/encode/encode.js +0 -0
  133. package/front_end/third_party/source-map-scopes-codec/package/src/encode/encode.js.map +0 -0
  134. package/front_end/third_party/source-map-scopes-codec/package/src/encode/encode.ts +0 -0
  135. package/front_end/third_party/source-map-scopes-codec/package/src/encode/encoder.js +0 -0
  136. package/front_end/third_party/source-map-scopes-codec/package/src/encode/encoder.js.map +0 -0
  137. package/front_end/third_party/source-map-scopes-codec/package/src/encode/encoder.ts +0 -0
  138. package/front_end/third_party/source-map-scopes-codec/package/src/mod.js +0 -0
  139. package/front_end/third_party/source-map-scopes-codec/package/src/mod.js.map +0 -0
  140. package/front_end/third_party/source-map-scopes-codec/package/src/mod.ts +0 -0
  141. package/front_end/third_party/source-map-scopes-codec/package/src/scopes.js +0 -0
  142. package/front_end/third_party/source-map-scopes-codec/package/src/scopes.js.map +0 -0
  143. package/front_end/third_party/source-map-scopes-codec/package/src/scopes.ts +0 -0
  144. package/front_end/third_party/source-map-scopes-codec/package/src/util.js +0 -0
  145. package/front_end/third_party/source-map-scopes-codec/package/src/util.js.map +0 -0
  146. package/front_end/third_party/source-map-scopes-codec/package/src/util.ts +0 -0
  147. package/front_end/third_party/source-map-scopes-codec/package/src/vlq.js +0 -0
  148. package/front_end/third_party/source-map-scopes-codec/package/src/vlq.js.map +0 -0
  149. package/front_end/third_party/source-map-scopes-codec/package/src/vlq.ts +0 -0
  150. package/front_end/ui/comments/CommentAnchorResolver.ts +132 -0
  151. package/front_end/ui/comments/comments.ts +9 -0
  152. package/front_end/ui/components/dialogs/ShortcutDialog.ts +2 -0
  153. package/front_end/ui/components/settings/SettingCheckbox.ts +4 -12
  154. package/front_end/ui/components/settings/settingCheckbox.css +0 -7
  155. package/front_end/ui/legacy/Treeoutline.ts +14 -14
  156. package/front_end/ui/legacy/UIUtils.ts +2 -47
  157. package/front_end/ui/legacy/Widget.ts +10 -2
  158. package/front_end/ui/legacy/components/data_grid/DataGridElement.ts +40 -0
  159. package/front_end/ui/legacy/components/settings_ui/SettingsUI.ts +1 -1
  160. package/front_end/ui/legacy/components/utils/Linkifier.ts +1 -0
  161. package/front_end/ui/lit/Directives.ts +80 -0
  162. package/front_end/ui/lit/lit.ts +1 -0
  163. package/front_end/ui/lit/render.ts +8 -0
  164. package/front_end/ui/settings/SettingUIRegistration.ts +4 -0
  165. package/front_end/ui/visual_logging/Debugging.ts +1 -5
  166. package/front_end/ui/visual_logging/KnownContextValues.ts +3 -0
  167. package/front_end/ui/visual_logging/LoggingConfig.ts +21 -0
  168. package/front_end/ui/visual_logging/visual_logging.ts +9 -0
  169. package/mcp/mcp.ts +1 -0
  170. package/package.json +1 -1
  171. package/front_end/panels/common/ThrottlingUtils.ts +0 -51
  172. package/front_end/panels/emulation/DeviceModeWrapper.ts +0 -248
  173. package/front_end/panels/mobile_throttling/MobileThrottlingSelector.ts +0 -92
  174. package/front_end/panels/timeline/components/CPUThrottlingSelector.ts +0 -235
  175. package/front_end/panels/timeline/components/NetworkThrottlingSelector.ts +0 -245
  176. package/front_end/panels/timeline/components/cpuThrottlingSelector.css +0 -30
  177. package/front_end/panels/timeline/components/networkThrottlingSelector.css +0 -24
@@ -5,11 +5,14 @@
5
5
 
6
6
  import * as Lit from '../../third_party/lit/lit.js';
7
7
 
8
+ import {InterceptBindingDirective} from './Directives.js';
9
+
8
10
  export interface RenderOptions extends Lit.RenderOptions {
9
11
  container?: {
10
12
  attributes?: Record<string, string|null|boolean|undefined|{toString(): string}>,
11
13
  classes?: string[],
12
14
  listeners?: Record<string, EventListenerOrEventListenerObject>,
15
+ interceptedListeners?: Record<string, EventListenerOrEventListenerObject>,
13
16
  };
14
17
  }
15
18
 
@@ -112,6 +115,11 @@ export function render(template: unknown, container: HTMLElement|DocumentFragmen
112
115
  listenersMap.delete(name);
113
116
  }
114
117
  }
118
+
119
+ if (host instanceof Element) {
120
+ InterceptBindingDirective.registerListeners(host, options?.container?.interceptedListeners);
121
+ }
122
+
115
123
  renderOptions.set(container, options);
116
124
  return Lit.render(template, container, options);
117
125
  }
@@ -51,6 +51,7 @@ export function register(
51
51
  if (registeredSettings.has(settingName)) {
52
52
  throw new Error(`Duplicate setting name '${settingName}'`);
53
53
  }
54
+ Common.SettingRegistration.registerCategoryOrder(settingUIDescriptor.category, settingUIDescriptor.order);
54
55
  registeredSettings.set(settingName, {descriptor: settingDescriptor, uiDescriptor: settingUIDescriptor});
55
56
  }
56
57
 
@@ -98,5 +99,8 @@ export function resolve(settingDescriptor: Common.Settings.SettingDescriptor<unk
98
99
  }
99
100
 
100
101
  export function resetSettings(): void {
102
+ for (const {uiDescriptor} of registeredSettings.values()) {
103
+ Common.SettingRegistration.removeCategoryOrder(uiDescriptor.category, uiDescriptor.order);
104
+ }
101
105
  registeredSettings.clear();
102
106
  }
@@ -6,7 +6,7 @@
6
6
  import {assertNotNullOrUndefined} from '../../core/platform/platform.js';
7
7
 
8
8
  import type {Loggable} from './Loggable.js';
9
- import {type LoggingConfig, VisualElements} from './LoggingConfig.js';
9
+ import {elementKey, type LoggingConfig, VisualElements} from './LoggingConfig.js';
10
10
  import {getLoggingState, type LoggingState} from './LoggingState.js';
11
11
 
12
12
  let veDebuggingEnabled = false;
@@ -406,10 +406,6 @@ function processImpressionsForAdHocAnalysisDebugLog(states: LoggingState[]): voi
406
406
  }
407
407
  }
408
408
 
409
- function elementKey(config: LoggingConfig): string {
410
- return `${VisualElements[config.ve]}${config.context ? `: ${config.context}` : ''}`;
411
- }
412
-
413
409
  export function debugString(config: LoggingConfig): string {
414
410
  const components = [VisualElements[config.ve]];
415
411
  if (config.context) {
@@ -2126,6 +2126,7 @@ export const knownContextValues = new Set([
2126
2126
  'integer-8-bit',
2127
2127
  'interactions',
2128
2128
  'interactivity',
2129
+ 'interest',
2129
2130
  'interest-delay',
2130
2131
  'interest-delay-end',
2131
2132
  'interest-delay-start',
@@ -3237,6 +3238,7 @@ export const knownContextValues = new Set([
3237
3238
  'protocol',
3238
3239
  'protocol-handlers',
3239
3240
  'protocol-monitor',
3241
+ 'protocol-monitor-columns',
3240
3242
  'protocol-monitor-documentation',
3241
3243
  'protocol-monitor.add-custom-property',
3242
3244
  'protocol-monitor.add-parameter',
@@ -4052,6 +4054,7 @@ export const knownContextValues = new Set([
4052
4054
  'text-combine-upright',
4053
4055
  'text-decoration',
4054
4056
  'text-decoration-color',
4057
+ 'text-decoration-inset',
4055
4058
  'text-decoration-line',
4056
4059
  'text-decoration-skip-ink',
4057
4060
  'text-decoration-skip-spaces',
@@ -27,6 +27,27 @@ export interface LoggingConfig {
27
27
  parent?: string;
28
28
  }
29
29
 
30
+ export function elementKey(config: LoggingConfig): string {
31
+ return `${VisualElements[config.ve]}${config.context ? `: ${config.context}` : ''}`;
32
+ }
33
+
34
+ export function getVePath(element: Element): string {
35
+ const parts: string[] = [];
36
+ let current: Element|null = element;
37
+ while (current) {
38
+ if (needsLogging(current)) {
39
+ try {
40
+ const config = getLoggingConfig(current);
41
+ parts.unshift(elementKey(config));
42
+ } catch {
43
+ // Skip invalid logging configs
44
+ }
45
+ }
46
+ current = current.parentElementOrShadowHost();
47
+ }
48
+ return parts.join(' > ');
49
+ }
50
+
30
51
  export function needsLogging(element: Element): boolean {
31
52
  return element.hasAttribute(LOGGING_ATTRIBUTE);
32
53
  }
@@ -11,6 +11,15 @@ import * as NonDomState from './NonDomState.js';
11
11
 
12
12
  export type Loggable = LoggableModule.Loggable;
13
13
  export {DebugLoggingFormat, setVeDebuggingEnabled, setVeDebugLoggingEnabled} from './Debugging.js';
14
+ export {
15
+ elementKey,
16
+ getLoggingConfig,
17
+ getVePath,
18
+ type LoggingConfig,
19
+ needsLogging,
20
+ parseJsLog,
21
+ VisualElements,
22
+ } from './LoggingConfig.js';
14
23
  export {addDocument, startLogging, stopLogging} from './LoggingDriver.js';
15
24
  export {logImpressions, logSettingAccess, logFunctionCall} from './LoggingEvents.js';
16
25
  export const logClick = (loggable: Loggable, event: Event, options: {doubleClick?: boolean} = {}): void =>
package/mcp/mcp.ts CHANGED
@@ -26,6 +26,7 @@ export {PuppeteerDevToolsConnection} from '../front_end/core/protocol_client/Pup
26
26
  export {DebuggerModel} from '../front_end/core/sdk/DebuggerModel.js';
27
27
  export * as NetworkManager from '../front_end/core/sdk/NetworkManager.js';
28
28
  export {RuntimeModel} from '../front_end/core/sdk/RuntimeModel.js';
29
+ export * as SourceMapManager from '../front_end/core/sdk/SourceMapManager.js';
29
30
  export {Target} from '../front_end/core/sdk/Target.js';
30
31
  export {TargetManager} from '../front_end/core/sdk/TargetManager.js';
31
32
  export * as Foundation from '../front_end/foundation/foundation.js';
package/package.json CHANGED
@@ -92,5 +92,5 @@
92
92
  "webidl2": "24.5.0",
93
93
  "yargs": "17.7.2"
94
94
  },
95
- "version": "1.0.1672557"
95
+ "version": "1.0.1675430"
96
96
  }
@@ -1,51 +0,0 @@
1
- // Copyright 2026 The Chromium Authors
2
- // Use of this source code is governed by a BSD-style license that can be
3
- // found in the LICENSE file.
4
-
5
- import * as SDK from '../../core/sdk/sdk.js';
6
- import * as CrUXManager from '../../models/crux-manager/crux-manager.js';
7
-
8
- import {
9
- CalibratedMidTierMobileThrottlingOption,
10
- type CPUThrottlingOption,
11
- MidTierThrottlingOption,
12
- } from './CPUThrottlingOption.js';
13
-
14
- export interface ThrottlingRecommendations {
15
- cpuOption: CPUThrottlingOption|null;
16
- networkConditions: SDK.NetworkManager.Conditions|null;
17
- }
18
-
19
- /**
20
- * Computes the recommended CPU and network throttling presets based on CrUX
21
- * field metric data.
22
- */
23
- export function getThrottlingRecommendations(): ThrottlingRecommendations {
24
- const cruxManager = CrUXManager.CrUXManager.instance();
25
- const roundTripTimeMetricData = cruxManager.getSelectedFieldMetricData('round_trip_time');
26
-
27
- let cpuOption: CPUThrottlingOption = CalibratedMidTierMobileThrottlingOption;
28
- if (cpuOption.rate() === 0) {
29
- cpuOption = MidTierThrottlingOption;
30
- }
31
-
32
- const networkConditions = getRecommendedNetworkConditions(roundTripTimeMetricData);
33
-
34
- return {
35
- cpuOption,
36
- networkConditions,
37
- };
38
- }
39
-
40
- /**
41
- * Computes the recommended network throttling preset based on CrUX RTT field
42
- * metric data. Returns null if no RTT data is available or no preset matches.
43
- */
44
- export function getRecommendedNetworkConditions(roundTripTimeMetricData?: CrUXManager.MetricResponse):
45
- SDK.NetworkManager.Conditions|null {
46
- if (roundTripTimeMetricData?.percentiles) {
47
- const rtt = Number(roundTripTimeMetricData.percentiles.p75);
48
- return SDK.NetworkManager.getRecommendedNetworkPreset(rtt);
49
- }
50
- return null;
51
- }
@@ -1,248 +0,0 @@
1
- // Copyright 2016 The Chromium Authors
2
- // Use of this source code is governed by a BSD-style license that can be
3
- // found in the LICENSE file.
4
-
5
- import type * as Common from '../../core/common/common.js';
6
- import * as Root from '../../core/root/root.js';
7
- import * as SDK from '../../core/sdk/sdk.js';
8
- import type * as Protocol from '../../generated/protocol.js';
9
- import * as EmulationModel from '../../models/emulation/emulation.js';
10
- import * as Geometry from '../../models/geometry/geometry.js';
11
- import * as UI from '../../ui/legacy/legacy.js';
12
- import {html, render} from '../../ui/lit/lit.js';
13
-
14
- import {DeviceModeView} from './DeviceModeView.js';
15
- import {InspectedPagePlaceholder} from './InspectedPagePlaceholder.js';
16
-
17
- const {widget} = UI.Widget;
18
- interface ViewInput {
19
- showDeviceMode: boolean;
20
- }
21
- type View = (input: ViewInput, output: undefined, target: HTMLElement) => void;
22
- export const DEFAULT_VIEW: View = (input, output, target) => {
23
- // clang-format off
24
- render(input.showDeviceMode ?
25
- html`<devtools-widget ${widget(DeviceModeView)}>
26
- ${widget(() => InspectedPagePlaceholder.instance(), {minimumSize: new Geometry.Size(1, 1)})}
27
- </devtools-widget>` :
28
- widget(() => InspectedPagePlaceholder.instance(), {minimumSize: new Geometry.Size(150, 150)}),
29
- target);
30
- // clang-format on
31
- };
32
-
33
- export class DeviceModeWrapper extends UI.Widget.VBox {
34
- private readonly toggleDeviceModeAction: UI.ActionRegistration.Action;
35
- private showDeviceModeSetting: Common.Settings.Setting<boolean>;
36
- readonly #view: View;
37
-
38
- constructor(element?: HTMLElement, view = DEFAULT_VIEW) {
39
- super(element);
40
- this.#view = view;
41
- this.toggleDeviceModeAction = UI.ActionRegistry.ActionRegistry.instance().getAction('emulation.toggle-device-mode');
42
- const model = EmulationModel.DeviceModeModel.DeviceModeModel.instance();
43
- this.showDeviceModeSetting = model.enabledSetting();
44
- this.showDeviceModeSetting.setRequiresUserAction(Boolean(Root.Runtime.Runtime.queryParam('hasOtherClients')));
45
- this.showDeviceModeSetting.addChangeListener(this.requestUpdate.bind(this));
46
- SDK.TargetManager.TargetManager.instance().addModelListener(SDK.OverlayModel.OverlayModel,
47
- SDK.OverlayModel.Events.SCREENSHOT_REQUESTED,
48
- this.screenshotRequestedFromOverlay, this);
49
- this.requestUpdate();
50
- }
51
-
52
- static #setNonEmulatedAvailableSize(): void {
53
- const model = EmulationModel.DeviceModeModel.DeviceModeModel.instance();
54
- if (model.type() !== EmulationModel.DeviceModeModel.Type.None) {
55
- return;
56
- }
57
-
58
- const zoomFactor = UI.ZoomManager.ZoomManager.instance().zoomFactor();
59
- const rect = InspectedPagePlaceholder.instance().element.getBoundingClientRect();
60
- const availableSize =
61
- new Geometry.Size(Math.max(rect.width * zoomFactor, 1), Math.max(rect.height * zoomFactor, 1));
62
- model.setAvailableSize(availableSize, availableSize);
63
- }
64
-
65
- static captureScreenshot(fullSize?: boolean, clip?: Protocol.Page.Viewport): boolean {
66
- const model = EmulationModel.DeviceModeModel.DeviceModeModel.instance();
67
-
68
- this.#setNonEmulatedAvailableSize();
69
- if (fullSize) {
70
- void model.captureFullSizeScreenshot();
71
- } else if (clip) {
72
- void model.captureAreaScreenshot(clip);
73
- } else {
74
- void model.captureScreenshot();
75
- }
76
- return true;
77
- }
78
-
79
- private screenshotRequestedFromOverlay(event: Common.EventTarget.EventTargetEvent<Protocol.Page.Viewport>): void {
80
- const clip = event.data;
81
- DeviceModeWrapper.captureScreenshot(false, clip);
82
- }
83
-
84
- override performUpdate(): void {
85
- this.toggleDeviceModeAction.setToggled(this.showDeviceModeSetting.get());
86
-
87
- this.#view({showDeviceMode: this.showDeviceModeSetting.get()}, undefined, this.contentElement);
88
- }
89
- }
90
-
91
- export class ActionDelegate implements UI.ActionRegistration.ActionDelegate {
92
- handleAction(context: UI.Context.Context, actionId: string): boolean {
93
- switch (actionId) {
94
- case 'emulation.capture-screenshot':
95
- return DeviceModeWrapper.captureScreenshot();
96
-
97
- case 'emulation.capture-node-screenshot': {
98
- const node = context.flavor(SDK.DOMModel.DOMNode);
99
- if (!node) {
100
- return true;
101
- }
102
- async function captureClip(): Promise<void> {
103
- if (!node) {
104
- return;
105
- }
106
-
107
- // Resolve to a remote object to ensure the node is alive in the context.
108
- const object = await node.resolveToObject();
109
- if (!object) {
110
- return;
111
- }
112
-
113
- // Get the Box Model via CDP.
114
- // This returns the quads relative to the target's viewport.
115
- // We use the 'border' quad to include the border and padding in the screenshot,
116
- // matching the 'width' and 'height' properties which are also Border Box dimensions.
117
- const nodeBoxModel = await node.boxModel();
118
- if (!nodeBoxModel) {
119
- throw new Error(`Unable to get box model of the node: ${new Error().stack}`);
120
- }
121
- const nodeBorderQuad = nodeBoxModel.border;
122
- // Calculate the rendered bounding box from the border quad to account for CSS scaling and transforms (e.g. zoom or transform: scale).
123
- const {minX, maxX, minY, maxY} = getQuadBoundingBox(nodeBorderQuad);
124
-
125
- // Get Layout Metrics to account for the Visual Viewport scroll and zoom.
126
- const metrics = await node.domModel().target().pageAgent().invoke_getLayoutMetrics();
127
- if (metrics.getError()) {
128
- throw new Error(`Unable to get metrics: ${new Error().stack}`);
129
- }
130
-
131
- const scrollX = metrics.cssVisualViewport.pageX;
132
- const scrollY = metrics.cssVisualViewport.pageY;
133
-
134
- // Calculate the global offset for OOPiFs (Out-of-Process iframes).
135
- // This accounts for the position of the target's frame within the main page.
136
- const {x: oopifOffsetX, y: oopifOffsetY} = await getOopifOffset(node.domModel().target());
137
-
138
- // Assemble the final Clip.
139
- // The absolute coordinates are: Global (OOPiF) + Viewport Scroll + Local Node Position (Border Box).
140
- const clip = {
141
- x: oopifOffsetX + scrollX + minX,
142
- y: oopifOffsetY + scrollY + minY,
143
- width: maxX - minX,
144
- height: maxY - minY,
145
- scale: 1,
146
- };
147
-
148
- // Apply Zoom factor.
149
- const zoom = metrics.cssVisualViewport.zoom ?? 1;
150
- clip.x *= zoom;
151
- clip.y *= zoom;
152
- clip.width *= zoom;
153
- clip.height *= zoom;
154
- DeviceModeWrapper.captureScreenshot(false, clip);
155
- }
156
- void captureClip();
157
- return true;
158
- }
159
-
160
- case 'emulation.capture-full-height-screenshot':
161
- return DeviceModeWrapper.captureScreenshot(true);
162
-
163
- case 'emulation.toggle-device-mode': {
164
- const model = EmulationModel.DeviceModeModel.DeviceModeModel.instance();
165
- model.toggleDeviceMode();
166
- return true;
167
- }
168
- }
169
- return false;
170
- }
171
- }
172
-
173
- /**
174
- * Calculate the offset of the "Local Root" frame relative to the "Global Root" (the main frame).
175
- * This involves traversing the CDP Targets for OOPiFs.
176
- */
177
- async function getOopifOffset(target: SDK.Target.Target|null): Promise<{x: number, y: number}> {
178
- if (!target) {
179
- return {x: 0, y: 0};
180
- }
181
-
182
- // Get the parent target. If there's no parent (we are at root) or it's not a frame, we are done.
183
- const parentTarget = target.parentTarget();
184
- if (!parentTarget || parentTarget.type() !== SDK.Target.Type.FRAME) {
185
- return {x: 0, y: 0};
186
- }
187
-
188
- // Identify the current frame's ID to find its owner in the parent.
189
- const frameId = target.model(SDK.ResourceTreeModel.ResourceTreeModel)?.mainFrame?.id;
190
- if (!frameId) {
191
- return {x: 0, y: 0};
192
- }
193
-
194
- // Get the DOMModel of the parent to query the frame owner element.
195
- const parentDOMModel = parentTarget.model(SDK.DOMModel.DOMModel);
196
- if (!parentDOMModel) {
197
- return {x: 0, y: 0};
198
- }
199
-
200
- // Retrieve the frame owner node (e.g. the <iframe> element) in the parent's document.
201
- const frameOwnerDeferred = await parentDOMModel.getOwnerNodeForFrame(frameId);
202
- const frameOwner = await frameOwnerDeferred?.resolvePromise();
203
- if (!frameOwner) {
204
- return {x: 0, y: 0};
205
- }
206
-
207
- // Get the content box of the iframe element.
208
- // This is relative to the parent target's viewport.
209
- const boxModel = await frameOwner.boxModel();
210
- if (!boxModel) {
211
- return {x: 0, y: 0};
212
- }
213
-
214
- // content is a Quad [x1, y1, x2, y2, x3, y3, x4, y4]
215
- const contentQuad = boxModel.content;
216
- const iframeContentX = contentQuad[0];
217
- const iframeContentY = contentQuad[1];
218
-
219
- // Get the scroll position of the parent target to convert viewport-relative coordinates
220
- // to document-relative coordinates.
221
- const parentMetrics = await parentTarget.pageAgent().invoke_getLayoutMetrics();
222
- if (parentMetrics.getError()) {
223
- return {x: 0, y: 0};
224
- }
225
-
226
- const scrollX = parentMetrics.cssVisualViewport.pageX;
227
- const scrollY = parentMetrics.cssVisualViewport.pageY;
228
-
229
- // Recursively add the offset of the parent target itself (if it is also an OOPiF).
230
- const parentOffset = await getOopifOffset(parentTarget);
231
-
232
- return {
233
- x: iframeContentX + scrollX + parentOffset.x,
234
- y: iframeContentY + scrollY + parentOffset.y,
235
- };
236
- }
237
-
238
- /**
239
- * Calculate the axis-aligned bounding box for a Quad [x1, y1, x2, y2, x3, y3, x4, y4].
240
- * This accounts for CSS scaling and transforms (e.g. zoom, transform: scale).
241
- */
242
- function getQuadBoundingBox(quad: Protocol.DOM.Quad): {minX: number, maxX: number, minY: number, maxY: number} {
243
- const minX = Math.min(quad[0], quad[2], quad[4], quad[6]);
244
- const maxX = Math.max(quad[0], quad[2], quad[4], quad[6]);
245
- const minY = Math.min(quad[1], quad[3], quad[5], quad[7]);
246
- const maxY = Math.max(quad[1], quad[3], quad[5], quad[7]);
247
- return {minX, maxX, minY, maxY};
248
- }
@@ -1,92 +0,0 @@
1
- // Copyright 2017 The Chromium Authors
2
- // Use of this source code is governed by a BSD-style license that can be
3
- // found in the LICENSE file.
4
-
5
- import * as i18n from '../../core/i18n/i18n.js';
6
- import * as SDK from '../../core/sdk/sdk.js';
7
-
8
- import {throttlingManager} from './ThrottlingManager.js';
9
- import {
10
- ThrottlingPresets,
11
- type Conditions,
12
- type ConditionsList,
13
- type MobileThrottlingConditionsGroup,
14
- } from './ThrottlingPresets.js';
15
-
16
- const UIStrings = {
17
- /**
18
- * @description Mobile throttling is disabled. The user can select this option to run mobile
19
- * emulation at a normal speed instead of throttled.
20
- */
21
- disabled: 'Disabled',
22
- /**
23
- * @description Title for a group of pre-decided configuration options for mobile throttling. These
24
- * are useful default options that users might want.
25
- */
26
- presets: 'Presets',
27
- /**
28
- * @description Title for a group of advanced configuration options for mobile throttling, which
29
- * might not be applicable to every user or situation.
30
- */
31
- advanced: 'Advanced',
32
- } as const;
33
- const str_ = i18n.i18n.registerUIStrings('panels/mobile_throttling/MobileThrottlingSelector.ts', UIStrings);
34
- const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
35
-
36
- export class MobileThrottlingSelector {
37
- private readonly populateCallback: (arg0: MobileThrottlingConditionsGroup[]) => ConditionsList;
38
- private readonly selectCallback: (arg0: number) => void;
39
- private readonly options: ConditionsList;
40
-
41
- constructor(
42
- populateCallback: (arg0: MobileThrottlingConditionsGroup[]) => ConditionsList,
43
- selectCallback: (arg0: number) => void) {
44
- this.populateCallback = populateCallback;
45
- this.selectCallback = selectCallback;
46
- SDK.CPUThrottlingManager.CPUThrottlingManager.instance().addEventListener(
47
- SDK.CPUThrottlingManager.Events.RATE_CHANGED, this.conditionsChanged, this);
48
- SDK.NetworkManager.MultitargetNetworkManager.instance().addEventListener(
49
- SDK.NetworkManager.MultitargetNetworkManager.Events.CONDITIONS_CHANGED, this.conditionsChanged, this);
50
- this.options = this.populateOptions();
51
- this.conditionsChanged();
52
- }
53
-
54
- optionSelected(conditions: Conditions): void {
55
- SDK.NetworkManager.MultitargetNetworkManager.instance().setNetworkConditions(conditions.network);
56
- throttlingManager().setCPUThrottlingOption(conditions.cpuThrottlingOption);
57
- }
58
-
59
- private populateOptions(): ConditionsList {
60
- const disabledGroup = {
61
- title: i18nString(UIStrings.disabled),
62
- items: [ThrottlingPresets.getNoThrottlingConditions()],
63
- };
64
- const presetsGroup = {title: i18nString(UIStrings.presets), items: ThrottlingPresets.getMobilePresets()};
65
- const advancedGroup = {title: i18nString(UIStrings.advanced), items: ThrottlingPresets.getAdvancedMobilePresets()};
66
- return this.populateCallback([disabledGroup, presetsGroup, advancedGroup]);
67
- }
68
-
69
- private conditionsChanged(): void {
70
- this.populateOptions();
71
-
72
- const networkConditions = SDK.NetworkManager.MultitargetNetworkManager.instance().networkConditions();
73
- const cpuThrottlingOption = throttlingManager().cpuThrottlingOption();
74
- for (let index = 0; index < this.options.length; ++index) {
75
- const option = this.options[index];
76
- if (option && 'network' in option && option.network === networkConditions &&
77
- option.cpuThrottlingOption === cpuThrottlingOption) {
78
- this.selectCallback(index);
79
- return;
80
- }
81
- }
82
-
83
- const customConditions = ThrottlingPresets.getCustomConditions();
84
- for (let index = 0; index < this.options.length; ++index) {
85
- const item = this.options[index];
86
- if (item && item.title === customConditions.title && item.description === customConditions.description) {
87
- this.selectCallback(index);
88
- return;
89
- }
90
- }
91
- }
92
- }