whole_func_string: 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;
      }
    }
  }
func_code_string: 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;
      }
    }
  }
func_documentation_string: (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.