add filterTextFlags() to SkDevice (virtual) to allow device subclasses to
filter what text features we try to use. The filtering allows for implementation
limitations to dictate when we turn off certain text features.



git-svn-id: http://skia.googlecode.com/svn/trunk@943 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/include/core/SkDevice.h b/include/core/SkDevice.h
index 55d823b..7332ba7 100644
--- a/include/core/SkDevice.h
+++ b/include/core/SkDevice.h
@@ -214,6 +214,21 @@
 
     SkRefDict& getRefDict() { return fRefDict; }
 
+    struct TextFlags {
+        uint32_t            fFlags;     // SkPaint::getFlags()
+        SkPaint::Hinting    fHinting;
+    };
+
+    /**
+     *  Device may filter the text flags for drawing text here. If it wants to
+     *  make a change to the specified values, it should write them into the
+     *  textflags parameter (output) and return true. If the paint is fine as
+     *  is, then ignore the textflags parameter and return false.
+     *
+     *  The baseclass SkDevice filters based on its depth and blitters.
+     */
+    virtual bool filterTextFlags(const SkPaint& paint, TextFlags*);
+
 protected:
     /** Update as needed the pixel value in the bitmap, so that the caller can access
         the pixels directly. Note: only the pixels field should be altered. The config/width/height/rowbytes
diff --git a/include/gpu/SkGpuDevice.h b/include/gpu/SkGpuDevice.h
index 3fed99a..8852803 100644
--- a/include/gpu/SkGpuDevice.h
+++ b/include/gpu/SkGpuDevice.h
@@ -109,6 +109,7 @@
                               const SkPaint& paint);
     virtual void drawDevice(const SkDraw&, SkDevice*, int x, int y,
                             const SkPaint&);
+    virtual bool filterTextFlags(const SkPaint& paint, TextFlags*);
 
     virtual void flush() { fContext->flush(false); }
 
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp
index 2b7d588..a31623e 100644
--- a/src/core/SkCanvas.cpp
+++ b/src/core/SkCanvas.cpp
@@ -1352,12 +1352,42 @@
     ITER_END
 }
 
+class SkDeviceFilteredPaint {
+public:
+    SkDeviceFilteredPaint(SkDevice* device, const SkPaint& paint) {
+        SkDevice::TextFlags flags;
+        if (device->filterTextFlags(paint, &flags)) {
+            SkPaint* newPaint = new (fStorage) SkPaint(paint);
+            newPaint->setFlags(flags.fFlags);
+            newPaint->setHinting(flags.fHinting);
+            fPaint = newPaint;
+        } else {
+            fPaint = &paint;
+        }
+    }
+
+    ~SkDeviceFilteredPaint() {
+        if (reinterpret_cast<SkPaint*>(fStorage) == fPaint) {
+            fPaint->~SkPaint();
+        }
+    }
+
+    const SkPaint& paint() const { return *fPaint; }
+
+private:
+    // points to either fStorage or the caller's paint
+    const SkPaint*  fPaint;
+    // we rely on the fPaint above to ensure proper alignment of fStorage
+    char            fStorage[sizeof(SkPaint)];
+};
+
 void SkCanvas::drawText(const void* text, size_t byteLength,
                         SkScalar x, SkScalar y, const SkPaint& paint) {
     ITER_BEGIN(paint, SkDrawFilter::kText_Type)
 
     while (iter.next()) {
-        iter.fDevice->drawText(iter, text, byteLength, x, y, paint);
+        SkDeviceFilteredPaint dfp(iter.fDevice, paint);
+        iter.fDevice->drawText(iter, text, byteLength, x, y, dfp.paint());
     }
 
     ITER_END
@@ -1368,8 +1398,9 @@
     ITER_BEGIN(paint, SkDrawFilter::kText_Type)
 
     while (iter.next()) {
+        SkDeviceFilteredPaint dfp(iter.fDevice, paint);
         iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 0, 2,
-                                  paint);
+                                  dfp.paint());
     }
 
     ITER_END
@@ -1381,8 +1412,9 @@
     ITER_BEGIN(paint, SkDrawFilter::kText_Type)
 
     while (iter.next()) {
+        SkDeviceFilteredPaint dfp(iter.fDevice, paint);
         iter.fDevice->drawPosText(iter, text, byteLength, xpos, constY, 1,
-                                  paint);
+                                  dfp.paint());
     }
 
     ITER_END
diff --git a/src/core/SkDevice.cpp b/src/core/SkDevice.cpp
index 619a371..8231848 100644
--- a/src/core/SkDevice.cpp
+++ b/src/core/SkDevice.cpp
@@ -178,6 +178,32 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
+bool SkDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) {
+    if (!paint.isLCDRenderText()) {
+        // we're cool with the paint as is
+        return false;
+    }
+
+    if (SkBitmap::kARGB_8888_Config != fBitmap.config() ||
+        paint.getShader() ||
+        paint.getXfermode() || // unless its srcover
+        paint.getMaskFilter() ||
+        paint.getRasterizer() ||
+        paint.getColorFilter() ||
+        paint.getPathEffect() ||
+        paint.isFakeBoldText() ||
+        paint.getStyle() != SkPaint::kFill_Style) {
+        // turn off lcd
+        flags->fFlags = paint.getFlags() & ~SkPaint::kLCDRenderText_Flag;
+        flags->fHinting = paint.getHinting();
+        return true;
+    }
+    // we're cool with the paint as is
+    return false;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
 SkDevice* SkRasterDeviceFactory::newDevice(SkCanvas* canvas,
                                            SkBitmap::Config config, int width,
                                            int height, bool isOpaque,
diff --git a/src/core/SkPaint.cpp b/src/core/SkPaint.cpp
index e3d8dd1..1e40641 100644
--- a/src/core/SkPaint.cpp
+++ b/src/core/SkPaint.cpp
@@ -1104,25 +1104,6 @@
     buffer->flatten(desc->addEntry(tag, buffer->size(), NULL));
 }
 
-/*
- *  Returns false if any condition holds where we cannot support rendering
- *  LCD16 text. Over time we may loosen these restrictions (e.g. as we write
- *  more blits that can handle it).
- *
- *  The goal is to never return false if the user has requested it, but for now
- *  we have some restrictions.
- */
-static bool canSupportLCD16(const SkPaint& paint) {
-    return  !paint.getShader() &&
-            !paint.getXfermode() && // unless its srcover
-            !paint.getMaskFilter() &&
-            !paint.getRasterizer() &&
-            !paint.getColorFilter() &&
-            !paint.getPathEffect() &&
-            !paint.isFakeBoldText() &&
-            paint.getStyle() == SkPaint::kFill_Style;
-}
-
 static SkMask::Format computeMaskFormat(const SkPaint& paint) {
     uint32_t flags = paint.getFlags();
 
@@ -1138,9 +1119,7 @@
     }
 #else
     if (flags & SkPaint::kLCDRenderText_Flag) {
-        if (canSupportLCD16(paint)) {
-            return SkMask::kLCD16_Format;
-        }
+        return SkMask::kLCD16_Format;
     }
 #endif
 
diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp
index 91a6319..3707b67 100644
--- a/src/gpu/SkGpuDevice.cpp
+++ b/src/gpu/SkGpuDevice.cpp
@@ -1181,6 +1181,31 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
+bool SkGpuDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) {
+    if (!paint.isLCDRenderText()) {
+        // we're cool with the paint as is
+        return false;
+    }
+
+    if (paint.getShader() ||
+        paint.getXfermode() || // unless its srcover
+        paint.getMaskFilter() ||
+        paint.getRasterizer() ||
+        paint.getColorFilter() ||
+        paint.getPathEffect() ||
+        paint.isFakeBoldText() ||
+        paint.getStyle() != SkPaint::kFill_Style) {
+        // turn off lcd
+        flags->fFlags = paint.getFlags() & ~SkPaint::kLCDRenderText_Flag;
+        flags->fHinting = paint.getHinting();
+        return true;
+    }
+    // we're cool with the paint as is
+    return false;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
 SkGpuDevice::TexCache* SkGpuDevice::lockCachedTexture(const SkBitmap& bitmap,
                                                   const GrSamplerState& sampler,
                                                   GrTexture** texture,