function RecordingContext(ctx) {
  forward(this, ctx, true /* only foward accessors */);

  var calls = [];
  this.calls = calls;

  for (var k in ctx) {
    (function(k) {
      if (typeof(ctx[k]) != 'function') return;
      this[k] = function() {
        // TODO: record current drawing style
        var args = Array.prototype.slice.call(arguments);
        calls.push([k].concat(args));
        return ctx[k].apply(ctx, arguments);
      };
    }).bind(this)(k);
  }

  this.pushObject = function(o) {
    calls.push(['pushObject', o]);
  };
  
  this.popObject = function() {
    calls.push(['popObject']);
  };

  this.reset = function() {
    this.calls = calls = [];
  };

  var recordingDrawImage = this.drawImage;  // plain recording drawImage()
  this.drawImage = function(image) {
    // If the drawn image has recorded calls, then they need to be transferred over.
    var recorder = RecordingContext.recorderForCanvas(image);
    if (!recorder) {
      recordingDrawImage.apply(ctx, arguments);
    } else {
      ctx.drawImage.apply(ctx, arguments);
      calls = calls.concat(transformedCalls(recorder.calls, arguments));
      this.calls = calls;
    }
  }
}
function RecordingContext(ctx) {
  forward(this, ctx, true );

  var calls = [];
  this.calls = calls;

  for (var k in ctx) {
    (function(k) {
      if (typeof(ctx[k]) != 'function') return;
      this[k] = function() {
        
        var args = Array.prototype.slice.call(arguments);
        calls.push([k].concat(args));
        return ctx[k].apply(ctx, arguments);
      };
    }).bind(this)(k);
  }

  this.pushObject = function(o) {
    calls.push(['pushObject', o]);
  };
  
  this.popObject = function() {
    calls.push(['popObject']);
  };

  this.reset = function() {
    this.calls = calls = [];
  };

  var recordingDrawImage = this.drawImage;  
  this.drawImage = function(image) {
    
    var recorder = RecordingContext.recorderForCanvas(image);
    if (!recorder) {
      recordingDrawImage.apply(ctx, arguments);
    } else {
      ctx.drawImage.apply(ctx, arguments);
      calls = calls.concat(transformedCalls(recorder.calls, arguments));
      this.calls = calls;
    }
  }
}
function RecordingContext ( ctx ) { forward ( this , ctx , true /* only foward accessors */ ) ; var calls = [ ] ; this . calls = calls ; for ( var k in ctx ) { ( function ( k ) { if ( typeof ( ctx [ k ] ) != 'function' ) return ; this [ k ] = function ( ) { // TODO: record current drawing style var args = Array . prototype . slice . call ( arguments ) ; calls . push ( [ k ] . concat ( args ) ) ; return ctx [ k ] . apply ( ctx , arguments ) ; } ; } ) . bind ( this ) ( k ) ; } this . pushObject = function ( o ) { calls . push ( [ 'pushObject' , o ] ) ; } ; this . popObject = function ( ) { calls . push ( [ 'popObject' ] ) ; } ; this . reset = function ( ) { this . calls = calls = [ ] ; } ; var recordingDrawImage = this . drawImage ; // plain recording drawImage() this . drawImage = function ( image ) { // If the drawn image has recorded calls, then they need to be transferred over. var recorder = RecordingContext . recorderForCanvas ( image ) ; if ( ! recorder ) { recordingDrawImage . apply ( ctx , arguments ) ; } else { ctx . drawImage . apply ( ctx , arguments ) ; calls = calls . concat ( transformedCalls ( recorder . calls , arguments ) ) ; this . calls = calls ; } } }
(CanvasRenderingContext2D, DataContext) pairs 
A context which records what it does (for testing).

This proxies all calls to the underlying canvas, so they do produce visible
drawing. Use `drawnObjectsWith` or `calls` to test what was drawn.
( CanvasRenderingContext2D DataContext ) pairs A context which records what it does ( for testing ) .