Add createNewCompatibleDevice. Allow devices to have a NULL factory and saveLayer will fall back on createNewCompatibleDevice.

Review URL: http://codereview.appspot.com/4633044/



git-svn-id: http://skia.googlecode.com/svn/trunk@1625 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp
index 5b2e964..0b6f086 100644
--- a/src/core/SkCanvas.cpp
+++ b/src/core/SkCanvas.cpp
@@ -434,10 +434,9 @@
         : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) {
     inc_canvas();
 
-    fDeviceFactory = device->getDeviceFactory();
-    SkASSERT(fDeviceFactory);
-    fDeviceFactory->ref();
-              
+    fDeviceFactory = device->getDeviceFactory();

+    SkSafeRef(fDeviceFactory);
+
     this->init(device);
 }
 
@@ -446,9 +445,8 @@
     inc_canvas();
 
     SkDevice* device = SkNEW_ARGS(SkDevice, (bitmap));
-    fDeviceFactory = device->getDeviceFactory();
-    SkASSERT(fDeviceFactory);
-    fDeviceFactory->ref();
+    fDeviceFactory = device->getDeviceFactory();

+    SkSafeRef(fDeviceFactory);
 
     this->init(device)->unref();
 }
@@ -736,8 +734,9 @@
     bool isOpaque;
     SkBitmap::Config config = resolve_config(this, ir, flags, &isOpaque);
 
-    SkDevice* device = this->createDevice(config, ir.width(), ir.height(),
-                                          isOpaque);
+    SkDevice* device = this->createLayerDevice(config, ir.width(), ir.height(),
+                                               isOpaque);
+
     device->setOrigin(ir.fLeft, ir.fTop);
     DeviceCM* layer = SkNEW_ARGS(DeviceCM, (device, ir.fLeft, ir.fTop, paint));
     device->unref();
@@ -1176,11 +1175,32 @@
     }
 }
 
-SkDevice* SkCanvas::createDevice(SkBitmap::Config config, int width, int height,
-                                 bool isOpaque) {
-    return fDeviceFactory->newDevice(this, config, width, height, isOpaque, true);
+SkDevice* SkCanvas::createLayerDevice(SkBitmap::Config config,
+                                      int width, int height,
+                                      bool isOpaque) {
+    if (fDeviceFactory) {
+        return fDeviceFactory->newDevice(this, config, width, height,
+                                         isOpaque, true);
+    } else {
+        return this->getDevice()->createCompatibleDeviceForSaveLayer(
+                                config, width, height,
+                                isOpaque);
+    }
 }
 
+SkDevice* SkCanvas::createCompatibleDevice(SkBitmap::Config config, 
+                                           int width, int height,
+                                           bool isOpaque) {
+    SkDevice* device = this->getDevice();
+    if (device) {
+        return device->createCompatibleDevice(config, width, height,
+                                              isOpaque);
+    } else {
+        return NULL;
+    }
+}
+
+
 //////////////////////////////////////////////////////////////////////////////
 //  These are the virtual drawing methods
 //////////////////////////////////////////////////////////////////////////////
diff --git a/src/core/SkDevice.cpp b/src/core/SkDevice.cpp
index 0c01335..ae283b0 100644
--- a/src/core/SkDevice.cpp
+++ b/src/core/SkDevice.cpp
@@ -57,7 +57,7 @@
 }
 
 SkDeviceFactory* SkDevice::onNewDeviceFactory() {
-    return SkNEW(SkRasterDeviceFactory);
+    return NULL;
 }
 
 SkDeviceFactory* SkDevice::getDeviceFactory() {
@@ -67,6 +67,27 @@
     return fCachedDeviceFactory;
 }
 
+SkDevice* SkDevice::createCompatibleDevice(SkBitmap::Config config, 
+                                           int width, int height,
+                                           bool isOpaque) {
+    return this->onCreateCompatibleDevice(config, width, height,
+                                          isOpaque, kGeneral_Usage);
+}
+
+SkDevice* SkDevice::createCompatibleDeviceForSaveLayer(SkBitmap::Config config,
+                                                       int width, int height,
+                                                       bool isOpaque) {
+    return this->onCreateCompatibleDevice(config, width, height,
+                                          isOpaque, kSaveLayer_Usage);
+}
+
+SkDevice* SkDevice::onCreateCompatibleDevice(SkBitmap::Config config, 
+                                             int width, int height, 
+                                             bool isOpaque,
+                                             Usage usage) {
+    return SkNEW_ARGS(SkDevice,(config, width, height, isOpaque));
+}
+
 SkMetaData& SkDevice::getMetaData() {
     // metadata users are rare, so we lazily allocate it. If that changes we
     // can decide to just make it a field in the device (rather than a ptr)
diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp
index 189b692..cda10d2 100644
--- a/src/gpu/SkGpuDevice.cpp
+++ b/src/gpu/SkGpuDevice.cpp
@@ -76,7 +76,7 @@
         fTex = NULL;
     } else {
         // look it up in our cache
-        fTex = device->lockCachedTexture(bitmap, sampler, &texture, false);
+        fTex = device->lockCachedTexture(bitmap, sampler, &texture);
     }
     return texture;
 }
@@ -166,7 +166,7 @@
 }
 
 SkGpuDevice::SkGpuDevice(GrContext* context, SkBitmap::Config config, int width,
-                         int height, bool isForSaveLayer)
+                         int height, Usage usage)
 : SkDevice(config, width, height, false /*isOpaque*/) {
     fNeedPrepareRenderTarget = false;
     fDrawProcs = NULL;
@@ -186,9 +186,11 @@
     bm.setConfig(config, width, height);
 
 #if CACHE_LAYER_TEXTURES
-
+    TexType type = (kSaveLayer_Usage == usage) ? 
+                            kSaveLayerDeviceRenderTarget_TexType :
+                            kDeviceRenderTarget_TexType;
     fCache = this->lockCachedTexture(bm, GrSamplerState::ClampNoFilter(),
-                                     &fTexture, true, isForSaveLayer);
+                                     &fTexture, type);
     if (fCache) {
         SkASSERT(NULL != fTexture);
         SkASSERT(NULL != fTexture->asRenderTarget());
@@ -1394,13 +1396,12 @@
 SkGpuDevice::TexCache* SkGpuDevice::lockCachedTexture(const SkBitmap& bitmap,
                                                       const GrSamplerState& sampler,
                                                       GrTexture** texture,
-                                                      bool forDeviceRenderTarget,
-                                                      bool isSaveLayer) {
+                                                      TexType type) {
     GrTexture* newTexture = NULL;
     GrTextureEntry* entry = NULL;
     GrContext* ctx = this->context();
 
-    if (forDeviceRenderTarget) {
+    if (kBitmap_TexType != type) {
         const GrTextureDesc desc = {
             kRenderTarget_GrTextureFlagBit,
             kNone_GrAALevel,
@@ -1408,12 +1409,13 @@
             bitmap.height(),
             SkGr::Bitmap2PixelConfig(bitmap)
         };
-        if (isSaveLayer) {
+        if (kSaveLayerDeviceRenderTarget_TexType == type) {
             // we know layers will only be drawn through drawDevice.
             // drawDevice has been made to work with content embedded in a
             // larger texture so its okay to use the approximate version.
             entry = ctx->findApproximateKeylessTexture(desc);
         } else {
+            SkASSERT(kDeviceRenderTarget_TexType == type);
             entry = ctx->lockKeylessTexture(desc);
         }
     } else {
@@ -1446,6 +1448,15 @@
     this->context()->unlockTexture((GrTextureEntry*)cache);
 }
 
+SkDevice* SkGpuDevice::onCreateCompatibleDevice(SkBitmap::Config config, 
+                                                int width, int height, 
+                                                bool isOpaque,
+                                                Usage usage) {
+    return SkNEW_ARGS(SkGpuDevice,(this->context(), config, 
+                                   width, height, usage));
+}
+
+
 ///////////////////////////////////////////////////////////////////////////////
 
 SkGpuDeviceFactory::SkGpuDeviceFactory(GrContext* context,
@@ -1499,3 +1510,4 @@
         return SkNEW_ARGS(SkGpuDevice, (fContext, fRootRenderTarget));
     }
 }
+
diff --git a/src/pdf/SkPDFDevice.cpp b/src/pdf/SkPDFDevice.cpp
index d17f864..67bc64a 100644
--- a/src/pdf/SkPDFDevice.cpp
+++ b/src/pdf/SkPDFDevice.cpp
@@ -423,6 +423,17 @@
     }
 }
 
+SkDevice* SkPDFDevice::onCreateCompatibleDevice(SkBitmap::Config config, 
+                                                int width, int height, 
+                                                bool isOpaque,
+                                                Usage usage) {
+    SkMatrix initialTransform;
+    initialTransform.reset();
+    SkISize size = SkISize::Make(width, height);
+    return SkNEW_ARGS(SkPDFDevice, (size, size, initialTransform));
+}
+
+
 struct ContentEntry {
     GraphicStateEntry fState;
     SkDynamicMemoryWStream fContent;
diff --git a/src/utils/SkProxyCanvas.cpp b/src/utils/SkProxyCanvas.cpp
index a7b7f97..33f77e4 100644
--- a/src/utils/SkProxyCanvas.cpp
+++ b/src/utils/SkProxyCanvas.cpp
@@ -151,8 +151,3 @@
     return fProxy->setDrawFilter(filter);
 }
 
-SkDevice* SkProxyCanvas::createDevice(SkBitmap::Config config, int width, int height,
-                                      bool isOpaque) {
-    return fProxy->createDevice(config, width, height, isOpaque);
-}
-