Home | History | Annotate | Download | only in cc
      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 base.requireStylesheet('cc.picture_debugger');
      8 
      9 base.require('cc.picture');
     10 base.require('cc.picture_ops_list_view');
     11 base.require('tracing.analysis.generic_object_view');
     12 base.require('ui.drag_handle');
     13 base.require('ui.info_bar');
     14 base.require('ui.list_view');
     15 base.require('ui.overlay');
     16 
     17 base.exportTo('cc', function() {
     18 
     19   /**
     20    * PictureDebugger is a view of a PictureSnapshot for inspecting
     21    * the picture in detail. (e.g., timing information, etc.)
     22    *
     23    * @constructor
     24    */
     25   var PictureDebugger = ui.define('picture-debugger');
     26 
     27   PictureDebugger.prototype = {
     28     __proto__: HTMLUnknownElement.prototype,
     29 
     30     decorate: function() {
     31       this.pictureAsCanvas_ = undefined;
     32 
     33       this.leftPanel_ = document.createElement('left-panel');
     34 
     35       this.pictureInfo_ = document.createElement('picture-info');
     36 
     37       this.title_ = document.createElement('span');
     38       this.title_.textContent = 'Skia Picture';
     39       this.title_.classList.add('title');
     40       this.sizeInfo_ = document.createElement('span');
     41       this.sizeInfo_.classList.add('size');
     42       this.filename_ = document.createElement('input');
     43       this.filename_.classList.add('filename');
     44       this.filename_.type = 'text';
     45       this.filename_.value = 'skpicture.skp';
     46       var exportButton = document.createElement('button');
     47       exportButton.textContent = 'Export';
     48       exportButton.addEventListener(
     49           'click', this.onSaveAsSkPictureClicked_.bind(this));
     50       this.pictureInfo_.appendChild(this.title_);
     51       this.pictureInfo_.appendChild(this.sizeInfo_);
     52       this.pictureInfo_.appendChild(document.createElement('br'));
     53       this.pictureInfo_.appendChild(this.filename_);
     54       this.pictureInfo_.appendChild(exportButton);
     55 
     56       this.titleDragHandle_ = new ui.DragHandle();
     57       this.titleDragHandle_.horizontal = true;
     58       this.titleDragHandle_.target = this.pictureInfo_;
     59 
     60       this.drawOpsView_ = new cc.PictureOpsListView();
     61       this.drawOpsView_.addEventListener(
     62           'selection-changed', this.onChangeDrawOps_.bind(this));
     63 
     64       this.leftPanel_.appendChild(this.pictureInfo_);
     65       this.leftPanel_.appendChild(this.titleDragHandle_);
     66       this.leftPanel_.appendChild(this.drawOpsView_);
     67 
     68       this.middleDragHandle_ = new ui.DragHandle();
     69       this.middleDragHandle_.horizontal = false;
     70       this.middleDragHandle_.target = this.leftPanel_;
     71 
     72       this.infoBar_ = new ui.InfoBar();
     73       this.rasterArea_ = document.createElement('raster-area');
     74 
     75       this.appendChild(this.leftPanel_);
     76       this.appendChild(this.middleDragHandle_);
     77       this.rasterArea_.appendChild(this.infoBar_);
     78       this.appendChild(this.rasterArea_);
     79 
     80       this.picture_ = undefined;
     81     },
     82 
     83     onSaveAsSkPictureClicked_: function() {
     84       // Decode base64 data into a String
     85       var rawData = atob(this.picture_.getBase64SkpData());
     86 
     87       // Convert this String into an Uint8Array
     88       var length = rawData.length;
     89       var arrayBuffer = new ArrayBuffer(length);
     90       var uint8Array = new Uint8Array(arrayBuffer);
     91       for (var c = 0; c < length; c++)
     92         uint8Array[c] = rawData.charCodeAt(c);
     93 
     94       // Create a blob URL from the binary array.
     95       var blob = new Blob([uint8Array], {type: 'application/octet-binary'});
     96       var blobUrl = window.webkitURL.createObjectURL(blob);
     97 
     98       // Create a link and click on it. BEST API EVAR!
     99       var link = document.createElementNS('http://www.w3.org/1999/xhtml', 'a');
    100       link.href = blobUrl;
    101       link.download = this.filename_.value;
    102       var event = document.createEvent('MouseEvents');
    103       event.initMouseEvent(
    104           'click', true, false, window, 0, 0, 0, 0, 0,
    105           false, false, false, false, 0, null);
    106       link.dispatchEvent(event);
    107     },
    108 
    109     get picture() {
    110       return this.picture_;
    111     },
    112 
    113     set picture(picture) {
    114       this.drawOpsView_.picture = picture;
    115       this.picture_ = picture;
    116       this.rasterize_();
    117 
    118       this.scheduleUpdateContents_();
    119     },
    120 
    121     scheduleUpdateContents_: function() {
    122       if (this.updateContentsPending_)
    123         return;
    124       this.updateContentsPending_ = true;
    125       base.requestAnimationFrameInThisFrameIfPossible(
    126           this.updateContents_.bind(this)
    127       );
    128     },
    129 
    130     updateContents_: function() {
    131       this.updateContentsPending_ = false;
    132 
    133       if (this.picture_) {
    134         this.sizeInfo_.textContent = '(' +
    135             this.picture_.layerRect.width + ' x ' +
    136             this.picture_.layerRect.height + ')';
    137       }
    138 
    139       // Return if picture hasn't finished rasterizing.
    140       if (!this.pictureAsCanvas_)
    141         return;
    142 
    143       this.infoBar_.visible = false;
    144       this.infoBar_.removeAllButtons();
    145       if (this.pictureAsCanvas_.error) {
    146         this.infoBar_.message = 'Cannot rasterize...';
    147         this.infoBar_.addButton('More info...', function() {
    148           var overlay = new ui.Overlay();
    149           overlay.textContent = this.pictureAsCanvas_.error;
    150           overlay.visible = true;
    151           overlay.obeyCloseEvents = true;
    152         }.bind(this));
    153         this.infoBar_.visible = true;
    154       }
    155 
    156       // FIXME(pdr): Append the canvas instead of using a background image.
    157       if (this.pictureAsCanvas_.canvas) {
    158         var imageUrl = this.pictureAsCanvas_.canvas.toDataURL();
    159         this.rasterArea_.style.backgroundImage = 'url("' + imageUrl + '")';
    160       } else {
    161         this.rasterArea_.style.backgroundImage = '';
    162       }
    163     },
    164 
    165     rasterize_: function() {
    166       if (this.picture_) {
    167         this.picture_.rasterize(
    168             {stopIndex: this.drawOpsView_.selectedOpIndex},
    169             this.onRasterComplete_.bind(this));
    170       }
    171     },
    172 
    173     onRasterComplete_: function(pictureAsCanvas) {
    174       this.pictureAsCanvas_ = pictureAsCanvas;
    175       this.scheduleUpdateContents_();
    176     },
    177 
    178     onChangeDrawOps_: function() {
    179       this.rasterize_();
    180       this.scheduleUpdateContents_();
    181     }
    182   };
    183 
    184   return {
    185     PictureDebugger: PictureDebugger
    186   };
    187 });
    188