1f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved. 2f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 3f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// found in the LICENSE file. 4f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 5f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)'use strict'; 6f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 7f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)/** 8f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * Command queue is the only way to modify images. 9f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * Supports undo/redo. 10f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * Command execution is asynchronous (callback-based). 11f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * 12f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * @param {Document} document Document to create canvases in. 13f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * @param {HTMLCanvasElement} canvas The canvas with the original image. 14f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * @param {function(callback)} saveFunction Function to save the image. 15f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * @constructor 16f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) */ 17f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)function CommandQueue(document, canvas, saveFunction) { 18f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) this.document_ = document; 19f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) this.undo_ = []; 20f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) this.redo_ = []; 21f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) this.subscribers_ = []; 22f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) this.currentImage_ = canvas; 23f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 24f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Current image may be null or not-null but with width = height = 0. 25f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Copying an image with zero dimensions causes js errors. 26f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (this.currentImage_) { 27f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) this.baselineImage_ = document.createElement('canvas'); 28f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) this.baselineImage_.width = this.currentImage_.width; 29f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) this.baselineImage_.height = this.currentImage_.height; 30f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (this.currentImage_.width > 0 && this.currentImage_.height > 0) { 31f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) var context = this.baselineImage_.getContext('2d'); 32f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) context.drawImage(this.currentImage_, 0, 0); 33f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 34f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } else { 35f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) this.baselineImage_ = null; 36f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 37f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 38f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) this.previousImage_ = document.createElement('canvas'); 39f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) this.previousImageAvailable_ = false; 40f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 41f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) this.saveFunction_ = saveFunction; 42f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) this.busy_ = false; 43f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) this.UIContext_ = {}; 44f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} 45f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 46f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)/** 47f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * Attach the UI elements to the command queue. 48f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * Once the UI is attached the results of image manipulations are displayed. 49f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * 50f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * @param {ImageView} imageView The ImageView object to display the results. 51f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * @param {ImageEditor.Prompt} prompt Prompt to use with this CommandQueue. 52f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * @param {function(boolean)} lock Function to enable/disable buttons etc. 53f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) */ 54f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)CommandQueue.prototype.attachUI = function(imageView, prompt, lock) { 55f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) this.UIContext_ = { 56f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) imageView: imageView, 57f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) prompt: prompt, 58f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) lock: lock 59f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) }; 60f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}; 61f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 62f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)/** 63f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * Execute the action when the queue is not busy. 64f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * @param {function} callback Callback. 65f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) */ 66f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)CommandQueue.prototype.executeWhenReady = function(callback) { 67f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (this.isBusy()) 68f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) this.subscribers_.push(callback); 69f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) else 70f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) setTimeout(callback, 0); 71f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}; 72f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 73f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)/** 74f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * @return {boolean} True if the command queue is busy. 75f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) */ 76f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)CommandQueue.prototype.isBusy = function() { return this.busy_ }; 77f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 78f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)/** 79f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * Set the queue state to busy. Lock the UI. 80f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * @private 81f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) */ 82f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)CommandQueue.prototype.setBusy_ = function() { 83f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (this.busy_) 84f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) throw new Error('CommandQueue already busy'); 85f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 86f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) this.busy_ = true; 87f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 88f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (this.UIContext_.lock) 89f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) this.UIContext_.lock(true); 90f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 91f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) ImageUtil.trace.resetTimer('command-busy'); 92f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}; 93f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 94f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)/** 95f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * Set the queue state to not busy. Unlock the UI and execute pending actions. 96f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * @private 97f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) */ 98f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)CommandQueue.prototype.clearBusy_ = function() { 99f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (!this.busy_) 100f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) throw new Error('Inconsistent CommandQueue already not busy'); 101f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 102f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) this.busy_ = false; 103f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 104f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Execute the actions requested while the queue was busy. 105f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) while (this.subscribers_.length) 106f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) this.subscribers_.shift()(); 107f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 108f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (this.UIContext_.lock) 109f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) this.UIContext_.lock(false); 110f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 111f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) ImageUtil.trace.reportTimer('command-busy'); 112f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}; 113f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 114f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)/** 115f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * Commit the image change: save and unlock the UI. 116f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * @param {number=} opt_delay Delay in ms (to avoid disrupting the animation). 117f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * @private 118f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) */ 119f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)CommandQueue.prototype.commit_ = function(opt_delay) { 120f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) setTimeout(this.saveFunction_.bind(null, this.clearBusy_.bind(this)), 121f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) opt_delay || 0); 122f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}; 123f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 124f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)/** 125f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * Internal function to execute the command in a given context. 126f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * 127f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * @param {Command} command The command to execute. 128f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * @param {Object} uiContext The UI context. 129f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * @param {function} callback Completion callback. 130f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * @private 131f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) */ 132f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)CommandQueue.prototype.doExecute_ = function(command, uiContext, callback) { 133f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (!this.currentImage_) 134f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) throw new Error('Cannot operate on null image'); 135f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 136f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Remember one previous image so that the first undo is as fast as possible. 137f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) this.previousImage_.width = this.currentImage_.width; 138f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) this.previousImage_.height = this.currentImage_.height; 139f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) this.previousImageAvailable_ = true; 140f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) var context = this.previousImage_.getContext('2d'); 141f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) context.drawImage(this.currentImage_, 0, 0); 142f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 143f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) command.execute( 144f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) this.document_, 145f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) this.currentImage_, 146f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) function(result, opt_delay) { 147f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) this.currentImage_ = result; 148f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) callback(opt_delay); 149f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) }.bind(this), 150f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) uiContext); 151f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}; 152f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 153f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)/** 154f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * Executes the command. 155f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * 156f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * @param {Command} command Command to execute. 157f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * @param {boolean=} opt_keep_redo True if redo stack should not be cleared. 158f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) */ 159f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)CommandQueue.prototype.execute = function(command, opt_keep_redo) { 160f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) this.setBusy_(); 161f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 162f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (!opt_keep_redo) 163f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) this.redo_ = []; 164f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 165f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) this.undo_.push(command); 166f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 167f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) this.doExecute_(command, this.UIContext_, this.commit_.bind(this)); 168f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}; 169f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 170f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)/** 171f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * @return {boolean} True if Undo is applicable. 172f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) */ 173f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)CommandQueue.prototype.canUndo = function() { 174f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return this.undo_.length != 0; 175f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}; 176f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 177f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)/** 178f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * Undo the most recent command. 179f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) */ 180f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)CommandQueue.prototype.undo = function() { 181f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (!this.canUndo()) 182f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) throw new Error('Cannot undo'); 183f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 184f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) this.setBusy_(); 185f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 186f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) var command = this.undo_.pop(); 187f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) this.redo_.push(command); 188f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 189f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) var self = this; 190f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 191f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) function complete() { 192f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) var delay = command.revertView( 193f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) self.currentImage_, self.UIContext_.imageView); 194f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) self.commit_(delay); 195f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 196f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 197f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (this.previousImageAvailable_) { 198f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // First undo after an execute call. 199f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) this.currentImage_.width = this.previousImage_.width; 200f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) this.currentImage_.height = this.previousImage_.height; 201f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) var context = this.currentImage_.getContext('2d'); 202f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) context.drawImage(this.previousImage_, 0, 0); 203f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 204f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Free memory. 205f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) this.previousImage_.width = 0; 206f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) this.previousImage_.height = 0; 207f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) this.previousImageAvailable_ = false; 208f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 209f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) complete(); 210f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // TODO(kaznacheev) Consider recalculating previousImage_ right here 211f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // by replaying the commands in the background. 212f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } else { 213f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) this.currentImage_.width = this.baselineImage_.width; 214f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) this.currentImage_.height = this.baselineImage_.height; 215f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) var context = this.currentImage_.getContext('2d'); 216f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) context.drawImage(this.baselineImage_, 0, 0); 217f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 218f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) var replay = function(index) { 219f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (index < self.undo_.length) 220f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) self.doExecute_(self.undo_[index], {}, replay.bind(null, index + 1)); 221f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) else { 222f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) complete(); 223f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 224f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) }; 225f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 226f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) replay(0); 227f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 228f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}; 229f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 230f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)/** 231f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * @return {boolean} True if Redo is applicable. 232f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) */ 233f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)CommandQueue.prototype.canRedo = function() { 234f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return this.redo_.length != 0; 235f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}; 236f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 237f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)/** 238f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * Repeat the command that was recently un-done. 239f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) */ 240f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)CommandQueue.prototype.redo = function() { 241f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (!this.canRedo()) 242f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) throw new Error('Cannot redo'); 243f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 244f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) this.execute(this.redo_.pop(), true); 245f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}; 246f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 247f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)/** 248f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * Closes internal buffers. Call to ensure, that internal buffers are freed 249f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * as soon as possible. 250f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) */ 251f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)CommandQueue.prototype.close = function() { 252f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Free memory used by the undo buffer. 253f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) this.previousImage_.width = 0; 254f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) this.previousImage_.height = 0; 255f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) this.previousImageAvailable_ = false; 256f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 257f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (this.baselineImage_) { 258f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) this.baselineImage_.width = 0; 259f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) this.baselineImage_.height = 0; 260f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 261f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}; 262f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 263f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)/** 264f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * Command object encapsulates an operation on an image and a way to visualize 265f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * its result. 266f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * 267f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * @param {string} name Command name. 268f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * @constructor 269f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) */ 270f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)function Command(name) { 271f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) this.name_ = name; 272f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} 273f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 274f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)/** 275f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * @return {string} String representation of the command. 276f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) */ 277f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)Command.prototype.toString = function() { 278f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return 'Command ' + this.name_; 279f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}; 280f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 281f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)/** 282f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * Execute the command and visualize its results. 283f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * 284f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * The two actions are combined into one method because sometimes it is nice 285f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * to be able to show partial results for slower operations. 286f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * 287f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * @param {Document} document Document on which to execute command. 288f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * @param {HTMLCanvasElement} srcCanvas Canvas to execute on. 289f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * @param {function(HTMLCanvasElement, number)} callback Callback to call on 290f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * completion. 291f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * @param {Object} uiContext Context to work in. 292f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) */ 293f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)Command.prototype.execute = function(document, srcCanvas, callback, uiContext) { 294f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) console.error('Command.prototype.execute not implemented'); 295f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}; 296f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 297f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)/** 298f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * Visualize reversion of the operation. 299f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * 300f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * @param {HTMLCanvasElement} canvas Image data to use. 301f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * @param {ImageView} imageView ImageView to revert. 302f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * @return {number} Animation duration in ms. 303f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) */ 304f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)Command.prototype.revertView = function(canvas, imageView) { 305f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) imageView.replace(canvas); 306f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return 0; 307f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}; 308f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 309f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)/** 310f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * Creates canvas to render on. 311f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * 312f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * @param {Document} document Document to create canvas in. 313f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * @param {HTMLCanvasElement} srcCanvas to copy optional dimensions from. 314f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * @param {number=} opt_width new canvas width. 315f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * @param {number=} opt_height new canvas height. 316f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * @return {HTMLCanvasElement} Newly created canvas. 317f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * @private 318f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) */ 319f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)Command.prototype.createCanvas_ = function( 320f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) document, srcCanvas, opt_width, opt_height) { 321f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) var result = document.createElement('canvas'); 322f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) result.width = opt_width || srcCanvas.width; 323f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) result.height = opt_height || srcCanvas.height; 324f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return result; 325f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}; 326f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 327f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 328f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)/** 329f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * Rotate command 330f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * @param {number} rotate90 Rotation angle in 90 degree increments (signed). 331f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * @constructor 332f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * @extends {Command} 333f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) */ 334f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)Command.Rotate = function(rotate90) { 335f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) Command.call(this, 'rotate(' + rotate90 * 90 + 'deg)'); 336f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) this.rotate90_ = rotate90; 337f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}; 338f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 339f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)Command.Rotate.prototype = { __proto__: Command.prototype }; 340f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 341f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)/** @override */ 342f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)Command.Rotate.prototype.execute = function( 343f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) document, srcCanvas, callback, uiContext) { 344f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) var result = this.createCanvas_( 345f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) document, 346f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) srcCanvas, 347f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) (this.rotate90_ & 1) ? srcCanvas.height : srcCanvas.width, 348f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) (this.rotate90_ & 1) ? srcCanvas.width : srcCanvas.height); 349f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) ImageUtil.drawImageTransformed( 350f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) result, srcCanvas, 1, 1, this.rotate90_ * Math.PI / 2); 351f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) var delay; 352f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (uiContext.imageView) { 353f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) delay = uiContext.imageView.replaceAndAnimate(result, null, this.rotate90_); 354f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 355f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) setTimeout(callback, 0, result, delay); 356f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}; 357f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 358f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)/** @override */ 359f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)Command.Rotate.prototype.revertView = function(canvas, imageView) { 360f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return imageView.replaceAndAnimate(canvas, null, -this.rotate90_); 361f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}; 362f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 363f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 364f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)/** 365f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * Crop command. 366f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * 367f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * @param {Rect} imageRect Crop rectangle in image coordinates. 368f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * @constructor 369f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * @extends {Command} 370f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) */ 371f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)Command.Crop = function(imageRect) { 372f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) Command.call(this, 'crop' + imageRect.toString()); 373f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) this.imageRect_ = imageRect; 374f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}; 375f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 376f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)Command.Crop.prototype = { __proto__: Command.prototype }; 377f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 378f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)/** @override */ 379f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)Command.Crop.prototype.execute = function( 380f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) document, srcCanvas, callback, uiContext) { 381f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) var result = this.createCanvas_( 382f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) document, srcCanvas, this.imageRect_.width, this.imageRect_.height); 383f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) Rect.drawImage(result.getContext('2d'), srcCanvas, null, this.imageRect_); 384f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) var delay; 385f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (uiContext.imageView) { 386f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) delay = uiContext.imageView.replaceAndAnimate(result, this.imageRect_, 0); 387f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 388f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) setTimeout(callback, 0, result, delay); 389f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}; 390f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 391f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)/** @override */ 392f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)Command.Crop.prototype.revertView = function(canvas, imageView) { 393f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return imageView.animateAndReplace(canvas, this.imageRect_); 394f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}; 395f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 396f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 397f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)/** 398f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * Filter command. 399f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * 400f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * @param {string} name Command name. 401f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * @param {function(ImageData,ImageData,number,number)} filter Filter function. 402f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * @param {string} message Message to display when done. 403f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * @constructor 404f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * @extends {Command} 405f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) */ 406f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)Command.Filter = function(name, filter, message) { 407f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) Command.call(this, name); 408f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) this.filter_ = filter; 409f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) this.message_ = message; 410f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}; 411f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 412f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)Command.Filter.prototype = { __proto__: Command.prototype }; 413f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 414f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)/** @override */ 415f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)Command.Filter.prototype.execute = function( 416f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) document, srcCanvas, callback, uiContext) { 417f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) var result = this.createCanvas_(document, srcCanvas); 418f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 419f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) var self = this; 420f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 421f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) var previousRow = 0; 422f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 423f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) function onProgressVisible(updatedRow, rowCount) { 424f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (updatedRow == rowCount) { 425f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) uiContext.imageView.replace(result); 426f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (self.message_) 427f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) uiContext.prompt.show(self.message_, 2000); 428f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) callback(result); 429f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } else { 430f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) var viewport = uiContext.imageView.viewport_; 431f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 432f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) var imageStrip = new Rect(viewport.getImageBounds()); 433f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) imageStrip.top = previousRow; 434f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) imageStrip.height = updatedRow - previousRow; 435f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 436f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) var screenStrip = new Rect(viewport.getImageBoundsOnScreen()); 437f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) screenStrip.top = Math.round(viewport.imageToScreenY(previousRow)); 438f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) screenStrip.height = 439f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) Math.round(viewport.imageToScreenY(updatedRow)) - screenStrip.top; 440f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 441f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) uiContext.imageView.paintDeviceRect( 442f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) viewport.screenToDeviceRect(screenStrip), result, imageStrip); 443f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) previousRow = updatedRow; 444f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 445f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 446f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 447f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) function onProgressInvisible(updatedRow, rowCount) { 448f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (updatedRow == rowCount) { 449f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) callback(result); 450f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 451f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 452f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 453f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) filter.applyByStrips(result, srcCanvas, this.filter_, 454f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) uiContext.imageView ? onProgressVisible : onProgressInvisible); 455f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}; 456