rename filterTextFlags to disableLCD

Under the hood, add SkPixelGeometry to the CreateInfo for new devices, allowing them to see their geometry (SkDeviceProperties) up front, rather than having it changed later.

The only exception is for devices that are used on the root-layer, where we don't see the device until after the fact (at least as long as we allow clients to attach a device to a canvas externally).

We also filter the geometry when we're creating a layer, so we can disable LCD text automatically if the layer is not marked as opaque.

NOTRY=True
-- gammatext flake?

Review URL: https://codereview.chromium.org/719253002
diff --git a/src/core/SkBitmapDevice.cpp b/src/core/SkBitmapDevice.cpp
index 0c28fea..5204fdb 100644
--- a/src/core/SkBitmapDevice.cpp
+++ b/src/core/SkBitmapDevice.cpp
@@ -7,6 +7,7 @@
 
 #include "SkBitmapDevice.h"
 #include "SkConfig8888.h"
+#include "SkDeviceProperties.h"
 #include "SkDraw.h"
 #include "SkRasterClip.h"
 #include "SkShader.h"
@@ -61,14 +62,12 @@
     SkASSERT(valid_for_bitmap_device(bitmap.info(), NULL));
 }
 
-#if 0
 SkBitmapDevice::SkBitmapDevice(const SkBitmap& bitmap, const SkDeviceProperties& deviceProperties)
     : SkBaseDevice(deviceProperties)
     , fBitmap(bitmap)
 {
     SkASSERT(valid_for_bitmap_device(bitmap.info(), NULL));
 }
-#endif
 
 SkBitmapDevice* SkBitmapDevice::Create(const SkImageInfo& origInfo,
                                        const SkDeviceProperties* props) {
@@ -93,8 +92,8 @@
         }
     }
 
-    if (props && false) {
-//        return SkNEW_ARGS(SkBitmapDevice, (bitmap, *props));
+    if (props) {
+        return SkNEW_ARGS(SkBitmapDevice, (bitmap, *props));
     } else {
         return SkNEW_ARGS(SkBitmapDevice, (bitmap));
     }
@@ -112,7 +111,8 @@
 }
 
 SkBaseDevice* SkBitmapDevice::onCreateCompatibleDevice(const CreateInfo& cinfo) {
-    return SkBitmapDevice::Create(cinfo.fInfo);// &this->getDeviceProperties());
+    SkDeviceProperties leaky(cinfo.fPixelGeometry);
+    return SkBitmapDevice::Create(cinfo.fInfo, &leaky);
 }
 
 void SkBitmapDevice::lockPixels() {
@@ -383,23 +383,15 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-bool SkBitmapDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) {
-    if (!paint.isLCDRenderText() || !paint.isAntiAlias()) {
-        // we're cool with the paint as is
-        return false;
-    }
-
+bool SkBitmapDevice::onShouldDisableLCD(const SkPaint& paint) const {
     if (kN32_SkColorType != fBitmap.colorType() ||
         paint.getRasterizer() ||
         paint.getPathEffect() ||
         paint.isFakeBoldText() ||
         paint.getStyle() != SkPaint::kFill_Style ||
-        !SkXfermode::IsMode(paint.getXfermode(), SkXfermode::kSrcOver_Mode)) {
-        // turn off lcd, but turn on kGenA8
-        flags->fFlags = paint.getFlags() & ~SkPaint::kLCDRenderText_Flag;
-        flags->fFlags |= SkPaint::kGenA8FromLCD_Flag;
+        !SkXfermode::IsMode(paint.getXfermode(), SkXfermode::kSrcOver_Mode))
+    {
         return true;
     }
-    // we're cool with the paint as is
     return false;
 }
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp
index ead844f..82d4816 100644
--- a/src/core/SkCanvas.cpp
+++ b/src/core/SkCanvas.cpp
@@ -405,10 +405,6 @@
 
 ////////////////////////////////////////////////////////////////////////////
 
-void SkCanvas::setupDevice(SkBaseDevice* device) {
-    device->setPixelGeometry(fProps.pixelGeometry());
-}
-
 SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) {
     fConservativeRasterClip = SkToBool(flags & kConservativeRasterClip_InitFlag);
     fCachedLocalClipBounds.setEmpty();
@@ -429,7 +425,7 @@
     fSurfaceBase = NULL;
 
     if (device) {
-        this->setupDevice(device);
+        device->initForRootLayer(fProps.pixelGeometry());
         if (device->forceConservativeRasterClip()) {
             fConservativeRasterClip = true;
         }
@@ -601,6 +597,7 @@
 
     if (device) {
         device->onAttachToCanvas(this);
+        device->initForRootLayer(fProps.pixelGeometry());
     }
     if (rootDevice) {
         rootDevice->onDetachFromCanvas();
@@ -608,7 +605,6 @@
 
     SkRefCnt_SafeAssign(rec->fLayer->fDevice, device);
     rootDevice = device;
-    this->setupDevice(device);
 
     fDeviceCMDirty = true;
 
@@ -931,20 +927,22 @@
     SkImageInfo info = SkImageInfo::MakeN32(ir.width(), ir.height(),
                         isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
 
-    SkBaseDevice* device;
-    if (paint && paint->getImageFilter()) {
-        device = this->getDevice();
-        if (device) {
-            device = device->createCompatibleDeviceForImageFilter(info);
-        }
-    } else {
-        device = this->createLayerDevice(info);
+    SkBaseDevice* device = this->getTopDevice();
+    if (NULL == device) {
+        SkDebugf("Unable to find device for layer.");
+        return count;
     }
+
+    SkBaseDevice::Usage usage = SkBaseDevice::kSaveLayer_Usage;
+    if (paint && paint->getImageFilter()) {
+        usage = SkBaseDevice::kImageFilter_Usage;
+    }
+    device = device->onCreateCompatibleDevice(SkBaseDevice::CreateInfo(info, usage,
+                                                                       fProps.pixelGeometry()));
     if (NULL == device) {
         SkDebugf("Unable to create device for layer.");
         return count;
     }
-    this->setupDevice(device);
 
     device->setOrigin(ir.fLeft, ir.fTop);
     DeviceCM* layer = SkNEW_ARGS(DeviceCM,
@@ -1665,11 +1663,6 @@
     return dev ? dev->accessRenderTarget() : NULL;
 }
 
-SkBaseDevice* SkCanvas::createLayerDevice(const SkImageInfo& info) {
-    SkBaseDevice* device = this->getTopDevice();
-    return device ? device->createCompatibleDeviceForSaveLayer(info) : NULL;
-}
-
 GrContext* SkCanvas::getGrContext() {
 #if SK_SUPPORT_GPU
     SkBaseDevice* device = this->getTopDevice();
@@ -2062,10 +2055,12 @@
 class SkDeviceFilteredPaint {
 public:
     SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) {
-        SkBaseDevice::TextFlags flags;
-        if (device->filterTextFlags(paint, &flags)) {
+        if (device->shouldDisableLCD(paint)) {
+            uint32_t flags = paint.getFlags();
+            flags &= ~SkPaint::kLCDRenderText_Flag;
+            flags |= SkPaint::kGenA8FromLCD_Flag;
             SkPaint* newPaint = fLazy.set(paint);
-            newPaint->setFlags(flags.fFlags);
+            newPaint->setFlags(flags);
             fPaint = newPaint;
         } else {
             fPaint = &paint;
diff --git a/src/core/SkDevice.cpp b/src/core/SkDevice.cpp
index 20219a4..90ea705 100644
--- a/src/core/SkDevice.cpp
+++ b/src/core/SkDevice.cpp
@@ -23,23 +23,21 @@
     fMetaData = NULL;
 }
 
+SkBaseDevice::SkBaseDevice(const SkDeviceProperties& dp)
+    : fLeakyProperties(SkNEW_ARGS(SkDeviceProperties, (dp)))
+#ifdef SK_DEBUG
+    , fAttachedToCanvas(false)
+#endif
+{
+    fOrigin.setZero();
+    fMetaData = NULL;
+}
+
 SkBaseDevice::~SkBaseDevice() {
     SkDELETE(fLeakyProperties);
     SkDELETE(fMetaData);
 }
 
-SkBaseDevice* SkBaseDevice::createCompatibleDevice(const SkImageInfo& info) {
-    return this->onCreateCompatibleDevice(CreateInfo(info, kGeneral_Usage));
-}
-
-SkBaseDevice* SkBaseDevice::createCompatibleDeviceForSaveLayer(const SkImageInfo& info) {
-    return this->onCreateCompatibleDevice(CreateInfo(info, kSaveLayer_Usage));
-}
-
-SkBaseDevice* SkBaseDevice::createCompatibleDeviceForImageFilter(const SkImageInfo& info) {
-    return this->onCreateCompatibleDevice(CreateInfo(info, kImageFilter_Usage));
-}
-
 SkMetaData& SkBaseDevice::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)
@@ -61,8 +59,31 @@
     return bitmap;
 }
 
-void SkBaseDevice::setPixelGeometry(SkPixelGeometry geo) {
-    fLeakyProperties->setPixelGeometry(geo);
+SkPixelGeometry SkBaseDevice::CreateInfo::AdjustGeometry(const SkImageInfo& info,
+                                                         Usage usage,
+                                                         SkPixelGeometry geo) {
+    switch (usage) {
+        case kGeneral_Usage:
+            break;
+        case kSaveLayer_Usage:
+            if (info.alphaType() != kOpaque_SkAlphaType) {
+                geo = kUnknown_SkPixelGeometry;
+            }
+            break;
+        case kImageFilter_Usage:
+            geo = kUnknown_SkPixelGeometry;
+            break;
+    }
+    return geo;
+}
+
+void SkBaseDevice::initForRootLayer(SkPixelGeometry geo) {
+    // For now we don't expect to change the geometry for the root-layer, but we make the call
+    // anyway to document logically what is going on.
+    //
+    fLeakyProperties->setPixelGeometry(CreateInfo::AdjustGeometry(this->imageInfo(),
+                                                                  kGeneral_Usage,
+                                                                  geo));
 }
 
 SkSurface* SkBaseDevice::newSurface(const SkImageInfo&, const SkSurfaceProps&) { return NULL; }
@@ -187,3 +208,18 @@
     // The base class doesn't perform any accelerated picture rendering
     return false;
 }
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+bool SkBaseDevice::shouldDisableLCD(const SkPaint& paint) const {
+    if (!paint.isLCDRenderText() || !paint.isAntiAlias()) {
+        return false;
+    }
+
+    if (kUnknown_SkPixelGeometry == fLeakyProperties->pixelGeometry()) {
+        return true;
+    }
+
+    return this->onShouldDisableLCD(paint);
+}
+
diff --git a/src/core/SkDeviceImageFilterProxy.h b/src/core/SkDeviceImageFilterProxy.h
index 0b83b1a..d7ab646 100644
--- a/src/core/SkDeviceImageFilterProxy.h
+++ b/src/core/SkDeviceImageFilterProxy.h
@@ -15,7 +15,10 @@
     SkDeviceImageFilterProxy(SkBaseDevice* device) : fDevice(device) {}
 
     virtual SkBaseDevice* createDevice(int w, int h) SK_OVERRIDE {
-        return fDevice->createCompatibleDeviceForImageFilter(SkImageInfo::MakeN32Premul(w, h));
+        SkBaseDevice::CreateInfo cinfo(SkImageInfo::MakeN32Premul(w, h),
+                                       SkBaseDevice::kImageFilter_Usage,
+                                       kUnknown_SkPixelGeometry);
+        return fDevice->onCreateCompatibleDevice(cinfo);
     }
     virtual bool canHandleImageFilter(const SkImageFilter* filter) SK_OVERRIDE {
         return fDevice->canHandleImageFilter(filter);
diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp
index d04d2d8..34964d5 100644
--- a/src/gpu/SkGpuDevice.cpp
+++ b/src/gpu/SkGpuDevice.cpp
@@ -130,8 +130,13 @@
     return SkNEW_ARGS(SkGpuDevice, (surface, props, flags));
 }
 
-SkGpuDevice::SkGpuDevice(GrSurface* surface, const SkSurfaceProps& props, unsigned flags) {
+static SkDeviceProperties surfaceprops_to_deviceprops(const SkSurfaceProps& props) {
+    return SkDeviceProperties(props.pixelGeometry());
+}
 
+SkGpuDevice::SkGpuDevice(GrSurface* surface, const SkSurfaceProps& props, unsigned flags)
+    : INHERITED(surfaceprops_to_deviceprops(props))
+{
     fDrawProcs = NULL;
 
     fContext = SkRef(surface->getContext());
@@ -145,8 +150,6 @@
     fLegacyBitmap.setInfo(info);
     fLegacyBitmap.setPixelRef(pr)->unref();
 
-    this->setPixelGeometry(props.pixelGeometry());
-
     bool useDFT = SkToBool(flags & kDFText_Flag);
     fTextContext = fContext->createTextContext(fRenderTarget, this->getLeakyProperties(), useDFT);
 }
@@ -1721,26 +1724,18 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-bool SkGpuDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) {
-    if (!paint.isLCDRenderText()) {
-        // we're cool with the paint as is
-        return false;
-    }
-
+bool SkGpuDevice::onShouldDisableLCD(const SkPaint& paint) const {
     if (paint.getShader() ||
-        paint.getXfermode() || // unless its srcover
+        !SkXfermode::IsMode(paint.getXfermode(), SkXfermode::kSrcOver_Mode) ||
         paint.getMaskFilter() ||
         paint.getRasterizer() ||
         paint.getColorFilter() ||
         paint.getPathEffect() ||
         paint.isFakeBoldText() ||
-        paint.getStyle() != SkPaint::kFill_Style) {
-        // turn off lcd, but turn on kGenA8
-        flags->fFlags = paint.getFlags() & ~SkPaint::kLCDRenderText_Flag;
-        flags->fFlags |= SkPaint::kGenA8FromLCD_Flag;
+        paint.getStyle() != SkPaint::kFill_Style)
+    {
         return true;
     }
-    // we're cool with the paint as is
     return false;
 }
 
@@ -1776,7 +1771,7 @@
     texture.reset(fContext->createUncachedTexture(desc, NULL, 0));
 #endif
     if (texture.get()) {
-        return SkGpuDevice::Create(texture, SkSurfaceProps(SkSurfaceProps::kLegacyFontHost_InitType), flags);
+        return SkGpuDevice::Create(texture, SkSurfaceProps(0, cinfo.fPixelGeometry), flags);
     } else {
         SkDebugf("---- failed to create compatible device texture [%d %d]\n",
                  cinfo.fInfo.width(), cinfo.fInfo.height());
diff --git a/src/gpu/SkGpuDevice.h b/src/gpu/SkGpuDevice.h
index d90ecbc..ef31276 100644
--- a/src/gpu/SkGpuDevice.h
+++ b/src/gpu/SkGpuDevice.h
@@ -56,6 +56,13 @@
 
     virtual ~SkGpuDevice();
 
+    SkGpuDevice* cloneDevice(const SkSurfaceProps& props) {
+        SkBaseDevice* dev = this->onCreateCompatibleDevice(CreateInfo(this->imageInfo(),
+                                                                      kGeneral_Usage,
+                                                                      props.pixelGeometry()));
+        return static_cast<SkGpuDevice*>(dev);
+    }
+
     GrContext* context() const { return fContext; }
 
     virtual GrRenderTarget* accessRenderTarget() SK_OVERRIDE;
@@ -102,7 +109,6 @@
                               const SkPaint&) SK_OVERRIDE;
     virtual void drawDevice(const SkDraw&, SkBaseDevice*, int x, int y,
                             const SkPaint&) SK_OVERRIDE;
-    virtual bool filterTextFlags(const SkPaint&, TextFlags*) SK_OVERRIDE;
 
     virtual void flush() SK_OVERRIDE;
 
@@ -119,6 +125,7 @@
 protected:
     virtual bool onReadPixels(const SkImageInfo&, void*, size_t, int, int) SK_OVERRIDE;
     virtual bool onWritePixels(const SkImageInfo&, const void*, size_t, int, int) SK_OVERRIDE;
+    bool onShouldDisableLCD(const SkPaint&) const SK_OVERRIDE;
 
     /**  PRIVATE / EXPERIMENTAL -- do not call */
     virtual bool EXPERIMENTAL_drawPicture(SkCanvas* canvas, const SkPicture* picture,
diff --git a/src/image/SkSurface_Gpu.cpp b/src/image/SkSurface_Gpu.cpp
index 1555c9a..d777e3a 100644
--- a/src/image/SkSurface_Gpu.cpp
+++ b/src/image/SkSurface_Gpu.cpp
@@ -85,8 +85,7 @@
         // We call createCompatibleDevice because it uses the texture cache. This isn't
         // necessarily correct (http://skbug.com/2252), but never using the cache causes
         // a Chromium regression. (http://crbug.com/344020)
-        SkGpuDevice* newDevice = static_cast<SkGpuDevice*>(
-            fDevice->createCompatibleDevice(fDevice->imageInfo()));
+        SkGpuDevice* newDevice = fDevice->cloneDevice(this->props());
         SkAutoTUnref<SkGpuDevice> aurd(newDevice);
         if (kRetain_ContentChangeMode == mode) {
             fDevice->context()->copySurface(newDevice->accessRenderTarget(), rt->asTexture());
diff --git a/src/utils/SkDeferredCanvas.cpp b/src/utils/SkDeferredCanvas.cpp
index c8216e4..3c845b1 100644
--- a/src/utils/SkDeferredCanvas.cpp
+++ b/src/utils/SkDeferredCanvas.cpp
@@ -168,11 +168,6 @@
     virtual bool onReadPixels(const SkImageInfo&, void*, size_t, int x, int y) SK_OVERRIDE;
     virtual bool onWritePixels(const SkImageInfo&, const void*, size_t, int x, int y) SK_OVERRIDE;
 
-    // The following methods are no-ops on a deferred device
-    virtual bool filterTextFlags(const SkPaint& paint, TextFlags*) SK_OVERRIDE {
-        return false;
-    }
-
     // None of the following drawing methods should ever get called on the
     // deferred device
     virtual void clear(SkColor color) SK_OVERRIDE
@@ -466,6 +461,7 @@
 SkBaseDevice* SkDeferredDevice::onCreateCompatibleDevice(const CreateInfo& cinfo) {
     // Save layer usage not supported, and not required by SkDeferredCanvas.
     SkASSERT(cinfo.fUsage != kSaveLayer_Usage);
+
     // Create a compatible non-deferred device.
     // We do not create a deferred device because we know the new device
     // will not be used with a deferred canvas (there is no API for that).
diff --git a/src/utils/SkPictureUtils.cpp b/src/utils/SkPictureUtils.cpp
index 3127497..dfa772a 100644
--- a/src/utils/SkPictureUtils.cpp
+++ b/src/utils/SkPictureUtils.cpp
@@ -62,9 +62,6 @@
         return SkImageInfo::MakeUnknown(fSize.width(), fSize.height());
     }
     virtual GrRenderTarget* accessRenderTarget() SK_OVERRIDE { return NULL; }
-    virtual bool filterTextFlags(const SkPaint& paint, TextFlags*) SK_OVERRIDE {
-        return false;
-    }
     // TODO: allow this call to return failure, or move to SkBitmapDevice only.
     virtual const SkBitmap& onAccessBitmap() SK_OVERRIDE {
         return fEmptyBitmap;