make SkDevice constructors explicit between offscreen and on/direct

http://codereview.appspot.com/4632044/



git-svn-id: http://skia.googlecode.com/svn/trunk@1620 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/bench/benchmain.cpp b/bench/benchmain.cpp
index 7fce807..29963a8 100644
--- a/bench/benchmain.cpp
+++ b/bench/benchmain.cpp
@@ -171,10 +171,10 @@
         case kRaster_Backend:
             bitmap.allocPixels();
             erase(bitmap);
-            device = new SkDevice(NULL, bitmap, true);
+            device = new SkDevice(bitmap);
             break;
         case kGPU_Backend:
-            device = new SkGpuDevice(context, bitmap, SkGpuDevice::Current3DApiRenderTarget());
+            device = new SkGpuDevice(context, SkGpuDevice::Current3DApiRenderTarget());
 //            device->clear(0xFFFFFFFF);
             break;
         case kPDF_Backend:
diff --git a/gm/gmmain.cpp b/gm/gmmain.cpp
index f015c00..a90e0a8 100644
--- a/gm/gmmain.cpp
+++ b/gm/gmmain.cpp
@@ -216,15 +216,16 @@
         if (NULL == context) {
             return false;
         }
-        SkGpuCanvas gc(context,
-                       SkGpuDevice::Current3DApiRenderTarget());
-        gc.setDevice(gc.createDevice(bitmap.config(),
-                                     bitmap.width(),
-                                     bitmap.height(),
-                                     bitmap.isOpaque(),
-                                     false))->unref();
+        
+        // not a real object, so don't unref it
+        GrRenderTarget* rt = SkGpuDevice::Current3DApiRenderTarget();
+        SkGpuCanvas gc(context, rt);
+        gc.setDevice(new SkGpuDevice(context, rt))->unref();
+
         gm->draw(&gc);
-        gc.readPixels(&bitmap); // overwrite our previous allocation
+        // the device is as large as the current rendertarget, so we explicitly
+        // only readback the amount we expect (in size)
+        gc.readPixels(SkIRect::MakeSize(size), &bitmap); // overwrite our previous allocation
     }
     return true;
 }
diff --git a/include/core/SkCanvas.h b/include/core/SkCanvas.h
index 273153f..d5032a7 100644
--- a/include/core/SkCanvas.h
+++ b/include/core/SkCanvas.h
@@ -101,13 +101,13 @@
         is raster, the pixels will be allocated automatically.
      */
     virtual SkDevice* createDevice(SkBitmap::Config, int width, int height,
-                                   bool isOpaque, bool forLayer = false);
+                                   bool isOpaque);
 
     /**
      *  Create a new raster device and make it current. This also returns
      *  the new device.
      */
-    SkDevice* setBitmapDevice(const SkBitmap& bitmap, bool forLayer = false);
+    SkDevice* setBitmapDevice(const SkBitmap& bitmap);
 
     /**
      *  Return the current device factory, or NULL. The reference count of
diff --git a/include/core/SkDevice.h b/include/core/SkDevice.h
index d9a4fde..ff9c4d1 100644
--- a/include/core/SkDevice.h
+++ b/include/core/SkDevice.h
@@ -52,18 +52,30 @@
 
 class SK_API SkDevice : public SkRefCnt {
 public:
-    SkDevice(SkCanvas*);
-    /** Construct a new device, extracting the width/height/config/isOpaque values from
-        the bitmap. If transferPixelOwnership is true, and the bitmap claims to own its
-        own pixels (getOwnsPixels() == true), then transfer this responsibility to the
-        device, and call setOwnsPixels(false) on the bitmap.
+//    SkDevice();
 
-        Subclasses may override the destructor, which is virtual, even though this class
-        doesn't have one. SkRefCnt does.
-
-        @param bitmap   A copy of this bitmap is made and stored in the device
+    /**
+     *  Construct a new device with the specified bitmap as its backend. It is
+     *  valid for the bitmap to have no pixels associated with it. In that case,
+     *  any drawing to this device will have no effect.
     */
-    SkDevice(SkCanvas*, const SkBitmap& bitmap, bool forOffscreen);
+    SkDevice(const SkBitmap& bitmap);
+
+    /**
+     *  Create a new raster device and have the pixels be automatically
+     *  allocated. The rowBytes of the device will be computed automatically
+     *  based on the config and the width.
+     *
+     *  @param config   The desired config for the pixels. If the request cannot
+     *                  be met, the closest matching support config will be used.
+     *  @param width    width (in pixels) of the device
+     *  @param height   height (in pixels) of the device
+     *  @param isOpaque Set to true if it is known that all of the pixels will
+     *                  be drawn to opaquely. Used as an accelerator when drawing
+     *                  these pixels to another device.
+     */
+    SkDevice(SkBitmap::Config config, int width, int height, bool isOpaque = false);
+
     virtual ~SkDevice();
 
     /**
@@ -276,7 +288,6 @@
     // just called by SkCanvas when built as a layer
     void setOrigin(int x, int y) { fOrigin.set(x, y); }
 
-    SkCanvas*   fCanvas;
     SkBitmap    fBitmap;
     SkIPoint    fOrigin;
     SkMetaData* fMetaData;
diff --git a/include/gpu/SkGpuDevice.h b/include/gpu/SkGpuDevice.h
index 96afa08..4d0efeb 100644
--- a/include/gpu/SkGpuDevice.h
+++ b/include/gpu/SkGpuDevice.h
@@ -19,6 +19,7 @@
 #define SkGpuDevice_DEFINED
 
 #include "SkGr.h"
+#include "SkBitmap.h"
 #include "SkDevice.h"
 #include "SkRegion.h"
 
@@ -33,15 +34,19 @@
 class SK_API SkGpuDevice : public SkDevice {
 public:
     /**
-     * The SkGpuDevice will render to the GrRenderTarget, or if the paremeter is
-     * null it will create its own render target and manage that target's
-     * lifetime. Setting isSaveLayer to true is for internal use and may cause 
-     * problems when using the device's bitmap as a src if used externally.
+     *  New device that will create an offscreen renderTarget based on the
+     *  config, width, height.
+     *
+     *  isForSaveLayer is a special flag that should only be set by SkCanvas
+     *  internally.
      */
-    SkGpuDevice(GrContext*,
-                const SkBitmap& bitmap,
-                GrRenderTarget* renderTargetOrNull,
-                bool isSaveLayer = false);
+    SkGpuDevice(GrContext*, SkBitmap::Config, int width, int height,
+                bool isForSaveLayer = false);
+
+    /**
+     *  New device that will render to the specified renderTarget.
+     */
+    SkGpuDevice(GrContext*, GrRenderTarget*);
 
     /**
      * Magic value that can be passed to constructor. Causes
diff --git a/include/utils/SkProxyCanvas.h b/include/utils/SkProxyCanvas.h
index 6e55aa6..5d03c07 100644
--- a/include/utils/SkProxyCanvas.h
+++ b/include/utils/SkProxyCanvas.h
@@ -76,7 +76,7 @@
     virtual SkDrawFilter* setDrawFilter(SkDrawFilter* filter);
 
     virtual SkDevice* createDevice(SkBitmap::Config, int width, int height,
-                                   bool isOpaque, bool isForLayer);
+                                   bool isOpaque);
 
 private:
     SkCanvas*   fProxy;
diff --git a/samplecode/SampleApp.cpp b/samplecode/SampleApp.cpp
index 455559c..f0c4e59 100644
--- a/samplecode/SampleApp.cpp
+++ b/samplecode/SampleApp.cpp
@@ -3,6 +3,7 @@
 #include "SkCanvas.h"
 #include "SkDevice.h"
 #include "SkGpuCanvas.h"
+#include "SkGpuDevice.h"
 #include "SkGraphics.h"
 #include "SkImageEncoder.h"
 #include "SkPaint.h"
@@ -699,9 +700,7 @@
                 fGpuCanvas = new SkGpuCanvas(fGrContext, renderTarget);
                 renderTarget->unref();
 
-                device = fGpuCanvas->createDevice(SkBitmap::kARGB_8888_Config,
-                                                  bitmap.width(), bitmap.height(),
-                                                  false, false);
+                device = new SkGpuDevice(fGrContext, renderTarget);
                 fGpuCanvas->setDevice(device)->unref();
 
                 fGpuCanvas->concat(canvas->getTotalMatrix());
diff --git a/samplecode/SampleTextureDomain.cpp b/samplecode/SampleTextureDomain.cpp
index be000f9..37f584e 100755
--- a/samplecode/SampleTextureDomain.cpp
+++ b/samplecode/SampleTextureDomain.cpp
@@ -55,7 +55,7 @@
         // when copying from one GPU device to another.
         SkRefPtr<SkDevice> primaryDevice(canvas->getDevice());
         SkRefPtr<SkDevice> secondDevice(canvas->createDevice(
-                SkBitmap::kARGB_8888_Config, 5, 5, true, true));
+                SkBitmap::kARGB_8888_Config, 5, 5, true));
         secondDevice->unref();
         SkCanvas secondCanvas(secondDevice.get());
 
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp
index 7d29f74..5b2e964 100644
--- a/src/core/SkCanvas.cpp
+++ b/src/core/SkCanvas.cpp
@@ -445,7 +445,7 @@
         : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) {
     inc_canvas();
 
-    SkDevice* device = SkNEW_ARGS(SkDevice, (this, bitmap, false));
+    SkDevice* device = SkNEW_ARGS(SkDevice, (bitmap));
     fDeviceFactory = device->getDeviceFactory();
     SkASSERT(fDeviceFactory);
     fDeviceFactory->ref();
@@ -554,8 +554,8 @@
     return device;
 }
 
-SkDevice* SkCanvas::setBitmapDevice(const SkBitmap& bitmap, bool forLayer) {
-    SkDevice* device = this->setDevice(SkNEW_ARGS(SkDevice, (this, bitmap, forLayer)));
+SkDevice* SkCanvas::setBitmapDevice(const SkBitmap& bitmap) {
+    SkDevice* device = this->setDevice(SkNEW_ARGS(SkDevice, (bitmap)));
     device->unref();
     return device;
 }
@@ -737,7 +737,7 @@
     SkBitmap::Config config = resolve_config(this, ir, flags, &isOpaque);
 
     SkDevice* device = this->createDevice(config, ir.width(), ir.height(),
-                                          isOpaque, true);
+                                          isOpaque);
     device->setOrigin(ir.fLeft, ir.fTop);
     DeviceCM* layer = SkNEW_ARGS(DeviceCM, (device, ir.fLeft, ir.fTop, paint));
     device->unref();
@@ -1177,8 +1177,8 @@
 }
 
 SkDevice* SkCanvas::createDevice(SkBitmap::Config config, int width, int height,
-                                 bool isOpaque, bool forLayer) {
-    return fDeviceFactory->newDevice(this, config, width, height, isOpaque, forLayer);
+                                 bool isOpaque) {
+    return fDeviceFactory->newDevice(this, config, width, height, isOpaque, true);
 }
 
 //////////////////////////////////////////////////////////////////////////////
diff --git a/src/core/SkDevice.cpp b/src/core/SkDevice.cpp
index aee5a5e..0c01335 100644
--- a/src/core/SkDevice.cpp
+++ b/src/core/SkDevice.cpp
@@ -25,26 +25,32 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-SkDevice::SkDevice(SkCanvas* canvas) : fCanvas(canvas), fMetaData(NULL) {
+#if 0
+SkDevice::SkDevice() : fMetaData(NULL) {
     fOrigin.setZero();
     fCachedDeviceFactory = NULL;
 }
+#endif
 
-SkDevice::SkDevice(SkCanvas* canvas, const SkBitmap& bitmap, bool isForLayer)
-        : fCanvas(canvas), fBitmap(bitmap), fMetaData(NULL) {
+SkDevice::SkDevice(const SkBitmap& bitmap) : fBitmap(bitmap) {
     fOrigin.setZero();
-    // auto-allocate if we're for offscreen drawing
-    if (isForLayer) {
-        if (NULL == fBitmap.getPixels() && NULL == fBitmap.pixelRef()) {
-            fBitmap.allocPixels();
-            if (!fBitmap.isOpaque()) {
-                fBitmap.eraseColor(0);
-            }
-        }
-    }
+    fMetaData = NULL;
     fCachedDeviceFactory = NULL;
 }
 
+SkDevice::SkDevice(SkBitmap::Config config, int width, int height, bool isOpaque) {
+    fOrigin.setZero();
+    fMetaData = NULL;
+    fCachedDeviceFactory = NULL;
+
+    fBitmap.setConfig(config, width, height);
+    fBitmap.allocPixels();
+    fBitmap.setIsOpaque(isOpaque);
+    if (!isOpaque) {
+        fBitmap.eraseColor(0);
+    }
+}
+
 SkDevice::~SkDevice() {
     delete fMetaData;
     SkSafeUnref(fCachedDeviceFactory);
@@ -253,13 +259,17 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-SkDevice* SkRasterDeviceFactory::newDevice(SkCanvas* canvas,
+SkDevice* SkRasterDeviceFactory::newDevice(SkCanvas*,
                                            SkBitmap::Config config, int width,
                                            int height, bool isOpaque,
                                            bool isForLayer) {
-    SkBitmap bitmap;
-    bitmap.setConfig(config, width, height);
-    bitmap.setIsOpaque(isOpaque);
-
-    return SkNEW_ARGS(SkDevice, (canvas, bitmap, isForLayer));
+    if (isForLayer) {
+        return SkNEW_ARGS(SkDevice, (config, width, height, isOpaque));
+    } else {
+        // should we ever get here?
+        SkBitmap bitmap;
+        bitmap.setConfig(config, width, height);
+        bitmap.setIsOpaque(isOpaque);
+        return SkNEW_ARGS(SkDevice, (bitmap));
+    }
 }
diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp
index 114573a..189b692 100644
--- a/src/gpu/SkGpuDevice.cpp
+++ b/src/gpu/SkGpuDevice.cpp
@@ -104,12 +104,70 @@
     return (GrRenderTarget*) -1;
 }
 
-SkGpuDevice::SkGpuDevice(GrContext* context,
-                         const SkBitmap& bitmap,
-                         GrRenderTarget* renderTargetOrNull,
-                         bool isSaveLayer)
-        : SkDevice(NULL, bitmap, (NULL == renderTargetOrNull)) {
+static SkBitmap::Config grConfig2skConfig(GrPixelConfig config, bool* isOpaque) {
+    switch (config) {
+        case kAlpha_8_GrPixelConfig:
+            *isOpaque = false;
+            return SkBitmap::kA8_Config;
+        case kRGB_565_GrPixelConfig:
+            *isOpaque = true;
+            return SkBitmap::kRGB_565_Config;
+        case kRGBA_4444_GrPixelConfig:
+            *isOpaque = false;
+            return SkBitmap::kARGB_4444_Config;
+        case kRGBA_8888_GrPixelConfig:
+        case kRGBX_8888_GrPixelConfig:
+            *isOpaque = (kRGBX_8888_GrPixelConfig == config);
+            return SkBitmap::kARGB_8888_Config;
+        default:
+            *isOpaque = false;
+            return SkBitmap::kNo_Config;
+    }
+}
 
+static SkBitmap make_bitmap(GrContext* context, GrRenderTarget* renderTarget) {
+    if (SkGpuDevice::Current3DApiRenderTarget() == renderTarget) {
+        renderTarget = context->createRenderTargetFrom3DApiState();
+    }
+    GrTexture* texture = renderTarget->asTexture();
+    GrPixelConfig config = texture ? texture->config() : kRGBA_8888_GrPixelConfig;
+
+    bool isOpaque;
+    SkBitmap bitmap;
+    bitmap.setConfig(grConfig2skConfig(config, &isOpaque),
+                     renderTarget->width(), renderTarget->height());
+    bitmap.setIsOpaque(isOpaque);
+    return bitmap;
+}
+
+SkGpuDevice::SkGpuDevice(GrContext* context, GrRenderTarget* renderTarget)
+: SkDevice(make_bitmap(context, renderTarget)) {
+    
+    fNeedPrepareRenderTarget = false;
+    fDrawProcs = NULL;
+    
+    fContext = context;
+    fContext->ref();
+    
+    fCache = NULL;
+    fTexture = NULL;
+    fRenderTarget = NULL;
+    fNeedClear = false;
+    
+    if (Current3DApiRenderTarget() == renderTarget) {
+        fRenderTarget = fContext->createRenderTargetFrom3DApiState();
+    } else {
+        fRenderTarget = renderTarget;
+        fRenderTarget->ref();
+    }
+
+    SkGrRenderTargetPixelRef* pr = new SkGrRenderTargetPixelRef(fRenderTarget);
+    this->setPixelRef(pr, 0)->unref();
+}
+
+SkGpuDevice::SkGpuDevice(GrContext* context, SkBitmap::Config config, int width,
+                         int height, bool isForSaveLayer)
+: SkDevice(config, width, height, false /*isOpaque*/) {
     fNeedPrepareRenderTarget = false;
     fDrawProcs = NULL;
 
@@ -121,58 +179,46 @@
     fRenderTarget = NULL;
     fNeedClear = false;
 
-    if (NULL == renderTargetOrNull) {
-        SkBitmap::Config c = bitmap.config();
-        if (c != SkBitmap::kRGB_565_Config) {
-            c = SkBitmap::kARGB_8888_Config;
-        }
-        SkBitmap bm;
-        bm.setConfig(c, this->width(), this->height());
+    if (config != SkBitmap::kRGB_565_Config) {
+        config = SkBitmap::kARGB_8888_Config;
+    }
+    SkBitmap bm;
+    bm.setConfig(config, width, height);
 
 #if CACHE_LAYER_TEXTURES
 
-        fCache = this->lockCachedTexture(bm, GrSamplerState::ClampNoFilter(),
-                       &fTexture, true);
-        if (fCache) {
-            SkASSERT(NULL != fTexture);
-            SkASSERT(NULL != fTexture->asRenderTarget());
-        }
+    fCache = this->lockCachedTexture(bm, GrSamplerState::ClampNoFilter(),
+                                     &fTexture, true, isForSaveLayer);
+    if (fCache) {
+        SkASSERT(NULL != fTexture);
+        SkASSERT(NULL != fTexture->asRenderTarget());
+    }
 #else
-        const GrTextureDesc desc = {
-            kRenderTarget_GrTextureFlagBit,
-            kNone_GrAALevel,
-            this->width(),
-            this->height(),
-            SkGr::Bitmap2PixelConfig(bm)
-        };
+    const GrTextureDesc desc = {
+        kRenderTarget_GrTextureFlagBit,
+        kNone_GrAALevel,
+        width,
+        height,
+        SkGr::Bitmap2PixelConfig(bm)
+    };
 
-        fTexture = fContext->createUncachedTexture(desc, NULL, 0);
+    fTexture = fContext->createUncachedTexture(desc, NULL, 0);
 #endif
-        if (NULL != fTexture) {
-            fRenderTarget = fTexture->asRenderTarget();
+    if (NULL != fTexture) {
+        fRenderTarget = fTexture->asRenderTarget();
 
-            GrAssert(NULL != fRenderTarget);
+        GrAssert(NULL != fRenderTarget);
 
-            // we defer the actual clear until our gainFocus()
-            fNeedClear = true;
+        // we defer the actual clear until our gainFocus()
+        fNeedClear = true;
 
-            // wrap the bitmap with a pixelref to expose our texture
-            SkGrTexturePixelRef* pr = new SkGrTexturePixelRef(fTexture);
-            this->setPixelRef(pr, 0)->unref();
-        } else {
-            GrPrintf("--- failed to create gpu-offscreen [%d %d]\n",
-                     this->width(), this->height());
-            GrAssert(false);
-        }
-    } else {
-        if (Current3DApiRenderTarget() == renderTargetOrNull) {
-            fRenderTarget = fContext->createRenderTargetFrom3DApiState();
-        } else {
-            fRenderTarget = renderTargetOrNull;
-            fRenderTarget->ref();
-        }
-        SkGrRenderTargetPixelRef* pr = new SkGrRenderTargetPixelRef(fRenderTarget);
+        // wrap the bitmap with a pixelref to expose our texture
+        SkGrTexturePixelRef* pr = new SkGrTexturePixelRef(fTexture);
         this->setPixelRef(pr, 0)->unref();
+    } else {
+        GrPrintf("--- failed to create gpu-offscreen [%d %d]\n",
+                 width, height);
+        GrAssert(false);
     }
 }
 
@@ -1447,8 +1493,9 @@
 SkDevice* SkGpuDeviceFactory::newDevice(SkCanvas*, SkBitmap::Config config,
                                         int width, int height,
                                         bool isOpaque, bool isLayer) {
-    SkBitmap bm;
-    bm.setConfig(config, width, height);
-    bm.setIsOpaque(isOpaque);
-    return new SkGpuDevice(fContext, bm, isLayer ?  NULL : fRootRenderTarget);
+    if (isLayer) {
+        return SkNEW_ARGS(SkGpuDevice, (fContext, config, width, height));
+    } else {
+        return SkNEW_ARGS(SkGpuDevice, (fContext, fRootRenderTarget));
+    }
 }
diff --git a/src/pdf/SkPDFDevice.cpp b/src/pdf/SkPDFDevice.cpp
index c6ddf39..d17f864 100644
--- a/src/pdf/SkPDFDevice.cpp
+++ b/src/pdf/SkPDFDevice.cpp
@@ -512,7 +512,7 @@
 
 SkPDFDevice::SkPDFDevice(const SkISize& pageSize, const SkISize& contentSize,
                          const SkMatrix& initialTransform)
-    : SkDevice(NULL, makeContentBitmap(contentSize, &initialTransform), false),
+    : SkDevice(makeContentBitmap(contentSize, &initialTransform)),
       fPageSize(pageSize),
       fContentSize(contentSize),
       fLastContentEntry(NULL) {
@@ -533,7 +533,7 @@
 SkPDFDevice::SkPDFDevice(const SkISize& layerSize,
                          const SkClipStack& existingClipStack,
                          const SkRegion& existingClipRegion)
-    : SkDevice(NULL, makeContentBitmap(layerSize, NULL), false),
+    : SkDevice(makeContentBitmap(layerSize, NULL)),
       fPageSize(layerSize),
       fContentSize(layerSize),
       fExistingClipStack(existingClipStack),
diff --git a/src/utils/SkProxyCanvas.cpp b/src/utils/SkProxyCanvas.cpp
index 05823ea..a7b7f97 100644
--- a/src/utils/SkProxyCanvas.cpp
+++ b/src/utils/SkProxyCanvas.cpp
@@ -152,7 +152,7 @@
 }
 
 SkDevice* SkProxyCanvas::createDevice(SkBitmap::Config config, int width, int height,
-                                      bool isOpaque, bool isForLayer) {
-    return fProxy->createDevice(config, width, height, isOpaque, isForLayer);
+                                      bool isOpaque) {
+    return fProxy->createDevice(config, width, height, isOpaque);
 }
 
diff --git a/src/views/SkWindow.cpp b/src/views/SkWindow.cpp
index db4faee..dc833ec 100644
--- a/src/views/SkWindow.cpp
+++ b/src/views/SkWindow.cpp
@@ -172,11 +172,8 @@
 
         if (NULL == canvas) {
             canvas = &rasterCanvas;
-            device = new SkDevice(canvas, bm, false);
-            canvas->setDevice(device)->unref();
-        } else {
-            canvas->setBitmapDevice(bm);
         }
+        canvas->setBitmapDevice(bm);
 
 		canvas->clipRegion(fDirtyRgn);
 		if (updateArea)