blob: 4c644406fb59aa88e699993f316657ed94c60101 [file] [log] [blame]
// Copyright (C) 2019 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 {searchSegment} from '../base/binary_search';
import {Actions} from '../common/actions';
import {getContainingTrackId} from '../common/state';
import {fromNs, TimeSpan, toNs} from '../common/time';
import {globals} from './globals';
export function executeSearch(reverse = false) {
const state = globals.frontendLocalState;
const index = state.searchIndex;
const startNs = toNs(globals.frontendLocalState.visibleWindowTime.start);
const endNs = toNs(globals.frontendLocalState.visibleWindowTime.end);
const currentTs = globals.currentSearchResults.tsStarts[index];
// If this is a new search or the currentTs is not in the viewport,
// select the first/last item in the viewport.
if (index === -1 || currentTs < startNs || currentTs > endNs) {
if (reverse) {
const [smaller,] =
searchSegment(globals.currentSearchResults.tsStarts, endNs);
globals.frontendLocalState.setSearchIndex(smaller);
} else {
const [, larger] =
searchSegment(globals.currentSearchResults.tsStarts, startNs);
globals.frontendLocalState.setSearchIndex(larger);
}
// If there is no result in the current viewport, move it.
const currentTs = globals.currentSearchResults.tsStarts[state.searchIndex];
if (currentTs < startNs || currentTs > endNs) {
moveViewportToCurrentSearch();
}
} else {
// If the currentTs is in the viewport, increment the index and move the
// viewport if necessary.
if (reverse) {
globals.frontendLocalState.setSearchIndex(Math.max(index - 1, 0));
} else {
globals.frontendLocalState.setSearchIndex(Math.min(
index + 1, globals.currentSearchResults.sliceIds.length - 1));
}
moveViewportToCurrentSearch();
}
selectCurrentSearchResult();
}
function moveViewportToCurrentSearch() {
// Move viewport if our selection moves outside.
const startNs = toNs(globals.frontendLocalState.visibleWindowTime.start);
const endNs = toNs(globals.frontendLocalState.visibleWindowTime.end);
const currentTs = globals.currentSearchResults
.tsStarts[globals.frontendLocalState.searchIndex];
const currentViewNs = endNs - startNs;
if (currentTs < startNs || currentTs > endNs) {
// TODO(taylori): This is an ugly jump, we should do a smooth pan instead.
globals.frontendLocalState.updateVisibleTime(new TimeSpan(
fromNs(currentTs - currentViewNs / 2),
fromNs(currentTs + currentViewNs / 2)));
}
// Update vertical (up/down) scroll position
const trackId = globals.currentSearchResults
.trackIds[globals.frontendLocalState.searchIndex];
let track = document.querySelector('#track_' + trackId);
if (!track) {
const parentTrackId = getContainingTrackId(globals.state, trackId);
if (parentTrackId) {
track = document.querySelector('#track_' + parentTrackId);
}
}
if (!track) {
console.error(`Can't scroll search result track not found (${trackId})`);
return;
}
// block: 'nearest' means that it will only scroll if the track is not
// currently in view.
track.scrollIntoView({behavior: 'smooth', block: 'nearest'});
}
function selectCurrentSearchResult() {
const state = globals.frontendLocalState;
const index = state.searchIndex;
const refType = globals.currentSearchResults.refTypes[index];
const currentId = globals.currentSearchResults.sliceIds[index];
if (currentId === undefined) return;
if (refType === 'cpu') {
globals.dispatch(Actions.selectSlice({
utid: globals.currentSearchResults.utids[index],
id: currentId,
}));
}
if (refType === 'utid') {
globals.dispatch(Actions.selectChromeSlice({
id: currentId,
}));
}
}