From f67e4cf4c18cd228738a11372859ee0280bce1d7 Mon Sep 17 00:00:00 2001 From: "reed@google.com" Date: Tue, 15 Mar 2011 20:56:58 +0000 Subject: [PATCH] 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 --- include/core/SkDevice.h | 15 +++++++++++++++ include/gpu/SkGpuDevice.h | 1 + src/core/SkCanvas.cpp | 38 +++++++++++++++++++++++++++++++++++--- src/core/SkDevice.cpp | 26 ++++++++++++++++++++++++++ src/core/SkPaint.cpp | 23 +---------------------- src/gpu/SkGpuDevice.cpp | 25 +++++++++++++++++++++++++ 6 files changed, 103 insertions(+), 25 deletions(-) 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 @@ public: 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 @@ public: 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 @@ void SkCanvas::drawSprite(const SkBitmap& bitmap, int x, int y, 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(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 @@ void SkCanvas::drawPosText(const void* text, size_t byteLength, 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 @@ void SkCanvas::drawPosTextH(const void* text, size_t byteLength, 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 @@ void SkDevice::drawDevice(const SkDraw& draw, SkDevice* device, /////////////////////////////////////////////////////////////////////////////// +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 @@ static void add_flattenable(SkDescriptor* desc, uint32_t tag, 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 @@ static SkMask::Format computeMaskFormat(const SkPaint& paint) { } #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 @@ void SkGpuDevice::drawTextOnPath(const SkDraw& draw, const void* text, /////////////////////////////////////////////////////////////////////////////// +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, -- 2.7.4