2 * Copyright (C) 2014 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 * @implements {WebInspector.FlameChartDataProvider}
34 * @param {!WebInspector.TracingTimelineModel} model
35 * @param {!WebInspector.TimelineFrameModelBase} frameModel
37 WebInspector.TimelineFlameChartDataProvider = function(model, frameModel)
39 WebInspector.FlameChartDataProvider.call(this);
42 this._frameModel = frameModel;
43 this._font = "12px " + WebInspector.fontFamily();
44 this._linkifier = new WebInspector.Linkifier();
45 this._captureStacksSetting = WebInspector.settings.createSetting("timelineCaptureStacks", true);
47 this.addFilter(WebInspector.TracingTimelineUIUtils.hiddenEventsFilter());
48 this.addFilter(new WebInspector.TracingTimelineModel.ExclusiveEventNameFilter([WebInspector.TracingTimelineModel.RecordType.Program]));
51 WebInspector.TimelineFlameChartDataProvider.InstantEventVisibleDurationMs = 0.01;
52 WebInspector.TimelineFlameChartDataProvider.JSFrameCoalesceThresholdMs = 1.1;
55 * @return {!WebInspector.FlameChart.ColorGenerator}
57 WebInspector.TimelineFlameChartDataProvider.consoleEventsColorGenerator = function()
59 if (!WebInspector.TimelineFlameChartDataProvider.consoleEventsColorGenerator._consoleEventsColorGenerator) {
60 var hueSpace = { min: 30, max: 55, count: 5 };
61 var satSpace = { min: 70, max: 100, count: 6 };
62 var colorGenerator = new WebInspector.FlameChart.ColorGenerator(hueSpace, satSpace, 50, 0.7);
63 WebInspector.TimelineFlameChartDataProvider.consoleEventsColorGenerator._consoleEventsColorGenerator = colorGenerator;
65 return WebInspector.TimelineFlameChartDataProvider.consoleEventsColorGenerator._consoleEventsColorGenerator;
68 WebInspector.TimelineFlameChartDataProvider.prototype = {
80 textBaseline: function()
88 textPadding: function()
94 * @param {number} entryIndex
97 entryFont: function(entryIndex)
103 * @param {number} entryIndex
106 entryTitle: function(entryIndex)
108 var event = this._entryEvents[entryIndex];
110 if (event.phase === WebInspector.TracingModel.Phase.AsyncStepInto || event.phase === WebInspector.TracingModel.Phase.AsyncStepPast)
111 return event.name + ":" + event.args["step"];
113 var name = WebInspector.TracingTimelineUIUtils.eventStyle(event).title;
114 // TODO(yurys): support event dividers
115 var details = WebInspector.TracingTimelineUIUtils.buildDetailsNodeForTraceEvent(event, this._linkifier);
116 if (event.name === WebInspector.TracingTimelineModel.RecordType.JSFrame && details)
117 return details.textContent;
118 return details ? WebInspector.UIString("%s (%s)", name, details.textContent) : name;
120 var title = this._entryIndexToTitle[entryIndex];
122 title = WebInspector.UIString("Unexpected entryIndex %d", entryIndex);
123 console.error(title);
129 * @param {number} startTime
130 * @param {number} endTime
131 * @return {?Array.<number>}
133 dividerOffsets: function(startTime, endTime)
140 * @param {number} index
143 markerColor: function(index)
145 var event = this._markerEvents[index];
146 return WebInspector.TracingTimelineUIUtils.markerEventColor(event);
151 * @param {number} index
154 markerTitle: function(index)
156 var event = this._markerEvents[index];
157 return WebInspector.TracingTimelineUIUtils.eventTitle(event, this._model);
162 this._timelineData = null;
163 /** @type {!Array.<!WebInspector.TracingModel.Event>} */
164 this._entryEvents = [];
165 this._entryIndexToTitle = {};
166 this._markerEvents = [];
167 this._entryIndexToFrame = {};
168 this._asyncColorByCategory = {};
172 * @return {!WebInspector.FlameChart.TimelineData}
174 timelineData: function()
176 if (this._timelineData)
177 return this._timelineData;
179 this._timelineData = new WebInspector.FlameChart.TimelineData([], [], []);
181 this._minimumBoundary = this._model.minimumRecordTime();
182 this._timeSpan = this._model.isEmpty() ? 1000 : this._model.maximumRecordTime() - this._minimumBoundary;
183 this._currentLevel = 0;
184 this._appendFrameBars(this._frameModel.frames());
185 this._appendThreadTimelineData(WebInspector.UIString("Main Thread"), this._model.mainThreadEvents(), this._model.mainThreadAsyncEvents());
186 var threads = this._model.virtualThreads();
187 for (var i = 0; i < threads.length; i++)
188 this._appendThreadTimelineData(threads[i].name, threads[i].events, threads[i].asyncEvents);
189 return this._timelineData;
193 * @param {string} threadTitle
194 * @param {!Array.<!WebInspector.TracingModel.Event>} syncEvents
195 * @param {!Array.<!Array.<!WebInspector.TracingModel.Event>>} asyncEvents
197 _appendThreadTimelineData: function(threadTitle, syncEvents, asyncEvents)
199 var levelCount = this._appendAsyncEvents(threadTitle, asyncEvents);
200 if (Runtime.experiments.isEnabled("timelineJSCPUProfile")) {
201 if (this._captureStacksSetting.get()) {
202 var jsFrameEvents = this._generateJSFrameEvents(syncEvents);
203 syncEvents = jsFrameEvents.mergeOrdered(syncEvents, WebInspector.TracingModel.Event.orderedCompareStartTime);
206 levelCount += this._appendSyncEvents(levelCount ? null : threadTitle, syncEvents);
208 ++this._currentLevel;
212 * @param {?string} headerName
213 * @param {!Array.<!WebInspector.TracingModel.Event>} events
216 _appendSyncEvents: function(headerName, events)
219 var headerAppended = false;
221 var maxStackDepth = 0;
222 for (var i = 0; i < events.length; ++i) {
224 if (WebInspector.TracingTimelineUIUtils.isMarkerEvent(e)) {
225 this._markerEvents.push(e);
226 this._timelineData.markerTimestamps.push(e.startTime);
228 if (!e.endTime && e.phase !== WebInspector.TracingModel.Phase.Instant)
230 if (!this._isVisible(e))
232 while (openEvents.length && openEvents.peekLast().endTime <= e.startTime)
234 if (!headerAppended && headerName) {
235 this._appendHeaderRecord(headerName, this._currentLevel++);
236 headerAppended = true;
238 this._appendEvent(e, this._currentLevel + openEvents.length);
239 maxStackDepth = Math.max(maxStackDepth, openEvents.length + 1);
243 this._currentLevel += maxStackDepth;
244 return !!maxStackDepth;
248 * @param {string} header
249 * @param {!Array.<!Array.<!WebInspector.TracingModel.Event>>} eventSteps
251 _appendAsyncEvents: function(header, eventSteps)
253 var lastUsedTimeByLevel = [];
254 var headerAppended = false;
256 var maxStackDepth = 0;
257 for (var i = 0; i < eventSteps.length; ++i) {
258 var e = eventSteps[i][0];
259 if (!this._isVisible(e))
261 if (!headerAppended && header) {
262 this._appendHeaderRecord(header, this._currentLevel++);
263 headerAppended = true;
266 for (level = 0; level < lastUsedTimeByLevel.length && lastUsedTimeByLevel[level] > e.startTime; ++level) {}
267 this._appendAsyncEventSteps(eventSteps[i], this._currentLevel + level);
268 var lastStep = eventSteps[i].peekLast();
269 lastUsedTimeByLevel[level] = lastStep.phase === WebInspector.TracingModel.Phase.AsyncEnd ? lastStep.startTime : Infinity;
271 this._currentLevel += lastUsedTimeByLevel.length;
272 return lastUsedTimeByLevel.length;
276 * @param {!Array.<!WebInspector.TimelineFrame>} frames
278 _appendFrameBars: function(frames)
280 this._frameBarsLevel = this._currentLevel++;
281 for (var i = 0; i < frames.length; ++i)
282 this._appendFrame(frames[i]);
286 * @param {!Array.<!WebInspector.TracingModel.Event>} events
287 * @return {!Array.<!WebInspector.TracingModel.Event>}
289 _generateJSFrameEvents: function(events)
291 function equalFrames(frame1, frame2)
293 return frame1.scriptId === frame2.scriptId && frame1.functionName === frame2.functionName;
296 function eventEndTime(e)
298 return e.endTime || e.startTime;
301 function isJSInvocationEvent(e)
304 case WebInspector.TracingTimelineModel.RecordType.FunctionCall:
305 case WebInspector.TracingTimelineModel.RecordType.EvaluateScript:
311 var jsFrameEvents = [];
312 var jsFramesStack = [];
313 var coalesceThresholdMs = WebInspector.TimelineFlameChartDataProvider.JSFrameCoalesceThresholdMs;
315 function onStartEvent(e)
317 extractStackTrace(e);
320 function onInstantEvent(e, top)
322 if (e.name === WebInspector.TracingTimelineModel.RecordType.JSSample && top && !isJSInvocationEvent(top))
324 extractStackTrace(e);
327 function onEndEvent(e)
329 if (isJSInvocationEvent(e))
330 jsFramesStack.length = 0;
333 function extractStackTrace(e)
337 while (jsFramesStack.length && eventEndTime(jsFramesStack.peekLast()) + coalesceThresholdMs <= e.startTime)
339 var endTime = eventEndTime(e);
340 var numFrames = e.stackTrace.length;
341 var minFrames = Math.min(numFrames, jsFramesStack.length);
343 for (j = 0; j < minFrames; ++j) {
344 var newFrame = e.stackTrace[numFrames - 1 - j];
345 var oldFrame = jsFramesStack[j].args["data"];
346 if (!equalFrames(newFrame, oldFrame))
348 jsFramesStack[j].setEndTime(Math.max(jsFramesStack[j].endTime, endTime));
350 jsFramesStack.length = j;
351 for (; j < numFrames; ++j) {
352 var frame = e.stackTrace[numFrames - 1 - j];
353 var jsFrameEvent = new WebInspector.TracingModel.Event(WebInspector.TracingModel.DevToolsMetadataEventCategory, WebInspector.TracingTimelineModel.RecordType.JSFrame,
354 WebInspector.TracingModel.Phase.Complete, e.startTime, e.thread);
355 jsFrameEvent.addArgs({ data: frame });
356 jsFrameEvent.setEndTime(endTime);
357 jsFramesStack.push(jsFrameEvent);
358 jsFrameEvents.push(jsFrameEvent);
363 for (var i = 0; i < events.length; ++i) {
365 var top = stack.peekLast();
366 if (top && top.endTime <= e.startTime)
367 onEndEvent(stack.pop());
372 onInstantEvent(e, stack.peekLast());
376 onEndEvent(stack.pop());
378 return jsFrameEvents;
382 * @param {!WebInspector.TracingTimelineModel.Filter} filter
384 addFilter: function(filter)
386 this._filters.push(filter);
390 * @param {!WebInspector.TracingModel.Event} event
393 _isVisible: function(event)
395 return this._filters.every(function (filter) { return filter.accept(event); });
401 minimumBoundary: function()
403 return this._minimumBoundary;
409 totalTime: function()
411 return this._timeSpan;
417 maxStackDepth: function()
419 return this._currentLevel;
423 * @param {number} entryIndex
424 * @return {?Array.<!{title: string, text: string}>}
426 prepareHighlightedEntryInfo: function(entryIndex)
432 * @param {number} entryIndex
435 canJumpToEntry: function(entryIndex)
441 * @param {number} entryIndex
444 entryColor: function(entryIndex)
446 var event = this._entryEvents[entryIndex];
448 return this._entryIndexToFrame[entryIndex] ? "white" : "#555";
449 if (event.name === WebInspector.TracingTimelineModel.RecordType.JSFrame)
450 return this._timelineData.entryLevels[entryIndex] % 2 ? "#efb320" : "#fcc02d";
451 var category = WebInspector.TracingTimelineUIUtils.eventStyle(event).category;
452 if (WebInspector.TracingModel.isAsyncPhase(event.phase)) {
453 if (event.category === WebInspector.TracingModel.ConsoleEventCategory)
454 return WebInspector.TimelineFlameChartDataProvider.consoleEventsColorGenerator().colorForID(event.name);
455 var color = this._asyncColorByCategory[category.name];
458 var parsedColor = WebInspector.Color.parse(category.fillColorStop1);
459 color = parsedColor.setAlpha(0.7).toString(WebInspector.Color.Format.RGBA) || "";
460 this._asyncColorByCategory[category.name] = color;
463 return category.fillColorStop1;
467 * @param {number} entryIndex
468 * @param {!CanvasRenderingContext2D} context
469 * @param {?string} text
470 * @param {number} barX
471 * @param {number} barY
472 * @param {number} barWidth
473 * @param {number} barHeight
474 * @param {function(number):number} offsetToPosition
477 decorateEntry: function(entryIndex, context, text, barX, barY, barWidth, barHeight, offsetToPosition)
479 var frame = this._entryIndexToFrame[entryIndex];
483 context.translate(0.5, 0.5);
486 context.moveTo(barX, barY);
487 context.lineTo(barX, context.canvas.height);
488 context.strokeStyle = "rgba(100, 100, 100, 0.4)";
489 context.setLineDash([5]);
491 context.setLineDash([]);
494 var padding = 4 * window.devicePixelRatio;
496 barWidth -= 2 * padding;
498 barHeight -= 2 * padding;
501 var radiusY = cornerRadis;
502 var radiusX = Math.min(cornerRadis, barWidth / 2);
505 context.moveTo(barX + radiusX, barY);
506 context.lineTo(barX + barWidth - radiusX, barY);
507 context.quadraticCurveTo(barX + barWidth, barY, barX + barWidth, barY + radiusY);
508 context.lineTo(barX + barWidth, barY + barHeight - radiusY);
509 context.quadraticCurveTo(barX + barWidth, barY + barHeight, barX + barWidth - radiusX, barY + barHeight);
510 context.lineTo(barX + radiusX, barY + barHeight);
511 context.quadraticCurveTo(barX, barY + barHeight, barX, barY + barHeight - radiusY);
512 context.lineTo(barX, barY + radiusY);
513 context.quadraticCurveTo(barX, barY, barX + radiusX, barY);
516 context.fillStyle = "rgba(200, 200, 200, 0.8)";
518 context.strokeStyle = "rgba(150, 150, 150, 0.8)";
521 var frameDurationText = Number.millisToString(frame.duration, true);
522 var textWidth = context.measureText(frameDurationText).width;
523 if (barWidth > textWidth) {
524 context.fillStyle = "#555";
525 context.fillText(frameDurationText, barX + ((barWidth - textWidth) >> 1), barY + barHeight - 2);
533 // Paint text using white color on dark background.
536 context.fillStyle = "white";
537 context.shadowColor = "rgba(0, 0, 0, 0.1)";
538 context.shadowOffsetX = 1;
539 context.shadowOffsetY = 1;
540 context.font = this._font;
541 context.fillText(text, barX + this.textPadding(), barY + barHeight - this.textBaseline());
545 var event = this._entryEvents[entryIndex];
546 if (event && event.warning) {
549 context.rect(barX, barY, barWidth, this.barHeight());
553 context.fillStyle = "red";
554 context.moveTo(barX + barWidth - 15, barY + 1);
555 context.lineTo(barX + barWidth - 1, barY + 1);
556 context.lineTo(barX + barWidth - 1, barY + 15);
566 * @param {number} entryIndex
569 forceDecoration: function(entryIndex)
571 var event = this._entryEvents[entryIndex];
573 return !!this._entryIndexToFrame[entryIndex];
574 return !!event.warning;
578 * @param {number} entryIndex
579 * @return {?{startTime: number, endTime: number}}
581 highlightTimeRange: function(entryIndex)
583 var startTime = this._timelineData.entryStartTimes[entryIndex];
587 startTime: startTime,
588 endTime: startTime + this._timelineData.entryTotalTimes[entryIndex]
595 paddingLeft: function()
601 * @param {number} entryIndex
604 textColor: function(entryIndex)
610 * @param {string} title
611 * @param {number} level
613 _appendHeaderRecord: function(title, level)
615 var index = this._entryEvents.length;
616 this._entryIndexToTitle[index] = title;
617 this._entryEvents.push(null);
618 this._timelineData.entryLevels[index] = level;
619 this._timelineData.entryTotalTimes[index] = this._timeSpan;
620 this._timelineData.entryStartTimes[index] = this._minimumBoundary;
624 * @param {!WebInspector.TracingModel.Event} event
625 * @param {number} level
627 _appendEvent: function(event, level)
629 var index = this._entryEvents.length;
630 this._entryEvents.push(event);
631 this._timelineData.entryLevels[index] = level;
632 this._timelineData.entryTotalTimes[index] = event.duration || WebInspector.TimelineFlameChartDataProvider.InstantEventVisibleDurationMs;
633 this._timelineData.entryStartTimes[index] = event.startTime;
637 * @param {!Array.<!WebInspector.TracingModel.Event>} steps
638 * @param {number} level
640 _appendAsyncEventSteps: function(steps, level)
642 // If we have past steps, put the end event for each range rather than start one.
643 var eventOffset = steps[1].phase === WebInspector.TracingModel.Phase.AsyncStepPast ? 1 : 0;
644 for (var i = 0; i < steps.length - 1; ++i) {
645 var index = this._entryEvents.length;
646 this._entryEvents.push(steps[i + eventOffset]);
647 var startTime = steps[i].startTime;
648 this._timelineData.entryLevels[index] = level;
649 this._timelineData.entryTotalTimes[index] = steps[i + 1].startTime - startTime;
650 this._timelineData.entryStartTimes[index] = startTime;
655 * @param {!WebInspector.TimelineFrame} frame
657 _appendFrame: function(frame)
659 var index = this._entryEvents.length;
660 this._entryEvents.push(null);
661 this._entryIndexToFrame[index] = frame;
662 this._entryIndexToTitle[index] = Number.millisToString(frame.duration, true);
663 this._timelineData.entryLevels[index] = this._frameBarsLevel;
664 this._timelineData.entryTotalTimes[index] = frame.duration;
665 this._timelineData.entryStartTimes[index] = frame.startTime;
669 * @param {number} entryIndex
670 * @return {?WebInspector.TimelineSelection}
672 createSelection: function(entryIndex)
674 var event = this._entryEvents[entryIndex];
676 this._lastSelection = new WebInspector.TimelineFlameChart.Selection(WebInspector.TimelineSelection.fromTraceEvent(event), entryIndex);
677 return this._lastSelection.timelineSelection;
679 var frame = this._entryIndexToFrame[entryIndex];
681 this._lastSelection = new WebInspector.TimelineFlameChart.Selection(WebInspector.TimelineSelection.fromFrame(frame), entryIndex);
682 return this._lastSelection.timelineSelection;
688 * @param {?WebInspector.TimelineSelection} selection
691 entryIndexForSelection: function(selection)
696 if (this._lastSelection && this._lastSelection.timelineSelection.object() === selection.object())
697 return this._lastSelection.entryIndex;
698 switch (selection.type()) {
699 case WebInspector.TimelineSelection.Type.TraceEvent:
700 var event = /** @type{!WebInspector.TracingModel.Event} */ (selection.object());
701 var entryEvents = this._entryEvents;
702 for (var entryIndex = 0; entryIndex < entryEvents.length; ++entryIndex) {
703 if (entryEvents[entryIndex] === event) {
704 this._lastSelection = new WebInspector.TimelineFlameChart.Selection(WebInspector.TimelineSelection.fromTraceEvent(event), entryIndex);
709 case WebInspector.TimelineSelection.Type.Frame:
710 var frame = /** @type {!WebInspector.TimelineFrame} */ (selection.object());
711 for (var frameIndex in this._entryIndexToFrame) {
712 if (this._entryIndexToFrame[frameIndex] === frame) {
713 this._lastSelection = new WebInspector.TimelineFlameChart.Selection(WebInspector.TimelineSelection.fromFrame(frame), Number(frameIndex));
714 return Number(frameIndex);
725 * @extends {WebInspector.VBox}
726 * @implements {WebInspector.TimelineModeView}
727 * @implements {WebInspector.FlameChartDelegate}
728 * @param {!WebInspector.TimelineModeViewDelegate} delegate
729 * @param {!WebInspector.TracingTimelineModel} tracingModel
730 * @param {!WebInspector.TimelineFrameModelBase} frameModel
732 WebInspector.TimelineFlameChart = function(delegate, tracingModel, frameModel)
734 WebInspector.VBox.call(this);
735 this.element.classList.add("timeline-flamechart");
736 this.registerRequiredCSS("flameChart.css");
737 this._delegate = delegate;
738 this._model = tracingModel;
739 this._dataProvider = new WebInspector.TimelineFlameChartDataProvider(tracingModel, frameModel)
740 this._mainView = new WebInspector.FlameChart(this._dataProvider, this, true);
741 this._mainView.show(this.element);
742 this._model.addEventListener(WebInspector.TimelineModel.Events.RecordingStarted, this._onRecordingStarted, this);
743 this._mainView.addEventListener(WebInspector.FlameChart.Events.EntrySelected, this._onEntrySelected, this);
746 WebInspector.TimelineFlameChart.prototype = {
749 this._model.removeEventListener(WebInspector.TimelineModel.Events.RecordingStarted, this._onRecordingStarted, this);
750 this._mainView.removeEventListener(WebInspector.FlameChart.Events.EntrySelected, this._onEntrySelected, this);
754 * @param {number} windowStartTime
755 * @param {number} windowEndTime
757 requestWindowTimes: function(windowStartTime, windowEndTime)
759 this._delegate.requestWindowTimes(windowStartTime, windowEndTime);
763 * @param {?RegExp} textFilter
765 refreshRecords: function(textFilter)
767 this._dataProvider.reset();
768 this._mainView.scheduleUpdate();
773 this._mainView.scheduleUpdate();
777 * @return {!WebInspector.View}
786 this._automaticallySizeWindow = true;
787 this._dataProvider.reset();
788 this._mainView.reset();
789 this._mainView.setWindowTimes(0, Infinity);
792 _onRecordingStarted: function()
794 this._automaticallySizeWindow = true;
795 this._mainView.reset();
799 * @param {!WebInspector.TimelineModel.Record} record
801 addRecord: function(record)
803 this._dataProvider.reset();
804 if (this._automaticallySizeWindow) {
805 var minimumRecordTime = this._model.minimumRecordTime();
806 if (record.startTime() > (minimumRecordTime + 1000)) {
807 this._automaticallySizeWindow = false;
808 this._delegate.requestWindowTimes(minimumRecordTime, minimumRecordTime + 1000);
810 this._mainView.scheduleUpdate();
812 if (!this._pendingUpdateTimer)
813 this._pendingUpdateTimer = window.setTimeout(this._updateOnAddRecord.bind(this), 300);
817 _updateOnAddRecord: function()
819 delete this._pendingUpdateTimer;
820 this._mainView.scheduleUpdate();
824 * @param {number} startTime
825 * @param {number} endTime
827 setWindowTimes: function(startTime, endTime)
829 this._mainView.setWindowTimes(startTime, endTime);
830 this._delegate.select(null);
834 * @param {number} width
836 setSidebarSize: function(width)
841 * @param {?WebInspector.TimelineModel.Record} record
842 * @param {string=} regex
843 * @param {boolean=} selectRecord
845 highlightSearchResult: function(record, regex, selectRecord)
850 * @param {?WebInspector.TimelineSelection} selection
852 setSelection: function(selection)
854 var index = this._dataProvider.entryIndexForSelection(selection);
855 this._mainView.setSelectedEntry(index);
859 * @param {!WebInspector.Event} event
861 _onEntrySelected: function(event)
863 var entryIndex = /** @type{number} */ (event.data);
864 var timelineSelection = this._dataProvider.createSelection(entryIndex);
865 if (timelineSelection)
866 this._delegate.select(timelineSelection);
869 __proto__: WebInspector.VBox.prototype
874 * @param {!WebInspector.TimelineSelection} selection
875 * @param {number} entryIndex
877 WebInspector.TimelineFlameChart.Selection = function(selection, entryIndex)
879 this.timelineSelection = selection;
880 this.entryIndex = entryIndex;