title: context drawImage / canvas toDataURL lagging significantly on opera mobile
body: <p>I have a bit of Javascript that runs on an <strong>Android</strong> tablet, running <strong>Opera Mobile 12</strong>. The tablet is attached to the wall in an office, so it's used by everyone who works in this office, as a timekeeping system (ie. they use it to clock in/clock out of work). This javascript takes a photo of the user when a certain event is raised, then converts this photo to a data URL so it can be sent to a server. This all runs in the background, though - <em>the <code>video</code> and <code>canvas</code> elements are both set to <code>display:none;</code></em>.</p>
  
  <p>Here's the code that handles the webcam interaction:</p>
  
  <pre><code>var Webcam = function() {
    var video = document.getElementById('video');
    var stream_webcam = function(stream) {
      video.addEventListener('loadedmetadata', function(){
        video.play();
      }, false);
      video.src = window.URL.createObjectURL(stream);
    }
  
    // start recording
    if (navigator.getUserMedia)
      navigator.getUserMedia({video: true}, stream_webcam);
    else
      _error("No navigator.getUserMedia support detected!");
  
    var w = {};
  
    w.snap = function(callback) {
      var canvas = document.getElementById('canvas');
      canvas.getContext('2d').drawImage(video, 0, 0, canvas.width, canvas.height);
      // delay is incurred in writing to canvas on opera mobile
      setTimeout(function() {
        callback(canvas.toDataURL());
      }, 1);
    };
  
    return w;
  }
  </code></pre>
  
  <p><code>w.snap(callback)</code> gets called when the user presses a certain button. The problem is that there is a <em>significant</em> lag between the call to <code>drawImage</code>, and an image actually being drawn to the canvas. <strong>Here's the problem that occurs</strong>:</p>
  
  <ul>
  <li>User 1 users the tablet, presses the button, has their photo "snapped" and sent to the server. The server receives a blank, transparent, image. (It's not the same issue as <a href="https://stackoverflow.com/questions/6919181/html5-canvas-todataurl-returns-blank-image">html5 canvas toDataURL returns blank image</a> - the data being sent to the server is substantially less for the first image, because it's blank)</li>
  <li>A few minutes later, user 2 uses the tablet and presses the button, and has their photo "snapped". The server receives the photo of user 1.</li>
  <li>Later, user 3 does the same thing, and the server gets a photo of user 2.</li>
  </ul>
  
  <p>So I'm guessing the call to <code>toDataURL()</code> is returning old data because <code>drawImage()</code> doesn't . (I read somewhere that it's async, but I can't confirm and can't find any way of attaching an event to when it finishes drawing.)</p>
  
  <p>I've tried:</p>
  
  <ul>
  <li>changing the timeout in <code>snap()</code> to a variety of values. The highest I tried was 2000, but the same issue occurred. (If anyone suggests higher numbers, I'm happy to try them, but I don't want to go much higher because if I go too high, there's potential for user 3 to have their photo taken before I've even processed user 2's photo, which means I might lose it entirely!)</li>
  <li>having the canvas draw something when the page first loads, but that didn't fix it - when user 1 was photographed, the server received whatever photo was taken when the page loaded, instead of the photo of user 1.</li>
  <li>"getting" the canvas element again, using <code>getElementById</code>, before calling <code>toDataURL</code>.</li>
  </ul>
  
  <p>A few more notes:</p>
  
  <ul>
  <li>This works fine on my computer (macbook air) in Chrome and Opera.</li>
  <li>I can't reliably replicate it using a debugger (linking to the tablet using Opera Dragonfly).</li>
  <li>AFAIK Opera Mobile is the only Android browser that supports <code>getUserMedia</code> and can thus take photos.</li>
  <li>If I remove the <code>display:none;</code> from the <code>video</code> and <code>canvas</code>, it works correctly (on the tablet). <strong>The issue only occurs when the video and canvas have <code>display:none;</code> set.</strong></li>
  </ul>
  
  <p>Because the page is a single page app with no scrolling or zooming required, a possible workaround is to move the video and canvas below the page fold, then disable scrolling with javascript (ie. scroll to the top whenever the user scrolls).</p>
  
  <p>But I would rather a proper fix than a workaround, if possible!</p>