onCreateDevice -> NULL now means the caller should create its own (bitmap) device
authorreed <reed@google.com>
Wed, 29 Apr 2015 15:34:00 +0000 (08:34 -0700)
committerCommit bot <commit-bot@chromium.org>
Wed, 29 Apr 2015 15:34:00 +0000 (08:34 -0700)
BUG=skia:

Review URL: https://codereview.chromium.org/1116453002

include/core/SkCanvas.h
include/core/SkDevice.h
src/core/SkCanvas.cpp
src/core/SkDeviceImageFilterProxy.h
src/gpu/SkGpuDevice.cpp
src/pdf/SkPDFDevice.cpp

index 828b92331d0adccc0b8bb1c8821c130d1382be72..dcbff3f60b6030f619358539d0f2b798dc0d6416 100644 (file)
@@ -1257,7 +1257,7 @@ private:
     MCRec*      fMCRec;
     // the first N recs that can fit here mean we won't call malloc
     enum {
-        kMCRecSize  = 128,   // most recent measurement
+        kMCRecSize  = 136,   // most recent measurement
         kMCRecCount = 8,     // common depth for save/restores
     };
     intptr_t fMCRecStorage[kMCRecSize * kMCRecCount / sizeof(intptr_t)];
@@ -1330,7 +1330,7 @@ private:
                                 const SkRect& dst, const SkPaint* paint);
     void internalDrawPaint(const SkPaint& paint);
     void internalSaveLayer(const SkRect* bounds, const SkPaint*, SaveFlags, SaveLayerStrategy);
-    void internalDrawDevice(SkBaseDevice*, int x, int y, const SkPaint*);
+    void internalDrawDevice(SkBaseDevice*, int x, int y, const SkPaint*, bool isBitmapDevice);
 
     // shared by save() and saveLayer()
     void internalSave();
index ec5771175436906f47071fdd51e1e0e97c6bd477..8a219d7053b0cd662fcb6fa03ba64b908be199f1 100644 (file)
@@ -348,6 +348,13 @@ protected:
     /**
      *  Create a new device based on CreateInfo. If the paint is not null, then it represents a
      *  preview of how the new device will be composed with its creator device (this).
+     *
+     *  The subclass may be handed this device in drawDevice(), so it must always return
+     *  a device that it knows how to draw, and that it knows how to identify if it is not of the
+     *  same subclass (since drawDevice is passed a SkBaseDevice*). If the subclass cannot fulfill
+     *  that contract (e.g. PDF cannot support some settings on the paint) it should return NULL,
+     *  and the caller may then decide to explicitly create a bitmapdevice, knowing that later
+     *  it could not call drawDevice with it (but it could call drawSprite or drawBitmap).
      */
     virtual SkBaseDevice* onCreateDevice(const CreateInfo&, const SkPaint*) {
         return NULL;
index 514a45460c23c82c35073686cfd15a522a188514..fbf6c9e83b904acc7df0b08a8b245097d768002d 100644 (file)
@@ -111,13 +111,16 @@ struct DeviceCM {
     DeviceCM*           fNext;
     SkBaseDevice*       fDevice;
     SkRasterClip        fClip;
-    const SkMatrix*     fMatrix;
     SkPaint*            fPaint; // may be null (in the future)
+    const SkMatrix*     fMatrix;
+    SkMatrix            fMatrixStorage;
+    const bool          fDeviceIsBitmapDevice;
 
     DeviceCM(SkBaseDevice* device, const SkPaint* paint, SkCanvas* canvas,
-             bool conservativeRasterClip)
+             bool conservativeRasterClip, bool deviceIsBitmapDevice)
         : fNext(NULL)
         , fClip(conservativeRasterClip)
+        , fDeviceIsBitmapDevice(deviceIsBitmapDevice)
     {
         if (NULL != device) {
             device->ref();
@@ -180,9 +183,6 @@ struct DeviceCM {
         }
 #endif
     }
-
-private:
-    SkMatrix    fMatrixStorage;
 };
 
 /*  This is the record we keep for each save/restore level in the stack.
@@ -486,7 +486,7 @@ SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) {
 
     SkASSERT(sizeof(DeviceCM) <= sizeof(fBaseLayerStorage));
     fMCRec->fLayer = (DeviceCM*)fBaseLayerStorage;
-    new (fBaseLayerStorage) DeviceCM(NULL, NULL, NULL, fConservativeRasterClip);
+    new (fBaseLayerStorage) DeviceCM(NULL, NULL, NULL, fConservativeRasterClip, false);
 
     fMCRec->fTopLayer = fMCRec->fLayer;
 
@@ -985,16 +985,27 @@ void SkCanvas::internalSaveLayer(const SkRect* bounds, const SkPaint* paint, Sav
         return;
     }
 
-    SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
-    device = device->onCreateDevice(SkBaseDevice::CreateInfo(info, usage, geo), paint);
-    if (NULL == device) {
-        SkErrorInternals::SetError( kInternalError_SkError,
-                                    "Unable to create device for layer.");
-        return;
+    bool forceSpriteOnRestore = false;
+    {
+        const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage;
+        const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo);
+        SkBaseDevice* newDev = device->onCreateDevice(createInfo, paint);
+        if (NULL == newDev) {
+            // If onCreateDevice didn't succeed, try raster (e.g. PDF couldn't handle the paint)
+            newDev = SkBitmapDevice::Create(createInfo.fInfo);
+            if (NULL == newDev) {
+                SkErrorInternals::SetError(kInternalError_SkError,
+                                           "Unable to create device for layer.");
+                return;
+            }
+            forceSpriteOnRestore = true;
+        }
+        device = newDev;
     }
 
     device->setOrigin(ir.fLeft, ir.fTop);
-    DeviceCM* layer = SkNEW_ARGS(DeviceCM, (device, paint, this, fConservativeRasterClip));
+    DeviceCM* layer = SkNEW_ARGS(DeviceCM, (device, paint, this, fConservativeRasterClip,
+                                            forceSpriteOnRestore));
     device->unref();
 
     layer->fNext = fMCRec->fTopLayer;
@@ -1043,7 +1054,7 @@ void SkCanvas::internalRestore() {
         if (layer->fNext) {
             const SkIPoint& origin = layer->fDevice->getOrigin();
             this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(),
-                                     layer->fPaint);
+                                     layer->fPaint, layer->fDeviceIsBitmapDevice);
             // reset this, since internalDrawDevice will have set it to true
             fDeviceCMDirty = true;
             SkDELETE(layer);
@@ -1155,7 +1166,7 @@ void SkCanvas::internalDrawBitmap(const SkBitmap& bitmap,
 }
 
 void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y,
-                                  const SkPaint* paint) {
+                                  const SkPaint* paint, bool deviceIsBitmapDevice) {
     SkPaint tmp;
     if (NULL == paint) {
         paint = &tmp;
@@ -1183,6 +1194,9 @@ void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y,
                 dstDev->drawSprite(iter, dst, pos.x() + offset.x(), pos.y() + offset.y(),
                                    tmpUnfiltered);
             }
+        } else if (deviceIsBitmapDevice) {
+            const SkBitmap& src = srcDev->accessBitmap(false);
+            dstDev->drawSprite(iter, src, pos.x(), pos.y(), *paint);
         } else {
             dstDev->drawDevice(iter, srcDev, pos.x(), pos.y(), *paint);
         }
index dcf12f7c4016d1564f92a9cd707c6ca68b3cabbe..79ff957564c48af5661dff3e3e5d0296499e2070 100644 (file)
@@ -8,6 +8,7 @@
 #ifndef SkDeviceImageFilterProxy_DEFINED
 #define SkDeviceImageFilterProxy_DEFINED
 
+#include "SkBitmapDevice.h"
 #include "SkDevice.h"
 #include "SkImageFilter.h"
 #include "SkSurfaceProps.h"
@@ -24,7 +25,11 @@ public:
                                        SkBaseDevice::kNever_TileUsage,
                                        kUnknown_SkPixelGeometry,
                                        true /*forImageFilter*/);
-        return fDevice->onCreateDevice(cinfo, NULL);
+        SkBaseDevice* dev = fDevice->onCreateDevice(cinfo, NULL);
+        if (NULL == dev) {
+            dev = SkBitmapDevice::Create(cinfo.fInfo);
+        }
+        return dev;
     }
     bool canHandleImageFilter(const SkImageFilter* filter) override {
         return fDevice->canHandleImageFilter(filter);
index d8b0ee0b6449eaa6a5456e5fb9c074ffc398883c..3434671d6add50f4532dcf25ba4fe0545edc01b7 100644 (file)
@@ -1959,7 +1959,7 @@ SkBaseDevice* SkGpuDevice::onCreateDevice(const CreateInfo& cinfo, const SkPaint
             texture->asRenderTarget(), cinfo.fInfo.width(), cinfo.fInfo.height(), &props, flags);
     } else {
         SkErrorInternals::SetError( kInternalError_SkError,
-                                    "---- failed to create compatible device texture [%d %d]\n",
+                                    "---- failed to create gpu device texture [%d %d]\n",
                                     cinfo.fInfo.width(), cinfo.fInfo.height());
         return NULL;
     }
index 88f9b810b608e5508ac0747c41b6b592377bbf1e..2dbad5f411403e800646f63d73d071957176eadc 100644 (file)
@@ -8,7 +8,6 @@
 #include "SkPDFDevice.h"
 
 #include "SkAnnotation.h"
-#include "SkBitmapDevice.h"
 #include "SkColor.h"
 #include "SkClipStack.h"
 #include "SkData.h"
@@ -579,7 +578,7 @@ static bool not_supported_for_layers(const SkPaint& layerPaint) {
 SkBaseDevice* SkPDFDevice::onCreateDevice(const CreateInfo& cinfo, const SkPaint* layerPaint) {
     if (cinfo.fForImageFilter ||
         (layerPaint && not_supported_for_layers(*layerPaint))) {
-        return SkBitmapDevice::Create(cinfo.fInfo);
+        return NULL;
     }
     SkISize size = SkISize::Make(cinfo.fInfo.width(), cinfo.fInfo.height());
     return SkPDFDevice::Create(size, fRasterDpi, fCanon);