| Index: third_party/WebKit/Source/devtools/front_end/coverage/CoverageModel.js
|
| diff --git a/third_party/WebKit/Source/devtools/front_end/coverage/CoverageModel.js b/third_party/WebKit/Source/devtools/front_end/coverage/CoverageModel.js
|
| index 8f339c9245527c394648340d5ea394704e677e3e..c322243d472cd73b3923800e79312cbd5ebfe1ee 100644
|
| --- a/third_party/WebKit/Source/devtools/front_end/coverage/CoverageModel.js
|
| +++ b/third_party/WebKit/Source/devtools/front_end/coverage/CoverageModel.js
|
| @@ -28,6 +28,8 @@ Coverage.CoverageModel = class extends SDK.SDKModel {
|
|
|
| /** @type {!Map<string, !Coverage.URLCoverageInfo>} */
|
| this._coverageByURL = new Map();
|
| + /** @type {!Map<!Common.ContentProvider, !Coverage.CoverageInfo>} */
|
| + this._coverageByContentProvider = new Map();
|
| }
|
|
|
| /**
|
| @@ -36,33 +38,66 @@ Coverage.CoverageModel = class extends SDK.SDKModel {
|
| start() {
|
| this._coverageByURL.clear();
|
| if (this._cssModel)
|
| - this._cssModel.startRuleUsageTracking();
|
| + this._cssModel.startCoverage();
|
| if (this._cpuProfilerModel)
|
| this._cpuProfilerModel.startPreciseCoverage();
|
| return !!(this._cssModel || this._cpuProfilerModel);
|
| }
|
|
|
| /**
|
| - * @return {!Promise<!Array<!Coverage.URLCoverageInfo>>}
|
| + * @return {!Promise<!Array<!Coverage.CoverageInfo>>}
|
| */
|
| - async stop() {
|
| - await Promise.all([this._stopCSSCoverage(), this._stopJSCoverage()]);
|
| + stop() {
|
| + var pollPromise = this.poll();
|
| + if (this._cpuProfilerModel)
|
| + this._cpuProfilerModel.stopPreciseCoverage();
|
| + if (this._cssModel)
|
| + this._cssModel.stopCoverage();
|
| + return pollPromise;
|
| + }
|
| +
|
| + /**
|
| + * @return {!Promise<!Array<!Coverage.CoverageInfo>>}
|
| + */
|
| + async poll() {
|
| + var updates = await Promise.all([this._takeCSSCoverage(), this._takeJSCoverage()]);
|
| + return updates[0].concat(updates[1]);
|
| + }
|
| +
|
| + /**
|
| + * @return {!Array<!Coverage.URLCoverageInfo>}
|
| + */
|
| + entries() {
|
| return Array.from(this._coverageByURL.values());
|
| }
|
|
|
| - async _stopJSCoverage() {
|
| + /**
|
| + * @param {!Common.ContentProvider} contentProvider
|
| + * @param {number} startOffset
|
| + * @param {number} endOffset
|
| + * @return {boolean|undefined}
|
| + */
|
| + usageForRange(contentProvider, startOffset, endOffset) {
|
| + var coverageInfo = this._coverageByContentProvider.get(contentProvider);
|
| + return coverageInfo && coverageInfo.usageForRange(startOffset, endOffset);
|
| + }
|
| +
|
| + /**
|
| + * @return {!Promise<!Array<!Coverage.CoverageInfo>>}
|
| + */
|
| + async _takeJSCoverage() {
|
| if (!this._cpuProfilerModel)
|
| - return;
|
| - var coveragePromise = this._cpuProfilerModel.takePreciseCoverage();
|
| - this._cpuProfilerModel.stopPreciseCoverage();
|
| - var rawCoverageData = await coveragePromise;
|
| - this._processJSCoverage(rawCoverageData);
|
| + return [];
|
| + var rawCoverageData = await this._cpuProfilerModel.takePreciseCoverage();
|
| + return this._processJSCoverage(rawCoverageData);
|
| }
|
|
|
| /**
|
| * @param {!Array<!Protocol.Profiler.ScriptCoverage>} scriptsCoverage
|
| + * @return {!Array<!Coverage.CoverageInfo>}
|
| */
|
| _processJSCoverage(scriptsCoverage) {
|
| + var updatedEntries = [];
|
| for (var entry of scriptsCoverage) {
|
| var script = this._debuggerModel.scriptForId(entry.scriptId);
|
| if (!script)
|
| @@ -72,8 +107,52 @@ Coverage.CoverageModel = class extends SDK.SDKModel {
|
| for (var range of func.ranges)
|
| ranges.push(range);
|
| }
|
| - this._addCoverage(script, script.contentLength, script.lineOffset, script.columnOffset, ranges);
|
| + var entry = this._addCoverage(script, script.contentLength, script.lineOffset, script.columnOffset, ranges);
|
| + if (entry)
|
| + updatedEntries.push(entry);
|
| }
|
| + return updatedEntries;
|
| + }
|
| +
|
| + /**
|
| + * @return {!Promise<!Array<!Coverage.CoverageInfo>>}
|
| + */
|
| + async _takeCSSCoverage() {
|
| + if (!this._cssModel)
|
| + return [];
|
| + var rawCoverageData = await this._cssModel.takeCoverageDelta();
|
| + return this._processCSSCoverage(rawCoverageData);
|
| + }
|
| +
|
| + /**
|
| + * @param {!Array<!Protocol.CSS.RuleUsage>} ruleUsageList
|
| + * @return {!Array<!Coverage.CoverageInfo>}
|
| + */
|
| + _processCSSCoverage(ruleUsageList) {
|
| + var updatedEntries = [];
|
| + /** @type {!Map<!SDK.CSSStyleSheetHeader, !Array<!Coverage.RangeUseCount>>} */
|
| + var rulesByStyleSheet = new Map();
|
| + for (var rule of ruleUsageList) {
|
| + var styleSheetHeader = this._cssModel.styleSheetHeaderForId(rule.styleSheetId);
|
| + if (!styleSheetHeader)
|
| + continue;
|
| + var ranges = rulesByStyleSheet.get(styleSheetHeader);
|
| + if (!ranges) {
|
| + ranges = [];
|
| + rulesByStyleSheet.set(styleSheetHeader, ranges);
|
| + }
|
| + ranges.push({startOffset: rule.startOffset, endOffset: rule.endOffset, count: Number(rule.used)});
|
| + }
|
| + for (var entry of rulesByStyleSheet) {
|
| + var styleSheetHeader = /** @type {!SDK.CSSStyleSheetHeader} */ (entry[0]);
|
| + var ranges = /** @type {!Array<!Coverage.RangeUseCount>} */ (entry[1]);
|
| + var entry = this._addCoverage(
|
| + styleSheetHeader, styleSheetHeader.contentLength, styleSheetHeader.startLine, styleSheetHeader.startColumn,
|
| + ranges);
|
| + if (entry)
|
| + updatedEntries.push(entry);
|
| + }
|
| + return updatedEntries;
|
| }
|
|
|
| /**
|
| @@ -121,60 +200,34 @@ Coverage.CoverageModel = class extends SDK.SDKModel {
|
| return result;
|
| }
|
|
|
| - async _stopCSSCoverage() {
|
| - if (!this._cssModel)
|
| - return [];
|
| -
|
| - var rawCoverageData = await this._cssModel.ruleListPromise();
|
| - this._processCSSCoverage(rawCoverageData);
|
| - }
|
| -
|
| - /**
|
| - * @param {!Array<!Protocol.CSS.RuleUsage>} ruleUsageList
|
| - */
|
| - _processCSSCoverage(ruleUsageList) {
|
| - /** @type {!Map<!SDK.CSSStyleSheetHeader, !Array<!Coverage.RangeUseCount>>} */
|
| - var rulesByStyleSheet = new Map();
|
| - for (var rule of ruleUsageList) {
|
| - var styleSheetHeader = this._cssModel.styleSheetHeaderForId(rule.styleSheetId);
|
| - if (!styleSheetHeader)
|
| - continue;
|
| - var ranges = rulesByStyleSheet.get(styleSheetHeader);
|
| - if (!ranges) {
|
| - ranges = [];
|
| - rulesByStyleSheet.set(styleSheetHeader, ranges);
|
| - }
|
| - ranges.push({startOffset: rule.startOffset, endOffset: rule.endOffset, count: Number(rule.used)});
|
| - }
|
| - for (var entry of rulesByStyleSheet) {
|
| - var styleSheetHeader = /** @type {!SDK.CSSStyleSheetHeader} */ (entry[0]);
|
| - var ranges = /** @type {!Array<!Coverage.RangeUseCount>} */ (entry[1]);
|
| - this._addCoverage(
|
| - styleSheetHeader, styleSheetHeader.contentLength, styleSheetHeader.startLine, styleSheetHeader.startColumn,
|
| - ranges);
|
| - }
|
| - }
|
| -
|
| /**
|
| * @param {!Common.ContentProvider} contentProvider
|
| * @param {number} contentLength
|
| * @param {number} startLine
|
| * @param {number} startColumn
|
| * @param {!Array<!Coverage.RangeUseCount>} ranges
|
| + * @return {?Coverage.CoverageInfo}
|
| */
|
| _addCoverage(contentProvider, contentLength, startLine, startColumn, ranges) {
|
| var url = contentProvider.contentURL();
|
| if (!url)
|
| - return;
|
| - var entry = this._coverageByURL.get(url);
|
| - if (!entry) {
|
| - entry = new Coverage.URLCoverageInfo(url);
|
| - this._coverageByURL.set(url, entry);
|
| + return null;
|
| + var urlCoverage = this._coverageByURL.get(url);
|
| + if (!urlCoverage) {
|
| + urlCoverage = new Coverage.URLCoverageInfo(url);
|
| + this._coverageByURL.set(url, urlCoverage);
|
| }
|
| + var coverageInfo = urlCoverage._ensureEntry(contentProvider, contentLength, startLine, startColumn);
|
| + this._coverageByContentProvider.set(contentProvider, coverageInfo);
|
| var segments = Coverage.CoverageModel._convertToDisjointSegments(ranges);
|
| if (segments.length && segments.peekLast().end < contentLength)
|
| segments.push({end: contentLength});
|
| - entry.update(contentProvider, contentLength, startLine, startColumn, segments);
|
| + var oldUsedSize = coverageInfo._usedSize;
|
| + coverageInfo.mergeCoverage(segments);
|
| + if (coverageInfo._usedSize === oldUsedSize)
|
| + return null;
|
| + urlCoverage._usedSize += coverageInfo._usedSize - oldUsedSize;
|
| + return coverageInfo;
|
| }
|
| };
|
|
|
| @@ -193,28 +246,6 @@ Coverage.URLCoverageInfo = class {
|
| }
|
|
|
| /**
|
| - * @param {!Common.ContentProvider} contentProvider
|
| - * @param {number} contentLength
|
| - * @param {number} lineOffset
|
| - * @param {number} columnOffset
|
| - * @param {!Array<!Coverage.CoverageSegment>} segments
|
| - */
|
| - update(contentProvider, contentLength, lineOffset, columnOffset, segments) {
|
| - var key = `${lineOffset}:${columnOffset}`;
|
| - var entry = this._coverageInfoByLocation.get(key);
|
| -
|
| - if (!entry) {
|
| - entry = new Coverage.CoverageInfo(contentProvider, lineOffset, columnOffset);
|
| - this._coverageInfoByLocation.set(key, entry);
|
| - this._size += contentLength;
|
| - this._type |= entry.type();
|
| - }
|
| - this._usedSize -= entry._usedSize;
|
| - entry.mergeCoverage(segments);
|
| - this._usedSize += entry._usedSize;
|
| - }
|
| -
|
| - /**
|
| * @return {string}
|
| */
|
| url() {
|
| @@ -250,14 +281,23 @@ Coverage.URLCoverageInfo = class {
|
| }
|
|
|
| /**
|
| - * @return {!Promise<!Array<!{range: !TextUtils.TextRange, count: number}>>}
|
| + * @param {!Common.ContentProvider} contentProvider
|
| + * @param {number} contentLength
|
| + * @param {number} lineOffset
|
| + * @param {number} columnOffset
|
| + * @return {!Coverage.CoverageInfo}
|
| */
|
| - async buildTextRanges() {
|
| - var textRangePromises = [];
|
| - for (var coverageInfo of this._coverageInfoByLocation.values())
|
| - textRangePromises.push(coverageInfo.buildTextRanges());
|
| - var allTextRanges = await Promise.all(textRangePromises);
|
| - return [].concat(...allTextRanges);
|
| + _ensureEntry(contentProvider, contentLength, lineOffset, columnOffset) {
|
| + var key = `${lineOffset}:${columnOffset}`;
|
| + var entry = this._coverageInfoByLocation.get(key);
|
| +
|
| + if (!entry) {
|
| + entry = new Coverage.CoverageInfo(contentProvider, lineOffset, columnOffset);
|
| + this._coverageInfoByLocation.set(key, entry);
|
| + this._size += contentLength;
|
| + this._type |= entry.type();
|
| + }
|
| + return entry;
|
| }
|
| };
|
|
|
| @@ -286,6 +326,20 @@ Coverage.CoverageInfo = class {
|
| }
|
|
|
| /**
|
| + * @return {!Common.ContentProvider}
|
| + */
|
| + contentProvider() {
|
| + return this._contentProvider;
|
| + }
|
| +
|
| + /**
|
| + * @return {string}
|
| + */
|
| + url() {
|
| + return this._contentProvider.contentURL();
|
| + }
|
| +
|
| + /**
|
| * @return {!Coverage.CoverageType}
|
| */
|
| type() {
|
| @@ -301,6 +355,20 @@ Coverage.CoverageInfo = class {
|
| }
|
|
|
| /**
|
| + * @param {number} start
|
| + * @param {number} end
|
| + * @return {boolean}
|
| + */
|
| + usageForRange(start, end) {
|
| + var index = this._segments.upperBound(start, (position, segment) => position - segment.end);
|
| + for (; index < this._segments.length && this._segments[index].end < end; ++index) {
|
| + if (this._segments[index].count)
|
| + return true;
|
| + }
|
| + return index < this._segments.length && this._segments[index].count;
|
| + }
|
| +
|
| + /**
|
| * @param {!Array<!Coverage.CoverageSegment>} segmentsA
|
| * @param {!Array<!Coverage.CoverageSegment>} segmentsB
|
| */
|
| @@ -333,35 +401,6 @@ Coverage.CoverageInfo = class {
|
| return result;
|
| }
|
|
|
| - /**
|
| - * @return {!Promise<!Array<!{range: !TextUtils.TextRange, count: number}>>}
|
| - */
|
| - async buildTextRanges() {
|
| - var contents = await this._contentProvider.requestContent();
|
| - if (!contents)
|
| - return [];
|
| - var text = new TextUtils.Text(contents);
|
| - var lastOffset = 0;
|
| - var result = [];
|
| - for (var segment of this._segments) {
|
| - if (!segment.end)
|
| - continue;
|
| - var startPosition = text.positionFromOffset(lastOffset);
|
| - var endPosition = text.positionFromOffset(segment.end);
|
| - if (!startPosition.lineNumber)
|
| - startPosition.columnNumber += this._columnOffset;
|
| - startPosition.lineNumber += this._lineOffset;
|
| - if (!endPosition.lineNumber)
|
| - endPosition.columnNumber += this._columnOffset;
|
| - endPosition.lineNumber += this._lineOffset;
|
| - var range = new TextUtils.TextRange(
|
| - startPosition.lineNumber, startPosition.columnNumber, endPosition.lineNumber, endPosition.columnNumber);
|
| - result.push({count: segment.count || 0, range: range});
|
| - lastOffset = segment.end;
|
| - }
|
| - return result;
|
| - }
|
| -
|
| _updateStats() {
|
| this._usedSize = 0;
|
|
|
|
|