title: How does Canvas determine its clip bounds?
body: <p>I've been doing some work with Android's <code>Canvas</code>, specifically trying to determine how its <code>getClipBounds</code> results are determined. I understand <code>Canvas</code> internally keeps a transform <code>Matrix</code> which is updated as I call <code>translate</code>, <code>scale</code>, etc. but trying to replicate that <code>Matrix</code>'s results has baffled me.</p>
  
  <pre><code>@Override
  public void onDraw(Canvas canvas) {
      Rect clipBounds;
      RectF viewport;
  
      canvas.save();
      canvas.concat(translationMatrix);
      //viewportMatrix.preConcat(canvas.getMatrix());
      viewportMatrix.set(canvas.getMatrix());
  
      clipBounds = canvas.getClipBounds();
      viewport = GetViewport();
  
      Log.d("clipBounds", clipBounds.toString() + " (" + clipBounds.width() + ", " + clipBounds.height() + ")");
      Log.d("viewport", viewport.toString() + " (" + viewport.width() + ", " + viewport.height() + ")");
  
      //drawing is done here
  
      canvas.restore();
  }
  
  //viewport code modeled after http://stackoverflow.com/a/17142856/2245528
  private RectF GetViewport() {
      RectF viewport = new RectF();
  
      viewportMatrix.mapRect(viewport, originalViewport);
  
      return viewport;
  }
  
  private void Translate(float x, float y) {
      translationMatrix.postTranslate(x, y);
  
      invalidate();
  }
  
  private void Scale(float scaleFactor, PointF focusPoint) {
      if (focusPoint == null) {
          translationMatrix.postScale(scaleFactor, scaleFactor);
      }
      //keep the focus point in focus if possible
      else {
          translationMatrix.postScale(scaleFactor, scaleFactor, focusPoint.x, focusPoint.y);
      }
  
      invalidate();
  }
  
  private final Matrix translationMatrix = new Matrix();
  private final RectF originalViewport = new RectF();
  private final Matrix viewportMatrix = new Matrix();
  </code></pre>
  
  <p><code>originalViewport</code> is set to <code>0, 0, canvas.getWidth(), canvas.getHeight()</code>. <code>Translate</code> and <code>Scale</code> are called from gesture event handlers, which are working correctly.</p>
  
  <p>The part that confuses me is <code>viewportMatrix</code>. It doesn't seem to matter whether I do</p>
  
  <pre><code>viewportMatrix.set(canvas.getMatrix());
  </code></pre>
  
  <p>or</p>
  
  <pre><code>viewportMatrix.preConcat(canvas.getMatrix());
  </code></pre>
  
  <p>or even a one-time call to</p>
  
  <pre><code>viewportMatrix.set(canvas.getMatrix());
  </code></pre>
  
  <p>at the beginning followed by side-by-side <code>Translate</code>/<code>Scale</code> calls to the two matrixes. I've even tried completely ignoring the <code>Canvas</code>'s built-in <code>Matrix</code> and rewriting <code>GetViewport</code> as</p>
  
  <pre><code>//viewport code modeled after http://stackoverflow.com/a/17142856/2245528
  private RectF GetViewport() {
      RectF viewport = new RectF();
  
      translationMatrix.mapRect(viewport, originalViewport);
  
      return viewport;
  }
  </code></pre>
  
  <p>I can never seem to match <code>getClipBounds()</code>, and the discrepancies are fairly serious:</p>
  
  <p>with <code>viewportMatrix.set(canvas.getMatrix)</code>:<br /></p>
  
  <blockquote>
    <p>clipBounds: Rect(-97, -97 - 602, 452) (699, 549)<br />
    viewport: RectF(97.04178, 97.06036, 797.04175, 647.06036) (700.0, 550.0)</p>
  </blockquote>
  
  <p>with <code>viewportMatrix.preConcat(canvas.getMatrix)</code>:<br /></p>
  
  <blockquote>
    <p>clipBounds: Rect(-97, -96 - 602, 453) (699, 549)<br />
    viewport: RectF(2708.9663, 2722.2754, 3408.9663, 3272.2754) (700.0, 550.0)</p>
  </blockquote>
  
  <p>with <code>translationMatrix.mapRect</code>:<br /></p>
  
  <blockquote>
    <p>clipBounds: Rect(-96, -96 - 603, 453) (699, 549)<br />
    viewport: RectF(96.73213, 96.85794, 796.7321, 646.8579) (700.0, 550.0)</p>
  </blockquote>
  
  <p>with a one-shot call to <code>viewportMatrix.preConcat(canvas.getMatrix())</code> followed by side-by-side <code>Translate</code>/<code>Scale</code> calls:</p>
  
  <blockquote>
    <p>clipBounds: Rect(-96, -97 - 603, 452) (699, 549)<br />
    viewport: RectF(96.57738, 97.78168, 796.5774, 647.7817) (700.0, 550.0)</p>
  </blockquote>
  
  <p>with a one-shot call to <code>viewportMatrix.set(canvas.getMatrix())</code> followed by side-by-side <code>Translate</code>/<code>Scale</code> calls:</p>
  
  <blockquote>
    <p>clipBounds: Rect(-96, -96 - 603, 453) (699, 549)<br />
    viewport: RectF(96.40051, 96.88153, 796.4005, 646.88153) (700.0, 550.0)</p>
  </blockquote>
  
  <p>I can't even check <a href="http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.2.2_r1/android/graphics/Canvas.java#Canvas">the <code>Canvas</code> source</a>, as all the <code>Matrix</code> code vanishes into private native calls whose code isn't shown.</p>
  
  <p>Why are my <code>GetViewport</code> calls so grossly off, and what's going on behind-the-scenes with <code>getClipBounds</code>?</p>