Chromium Code Reviews| 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; |
|
alph
2017/05/05 22:50:36
I'll repeat my question: can't this segment be bey
|
| + } |
| + |
| + /** |
| * @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; |