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; |