add rowbytes option to allocPixels

TBR=

Author: reed@google.com

Review URL: https://codereview.chromium.org/345263005
diff --git a/bench/BitmapBench.cpp b/bench/BitmapBench.cpp
index a269e90..e9ba1dc 100644
--- a/bench/BitmapBench.cpp
+++ b/bench/BitmapBench.cpp
@@ -107,12 +107,10 @@
         SkBitmap bm;
 
         if (kIndex_8_SkColorType == fColorType) {
-            bm.setInfo(SkImageInfo::MakeN32(W, H, fAlphaType));
+            bm.allocPixels(SkImageInfo::MakeN32(W, H, fAlphaType));
         } else {
-            bm.setInfo(SkImageInfo::Make(W, H, fColorType, fAlphaType));
+            bm.allocPixels(SkImageInfo::Make(W, H, fColorType, fAlphaType));
         }
-
-        bm.allocPixels();
         bm.eraseColor(kOpaque_SkAlphaType == fAlphaType ? SK_ColorBLACK : 0);
 
         onDrawIntoBitmap(bm);
diff --git a/include/core/SkBitmap.h b/include/core/SkBitmap.h
index d3a20c0..6728308 100644
--- a/include/core/SkBitmap.h
+++ b/include/core/SkBitmap.h
@@ -290,7 +290,7 @@
 #endif
 
     /**
-     *  Allocate a pixelref to match the specified image info. If the Factory
+     *  Allocate the bitmap's pixels to match the requested image info. If the Factory
      *  is non-null, call it to allcoate the pixelref. If the ImageInfo requires
      *  a colortable, then ColorTable must be non-null, and will be ref'd.
      *  On failure, the bitmap will be set to empty and return false.
@@ -298,13 +298,23 @@
     bool allocPixels(const SkImageInfo&, SkPixelRefFactory*, SkColorTable*);
 
     /**
+     *  Allocate the bitmap's pixels to match the requested image info and
+     *  rowBytes. If the request cannot be met (e.g. the info is invalid or
+     *  the requested rowBytes are not compatible with the info
+     *  (e.g. rowBytes < info.minRowBytes() or rowBytes is not aligned with
+     *  the pixel size specified by info.colorType()) then false is returned
+     *  and the bitmap is set to empty.
+     */
+    bool allocPixels(const SkImageInfo& info, size_t rowBytes);
+
+    /**
      *  Allocate a pixelref to match the specified image info, using the default
      *  allocator.
      *  On success, the bitmap's pixels will be "locked", and return true.
      *  On failure, the bitmap will be set to empty and return false.
      */
     bool allocPixels(const SkImageInfo& info) {
-        return this->allocPixels(info, NULL, NULL);
+        return this->allocPixels(info, info.minRowBytes());
     }
 
     bool allocN32Pixels(int width, int height, bool isOpaque = false) {
diff --git a/src/animator/SkDrawBitmap.cpp b/src/animator/SkDrawBitmap.cpp
index f481ee7..5349774 100644
--- a/src/animator/SkDrawBitmap.cpp
+++ b/src/animator/SkDrawBitmap.cpp
@@ -89,8 +89,8 @@
     SkASSERT(height != -1);
     SkASSERT(rowBytes >= 0);
     SkColorType colorType = SkColorType(format);
-    fBitmap.setInfo(SkImageInfo::Make(width, height, colorType, kPremul_SkAlphaType), rowBytes);
-    fBitmap.allocPixels();
+    fBitmap.allocPixels(SkImageInfo::Make(width, height, colorType, kPremul_SkAlphaType),
+                        rowBytes);
     if (fColorSet)
         fBitmap.eraseColor(fColor);
 }
diff --git a/src/core/SkBitmap.cpp b/src/core/SkBitmap.cpp
index 789bf11..38df07c 100644
--- a/src/core/SkBitmap.cpp
+++ b/src/core/SkBitmap.cpp
@@ -366,6 +366,36 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
+bool SkBitmap::allocPixels(const SkImageInfo& requestedInfo, size_t rowBytes) {
+    if (kIndex_8_SkColorType == requestedInfo.colorType()) {
+        return reset_return_false(this);
+    }
+    if (!this->setInfo(requestedInfo)) {
+        return reset_return_false(this);
+    }
+    
+    // setInfo may have corrected info (e.g. 565 is always opaque).
+    const SkImageInfo& correctedInfo = this->info();
+    if (!correctedInfo.validRowBytes(rowBytes)) {
+        return reset_return_false(this);
+    }
+    
+    SkMallocPixelRef::PRFactory defaultFactory;
+    
+    SkPixelRef* pr = defaultFactory.create(correctedInfo, NULL);
+    if (NULL == pr) {
+        return reset_return_false(this);
+    }
+    this->setPixelRef(pr)->unref();
+    
+    // TODO: lockPixels could/should return bool or void*/NULL
+    this->lockPixels();
+    if (NULL == this->getPixels()) {
+        return reset_return_false(this);
+    }
+    return true;
+}
+
 bool SkBitmap::allocPixels(const SkImageInfo& requestedInfo, SkPixelRefFactory* factory,
                            SkColorTable* ctable) {
     if (kIndex_8_SkColorType == requestedInfo.fColorType && NULL == ctable) {
diff --git a/src/lazy/SkCachingPixelRef.cpp b/src/lazy/SkCachingPixelRef.cpp
index 76510f6..97503e5 100644
--- a/src/lazy/SkCachingPixelRef.cpp
+++ b/src/lazy/SkCachingPixelRef.cpp
@@ -54,7 +54,7 @@
                                                      &bitmap);
     if (NULL == fScaledCacheId) {
         // Cache has been purged, must re-decode.
-        if ((!bitmap.setInfo(info, fRowBytes)) || !bitmap.allocPixels()) {
+        if (!bitmap.allocPixels(info, fRowBytes)) {
             fErrorInDecoding = true;
             return false;
         }