65a9c4029679bcf8a9c288c5d5959d6351348e45
[WebKit-https.git] / Source / WebCore / inspector / front-end / ScriptMapping.js
1 /*
2  * Copyright (C) 2012 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  *     * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *     * Neither the name of Google Inc. nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 /**
32  * @constructor
33  * @extends {WebInspector.Object}
34  */
35 WebInspector.ScriptMapping = function()
36 {
37 }
38
39 WebInspector.ScriptMapping.Events = {
40     UISourceCodeListChanged: "us-source-code-list-changed"
41 }
42
43 WebInspector.ScriptMapping.prototype = {
44     /**
45      * @param {DebuggerAgent.Location} rawLocation
46      * @return {WebInspector.UILocation}
47      */
48     rawLocationToUILocation: function(rawLocation) {},
49
50     /**
51      * @param {WebInspector.UISourceCode} uiSourceCode
52      * @param {number} lineNumber
53      * @param {number} columnNumber
54      * @return {DebuggerAgent.Location}
55      */
56     uiLocationToRawLocation: function(uiSourceCode, lineNumber, columnNumber) {},
57
58     /**
59      * @return {Array.<WebInspector.UISourceCode>}
60      */
61     uiSourceCodeList: function() {}
62 }
63
64 WebInspector.ScriptMapping.prototype.__proto__ = WebInspector.Object.prototype;
65
66 /**
67  * @constructor
68  * @extends {WebInspector.Object}
69  */
70 WebInspector.MainScriptMapping = function()
71 {
72     this._mappings = [];
73
74     this._resourceMapping = new WebInspector.ResourceScriptMapping();
75     this._mappings.push(this._resourceMapping);
76     this._compilerMapping = new WebInspector.CompilerScriptMapping();
77     this._mappings.push(this._compilerMapping);
78
79     for (var i = 0; i < this._mappings.length; ++i)
80         this._mappings[i].addEventListener(WebInspector.ScriptMapping.Events.UISourceCodeListChanged, this._handleUISourceCodeListChanged, this);
81
82     if (WebInspector.experimentsSettings.snippetsSupport.isEnabled()) {
83         this._snippetsMapping = new WebInspector.SnippetsScriptMapping();
84         this._mappings.push(this._snippetsMapping);
85     }
86
87     for (var i = 0; i < this._mappings.length; ++i)
88         this._mappings[i].addEventListener(WebInspector.ScriptMapping.Events.UISourceCodeListChanged, this._handleUISourceCodeListChanged, this);
89
90     this._mappingForScriptId = {};
91     this._mappingForUISourceCode = new Map();
92     this._liveLocationsForScriptId = {};
93 }
94
95 WebInspector.MainScriptMapping.Events = {
96     UISourceCodeListChanged: "us-source-code-list-changed"
97 }
98
99 WebInspector.MainScriptMapping.prototype = {
100     /**
101      * @param {DebuggerAgent.Location} rawLocation
102      * @return {WebInspector.UILocation}
103      */
104     rawLocationToUILocation: function(rawLocation)
105     {
106         return this._mappingForScriptId[rawLocation.scriptId].rawLocationToUILocation(rawLocation);
107     },
108
109     /**
110      * @param {WebInspector.UISourceCode} uiSourceCode
111      * @param {number} lineNumber
112      * @param {number} columnNumber
113      * @return {DebuggerAgent.Location}
114      */
115     uiLocationToRawLocation: function(uiSourceCode, lineNumber, columnNumber)
116     {
117         return this._mappingForUISourceCode.get(uiSourceCode).uiLocationToRawLocation(uiSourceCode, lineNumber, columnNumber);
118     },
119
120     /**
121      * @param {DebuggerAgent.Location} rawLocation
122      * @param {function(WebInspector.UILocation)} updateDelegate
123      * @return {WebInspector.LiveLocation}
124      */
125     createLiveLocation: function(rawLocation, updateDelegate)
126     {
127         return new WebInspector.LiveLocation(this, rawLocation, updateDelegate);
128     },
129
130     _registerLiveLocation: function(scriptId, liveLocation)
131     {
132         this._liveLocationsForScriptId[scriptId].push(liveLocation)
133         liveLocation._update();
134     },
135
136     _unregisterLiveLocation: function(scriptId, liveLocation)
137     {
138         this._liveLocationsForScriptId[scriptId].remove(liveLocation);
139     },
140
141     _updateLiveLocations: function(scriptIds)
142     {
143         for (var i = 0; i < scriptIds.length; ++i) {
144             var liveLocations = this._liveLocationsForScriptId[scriptIds[i]];
145             for (var j = 0; j < liveLocations.length; ++j)
146                 liveLocations[j]._update();
147         }
148     },
149
150     /**
151      * @return {Array.<WebInspector.UISourceCode>}
152      */
153     uiSourceCodeList: function()
154     {
155         var result = [];
156         for (var i = 0; i < this._mappings.length; ++i) {
157             var uiSourceCodeList = this._mappings[i].uiSourceCodeList();
158             for (var j = 0; j < uiSourceCodeList.length; ++j)
159                 result.push(uiSourceCodeList[j]);
160         }
161         return result;
162     },
163
164     /**
165      * @param {WebInspector.Script} script
166      */
167     addScript: function(script)
168     {
169         this._liveLocationsForScriptId[script.scriptId] = [];
170
171         var mapping = this._mappingForScript(script);
172         this._mappingForScriptId[script.scriptId] = mapping;
173         mapping.addScript(script);
174     },
175
176     /**
177      * @param {WebInspector.Script} script
178      * @return {WebInspector.ScriptMapping}
179      */
180     _mappingForScript: function(script)
181     {
182         if (WebInspector.experimentsSettings.snippetsSupport.isEnabled()) {
183             if (WebInspector.snippetsModel.snippetIdForSourceURL(script.sourceURL))
184                 return this._snippetsMapping;
185         }
186
187         if (WebInspector.settings.sourceMapsEnabled.get() && script.sourceMapURL) {
188             if (this._compilerMapping.loadSourceMapForScript(script))
189                 return this._compilerMapping;
190         }
191
192         return this._resourceMapping;
193     },
194
195     /**
196      * @param {WebInspector.Event} event
197      */
198     _handleUISourceCodeListChanged: function(event)
199     {
200         var scriptMapping = /** @type {WebInspector.ScriptMapping} */ event.target;
201         var removedItems = /** @type {Array.<WebInspector.UISourceCode>} */ event.data["removedItems"];
202         var addedItems = /** @type {Array.<WebInspector.UISourceCode>} */ event.data["addedItems"];
203         var scriptIds = /** @type {Array.<number>} */ event.data["scriptIds"];
204
205         for (var i = 0; i < removedItems.length; ++i)
206             this._mappingForUISourceCode.remove(removedItems[i]);
207         for (var i = 0; i < addedItems.length; ++i)
208             this._mappingForUISourceCode.put(addedItems[i], scriptMapping);
209         this._updateLiveLocations(scriptIds);
210         this.dispatchEventToListeners(WebInspector.MainScriptMapping.Events.UISourceCodeListChanged, event.data);
211     },
212
213     /**
214      * @param {boolean} formatSource
215      */
216     setFormatSource: function(formatSource)
217     {
218         this._resourceMapping.setFormatSource(formatSource);
219     },
220
221     /**
222      * @param {DebuggerAgent.Location} rawLocation
223      */
224     forceUpdateSourceMapping: function(rawLocation)
225     {
226         if (this._mappingForScriptId[rawLocation.scriptId] === this._resourceMapping)
227             this._resourceMapping.forceUpdateSourceMapping(rawLocation);
228     },
229
230     reset: function()
231     {
232         for (var i = 0; i < this._mappings.length; ++i)
233             this._mappings[i].reset();
234         this._mappingForScriptId = {};
235         this._mappingForUISourceCode = new Map();
236         this._liveLocationsForScriptId = {};
237     }
238 }
239
240 WebInspector.MainScriptMapping.prototype.__proto__ = WebInspector.Object.prototype;
241
242 /**
243  * @constructor
244  * @param {WebInspector.MainScriptMapping} scriptMapping
245  * @param {DebuggerAgent.Location} rawLocation
246  * @param {function(WebInspector.UILocation)} updateDelegate
247  */
248 WebInspector.LiveLocation = function(scriptMapping, rawLocation, updateDelegate)
249 {
250     this._scriptMapping = scriptMapping;
251     this._rawLocation = rawLocation;
252     this._updateDelegate = updateDelegate;
253 }
254
255 WebInspector.LiveLocation.prototype = {
256     init: function()
257     {
258         this._scriptMapping._registerLiveLocation(this._rawLocation.scriptId, this);
259     },
260
261     dispose: function()
262     {
263         this._scriptMapping._unregisterLiveLocation(this._rawLocation.scriptId, this);
264     },
265
266     _update: function()
267     {
268         var uiLocation = this._scriptMapping.rawLocationToUILocation(this._rawLocation);
269         if (uiLocation)
270             this._updateDelegate(uiLocation);
271     }
272 }