TimelinePresentationModel.js [plain text]
WebInspector.TimelinePresentationModel = function()
{
this._linkifier = new WebInspector.Linkifier();
this._glueRecords = false;
this._filters = [];
this.reset();
}
WebInspector.TimelinePresentationModel.shortRecordThreshold = 0.015;
WebInspector.TimelinePresentationModel.categories = function()
{
if (WebInspector.TimelinePresentationModel._categories)
return WebInspector.TimelinePresentationModel._categories;
WebInspector.TimelinePresentationModel._categories = {
loading: new WebInspector.TimelineCategory("loading", WebInspector.UIString("Loading"), "rgb(47,102,236)"),
scripting: new WebInspector.TimelineCategory("scripting", WebInspector.UIString("Scripting"), "rgb(157,231,119)"),
rendering: new WebInspector.TimelineCategory("rendering", WebInspector.UIString("Rendering"), "rgb(164,60,255)")
};
return WebInspector.TimelinePresentationModel._categories;
};
WebInspector.TimelinePresentationModel.recordStyle = function(record) {
if (WebInspector.TimelinePresentationModel._recordStylesMap)
return WebInspector.TimelinePresentationModel._recordStylesMap[record.type];
var recordTypes = WebInspector.TimelineModel.RecordType;
var categories = WebInspector.TimelinePresentationModel.categories();
var recordStyles = {};
recordStyles[recordTypes.Root] = { title: "#root", category: categories["loading"] };
recordStyles[recordTypes.EventDispatch] = { title: WebInspector.UIString("Event"), category: categories["scripting"] };
recordStyles[recordTypes.Layout] = { title: WebInspector.UIString("Layout"), category: categories["rendering"] };
recordStyles[recordTypes.RecalculateStyles] = { title: WebInspector.UIString("Recalculate Style"), category: categories["rendering"] };
recordStyles[recordTypes.Paint] = { title: WebInspector.UIString("Paint"), category: categories["rendering"] };
recordStyles[recordTypes.BeginFrame] = { title: WebInspector.UIString("Frame Start"), category: categories["rendering"] };
recordStyles[recordTypes.ParseHTML] = { title: WebInspector.UIString("Parse"), category: categories["loading"] };
recordStyles[recordTypes.TimerInstall] = { title: WebInspector.UIString("Install Timer"), category: categories["scripting"] };
recordStyles[recordTypes.TimerRemove] = { title: WebInspector.UIString("Remove Timer"), category: categories["scripting"] };
recordStyles[recordTypes.TimerFire] = { title: WebInspector.UIString("Timer Fired"), category: categories["scripting"] };
recordStyles[recordTypes.XHRReadyStateChange] = { title: WebInspector.UIString("XHR Ready State Change"), category: categories["scripting"] };
recordStyles[recordTypes.XHRLoad] = { title: WebInspector.UIString("XHR Load"), category: categories["scripting"] };
recordStyles[recordTypes.EvaluateScript] = { title: WebInspector.UIString("Evaluate Script"), category: categories["scripting"] };
recordStyles[recordTypes.TimeStamp] = { title: WebInspector.UIString("Stamp"), category: categories["scripting"] };
recordStyles[recordTypes.ResourceSendRequest] = { title: WebInspector.UIString("Send Request"), category: categories["loading"] };
recordStyles[recordTypes.ResourceReceiveResponse] = { title: WebInspector.UIString("Receive Response"), category: categories["loading"] };
recordStyles[recordTypes.ResourceFinish] = { title: WebInspector.UIString("Finish Loading"), category: categories["loading"] };
recordStyles[recordTypes.FunctionCall] = { title: WebInspector.UIString("Function Call"), category: categories["scripting"] };
recordStyles[recordTypes.ResourceReceivedData] = { title: WebInspector.UIString("Receive Data"), category: categories["loading"] };
recordStyles[recordTypes.GCEvent] = { title: WebInspector.UIString("GC Event"), category: categories["scripting"] };
recordStyles[recordTypes.MarkDOMContent] = { title: WebInspector.UIString("DOMContent event"), category: categories["scripting"] };
recordStyles[recordTypes.MarkLoad] = { title: WebInspector.UIString("Load event"), category: categories["scripting"] };
recordStyles[recordTypes.ScheduleResourceRequest] = { title: WebInspector.UIString("Schedule Request"), category: categories["loading"] };
recordStyles[recordTypes.RequestAnimationFrame] = { title: WebInspector.UIString("Request Animation Frame"), category: categories["scripting"] };
recordStyles[recordTypes.CancelAnimationFrame] = { title: WebInspector.UIString("Cancel Animation Frame"), category: categories["scripting"] };
recordStyles[recordTypes.FireAnimationFrame] = { title: WebInspector.UIString("Animation Frame Fired"), category: categories["scripting"] };
WebInspector.TimelinePresentationModel._recordStylesMap = recordStyles;
return recordStyles[record.type];
}
WebInspector.TimelinePresentationModel.categoryForRecord = function(record)
{
return WebInspector.TimelinePresentationModel.recordStyle(record).category;
}
WebInspector.TimelinePresentationModel.isEventDivider = function(record)
{
var recordTypes = WebInspector.TimelineModel.RecordType;
return record.type === recordTypes.MarkDOMContent || record.type === recordTypes.MarkLoad || record.type === recordTypes.TimeStamp;
}
WebInspector.TimelinePresentationModel.forAllRecords = function(recordsArray, callback)
{
if (!recordsArray)
return;
var stack = [{array: recordsArray, index: 0}];
while (stack.length) {
var entry = stack[stack.length - 1];
var records = entry.array;
if (entry.index < records.length) {
var record = records[entry.index];
if (callback(record))
return;
if (record.children)
stack.push({array: record.children, index: 0});
++entry.index;
} else
stack.pop();
}
}
WebInspector.TimelinePresentationModel.createEventDivider = function(recordType, title)
{
var eventDivider = document.createElement("div");
eventDivider.className = "resources-event-divider";
var recordTypes = WebInspector.TimelineModel.RecordType;
var eventDividerPadding = document.createElement("div");
eventDividerPadding.className = "resources-event-divider-padding";
if (recordType === recordTypes.MarkDOMContent)
eventDivider.className += " resources-blue-divider";
else if (recordType === recordTypes.MarkLoad)
eventDivider.className += " resources-red-divider";
else if (recordType === recordTypes.TimeStamp)
eventDivider.className += " resources-orange-divider";
else if (recordType === recordTypes.BeginFrame)
eventDivider.className += " timeline-frame-divider";
if (title)
eventDividerPadding.title = title;
eventDividerPadding.appendChild(eventDivider);
return eventDividerPadding;
}
WebInspector.TimelinePresentationModel.prototype = {
addFilter: function(filter)
{
this._filters.push(filter);
},
rootRecord: function()
{
return this._rootRecord;
},
frames: function()
{
return this._frames;
},
reset: function()
{
this._linkifier.reset();
this._rootRecord = new WebInspector.TimelinePresentationModel.Record(this, { type: WebInspector.TimelineModel.RecordType.Root }, null, null);
this._sendRequestRecords = {};
this._scheduledResourceRequests = {};
this._timerRecords = {};
this._requestAnimationFrameRecords = {};
this._frames = [];
this._minimumRecordTime = -1;
},
addFrame: function(frame)
{
this._frames.push(frame);
},
addRecord: function(record, parentRecord)
{
var connectedToOldRecord = false;
var recordTypes = WebInspector.TimelineModel.RecordType;
if (this._minimumRecordTime === -1 || record.startTime < this._minimumRecordTime)
this._minimumRecordTime = WebInspector.TimelineModel.startTimeInSeconds(record);
if (record.type === recordTypes.MarkDOMContent || record.type === recordTypes.MarkLoad)
parentRecord = null; else {
var newParentRecord = this._findParentRecord(record);
if (newParentRecord) {
parentRecord = newParentRecord;
connectedToOldRecord = true;
}
}
var children = record.children;
var scriptDetails;
if (record.data && record.data["scriptName"]) {
scriptDetails = {
scriptName: record.data["scriptName"],
scriptLine: record.data["scriptLine"]
}
};
if ((record.type === recordTypes.TimerFire || record.type === recordTypes.FireAnimationFrame) && children && children.length) {
var childRecord = children[0];
if (childRecord.type === recordTypes.FunctionCall) {
scriptDetails = {
scriptName: childRecord.data["scriptName"],
scriptLine: childRecord.data["scriptLine"]
};
children = childRecord.children.concat(children.slice(1));
}
}
var formattedRecord = new WebInspector.TimelinePresentationModel.Record(this, record, parentRecord, scriptDetails);
if (record.type === recordTypes.MarkDOMContent || record.type === recordTypes.MarkLoad)
return formattedRecord;
formattedRecord.collapsed = (parentRecord === this._rootRecord);
var childrenCount = children ? children.length : 0;
for (var i = 0; i < childrenCount; ++i)
this.addRecord(children[i], formattedRecord);
formattedRecord.calculateAggregatedStats(WebInspector.TimelinePresentationModel.categories());
if (connectedToOldRecord) {
record = formattedRecord;
do {
var parent = record.parent;
parent._cpuTime += formattedRecord._cpuTime;
if (parent.lastChildEndTime < record.lastChildEndTime)
parent.lastChildEndTime = record.lastChildEndTime;
for (var category in formattedRecord.aggregatedStats)
parent.aggregatedStats[category] += formattedRecord.aggregatedStats[category];
record = parent;
} while (record.parent);
} else {
if (parentRecord !== this._rootRecord)
parentRecord.selfTime -= formattedRecord.endTime - formattedRecord.startTime;
}
return formattedRecord;
},
_findParentRecord: function(record)
{
if (!this._glueRecords)
return null;
var recordTypes = WebInspector.TimelineModel.RecordType;
var parentRecord;
if (record.type === recordTypes.ResourceReceiveResponse ||
record.type === recordTypes.ResourceFinish ||
record.type === recordTypes.ResourceReceivedData)
parentRecord = this._sendRequestRecords[record.data["requestId"]];
else if (record.type === recordTypes.TimerFire)
parentRecord = this._timerRecords[record.data["timerId"]];
else if (record.type === recordTypes.ResourceSendRequest)
parentRecord = this._scheduledResourceRequests[record.data["url"]];
else if (record.type === recordTypes.FireAnimationFrame)
parentRecord = this._requestAnimationFrameRecords[record.data["id"]];
return parentRecord;
},
setGlueRecords: function(glue)
{
this._glueRecords = glue;
},
filteredRecords: function()
{
function filter(record)
{
for (var i = 0; i < this._filters.length; ++i) {
if (!this._filters[i].accept(record))
return false;
}
return true;
}
return this._filterRecords(filter.bind(this));
},
_filterRecords: function(filter)
{
var recordsInWindow = [];
var stack = [{children: this._rootRecord.children, index: 0, parentIsCollapsed: false}];
while (stack.length) {
var entry = stack[stack.length - 1];
var records = entry.children;
if (records && entry.index < records.length) {
var record = records[entry.index];
++entry.index;
if (filter(record)) {
++record.parent._invisibleChildrenCount;
if (!entry.parentIsCollapsed)
recordsInWindow.push(record);
}
record._invisibleChildrenCount = 0;
stack.push({children: record.children,
index: 0,
parentIsCollapsed: (entry.parentIsCollapsed || record.collapsed),
parentRecord: record,
windowLengthBeforeChildrenTraversal: recordsInWindow.length});
} else {
stack.pop();
if (entry.parentRecord)
entry.parentRecord._visibleChildrenCount = recordsInWindow.length - entry.windowLengthBeforeChildrenTraversal;
}
}
return recordsInWindow;
}
}
WebInspector.TimelinePresentationModel.prototype.__proto__ = WebInspector.Object.prototype;
WebInspector.TimelinePresentationModel.Record = function(presentationModel, record, parentRecord, scriptDetails)
{
this._presentationModel = presentationModel;
this._linkifier = this._presentationModel._linkifier;
this._aggregatedStats = [];
var recordTypes = WebInspector.TimelineModel.RecordType;
var style = WebInspector.TimelinePresentationModel.recordStyle(record);
this.parent = parentRecord;
if (parentRecord)
parentRecord.children.push(this);
this.category = style.category;
this.title = record.type === recordTypes.TimeStamp ? record.data["message"] : style.title;
this.startTime = WebInspector.TimelineModel.startTimeInSeconds(record);
this.data = record.data;
this.type = record.type;
this.endTime = WebInspector.TimelineModel.endTimeInSeconds(record);
this._selfTime = this.endTime - this.startTime;
this._lastChildEndTime = this.endTime;
this._initiatorOffset = (parentRecord && parentRecord !== presentationModel._rootRecord) ?
parentRecord._initiatorOffset + this.startTime - parentRecord.startTime : 0;
this._startTimeOffset = this.startTime - presentationModel._minimumRecordTime;
if (record.stackTrace && record.stackTrace.length)
this.stackTrace = record.stackTrace;
this.totalHeapSize = record.totalHeapSize;
this.usedHeapSize = record.usedHeapSize;
if (record.data && record.data["url"])
this.url = record.data["url"];
if (scriptDetails) {
this.scriptName = scriptDetails.scriptName;
this.scriptLine = scriptDetails.scriptLine;
}
if (record.type === recordTypes.ResourceSendRequest) {
presentationModel._sendRequestRecords[record.data["requestId"]] = this;
} else if (record.type === recordTypes.ScheduleResourceRequest) {
presentationModel._scheduledResourceRequests[record.data["url"]] = this;
} else if (record.type === recordTypes.ResourceReceiveResponse) {
var sendRequestRecord = presentationModel._sendRequestRecords[record.data["requestId"]];
if (sendRequestRecord) { this.url = sendRequestRecord.url;
sendRequestRecord._refreshDetails();
if (sendRequestRecord.parent !== presentationModel._rootRecord && sendRequestRecord.parent.type === recordTypes.ScheduleResourceRequest)
sendRequestRecord.parent._refreshDetails();
}
} else if (record.type === recordTypes.ResourceReceivedData || record.type === recordTypes.ResourceFinish) {
var sendRequestRecord = presentationModel._sendRequestRecords[record.data["requestId"]];
if (sendRequestRecord) this.url = sendRequestRecord.url;
} else if (record.type === recordTypes.TimerInstall) {
this.timeout = record.data["timeout"];
this.singleShot = record.data["singleShot"];
presentationModel._timerRecords[record.data["timerId"]] = this;
} else if (record.type === recordTypes.TimerFire) {
var timerInstalledRecord = presentationModel._timerRecords[record.data["timerId"]];
if (timerInstalledRecord) {
this.callSiteStackTrace = timerInstalledRecord.stackTrace;
this.timeout = timerInstalledRecord.timeout;
this.singleShot = timerInstalledRecord.singleShot;
}
} else if (record.type === recordTypes.RequestAnimationFrame) {
presentationModel._requestAnimationFrameRecords[record.data["id"]] = this;
} else if (record.type === recordTypes.FireAnimationFrame) {
var requestAnimationRecord = presentationModel._requestAnimationFrameRecords[record.data["id"]];
if (requestAnimationRecord)
this.callSiteStackTrace = requestAnimationRecord.stackTrace;
}
this._refreshDetails();
}
WebInspector.TimelinePresentationModel.Record.prototype = {
get lastChildEndTime()
{
return this._lastChildEndTime;
},
set lastChildEndTime(time)
{
this._lastChildEndTime = time;
},
get selfTime()
{
return this._selfTime;
},
set selfTime(time)
{
this._selfTime = time;
},
get cpuTime()
{
return this._cpuTime;
},
isLong: function()
{
return (this._lastChildEndTime - this.startTime) > WebInspector.TimelinePresentationModel.shortRecordThreshold;
},
get children()
{
if (!this._children)
this._children = [];
return this._children;
},
get visibleChildrenCount()
{
return this._visibleChildrenCount || 0;
},
get invisibleChildrenCount()
{
return this._invisibleChildrenCount || 0;
},
containsTime: function(time)
{
return this.startTime <= time && time <= this.endTime;
},
generatePopupContent: function()
{
var contentHelper = new WebInspector.TimelinePresentationModel.PopupContentHelper(this.title);
if (this._children && this._children.length) {
contentHelper._appendTextRow(WebInspector.UIString("Self Time"), Number.secondsToString(this._selfTime, true));
contentHelper._appendElementRow(WebInspector.UIString("Aggregated Time"),
WebInspector.TimelinePresentationModel._generateAggregatedInfo(this._aggregatedStats));
}
var text = WebInspector.UIString("%s (at %s)", Number.secondsToString(this._lastChildEndTime - this.startTime, true),
Number.secondsToString(this._startTimeOffset));
contentHelper._appendTextRow(WebInspector.UIString("Duration"), text);
const recordTypes = WebInspector.TimelineModel.RecordType;
switch (this.type) {
case recordTypes.GCEvent:
contentHelper._appendTextRow(WebInspector.UIString("Collected"), Number.bytesToString(this.data["usedHeapSizeDelta"]));
break;
case recordTypes.TimerInstall:
case recordTypes.TimerFire:
case recordTypes.TimerRemove:
contentHelper._appendTextRow(WebInspector.UIString("Timer ID"), this.data["timerId"]);
if (typeof this.timeout === "number") {
contentHelper._appendTextRow(WebInspector.UIString("Timeout"), Number.secondsToString(this.timeout / 1000));
contentHelper._appendTextRow(WebInspector.UIString("Repeats"), !this.singleShot);
}
break;
case recordTypes.FireAnimationFrame:
contentHelper._appendTextRow(WebInspector.UIString("Callback ID"), this.data["id"]);
break;
case recordTypes.FunctionCall:
contentHelper._appendElementRow(WebInspector.UIString("Location"), this._linkifyScriptLocation());
break;
case recordTypes.ScheduleResourceRequest:
case recordTypes.ResourceSendRequest:
case recordTypes.ResourceReceiveResponse:
case recordTypes.ResourceReceivedData:
case recordTypes.ResourceFinish:
contentHelper._appendElementRow(WebInspector.UIString("Resource"), this._linkifyLocation(this.url));
if (this.data["requestMethod"])
contentHelper._appendTextRow(WebInspector.UIString("Request Method"), this.data["requestMethod"]);
if (typeof this.data["statusCode"] === "number")
contentHelper._appendTextRow(WebInspector.UIString("Status Code"), this.data["statusCode"]);
if (this.data["mimeType"])
contentHelper._appendTextRow(WebInspector.UIString("MIME Type"), this.data["mimeType"]);
break;
case recordTypes.EvaluateScript:
if (this.data && this.url)
contentHelper._appendElementRow(WebInspector.UIString("Script"), this._linkifyLocation(this.url, this.data["lineNumber"]));
break;
case recordTypes.Paint:
contentHelper._appendTextRow(WebInspector.UIString("Location"), WebInspector.UIString("(%d, %d)", this.data["x"], this.data["y"]));
contentHelper._appendTextRow(WebInspector.UIString("Dimensions"), WebInspector.UIString("%d × %d", this.data["width"], this.data["height"]));
case recordTypes.RecalculateStyles: break;
default:
if (this.details)
contentHelper._appendTextRow(WebInspector.UIString("Details"), this.details);
break;
}
if (this.scriptName && this.type !== recordTypes.FunctionCall)
contentHelper._appendElementRow(WebInspector.UIString("Function Call"), this._linkifyScriptLocation());
if (this.usedHeapSize)
contentHelper._appendTextRow(WebInspector.UIString("Used Heap Size"), WebInspector.UIString("%s of %s", Number.bytesToString(this.usedHeapSize), Number.bytesToString(this.totalHeapSize)));
if (this.callSiteStackTrace && this.callSiteStackTrace.length)
contentHelper._appendStackTrace(WebInspector.UIString("Call Site stack"), this.callSiteStackTrace, this._linkifyCallFrame.bind(this));
if (this.stackTrace)
contentHelper._appendStackTrace(WebInspector.UIString("Call Stack"), this.stackTrace, this._linkifyCallFrame.bind(this));
return contentHelper._contentTable;
},
_refreshDetails: function()
{
this.details = this._getRecordDetails();
},
_getRecordDetails: function()
{
switch (this.type) {
case WebInspector.TimelineModel.RecordType.GCEvent:
return WebInspector.UIString("%s collected", Number.bytesToString(this.data["usedHeapSizeDelta"]));
case WebInspector.TimelineModel.RecordType.TimerFire:
return this._linkifyScriptLocation(this.data["timerId"]);
case WebInspector.TimelineModel.RecordType.FunctionCall:
return this._linkifyScriptLocation();
case WebInspector.TimelineModel.RecordType.FireAnimationFrame:
return this._linkifyScriptLocation(this.data["id"]);
case WebInspector.TimelineModel.RecordType.EventDispatch:
return this.data ? this.data["type"] : null;
case WebInspector.TimelineModel.RecordType.Paint:
return this.data["width"] + "\u2009\u00d7\u2009" + this.data["height"];
case WebInspector.TimelineModel.RecordType.TimerInstall:
case WebInspector.TimelineModel.RecordType.TimerRemove:
return this._linkifyTopCallFrame(this.data["timerId"]);
case WebInspector.TimelineModel.RecordType.RequestAnimationFrame:
case WebInspector.TimelineModel.RecordType.CancelAnimationFrame:
return this._linkifyTopCallFrame(this.data["id"]);
case WebInspector.TimelineModel.RecordType.ParseHTML:
case WebInspector.TimelineModel.RecordType.RecalculateStyles:
return this._linkifyTopCallFrame();
case WebInspector.TimelineModel.RecordType.EvaluateScript:
return this.url ? this._linkifyLocation(this.url, this.data["lineNumber"], 0) : null;
case WebInspector.TimelineModel.RecordType.XHRReadyStateChange:
case WebInspector.TimelineModel.RecordType.XHRLoad:
case WebInspector.TimelineModel.RecordType.ScheduleResourceRequest:
case WebInspector.TimelineModel.RecordType.ResourceSendRequest:
case WebInspector.TimelineModel.RecordType.ResourceReceivedData:
case WebInspector.TimelineModel.RecordType.ResourceReceiveResponse:
case WebInspector.TimelineModel.RecordType.ResourceFinish:
return WebInspector.displayNameForURL(this.url);
case WebInspector.TimelineModel.RecordType.TimeStamp:
return this.data["message"];
default:
return null;
}
},
_linkifyLocation: function(url, lineNumber, columnNumber)
{
lineNumber = lineNumber ? lineNumber - 1 : lineNumber;
columnNumber = columnNumber ? columnNumber - 1 : 0;
return this._linkifier.linkifyLocation(url, lineNumber, columnNumber, "timeline-details");
},
_linkifyCallFrame: function(callFrame)
{
return this._linkifyLocation(callFrame.url, callFrame.lineNumber, callFrame.columnNumber);
},
_linkifyTopCallFrame: function(defaultValue)
{
return this.stackTrace ? this._linkifyCallFrame(this.stackTrace[0]) : defaultValue;
},
_linkifyScriptLocation: function(defaultValue)
{
return this.scriptName ? this._linkifyLocation(this.scriptName, this.scriptLine, 0) : defaultValue;
},
calculateAggregatedStats: function(categories)
{
this._aggregatedStats = {};
for (var category in categories)
this._aggregatedStats[category] = 0;
this._cpuTime = this._selfTime;
if (this._children) {
for (var index = this._children.length; index; --index) {
var child = this._children[index - 1];
for (var category in categories)
this._aggregatedStats[category] += child._aggregatedStats[category];
}
for (var category in this._aggregatedStats)
this._cpuTime += this._aggregatedStats[category];
}
this._aggregatedStats[this.category.name] += this._selfTime;
},
get aggregatedStats()
{
return this._aggregatedStats;
}
}
WebInspector.TimelinePresentationModel._generateAggregatedInfo = function(aggregatedStats)
{
var cell = document.createElement("span");
cell.className = "timeline-aggregated-info";
for (var index in aggregatedStats) {
var label = document.createElement("div");
label.className = "timeline-aggregated-category timeline-" + index;
cell.appendChild(label);
var text = document.createElement("span");
text.textContent = Number.secondsToString(aggregatedStats[index], true);
cell.appendChild(text);
}
return cell;
}
WebInspector.TimelinePresentationModel.PopupContentHelper = function(title)
{
this._contentTable = document.createElement("table");
var titleCell = this._createCell(WebInspector.UIString("%s - Details", title), "timeline-details-title");
titleCell.colSpan = 2;
var titleRow = document.createElement("tr");
titleRow.appendChild(titleCell);
this._contentTable.appendChild(titleRow);
}
WebInspector.TimelinePresentationModel.PopupContentHelper.prototype = {
_createCell: function(content, styleName)
{
var text = document.createElement("label");
text.appendChild(document.createTextNode(content));
var cell = document.createElement("td");
cell.className = "timeline-details";
if (styleName)
cell.className += " " + styleName;
cell.textContent = content;
return cell;
},
_appendTextRow: function(title, content)
{
var row = document.createElement("tr");
row.appendChild(this._createCell(title, "timeline-details-row-title"));
row.appendChild(this._createCell(content, "timeline-details-row-data"));
this._contentTable.appendChild(row);
},
_appendElementRow: function(title, content, titleStyle)
{
var row = document.createElement("tr");
var titleCell = this._createCell(title, "timeline-details-row-title");
if (titleStyle)
titleCell.addStyleClass(titleStyle);
row.appendChild(titleCell);
var cell = document.createElement("td");
cell.className = "timeline-details";
cell.appendChild(content);
row.appendChild(cell);
this._contentTable.appendChild(row);
},
_appendStackTrace: function(title, stackTrace, callFrameLinkifier)
{
this._appendTextRow("", "");
var framesTable = document.createElement("table");
for (var i = 0; i < stackTrace.length; ++i) {
var stackFrame = stackTrace[i];
var row = document.createElement("tr");
row.className = "timeline-details";
row.appendChild(this._createCell(stackFrame.functionName ? stackFrame.functionName : WebInspector.UIString("(anonymous function)"), "timeline-function-name"));
row.appendChild(this._createCell(" @ "));
var linkCell = document.createElement("td");
var urlElement = callFrameLinkifier(stackFrame);
linkCell.appendChild(urlElement);
row.appendChild(linkCell);
framesTable.appendChild(row);
}
this._appendElementRow(title, framesTable, "timeline-stacktrace-title");
}
}
WebInspector.TimelinePresentationModel.generatePopupContentForFrame = function(frame)
{
var contentHelper = new WebInspector.TimelinePresentationModel.PopupContentHelper(WebInspector.UIString("Frame"));
var durationInSeconds = frame.endTime - frame.startTime;
var durationText = WebInspector.UIString("%s (at %s)", Number.secondsToString(frame.endTime - frame.startTime, true),
Number.secondsToString(frame.startTimeOffset, true));
contentHelper._appendTextRow(WebInspector.UIString("Duration"), durationText);
contentHelper._appendTextRow(WebInspector.UIString("FPS"), Math.floor(1 / durationInSeconds));
contentHelper._appendTextRow(WebInspector.UIString("CPU time"), Number.secondsToString(frame.cpuTime, true));
contentHelper._appendElementRow(WebInspector.UIString("Aggregated Time"),
WebInspector.TimelinePresentationModel._generateAggregatedInfo(frame.timeByCategory));
return contentHelper._contentTable;
}
WebInspector.TimelinePresentationModel.Filter = function()
{
}
WebInspector.TimelinePresentationModel.Filter.prototype = {
accept: function(record) { return false; }
}
WebInspector.TimelineCategory = function(name, title, color)
{
this.name = name;
this.title = title;
this.color = color;
this.hidden = false;
}
WebInspector.TimelineCategory.Events = {
VisibilityChanged: "VisibilityChanged"
};
WebInspector.TimelineCategory.prototype = {
get hidden()
{
return this._hidden;
},
set hidden(hidden)
{
this._hidden = hidden;
this.dispatchEventToListeners(WebInspector.TimelineCategory.Events.VisibilityChanged, this);
}
}
WebInspector.TimelineCategory.prototype.__proto__ = WebInspector.Object.prototype;