Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / devtools / front_end / sdk / LayerTreeModel.js
1 /*
2  * Copyright (C) 2013 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 /** @typedef {!{
32         bounds: {height: number, width: number},
33         children: Array.<!WebInspector.TracingLayerPayload>,
34         layer_id: number,
35         position: Array.<number>,
36         scroll_offset: Array.<number>,
37         layer_quad: Array.<number>,
38         draws_content: number,
39         transform: Array.<number>
40     }}
41 */
42 WebInspector.TracingLayerPayload;
43
44 /**
45   * @constructor
46   * @extends {WebInspector.TargetAwareObject}
47   */
48 WebInspector.LayerTreeModel = function(target)
49 {
50     WebInspector.TargetAwareObject.call(this, target);
51     this._layersById = {};
52     // We fetch layer tree lazily and get paint events asynchronously, so keep the last painted
53     // rect separate from layer so we can get it after refreshing the tree.
54     this._lastPaintRectByLayerId = {};
55     this._backendNodeIdToNodeId = {};
56     InspectorBackend.registerLayerTreeDispatcher(new WebInspector.LayerTreeDispatcher(this));
57     target.domModel.addEventListener(WebInspector.DOMModel.Events.DocumentUpdated, this._onDocumentUpdated, this);
58 }
59
60 WebInspector.LayerTreeModel.Events = {
61     LayerTreeChanged: "LayerTreeChanged",
62     LayerPainted: "LayerPainted",
63 }
64
65 WebInspector.LayerTreeModel.ScrollRectType = {
66     NonFastScrollable: {name: "NonFastScrollable", description: "Non fast scrollable"},
67     TouchEventHandler: {name: "TouchEventHandler", description: "Touch event handler"},
68     WheelEventHandler: {name: "WheelEventHandler", description: "Wheel event handler"},
69     RepaintsOnScroll: {name: "RepaintsOnScroll", description: "Repaints on scroll"}
70 }
71
72 WebInspector.LayerTreeModel.prototype = {
73     disable: function()
74     {
75         if (!this._enabled)
76             return;
77         this._enabled = false;
78         this._backendNodeIdToNodeId = {};
79         LayerTreeAgent.disable();
80     },
81
82     /**
83      * @param {function()=} callback
84      */
85     enable: function(callback)
86     {
87         if (this._enabled)
88             return;
89         this._enabled = true;
90         LayerTreeAgent.enable();
91     },
92
93     /**
94      * @param {!WebInspector.LayerTreeSnapshot} snapshot
95      */
96     setSnapshot: function(snapshot)
97     {
98         this.disable();
99         this._resolveNodesAndRepopulate(snapshot.layers);
100     },
101
102     /**
103      * @param {!WebInspector.TracingLayerSnapshot} snapshot
104      */
105     setTracingSnapshot: function(snapshot)
106     {
107         this.disable();
108         this._importTracingLayers(snapshot.root);
109     },
110
111     /**
112      * @return {?WebInspector.Layer}
113      */
114     root: function()
115     {
116         return this._root;
117     },
118
119     /**
120      * @return {?WebInspector.Layer}
121      */
122     contentRoot: function()
123     {
124         return this._contentRoot;
125     },
126
127     /**
128      * @param {function(!WebInspector.Layer)} callback
129      * @param {?WebInspector.Layer=} root
130      * @return {boolean}
131      */
132     forEachLayer: function(callback, root)
133     {
134         if (!root) {
135             root = this.root();
136             if (!root)
137                 return false;
138         }
139         return callback(root) || root.children().some(this.forEachLayer.bind(this, callback));
140     },
141
142     /**
143      * @param {string} id
144      * @return {?WebInspector.Layer}
145      */
146     layerById: function(id)
147     {
148         return this._layersById[id] || null;
149     },
150
151     /**
152      * @param {!Array.<!LayerTreeAgent.Layer>=} payload
153      */
154     _resolveNodesAndRepopulate: function(payload)
155     {
156         if (payload)
157             this._resolveBackendNodeIdsForLayers(payload, onBackendNodeIdsResolved.bind(this));
158         else
159             onBackendNodeIdsResolved.call(this);
160         /**
161          * @this {WebInspector.LayerTreeModel}
162          */
163         function onBackendNodeIdsResolved()
164         {
165             this._repopulate(payload || []);
166             this.dispatchEventToListeners(WebInspector.LayerTreeModel.Events.LayerTreeChanged);
167         }
168     },
169
170     /**
171      * @param {!Array.<!LayerTreeAgent.Layer>} layers
172      */
173     _repopulate: function(layers)
174     {
175         this._root = null;
176         this._contentRoot = null;
177         // Payload will be null when not in the composited mode.
178         if (!layers)
179             return;
180         var oldLayersById = this._layersById;
181         this._layersById = {};
182         for (var i = 0; i < layers.length; ++i) {
183             var layerId = layers[i].layerId;
184             var layer = oldLayersById[layerId];
185             if (layer)
186                 layer._reset(layers[i]);
187             else
188                 layer = new WebInspector.AgentLayer(layers[i]);
189             this._layersById[layerId] = layer;
190             if (layers[i].backendNodeId) {
191                 layer._setNode(this._target.domModel.nodeForId(this._backendNodeIdToNodeId[layers[i].backendNodeId]));
192                 if (!this._contentRoot)
193                     this._contentRoot = layer;
194             }
195             var lastPaintRect = this._lastPaintRectByLayerId[layerId];
196             if (lastPaintRect)
197                 layer._lastPaintRect = lastPaintRect;
198             var parentId = layer.parentId();
199             if (parentId) {
200                 var parent = this._layersById[parentId];
201                 if (!parent)
202                     console.assert(parent, "missing parent " + parentId + " for layer " + layerId);
203                 parent.addChild(layer);
204             } else {
205                 if (this._root)
206                     console.assert(false, "Multiple root layers");
207                 this._root = layer;
208             }
209         }
210         if (this._root)
211             this._root._calculateQuad(new WebKitCSSMatrix());
212         this._lastPaintRectByLayerId = {};
213     },
214
215     /**
216      * @param {!WebInspector.TracingLayerPayload} root
217      */
218     _importTracingLayers: function(root)
219     {
220         this._layersById = {};
221         this._contentRoot = null;
222         this._root = this._innerImportTracingLayers(root);
223         this.dispatchEventToListeners(WebInspector.LayerTreeModel.Events.LayerTreeChanged);
224     },
225
226     /**
227      * @param {!WebInspector.TracingLayerPayload} payload
228      * @return {!WebInspector.TracingLayer}
229      */
230     _innerImportTracingLayers: function(payload)
231     {
232         var layer = new WebInspector.TracingLayer(payload);
233         if (!this._contentRoot && payload.draws_content)
234             this._contentRoot = layer;
235         for (var i = 0; i < payload.children.length; ++i)
236             layer.addChild(this._innerImportTracingLayers(payload.children[i]));
237         return layer;
238     },
239
240     /**
241      * @param {!Array.<!LayerTreeAgent.Layer>=} layers
242      */
243     _layerTreeChanged: function(layers)
244     {
245         if (!this._enabled)
246             return;
247         this._resolveNodesAndRepopulate(layers);
248     },
249
250     /**
251      * @param {!Array.<!LayerTreeAgent.Layer>} layers
252      * @param {function()} callback
253      */
254     _resolveBackendNodeIdsForLayers: function(layers, callback)
255     {
256         var idsToResolve = {};
257         var requestedIds = [];
258         for (var i = 0; i < layers.length; ++i) {
259             var backendNodeId = layers[i].backendNodeId;
260             if (!backendNodeId || idsToResolve[backendNodeId] ||
261                 (this._backendNodeIdToNodeId[backendNodeId] && this.target().domModel.nodeForId(this._backendNodeIdToNodeId[backendNodeId]))) {
262                 continue;
263             }
264             idsToResolve[backendNodeId] = true;
265             requestedIds.push(backendNodeId);
266         }
267         if (!requestedIds.length) {
268             callback();
269             return;
270         }
271         this.target().domModel.pushNodesByBackendIdsToFrontend(requestedIds, populateBackendNodeIdMap.bind(this));
272
273         /**
274          * @this {WebInspector.LayerTreeModel}
275          * @param {?Array.<number>} nodeIds
276          */
277         function populateBackendNodeIdMap(nodeIds)
278         {
279             if (nodeIds) {
280                 for (var i = 0; i < requestedIds.length; ++i) {
281                     var nodeId = nodeIds[i];
282                     if (nodeId)
283                         this._backendNodeIdToNodeId[requestedIds[i]] = nodeId;
284                 }
285             }
286             callback();
287         }
288     },
289
290     /**
291      * @param {!LayerTreeAgent.LayerId} layerId
292      * @param {!DOMAgent.Rect} clipRect
293      */
294     _layerPainted: function(layerId, clipRect)
295     {
296         var layer = this._layersById[layerId];
297         if (!layer) {
298             this._lastPaintRectByLayerId[layerId] = clipRect;
299             return;
300         }
301         layer._didPaint(clipRect);
302         this.dispatchEventToListeners(WebInspector.LayerTreeModel.Events.LayerPainted, layer);
303     },
304
305     _onDocumentUpdated: function()
306     {
307         this.disable();
308         this.enable();
309     },
310
311     __proto__: WebInspector.TargetAwareObject.prototype
312 }
313
314 /**
315  * @interface
316  */
317 WebInspector.Layer = function()
318 {
319 }
320
321 WebInspector.Layer.prototype = {
322     /**
323      * @return {string}
324      */
325     id: function() { },
326
327     /**
328      * @return {?string}
329      */
330     parentId: function() { },
331
332     /**
333      * @return {?WebInspector.Layer}
334      */
335     parent: function() { },
336
337     /**
338      * @return {boolean}
339      */
340     isRoot: function() { },
341
342     /**
343      * @return {!Array.<!WebInspector.Layer>}
344      */
345     children: function() { },
346
347     /**
348      * @param {!WebInspector.Layer} child
349      */
350     addChild: function(child) { },
351
352     /**
353      * @return {?WebInspector.DOMNode}
354      */
355     node: function() { },
356
357     /**
358      * @return {?WebInspector.DOMNode}
359      */
360     nodeForSelfOrAncestor: function() { },
361
362     /**
363      * @return {number}
364      */
365     offsetX: function() { },
366
367     /**
368      * @return {number}
369      */
370     offsetY: function() { },
371
372     /**
373      * @return {number}
374      */
375     width: function() { },
376
377     /**
378      * @return {number}
379      */
380     height: function() { },
381
382     /**
383      * @return {?Array.<number>}
384      */
385     transform: function() { },
386
387     /**
388      * @return {!Array.<number>}
389      */
390     quad: function() { },
391
392     /**
393      * @return {!Array.<number>}
394      */
395     anchorPoint: function() { },
396
397     /**
398      * @return {boolean}
399      */
400     invisible: function() { },
401
402     /**
403      * @return {number}
404      */
405     paintCount: function() { },
406
407     /**
408      * @return {?DOMAgent.Rect}
409      */
410     lastPaintRect: function() { },
411
412     /**
413      * @return {!Array.<!LayerTreeAgent.ScrollRect>}
414      */
415     scrollRects: function() { },
416
417     /**
418      * @param {function(!Array.<string>)} callback
419      */
420     requestCompositingReasons: function(callback) { },
421
422     /**
423      * @param {function(!WebInspector.PaintProfilerSnapshot=)} callback
424      */
425     requestSnapshot: function(callback) { },
426 }
427
428 /**
429  * @constructor
430  * @implements {WebInspector.Layer}
431  * @param {!LayerTreeAgent.Layer} layerPayload
432  */
433 WebInspector.AgentLayer = function(layerPayload)
434 {
435     this._scrollRects = [];
436     this._reset(layerPayload);
437 }
438
439 WebInspector.AgentLayer.prototype = {
440     /**
441      * @return {string}
442      */
443     id: function()
444     {
445         return this._layerPayload.layerId;
446     },
447
448     /**
449      * @return {?string}
450      */
451     parentId: function()
452     {
453         return this._layerPayload.parentLayerId;
454     },
455
456     /**
457      * @return {?WebInspector.Layer}
458      */
459     parent: function()
460     {
461         return this._parent;
462     },
463
464     /**
465      * @return {boolean}
466      */
467     isRoot: function()
468     {
469         return !this.parentId();
470     },
471
472     /**
473      * @return {!Array.<!WebInspector.Layer>}
474      */
475     children: function()
476     {
477         return this._children;
478     },
479
480     /**
481      * @param {!WebInspector.Layer} child
482      */
483     addChild: function(child)
484     {
485         if (child._parent)
486             console.assert(false, "Child already has a parent");
487         this._children.push(child);
488         child._parent = this;
489     },
490
491     /**
492      * @param {?WebInspector.DOMNode} node
493      */
494     _setNode: function(node)
495     {
496         this._node = node;
497     },
498
499     /**
500      * @return {?WebInspector.DOMNode}
501      */
502     node: function()
503     {
504         return this._node;
505     },
506
507     /**
508      * @return {?WebInspector.DOMNode}
509      */
510     nodeForSelfOrAncestor: function()
511     {
512         for (var layer = this; layer; layer = layer._parent) {
513             if (layer._node)
514                 return layer._node;
515         }
516         return null;
517     },
518
519     /**
520      * @return {number}
521      */
522     offsetX: function()
523     {
524         return this._layerPayload.offsetX;
525     },
526
527     /**
528      * @return {number}
529      */
530     offsetY: function()
531     {
532         return this._layerPayload.offsetY;
533     },
534
535     /**
536      * @return {number}
537      */
538     width: function()
539     {
540         return this._layerPayload.width;
541     },
542
543     /**
544      * @return {number}
545      */
546     height: function()
547     {
548         return this._layerPayload.height;
549     },
550
551     /**
552      * @return {?Array.<number>}
553      */
554     transform: function()
555     {
556         return this._layerPayload.transform;
557     },
558
559     /**
560      * @return {!Array.<number>}
561      */
562     quad: function()
563     {
564         return this._quad;
565     },
566
567     /**
568      * @return {!Array.<number>}
569      */
570     anchorPoint: function()
571     {
572         return [
573             this._layerPayload.anchorX || 0,
574             this._layerPayload.anchorY || 0,
575             this._layerPayload.anchorZ || 0,
576         ];
577     },
578
579     /**
580      * @return {boolean}
581      */
582     invisible: function()
583     {
584         return this._layerPayload.invisible;
585     },
586
587     /**
588      * @return {number}
589      */
590     paintCount: function()
591     {
592         return this._paintCount || this._layerPayload.paintCount;
593     },
594
595     /**
596      * @return {?DOMAgent.Rect}
597      */
598     lastPaintRect: function()
599     {
600         return this._lastPaintRect;
601     },
602
603     /**
604      * @return {!Array.<!LayerTreeAgent.ScrollRect>}
605      */
606     scrollRects: function()
607     {
608         return this._scrollRects;
609     },
610
611     /**
612      * @param {function(!Array.<string>)} callback
613      */
614     requestCompositingReasons: function(callback)
615     {
616         var wrappedCallback = InspectorBackend.wrapClientCallback(callback, "LayerTreeAgent.reasonsForCompositingLayer(): ", undefined, []);
617         LayerTreeAgent.compositingReasons(this.id(), wrappedCallback);
618     },
619
620     /**
621      * @param {function(!WebInspector.PaintProfilerSnapshot=)} callback
622      */
623     requestSnapshot: function(callback)
624     {
625         var wrappedCallback = InspectorBackend.wrapClientCallback(callback, "LayerTreeAgent.makeSnapshot(): ", WebInspector.PaintProfilerSnapshot);
626         LayerTreeAgent.makeSnapshot(this.id(), wrappedCallback);
627     },
628
629     /**
630      * @param {!DOMAgent.Rect} rect
631      */
632     _didPaint: function(rect)
633     {
634         this._lastPaintRect = rect;
635         this._paintCount = this.paintCount() + 1;
636         this._image = null;
637     },
638
639     /**
640      * @param {!LayerTreeAgent.Layer} layerPayload
641      */
642     _reset: function(layerPayload)
643     {
644         this._children = [];
645         this._parent = null;
646         this._paintCount = 0;
647         this._layerPayload = layerPayload;
648         this._image = null;
649         this._scrollRects = this._layerPayload.scrollRects || [];
650     },
651
652     /**
653      * @param {!Array.<number>} a
654      * @return {!CSSMatrix}
655      */
656     _matrixFromArray: function(a)
657     {
658         function toFixed9(x) { return x.toFixed(9); }
659         return new WebKitCSSMatrix("matrix3d(" + a.map(toFixed9).join(",") + ")");
660     },
661
662     /**
663      * @param {!CSSMatrix} parentTransform
664      * @return {!CSSMatrix}
665      */
666     _calculateTransformToViewport: function(parentTransform)
667     {
668         var offsetMatrix = new WebKitCSSMatrix().translate(this._layerPayload.offsetX, this._layerPayload.offsetY);
669         var matrix = offsetMatrix;
670
671         if (this._layerPayload.transform) {
672             var transformMatrix = this._matrixFromArray(this._layerPayload.transform);
673             var anchorVector = new WebInspector.Geometry.Vector(this._layerPayload.width * this.anchorPoint()[0], this._layerPayload.height * this.anchorPoint()[1], this.anchorPoint()[2]);
674             var anchorPoint = WebInspector.Geometry.multiplyVectorByMatrixAndNormalize(anchorVector, matrix);
675             var anchorMatrix = new WebKitCSSMatrix().translate(-anchorPoint.x, -anchorPoint.y, -anchorPoint.z);
676             matrix = anchorMatrix.inverse().multiply(transformMatrix.multiply(anchorMatrix.multiply(matrix)));
677         }
678
679         matrix = parentTransform.multiply(matrix);
680         return matrix;
681     },
682
683     /**
684      * @param {number} width
685      * @param {number} height
686      * @return {!Array.<number>}
687      */
688     _createVertexArrayForRect: function(width, height)
689     {
690         return [0, 0, 0, width, 0, 0, width, height, 0, 0, height, 0];
691     },
692
693     /**
694      * @param {!CSSMatrix} parentTransform
695      */
696     _calculateQuad: function(parentTransform)
697     {
698         var matrix = this._calculateTransformToViewport(parentTransform);
699         this._quad = [];
700         var vertices = this._createVertexArrayForRect(this._layerPayload.width, this._layerPayload.height);
701         for (var i = 0; i < 4; ++i) {
702             var point = WebInspector.Geometry.multiplyVectorByMatrixAndNormalize(new WebInspector.Geometry.Vector(vertices[i * 3], vertices[i * 3 + 1], vertices[i * 3 + 2]), matrix);
703             this._quad.push(point.x, point.y);
704         }
705
706         function calculateQuadForLayer(layer)
707         {
708             layer._calculateQuad(matrix);
709         }
710
711         this._children.forEach(calculateQuadForLayer);
712     }
713 }
714
715 /**
716  * @constructor
717  * @param {!WebInspector.TracingLayerPayload} payload
718  * @implements {WebInspector.Layer}
719  */
720 WebInspector.TracingLayer = function(payload)
721 {
722     this._layerId = String(payload.layer_id);
723     this._offsetX = payload.position[0];
724     this._offsetY = payload.position[1];
725     this._width = payload.bounds.width;
726     this._height = payload.bounds.height;
727     this._children = [];
728     this._parentLayerId = null;
729     this._parent = null;
730     this._quad = payload.layer_quad || [];
731     this._createScrollRects(payload);
732 }
733
734 WebInspector.TracingLayer.prototype = {
735     /**
736      * @return {string}
737      */
738     id: function()
739     {
740         return this._layerId;
741     },
742
743     /**
744      * @return {?string}
745      */
746     parentId: function()
747     {
748         return this._parentLayerId;
749     },
750
751     /**
752      * @return {?WebInspector.Layer}
753      */
754     parent: function()
755     {
756         return this._parent;
757     },
758
759     /**
760      * @return {boolean}
761      */
762     isRoot: function()
763     {
764         return !this.parentId();
765     },
766
767     /**
768      * @return {!Array.<!WebInspector.Layer>}
769      */
770     children: function()
771     {
772         return this._children;
773     },
774
775     /**
776      * @param {!WebInspector.Layer} child
777      */
778     addChild: function(child)
779     {
780         if (child._parent)
781             console.assert(false, "Child already has a parent");
782         this._children.push(child);
783         child._parent = this;
784         child._parentLayerId = this._layerId;
785     },
786
787     /**
788      * @return {?WebInspector.DOMNode}
789      */
790     node: function()
791     {
792         return null;
793     },
794
795     /**
796      * @return {?WebInspector.DOMNode}
797      */
798     nodeForSelfOrAncestor: function()
799     {
800         return null;
801     },
802
803     /**
804      * @return {number}
805      */
806     offsetX: function()
807     {
808         return this._offsetX;
809     },
810
811     /**
812      * @return {number}
813      */
814     offsetY: function()
815     {
816         return this._offsetY;
817     },
818
819     /**
820      * @return {number}
821      */
822     width: function()
823     {
824         return this._width;
825     },
826
827     /**
828      * @return {number}
829      */
830     height: function()
831     {
832         return this._height;
833     },
834
835     /**
836      * @return {?Array.<number>}
837      */
838     transform: function()
839     {
840         return null;
841     },
842
843     /**
844      * @return {!Array.<number>}
845      */
846     quad: function()
847     {
848         return this._quad;
849     },
850
851     /**
852      * @return {!Array.<number>}
853      */
854     anchorPoint: function()
855     {
856         return [0.5, 0.5, 0];
857     },
858
859     /**
860      * @return {boolean}
861      */
862     invisible: function()
863     {
864         return false;
865     },
866
867     /**
868      * @return {number}
869      */
870     paintCount: function()
871     {
872         return 0;
873     },
874
875     /**
876      * @return {?DOMAgent.Rect}
877      */
878     lastPaintRect: function()
879     {
880         return null;
881     },
882
883     /**
884      * @return {!Array.<!LayerTreeAgent.ScrollRect>}
885      */
886     scrollRects: function()
887     {
888         return this._scrollRects;
889     },
890
891     /**
892      * @param {!Array.<number>} params
893      * @param {string} type
894      * @return {!Object}
895      */
896     _scrollRectsFromParams: function(params, type)
897     {
898         return {rect: {x: params[0], y: params[1], width: params[2], height: params[3]}, type: type};
899     },
900
901     /**
902      * @param {!WebInspector.TracingLayerPayload} payload
903      */
904     _createScrollRects: function(payload)
905     {
906         this._scrollRects = [];
907         if (payload.non_fast_scrollable_region)
908             this._scrollRects.push(this._scrollRectsFromParams(payload.non_fast_scrollable_region, WebInspector.LayerTreeModel.ScrollRectType.NonFastScrollable.name));
909         if (payload.touch_event_handler_region)
910             this._scrollRects.push(this._scrollRectsFromParams(payload.touch_event_handler_region, WebInspector.LayerTreeModel.ScrollRectType.TouchEventHandler.name));
911         if (payload.wheel_event_handler_region)
912             this._scrollRects.push(this._scrollRectsFromParams(payload.wheel_event_handler_region, WebInspector.LayerTreeModel.ScrollRectType.WheelEventHandler.name));
913         if (payload.scroll_event_handler_region)
914             this._scrollRects.push(this._scrollRectsFromParams(payload.scroll_event_handler_region, WebInspector.LayerTreeModel.ScrollRectType.RepaintsOnScroll.name));
915     },
916
917     /**
918      * @param {function(!Array.<string>)} callback
919      */
920     requestCompositingReasons: function(callback)
921     {
922         var wrappedCallback = InspectorBackend.wrapClientCallback(callback, "LayerTreeAgent.reasonsForCompositingLayer(): ", undefined, []);
923         LayerTreeAgent.compositingReasons(this.id(), wrappedCallback);
924     },
925
926     /**
927      * @param {function(!WebInspector.PaintProfilerSnapshot=)} callback
928      */
929     requestSnapshot: function(callback)
930     {
931         var wrappedCallback = InspectorBackend.wrapClientCallback(callback, "LayerTreeAgent.makeSnapshot(): ", WebInspector.PaintProfilerSnapshot);
932         LayerTreeAgent.makeSnapshot(this.id(), wrappedCallback);
933     }
934 }
935
936 /**
937  * @constructor
938  * @param {!Array.<!LayerTreeAgent.Layer>} layers
939  */
940 WebInspector.LayerTreeSnapshot = function(layers)
941 {
942     this.layers = layers;
943 }
944
945 /**
946  * @constructor
947  * @param {!WebInspector.TracingLayerPayload} root
948  */
949 WebInspector.TracingLayerSnapshot = function(root)
950 {
951     this.root = root;
952 }
953
954 /**
955  * @constructor
956  * @implements {LayerTreeAgent.Dispatcher}
957  * @param {!WebInspector.LayerTreeModel} layerTreeModel
958  */
959 WebInspector.LayerTreeDispatcher = function(layerTreeModel)
960 {
961     this._layerTreeModel = layerTreeModel;
962 }
963
964 WebInspector.LayerTreeDispatcher.prototype = {
965     /**
966      * @param {!Array.<!LayerTreeAgent.Layer>=} layers
967      */
968     layerTreeDidChange: function(layers)
969     {
970         this._layerTreeModel._layerTreeChanged(layers);
971     },
972
973     /**
974      * @param {!LayerTreeAgent.LayerId} layerId
975      * @param {!DOMAgent.Rect} clipRect
976      */
977     layerPainted: function(layerId, clipRect)
978     {
979         this._layerTreeModel._layerPainted(layerId, clipRect);
980     }
981 }