166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis// Copyright (c) 2013 The Chromium Authors. All rights reserved.
266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis// Use of this source code is governed by a BSD-style license that can be
366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis// found in the LICENSE file.
466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis'use strict';
666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennisbase.require('base.guid');
866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennisbase.require('base.rect');
966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennisbase.require('base.raf');
1066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennisbase.require('tracing.trace_model.object_instance');
116833e18b1d4077bf3a727b4422cc2acdbeee35a7Jamie Gennisbase.require('cc.picture_as_canvas');
1266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennisbase.require('cc.util');
1366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
1466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennisbase.exportTo('cc', function() {
1566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
1666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis  var ObjectSnapshot = tracing.trace_model.ObjectSnapshot;
1766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
1866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis  // Number of pictures created. Used as an uniqueId because we are immutable.
1966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis  var PictureCount = 0;
2066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
2166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis  /**
2266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis   * @constructor
2366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis   */
2466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis  function PictureSnapshot() {
2566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    ObjectSnapshot.apply(this, arguments);
2666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    this.guid_ = base.GUID.allocate();
2766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis  }
2866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
2966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis  PictureSnapshot.CanRasterize = function() {
3066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    if (!window.chrome)
3166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis      return false;
3266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    if (!window.chrome.skiaBenchmarking)
3366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis      return false;
3466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    if (!window.chrome.skiaBenchmarking.rasterize)
3566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis      return false;
3666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    return true;
3766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis  }
3866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
3966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis  PictureSnapshot.CanGetOps = function() {
4066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    if (!window.chrome)
4166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis      return false;
4266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    if (!window.chrome.skiaBenchmarking)
4366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis      return false;
4466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    if (!window.chrome.skiaBenchmarking.getOps)
4566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis      return false;
4666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    return true;
4766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis  }
4866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
4966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis  PictureSnapshot.HowToEnablePictureDebugging = function() {
5066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    var usualReason = [
5166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis      'For pictures to show up, you need to have Chrome running with ',
5266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis      '--enable-skia-benchmarking. Please restart chrome with this flag ',
5366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis      'and try again.'
5466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    ].join('');
5566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
5666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    if (!window.chrome)
5766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis      return usualReason;
5866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    if (!window.chrome.skiaBenchmarking)
5966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis      return usualReason;
6066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    if (!window.chrome.skiaBenchmarking.rasterize)
6166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis      return 'Your chrome is old';
6266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    if (!window.chrome.skiaBenchmarking.getOps)
6366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis      return 'Your chrome is old, skiaBenchmarking.getOps not found';
6466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    return 'Rasterizing is on';
6566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis  }
6666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
6766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis  PictureSnapshot.prototype = {
6866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    __proto__: ObjectSnapshot.prototype,
6966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
7066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    preInitialize: function() {
7166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis      cc.preInitializeObject(this);
7266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis      this.rasterResult_ = undefined;
7366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    },
7466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
7566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    initialize: function() {
7666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis      if (!this.args.params.layerRect)
7766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        throw new Error('Missing layer rect');
7866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis      this.layerRect_ = this.args.params.layerRect;
7966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis      this.layerRect_ = base.Rect.FromArray(this.layerRect_);
8066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    },
8166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
8266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    get layerRect() {
8366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis      return this.layerRect_;
8466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    },
8566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
8666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    get guid() {
8766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis      return this.guid_;
8866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    },
8966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
9066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    getBase64SkpData: function() {
9166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis      return this.args.skp64;
9266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    },
9366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
9466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    getOps: function() {
9566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis      if (!PictureSnapshot.CanGetOps()) {
9666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        console.error(PictureSnapshot.HowToEnablePictureDebugging());
9766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        return undefined;
9866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis      }
9966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
10066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis      var ops = window.chrome.skiaBenchmarking.getOps({
10166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        skp64: this.args.skp64,
10266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        params: {
10366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis          layer_rect: this.args.params.layerRect,
10466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis          opaque_rect: this.args.params.opaqueRect
10566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        }
10666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis      });
10766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
10866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis      if (!ops)
10966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        console.error('Failed to get picture ops.');
11066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
11166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis      return ops;
11266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    },
11366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
11466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    /**
11566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis     * Rasterize the picture.
11666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis     *
11766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis     * @param {{opt_stopIndex: number, params}} The SkPicture operation to
11866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis     *     rasterize up to. If not defined, the entire SkPicture is rasterized.
1196833e18b1d4077bf3a727b4422cc2acdbeee35a7Jamie Gennis     * @param {function(cc.PictureAsCanvas)} The callback function that is
1206833e18b1d4077bf3a727b4422cc2acdbeee35a7Jamie Gennis     *     called after rasterization is complete or fails.
12166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis     */
12266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    rasterize: function(params, rasterCompleteCallback) {
12366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis      if (!PictureSnapshot.CanRasterize() || !PictureSnapshot.CanGetOps()) {
1246833e18b1d4077bf3a727b4422cc2acdbeee35a7Jamie Gennis        rasterCompleteCallback(new cc.PictureAsCanvas(
12566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis            this, cc.PictureSnapshot.HowToEnablePictureDebugging()));
12666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        return;
12766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis      }
12866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
12966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis      var raster = window.chrome.skiaBenchmarking.rasterize(
13066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis          {
13166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis            skp64: this.args.skp64,
13266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis            params: {
13366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis              layer_rect: this.args.params.layerRect,
13466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis              opaque_rect: this.args.params.opaqueRect
13566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis            }
13666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis          },
13766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis          {
13866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis            stop: params.stopIndex === undefined ? -1 : params.stopIndex,
13966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis            params: { }
14066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis          });
14166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
14266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis      if (raster) {
1436833e18b1d4077bf3a727b4422cc2acdbeee35a7Jamie Gennis        var canvas = document.createElement('canvas');
1446833e18b1d4077bf3a727b4422cc2acdbeee35a7Jamie Gennis        var ctx = canvas.getContext('2d');
1456833e18b1d4077bf3a727b4422cc2acdbeee35a7Jamie Gennis        canvas.width = raster.width;
1466833e18b1d4077bf3a727b4422cc2acdbeee35a7Jamie Gennis        canvas.height = raster.height;
14766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        var imageData = ctx.createImageData(raster.width, raster.height);
14866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        imageData.data.set(new Uint8ClampedArray(raster.data));
14966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        ctx.putImageData(imageData, 0, 0);
1506833e18b1d4077bf3a727b4422cc2acdbeee35a7Jamie Gennis        rasterCompleteCallback(new cc.PictureAsCanvas(this, canvas));
15166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis      } else {
15266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis        var error = 'Failed to rasterize picture. ' +
15366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis                'Your recording may be from an old Chrome version. ' +
15466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis                'The SkPicture format is not backward compatible.';
1556833e18b1d4077bf3a727b4422cc2acdbeee35a7Jamie Gennis        rasterCompleteCallback(new cc.PictureAsCanvas(this, error));
15666a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis      }
15766a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    }
15866a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis  };
15966a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
16066a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis  ObjectSnapshot.register('cc::Picture', PictureSnapshot);
16166a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis
16266a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis  return {
16366a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis    PictureSnapshot: PictureSnapshot
16466a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis  };
16566a37686207944273ced825e0e8b6b6375f8c3deJamie Gennis});
166