Home | History | Annotate | Download | only in ui
      1 // Copyright (c) 2012 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.require('base.range');
      8 base.require('base.events');
      9 
     10 base.exportTo('ui', function() {
     11   // FIXME(pdr): Replace this padding with just what's necessary for
     12   //             drawing borders / highlights.
     13   //             https://code.google.com/p/trace-viewer/issues/detail?id=228
     14   var DEFAULT_PAD_PERCENTAGE = 0.75;
     15 
     16   function QuadViewViewport(worldRect,
     17                             opt_quad_stack_scale,
     18                             opt_padding,
     19                             opt_devicePixelRatio) {
     20     base.EventTarget.call(this);
     21     if (!worldRect)
     22       throw new Error('Cannot initialize a viewport with an empty worldRect');
     23 
     24     // Physical pixels / device-independent pixels;
     25     // 1 is normal; higher for eg Retina
     26     this.devicePixelRatio =
     27         opt_devicePixelRatio || window.devicePixelRatio || 1;
     28 
     29     this.layoutRect_ = undefined;
     30     this.setWorldRect_(worldRect, opt_padding);
     31 
     32     var scale;
     33     if (opt_quad_stack_scale) {
     34       scale = opt_quad_stack_scale;
     35     } else {
     36       scale = 0.125;
     37       if (this.devicePixelRatio > 1)
     38         scale = scale * this.devicePixelRatio;
     39     }
     40     this.worldPixelsPerDevicePixel_ = scale;
     41 
     42     this.updateScale_();
     43   }
     44 
     45   QuadViewViewport.prototype = {
     46 
     47     __proto__: base.EventTarget.prototype,
     48 
     49     // The pixels in the original, traced browser are
     50     // represented in a canvas 'world', scaled by a
     51     // this 'scale' value.
     52     set scale(scale) {
     53       this.worldPixelsPerDevicePixel_ = scale;
     54       this.updateScale_();
     55       this.didChange_();
     56     },
     57 
     58     get scale() {
     59       return this.worldPixelsPerDevicePixel_;
     60     },
     61 
     62     get worldRect() {
     63       return this.worldRect_;
     64     },
     65 
     66     get unpaddedWorldRect() {
     67       return this.unpaddedWorldRect_;
     68     },
     69 
     70     updateBoxSize: function(canvas) {
     71       var resizedCanvas = false;
     72       if (canvas.width !== this.worldWidthInDevicePixels_) {
     73         canvas.width = this.worldWidthInDevicePixels_ * ui.RASTER_SCALE;
     74         canvas.style.width = this.layoutRect_.width + 'px';
     75         resizedCanvas = true;
     76       }
     77       if (canvas.height !== this.worldHeightInDevicePixels_) {
     78         canvas.height = this.worldHeightInDevicePixels_ * ui.RASTER_SCALE;
     79         canvas.style.height = this.layoutRect_.height + 'px';
     80         resizedCanvas = true;
     81       }
     82       return resizedCanvas;
     83     },
     84 
     85     layoutPixelsToWorldPixels: function(v) {
     86       var tmp = this.layoutPixelsToDevicePixels(v);
     87       return this.devicePixelsToWorldPixels(tmp);
     88     },
     89 
     90     layoutPixelsToDevicePixels: function(v) {
     91       var res = vec2.create();
     92       return vec2.scale(res, v, this.devicePixelRatio);
     93     },
     94 
     95     devicePixelsToWorldPixels: function(v) {
     96       var res = vec2.create();
     97       vec2.transformMat2d(res, v, this.transformDevicePixelsToWorld_);
     98       return res;
     99     },
    100 
    101     getWorldToDevicePixelsTransform: function() {
    102       return this.transformWorldToDevicePixels_;
    103     },
    104 
    105     getDeviceLineWidthAssumingTransformIsApplied: function(
    106         desiredDeviceLineWidth) {
    107       return desiredDeviceLineWidth / this.worldPixelsPerDevicePixel_;
    108     },
    109 
    110     applyTransformToContext: function(ctx) {
    111       var transform = this.transformWorldToDevicePixels_;
    112       ctx.transform(transform[0], transform[1], transform[2],
    113                     transform[3], transform[4], transform[5]);
    114     },
    115 
    116     forceRedrawAll: function() {
    117       this.didChange_();
    118     },
    119 
    120     //-------------------------------------------
    121 
    122     updateScale_: function() {
    123       this.worldWidthInDevicePixels_ =
    124           this.worldRect_.width * this.worldPixelsPerDevicePixel_;
    125       this.worldHeightInDevicePixels_ =
    126           this.worldRect_.height * this.worldPixelsPerDevicePixel_;
    127 
    128       this.updateLayoutRect_();
    129 
    130       this.transformWorldToDevicePixels_ = mat2d.create();
    131       this.transformDevicePixelsToWorld_ = mat2d.create();
    132       this.updateTransform_();
    133     },
    134 
    135     /** Adjust the scaled world box for Retina-like displays */
    136     updateLayoutRect_: function() {
    137       var devicePixelsPerLayoutPixel =
    138           this.worldPixelsPerDevicePixel_ / this.devicePixelRatio;
    139       this.layoutRect_ = this.worldRect.scale(devicePixelsPerLayoutPixel);
    140     },
    141 
    142     setWorldRect_: function(worldRect, opt_padding) {
    143       var worldPad;
    144       var padding;
    145       if (opt_padding !== undefined) {
    146         padding = opt_padding;
    147       } else {
    148         padding = DEFAULT_PAD_PERCENTAGE;
    149       }
    150       worldPad = Math.min(worldRect.width,
    151                           worldRect.height) * padding;
    152 
    153       this.unpaddedWorldRect_ = worldRect;
    154       this.worldRect_ = worldRect.clone().enlarge(worldPad);
    155     },
    156 
    157     updateTransform_: function() {
    158       if (!this.transformWorldToDevicePixels_)
    159         return;
    160 
    161       mat2d.identity(this.transformWorldToDevicePixels_);
    162       mat2d.translateXY(
    163           this.transformWorldToDevicePixels_,
    164           -this.worldRect_.x, -this.worldRect_.y);
    165       mat2d.scaleXY(this.transformWorldToDevicePixels_,
    166           this.worldPixelsPerDevicePixel_,
    167           this.worldPixelsPerDevicePixel_);
    168 
    169       mat2d.invert(this.transformDevicePixelsToWorld_,
    170                    this.transformWorldToDevicePixels_);
    171     },
    172 
    173     didChange_: function() {
    174       base.dispatchSimpleEvent(this, 'change', false, false);
    175     }
    176   };
    177 
    178   return {
    179     QuadViewViewport: QuadViewViewport
    180   };
    181 });
    182