Automatically scale compositions to the size of the canvas (#178)

diff --git a/LottieSample/screenshots/LottieLogo1.png b/LottieSample/screenshots/LottieLogo1.png
index 54744cb..a402f3b 100644
--- a/LottieSample/screenshots/LottieLogo1.png
+++ b/LottieSample/screenshots/LottieLogo1.png
Binary files differ
diff --git a/LottieSample/screenshots/LottieLogo2.png b/LottieSample/screenshots/LottieLogo2.png
index 3871e29..f9355c8 100644
--- a/LottieSample/screenshots/LottieLogo2.png
+++ b/LottieSample/screenshots/LottieLogo2.png
Binary files differ
diff --git a/LottieSample/screenshots/MotionCorpse-Jrcanest.png b/LottieSample/screenshots/MotionCorpse-Jrcanest.png
index 713a34a..c7eea27 100644
--- a/LottieSample/screenshots/MotionCorpse-Jrcanest.png
+++ b/LottieSample/screenshots/MotionCorpse-Jrcanest.png
Binary files differ
diff --git a/LottieSample/screenshots/Tests_Laugh4.png b/LottieSample/screenshots/Tests_Laugh4.png
index 494b478..ed208a6 100644
--- a/LottieSample/screenshots/Tests_Laugh4.png
+++ b/LottieSample/screenshots/Tests_Laugh4.png
Binary files differ
diff --git a/lottie/src/main/java/com/airbnb/lottie/BitmapCanvas.java b/lottie/src/main/java/com/airbnb/lottie/BitmapCanvas.java
new file mode 100644
index 0000000..1a2e9b1
--- /dev/null
+++ b/lottie/src/main/java/com/airbnb/lottie/BitmapCanvas.java
@@ -0,0 +1,18 @@
+package com.airbnb.lottie;
+
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+
+class BitmapCanvas extends Canvas {
+
+  private final Bitmap bitmap;
+
+  BitmapCanvas(Bitmap bitmap) {
+    super(bitmap);
+    this.bitmap = bitmap;
+  }
+
+  Bitmap getBitmap() {
+    return bitmap;
+  }
+}
diff --git a/lottie/src/main/java/com/airbnb/lottie/CanvasPool.java b/lottie/src/main/java/com/airbnb/lottie/CanvasPool.java
new file mode 100644
index 0000000..072ab26
--- /dev/null
+++ b/lottie/src/main/java/com/airbnb/lottie/CanvasPool.java
@@ -0,0 +1,81 @@
+package com.airbnb.lottie;
+
+import android.graphics.Bitmap;
+import android.graphics.Color;
+import android.support.v4.util.LongSparseArray;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import static junit.framework.Assert.assertNotNull;
+
+class CanvasPool {
+  private final LongSparseArray<List<Bitmap>> availableBitmaps = new LongSparseArray<>();
+  private final Map<BitmapCanvas, Bitmap> canvasBitmapMap = new HashMap<>();
+  private final Map<Bitmap, BitmapCanvas> bitmapCanvasMap = new HashMap<>();
+
+  BitmapCanvas acquire(int width, int height, Bitmap.Config config) {
+    int key = getKey(width, height, config);
+    List<Bitmap> bitmaps = availableBitmaps.get(key);
+    if (bitmaps == null) {
+      bitmaps = new ArrayList<>();
+      availableBitmaps.put(key, bitmaps);
+    }
+
+    BitmapCanvas canvas;
+    if (bitmaps.isEmpty()) {
+      Bitmap bitmap = Bitmap.createBitmap(width, height, config);
+      canvas = new BitmapCanvas(bitmap);
+      canvasBitmapMap.put(canvas, bitmap);
+      bitmapCanvasMap.put(bitmap, canvas);
+    } else {
+      Bitmap bitmap = bitmaps.remove(0);
+      canvas = bitmapCanvasMap.get(bitmap);
+      assertNotNull(canvas);
+    }
+    canvas.getBitmap().eraseColor(Color.TRANSPARENT);
+    return canvas;
+  }
+
+  void release(BitmapCanvas canvas) {
+    assertNotNull(canvas);
+    Bitmap bitmap = canvasBitmapMap.get(canvas);
+    assertNotNull(bitmap);
+    int key = getKey(bitmap);
+    List<Bitmap> bitmaps = availableBitmaps.get(key);
+    assertNotNull(bitmaps);
+    if (bitmaps.contains(bitmap)) {
+      throw new IllegalStateException("Canvas already released.");
+    }
+    bitmaps.add(bitmap);
+  }
+
+  void recycleBitmaps() {
+    for (int i = 0; i < availableBitmaps.size(); i++) {
+      List<Bitmap> bitmaps = availableBitmaps.valueAt(i);
+      Iterator<Bitmap> it = bitmaps.iterator();
+      while (it.hasNext()) {
+        Bitmap bitmap = it.next();
+        BitmapCanvas canvas = bitmapCanvasMap.get(bitmap);
+        bitmapCanvasMap.remove(bitmap);
+        canvasBitmapMap.remove(canvas);
+        bitmap.recycle();
+        it.remove();
+      }
+    }
+    if (!bitmapCanvasMap.isEmpty()) {
+      throw new IllegalStateException("Not all canvases have been released!");
+    }
+  }
+
+  private int getKey(Bitmap bitmap) {
+    return getKey(bitmap.getWidth(), bitmap.getHeight(), bitmap.getConfig());
+  }
+
+  private int getKey(int width, int height, Bitmap.Config config) {
+    return (width & 0xffff) << 17 | (height & 0xffff) << 1 | (config.ordinal() & 0x1);
+  }
+}
diff --git a/lottie/src/main/java/com/airbnb/lottie/LottieDrawable.java b/lottie/src/main/java/com/airbnb/lottie/LottieDrawable.java
index dffc010..b6b7132 100644
--- a/lottie/src/main/java/com/airbnb/lottie/LottieDrawable.java
+++ b/lottie/src/main/java/com/airbnb/lottie/LottieDrawable.java
@@ -196,6 +196,10 @@
     if (composition == null) {
       return;
     }
+    float xScale = canvas.getWidth() / (float) composition.getBounds().width();
+    float yScale = canvas.getHeight() / (float) composition.getBounds().height();
+    setScale(Math.min(xScale, yScale));
+
     int saveCount = canvas.save();
     canvas.clipRect(0, 0, getIntrinsicWidth(), getIntrinsicHeight());
     super.draw(canvas);
@@ -274,7 +278,6 @@
   @SuppressWarnings("WeakerAccess") public void setScale(float scale) {
     this.scale = scale;
     updateBounds();
-    invalidateSelf();
   }
 
   @SuppressWarnings("WeakerAccess") public float getScale() {