Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / trace-viewer / trace_viewer / cc / picture_ops_list_view.html
1 <!DOCTYPE html>
2 <!--
3 Copyright (c) 2013 The Chromium Authors. All rights reserved.
4 Use of this source code is governed by a BSD-style license that can be
5 found in the LICENSE file.
6 -->
7
8 <link rel="stylesheet" href="/cc/picture_ops_list_view.css">
9
10 <link rel="import" href="/cc/constants.html">
11 <link rel="import" href="/cc/selection.html">
12 <link rel="import" href="/tvcm/ui/list_view.html">
13 <link rel="import" href="/tvcm/ui/dom_helpers.html">
14
15 <script>
16 'use strict';
17
18 tvcm.exportTo('cc', function() {
19   var OPS_TIMING_ITERATIONS = 3; // Iterations to average op timing info over.
20   var ANNOTATION = 'Comment';
21   var BEGIN_ANNOTATION = 'BeginCommentGroup';
22   var END_ANNOTATION = 'EndCommentGroup';
23   var ANNOTATION_ID = 'ID: ';
24   var ANNOTATION_CLASS = 'CLASS: ';
25   var ANNOTATION_TAG = 'TAG: ';
26
27   var constants = cc.constants;
28
29   /**
30    * @constructor
31    */
32   var PictureOpsListView = tvcm.ui.define('picture-ops-list-view');
33
34   PictureOpsListView.prototype = {
35     __proto__: HTMLUnknownElement.prototype,
36
37     decorate: function() {
38       this.opsList_ = new tvcm.ui.ListView();
39       this.appendChild(this.opsList_);
40
41       this.selectedOp_ = undefined;
42       this.selectedOpIndex_ = undefined;
43       this.opsList_.addEventListener(
44           'selection-changed', this.onSelectionChanged_.bind(this));
45
46       this.picture_ = undefined;
47     },
48
49     get picture() {
50       return this.picture_;
51     },
52
53     set picture(picture) {
54       this.picture_ = picture;
55       this.updateContents_();
56     },
57
58     updateContents_: function() {
59       this.opsList_.clear();
60
61       if (!this.picture_)
62         return;
63
64       var ops = this.picture_.getOps();
65       if (!ops)
66         return;
67
68       ops = this.picture_.tagOpsWithTimings(ops);
69
70       ops = this.opsTaggedWithAnnotations_(ops);
71
72       for (var i = 0; i < ops.length; i++) {
73         var op = ops[i];
74         var item = document.createElement('div');
75         item.opIndex = op.opIndex;
76         item.textContent = i + ') ' + op.cmd_string;
77
78         // Display the element info associated with the op, if available.
79         if (op.elementInfo.tag || op.elementInfo.id || op.elementInfo.class) {
80           var elementInfo = document.createElement('span');
81           elementInfo.classList.add('elementInfo');
82           var tag = op.elementInfo.tag ? op.elementInfo.tag : 'unknown';
83           var id = op.elementInfo.id ? 'id=' + op.elementInfo.id : undefined;
84           var className = op.elementInfo.class ? 'class=' +
85               op.elementInfo.class : undefined;
86           elementInfo.textContent =
87               '<' + tag + (id ? ' ' : '') +
88               (id ? id : '') + (className ? ' ' : '') +
89               (className ? className : '') + '>';
90           item.appendChild(elementInfo);
91         }
92
93         // Display each of the Skia ops.
94         op.info.forEach(function(info) {
95           var infoItem = document.createElement('div');
96           infoItem.textContent = info;
97           item.appendChild(infoItem);
98         });
99
100         // Display the op timing, if available.
101         if (op.cmd_time && op.cmd_time >= 0.0001) {
102           var time = document.createElement('span');
103           time.classList.add('time');
104           var rounded = op.cmd_time.toFixed(4);
105           time.textContent = '(' + rounded + 'ms)';
106           item.appendChild(time);
107         }
108
109         this.opsList_.appendChild(item);
110       }
111     },
112
113     onSelectionChanged_: function(e) {
114       var beforeSelectedOp = true;
115
116       // Deselect on re-selection.
117       if (this.opsList_.selectedElement === this.selectedOp_) {
118         this.opsList_.selectedElement = undefined;
119         beforeSelectedOp = false;
120         this.selectedOpIndex_ = undefined;
121       }
122
123       this.selectedOp_ = this.opsList_.selectedElement;
124
125       // Set selection on all previous ops.
126       var ops = this.opsList_.children;
127       for (var i = 0; i < ops.length; i++) {
128         var op = ops[i];
129         if (op === this.selectedOp_) {
130           beforeSelectedOp = false;
131           this.selectedOpIndex_ = op.opIndex;
132         } else if (beforeSelectedOp) {
133           op.setAttribute('beforeSelection', 'beforeSelection');
134         } else {
135           op.removeAttribute('beforeSelection');
136         }
137       }
138
139       tvcm.dispatchSimpleEvent(this, 'selection-changed', false);
140     },
141
142     get numOps() {
143       return this.opsList_.children.length;
144     },
145
146     get selectedOpIndex() {
147       return this.selectedOpIndex_;
148     },
149
150     set selectedOpIndex(s) {
151       this.selectedOpIndex_ = s;
152
153       if (s === undefined) {
154         this.opsList_.selectedElement = this.selectedOp_;
155         this.onSelectionChanged_();
156       } else {
157         if (s < 0) throw new Error('Invalid index');
158         if (s >= this.numOps) throw new Error('Invalid index');
159         this.opsList_.selectedElement = this.opsList_.getElementByIndex(s + 1);
160         tvcm.scrollIntoViewIfNeeded(this.opsList_.selectedElement);
161       }
162     },
163
164     /**
165      * Return Skia operations tagged by annotation.
166      *
167      * The ops returned from Picture.getOps() contain both Skia ops and
168      * annotations threaded together. This function removes all annotations
169      * from the list and tags each op with the associated annotations.
170      * Additionally, the last {tag, id, class} is stored as elementInfo on
171      * each op.
172      *
173      * @param {Array} ops Array of Skia operations and annotations.
174      * @return {Array} Skia ops where op.annotations contains the associated
175      *         annotations for a given op.
176      */
177     opsTaggedWithAnnotations_: function(ops) {
178       // This algorithm works by walking all the ops and pushing any
179       // annotations onto a stack. When a non-annotation op is found, the
180       // annotations stack is traversed and stored with the op.
181       var annotationGroups = new Array();
182       var opsWithoutAnnotations = new Array();
183       for (var opIndex = 0; opIndex < ops.length; opIndex++) {
184         var op = ops[opIndex];
185         op.opIndex = opIndex;
186         switch (op.cmd_string) {
187           case BEGIN_ANNOTATION:
188             annotationGroups.push(new Array());
189             break;
190           case END_ANNOTATION:
191             annotationGroups.pop();
192             break;
193           case ANNOTATION:
194             annotationGroups[annotationGroups.length - 1].push(op);
195             break;
196           default:
197             var annotations = new Array();
198             var elementInfo = {};
199             annotationGroups.forEach(function(annotationGroup) {
200               elementInfo = {};
201               annotationGroup.forEach(function(annotation) {
202                 annotation.info.forEach(function(info) {
203                   if (info.indexOf(ANNOTATION_TAG) != -1)
204                     elementInfo.tag = info.substring(
205                         info.indexOf(ANNOTATION_TAG) +
206                         ANNOTATION_TAG.length).toLowerCase();
207                   else if (info.indexOf(ANNOTATION_ID) != -1)
208                     elementInfo.id = info.substring(
209                         info.indexOf(ANNOTATION_ID) +
210                         ANNOTATION_ID.length);
211                   else if (info.indexOf(ANNOTATION_CLASS) != -1)
212                     elementInfo.class = info.substring(
213                         info.indexOf(ANNOTATION_CLASS) +
214                         ANNOTATION_CLASS.length);
215
216                   annotations.push(info);
217                 });
218               });
219             });
220             op.annotations = annotations;
221             op.elementInfo = elementInfo;
222             opsWithoutAnnotations.push(op);
223         }
224       }
225
226       return opsWithoutAnnotations;
227     }
228   };
229
230   return {
231     PictureOpsListView: PictureOpsListView
232   };
233 });
234 </script>