Upstream version 9.37.197.0
[platform/framework/web/crosswalk.git] / src / third_party / trace-viewer / trace_viewer / cc / picture.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.require('tvcm.guid');
8 tvcm.require('tvcm.rect');
9 tvcm.require('tvcm.raf');
10 tvcm.require('tracing.trace_model.object_instance');
11 tvcm.require('cc.picture_as_image_data');
12 tvcm.require('cc.util');
13
14 tvcm.exportTo('cc', function() {
15
16   var ObjectSnapshot = tracing.trace_model.ObjectSnapshot;
17
18   // Number of pictures created. Used as an uniqueId because we are immutable.
19   var PictureCount = 0;
20   var OPS_TIMING_ITERATIONS = 3;
21
22   function Picture(skp64, layerRect, opaqueRect) {
23     this.skp64_ = skp64;
24     this.layerRect_ = layerRect;
25     this.opaqueRect_ = opaqueRect;
26
27     this.guid_ = tvcm.GUID.allocate();
28   }
29
30   Picture.prototype = {
31     get canSave() {
32       return true;
33     },
34
35     get layerRect() {
36       return this.layerRect_;
37     },
38
39     get guid() {
40       return this.guid_;
41     },
42
43     getBase64SkpData: function() {
44       return this.skp64_;
45     },
46
47     getOps: function() {
48       if (!PictureSnapshot.CanGetOps()) {
49         console.error(PictureSnapshot.HowToEnablePictureDebugging());
50         return undefined;
51       }
52
53       var ops = window.chrome.skiaBenchmarking.getOps({
54         skp64: this.skp64_,
55         params: {
56           layer_rect: this.layerRect_.toArray(),
57           opaque_rect: this.opaqueRect_.toArray()
58         }
59       });
60
61       if (!ops)
62         console.error('Failed to get picture ops.');
63
64       return ops;
65     },
66
67     getOpTimings: function() {
68       if (!PictureSnapshot.CanGetOpTimings()) {
69         console.error(PictureSnapshot.HowToEnablePictureDebugging());
70         return undefined;
71       }
72
73       var opTimings = window.chrome.skiaBenchmarking.getOpTimings({
74         skp64: this.skp64_,
75         params: {
76           layer_rect: this.layerRect_.toArray(),
77           opaque_rect: this.opaqueRect_.toArray()
78         }
79       });
80
81       if (!opTimings)
82         console.error('Failed to get picture op timings.');
83
84       return opTimings;
85     },
86
87     /**
88      * Tag each op with the time it takes to rasterize.
89      *
90      * FIXME: We should use real statistics to get better numbers here, see
91      *        https://code.google.com/p/trace-viewer/issues/detail?id=357
92      *
93      * @param {Array} ops Array of Skia operations.
94      * @return {Array} Skia ops where op.cmd_time contains the associated time
95      *         for a given op.
96      */
97     tagOpsWithTimings: function(ops) {
98       var opTimings = new Array();
99       for (var iteration = 0; iteration < OPS_TIMING_ITERATIONS; iteration++) {
100         opTimings[iteration] = this.getOpTimings();
101         if (!opTimings[iteration] || !opTimings[iteration].cmd_times)
102           return ops;
103         if (opTimings[iteration].cmd_times.length != ops.length)
104           return ops;
105       }
106
107       for (var opIndex = 0; opIndex < ops.length; opIndex++) {
108         var min = Number.MAX_VALUE;
109         for (var i = 0; i < OPS_TIMING_ITERATIONS; i++)
110           min = Math.min(min, opTimings[i].cmd_times[opIndex]);
111         ops[opIndex].cmd_time = min;
112       }
113
114       return ops;
115     },
116
117     /**
118      * Rasterize the picture.
119      *
120      * @param {{opt_stopIndex: number, params}} The SkPicture operation to
121      *     rasterize up to. If not defined, the entire SkPicture is rasterized.
122      * @param {{opt_showOverdraw: bool, params}} Defines whether pixel overdraw
123            should be visualized in the image.
124      * @param {function(cc.PictureAsImageData)} The callback function that is
125      *     called after rasterization is complete or fails.
126      */
127     rasterize: function(params, rasterCompleteCallback) {
128       if (!PictureSnapshot.CanRasterize() || !PictureSnapshot.CanGetOps()) {
129         rasterCompleteCallback(new cc.PictureAsImageData(
130             this, cc.PictureSnapshot.HowToEnablePictureDebugging()));
131         return;
132       }
133
134       var raster = window.chrome.skiaBenchmarking.rasterize(
135           {
136             skp64: this.skp64_,
137             params: {
138               layer_rect: this.layerRect_.toArray(),
139               opaque_rect: this.opaqueRect_.toArray()
140             }
141           },
142           {
143             stop: params.stopIndex === undefined ? -1 : params.stopIndex,
144             overdraw: !!params.showOverdraw,
145             params: { }
146           });
147
148       if (raster) {
149         var canvas = document.createElement('canvas');
150         var ctx = canvas.getContext('2d');
151         canvas.width = raster.width;
152         canvas.height = raster.height;
153         var imageData = ctx.createImageData(raster.width, raster.height);
154         imageData.data.set(new Uint8ClampedArray(raster.data));
155         rasterCompleteCallback(new cc.PictureAsImageData(this, imageData));
156       } else {
157         var error = 'Failed to rasterize picture. ' +
158                 'Your recording may be from an old Chrome version. ' +
159                 'The SkPicture format is not backward compatible.';
160         rasterCompleteCallback(new cc.PictureAsImageData(this, error));
161       }
162     }
163   };
164
165   function LayeredPicture(pictures) {
166     this.guid_ = tvcm.GUID.allocate();
167     this.pictures_ = pictures;
168     this.layerRect_ = undefined;
169   }
170
171   LayeredPicture.prototype = {
172     __proto__: Picture.prototype,
173
174     get canSave() {
175       return false;
176     },
177
178     get typeName() {
179       return 'cc::LayeredPicture';
180     },
181
182     get layerRect() {
183       if (this.layerRect_ !== undefined)
184         return this.layerRect_;
185
186       this.layerRect_ = {
187         x: 0,
188         y: 0,
189         width: 0,
190         height: 0
191       };
192
193       for (var i = 0; i < this.pictures_.length; ++i) {
194         var rect = this.pictures_[i].layerRect;
195         this.layerRect_.x = Math.min(this.layerRect_.x, rect.x);
196         this.layerRect_.y = Math.min(this.layerRect_.y, rect.y);
197         this.layerRect_.width =
198             Math.max(this.layerRect_.width, rect.x + rect.width);
199         this.layerRect_.height =
200             Math.max(this.layerRect_.height, rect.y + rect.height);
201       }
202       return this.layerRect_;
203     },
204
205     get guid() {
206       return this.guid_;
207     },
208
209     getBase64SkpData: function() {
210       throw new Error('Not available with a LayeredPicture.');
211     },
212
213     getOps: function() {
214       var ops = [];
215       for (var i = 0; i < this.pictures_.length; ++i)
216         ops = ops.concat(this.pictures_[i].getOps());
217       return ops;
218     },
219
220     getOpTimings: function() {
221       var opTimings = this.pictures_[0].getOpTimings();
222       for (var i = 1; i < this.pictures_.length; ++i) {
223         var timings = this.pictures_[i].getOpTimings();
224         opTimings.cmd_times = opTimings.cmd_times.concat(timings.cmd_times);
225         opTimings.total_time += timings.total_time;
226       }
227       return opTimings;
228     },
229
230     tagOpsWithTimings: function(ops) {
231       var opTimings = new Array();
232       for (var iteration = 0; iteration < OPS_TIMING_ITERATIONS; iteration++) {
233         opTimings[iteration] = this.getOpTimings();
234         if (!opTimings[iteration] || !opTimings[iteration].cmd_times)
235           return ops;
236       }
237
238       for (var opIndex = 0; opIndex < ops.length; opIndex++) {
239         var min = Number.MAX_VALUE;
240         for (var i = 0; i < OPS_TIMING_ITERATIONS; i++)
241           min = Math.min(min, opTimings[i].cmd_times[opIndex]);
242         ops[opIndex].cmd_time = min;
243       }
244       return ops;
245     },
246
247     rasterize: function(params, rasterCompleteCallback) {
248       this.picturesAsImageData_ = [];
249       var rasterCallback = function(pictureAsImageData) {
250         this.picturesAsImageData_.push(pictureAsImageData);
251         if (this.picturesAsImageData_.length !== this.pictures_.length)
252           return;
253
254         var canvas = document.createElement('canvas');
255         var ctx = canvas.getContext('2d');
256         canvas.width = this.layerRect.width;
257         canvas.height = this.layerRect.height;
258
259         // TODO(dsinclair): Verify these finish in the order started.
260         //   Do the rasterize calls run sync or asyn? As the imageData
261         //   going to be in the same order as the pictures_ list?
262         for (var i = 0; i < this.picturesAsImageData_.length; ++i) {
263           ctx.putImageData(this.picturesAsImageData_[i].imageData,
264                            this.pictures_[i].layerRect.x,
265                            this.pictures_[i].layerRect.y);
266         }
267         this.picturesAsImageData_ = [];
268
269         rasterCompleteCallback(new cc.PictureAsImageData(this,
270             ctx.getImageData(this.layerRect.x, this.layerRect.y,
271                              this.layerRect.width, this.layerRect.height)));
272       }.bind(this);
273
274       for (var i = 0; i < this.pictures_.length; ++i)
275         this.pictures_[i].rasterize(params, rasterCallback);
276     }
277   };
278
279
280   /**
281    * @constructor
282    */
283   function PictureSnapshot() {
284     ObjectSnapshot.apply(this, arguments);
285   }
286
287   PictureSnapshot.HasSkiaBenchmarking = function() {
288     if (!window.chrome)
289       return false;
290     if (!window.chrome.skiaBenchmarking)
291       return false;
292     return true;
293   }
294
295   PictureSnapshot.CanRasterize = function() {
296     if (!PictureSnapshot.HasSkiaBenchmarking())
297       return false;
298     if (!window.chrome.skiaBenchmarking.rasterize)
299       return false;
300     return true;
301   }
302
303   PictureSnapshot.CanGetOps = function() {
304     if (!PictureSnapshot.HasSkiaBenchmarking())
305       return false;
306     if (!window.chrome.skiaBenchmarking.getOps)
307       return false;
308     return true;
309   }
310
311   PictureSnapshot.CanGetOpTimings = function() {
312     if (!PictureSnapshot.HasSkiaBenchmarking())
313       return false;
314     if (!window.chrome.skiaBenchmarking.getOpTimings)
315       return false;
316     return true;
317   }
318
319   PictureSnapshot.CanGetInfo = function() {
320     if (!PictureSnapshot.HasSkiaBenchmarking())
321       return false;
322     if (!window.chrome.skiaBenchmarking.getInfo)
323       return false;
324     return true;
325   }
326
327   PictureSnapshot.HowToEnablePictureDebugging = function() {
328     var usualReason = [
329       'For pictures to show up, you need to have Chrome running with ',
330       '--enable-skia-benchmarking. Please restart chrome with this flag ',
331       'and try again.'
332     ].join('');
333
334     if (!window.chrome)
335       return usualReason;
336     if (!window.chrome.skiaBenchmarking)
337       return usualReason;
338     if (!window.chrome.skiaBenchmarking.rasterize)
339       return 'Your chrome is old';
340     if (!window.chrome.skiaBenchmarking.getOps)
341       return 'Your chrome is old: skiaBenchmarking.getOps not found';
342     if (!window.chrome.skiaBenchmarking.getOpTimings)
343       return 'Your chrome is old: skiaBenchmarking.getOpTimings not found';
344     if (!window.chrome.skiaBenchmarking.getInfo)
345       return 'Your chrome is old: skiaBenchmarking.getInfo not found';
346     return 'Rasterizing is on';
347   }
348
349   PictureSnapshot.prototype = {
350     __proto__: ObjectSnapshot.prototype,
351
352     preInitialize: function() {
353       cc.preInitializeObject(this);
354       this.rasterResult_ = undefined;
355     },
356
357     initialize: function() {
358       // If we have an alias args, that means this picture was represented
359       // by an alias, and the real args is in alias.args.
360       if (this.args.alias)
361         this.args = this.args.alias.args;
362
363       if (!this.args.params.layerRect)
364         throw new Error('Missing layer rect');
365
366       this.layerRect_ = this.args.params.layerRect;
367       this.picture_ = new Picture(this.args.skp64,
368           this.args.params.layerRect, this.args.params.opaqueRect);
369     },
370
371     set picture(picture) {
372       this.picture_ = picture;
373     },
374
375     get canSave() {
376       return this.picture_.canSave;
377     },
378
379     get layerRect() {
380       return this.layerRect_ ? this.layerRect_ : this.picture_.layerRect;
381     },
382
383     get guid() {
384       return this.picture_.guid;
385     },
386
387     getBase64SkpData: function() {
388       return this.picture_.getBase64SkpData();
389     },
390
391     getOps: function() {
392       return this.picture_.getOps();
393     },
394
395     getOpTimings: function() {
396       return this.picture_.getOpTimings();
397     },
398
399     tagOpsWithTimings: function(ops) {
400       return this.picture_.tagOpsWithTimings(ops);
401     },
402
403     rasterize: function(params, rasterCompleteCallback) {
404       this.picture_.rasterize(params, rasterCompleteCallback);
405     }
406   };
407
408   ObjectSnapshot.register('cc::Picture', PictureSnapshot);
409
410   return {
411     PictureSnapshot: PictureSnapshot,
412     Picture: Picture,
413     LayeredPicture: LayeredPicture
414   };
415 });