UNPKG

strong-arc

Version:

A visual suite for the StrongLoop API Platform

673 lines (588 loc) 18.2 kB
/* * Copyright (C) 2012 Google Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** * @constructor * @extends {WebInspector.Object} */ WebInspector.TimelineModel = function() { WebInspector.Object.call(this); this._filters = []; } WebInspector.TimelineModel.RecordType = { Root: "Root", Program: "Program", EventDispatch: "EventDispatch", GPUTask: "GPUTask", RequestMainThreadFrame: "RequestMainThreadFrame", BeginFrame: "BeginFrame", ActivateLayerTree: "ActivateLayerTree", DrawFrame: "DrawFrame", ScheduleStyleRecalculation: "ScheduleStyleRecalculation", RecalculateStyles: "RecalculateStyles", InvalidateLayout: "InvalidateLayout", Layout: "Layout", UpdateLayerTree: "UpdateLayerTree", PaintSetup: "PaintSetup", Paint: "Paint", Rasterize: "Rasterize", ScrollLayer: "ScrollLayer", DecodeImage: "DecodeImage", ResizeImage: "ResizeImage", CompositeLayers: "CompositeLayers", ParseHTML: "ParseHTML", TimerInstall: "TimerInstall", TimerRemove: "TimerRemove", TimerFire: "TimerFire", XHRReadyStateChange: "XHRReadyStateChange", XHRLoad: "XHRLoad", EvaluateScript: "EvaluateScript", MarkLoad: "MarkLoad", MarkDOMContent: "MarkDOMContent", MarkFirstPaint: "MarkFirstPaint", TimeStamp: "TimeStamp", ConsoleTime: "ConsoleTime", ResourceSendRequest: "ResourceSendRequest", ResourceReceiveResponse: "ResourceReceiveResponse", ResourceReceivedData: "ResourceReceivedData", ResourceFinish: "ResourceFinish", FunctionCall: "FunctionCall", GCEvent: "GCEvent", JSFrame: "JSFrame", UpdateCounters: "UpdateCounters", RequestAnimationFrame: "RequestAnimationFrame", CancelAnimationFrame: "CancelAnimationFrame", FireAnimationFrame: "FireAnimationFrame", WebSocketCreate : "WebSocketCreate", WebSocketSendHandshakeRequest : "WebSocketSendHandshakeRequest", WebSocketReceiveHandshakeResponse : "WebSocketReceiveHandshakeResponse", WebSocketDestroy : "WebSocketDestroy", EmbedderCallback : "EmbedderCallback", } WebInspector.TimelineModel.Events = { RecordAdded: "RecordAdded", RecordsCleared: "RecordsCleared", RecordingStarted: "RecordingStarted", RecordingStopped: "RecordingStopped", RecordingProgress: "RecordingProgress", RecordFilterChanged: "RecordFilterChanged" } WebInspector.TimelineModel.MainThreadName = "main"; /** * @param {!Array.<!WebInspector.TimelineModel.Record>} recordsArray * @param {?function(!WebInspector.TimelineModel.Record)|?function(!WebInspector.TimelineModel.Record,number)} preOrderCallback * @param {function(!WebInspector.TimelineModel.Record)|function(!WebInspector.TimelineModel.Record,number)=} postOrderCallback * @return {boolean} */ WebInspector.TimelineModel.forAllRecords = function(recordsArray, preOrderCallback, postOrderCallback) { /** * @param {!Array.<!WebInspector.TimelineModel.Record>} records * @param {number} depth * @return {boolean} */ function processRecords(records, depth) { for (var i = 0; i < records.length; ++i) { var record = records[i]; if (preOrderCallback && preOrderCallback(record, depth)) return true; if (processRecords(record.children(), depth + 1)) return true; if (postOrderCallback && postOrderCallback(record, depth)) return true; } return false; } return processRecords(recordsArray, 0); } WebInspector.TimelineModel.prototype = { /** * @param {boolean} captureStacks * @param {boolean} captureMemory * @param {boolean} capturePictures */ startRecording: function(captureStacks, captureMemory, capturePictures) { }, stopRecording: function() { }, /** * @param {?function(!WebInspector.TimelineModel.Record)|?function(!WebInspector.TimelineModel.Record,number)} preOrderCallback * @param {function(!WebInspector.TimelineModel.Record)|function(!WebInspector.TimelineModel.Record,number)=} postOrderCallback */ forAllRecords: function(preOrderCallback, postOrderCallback) { WebInspector.TimelineModel.forAllRecords(this._records, preOrderCallback, postOrderCallback); }, /** * @param {!WebInspector.TimelineModel.Filter} filter */ addFilter: function(filter) { this._filters.push(filter); filter._model = this; }, /** * @param {function(!WebInspector.TimelineModel.Record)|function(!WebInspector.TimelineModel.Record,number)} callback */ forAllFilteredRecords: function(callback) { /** * @param {!WebInspector.TimelineModel.Record} record * @param {number} depth * @this {WebInspector.TimelineModel} * @return {boolean} */ function processRecord(record, depth) { var visible = this.isVisible(record); if (visible) { if (callback(record, depth)) return true; } for (var i = 0; i < record.children().length; ++i) { if (processRecord.call(this, record.children()[i], visible ? depth + 1 : depth)) return true; } return false; } for (var i = 0; i < this._records.length; ++i) processRecord.call(this, this._records[i], 0); }, /** * @param {!WebInspector.TimelineModel.Record} record * @return {boolean} */ isVisible: function(record) { for (var i = 0; i < this._filters.length; ++i) { if (!this._filters[i].accept(record)) return false; } return true; }, _filterChanged: function() { this.dispatchEventToListeners(WebInspector.TimelineModel.Events.RecordFilterChanged); }, /** * @return {!Array.<!WebInspector.TimelineModel.Record>} */ records: function() { return this._records; }, /** * @param {!Blob} file * @param {!WebInspector.Progress} progress */ loadFromFile: function(file, progress) { var delegate = new WebInspector.TimelineModelLoadFromFileDelegate(this, progress); var fileReader = this._createFileReader(file, delegate); var loader = this.createLoader(fileReader, progress); fileReader.start(loader); }, /** * @param {!WebInspector.ChunkedFileReader} fileReader * @param {!WebInspector.Progress} progress * @return {!WebInspector.OutputStream} */ createLoader: function(fileReader, progress) { throw new Error("Not implemented."); }, _createFileReader: function(file, delegate) { return new WebInspector.ChunkedFileReader(file, WebInspector.TimelineModelImpl.TransferChunkLengthBytes, delegate); }, _createFileWriter: function() { return new WebInspector.FileOutputStream(); }, saveToFile: function() { var now = new Date(); var fileName = "TimelineRawData-" + now.toISO8601Compact() + ".json"; var stream = this._createFileWriter(); /** * @param {boolean} accepted * @this {WebInspector.TimelineModel} */ function callback(accepted) { if (!accepted) return; this.writeToStream(stream); } stream.open(fileName, callback.bind(this)); }, /** * @param {!WebInspector.OutputStream} stream */ writeToStream: function(stream) { throw new Error("Not implemented."); }, reset: function() { this._records = []; this._minimumRecordTime = 0; this._maximumRecordTime = 0; /** @type {!Array.<!WebInspector.TimelineModel.Record>} */ this._mainThreadTasks = []; /** @type {!Array.<!WebInspector.TimelineModel.Record>} */ this._gpuThreadTasks = []; /** @type {!Array.<!WebInspector.TimelineModel.Record>} */ this._eventDividerRecords = []; this.dispatchEventToListeners(WebInspector.TimelineModel.Events.RecordsCleared); }, /** * @return {number} */ minimumRecordTime: function() { return this._minimumRecordTime; }, /** * @return {number} */ maximumRecordTime: function() { return this._maximumRecordTime; }, /** * @return {boolean} */ isEmpty: function() { return this.minimumRecordTime() === 0 && this.maximumRecordTime() === 0; }, /** * @param {!WebInspector.TimelineModel.Record} record */ _updateBoundaries: function(record) { var startTime = record.startTime(); var endTime = record.endTime(); if (!this._minimumRecordTime || startTime < this._minimumRecordTime) this._minimumRecordTime = startTime; if (endTime > this._maximumRecordTime) this._maximumRecordTime = endTime; }, /** * @return {!Array.<!WebInspector.TimelineModel.Record>} */ mainThreadTasks: function() { return this._mainThreadTasks; }, /** * @return {!Array.<!WebInspector.TimelineModel.Record>} */ gpuThreadTasks: function() { return this._gpuThreadTasks; }, /** * @return {!Array.<!WebInspector.TimelineModel.Record>} */ eventDividerRecords: function() { return this._eventDividerRecords; }, __proto__: WebInspector.Object.prototype } /** * @interface */ WebInspector.TimelineModel.Record = function() { } WebInspector.TimelineModel.Record.prototype = { /** * @return {?Array.<!ConsoleAgent.CallFrame>} */ callSiteStackTrace: function() { }, /** * @return {?WebInspector.TimelineModel.Record} */ initiator: function() { }, /** * @return {?WebInspector.Target} */ target: function() { }, /** * @return {number} */ selfTime: function() { }, /** * @return {!Array.<!WebInspector.TimelineModel.Record>} */ children: function() { }, /** * @return {number} */ startTime: function() { }, /** * @return {string} */ thread: function() { }, /** * @return {number} */ endTime: function() { }, /** * @param {number} endTime */ setEndTime: function(endTime) { }, /** * @return {!Object} */ data: function() { }, /** * @return {string} */ type: function() { }, /** * @return {string} */ frameId: function() { }, /** * @return {?Array.<!ConsoleAgent.CallFrame>} */ stackTrace: function() { }, /** * @param {string} key * @return {?Object} */ getUserObject: function(key) { }, /** * @param {string} key * @param {?Object|undefined} value */ setUserObject: function(key, value) { }, /** * @return {?Array.<string>} */ warnings: function() { } } /** * @constructor */ WebInspector.TimelineModel.Filter = function() { /** @type {!WebInspector.TimelineModel} */ this._model; } WebInspector.TimelineModel.Filter.prototype = { /** * @param {!WebInspector.TimelineModel.Record} record * @return {boolean} */ accept: function(record) { return true; }, notifyFilterChanged: function() { this._model._filterChanged(); } } /** * @constructor * @extends {WebInspector.TimelineModel.Filter} * @param {!Array.<string>} recordTypes */ WebInspector.TimelineRecordTypeFilter = function(recordTypes) { WebInspector.TimelineModel.Filter.call(this); this._recordTypes = recordTypes.keySet(); } WebInspector.TimelineRecordTypeFilter.prototype = { __proto__: WebInspector.TimelineModel.Filter.prototype } /** * @constructor * @extends {WebInspector.TimelineRecordTypeFilter} * @param {!Array.<string>} recordTypes */ WebInspector.TimelineRecordHiddenEmptyTypeFilter = function(recordTypes) { WebInspector.TimelineRecordTypeFilter.call(this, recordTypes); } WebInspector.TimelineRecordHiddenEmptyTypeFilter.prototype = { /** * @param {!WebInspector.TimelineModel.Record} record * @return {boolean} */ accept: function(record) { return record.children().length !== 0 || !this._recordTypes[record.type()]; }, __proto__: WebInspector.TimelineRecordTypeFilter.prototype } /** * @constructor * @extends {WebInspector.TimelineRecordTypeFilter} * @param {!Array.<string>} recordTypes */ WebInspector.TimelineRecordHiddenTypeFilter = function(recordTypes) { WebInspector.TimelineRecordTypeFilter.call(this, recordTypes); } WebInspector.TimelineRecordHiddenTypeFilter.prototype = { /** * @param {!WebInspector.TimelineModel.Record} record * @return {boolean} */ accept: function(record) { return !this._recordTypes[record.type()]; }, __proto__: WebInspector.TimelineRecordTypeFilter.prototype } /** * @constructor * @extends {WebInspector.TimelineRecordTypeFilter} * @param {!Array.<string>} recordTypes */ WebInspector.TimelineRecordVisibleTypeFilter = function(recordTypes) { WebInspector.TimelineRecordTypeFilter.call(this, recordTypes); } WebInspector.TimelineRecordVisibleTypeFilter.prototype = { /** * @param {!WebInspector.TimelineModel.Record} record * @return {boolean} */ accept: function(record) { return !!this._recordTypes[record.type()]; }, __proto__: WebInspector.TimelineRecordTypeFilter.prototype } /** * @constructor */ WebInspector.TimelineMergingRecordBuffer = function() { this._backgroundRecordsBuffer = []; } /** * @constructor */ WebInspector.TimelineMergingRecordBuffer.prototype = { /** * @param {string} thread * @param {!Array.<!WebInspector.TimelineModel.Record>} records * @return {!Array.<!WebInspector.TimelineModel.Record>} */ process: function(thread, records) { if (thread !== WebInspector.TimelineModel.MainThreadName) { this._backgroundRecordsBuffer = this._backgroundRecordsBuffer.concat(records); return []; } /** * @param {!WebInspector.TimelineModel.Record} a * @param {!WebInspector.TimelineModel.Record} b */ function recordTimestampComparator(a, b) { // Never return 0, as the merge function will squash identical entries. return a.startTime() < b.startTime() ? -1 : 1; } var result = this._backgroundRecordsBuffer.mergeOrdered(records, recordTimestampComparator); this._backgroundRecordsBuffer = []; return result; } } /** * @constructor * @implements {WebInspector.OutputStreamDelegate} * @param {!WebInspector.TimelineModel} model * @param {!WebInspector.Progress} progress */ WebInspector.TimelineModelLoadFromFileDelegate = function(model, progress) { this._model = model; this._progress = progress; } WebInspector.TimelineModelLoadFromFileDelegate.prototype = { onTransferStarted: function() { this._progress.setTitle(WebInspector.UIString("Loading\u2026")); }, /** * @param {!WebInspector.ChunkedReader} reader */ onChunkTransferred: function(reader) { if (this._progress.isCanceled()) { reader.cancel(); this._progress.done(); this._model.reset(); return; } var totalSize = reader.fileSize(); if (totalSize) { this._progress.setTotalWork(totalSize); this._progress.setWorked(reader.loadedSize()); } }, onTransferFinished: function() { this._progress.done(); }, /** * @param {!WebInspector.ChunkedReader} reader * @param {!Event} event */ onError: function(reader, event) { this._progress.done(); this._model.reset(); switch (event.target.error.code) { case FileError.NOT_FOUND_ERR: WebInspector.console.error(WebInspector.UIString("File \"%s\" not found.", reader.fileName())); break; case FileError.NOT_READABLE_ERR: WebInspector.console.error(WebInspector.UIString("File \"%s\" is not readable", reader.fileName())); break; case FileError.ABORT_ERR: break; default: WebInspector.console.error(WebInspector.UIString("An error occurred while reading the file \"%s\"", reader.fileName())); } } }