Commit 4e14978a authored by caseq's avatar caseq Committed by Commit bot

Timeline: move SegmentedRange into the WebInspector namespace and a file of its own

... for ease of re-used outside of front-end codebase.

Review URL: https://codereview.chromium.org/1808063002

Cr-Commit-Position: refs/heads/master@{#381789}
parent 5b50b674
......@@ -9,14 +9,13 @@ function test()
{
InspectorTest.addResult("Test case: " + testName);
InspectorTest.addResult("Input Segments: " + JSON.stringify(data));
var range = SegmentedRange(merge);
var forwardRange = new SegmentedRange(merge);
data.map(entry => new Segment(entry[0], entry[1], entry[2])).forEach(forwardRange.append, forwardRange);
var forwardRange = new WebInspector.SegmentedRange(merge);
data.map(entry => new WebInspector.Segment(entry[0], entry[1], entry[2])).forEach(forwardRange.append, forwardRange);
var forward = forwardRange.segments();
var backwardRange = new SegmentedRange(merge);
data.reverse().map(entry => new Segment(entry[0], entry[1], entry[2])).forEach(backwardRange.append, backwardRange);
var backwardRange = new WebInspector.SegmentedRange(merge);
data.reverse().map(entry => new WebInspector.Segment(entry[0], entry[1], entry[2])).forEach(backwardRange.append, backwardRange);
var backward = backwardRange.segments();
// Only do reverse if we merge, otherwise result is order-dependent.
......
......@@ -72,6 +72,7 @@
'front_end/common/Settings.js',
'front_end/common/StaticContentProvider.js',
'front_end/common/OutputStream.js',
'front_end/common/SegmentedRange.js',
'front_end/common/TestBase.js',
'front_end/common/Text.js',
'front_end/common/TextDictionary.js',
......
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* @constructor
* @param {number} begin
* @param {number} end
* @param {*} data
*/
WebInspector.Segment = function(begin, end, data)
{
if (begin > end)
console.assert(false, "Invalid segment");
this.begin = begin;
this.end = end;
this.data = data;
}
WebInspector.Segment.prototype = {
/**
* @param {!WebInspector.Segment} that
* @return {boolean}
*/
intersects: function(that)
{
return this.begin < that.end && that.begin < this.end;
}
};
/**
* @constructor
* @param {(function(!WebInspector.Segment, !WebInspector.Segment): ?WebInspector.Segment)=} mergeCallback
*/
WebInspector.SegmentedRange = function(mergeCallback)
{
/** @type {!Array<!WebInspector.Segment>} */
this._segments = [];
this._mergeCallback = mergeCallback;
}
WebInspector.SegmentedRange.prototype = {
/**
* @param {!WebInspector.Segment} newSegment
*/
append: function(newSegment)
{
// 1. Find the proper insertion point for new segment
var startIndex = this._segments.lowerBound(newSegment, (a, b) => a.begin - b.begin);
var endIndex = startIndex;
var merged = null;
if (startIndex > 0) {
// 2. Try mering the preceding segment
var precedingSegment = this._segments[startIndex - 1];
merged = this._tryMerge(precedingSegment, newSegment);
if (merged) {
--startIndex;
newSegment = merged;
} else if (this._segments[startIndex - 1].end >= newSegment.begin) {
// 2a. If merge failed and segments overlap, adjust preceding segment.
// If an old segment entirely contains new one, split it in two.
if (newSegment.end < precedingSegment.end)
this._segments.splice(startIndex, 0, new WebInspector.Segment(newSegment.end, precedingSegment.end, precedingSegment.data));
precedingSegment.end = newSegment.begin;
}
}
// 3. Consume all segments that are entirely covered by the new one.
while (endIndex < this._segments.length && this._segments[endIndex].end <= newSegment.end)
++endIndex;
// 4. Merge or adjust the succeeding segment if it overlaps.
if (endIndex < this._segments.length) {
merged = this._tryMerge(newSegment, this._segments[endIndex]);
if (merged) {
endIndex++;
newSegment = merged;
} else if (newSegment.intersects(this._segments[endIndex]))
this._segments[endIndex].begin = newSegment.end;
}
this._segments.splice(startIndex, endIndex - startIndex, newSegment);
},
/**
* @param {!WebInspector.SegmentedRange} that
*/
appendRange: function(that)
{
that.segments().forEach(segment => this.append(segment));
},
/**
* @return {!Array<!WebInspector.Segment>}
*/
segments: function()
{
return this._segments;
},
/**
* @param {!WebInspector.Segment} first
* @param {!WebInspector.Segment} second
* @return {?WebInspector.Segment}
*/
_tryMerge: function(first, second)
{
var merged = this._mergeCallback && this._mergeCallback(first, second);
if (!merged)
return null;
merged.begin = first.begin;
merged.end = Math.max(first.end, second.end);
return merged;
}
}
......@@ -18,6 +18,7 @@
"Settings.js",
"StaticContentProvider.js",
"OutputStream.js",
"SegmentedRange.js",
"TestBase.js",
"Text.js",
"TextRange.js",
......
......@@ -1529,112 +1529,3 @@ Promise.prototype.catchException = function(defaultValue) {
return defaultValue;
});
}
/**
* @constructor
* @param {(function(!Segment, !Segment): ?Segment)=} mergeCallback
*/
function SegmentedRange(mergeCallback)
{
/** @type {!Array<!Segment>} */
this._segments = [];
this._mergeCallback = mergeCallback;
}
/**
* @constructor
* @param {number} begin
* @param {number} end
* @param {*} data
*/
function Segment(begin, end, data)
{
if (begin > end)
console.assert(false, "Invalid segment");
this.begin = begin;
this.end = end;
this.data = data;
}
Segment.prototype = {
/**
* @param {!Segment} that
* @return {boolean}
*/
intersects: function(that)
{
return this.begin < that.end && that.begin < this.end;
}
};
SegmentedRange.prototype = {
/**
* @param {!Segment} newSegment
*/
append: function(newSegment)
{
// 1. Find the proper insertion point for new segment
var startIndex = this._segments.lowerBound(newSegment, (a, b) => a.begin - b.begin);
var endIndex = startIndex;
var merged = null;
if (startIndex > 0) {
// 2. Try mering the preceding segment
var precedingSegment = this._segments[startIndex - 1];
merged = this._tryMerge(precedingSegment, newSegment);
if (merged) {
--startIndex;
newSegment = merged;
} else if (this._segments[startIndex - 1].end >= newSegment.begin) {
// 2a. If merge failed and segments overlap, adjust preceding segment.
// If an old segment entirely contains new one, split it in two.
if (newSegment.end < precedingSegment.end)
this._segments.splice(startIndex, 0, new Segment(newSegment.end, precedingSegment.end, precedingSegment.data));
precedingSegment.end = newSegment.begin;
}
}
// 3. Consume all segments that are entirely covered by the new one.
while (endIndex < this._segments.length && this._segments[endIndex].end <= newSegment.end)
++endIndex;
// 4. Merge or adjust the succeeding segment if it overlaps.
if (endIndex < this._segments.length) {
merged = this._tryMerge(newSegment, this._segments[endIndex]);
if (merged) {
endIndex++;
newSegment = merged;
} else if (newSegment.intersects(this._segments[endIndex]))
this._segments[endIndex].begin = newSegment.end;
}
this._segments.splice(startIndex, endIndex - startIndex, newSegment);
},
/**
* @param {!SegmentedRange} that
*/
appendRange: function(that)
{
that.segments().forEach(segment => this.append(segment));
},
/**
* @return {!Array<!Segment>}
*/
segments: function()
{
return this._segments;
},
/**
* @param {!Segment} first
* @param {!Segment} second
* @return {?Segment}
*/
_tryMerge: function(first, second)
{
var merged = this._mergeCallback && this._mergeCallback(first, second);
if (!merged)
return null;
merged.begin = first.begin;
merged.end = Math.max(first.end, second.end);
return merged;
}
}
......@@ -837,7 +837,7 @@ WebInspector.TimelineFlameChartDataProvider.prototype = {
},
/**
* @param {!Segment} segment
* @param {!WebInspector.Segment} segment
*/
_appendSegment: function(segment)
{
......
......@@ -82,7 +82,7 @@ WebInspector.TimelineIRModel.prototype = {
var animations = asyncEventsByGroup.get(groups.animation);
if (animations)
this._processAnimations(animations);
var range = new SegmentedRange();
var range = new WebInspector.SegmentedRange();
range.appendRange(this._drags); // Drags take lower precedence than animation, as we can't detect them reliably.
range.appendRange(this._cssAnimations);
range.appendRange(this._scrolls);
......@@ -129,7 +129,7 @@ WebInspector.TimelineIRModel.prototype = {
// FIXME: also process renderer fling events.
if (!flingStart)
break;
this._scrolls.append(new Segment(flingStart.startTime, event.endTime, phases.Fling));
this._scrolls.append(new WebInspector.Segment(flingStart.startTime, event.endTime, phases.Fling));
flingStart = null;
break;
......@@ -168,7 +168,7 @@ WebInspector.TimelineIRModel.prototype = {
this._drags.append(this._segmentForEvent(event, phases.Drag));
} else if (touchStart) {
firstTouchMove = event;
this._responses.append(new Segment(touchStart.startTime, event.endTime, phases.Response));
this._responses.append(new WebInspector.Segment(touchStart.startTime, event.endTime, phases.Response));
}
break;
......@@ -199,7 +199,7 @@ WebInspector.TimelineIRModel.prototype = {
case eventTypes.MouseWheel:
// Do not consider first MouseWheel as trace viewer's implementation does -- in case of MouseWheel it's not really special.
if (mouseWheel && canMerge(thresholdsMs.mouse, mouseWheel, event))
this._scrolls.append(new Segment(mouseWheel.endTime, event.startTime, phases.Scroll));
this._scrolls.append(new WebInspector.Segment(mouseWheel.endTime, event.startTime, phases.Scroll));
this._scrolls.append(this._segmentForEvent(event, phases.Scroll));
mouseWheel = event;
break;
......@@ -230,15 +230,15 @@ WebInspector.TimelineIRModel.prototype = {
/**
* @param {!WebInspector.TracingModel.AsyncEvent} event
* @param {!WebInspector.TimelineIRModel.Phases} phase
* @return {!Segment}
* @return {!WebInspector.Segment}
*/
_segmentForEvent: function(event, phase)
{
return new Segment(event.startTime, event.endTime, phase);
return new WebInspector.Segment(event.startTime, event.endTime, phase);
},
/**
* @return {!Array<!Segment>}
* @return {!Array<!WebInspector.Segment>}
*/
interactionRecords: function()
{
......@@ -250,15 +250,15 @@ WebInspector.TimelineIRModel.prototype = {
var thresholdsMs = WebInspector.TimelineIRModel._mergeThresholdsMs;
this._segments = [];
this._drags = new SegmentedRange(merge.bind(null, thresholdsMs.mouse));
this._cssAnimations = new SegmentedRange(merge.bind(null, thresholdsMs.animation));
this._responses = new SegmentedRange(merge.bind(null, 0));
this._scrolls = new SegmentedRange(merge.bind(null, thresholdsMs.animation));
this._drags = new WebInspector.SegmentedRange(merge.bind(null, thresholdsMs.mouse));
this._cssAnimations = new WebInspector.SegmentedRange(merge.bind(null, thresholdsMs.animation));
this._responses = new WebInspector.SegmentedRange(merge.bind(null, 0));
this._scrolls = new WebInspector.SegmentedRange(merge.bind(null, thresholdsMs.animation));
/**
* @param {number} threshold
* @param {!Segment} first
* @param {!Segment} second
* @param {!WebInspector.Segment} first
* @param {!WebInspector.Segment} second
*/
function merge(threshold, first, second)
{
......
......@@ -1490,7 +1490,7 @@ WebInspector.FlameChart.prototype = {
*/
_drawCollapsedOverviewForGroup: function(y, startLevel, endLevel)
{
var range = new SegmentedRange(mergeCallback);
var range = new WebInspector.SegmentedRange(mergeCallback);
var timeWindowRight = this._timeWindowRight;
var timeWindowLeft = this._timeWindowLeft - this._paddingLeft / this._timeToPixel;
var context = this._canvas.getContext("2d");
......@@ -1514,7 +1514,7 @@ WebInspector.FlameChart.prototype = {
break;
lastDrawOffset = startPosition;
var color = this._dataProvider.entryColor(entryIndex);
range.append(new Segment(startPosition, this._timeToPositionClipped(entryEndTime), color));
range.append(new WebInspector.Segment(startPosition, this._timeToPositionClipped(entryEndTime), color));
}
}
......@@ -1534,9 +1534,9 @@ WebInspector.FlameChart.prototype = {
context.fill();
/**
* @param {!Segment} a
* @param {!Segment} b
* @return {?Segment}
* @param {!WebInspector.Segment} a
* @param {!WebInspector.Segment} b
* @return {?WebInspector.Segment}
*/
function mergeCallback(a, b)
{
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment