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