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/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,