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