• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
7base.requireStylesheet('cc.picture_ops_list_view');
8
9base.require('cc.constants');
10base.require('cc.selection');
11base.require('ui.list_view');
12base.require('ui.dom_helpers');
13
14base.exportTo('cc', function() {
15  var ANNOTATION = 'Comment';
16  var BEGIN_ANNOTATION = 'BeginCommentGroup';
17  var END_ANNOTATION = 'EndCommentGroup';
18  var ANNOTATION_ID = 'ID: ';
19  var ANNOTATION_CLASS = 'CLASS: ';
20  var ANNOTATION_TAG = 'TAG: ';
21
22  var constants = cc.constants;
23
24  /**
25   * @constructor
26   */
27  var PictureOpsListView = ui.define('picture-ops-list-view');
28
29  PictureOpsListView.prototype = {
30    __proto__: HTMLUnknownElement.prototype,
31
32    decorate: function() {
33      this.opsList_ = new ui.ListView();
34      this.appendChild(this.opsList_);
35
36      this.selectedOp_ = undefined;
37      this.selectedOpIndex_ = undefined;
38      this.opsList_.addEventListener(
39          'selection-changed', this.onSelectionChanged_.bind(this));
40
41      this.picture_ = undefined;
42    },
43
44    get picture() {
45      return this.picture_;
46    },
47
48    set picture(picture) {
49      this.picture_ = picture;
50      this.updateContents_();
51    },
52
53    updateContents_: function() {
54      this.opsList_.clear();
55
56      if (!this.picture_)
57        return;
58
59      var ops = this.picture_.getOps();
60      if (!ops)
61        return;
62
63      ops = this.opsTaggedWithAnnotations_(ops);
64
65      for (var i = 0; i < ops.length; i++) {
66        var op = ops[i];
67        var item = document.createElement('div');
68        item.opIndex = op.opIndex;
69        item.textContent = i + ') ' + op.cmd_string;
70
71        // Display the element info associated with the op, if available.
72        if (op.elementInfo.tag || op.elementInfo.id || op.elementInfo.class) {
73          var elementInfo = document.createElement('span');
74          elementInfo.classList.add('elementInfo');
75          var tag = op.elementInfo.tag ? op.elementInfo.tag : 'unknown';
76          var id = op.elementInfo.id ? 'id=' + op.elementInfo.id : undefined;
77          var className = op.elementInfo.class ? 'class=' +
78              op.elementInfo.class : undefined;
79          elementInfo.textContent =
80              '<' + tag + (id ? ' ' : '') +
81              (id ? id : '') + (className ? ' ' : '') +
82              (className ? className : '') + '>';
83          item.appendChild(elementInfo);
84        }
85
86        // Display each of the Skia ops.
87        op.info.forEach(function(info) {
88          var infoItem = document.createElement('div');
89          infoItem.textContent = info;
90          item.appendChild(infoItem);
91        });
92
93        this.opsList_.appendChild(item);
94      }
95    },
96
97    onSelectionChanged_: function(e) {
98      var beforeSelectedOp = true;
99
100      // Deselect on re-selection.
101      if (this.opsList_.selectedElement === this.selectedOp_) {
102        this.opsList_.selectedElement = undefined;
103        beforeSelectedOp = false;
104        this.selectedOpIndex_ = undefined;
105      }
106
107      this.selectedOp_ = this.opsList_.selectedElement;
108
109      // Set selection on all previous ops.
110      var ops = this.opsList_.children;
111      for (var i = 0; i < ops.length; i++) {
112        var op = ops[i];
113        if (op === this.selectedOp_) {
114          beforeSelectedOp = false;
115          this.selectedOpIndex_ = op.opIndex;
116        } else if (beforeSelectedOp) {
117          op.setAttribute('beforeSelection', 'beforeSelection');
118        } else {
119          op.removeAttribute('beforeSelection');
120        }
121      }
122
123      base.dispatchSimpleEvent(this, 'selection-changed', false);
124    },
125
126    get selectedOpIndex() {
127      return this.selectedOpIndex_;
128    },
129
130    /**
131     * Return Skia operations tagged by annotation.
132     *
133     * The ops returned from Picture.getOps() contain both Skia ops and
134     * annotations threaded together. This function removes all annotations
135     * from the list and tags each op with the associated annotations.
136     * Additionally, the last {tag, id, class} is stored as elementInfo on
137     * each op.
138     *
139     * @param {Array} ops Array of Skia operations and annotations.
140     * @return {Array} Skia ops where op.annotations contains the associated
141     *         annotations for a given op.
142     */
143    opsTaggedWithAnnotations_: function(ops) {
144      // This algorithm works by walking all the ops and pushing any
145      // annotations onto a stack. When a non-annotation op is found, the
146      // annotations stack is traversed and stored with the op.
147      var annotationGroups = new Array();
148      var opsWithoutAnnotations = new Array();
149      for (var opIndex = 0; opIndex < ops.length; opIndex++) {
150        var op = ops[opIndex];
151        op.opIndex = opIndex;
152        switch (op.cmd_string) {
153          case BEGIN_ANNOTATION:
154            annotationGroups.push(new Array());
155            break;
156          case END_ANNOTATION:
157            annotationGroups.pop();
158            break;
159          case ANNOTATION:
160            annotationGroups[annotationGroups.length - 1].push(op);
161            break;
162          default:
163            var annotations = new Array();
164            var elementInfo = {};
165            annotationGroups.forEach(function(annotationGroup) {
166              elementInfo = {};
167              annotationGroup.forEach(function(annotation) {
168                annotation.info.forEach(function(info) {
169                  if (info.indexOf(ANNOTATION_TAG) != -1)
170                    elementInfo.tag = info.substring(
171                        info.indexOf(ANNOTATION_TAG) +
172                        ANNOTATION_TAG.length).toLowerCase();
173                  else if (info.indexOf(ANNOTATION_ID) != -1)
174                    elementInfo.id = info.substring(
175                        info.indexOf(ANNOTATION_ID) +
176                        ANNOTATION_ID.length);
177                  else if (info.indexOf(ANNOTATION_CLASS) != -1)
178                    elementInfo.class = info.substring(
179                        info.indexOf(ANNOTATION_CLASS) +
180                        ANNOTATION_CLASS.length);
181
182                  annotations.push(info);
183                });
184              });
185            });
186            op.annotations = annotations;
187            op.elementInfo = elementInfo;
188            opsWithoutAnnotations.push(op);
189        }
190      }
191      return opsWithoutAnnotations;
192    }
193  };
194
195  return {
196    PictureOpsListView: PictureOpsListView
197  };
198});
199