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