Skip to content

Commit

Permalink
Add brick breaker game to performance panel
Browse files Browse the repository at this point in the history
Bug: none
Change-Id: I2a931e9013738e1d1f5d439ff5b1d999174b2694
Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/5279587
Reviewed-by: Victor Porof <victorporof@chromium.org>
Commit-Queue: Andres Olivares <andoli@chromium.org>
  • Loading branch information
AlinaVarkki authored and Devtools-frontend LUCI CQ committed Feb 12, 2024
1 parent 969250e commit 7a45cff
Show file tree
Hide file tree
Showing 9 changed files with 840 additions and 3 deletions.
1 change: 1 addition & 0 deletions config/gni/devtools_grd_files.gni
Expand Up @@ -2074,6 +2074,7 @@ grd_files_debug_sources = [
"front_end/ui/legacy/components/object_ui/objectPopover.css.js",
"front_end/ui/legacy/components/object_ui/objectPropertiesSection.css.js",
"front_end/ui/legacy/components/object_ui/objectValue.css.js",
"front_end/ui/legacy/components/perf_ui/BrickBreaker.js",
"front_end/ui/legacy/components/perf_ui/ChartViewport.js",
"front_end/ui/legacy/components/perf_ui/FilmStripView.js",
"front_end/ui/legacy/components/perf_ui/FlameChart.js",
Expand Down
33 changes: 32 additions & 1 deletion front_end/panels/timeline/TimelineFlameChartView.ts
Expand Up @@ -58,6 +58,7 @@ export class TimelineFlameChartView extends UI.Widget.VBox implements PerfUI.Fla
private readonly networkPane: UI.Widget.VBox;
private readonly splitResizer: HTMLElement;
private readonly chartSplitWidget: UI.SplitWidget.SplitWidget;
private brickGame?: PerfUI.BrickBreaker.BrickBreaker;
private readonly countersView: CountersGraph;
private readonly detailsSplitWidget: UI.SplitWidget.SplitWidget;
private readonly detailsView: TimelineDetailsView;
Expand All @@ -75,9 +76,12 @@ export class TimelineFlameChartView extends UI.Widget.VBox implements PerfUI.Fla
#traceEngineData: TraceEngine.Handlers.Types.TraceParseData|null;
#selectedGroupName: string|null = null;
#onTraceBoundsChangeBound = this.#onTraceBoundsChange.bind(this);
#gameKeyMatches = 0;
#gameTimeout = setTimeout(() => ({}), 0);
constructor(delegate: TimelineModeViewDelegate) {
super();
this.element.classList.add('timeline-flamechart');

this.delegate = delegate;
this.model = null;
this.eventListeners = [];
Expand Down Expand Up @@ -141,7 +145,7 @@ export class TimelineFlameChartView extends UI.Widget.VBox implements PerfUI.Fla
this.networkFlameChart.addEventListener(PerfUI.FlameChart.Events.EntrySelected, this.onNetworkEntrySelected, this);
this.networkFlameChart.addEventListener(PerfUI.FlameChart.Events.EntryInvoked, this.onNetworkEntrySelected, this);
this.mainFlameChart.addEventListener(PerfUI.FlameChart.Events.EntryHighlighted, this.onEntryHighlighted, this);

this.element.addEventListener('keydown', this.#keydownHandler.bind(this));
this.boundRefresh = this.#reset.bind(this);
this.#selectedEvents = null;

Expand All @@ -154,6 +158,33 @@ export class TimelineFlameChartView extends UI.Widget.VBox implements PerfUI.Fla
TraceBounds.TraceBounds.onChange(this.#onTraceBoundsChangeBound);
}

#keydownHandler(event: KeyboardEvent): void {
const keyCombo = 'fixme';
if (event.key === keyCombo[this.#gameKeyMatches]) {
this.#gameKeyMatches++;
clearTimeout(this.#gameTimeout);
this.#gameTimeout = setTimeout(() => {
this.#gameKeyMatches = 0;
}, 2000);
} else {
this.#gameKeyMatches = 0;
clearTimeout(this.#gameTimeout);
}
if (this.#gameKeyMatches !== keyCombo.length) {
return;
}
this.fixMe();
}

fixMe(): void {
if ([...this.element.childNodes].find(child => child instanceof PerfUI.BrickBreaker.BrickBreaker)) {
return;
}
this.brickGame = new PerfUI.BrickBreaker.BrickBreaker(this.mainFlameChart);
this.brickGame.classList.add('brick-game');
this.element.append(this.brickGame);
}

#onTraceBoundsChange(event: TraceBounds.TraceBounds.StateChangedEvent): void {
if (event.updateType === 'MINIMAP_BOUNDS') {
// If the update type was a changing of the minimap bounds, we do not
Expand Down
56 changes: 54 additions & 2 deletions front_end/panels/timeline/TimelinePanel.ts
Expand Up @@ -44,6 +44,7 @@ import type * as TimelineModel from '../../models/timeline_model/timeline_model.
import * as TraceEngine from '../../models/trace/trace.js';
import * as Workspace from '../../models/workspace/workspace.js';
import * as TraceBounds from '../../services/trace_bounds/trace_bounds.js';
import * as Adorners from '../../ui/components/adorners/adorners.js';
import * as PanelFeedback from '../../ui/components/panel_feedback/panel_feedback.js';
import * as PerfUI from '../../ui/legacy/components/perf_ui/perf_ui.js';
import * as UI from '../../ui/legacy/legacy.js';
Expand Down Expand Up @@ -94,6 +95,10 @@ const UIStrings = {
*@description Text to clear content
*/
clear: 'Clear',
/**
*@description A label for a button that fixes something.
*/
fixMe: 'Fix me',
/**
*@description Tooltip text that appears when hovering over the largeicon load button
*/
Expand Down Expand Up @@ -283,6 +288,8 @@ export class TimelinePanel extends UI.Panel.Panel implements Client, TimelineMod
private controller!: TimelineController|null;
private cpuProfiler!: SDK.CPUProfilerModel.CPUProfilerModel|null;
private clearButton!: UI.Toolbar.ToolbarButton;
private fixMeButton: UI.Toolbar.ToolbarButton;
private fixMeButtonAdded = false;
private loadButton!: UI.Toolbar.ToolbarButton;
private saveButton!: UI.Toolbar.ToolbarButton;
private statusPane!: StatusPane|null;
Expand All @@ -306,10 +313,25 @@ export class TimelinePanel extends UI.Panel.Panel implements Client, TimelineMod
#traceEngineActiveTraceIndex = -1;
#sourceMapsResolver: SourceMapsResolver|null = null;
#onSourceMapsNodeNamesResolvedBound = this.#onSourceMapsNodeNamesResolved.bind(this);

readonly #onChartPlayableStateChangeBound: (event: Common.EventTarget.EventTargetEvent<boolean>) => void;
constructor() {
super('timeline');

const adornerContent = document.createElement('span');
adornerContent.innerHTML = `<div style="
font-size: 12px;
transform: scale(1.25);
color: transparent;
background: linear-gradient(90deg, rgb(255 0 0 / 100%) 0%, rgb(255 154 0 / 100%) 10%, rgb(208 222 33 / 100%) 20%, rgb(79 220 74 / 100%) 30%, rgb(63 218 216 / 100%) 40%, rgb(47 201 226 / 100%) 50%, rgb(28 127 238 / 100%) 60%, rgb(95 21 242 / 100%) 70%, rgb(186 12 248 / 100%) 80%, rgb(251 7 217 / 100%) 90%, rgb(255 0 0 / 100%) 100%);
-webkit-background-clip: text;
">💫</div>`;
const adorner = new Adorners.Adorner.Adorner();
adorner.classList.add('fix-perf-icon');
adorner.data = {
name: i18nString(UIStrings.fixMe),
content: adornerContent,
};
this.fixMeButton = new UI.Toolbar.ToolbarButton(i18nString(UIStrings.fixMe), adorner);
this.fixMeButton.addEventListener(UI.Toolbar.ToolbarButton.Events.Click, () => this.onFixMe());
const config = TraceEngine.Types.Configuration.DEFAULT;
config.experiments.timelineShowAllEvents = Root.Runtime.experiments.isEnabled('timelineShowAllEvents');
config.experiments.timelineV8RuntimeCallStats = Root.Runtime.experiments.isEnabled('timelineV8RuntimeCallStats');
Expand Down Expand Up @@ -372,6 +394,11 @@ export class TimelinePanel extends UI.Panel.Panel implements Client, TimelineMod
SDK.ResourceTreeModel.ResourceTreeModel, SDK.ResourceTreeModel.Events.Load, this.loadEventFired, this);

this.flameChart = new TimelineFlameChartView(this);
this.#onChartPlayableStateChangeBound = this.#onChartPlayableStateChange.bind(this);

this.flameChart.getMainFlameChart().addEventListener(
PerfUI.FlameChart.Events.ChartPlayableStateChange, this.#onChartPlayableStateChangeBound, this);

this.searchableViewInternal = new UI.SearchableView.SearchableView(this.flameChart, null);
this.searchableViewInternal.setMinimumSize(0, 100);
this.searchableViewInternal.element.classList.add('searchable-view');
Expand Down Expand Up @@ -461,6 +488,22 @@ export class TimelinePanel extends UI.Panel.Panel implements Client, TimelineMod
return this.flameChart;
}

#onChartPlayableStateChange(event: Common.EventTarget.EventTargetEvent<boolean, unknown>): void {
if (event.data) {
const dateObj = new Date();
const month = dateObj.getUTCMonth() + 1;
const day = dateObj.getUTCDate();
const isAprilFools = (month === 4 && day === 1) || true; // TODO: show only on April fools
if (isAprilFools && !this.fixMeButtonAdded) {
this.fixMeButtonAdded = true;
this.panelToolbar.appendToolbarItem(this.fixMeButton);
}
} else {
this.fixMeButtonAdded = false;
this.panelToolbar.removeToolbarItem(this.fixMeButton);
}
}

private loadFromCpuProfile(profile: Protocol.Profiler.Profile|null, title?: string): void {
if (this.state !== State.Idle) {
return;
Expand Down Expand Up @@ -1066,6 +1109,13 @@ export class TimelinePanel extends UI.Panel.Panel implements Client, TimelineMod
this.clear();
}

private onFixMe(): void {
if (!this.performanceModel) {
return;
}
this.flameChart.fixMe();
}

private clear(): void {
if (this.statusPane) {
this.statusPane.remove();
Expand Down Expand Up @@ -1137,6 +1187,8 @@ export class TimelinePanel extends UI.Panel.Panel implements Client, TimelineMod
this.searchableViewInternal.showWidget();
} else {
this.searchableViewInternal.hideWidget();
this.fixMeButtonAdded = false;
this.panelToolbar.removeToolbarItem(this.fixMeButton);
}
this.flameChart.setModel(model, traceParsedData, isCpuProfile);
this.flameChart.setSelection(null);
Expand Down
73 changes: 73 additions & 0 deletions front_end/panels/timeline/timelinePanel.css
Expand Up @@ -243,6 +243,79 @@
overflow: hidden;
}

.brick-game {
background-color: var(--sys-color-neutral-container);
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 9999; /* A high value to ensure it's on top */
}

.game-close-button {
display: flex;
align-items: center;
justify-content: center;
width: 25px;
height: 25px;
position: absolute;
right: 15px;
top: 15px;
border-radius: 50%;
cursor: pointer;
}

.scorePanel {
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
white-space: pre-line;
padding: 15px;
position: absolute;
left: 15px;
bottom: 15px;
border: double 7px transparent;
border-radius: 20px;
background-origin: border-box;
background-clip: content-box, border-box;
font-weight: 200;
}

.confetti-100 {
display: block;
top: 0;
left: 0;
width: 100%;
height: 100%;
}

.confetti-100 > .confetti-100-particle {
opacity: 0%;
position: fixed;
animation: confetti-100-animation 1s none ease-out;
font-size: 30px;
}

@keyframes confetti-100-animation {
0% {
opacity: 100%;
transform: translateY(0%) translateY(0%) rotate(0deg);
}

100% {
opacity: 0%;
transform: translateY(var(--to-Y)) translateX(var(--to-X)) rotate(var(--rotation));
}
}

@media (prefers-reduced-motion) {
.confetti-100 > .confetti-100-particle {
animation-name: dissolve;
}
}

.timeline-flamechart-resizer {
flex: 8px 0 0;
background-color: var(--sys-color-surface2);
Expand Down
1 change: 1 addition & 0 deletions front_end/ui/legacy/components/perf_ui/BUILD.gn
Expand Up @@ -28,6 +28,7 @@ generate_css("legacy_css_files") {

devtools_module("perf_ui") {
sources = [
"BrickBreaker.ts",
"ChartViewport.ts",
"FilmStripView.ts",
"FlameChart.ts",
Expand Down

0 comments on commit 7a45cff

Please sign in to comment.