From ae2c20f398933a9e86c387dcc465ec0f71065ffc Mon Sep 17 00:00:00 2001 From: "initial.commit" Date: Sun, 27 Jul 2008 00:09:42 +0000 Subject: Add skia to the repository. git-svn-id: svn://svn.chromium.org/chrome/trunk/src@16 0039d316-1c4b-4281-b951-d872f2087c98 --- skia/sgl/SkBlitter_4444.cpp | 495 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 495 insertions(+) create mode 100644 skia/sgl/SkBlitter_4444.cpp (limited to 'skia/sgl/SkBlitter_4444.cpp') diff --git a/skia/sgl/SkBlitter_4444.cpp b/skia/sgl/SkBlitter_4444.cpp new file mode 100644 index 0000000..de42312 --- /dev/null +++ b/skia/sgl/SkBlitter_4444.cpp @@ -0,0 +1,495 @@ +/* libs/graphics/sgl/SkBlitter_ARGB32.cpp + ** + ** Copyright 2006, Google Inc. + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ + +#include "SkCoreBlitters.h" +#include "SkColorPriv.h" +#include "SkDither.h" +#include "SkShader.h" +#include "SkTemplatesPriv.h" +#include "SkUtils.h" +#include "SkXfermode.h" + +inline SkPMColor SkBlendARGB4444(SkPMColor16 src, SkPMColor16 dst, U8CPU aa) +{ + SkASSERT((unsigned)aa <= 255); + + unsigned src_scale = SkAlpha255To256(aa) >> 4; + unsigned dst_scale = SkAlpha15To16(15 - SkAlphaMul4(SkGetPackedA4444(src), src_scale)); + + uint32_t src32 = SkExpand_4444(src) * src_scale; + uint32_t dst32 = SkExpand_4444(dst) * dst_scale; + return SkCompact_4444((src32 + dst32) >> 4); +} + +/////////////////////////////////////////////////////////////////////////////// + +class SkARGB4444_Blitter : public SkRasterBlitter { +public: + SkARGB4444_Blitter(const SkBitmap& device, const SkPaint& paint); + virtual void blitH(int x, int y, int width); + virtual void blitAntiH(int x, int y, const SkAlpha antialias[], const int16_t runs[]); + virtual void blitV(int x, int y, int height, SkAlpha alpha); + virtual void blitRect(int x, int y, int width, int height); + virtual void blitMask(const SkMask&, const SkIRect&); + virtual const SkBitmap* justAnOpaqueColor(uint32_t*); + +protected: + SkPMColor16 fPMColor16, fPMColor16Other; + SkPMColor16 fRawColor16, fRawColor16Other; + uint8_t fScale16; + +private: + // illegal + SkARGB4444_Blitter& operator=(const SkARGB4444_Blitter&); + + typedef SkRasterBlitter INHERITED; +}; + + +SkARGB4444_Blitter::SkARGB4444_Blitter(const SkBitmap& device, const SkPaint& paint) + : INHERITED(device) +{ + // cache premultiplied versions in 4444 + SkPMColor c = SkPreMultiplyColor(paint.getColor()); + fPMColor16 = SkPixel32ToPixel4444(c); + if (paint.isDither()) { + fPMColor16Other = SkDitherPixel32To4444(c); + } else { + fPMColor16Other = fPMColor16; + } + + // cache raw versions in 4444 + fRawColor16 = SkPackARGB4444(0xFF >> 4, SkColorGetR(c) >> 4, + SkColorGetG(c) >> 4, SkColorGetB(c) >> 4); + if (paint.isDither()) { + fRawColor16Other = SkDitherARGB32To4444(0xFF, SkColorGetR(c), + SkColorGetG(c), SkColorGetB(c)); + } else { + fRawColor16Other = fRawColor16; + } + + // our dithered color will be the same or more opaque than the original + // so use dithered to compute our scale + SkASSERT(SkGetPackedA4444(fPMColor16Other) >= SkGetPackedA4444(fPMColor16)); + + fScale16 = SkAlpha15To16(SkGetPackedA4444(fPMColor16Other)); + if (16 == fScale16) { + // force the original to also be opaque + fPMColor16 |= (0xF << SK_A4444_SHIFT); + } +} + +const SkBitmap* SkARGB4444_Blitter::justAnOpaqueColor(uint32_t* value) +{ + if (16 == fScale16) { + *value = fPMColor16; + return &fDevice; + } + return NULL; +} + +static void src_over_4444(SkPMColor16 dst[], SkPMColor16 color, + SkPMColor16 other, unsigned invScale, int count) +{ + int twice = count >> 1; + while (--twice >= 0) { + *dst = color + SkAlphaMulQ4(*dst, invScale); + dst++; + *dst = other + SkAlphaMulQ4(*dst, invScale); + dst++; + } + if (color & 1) { + *dst = color + SkAlphaMulQ4(*dst, invScale); + } +} + +static inline uint32_t SkExpand_4444_Replicate(SkPMColor16 c) +{ + uint32_t c32 = SkExpand_4444(c); + return c32 | (c32 << 4); +} + +static void src_over_4444x(SkPMColor16 dst[], uint32_t color, + uint32_t other, unsigned invScale, int count) +{ + int twice = count >> 1; + uint32_t tmp; + while (--twice >= 0) { + tmp = SkExpand_4444(*dst) * invScale; + *dst++ = SkCompact_4444((color + tmp) >> 4); + tmp = SkExpand_4444(*dst) * invScale; + *dst++ = SkCompact_4444((other + tmp) >> 4); + } + if (color & 1) { + tmp = SkExpand_4444(*dst) * invScale; + *dst = SkCompact_4444((color + tmp) >> 4); + } +} + +void SkARGB4444_Blitter::blitH(int x, int y, int width) +{ + SkASSERT(x >= 0 && y >= 0 && x + width <= fDevice.width()); + + if (0 == fScale16) { + return; + } + + SkPMColor16* device = fDevice.getAddr16(x, y); + SkPMColor16 color = fPMColor16; + SkPMColor16 other = fPMColor16Other; + + if ((x ^ y) & 1) { + SkTSwap(color, other); + } + + if (16 == fScale16) { + sk_dither_memset16(device, color, other, width); + } + else { + src_over_4444x(device, SkExpand_4444_Replicate(color), + SkExpand_4444_Replicate(other), + 16 - fScale16, width); + } +} + +void SkARGB4444_Blitter::blitV(int x, int y, int height, SkAlpha alpha) +{ + if (0 == alpha || 0 == fScale16) { + return; + } + + SkPMColor16* device = fDevice.getAddr16(x, y); + SkPMColor16 color = fPMColor16; + SkPMColor16 other = fPMColor16Other; + unsigned rb = fDevice.rowBytes(); + + if ((x ^ y) & 1) { + SkTSwap(color, other); + } + + if (16 == fScale16 && 255 == alpha) { + while (--height >= 0) { + *device = color; + device = (SkPMColor16*)((char*)device + rb); + SkTSwap(color, other); + } + } else { + unsigned alphaScale = SkAlpha255To256(alpha); + uint32_t c32 = SkExpand_4444(color) * (alphaScale >> 4); + // need to normalize the low nibble of each expanded component + // so we don't overflow the add with d32 + c32 = SkCompact_4444(c32 >> 4); + unsigned invScale = 16 - SkAlpha15To16(SkGetPackedA4444(c32)); + // now re-expand and replicate + c32 = SkExpand_4444_Replicate(c32); + + while (--height >= 0) { + uint32_t d32 = SkExpand_4444(*device) * invScale; + *device = SkCompact_4444((c32 + d32) >> 4); + device = (SkPMColor16*)((char*)device + rb); + } + } +} + +void SkARGB4444_Blitter::blitRect(int x, int y, int width, int height) +{ + SkASSERT(x >= 0 && y >= 0 && x + width <= fDevice.width() && y + height <= fDevice.height()); + + if (0 == fScale16) { + return; + } + + SkPMColor16* device = fDevice.getAddr16(x, y); + SkPMColor16 color = fPMColor16; + SkPMColor16 other = fPMColor16Other; + + if ((x ^ y) & 1) { + SkTSwap(color, other); + } + + if (16 == fScale16) { + while (--height >= 0) { + sk_dither_memset16(device, color, other, width); + device = (SkPMColor16*)((char*)device + fDevice.rowBytes()); + SkTSwap(color, other); + } + } else { + unsigned invScale = 16 - fScale16; + + uint32_t c32 = SkExpand_4444_Replicate(color); + uint32_t o32 = SkExpand_4444_Replicate(other); + while (--height >= 0) { + src_over_4444x(device, c32, o32, invScale, width); + device = (SkPMColor16*)((char*)device + fDevice.rowBytes()); + SkTSwap(c32, o32); + } + } +} + +void SkARGB4444_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[], const int16_t runs[]) +{ + if (0 == fScale16) { + return; + } + + SkPMColor16* device = fDevice.getAddr16(x, y); + SkPMColor16 color = fPMColor16; + SkPMColor16 other = fPMColor16Other; + + if ((x ^ y) & 1) { + SkTSwap(color, other); + } + + for (;;) { + int count = runs[0]; + SkASSERT(count >= 0); + if (count <= 0) { + return; + } + + unsigned aa = antialias[0]; + if (aa) { + if (0xFF == aa) { + if (16 == fScale16) { + sk_dither_memset16(device, color, other, count); + } else { + src_over_4444(device, color, other, 16 - fScale16, count); + } + } else { + // todo: respect dithering + aa = SkAlpha255To256(aa); // FIX + SkPMColor16 src = SkAlphaMulQ4(color, aa >> 4); + unsigned dst_scale = SkAlpha15To16(15 - SkGetPackedA4444(src)); // FIX + int n = count; + do { + --n; + device[n] = src + SkAlphaMulQ4(device[n], dst_scale); + } while (n > 0); + } + } + + runs += count; + antialias += count; + device += count; + + if (count & 1) { + SkTSwap(color, other); + } + } +} + +////////////////////////////////////////////////////////////////////////////////////// + +#define solid_8_pixels(mask, dst, color) \ +do { \ +if (mask & 0x80) dst[0] = color; \ +if (mask & 0x40) dst[1] = color; \ +if (mask & 0x20) dst[2] = color; \ +if (mask & 0x10) dst[3] = color; \ +if (mask & 0x08) dst[4] = color; \ +if (mask & 0x04) dst[5] = color; \ +if (mask & 0x02) dst[6] = color; \ +if (mask & 0x01) dst[7] = color; \ +} while (0) + +#define SK_BLITBWMASK_NAME SkARGB4444_BlitBW +#define SK_BLITBWMASK_ARGS , SkPMColor16 color +#define SK_BLITBWMASK_BLIT8(mask, dst) solid_8_pixels(mask, dst, color) +#define SK_BLITBWMASK_GETADDR getAddr16 +#define SK_BLITBWMASK_DEVTYPE uint16_t +#include "SkBlitBWMaskTemplate.h" + +#define blend_8_pixels(mask, dst, sc, dst_scale) \ +do { \ +if (mask & 0x80) { dst[0] = sc + SkAlphaMulQ4(dst[0], dst_scale); } \ +if (mask & 0x40) { dst[1] = sc + SkAlphaMulQ4(dst[1], dst_scale); } \ +if (mask & 0x20) { dst[2] = sc + SkAlphaMulQ4(dst[2], dst_scale); } \ +if (mask & 0x10) { dst[3] = sc + SkAlphaMulQ4(dst[3], dst_scale); } \ +if (mask & 0x08) { dst[4] = sc + SkAlphaMulQ4(dst[4], dst_scale); } \ +if (mask & 0x04) { dst[5] = sc + SkAlphaMulQ4(dst[5], dst_scale); } \ +if (mask & 0x02) { dst[6] = sc + SkAlphaMulQ4(dst[6], dst_scale); } \ +if (mask & 0x01) { dst[7] = sc + SkAlphaMulQ4(dst[7], dst_scale); } \ +} while (0) + +#define SK_BLITBWMASK_NAME SkARGB4444_BlendBW +#define SK_BLITBWMASK_ARGS , uint16_t sc, unsigned dst_scale +#define SK_BLITBWMASK_BLIT8(mask, dst) blend_8_pixels(mask, dst, sc, dst_scale) +#define SK_BLITBWMASK_GETADDR getAddr16 +#define SK_BLITBWMASK_DEVTYPE uint16_t +#include "SkBlitBWMaskTemplate.h" + +void SkARGB4444_Blitter::blitMask(const SkMask& mask, const SkIRect& clip) +{ + SkASSERT(mask.fBounds.contains(clip)); + + if (0 == fScale16) { + return; + } + + if (mask.fFormat == SkMask::kBW_Format) { + if (16 == fScale16) { + SkARGB4444_BlitBW(fDevice, mask, clip, fPMColor16); + } else { + SkARGB4444_BlendBW(fDevice, mask, clip, fPMColor16, 16 - fScale16); + } + return; + } + + int x = clip.fLeft; + int y = clip.fTop; + int width = clip.width(); + int height = clip.height(); + + SkPMColor16* device = fDevice.getAddr16(x, y); + const uint8_t* alpha = mask.getAddr(x, y); + SkPMColor16 srcColor = fPMColor16; + unsigned devRB = fDevice.rowBytes() - (width << 1); + unsigned maskRB = mask.fRowBytes - width; + + do { + int w = width; + do { + unsigned aa = *alpha++; + *device = SkBlendARGB4444(srcColor, *device, aa); + device += 1; + } while (--w != 0); + device = (SkPMColor16*)((char*)device + devRB); + alpha += maskRB; + } while (--height != 0); +} + +////////////////////////////////////////////////////////////////////////////////////////// + +class SkARGB4444_Shader_Blitter : public SkShaderBlitter { + SkXfermode* fXfermode; + SkBlitRow::Proc fOpaqueProc; + SkBlitRow::Proc fAlphaProc; + SkPMColor* fBuffer; +public: +SkARGB4444_Shader_Blitter(const SkBitmap& device, const SkPaint& paint) + : INHERITED(device, paint) +{ + fBuffer = (SkPMColor*)sk_malloc_throw(device.width() * (sizeof(SkPMColor))); + + (fXfermode = paint.getXfermode())->safeRef(); + + unsigned flags = 0; + if (!(fShader->getFlags() & SkShader::kOpaqueAlpha_Flag)) { + flags |= SkBlitRow::kSrcPixelAlpha_Flag; + } + if (paint.isDither()) { + flags |= SkBlitRow::kDither_Flag; + } + fOpaqueProc = SkBlitRow::Factory(flags, SkBitmap::kARGB_4444_Config); + fAlphaProc = SkBlitRow::Factory(flags | SkBlitRow::kGlobalAlpha_Flag, + SkBitmap::kARGB_4444_Config); +} + +virtual ~SkARGB4444_Shader_Blitter() +{ + fXfermode->safeUnref(); + sk_free(fBuffer); +} + +virtual void blitH(int x, int y, int width) +{ + SkASSERT(x >= 0 && y >= 0 && x + width <= fDevice.width()); + + SkPMColor16* device = fDevice.getAddr16(x, y); + SkPMColor* span = fBuffer; + + fShader->shadeSpan(x, y, span, width); + if (fXfermode) { + fXfermode->xfer4444(device, span, width, NULL); + } + else { + fOpaqueProc(device, span, width, 0xFF, x, y); + } +} + +virtual void blitAntiH(int x, int y, const SkAlpha antialias[], const int16_t runs[]) +{ + SkPMColor* span = fBuffer; + SkPMColor16* device = fDevice.getAddr16(x, y); + SkShader* shader = fShader; + SkXfermode* xfer = fXfermode; + + if (NULL != xfer) { + for (;;) { + int count = *runs; + if (count <= 0) + break; + int aa = *antialias; + if (aa) { + shader->shadeSpan(x, y, span, count); + if (255 == aa) { + xfer->xfer4444(device, span, count, NULL); + } else { + // count is almost always 1 + for (int i = count - 1; i >= 0; --i) { + xfer->xfer4444(&device[i], &span[i], count, antialias); + } + } + } + device += count; + runs += count; + antialias += count; + x += count; + } + } else { // no xfermode + for (;;) { + int count = *runs; + if (count <= 0) + break; + int aa = *antialias; + if (aa) { + fShader->shadeSpan(x, y, span, count); + if (255 == aa) { + fOpaqueProc(device, span, count, aa, x, y); + } else { + fAlphaProc(device, span, count, aa, x, y); + } + } + device += count; + runs += count; + antialias += count; + x += count; + } + } +} + +private: + typedef SkShaderBlitter INHERITED; +}; + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +SkBlitter* SkBlitter_ChooseD4444(const SkBitmap& device, + const SkPaint& paint, + void* storage, size_t storageSize) +{ + SkBlitter* blitter; + + if (paint.getShader()) { + SK_PLACEMENT_NEW_ARGS(blitter, SkARGB4444_Shader_Blitter, storage, storageSize, (device, paint)); + } else { + SK_PLACEMENT_NEW_ARGS(blitter, SkARGB4444_Blitter, storage, storageSize, (device, paint)); + } + return blitter; +} + -- cgit v1.1