Skip to content

Commit

Permalink
Merge "Basic widget for text paragraphs, used in scroll jank plugin."…
Browse files Browse the repository at this point in the history
… into main
  • Loading branch information
Harkiran Bolaria authored and Gerrit Code Review committed Oct 2, 2023
2 parents d6791ce + 1fec143 commit ee5cadb
Show file tree
Hide file tree
Showing 7 changed files with 178 additions and 43 deletions.
1 change: 1 addition & 0 deletions ui/src/assets/perfetto.scss
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,4 @@
@import "widgets/editor";
@import "widgets/vega_view";
@import "widgets/hotkey";
@import "widgets/text_paragraph";
22 changes: 22 additions & 0 deletions ui/src/assets/widgets/text_paragraph.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright (C) 2023 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

@import "theme";

.pf-text-paragraph {
white-space:pre-wrap;
padding-top:5px;
padding-bottom:5px;
word-break:break-word;
}
45 changes: 45 additions & 0 deletions ui/src/frontend/widgets_page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import {FilterableSelect, Select} from '../widgets/select';
import {Spinner} from '../widgets/spinner';
import {Switch} from '../widgets/switch';
import {TextInput} from '../widgets/text_input';
import {MultiParagraphText, TextParagraph} from '../widgets/text_paragraph';
import {LazyTreeNode, Tree, TreeNode} from '../widgets/tree';

import {createPage} from './pages';
Expand Down Expand Up @@ -969,6 +970,50 @@ export const WidgetsPage = createPage({
platform: new EnumOption('auto', ['auto', 'Mac', 'PC']),
},
}),
m(
WidgetShowcase, {
label: 'Text Paragraph',
description: `A basic formatted text paragraph with wrapping. If
it is desirable to preserve the original text format/line breaks,
set the compressSpace attribute to false.`,
renderWidget: (opts) => {
return m(TextParagraph, {
text: `Lorem ipsum dolor sit amet, consectetur adipiscing
elit. Nulla rhoncus tempor neque, sed malesuada eros
dapibus vel. Aliquam in ligula vitae tortor porttitor
laoreet iaculis finibus est.`,
compressSpace: opts.compressSpace,
});
},
initialOpts: {
compressSpace: true,
},
}),
m(
WidgetShowcase, {
label: 'Multi Paragraph Text',
description: `A wrapper for multiple paragraph widgets.`,
renderWidget: () => {
return m(MultiParagraphText,
m(TextParagraph, {
text: `Lorem ipsum dolor sit amet, consectetur adipiscing
elit. Nulla rhoncus tempor neque, sed malesuada eros
dapibus vel. Aliquam in ligula vitae tortor porttitor
laoreet iaculis finibus est.`,
compressSpace: true,
}), m(TextParagraph, {
text: `Sed ut perspiciatis unde omnis iste natus error sit
voluptatem accusantium doloremque laudantium, totam rem
aperiam, eaque ipsa quae ab illo inventore veritatis et
quasi architecto beatae vitae dicta sunt explicabo.
Nemo enim ipsam voluptatem quia voluptas sit aspernatur
aut odit aut fugit, sed quia consequuntur magni dolores
eos qui ratione voluptatem sequi nesciunt.`,
compressSpace: true,
}),
);
},
}),
);
},
});
Expand Down
39 changes: 22 additions & 17 deletions ui/src/tracks/chrome_scroll_jank/event_latency_details_panel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import {asSliceSqlId} from '../../frontend/sql_types';
import {DetailsShell} from '../../widgets/details_shell';
import {GridLayout, GridLayoutColumn} from '../../widgets/grid_layout';
import {Section} from '../../widgets/section';
import {MultiParagraphText, TextParagraph} from '../../widgets/text_paragraph';
import {Tree, TreeNode} from '../../widgets/tree';

import {
Expand Down Expand Up @@ -134,23 +135,27 @@ export class EventLatencySliceDetailsPanel extends

private getDescriptionText(): m.Child {
return m(
`div[style='white-space:pre-wrap']`,
`EventLatency tracks the latency of handling a given input event
(Scrolls, Touchs, Taps, etc). Ideally from when the input was read by
the hardware to when it was reflected on the screen.{new_lines}
Note however the concept of coalescing or terminating early. This occurs
when we receive multiple events or handle them quickly by converting
the into a different event. Such as a TOUCH_MOVE being converted into a
GESTURE_SCROLL_UPDATE type, or a multiple GESTURE_SCROLL_UPDATE events
being formed into a single frame at the end of the
RendererCompositorQueuingDelay.{new_lines}
*Important:* On some platforms (MacOS) we do not get feedback on when
something is presented on the screen so the timings are only accurate
for what we know on a given platform.`.replace(/\s\s+/g, ' ')
.replace(/{new_lines}/g, '\n\n')
.replace(/ Note:/g, 'Note:'),
MultiParagraphText,
m(TextParagraph, {
text: `EventLatency tracks the latency of handling a given input event
(Scrolls, Touches, Taps, etc). Ideally from when the input was
read by the hardware to when it was reflected on the screen.`,
}),
m(TextParagraph, {
text:
`Note however the concept of coalescing or terminating early. This
occurs when we receive multiple events or handle them quickly by
converting them into a different event. Such as a TOUCH_MOVE
being converted into a GESTURE_SCROLL_UPDATE type, or a multiple
GESTURE_SCROLL_UPDATE events being formed into a single frame at
the end of the RendererCompositorQueuingDelay.`,
}),
m(TextParagraph, {
text:
`*Important:* On some platforms (MacOS) we do not get feedback on
when something is presented on the screen so the timings are only
accurate for what we know on a given platform.`,
}),
);
}

Expand Down
37 changes: 20 additions & 17 deletions ui/src/tracks/chrome_scroll_jank/scroll_details_panel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import {DurationWidget} from '../../widgets/duration';
import {GridLayout, GridLayoutColumn} from '../../widgets/grid_layout';
import {Section} from '../../widgets/section';
import {SqlRef} from '../../widgets/sql_ref';
import {MultiParagraphText, TextParagraph} from '../../widgets/text_paragraph';
import {dictToTreeNodes, Tree} from '../../widgets/tree';

import {
Expand Down Expand Up @@ -279,22 +280,24 @@ export class ScrollDetailsPanel extends

private getDescriptionText(): m.Child {
return m(
`div[style='white-space:pre-wrap']`,
`The interval during which the user has started a scroll ending after
their finger leaves the screen and any resulting fling animations have
finished.{new_lines}
Note: This can contain periods of time where the finger is down and not
moving and no active scrolling is occurring.{new_lines}
Note: Sometimes if a user touches the screen quickly after letting go
or Chrome was hung and got into a bad state. A new scroll will start
which will result in a slightly overlapping scroll. This can occur due
to the last scroll still outputting frames (to get caught up) and the
"new" scroll having started producing frames after the user has started
scrolling again.`.replace(/\s\s+/g, ' ')
.replace(/{new_lines}/g, '\n\n')
.replace(/ Note:/g, 'Note:'),
MultiParagraphText,
m(TextParagraph, {
text: `The interval during which the user has started a scroll ending
after their finger leaves the screen and any resulting fling
animations have finished.`,
}),
m(TextParagraph, {
text: `Note: This can contain periods of time where the finger is down
and not moving and no active scrolling is occurring.`,
}),
m(TextParagraph, {
text: `Note: Sometimes if a user touches the screen quickly after
letting go or Chrome was hung and got into a bad state. A new
scroll will start which will result in a slightly overlapping
scroll. This can occur due to the last scroll still outputting
frames (to get caught up) and the "new" scroll having started
producing frames after the user has started scrolling again.`,
}),
);
}

Expand Down Expand Up @@ -335,7 +338,7 @@ export class ScrollDetailsPanel extends
m(
Section,
{title: 'Description'},
m('.div', this.getDescriptionText()),
this.getDescriptionText(),
),
// TODO: Add custom widgets (e.g. event latency table).
)),
Expand Down
19 changes: 10 additions & 9 deletions ui/src/tracks/chrome_scroll_jank/scroll_jank_v3_details_panel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import {DurationWidget} from '../../widgets/duration';
import {GridLayout, GridLayoutColumn} from '../../widgets/grid_layout';
import {Section} from '../../widgets/section';
import {SqlRef} from '../../widgets/sql_ref';
import {MultiParagraphText, TextParagraph} from '../../widgets/text_paragraph';
import {dictToTreeNodes, Tree, TreeNode} from '../../widgets/tree';

import {EventLatencyTrack} from './event_latency_track';
Expand Down Expand Up @@ -239,15 +240,15 @@ export class ScrollJankV3DetailsPanel extends

private getDescriptionText(): m.Child {
return m(
`div[style='white-space:pre-wrap']`,
`Delay between when the frame was expected to be presented and when it
was actually presented.{new_lines}
This is the period of time during which the user is viewing a frame
that isn't correct.`.replace(/\s\s+/g, ' ')
.replace(/{new_lines}/g, '\n\n')
.replace(' This', 'This'),
);
MultiParagraphText,
m(TextParagraph, {
text: `Delay between when the frame was expected to be presented and
when it was actually presented.`,
}),
m(TextParagraph, {
text: `This is the period of time during which the user is viewing a
frame that isn't correct.`,
}));
}

private getLinksSection(): m.Child[] {
Expand Down
58 changes: 58 additions & 0 deletions ui/src/widgets/text_paragraph.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// Copyright (C) 2023 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import m from 'mithril';
import {classNames} from '../base/classnames';

export interface TextParagraphAttrs {
// Paragraph text.
text: string;
// Whether to compress multiple spaces (e.g. the string is multi-line but
// should render with the default UI wrapping)
compressSpace?: boolean;
// Remaining attributes forwarded to the underlying HTML <section>.
[htmlAttrs: string]: any;
}

export class TextParagraph implements m.ClassComponent<TextParagraphAttrs> {
view({attrs}: m.CVnode<TextParagraphAttrs>) {
let {text, compressSpace} = attrs;
if (compressSpace === undefined) {
compressSpace = true;
}
return m(
`div.pf-text-paragraph`,
compressSpace ? text.replace(/\s\s+/g, ' ') : text);
}
}

interface MultiParagraphTextAttrs {
// Space delimited class list applied to element.
className?: string;
}

export class MultiParagraphText implements
m.ClassComponent<MultiParagraphTextAttrs> {
view({attrs, children}: m.Vnode<MultiParagraphTextAttrs>): m.Children {
const {
className = '',
} = attrs;

const classes = classNames(
className,
);

return m('div', {class: classes}, children);
}
}

0 comments on commit ee5cadb

Please sign in to comment.