Ensure overdraw, not overdraw, of reused bitmaps

Rounding errors should tilt toward a 1 pixel overdraw. These
errors could occur because the application of a scaling matrix
is opaque to caller within Canvas, and underdrawing can result
in garbage pixels in an extra line. Also added verbose logging.

Bug: 17963089
Change-Id: Id85b50ee646aecdcb7d6b26bd988577bc6fec980
diff --git a/library/src/main/java/com/bumptech/glide/load/resource/bitmap/TransformationUtils.java b/library/src/main/java/com/bumptech/glide/load/resource/bitmap/TransformationUtils.java
index 2714b6a..9cffbd8 100644
--- a/library/src/main/java/com/bumptech/glide/load/resource/bitmap/TransformationUtils.java
+++ b/library/src/main/java/com/bumptech/glide/load/resource/bitmap/TransformationUtils.java
@@ -79,20 +79,41 @@
      */
     public static Bitmap fitCenter(Bitmap toFit, BitmapPool pool, int width, int height) {
         if (toFit.getWidth() == width && toFit.getHeight() == height) {
+            if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                Log.v(TAG, "requested target size matches input, returning input");
+            }
             return toFit;
         }
         final float widthPercentage = width / (float) toFit.getWidth();
         final float heightPercentage = height / (float) toFit.getHeight();
         final float minPercentage = Math.min(widthPercentage, heightPercentage);
 
-        final int targetWidth = Math.round(minPercentage * toFit.getWidth());
-        final int targetHeight = Math.round(minPercentage * toFit.getHeight());
+        // take the floor of the target width/height, not round. If the matrix
+        // passed into drawBitmap rounds differently, we want to slightly
+        // overdraw, not underdraw, to avoid artifacts from bitmap reuse.
+        final int targetWidth = (int) (minPercentage * toFit.getWidth());
+        final int targetHeight = (int) (minPercentage * toFit.getHeight());
+
+        if (toFit.getWidth() == targetWidth && toFit.getHeight() == targetHeight) {
+            if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                Log.v(TAG, "adjusted target size matches input, returning input");
+            }
+            return toFit;
+        }
 
         Bitmap.Config config = toFit.getConfig() != null ? toFit.getConfig() : Bitmap.Config.ARGB_8888;
         Bitmap toReuse = pool.get(targetWidth, targetHeight, config);
         if (toReuse == null) {
             toReuse = Bitmap.createBitmap(targetWidth, targetHeight, config);
         }
+
+        if (Log.isLoggable(TAG, Log.VERBOSE)) {
+            Log.v(TAG, "request: " + width + "x" + height);
+            Log.v(TAG, "toFit:   " + toFit.getWidth() + "x" + toFit.getHeight());
+            Log.v(TAG, "toReuse: " + toReuse.getWidth() + "x" + toReuse.getHeight());
+            Log.v(TAG, "minPct:   " + minPercentage);
+        }
+
         Canvas canvas = new Canvas(toReuse);
         Matrix matrix = new Matrix();
         matrix.setScale(minPercentage, minPercentage);