diff options
author | Allan Sandfeld Jensen <allan.jensen@digia.com> | 2013-09-13 12:51:20 +0200 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2013-09-19 20:50:05 +0200 |
commit | d441d6f39bb846989d95bcf5caf387b42414718d (patch) | |
tree | e367e64a75991c554930278175d403c072de6bb8 /Source/WebInspectorUI/UserInterface/SourceMap.js | |
parent | 0060b2994c07842f4c59de64b5e3e430525c4b90 (diff) | |
download | qtwebkit-d441d6f39bb846989d95bcf5caf387b42414718d.tar.gz |
Import Qt5x2 branch of QtWebkit for Qt 5.2
Importing a new snapshot of webkit.
Change-Id: I2d01ad12cdc8af8cb015387641120a9d7ea5f10c
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@digia.com>
Diffstat (limited to 'Source/WebInspectorUI/UserInterface/SourceMap.js')
-rw-r--r-- | Source/WebInspectorUI/UserInterface/SourceMap.js | 333 |
1 files changed, 333 insertions, 0 deletions
diff --git a/Source/WebInspectorUI/UserInterface/SourceMap.js b/Source/WebInspectorUI/UserInterface/SourceMap.js new file mode 100644 index 000000000..b910baadd --- /dev/null +++ b/Source/WebInspectorUI/UserInterface/SourceMap.js @@ -0,0 +1,333 @@ +/* + * Copyright (C) 2013 Apple 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: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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. + */ + +/** + * Implements Source Map V3 model. See http://code.google.com/p/closure-compiler/wiki/SourceMaps + * for format description. + * @constructor + * @param {string} sourceMappingURL + * @param {SourceMapV3} payload + * @param {WebInspector.Resource|WebInspector.Script} originalSourceCode + */ +WebInspector.SourceMap = function(sourceMappingURL, payload, originalSourceCode) +{ + if (!WebInspector.SourceMap.prototype._base64Map) { + const base64Digits = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + WebInspector.SourceMap.prototype._base64Map = {}; + for (var i = 0; i < base64Digits.length; ++i) + WebInspector.SourceMap.prototype._base64Map[base64Digits.charAt(i)] = i; + } + + this._originalSourceCode = originalSourceCode || null; + this._sourceMapResources = {}; + this._sourceMapResourcesList = []; + + this._sourceMappingURL = sourceMappingURL; + this._reverseMappingsBySourceURL = {}; + this._mappings = []; + this._sources = {}; + this._sourceRoot = null; + this._sourceContentByURL = {}; + this._parseMappingPayload(payload); +} + +WebInspector.SourceMap.prototype = { + + get originalSourceCode() + { + return this._originalSourceCode; + }, + + get sourceMappingBasePathURLComponents() + { + if (this._sourceMappingURLBasePathComponents) + return this._sourceMappingURLBasePathComponents; + + if (this._sourceRoot) { + var baseURLPath = absoluteURL(this._sourceRoot, this._sourceMappingURL); + console.assert(baseURLPath); + if (baseURLPath) { + var urlComponents = parseURL(baseURLPath); + if (!/\/$/.test(urlComponents.path)) + urlComponents.path += "/"; + this._sourceMappingURLBasePathComponents = urlComponents; + return this._sourceMappingURLBasePathComponents; + } + } + + var urlComponents = parseURL(this._sourceMappingURL); + urlComponents.path = urlComponents.path.substr(0, urlComponents.path.lastIndexOf(urlComponents.lastPathComponent)); + urlComponents.lastPathComponent = null; + this._sourceMappingURLBasePathComponents = urlComponents; + return this._sourceMappingURLBasePathComponents; + }, + + get resources() + { + return this._sourceMapResourcesList; + }, + + addResource: function(resource) + { + console.assert(!(resource.url in this._sourceMapResources)); + this._sourceMapResources[resource.url] = resource; + this._sourceMapResourcesList.push(resource); + }, + + resourceForURL: function(url) + { + return this._sourceMapResources[url]; + }, + + /** + * @return {Array.<string>} + */ + sources: function() + { + return Object.keys(this._sources); + }, + + /** + * @param {string} sourceURL + * @return {string|undefined} + */ + sourceContent: function(sourceURL) + { + return this._sourceContentByURL[sourceURL]; + }, + + /** + * @param {SourceMapV3} mappingPayload + */ + _parseMappingPayload: function(mappingPayload) + { + if (mappingPayload.sections) + this._parseSections(mappingPayload.sections); + else + this._parseMap(mappingPayload, 0, 0); + }, + + /** + * @param {Array.<SourceMapV3.Section>} sections + */ + _parseSections: function(sections) + { + for (var i = 0; i < sections.length; ++i) { + var section = sections[i]; + this._parseMap(section.map, section.offset.line, section.offset.column); + } + }, + + /** + * @param {number} lineNumber in compiled resource + * @param {number} columnNumber in compiled resource + * @return {?Array} + */ + findEntry: function(lineNumber, columnNumber) + { + var first = 0; + var count = this._mappings.length; + while (count > 1) { + var step = count >> 1; + var middle = first + step; + var mapping = this._mappings[middle]; + if (lineNumber < mapping[0] || (lineNumber === mapping[0] && columnNumber < mapping[1])) + count = step; + else { + first = middle; + count -= step; + } + } + var entry = this._mappings[first]; + if (!first && entry && (lineNumber < entry[0] || (lineNumber === entry[0] && columnNumber < entry[1]))) + return null; + return entry; + }, + + /** + * @param {string} sourceURL of the originating resource + * @param {number} lineNumber in the originating resource + * @return {Array} + */ + findEntryReversed: function(sourceURL, lineNumber) + { + var mappings = this._reverseMappingsBySourceURL[sourceURL]; + for ( ; lineNumber < mappings.length; ++lineNumber) { + var mapping = mappings[lineNumber]; + if (mapping) + return mapping; + } + return this._mappings[0]; + }, + + /** + * @param {SourceMapV3} map + * @param {number} lineNumber + * @param {number} columnNumber + */ + _parseMap: function(map, lineNumber, columnNumber) + { + var sourceIndex = 0; + var sourceLineNumber = 0; + var sourceColumnNumber = 0; + var nameIndex = 0; + + var sources = []; + var originalToCanonicalURLMap = {}; + for (var i = 0; i < map.sources.length; ++i) { + var originalSourceURL = map.sources[i]; + var href = originalSourceURL; + if (map.sourceRoot && href.charAt(0) !== "/") + href = map.sourceRoot.replace(/\/+$/, "") + "/" + href; + var url = absoluteURL(href, this._sourceMappingURL) || href; + originalToCanonicalURLMap[originalSourceURL] = url; + sources.push(url); + this._sources[url] = true; + + if (map.sourcesContent && map.sourcesContent[i]) + this._sourceContentByURL[url] = map.sourcesContent[i]; + } + + this._sourceRoot = map.sourceRoot || null; + + var stringCharIterator = new WebInspector.SourceMap.StringCharIterator(map.mappings); + var sourceURL = sources[sourceIndex]; + + while (true) { + if (stringCharIterator.peek() === ",") + stringCharIterator.next(); + else { + while (stringCharIterator.peek() === ";") { + lineNumber += 1; + columnNumber = 0; + stringCharIterator.next(); + } + if (!stringCharIterator.hasNext()) + break; + } + + columnNumber += this._decodeVLQ(stringCharIterator); + if (this._isSeparator(stringCharIterator.peek())) { + this._mappings.push([lineNumber, columnNumber]); + continue; + } + + var sourceIndexDelta = this._decodeVLQ(stringCharIterator); + if (sourceIndexDelta) { + sourceIndex += sourceIndexDelta; + sourceURL = sources[sourceIndex]; + } + sourceLineNumber += this._decodeVLQ(stringCharIterator); + sourceColumnNumber += this._decodeVLQ(stringCharIterator); + if (!this._isSeparator(stringCharIterator.peek())) + nameIndex += this._decodeVLQ(stringCharIterator); + + this._mappings.push([lineNumber, columnNumber, sourceURL, sourceLineNumber, sourceColumnNumber]); + } + + for (var i = 0; i < this._mappings.length; ++i) { + var mapping = this._mappings[i]; + var url = mapping[2]; + if (!url) + continue; + if (!this._reverseMappingsBySourceURL[url]) + this._reverseMappingsBySourceURL[url] = []; + var reverseMappings = this._reverseMappingsBySourceURL[url]; + var sourceLine = mapping[3]; + if (!reverseMappings[sourceLine]) + reverseMappings[sourceLine] = [mapping[0], mapping[1]]; + } + }, + + /** + * @param {string} char + * @return {boolean} + */ + _isSeparator: function(char) + { + return char === "," || char === ";"; + }, + + /** + * @param {WebInspector.SourceMap.StringCharIterator} stringCharIterator + * @return {number} + */ + _decodeVLQ: function(stringCharIterator) + { + // Read unsigned value. + var result = 0; + var shift = 0; + do { + var digit = this._base64Map[stringCharIterator.next()]; + result += (digit & this._VLQ_BASE_MASK) << shift; + shift += this._VLQ_BASE_SHIFT; + } while (digit & this._VLQ_CONTINUATION_MASK); + + // Fix the sign. + var negative = result & 1; + result >>= 1; + return negative ? -result : result; + }, + + _VLQ_BASE_SHIFT: 5, + _VLQ_BASE_MASK: (1 << 5) - 1, + _VLQ_CONTINUATION_MASK: 1 << 5 +} + +/** + * @constructor + * @param {string} string + */ +WebInspector.SourceMap.StringCharIterator = function(string) +{ + this._string = string; + this._position = 0; +} + +WebInspector.SourceMap.StringCharIterator.prototype = { + /** + * @return {string} + */ + next: function() + { + return this._string.charAt(this._position++); + }, + + /** + * @return {string} + */ + peek: function() + { + return this._string.charAt(this._position); + }, + + /** + * @return {boolean} + */ + hasNext: function() + { + return this._position < this._string.length; + } +} |