Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2017 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2017 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 /** @typedef {{startOffset: number, endOffset: number, count: number}} */ | 5 /** @typedef {{startOffset: number, endOffset: number, count: number}} */ |
| 6 Coverage.RangeUseCount; | 6 Coverage.RangeUseCount; |
| 7 | 7 |
| 8 /** @typedef {{end: number, count: (number|undefined)}} */ | 8 /** @typedef {{end: number, count: (number|undefined)}} */ |
| 9 Coverage.CoverageSegment; | 9 Coverage.CoverageSegment; |
| 10 | 10 |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 21 * @param {!SDK.Target} target | 21 * @param {!SDK.Target} target |
| 22 */ | 22 */ |
| 23 constructor(target) { | 23 constructor(target) { |
| 24 super(target); | 24 super(target); |
| 25 this._cpuProfilerModel = target.model(SDK.CPUProfilerModel); | 25 this._cpuProfilerModel = target.model(SDK.CPUProfilerModel); |
| 26 this._cssModel = target.model(SDK.CSSModel); | 26 this._cssModel = target.model(SDK.CSSModel); |
| 27 this._debuggerModel = target.model(SDK.DebuggerModel); | 27 this._debuggerModel = target.model(SDK.DebuggerModel); |
| 28 | 28 |
| 29 /** @type {!Map<string, !Coverage.URLCoverageInfo>} */ | 29 /** @type {!Map<string, !Coverage.URLCoverageInfo>} */ |
| 30 this._coverageByURL = new Map(); | 30 this._coverageByURL = new Map(); |
| 31 /** @type {!Map<!Common.ContentProvider, !Coverage.CoverageInfo>} */ | |
| 32 this._coverageByContentProvider = new Map(); | |
| 31 } | 33 } |
| 32 | 34 |
| 33 /** | 35 /** |
| 34 * @return {boolean} | 36 * @return {boolean} |
| 35 */ | 37 */ |
| 36 start() { | 38 start() { |
| 37 this._coverageByURL.clear(); | 39 this._coverageByURL.clear(); |
| 38 if (this._cssModel) | 40 if (this._cssModel) |
| 39 this._cssModel.startRuleUsageTracking(); | 41 this._cssModel.startCoverage(); |
| 40 if (this._cpuProfilerModel) | 42 if (this._cpuProfilerModel) |
| 41 this._cpuProfilerModel.startPreciseCoverage(); | 43 this._cpuProfilerModel.startPreciseCoverage(); |
| 42 return !!(this._cssModel || this._cpuProfilerModel); | 44 return !!(this._cssModel || this._cpuProfilerModel); |
| 43 } | 45 } |
| 44 | 46 |
| 45 /** | 47 /** |
| 46 * @return {!Promise<!Array<!Coverage.URLCoverageInfo>>} | 48 * @return {!Promise<!Array<!Coverage.CoverageInfo>>} |
| 47 */ | 49 */ |
| 48 async stop() { | 50 stop() { |
| 49 await Promise.all([this._stopCSSCoverage(), this._stopJSCoverage()]); | 51 var pollPromise = this.poll(); |
| 52 if (this._cpuProfilerModel) | |
| 53 this._cpuProfilerModel.stopPreciseCoverage(); | |
| 54 if (this._cssModel) | |
| 55 this._cssModel.stopCoverage(); | |
| 56 return pollPromise; | |
| 57 } | |
| 58 | |
| 59 /** | |
| 60 * @return {!Promise<!Array<!Coverage.CoverageInfo>>} | |
| 61 */ | |
| 62 async poll() { | |
| 63 var updates = await Promise.all([this._takeCSSCoverage(), this._takeJSCovera ge()]); | |
| 64 return updates[0].concat(updates[1]); | |
| 65 } | |
| 66 | |
| 67 /** | |
| 68 * @return {!Array<!Coverage.URLCoverageInfo>} | |
| 69 */ | |
| 70 entries() { | |
| 50 return Array.from(this._coverageByURL.values()); | 71 return Array.from(this._coverageByURL.values()); |
| 51 } | 72 } |
| 52 | 73 |
| 53 async _stopJSCoverage() { | 74 /** |
| 75 * @param {!Common.ContentProvider} contentProvider | |
| 76 * @param {number} startOffset | |
| 77 * @param {number} endOffset | |
| 78 * @return {boolean|undefined} | |
| 79 */ | |
| 80 usageForRange(contentProvider, startOffset, endOffset) { | |
| 81 var coverageInfo = this._coverageByContentProvider.get(contentProvider); | |
| 82 return coverageInfo && coverageInfo.usageForRange(startOffset, endOffset); | |
| 83 } | |
| 84 | |
| 85 /** | |
| 86 * @return {!Promise<!Array<!Coverage.CoverageInfo>>} | |
| 87 */ | |
| 88 async _takeJSCoverage() { | |
| 54 if (!this._cpuProfilerModel) | 89 if (!this._cpuProfilerModel) |
| 55 return; | 90 return []; |
| 56 var coveragePromise = this._cpuProfilerModel.takePreciseCoverage(); | 91 var rawCoverageData = await this._cpuProfilerModel.takePreciseCoverage(); |
| 57 this._cpuProfilerModel.stopPreciseCoverage(); | 92 return this._processJSCoverage(rawCoverageData); |
| 58 var rawCoverageData = await coveragePromise; | |
| 59 this._processJSCoverage(rawCoverageData); | |
| 60 } | 93 } |
| 61 | 94 |
| 62 /** | 95 /** |
| 63 * @param {!Array<!Protocol.Profiler.ScriptCoverage>} scriptsCoverage | 96 * @param {!Array<!Protocol.Profiler.ScriptCoverage>} scriptsCoverage |
| 97 * @return {!Array<!Coverage.CoverageInfo>} | |
| 64 */ | 98 */ |
| 65 _processJSCoverage(scriptsCoverage) { | 99 _processJSCoverage(scriptsCoverage) { |
| 100 var updatedEntries = []; | |
| 66 for (var entry of scriptsCoverage) { | 101 for (var entry of scriptsCoverage) { |
| 67 var script = this._debuggerModel.scriptForId(entry.scriptId); | 102 var script = this._debuggerModel.scriptForId(entry.scriptId); |
| 68 if (!script) | 103 if (!script) |
| 69 continue; | 104 continue; |
| 70 var ranges = []; | 105 var ranges = []; |
| 71 for (var func of entry.functions) { | 106 for (var func of entry.functions) { |
| 72 for (var range of func.ranges) | 107 for (var range of func.ranges) |
| 73 ranges.push(range); | 108 ranges.push(range); |
| 74 } | 109 } |
| 75 this._addCoverage(script, script.contentLength, script.lineOffset, script. columnOffset, ranges); | 110 var entry = this._addCoverage(script, script.contentLength, script.lineOff set, script.columnOffset, ranges); |
| 111 if (entry) | |
| 112 updatedEntries.push(entry); | |
| 76 } | 113 } |
| 114 return updatedEntries; | |
| 77 } | 115 } |
| 78 | 116 |
| 79 /** | 117 /** |
| 118 * @return {!Promise<!Array<!Coverage.CoverageInfo>>} | |
| 119 */ | |
| 120 async _takeCSSCoverage() { | |
| 121 if (!this._cssModel) | |
| 122 return []; | |
| 123 var rawCoverageData = await this._cssModel.takeCoverageDelta(); | |
| 124 return this._processCSSCoverage(rawCoverageData); | |
| 125 } | |
| 126 | |
| 127 /** | |
| 128 * @param {!Array<!Protocol.CSS.RuleUsage>} ruleUsageList | |
| 129 * @return {!Array<!Coverage.CoverageInfo>} | |
| 130 */ | |
| 131 _processCSSCoverage(ruleUsageList) { | |
| 132 var updatedEntries = []; | |
| 133 /** @type {!Map<!SDK.CSSStyleSheetHeader, !Array<!Coverage.RangeUseCount>>} */ | |
| 134 var rulesByStyleSheet = new Map(); | |
| 135 for (var rule of ruleUsageList) { | |
| 136 var styleSheetHeader = this._cssModel.styleSheetHeaderForId(rule.styleShee tId); | |
| 137 if (!styleSheetHeader) | |
| 138 continue; | |
| 139 var ranges = rulesByStyleSheet.get(styleSheetHeader); | |
| 140 if (!ranges) { | |
| 141 ranges = []; | |
| 142 rulesByStyleSheet.set(styleSheetHeader, ranges); | |
| 143 } | |
| 144 ranges.push({startOffset: rule.startOffset, endOffset: rule.endOffset, cou nt: Number(rule.used)}); | |
| 145 } | |
| 146 for (var entry of rulesByStyleSheet) { | |
| 147 var styleSheetHeader = /** @type {!SDK.CSSStyleSheetHeader} */ (entry[0]); | |
| 148 var ranges = /** @type {!Array<!Coverage.RangeUseCount>} */ (entry[1]); | |
| 149 var entry = this._addCoverage( | |
| 150 styleSheetHeader, styleSheetHeader.contentLength, styleSheetHeader.sta rtLine, styleSheetHeader.startColumn, | |
| 151 ranges); | |
| 152 if (entry) | |
| 153 updatedEntries.push(entry); | |
| 154 } | |
| 155 return updatedEntries; | |
| 156 } | |
| 157 | |
| 158 /** | |
| 80 * @param {!Array<!Coverage.RangeUseCount>} ranges | 159 * @param {!Array<!Coverage.RangeUseCount>} ranges |
| 81 * @return {!Array<!Coverage.CoverageSegment>} | 160 * @return {!Array<!Coverage.CoverageSegment>} |
| 82 */ | 161 */ |
| 83 static _convertToDisjointSegments(ranges) { | 162 static _convertToDisjointSegments(ranges) { |
| 84 ranges.sort((a, b) => a.startOffset - b.startOffset); | 163 ranges.sort((a, b) => a.startOffset - b.startOffset); |
| 85 | 164 |
| 86 var result = []; | 165 var result = []; |
| 87 var stack = []; | 166 var stack = []; |
| 88 for (var entry of ranges) { | 167 for (var entry of ranges) { |
| 89 var top = stack.peekLast(); | 168 var top = stack.peekLast(); |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 114 last.end = end; | 193 last.end = end; |
| 115 return; | 194 return; |
| 116 } | 195 } |
| 117 } | 196 } |
| 118 result.push({end: end, count: count}); | 197 result.push({end: end, count: count}); |
| 119 } | 198 } |
| 120 | 199 |
| 121 return result; | 200 return result; |
| 122 } | 201 } |
| 123 | 202 |
| 124 async _stopCSSCoverage() { | |
| 125 if (!this._cssModel) | |
| 126 return []; | |
| 127 | |
| 128 var rawCoverageData = await this._cssModel.ruleListPromise(); | |
| 129 this._processCSSCoverage(rawCoverageData); | |
| 130 } | |
| 131 | |
| 132 /** | |
| 133 * @param {!Array<!Protocol.CSS.RuleUsage>} ruleUsageList | |
| 134 */ | |
| 135 _processCSSCoverage(ruleUsageList) { | |
| 136 /** @type {!Map<!SDK.CSSStyleSheetHeader, !Array<!Coverage.RangeUseCount>>} */ | |
| 137 var rulesByStyleSheet = new Map(); | |
| 138 for (var rule of ruleUsageList) { | |
| 139 var styleSheetHeader = this._cssModel.styleSheetHeaderForId(rule.styleShee tId); | |
| 140 if (!styleSheetHeader) | |
| 141 continue; | |
| 142 var ranges = rulesByStyleSheet.get(styleSheetHeader); | |
| 143 if (!ranges) { | |
| 144 ranges = []; | |
| 145 rulesByStyleSheet.set(styleSheetHeader, ranges); | |
| 146 } | |
| 147 ranges.push({startOffset: rule.startOffset, endOffset: rule.endOffset, cou nt: Number(rule.used)}); | |
| 148 } | |
| 149 for (var entry of rulesByStyleSheet) { | |
| 150 var styleSheetHeader = /** @type {!SDK.CSSStyleSheetHeader} */ (entry[0]); | |
| 151 var ranges = /** @type {!Array<!Coverage.RangeUseCount>} */ (entry[1]); | |
| 152 this._addCoverage( | |
| 153 styleSheetHeader, styleSheetHeader.contentLength, styleSheetHeader.sta rtLine, styleSheetHeader.startColumn, | |
| 154 ranges); | |
| 155 } | |
| 156 } | |
| 157 | |
| 158 /** | 203 /** |
| 159 * @param {!Common.ContentProvider} contentProvider | 204 * @param {!Common.ContentProvider} contentProvider |
| 160 * @param {number} contentLength | 205 * @param {number} contentLength |
| 161 * @param {number} startLine | 206 * @param {number} startLine |
| 162 * @param {number} startColumn | 207 * @param {number} startColumn |
| 163 * @param {!Array<!Coverage.RangeUseCount>} ranges | 208 * @param {!Array<!Coverage.RangeUseCount>} ranges |
| 209 * @return {?Coverage.CoverageInfo} | |
| 164 */ | 210 */ |
| 165 _addCoverage(contentProvider, contentLength, startLine, startColumn, ranges) { | 211 _addCoverage(contentProvider, contentLength, startLine, startColumn, ranges) { |
| 166 var url = contentProvider.contentURL(); | 212 var url = contentProvider.contentURL(); |
| 167 if (!url) | 213 if (!url) |
| 168 return; | 214 return null; |
| 169 var entry = this._coverageByURL.get(url); | 215 var urlCoverage = this._coverageByURL.get(url); |
| 170 if (!entry) { | 216 if (!urlCoverage) { |
| 171 entry = new Coverage.URLCoverageInfo(url); | 217 urlCoverage = new Coverage.URLCoverageInfo(url); |
| 172 this._coverageByURL.set(url, entry); | 218 this._coverageByURL.set(url, urlCoverage); |
| 173 } | 219 } |
| 220 var coverageInfo = urlCoverage._ensureEntry(contentProvider, contentLength, startLine, startColumn); | |
| 221 this._coverageByContentProvider.set(contentProvider, coverageInfo); | |
| 174 var segments = Coverage.CoverageModel._convertToDisjointSegments(ranges); | 222 var segments = Coverage.CoverageModel._convertToDisjointSegments(ranges); |
| 175 if (segments.length && segments.peekLast().end < contentLength) | 223 if (segments.length && segments.peekLast().end < contentLength) |
| 176 segments.push({end: contentLength}); | 224 segments.push({end: contentLength}); |
| 177 entry.update(contentProvider, contentLength, startLine, startColumn, segment s); | 225 var oldUsedSize = coverageInfo._usedSize; |
| 226 coverageInfo.mergeCoverage(segments); | |
| 227 if (coverageInfo._usedSize === oldUsedSize) | |
| 228 return null; | |
| 229 urlCoverage._usedSize += coverageInfo._usedSize - oldUsedSize; | |
| 230 return coverageInfo; | |
| 178 } | 231 } |
| 179 }; | 232 }; |
| 180 | 233 |
| 181 Coverage.URLCoverageInfo = class { | 234 Coverage.URLCoverageInfo = class { |
| 182 /** | 235 /** |
| 183 * @param {string} url | 236 * @param {string} url |
| 184 */ | 237 */ |
| 185 constructor(url) { | 238 constructor(url) { |
| 186 this._url = url; | 239 this._url = url; |
| 187 /** @type {!Map<string, !Coverage.CoverageInfo>} */ | 240 /** @type {!Map<string, !Coverage.CoverageInfo>} */ |
| 188 this._coverageInfoByLocation = new Map(); | 241 this._coverageInfoByLocation = new Map(); |
| 189 this._size = 0; | 242 this._size = 0; |
| 190 this._usedSize = 0; | 243 this._usedSize = 0; |
| 191 /** @type {!Coverage.CoverageType} */ | 244 /** @type {!Coverage.CoverageType} */ |
| 192 this._type; | 245 this._type; |
| 193 } | 246 } |
| 194 | 247 |
| 195 /** | 248 /** |
| 196 * @param {!Common.ContentProvider} contentProvider | |
| 197 * @param {number} contentLength | |
| 198 * @param {number} lineOffset | |
| 199 * @param {number} columnOffset | |
| 200 * @param {!Array<!Coverage.CoverageSegment>} segments | |
| 201 */ | |
| 202 update(contentProvider, contentLength, lineOffset, columnOffset, segments) { | |
| 203 var key = `${lineOffset}:${columnOffset}`; | |
| 204 var entry = this._coverageInfoByLocation.get(key); | |
| 205 | |
| 206 if (!entry) { | |
| 207 entry = new Coverage.CoverageInfo(contentProvider, lineOffset, columnOffse t); | |
| 208 this._coverageInfoByLocation.set(key, entry); | |
| 209 this._size += contentLength; | |
| 210 this._type |= entry.type(); | |
| 211 } | |
| 212 this._usedSize -= entry._usedSize; | |
| 213 entry.mergeCoverage(segments); | |
| 214 this._usedSize += entry._usedSize; | |
| 215 } | |
| 216 | |
| 217 /** | |
| 218 * @return {string} | 249 * @return {string} |
| 219 */ | 250 */ |
| 220 url() { | 251 url() { |
| 221 return this._url; | 252 return this._url; |
| 222 } | 253 } |
| 223 | 254 |
| 224 /** | 255 /** |
| 225 * @return {!Coverage.CoverageType} | 256 * @return {!Coverage.CoverageType} |
| 226 */ | 257 */ |
| 227 type() { | 258 type() { |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 243 } | 274 } |
| 244 | 275 |
| 245 /** | 276 /** |
| 246 * @return {number} | 277 * @return {number} |
| 247 */ | 278 */ |
| 248 unusedSize() { | 279 unusedSize() { |
| 249 return this._size - this._usedSize; | 280 return this._size - this._usedSize; |
| 250 } | 281 } |
| 251 | 282 |
| 252 /** | 283 /** |
| 253 * @return {!Promise<!Array<!{range: !TextUtils.TextRange, count: number}>>} | 284 * @param {!Common.ContentProvider} contentProvider |
| 285 * @param {number} contentLength | |
| 286 * @param {number} lineOffset | |
| 287 * @param {number} columnOffset | |
| 288 * @return {!Coverage.CoverageInfo} | |
| 254 */ | 289 */ |
| 255 async buildTextRanges() { | 290 _ensureEntry(contentProvider, contentLength, lineOffset, columnOffset) { |
| 256 var textRangePromises = []; | 291 var key = `${lineOffset}:${columnOffset}`; |
| 257 for (var coverageInfo of this._coverageInfoByLocation.values()) | 292 var entry = this._coverageInfoByLocation.get(key); |
| 258 textRangePromises.push(coverageInfo.buildTextRanges()); | 293 |
| 259 var allTextRanges = await Promise.all(textRangePromises); | 294 if (!entry) { |
| 260 return [].concat(...allTextRanges); | 295 entry = new Coverage.CoverageInfo(contentProvider, lineOffset, columnOffse t); |
| 296 this._coverageInfoByLocation.set(key, entry); | |
| 297 this._size += contentLength; | |
| 298 this._type |= entry.type(); | |
| 299 } | |
| 300 return entry; | |
| 261 } | 301 } |
| 262 }; | 302 }; |
| 263 | 303 |
| 264 Coverage.CoverageInfo = class { | 304 Coverage.CoverageInfo = class { |
| 265 /** | 305 /** |
| 266 * @param {!Common.ContentProvider} contentProvider | 306 * @param {!Common.ContentProvider} contentProvider |
| 267 * @param {number} lineOffset | 307 * @param {number} lineOffset |
| 268 * @param {number} columnOffset | 308 * @param {number} columnOffset |
| 269 */ | 309 */ |
| 270 constructor(contentProvider, lineOffset, columnOffset) { | 310 constructor(contentProvider, lineOffset, columnOffset) { |
| 271 this._contentProvider = contentProvider; | 311 this._contentProvider = contentProvider; |
| 272 this._lineOffset = lineOffset; | 312 this._lineOffset = lineOffset; |
| 273 this._columnOffset = columnOffset; | 313 this._columnOffset = columnOffset; |
| 274 this._usedSize = 0; | 314 this._usedSize = 0; |
| 275 | 315 |
| 276 if (contentProvider.contentType().isScript()) { | 316 if (contentProvider.contentType().isScript()) { |
| 277 this._coverageType = Coverage.CoverageType.JavaScript; | 317 this._coverageType = Coverage.CoverageType.JavaScript; |
| 278 } else if (contentProvider.contentType().isStyleSheet()) { | 318 } else if (contentProvider.contentType().isStyleSheet()) { |
| 279 this._coverageType = Coverage.CoverageType.CSS; | 319 this._coverageType = Coverage.CoverageType.CSS; |
| 280 } else { | 320 } else { |
| 281 console.assert( | 321 console.assert( |
| 282 false, `Unexpected resource type ${contentProvider.contentType().name} for ${contentProvider.contentURL()}`); | 322 false, `Unexpected resource type ${contentProvider.contentType().name} for ${contentProvider.contentURL()}`); |
| 283 } | 323 } |
| 284 /** !Array<!Coverage.CoverageSegment> */ | 324 /** !Array<!Coverage.CoverageSegment> */ |
| 285 this._segments = []; | 325 this._segments = []; |
| 286 } | 326 } |
| 287 | 327 |
| 288 /** | 328 /** |
| 329 * @return {!Common.ContentProvider} | |
| 330 */ | |
| 331 contentProvider() { | |
| 332 return this._contentProvider; | |
| 333 } | |
| 334 | |
| 335 /** | |
| 336 * @return {string} | |
| 337 */ | |
| 338 url() { | |
| 339 return this._contentProvider.contentURL(); | |
| 340 } | |
| 341 | |
| 342 /** | |
| 289 * @return {!Coverage.CoverageType} | 343 * @return {!Coverage.CoverageType} |
| 290 */ | 344 */ |
| 291 type() { | 345 type() { |
| 292 return this._coverageType; | 346 return this._coverageType; |
| 293 } | 347 } |
| 294 | 348 |
| 295 /** | 349 /** |
| 296 * @param {!Array<!Coverage.CoverageSegment>} segments | 350 * @param {!Array<!Coverage.CoverageSegment>} segments |
| 297 */ | 351 */ |
| 298 mergeCoverage(segments) { | 352 mergeCoverage(segments) { |
| 299 this._segments = Coverage.CoverageInfo._mergeCoverage(this._segments, segmen ts); | 353 this._segments = Coverage.CoverageInfo._mergeCoverage(this._segments, segmen ts); |
| 300 this._updateStats(); | 354 this._updateStats(); |
| 301 } | 355 } |
| 302 | 356 |
| 303 /** | 357 /** |
| 358 * @param {number} start | |
| 359 * @param {number} end | |
| 360 * @return {boolean} | |
| 361 */ | |
| 362 usageForRange(start, end) { | |
| 363 var index = this._segments.upperBound(start, (position, segment) => position - segment.end); | |
| 364 for (; index < this._segments.length && this._segments[index].end < end; ++i ndex) { | |
| 365 if (this._segments[index].count) | |
| 366 return true; | |
| 367 } | |
| 368 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
| |
| 369 } | |
| 370 | |
| 371 /** | |
| 304 * @param {!Array<!Coverage.CoverageSegment>} segmentsA | 372 * @param {!Array<!Coverage.CoverageSegment>} segmentsA |
| 305 * @param {!Array<!Coverage.CoverageSegment>} segmentsB | 373 * @param {!Array<!Coverage.CoverageSegment>} segmentsB |
| 306 */ | 374 */ |
| 307 static _mergeCoverage(segmentsA, segmentsB) { | 375 static _mergeCoverage(segmentsA, segmentsB) { |
| 308 var result = []; | 376 var result = []; |
| 309 | 377 |
| 310 var indexA = 0; | 378 var indexA = 0; |
| 311 var indexB = 0; | 379 var indexB = 0; |
| 312 while (indexA < segmentsA.length && indexB < segmentsB.length) { | 380 while (indexA < segmentsA.length && indexB < segmentsB.length) { |
| 313 var a = segmentsA[indexA]; | 381 var a = segmentsA[indexA]; |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 326 indexB++; | 394 indexB++; |
| 327 } | 395 } |
| 328 | 396 |
| 329 for (; indexA < segmentsA.length; indexA++) | 397 for (; indexA < segmentsA.length; indexA++) |
| 330 result.push(segmentsA[indexA]); | 398 result.push(segmentsA[indexA]); |
| 331 for (; indexB < segmentsB.length; indexB++) | 399 for (; indexB < segmentsB.length; indexB++) |
| 332 result.push(segmentsB[indexB]); | 400 result.push(segmentsB[indexB]); |
| 333 return result; | 401 return result; |
| 334 } | 402 } |
| 335 | 403 |
| 336 /** | |
| 337 * @return {!Promise<!Array<!{range: !TextUtils.TextRange, count: number}>>} | |
| 338 */ | |
| 339 async buildTextRanges() { | |
| 340 var contents = await this._contentProvider.requestContent(); | |
| 341 if (!contents) | |
| 342 return []; | |
| 343 var text = new TextUtils.Text(contents); | |
| 344 var lastOffset = 0; | |
| 345 var result = []; | |
| 346 for (var segment of this._segments) { | |
| 347 if (!segment.end) | |
| 348 continue; | |
| 349 var startPosition = text.positionFromOffset(lastOffset); | |
| 350 var endPosition = text.positionFromOffset(segment.end); | |
| 351 if (!startPosition.lineNumber) | |
| 352 startPosition.columnNumber += this._columnOffset; | |
| 353 startPosition.lineNumber += this._lineOffset; | |
| 354 if (!endPosition.lineNumber) | |
| 355 endPosition.columnNumber += this._columnOffset; | |
| 356 endPosition.lineNumber += this._lineOffset; | |
| 357 var range = new TextUtils.TextRange( | |
| 358 startPosition.lineNumber, startPosition.columnNumber, endPosition.line Number, endPosition.columnNumber); | |
| 359 result.push({count: segment.count || 0, range: range}); | |
| 360 lastOffset = segment.end; | |
| 361 } | |
| 362 return result; | |
| 363 } | |
| 364 | |
| 365 _updateStats() { | 404 _updateStats() { |
| 366 this._usedSize = 0; | 405 this._usedSize = 0; |
| 367 | 406 |
| 368 var last = 0; | 407 var last = 0; |
| 369 for (var segment of this._segments) { | 408 for (var segment of this._segments) { |
| 370 if (segment.count) | 409 if (segment.count) |
| 371 this._usedSize += segment.end - last; | 410 this._usedSize += segment.end - last; |
| 372 last = segment.end; | 411 last = segment.end; |
| 373 } | 412 } |
| 374 } | 413 } |
| 375 }; | 414 }; |
| OLD | NEW |