Upstream version 11.40.277.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / devtools / front_end / sdk / Target.js
1 /*
2  * Copyright 2014 The Chromium Authors. All rights reserved.
3  * Use of this source code is governed by a BSD-style license that can be
4  * found in the LICENSE file.
5  */
6
7 /**
8  * @constructor
9  * @extends {Protocol.Agents}
10  * @param {string} name
11  * @param {!InspectorBackendClass.Connection} connection
12  * @param {function(?WebInspector.Target)=} callback
13  */
14 WebInspector.Target = function(name, connection, callback)
15 {
16     Protocol.Agents.call(this, connection.agentsMap());
17     this._name = name;
18     this._connection = connection;
19     connection.addEventListener(InspectorBackendClass.Connection.Events.Disconnected, this._onDisconnect, this);
20     this._id = WebInspector.Target._nextId++;
21
22     /** @type {!Map.<!Function, !WebInspector.SDKModel>} */
23     this._modelByConstructor = new Map();
24
25     /** @type {!Object.<string, boolean>} */
26     this._capabilities = {};
27     this.pageAgent().canScreencast(this._initializeCapability.bind(this, WebInspector.Target.Capabilities.CanScreencast, null));
28     this.pageAgent().canEmulate(this._initializeCapability.bind(this, WebInspector.Target.Capabilities.CanEmulate, null));
29     if (Runtime.experiments.isEnabled("timelinePowerProfiler"))
30         this.powerAgent().canProfilePower(this._initializeCapability.bind(this, WebInspector.Target.Capabilities.CanProfilePower, null));
31     this.workerAgent().canInspectWorkers(this._initializeCapability.bind(this, WebInspector.Target.Capabilities.CanInspectWorkers, this._loadedWithCapabilities.bind(this, callback)));
32     if (Runtime.experiments.isEnabled("timelineOnTraceEvents"))
33         this.consoleAgent().setTracingBasedTimeline(true);
34 }
35
36 /**
37  * @enum {string}
38  */
39 WebInspector.Target.Capabilities = {
40     CanScreencast: "CanScreencast",
41     HasTouchInputs: "HasTouchInputs",
42     CanProfilePower: "CanProfilePower",
43     CanInspectWorkers: "CanInspectWorkers",
44     CanEmulate: "CanEmulate"
45 }
46
47 WebInspector.Target._nextId = 1;
48
49 WebInspector.Target.prototype = {
50     suspend: function()
51     {
52         if (!Runtime.experiments.isEnabled("disableAgentsWhenProfile")) {
53             this.debuggerModel.asyncStackTracesStateChanged();
54             return;
55         }
56         this.debuggerModel.suspendModel();
57         this.cssModel.suspendModel();
58         this.domModel.suspendModel();
59     },
60
61     resume: function()
62     {
63         if (Runtime.experiments.isEnabled("disableAgentsWhenProfile")) {
64             this.domModel.resumeModel();
65             this.cssModel.resumeModel();
66             this.debuggerModel.resumeModel();
67         } else {
68             this.debuggerModel.asyncStackTracesStateChanged();
69         }
70     },
71
72     /**
73      * @return {number}
74      */
75     id: function()
76     {
77         return this._id;
78     },
79
80     /**
81      *
82      * @return {string}
83      */
84     name: function()
85     {
86         return this._name;
87     },
88
89     /**
90      * @param {string} name
91      * @param {function()|null} callback
92      * @param {?Protocol.Error} error
93      * @param {boolean} result
94      */
95     _initializeCapability: function(name, callback, error, result)
96     {
97         this._capabilities[name] = result;
98         if (callback)
99             callback();
100     },
101
102     /**
103      * @param {string} capability
104      * @return {boolean}
105      */
106     hasCapability: function(capability)
107     {
108         return !!this._capabilities[capability];
109     },
110
111     /**
112      * @param {function(?WebInspector.Target)=} callback
113      */
114     _loadedWithCapabilities: function(callback)
115     {
116         if (this._connection.isClosed()) {
117             callback(null);
118             return;
119         }
120
121         /** @type {!WebInspector.ConsoleModel} */
122         this.consoleModel = new WebInspector.ConsoleModel(this);
123
124         /** @type {!WebInspector.NetworkManager} */
125         this.networkManager = new WebInspector.NetworkManager(this);
126
127         /** @type {!WebInspector.ResourceTreeModel} */
128         this.resourceTreeModel = new WebInspector.ResourceTreeModel(this);
129         if (!WebInspector.resourceTreeModel)
130             WebInspector.resourceTreeModel = this.resourceTreeModel;
131
132         /** @type {!WebInspector.NetworkLog} */
133         this.networkLog = new WebInspector.NetworkLog(this);
134         if (!WebInspector.networkLog)
135             WebInspector.networkLog = this.networkLog;
136
137         /** @type {!WebInspector.DebuggerModel} */
138         this.debuggerModel = new WebInspector.DebuggerModel(this);
139         if (!WebInspector.debuggerModel)
140             WebInspector.debuggerModel = this.debuggerModel;
141
142         /** @type {!WebInspector.RuntimeModel} */
143         this.runtimeModel = new WebInspector.RuntimeModel(this);
144         if (!WebInspector.runtimeModel)
145             WebInspector.runtimeModel = this.runtimeModel;
146
147         /** @type {!WebInspector.DOMModel} */
148         this.domModel = new WebInspector.DOMModel(this);
149
150         /** @type {!WebInspector.CSSStyleModel} */
151         this.cssModel = new WebInspector.CSSStyleModel(this);
152         if (!WebInspector.cssModel)
153             WebInspector.cssModel = this.cssModel;
154
155         /** @type {!WebInspector.WorkerManager} */
156         this.workerManager = new WebInspector.WorkerManager(this, this.hasCapability(WebInspector.Target.Capabilities.CanInspectWorkers));
157         if (!WebInspector.workerManager)
158             WebInspector.workerManager = this.workerManager;
159
160         if (this.hasCapability(WebInspector.Target.Capabilities.CanProfilePower))
161             WebInspector.powerProfiler = new WebInspector.PowerProfiler(this);
162
163         /** @type {!WebInspector.TimelineManager} */
164         this.timelineManager = new WebInspector.TimelineManager(this);
165
166         /** @type {!WebInspector.DatabaseModel} */
167         this.databaseModel = new WebInspector.DatabaseModel(this);
168         if (!WebInspector.databaseModel)
169             WebInspector.databaseModel = this.databaseModel;
170
171         /** @type {!WebInspector.DOMStorageModel} */
172         this.domStorageModel = new WebInspector.DOMStorageModel(this);
173         if (!WebInspector.domStorageModel)
174             WebInspector.domStorageModel = this.domStorageModel;
175
176         /** @type {!WebInspector.CPUProfilerModel} */
177         this.cpuProfilerModel = new WebInspector.CPUProfilerModel(this);
178         if (!WebInspector.cpuProfilerModel)
179             WebInspector.cpuProfilerModel = this.cpuProfilerModel;
180
181         /** @type {!WebInspector.HeapProfilerModel} */
182         this.heapProfilerModel = new WebInspector.HeapProfilerModel(this);
183
184         /** @type {!WebInspector.IndexedDBModel} */
185         this.indexedDBModel = new WebInspector.IndexedDBModel(this);
186
187         /** @type {!WebInspector.LayerTreeModel} */
188         this.layerTreeModel = new WebInspector.LayerTreeModel(this);
189
190         /** @type {!WebInspector.AnimationModel} */
191         this.animationModel = new WebInspector.AnimationModel(this);
192
193         if (callback)
194             callback(this);
195     },
196
197     /**
198      * @override
199      * @param {string} domain
200      * @param {!Object} dispatcher
201      */
202     registerDispatcher: function(domain, dispatcher)
203     {
204         this._connection.registerDispatcher(domain, dispatcher);
205     },
206
207     /**
208      * @return {boolean}
209      */
210     isWorkerTarget: function()
211     {
212         return !this.hasCapability(WebInspector.Target.Capabilities.CanInspectWorkers);
213     },
214
215     /**
216      * @return {boolean}
217      */
218     canEmulate: function()
219     {
220         return this.hasCapability(WebInspector.Target.Capabilities.CanEmulate);
221     },
222
223     _onDisconnect: function()
224     {
225         WebInspector.targetManager.removeTarget(this);
226         this._dispose();
227     },
228
229     _dispose: function()
230     {
231         this.debuggerModel.dispose();
232         this.networkManager.dispose();
233         this.cpuProfilerModel.dispose();
234     },
235
236     /**
237      * @return {boolean}
238      */
239     isDetached: function()
240     {
241         return this._connection.isClosed();
242     },
243
244     __proto__: Protocol.Agents.prototype
245 }
246
247 /**
248  * @constructor
249  * @extends {WebInspector.Object}
250  * @param {!WebInspector.Target} target
251  */
252 WebInspector.SDKObject = function(target)
253 {
254     WebInspector.Object.call(this);
255     this._target = target;
256 }
257
258 WebInspector.SDKObject.prototype = {
259     /**
260      * @return {!WebInspector.Target}
261      */
262     target: function()
263     {
264         return this._target;
265     },
266
267     __proto__: WebInspector.Object.prototype
268 }
269
270 /**
271  * @constructor
272  * @extends {WebInspector.SDKObject}
273  * @param {!Function} modelClass
274  * @param {!WebInspector.Target} target
275  */
276 WebInspector.SDKModel = function(modelClass, target)
277 {
278     WebInspector.SDKObject.call(this, target);
279     target._modelByConstructor.set(modelClass, this);
280 }
281
282 WebInspector.SDKModel.prototype = {
283     __proto__: WebInspector.SDKObject.prototype
284 }
285
286 /**
287  * @constructor
288  * @extends {WebInspector.Object}
289  */
290 WebInspector.TargetManager = function()
291 {
292     WebInspector.Object.call(this);
293     /** @type {!Array.<!WebInspector.Target>} */
294     this._targets = [];
295     /** @type {!Array.<!WebInspector.TargetManager.Observer>} */
296     this._observers = [];
297     /** @type {!Object.<string, !Array.<{modelClass: !Function, thisObject: (!Object|undefined), listener: function(!WebInspector.Event)}>>} */
298     this._modelListeners = {};
299     /** @type {boolean} */
300     this._allTargetsSuspended = false;
301 }
302
303 WebInspector.TargetManager.Events = {
304     InspectedURLChanged: "InspectedURLChanged",
305     MainFrameNavigated: "MainFrameNavigated",
306     Load: "Load",
307     WillReloadPage: "WillReloadPage",
308     SuspendStateChanged: "SuspendStateChanged"
309 }
310
311 WebInspector.TargetManager.prototype = {
312     suspendAllTargets: function()
313     {
314         console.assert(!this._allTargetsSuspended);
315         if (this._allTargetsSuspended)
316             return;
317         this._allTargetsSuspended = true;
318         this._targets.forEach(function(target)
319         {
320             target.suspend();
321         });
322         this.dispatchEventToListeners(WebInspector.TargetManager.Events.SuspendStateChanged);
323     },
324
325     resumeAllTargets: function()
326     {
327         console.assert(this._allTargetsSuspended);
328         if (!this._allTargetsSuspended)
329             return;
330         this._allTargetsSuspended = false;
331         this._targets.forEach(function(target)
332         {
333             target.resume();
334         });
335         this.dispatchEventToListeners(WebInspector.TargetManager.Events.SuspendStateChanged);
336     },
337
338     /**
339      * @return {boolean}
340      */
341     allTargetsSuspended: function()
342     {
343         return this._allTargetsSuspended;
344     },
345
346     /**
347      * @return {string}
348      */
349     inspectedPageURL: function()
350     {
351         if (!this._targets.length)
352             return "";
353
354         return this._targets[0].resourceTreeModel.inspectedPageURL();
355     },
356
357     /**
358      * @return {string}
359      */
360     inspectedPageDomain: function()
361     {
362         if (!this._targets.length)
363             return "";
364
365         return this._targets[0].resourceTreeModel.inspectedPageDomain();
366     },
367
368     /**
369      * @param {!WebInspector.Event} event
370      */
371     _redispatchEvent: function(event)
372     {
373         this.dispatchEventToListeners(event.type, event.data);
374     },
375
376     /**
377      * @param {boolean=} ignoreCache
378      */
379     reloadPage: function(ignoreCache)
380     {
381         if (this._targets.length)
382             this._targets[0].resourceTreeModel.reloadPage(ignoreCache);
383     },
384
385     /**
386      * @param {!Function} modelClass
387      * @param {string} eventType
388      * @param {function(!WebInspector.Event)} listener
389      * @param {!Object=} thisObject
390      */
391     addModelListener: function(modelClass, eventType, listener, thisObject)
392     {
393         for (var i = 0; i < this._targets.length; ++i) {
394             var model = this._targets[i]._modelByConstructor.get(modelClass);
395             model.addEventListener(eventType, listener, thisObject);
396         }
397         if (!this._modelListeners[eventType])
398             this._modelListeners[eventType] = [];
399         this._modelListeners[eventType].push({ modelClass: modelClass, thisObject: thisObject, listener: listener });
400     },
401
402     /**
403      * @param {!Function} modelClass
404      * @param {string} eventType
405      * @param {function(!WebInspector.Event)} listener
406      * @param {!Object=} thisObject
407      */
408     removeModelListener: function(modelClass, eventType, listener, thisObject)
409     {
410         if (!this._modelListeners[eventType])
411             return;
412
413         for (var i = 0; i < this._targets.length; ++i) {
414             var model = this._targets[i]._modelByConstructor.get(modelClass);
415             model.removeEventListener(eventType, listener, thisObject);
416         }
417
418         var listeners = this._modelListeners[eventType];
419         for (var i = 0; i < listeners.length; ++i) {
420             if (listeners[i].modelClass === modelClass && listeners[i].listener === listener && listeners[i].thisObject === thisObject)
421                 listeners.splice(i--, 1);
422         }
423         if (!listeners.length)
424             delete this._modelListeners[eventType];
425     },
426
427     /**
428      * @param {!WebInspector.TargetManager.Observer} targetObserver
429      */
430     observeTargets: function(targetObserver)
431     {
432         this.targets().forEach(targetObserver.targetAdded.bind(targetObserver));
433         this._observers.push(targetObserver);
434     },
435
436     /**
437      * @param {!WebInspector.TargetManager.Observer} targetObserver
438      */
439     unobserveTargets: function(targetObserver)
440     {
441         this._observers.remove(targetObserver);
442     },
443
444     /**
445      * @param {string} name
446      * @param {!InspectorBackendClass.Connection} connection
447      * @param {function(?WebInspector.Target)=} callback
448      */
449     createTarget: function(name, connection, callback)
450     {
451         var target = new WebInspector.Target(name, connection, callbackWrapper.bind(this));
452
453         /**
454          * @this {WebInspector.TargetManager}
455          * @param {?WebInspector.Target} newTarget
456          */
457         function callbackWrapper(newTarget)
458         {
459             if (newTarget)
460                 this.addTarget(newTarget);
461             if (callback)
462                 callback(newTarget);
463         }
464     },
465
466     /**
467      * @param {!WebInspector.Target} target
468      */
469     addTarget: function(target)
470     {
471         this._targets.push(target);
472         if (this._targets.length === 1) {
473             target.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.InspectedURLChanged, this._redispatchEvent, this);
474             target.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.MainFrameNavigated, this._redispatchEvent, this);
475             target.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.Load, this._redispatchEvent, this);
476             target.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.WillReloadPage, this._redispatchEvent, this);
477         }
478         var copy = this._observers.slice();
479         for (var i = 0; i < copy.length; ++i)
480             copy[i].targetAdded(target);
481
482         for (var eventType in this._modelListeners) {
483             var listeners = this._modelListeners[eventType];
484             for (var i = 0; i < listeners.length; ++i) {
485                 var model = target._modelByConstructor.get(listeners[i].modelClass);
486                 model.addEventListener(eventType, listeners[i].listener, listeners[i].thisObject);
487             }
488         }
489     },
490
491     /**
492      * @param {!WebInspector.Target} target
493      */
494     removeTarget: function(target)
495     {
496         this._targets.remove(target);
497         if (this._targets.length === 0) {
498             target.resourceTreeModel.removeEventListener(WebInspector.ResourceTreeModel.EventTypes.InspectedURLChanged, this._redispatchEvent, this);
499             target.resourceTreeModel.removeEventListener(WebInspector.ResourceTreeModel.EventTypes.MainFrameNavigated, this._redispatchEvent, this);
500             target.resourceTreeModel.removeEventListener(WebInspector.ResourceTreeModel.EventTypes.Load, this._redispatchEvent, this);
501             target.resourceTreeModel.removeEventListener(WebInspector.ResourceTreeModel.EventTypes.WillReloadPage, this._redispatchEvent, this);
502         }
503         var copy = this._observers.slice();
504         for (var i = 0; i < copy.length; ++i)
505             copy[i].targetRemoved(target);
506
507         for (var eventType in this._modelListeners) {
508             var listeners = this._modelListeners[eventType];
509             for (var i = 0; i < listeners.length; ++i) {
510                 var model = target._modelByConstructor.get(listeners[i].modelClass);
511                 model.removeEventListener(eventType, listeners[i].listener, listeners[i].thisObject);
512             }
513         }
514     },
515
516     /**
517      * @return {boolean}
518      */
519     hasTargets: function()
520     {
521         return !!this._targets.length;
522     },
523
524     /**
525      * @return {!Array.<!WebInspector.Target>}
526      */
527     targets: function()
528     {
529         return this._targets.slice();
530     },
531
532     /**
533      * @return {?WebInspector.Target}
534      */
535     mainTarget: function()
536     {
537         return this._targets[0] || null;
538     },
539
540     __proto__: WebInspector.Object.prototype
541 }
542
543 /**
544  * @interface
545  */
546 WebInspector.TargetManager.Observer = function()
547 {
548 }
549
550 WebInspector.TargetManager.Observer.prototype = {
551     /**
552      * @param {!WebInspector.Target} target
553      */
554     targetAdded: function(target) { },
555
556     /**
557      * @param {!WebInspector.Target} target
558      */
559     targetRemoved: function(target) { },
560 }
561
562 /**
563  * @type {!WebInspector.TargetManager}
564  */
565 WebInspector.targetManager = new WebInspector.TargetManager();