1<!DOCTYPE html> 2<!-- 3Copyright (c) 2012 The Chromium Authors. All rights reserved. 4Use of this source code is governed by a BSD-style license that can be 5found in the LICENSE file. 6--> 7<link rel="import" href="/tracing/base/base.html"> 8<script> 9'use strict'; 10 11/** 12 * @fileoverview Provides a mechanism for drawing massive numbers of 13 * colored rectangles into a canvas in an efficient manner, provided 14 * they are drawn left to right with fixed y and height throughout. 15 * 16 * The basic idea used here is to fuse subpixel rectangles together so that 17 * we never issue a canvas fillRect for them. It turns out Javascript can 18 * do this quite efficiently, compared to asking Canvas2D to do the same. 19 * 20 * A few extra things are done by this class in the name of speed: 21 * - Viewport culling: off-viewport rectangles are discarded. 22 * 23 * - The actual discarding operation is done in world space, 24 * e.g. pre-transform. 25 * 26 * - Rather than expending compute cycles trying to figure out an average 27 * color for fused rectangles from css strings, you instead draw using 28 * palletized colors. The fused rect color is choosen from the rectangle with 29 * the higher alpha value, if equal the max pallete index encountered. 30 * 31 * Make sure to flush the trackRenderer before finishing drawing in order 32 * to commit any queued drawing operations. 33 */ 34tr.exportTo('tr.ui.b', function() { 35 36 /** 37 * Creates a fast rect renderer with a specific set of culling rules 38 * and color pallette. 39 * @param {GraphicsContext2D} ctx Canvas2D drawing context. 40 * @param {number} minRectSize Only rectangles with width < minRectSize are 41 * considered for merging. 42 * @param {number} maxMergeDist Controls how many successive small rectangles 43 * can be merged together before issuing a rectangle. 44 * @param {Array} pallette The color pallete for drawing. Pallette slots 45 * should map to valid Canvas fillStyle strings. 46 * 47 * @constructor 48 */ 49 function FastRectRenderer(ctx, minRectSize, maxMergeDist, pallette) { 50 this.ctx_ = ctx; 51 this.minRectSize_ = minRectSize; 52 this.maxMergeDist_ = maxMergeDist; 53 this.pallette_ = pallette; 54 } 55 56 FastRectRenderer.prototype = { 57 y_: 0, 58 h_: 0, 59 merging_: false, 60 mergeStartX_: 0, 61 mergeCurRight_: 0, 62 mergedColorId_: 0, 63 mergedAlpha_: 0, 64 65 /** 66 * Changes the y position and height for subsequent fillRect 67 * calls. x and width are specifieid on the fillRect calls. 68 */ 69 setYandH: function(y, h) { 70 if (this.y_ === y && 71 this.h_ === h) 72 return; 73 this.flush(); 74 this.y_ = y; 75 this.h_ = h; 76 }, 77 78 /** 79 * Fills rectangle at the specified location, if visible. If the 80 * rectangle is subpixel, it will be merged with adjacent rectangles. 81 * The drawing operation may not take effect until flush is called. 82 * @param {number} colorId The color of this rectangle, as an index 83 * in the renderer's color pallete. 84 * @param {number} alpha The opacity of the rectangle as 0.0-1.0 number. 85 */ 86 fillRect: function(x, w, colorId, alpha) { 87 var r = x + w; 88 if (w < this.minRectSize_) { 89 if (r - this.mergeStartX_ > this.maxMergeDist_) 90 this.flush(); 91 if (!this.merging_) { 92 this.merging_ = true; 93 this.mergeStartX_ = x; 94 this.mergeCurRight_ = r; 95 this.mergedColorId_ = colorId; 96 this.mergedAlpha_ = alpha; 97 } else { 98 this.mergeCurRight_ = r; 99 100 if (this.mergedAlpha_ < alpha || 101 (this.mergedAlpha_ === alpha && this.mergedColorId_ < colorId)) { 102 this.mergedAlpha_ = alpha; 103 this.mergedColorId_ = colorId; 104 } 105 } 106 } else { 107 if (this.merging_) 108 this.flush(); 109 this.ctx_.fillStyle = this.pallette_[colorId]; 110 this.ctx_.globalAlpha = alpha; 111 this.ctx_.fillRect(x, this.y_, w, this.h_); 112 } 113 }, 114 115 /** 116 * Commits any pending fillRect operations to the underlying graphics 117 * context. 118 */ 119 flush: function() { 120 if (this.merging_) { 121 this.ctx_.fillStyle = this.pallette_[this.mergedColorId_]; 122 this.ctx_.globalAlpha = this.mergedAlpha_; 123 this.ctx_.fillRect(this.mergeStartX_, this.y_, 124 this.mergeCurRight_ - this.mergeStartX_, this.h_); 125 this.merging_ = false; 126 } 127 } 128 }; 129 130 return { 131 FastRectRenderer: FastRectRenderer 132 }; 133}); 134</script> 135