diff options
-rw-r--r-- | gm/bitmapcopy.cpp | 1 | ||||
-rw-r--r-- | gm/bitmapfilters.cpp | 1 | ||||
-rw-r--r-- | gyp/core.gypi | 1 | ||||
-rw-r--r-- | include/core/SkBitmap.h | 22 | ||||
-rw-r--r-- | include/core/SkImageDecoder.h | 2 | ||||
-rw-r--r-- | samplecode/SampleApp.cpp | 2 | ||||
-rw-r--r-- | samplecode/SampleFilter.cpp | 1 | ||||
-rw-r--r-- | src/animator/SkDrawBitmap.cpp | 9 | ||||
-rw-r--r-- | src/core/SkBitmap.cpp | 68 | ||||
-rw-r--r-- | src/core/SkBlitter.cpp | 5 | ||||
-rw-r--r-- | src/core/SkBlitter_A1.cpp | 50 | ||||
-rw-r--r-- | src/core/SkCoreBlitters.h | 16 | ||||
-rw-r--r-- | src/core/SkScalerContext.cpp | 91 | ||||
-rw-r--r-- | src/effects/SkTransparentShader.cpp | 3 | ||||
-rw-r--r-- | src/pdf/SkPDFImage.cpp | 56 | ||||
-rw-r--r-- | src/utils/debugger/SkObjectParser.cpp | 4 | ||||
-rw-r--r-- | tests/BitmapCopyTest.cpp | 68 | ||||
-rw-r--r-- | tests/BitmapGetColorTest.cpp | 63 | ||||
-rw-r--r-- | tests/BlitRowTest.cpp | 2 | ||||
-rw-r--r-- | tests/ImageDecodingTest.cpp | 2 |
20 files changed, 373 insertions, 94 deletions
diff --git a/gm/bitmapcopy.cpp b/gm/bitmapcopy.cpp index 928b4037c1..5e88cfdd0f 100644 --- a/gm/bitmapcopy.cpp +++ b/gm/bitmapcopy.cpp @@ -11,6 +11,7 @@ namespace skiagm { static const char* gConfigNames[] = { "unknown config", + "A1", "A8", "Index8", "565", diff --git a/gm/bitmapfilters.cpp b/gm/bitmapfilters.cpp index 5856f87f66..f0153e482b 100644 --- a/gm/bitmapfilters.cpp +++ b/gm/bitmapfilters.cpp @@ -47,6 +47,7 @@ static SkScalar draw_set(SkCanvas* c, const SkBitmap& bm, SkScalar x, static const char* gConfigNames[] = { "unknown config", + "A1", "A8", "Index8", "565", diff --git a/gyp/core.gypi b/gyp/core.gypi index 530b11831a..54e23efb4f 100644 --- a/gyp/core.gypi +++ b/gyp/core.gypi @@ -44,6 +44,7 @@ '<(skia_src_path)/core/SkBlitRow_D32.cpp', '<(skia_src_path)/core/SkBlitter.h', '<(skia_src_path)/core/SkBlitter.cpp', + '<(skia_src_path)/core/SkBlitter_A1.cpp', '<(skia_src_path)/core/SkBlitter_A8.cpp', '<(skia_src_path)/core/SkBlitter_ARGB32.cpp', '<(skia_src_path)/core/SkBlitter_RGB16.cpp', diff --git a/include/core/SkBitmap.h b/include/core/SkBitmap.h index cd85b6a9b1..b58925c9db 100644 --- a/include/core/SkBitmap.h +++ b/include/core/SkBitmap.h @@ -42,6 +42,12 @@ public: enum Config { kNo_Config, //!< bitmap has not been configured + /** + * 1-bit per pixel, (0 is transparent, 1 is opaque) + * Valid as a destination (target of a canvas), but not valid as a src. + * i.e. you can draw into a 1-bit bitmap, but you cannot draw from one. + */ + kA1_Config, kA8_Config, //!< 8-bits per pixel, with only alpha specified (0 is transparent, 0xFF is opaque) kIndex8_Config, //!< 8-bits per pixel, using SkColorTable to specify the colors kRGB_565_Config, //!< 16-bits per pixel, (see SkColorPriv.h for packing) @@ -483,6 +489,14 @@ public: */ inline uint8_t* getAddr8(int x, int y) const; + /** Returns the address of the byte containing the pixel specified by x,y + * for 1bit pixels. + * In debug build, this asserts that the pixels are allocated and locked, + * and that the config is 1-bit, however none of these checks are performed + * in the release build. + */ + inline uint8_t* getAddr1(int x, int y) const; + /** Returns the color corresponding to the pixel specified by x,y for * colortable based bitmaps. * In debug build, this asserts that the pixels are allocated and locked, @@ -804,4 +818,12 @@ inline SkPMColor SkBitmap::getIndex8Color(int x, int y) const { return (*fColorTable)[*((const uint8_t*)fPixels + y * fRowBytes + x)]; } +// returns the address of the byte that contains the x coordinate +inline uint8_t* SkBitmap::getAddr1(int x, int y) const { + SkASSERT(fPixels); + SkASSERT(fConfig == kA1_Config); + SkASSERT((unsigned)x < fWidth && (unsigned)y < fHeight); + return (uint8_t*)fPixels + y * fRowBytes + (x >> 3); +} + #endif diff --git a/include/core/SkImageDecoder.h b/include/core/SkImageDecoder.h index 5745dbd5ba..a7e3646553 100644 --- a/include/core/SkImageDecoder.h +++ b/include/core/SkImageDecoder.h @@ -186,7 +186,7 @@ public: src: 32/24, no-alpha -> 4 src: 32/24, yes-alpha -> 5 */ - void setPrefConfigTable(const SkBitmap::Config pref[5]); + void setPrefConfigTable(const SkBitmap::Config pref[6]); /** * Optional table describing the caller's preferred config based on diff --git a/samplecode/SampleApp.cpp b/samplecode/SampleApp.cpp index 7162b7b2ad..bb22685e24 100644 --- a/samplecode/SampleApp.cpp +++ b/samplecode/SampleApp.cpp @@ -1537,6 +1537,7 @@ void SampleWindow::afterChild(SkView* child, SkCanvas* canvas) { static SkBitmap::Config gConfigCycle[] = { SkBitmap::kNo_Config, // none -> none + SkBitmap::kNo_Config, // a1 -> none SkBitmap::kNo_Config, // a8 -> none SkBitmap::kNo_Config, // index8 -> none SkBitmap::kARGB_4444_Config, // 565 -> 4444 @@ -2073,6 +2074,7 @@ void SampleWindow::loadView(SkView* view) { static const char* gConfigNames[] = { "unknown config", + "A1", "A8", "Index8", "565", diff --git a/samplecode/SampleFilter.cpp b/samplecode/SampleFilter.cpp index 7f902d5b2e..71ab62fd55 100644 --- a/samplecode/SampleFilter.cpp +++ b/samplecode/SampleFilter.cpp @@ -67,6 +67,7 @@ static SkScalar draw_set(SkCanvas* c, const SkBitmap& bm, SkScalar x, SkPaint* p static const char* gConfigNames[] = { "unknown config", + "A1", "A8", "Index8", "565", diff --git a/src/animator/SkDrawBitmap.cpp b/src/animator/SkDrawBitmap.cpp index 327e81365a..568401d0e6 100644 --- a/src/animator/SkDrawBitmap.cpp +++ b/src/animator/SkDrawBitmap.cpp @@ -75,10 +75,11 @@ void SkDrawBitmap::dump(SkAnimateMaker* maker) { const char* formatName; switch (format) { case 0: formatName = "none"; break; - case 1: formatName = "A8"; break; - case 2: formatName = "Index8"; break; - case 3: formatName = "RGB16"; break; - case 4: formatName = "RGB32"; break; + case 1: formatName = "A1"; break; + case 2: formatName = "A8"; break; + case 3: formatName = "Index8"; break; + case 4: formatName = "RGB16"; break; + case 5: formatName = "RGB32"; break; } SkDebugf("format=\"%s\" />\n", formatName); } diff --git a/src/core/SkBitmap.cpp b/src/core/SkBitmap.cpp index 38594f8f3c..2fae75ae38 100644 --- a/src/core/SkBitmap.cpp +++ b/src/core/SkBitmap.cpp @@ -161,6 +161,7 @@ int SkBitmap::ComputeBytesPerPixel(SkBitmap::Config config) { int bpp; switch (config) { case kNo_Config: + case kA1_Config: bpp = 0; // not applicable break; case kA8_Config: @@ -193,6 +194,11 @@ size_t SkBitmap::ComputeRowBytes(Config c, int width) { switch (c) { case kNo_Config: break; + case kA1_Config: + rowBytes.set(width); + rowBytes.add(7); + rowBytes.shiftRight(3); + break; case kA8_Config: case kIndex8_Config: rowBytes.set(width); @@ -269,6 +275,7 @@ static bool validate_alphaType(SkBitmap::Config config, SkAlphaType alphaType, case SkBitmap::kNo_Config: alphaType = kIgnore_SkAlphaType; break; + case SkBitmap::kA1_Config: case SkBitmap::kA8_Config: if (kUnpremul_SkAlphaType == alphaType) { alphaType = kPremul_SkAlphaType; @@ -284,8 +291,6 @@ static bool validate_alphaType(SkBitmap::Config config, SkAlphaType alphaType, case SkBitmap::kRGB_565_Config: alphaType = kOpaque_SkAlphaType; break; - default: - return false; } if (canonical) { *canonical = alphaType; @@ -601,6 +606,8 @@ void* SkBitmap::getAddr(int x, int y) const { case SkBitmap::kIndex8_Config: base += x; break; + case SkBitmap::kA1_Config: + base += x >> 3; break; default: SkDEBUGFAIL("Can't return addr for config"); @@ -616,6 +623,15 @@ SkColor SkBitmap::getColor(int x, int y) const { SkASSERT((unsigned)y < (unsigned)this->height()); switch (this->config()) { + case SkBitmap::kA1_Config: { + uint8_t* addr = this->getAddr1(x, y); + uint8_t mask = 1 << (7 - (x % 8)); + if (addr[0] & mask) { + return SK_ColorBLACK; + } else { + return 0; + } + } case SkBitmap::kA8_Config: { uint8_t* addr = this->getAddr8(x, y); return SkColorSetA(0, addr[0]); @@ -638,7 +654,6 @@ SkColor SkBitmap::getColor(int x, int y) const { return SkUnPreMultiply::PMColorToColor(addr[0]); } case kNo_Config: - default: SkASSERT(false); return 0; } @@ -656,6 +671,9 @@ bool SkBitmap::ComputeIsOpaque(const SkBitmap& bm) { const int width = bm.width(); switch (bm.config()) { + case SkBitmap::kA1_Config: { + // TODO + } break; case SkBitmap::kA8_Config: { unsigned a = 0xFF; for (int y = 0; y < height; ++y) { @@ -761,6 +779,38 @@ void SkBitmap::internalErase(const SkIRect& area, } switch (fConfig) { + case kA1_Config: { + uint8_t* p = this->getAddr1(area.fLeft, area.fTop); + const int left = area.fLeft >> 3; + const int right = area.fRight >> 3; + + int middle = right - left - 1; + + uint8_t leftMask = 0xFF >> (area.fLeft & 7); + uint8_t rightMask = ~(0xFF >> (area.fRight & 7)); + if (left == right) { + leftMask &= rightMask; + rightMask = 0; + } + + a = (a >> 7) ? 0xFF : 0; + while (--height >= 0) { + uint8_t* startP = p; + + *p = (*p & ~leftMask) | (a & leftMask); + p++; + if (middle > 0) { + memset(p, a, middle); + p += middle; + } + if (rightMask) { + *p = (*p & ~rightMask) | (a & rightMask); + } + + p = startP + rowBytes; + } + break; + } case kA8_Config: { uint8_t* p = this->getAddr8(area.fLeft, area.fTop); while (--height >= 0) { @@ -846,6 +896,7 @@ static size_t get_sub_offset(const SkBitmap& bm, int x, int y) { break; case SkBitmap::kNo_Config: + case SkBitmap::kA1_Config: default: return SUB_OFFSET_FAILURE; } @@ -888,6 +939,8 @@ bool get_upper_left_from_offset(SkBitmap::Config config, size_t offset, size_t r case SkBitmap::kNo_Config: // Fall through. + case SkBitmap::kA1_Config: + // Fall through. default: return false; } @@ -968,6 +1021,7 @@ bool SkBitmap::canCopyTo(Config dstConfig) const { case kRGB_565_Config: case kARGB_8888_Config: break; + case kA1_Config: case kIndex8_Config: if (!sameConfigs) { return false; @@ -978,6 +1032,12 @@ bool SkBitmap::canCopyTo(Config dstConfig) const { default: return false; } + + // do not copy src if srcConfig == kA1_Config while dstConfig != kA1_Config + if (this->config() == kA1_Config && !sameConfigs) { + return false; + } + return true; } @@ -1621,7 +1681,7 @@ void SkBitmap::validate() const { void SkBitmap::toString(SkString* str) const { static const char* gConfigNames[kConfigCount] = { - "NONE", "A8", "INDEX8", "565", "4444", "8888" + "NONE", "A1", "A8", "INDEX8", "565", "4444", "8888" }; str->appendf("bitmap: ((%d, %d) %s", this->width(), this->height(), diff --git a/src/core/SkBlitter.cpp b/src/core/SkBlitter.cpp index 9682d5572a..dc7946a4bd 100644 --- a/src/core/SkBlitter.cpp +++ b/src/core/SkBlitter.cpp @@ -945,6 +945,11 @@ SkBlitter* SkBlitter::Choose(const SkBitmap& device, switch (device.config()) { + case SkBitmap::kA1_Config: + SK_PLACEMENT_NEW_ARGS(blitter, SkA1_Blitter, + storage, storageSize, (device, *paint)); + break; + case SkBitmap::kA8_Config: if (drawCoverage) { SkASSERT(NULL == shader); diff --git a/src/core/SkBlitter_A1.cpp b/src/core/SkBlitter_A1.cpp new file mode 100644 index 0000000000..b64afe2ae9 --- /dev/null +++ b/src/core/SkBlitter_A1.cpp @@ -0,0 +1,50 @@ + +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#include "SkCoreBlitters.h" + +SkA1_Blitter::SkA1_Blitter(const SkBitmap& device, const SkPaint& paint) + : INHERITED(device) { + fSrcA = paint.getAlpha(); +} + +void SkA1_Blitter::blitH(int x, int y, int width) { + SkASSERT(x >= 0 && y >= 0 && + (unsigned)(x + width) <= (unsigned)fDevice.width()); + + if (fSrcA <= 0x7F) { + return; + } + uint8_t* dst = fDevice.getAddr1(x, y); + int right = x + width; + + int left_mask = 0xFF >> (x & 7); + int rite_mask = 0xFF << (8 - (right & 7)); + int full_runs = (right >> 3) - ((x + 7) >> 3); + + // check for empty right mask, so we don't read off the end + // (or go slower than we need to) + if (rite_mask == 0) { + SkASSERT(full_runs >= 0); + full_runs -= 1; + rite_mask = 0xFF; + } + if (left_mask == 0xFF) { + full_runs -= 1; + } + if (full_runs < 0) { + SkASSERT((left_mask & rite_mask) != 0); + *dst |= (left_mask & rite_mask); + } else { + *dst++ |= left_mask; + memset(dst, 0xFF, full_runs); + dst += full_runs; + *dst |= rite_mask; + } +} diff --git a/src/core/SkCoreBlitters.h b/src/core/SkCoreBlitters.h index 1605a5273d..673b874545 100644 --- a/src/core/SkCoreBlitters.h +++ b/src/core/SkCoreBlitters.h @@ -162,6 +162,22 @@ private: /////////////////////////////////////////////////////////////////////////////// +class SkA1_Blitter : public SkRasterBlitter { +public: + SkA1_Blitter(const SkBitmap& device, const SkPaint& paint); + virtual void blitH(int x, int y, int width) SK_OVERRIDE; + +private: + uint8_t fSrcA; + + // illegal + SkA1_Blitter& operator=(const SkA1_Blitter&); + + typedef SkRasterBlitter INHERITED; +}; + +/////////////////////////////////////////////////////////////////////////////// + /* These return the correct subclass of blitter for their device config. Currently, they make the following assumptions about the state of the diff --git a/src/core/SkScalerContext.cpp b/src/core/SkScalerContext.cpp index f4f23911b0..1d6c2f79a5 100644 --- a/src/core/SkScalerContext.cpp +++ b/src/core/SkScalerContext.cpp @@ -523,54 +523,10 @@ static void pack4xHToLCD32(const SkBitmap& src, const SkMask& dst, } } -static inline int convert_8_to_1(unsigned byte) { - SkASSERT(byte <= 0xFF); - return byte >> 7; -} - -static uint8_t pack_8_to_1(const uint8_t alpha[8]) { - unsigned bits = 0; - for (int i = 0; i < 8; ++i) { - bits |= convert_8_to_1(alpha[i]); - bits <<= 1; - } - return SkToU8(bits); -} - -static void packA8ToA1(const SkMask& mask, const uint8_t* src, size_t srcRB) { - const int height = mask.fBounds.height(); - const int width = mask.fBounds.width(); - const int octs = width >> 3; - const int leftOverBits = width & 7; - - uint8_t* dst = mask.fImage; - const int dstPad = mask.fRowBytes - SkAlign8(width); - SkASSERT(dstPad >= 0); - - const int srcPad = srcRB - width; - SkASSERT(srcPad >= 0); - - for (int y = 0; y < height; ++y) { - for (int i = 0; i < octs; ++i) { - *dst++ = pack_8_to_1(src); - src += 8; - } - if (leftOverBits > 0) { - unsigned bits = 0; - int shift = 7; - for (int i = 0; i < leftOverBits; ++i, --shift) { - bits |= convert_8_to_1(*src++ >> 7) << shift; - } - *dst++ = bits; - } - src += srcPad; - dst += dstPad; - } -} - static void generateMask(const SkMask& mask, const SkPath& path, const SkMaskGamma::PreBlend& maskPreBlend) { - SkPaint paint; + SkBitmap::Config config; + SkPaint paint; int srcW = mask.fBounds.width(); int srcH = mask.fBounds.height(); @@ -582,25 +538,27 @@ static void generateMask(const SkMask& mask, const SkPath& path, matrix.setTranslate(-SkIntToScalar(mask.fBounds.fLeft), -SkIntToScalar(mask.fBounds.fTop)); - SkBitmap::Config config = SkBitmap::kA8_Config; - paint.setAntiAlias(SkMask::kBW_Format != mask.fFormat); - switch (mask.fFormat) { - case SkMask::kBW_Format: - dstRB = 0; // signals we need a copy - break; - case SkMask::kA8_Format: - break; - case SkMask::kLCD16_Format: - case SkMask::kLCD32_Format: - // TODO: trigger off LCD orientation - dstW = 4*dstW - 8; - matrix.setTranslate(-SkIntToScalar(mask.fBounds.fLeft + 1), - -SkIntToScalar(mask.fBounds.fTop)); - matrix.postScale(SkIntToScalar(4), SK_Scalar1); - dstRB = 0; // signals we need a copy - break; - default: - SkDEBUGFAIL("unexpected mask format"); + if (SkMask::kBW_Format == mask.fFormat) { + config = SkBitmap::kA1_Config; + paint.setAntiAlias(false); + } else { + config = SkBitmap::kA8_Config; + paint.setAntiAlias(true); + switch (mask.fFormat) { + case SkMask::kA8_Format: + break; + case SkMask::kLCD16_Format: + case SkMask::kLCD32_Format: + // TODO: trigger off LCD orientation + dstW = 4*dstW - 8; + matrix.setTranslate(-SkIntToScalar(mask.fBounds.fLeft + 1), + -SkIntToScalar(mask.fBounds.fTop)); + matrix.postScale(SkIntToScalar(4), SK_Scalar1); + dstRB = 0; // signals we need a copy + break; + default: + SkDEBUGFAIL("unexpected mask format"); + } } SkRasterClip clip; @@ -629,9 +587,6 @@ static void generateMask(const SkMask& mask, const SkPath& path, draw.drawPath(path, paint); switch (mask.fFormat) { - case SkMask::kBW_Format: - packA8ToA1(mask, bm.getAddr8(0, 0), bm.rowBytes()); - break; case SkMask::kA8_Format: if (maskPreBlend.isApplicable()) { applyLUTToA8Mask(mask, maskPreBlend.fG); diff --git a/src/effects/SkTransparentShader.cpp b/src/effects/SkTransparentShader.cpp index 1d7e80877e..970e74faa8 100644 --- a/src/effects/SkTransparentShader.cpp +++ b/src/effects/SkTransparentShader.cpp @@ -94,6 +94,9 @@ void SkTransparentShader::shadeSpan(int x, int y, SkPMColor span[], int count) { } break; } + case SkBitmap::kA1_Config: + SkDEBUGFAIL("kA1_Config umimplemented at this time"); + break; default: // to avoid warnings break; } diff --git a/src/pdf/SkPDFImage.cpp b/src/pdf/SkPDFImage.cpp index 81adcc20d6..a99c9fe390 100644 --- a/src/pdf/SkPDFImage.cpp +++ b/src/pdf/SkPDFImage.cpp @@ -36,6 +36,7 @@ static size_t get_uncompressed_size(const SkBitmap& bitmap, return srcRect.width() * 3 * srcRect.height(); case SkBitmap::kARGB_8888_Config: return srcRect.width() * 3 * srcRect.height(); + case SkBitmap::kA1_Config: case SkBitmap::kA8_Config: return 1; default: @@ -165,6 +166,48 @@ static SkStream* extract_argb8888_data(const SkBitmap& bitmap, return stream; } +static SkStream* extract_a1_alpha(const SkBitmap& bitmap, + const SkIRect& srcRect, + bool* isOpaque, + bool* isTransparent) { + const int alphaRowBytes = (srcRect.width() + 7) / 8; + SkStream* stream = SkNEW_ARGS(SkMemoryStream, + (alphaRowBytes * srcRect.height())); + uint8_t* alphaDst = (uint8_t*)stream->getMemoryBase(); + + int offset1 = srcRect.fLeft % 8; + int offset2 = 8 - offset1; + + for (int y = srcRect.fTop; y < srcRect.fBottom; y++) { + uint8_t* src = bitmap.getAddr1(0, y); + // This may read up to one byte after src, but the + // potentially invalid bits are never used for computation. + for (int x = srcRect.fLeft; x < srcRect.fRight; x += 8) { + if (offset1) { + alphaDst[0] = src[x / 8] << offset1 | + src[x / 8 + 1] >> offset2; + } else { + alphaDst[0] = src[x / 8]; + } + if (x + 7 < srcRect.fRight) { + *isOpaque &= alphaDst[0] == SK_AlphaOPAQUE; + *isTransparent &= alphaDst[0] == SK_AlphaTRANSPARENT; + } + alphaDst++; + } + // Calculate the mask of bits we're interested in within the + // last byte of alphaDst. + // width mod 8 == 1 -> 0x80 ... width mod 8 == 7 -> 0xFE + uint8_t mask = ~((1 << (8 - (srcRect.width() % 8))) - 1); + if (srcRect.width() % 8) { + *isOpaque &= (alphaDst[-1] & mask) == (SK_AlphaOPAQUE & mask); + *isTransparent &= + (alphaDst[-1] & mask) == (SK_AlphaTRANSPARENT & mask); + } + } + return stream; +} + static SkStream* extract_a8_alpha(const SkBitmap& bitmap, const SkIRect& srcRect, bool* isOpaque, @@ -240,6 +283,14 @@ static SkStream* extract_image_data(const SkBitmap& bitmap, stream = extract_argb8888_data(bitmap, srcRect, extractAlpha, &isOpaque, &transparent); break; + case SkBitmap::kA1_Config: + if (!extractAlpha) { + stream = create_black_image(); + } else { + stream = extract_a1_alpha(bitmap, srcRect, + &isOpaque, &transparent); + } + break; case SkBitmap::kA8_Config: if (!extractAlpha) { stream = create_black_image(); @@ -523,7 +574,8 @@ SkPDFImage::SkPDFImage(SkStream* stream, insertName("Type", "XObject"); insertName("Subtype", "Image"); - bool alphaOnly = (config == SkBitmap::kA8_Config); + bool alphaOnly = (config == SkBitmap::kA1_Config || + config == SkBitmap::kA8_Config); if (!isAlpha && alphaOnly) { // For alpha only images, we stretch a single pixel of black for @@ -549,6 +601,8 @@ SkPDFImage::SkPDFImage(SkStream* stream, int bitsPerComp = 8; if (config == SkBitmap::kARGB_4444_Config) { bitsPerComp = 4; + } else if (isAlpha && config == SkBitmap::kA1_Config) { + bitsPerComp = 1; } insertInt("BitsPerComponent", bitsPerComp); diff --git a/src/utils/debugger/SkObjectParser.cpp b/src/utils/debugger/SkObjectParser.cpp index ebbd40018e..54ae0773fd 100644 --- a/src/utils/debugger/SkObjectParser.cpp +++ b/src/utils/debugger/SkObjectParser.cpp @@ -26,9 +26,9 @@ SkString* SkObjectParser::BitmapToString(const SkBitmap& bitmap) { mBitmap->appendS32(bitmap.height()); const char* gConfigStrings[] = { - "None", "A8", "Index8", "RGB565", "ARGB4444", "ARGB8888" + "None", "A1", "A8", "Index8", "RGB565", "ARGB4444", "ARGB8888" }; - SkASSERT(SkBitmap::kConfigCount == SK_ARRAY_COUNT(gConfigStrings)); + SkASSERT(SkBitmap::kConfigCount == 7); mBitmap->append(" Config: "); mBitmap->append(gConfigStrings[bitmap.config()]); diff --git a/tests/BitmapCopyTest.cpp b/tests/BitmapCopyTest.cpp index f61d55e953..5cef1eb986 100644 --- a/tests/BitmapCopyTest.cpp +++ b/tests/BitmapCopyTest.cpp @@ -15,7 +15,7 @@ static const char* boolStr(bool value) { // these are in the same order as the SkBitmap::Config enum static const char* gConfigName[] = { - "None", "A8", "Index8", "565", "4444", "8888" + "None", "A1", "A8", "Index8", "565", "4444", "8888", "RLE_Index8" }; static void report_opaqueness(skiatest::Reporter* reporter, const SkBitmap& src, @@ -57,6 +57,10 @@ static void init_src(const SkBitmap& bitmap) { if (bitmap.getPixels()) { if (bitmap.getColorTable()) { sk_bzero(bitmap.getPixels(), bitmap.getSize()); + } else if (SkBitmap::kA1_Config == bitmap.config()) { + // The A1 config can have uninitialized bits at the + // end of each row if eraseColor is used + memset(bitmap.getPixels(), 0xff, bitmap.getSafeSize()); } else { bitmap.eraseColor(SK_ColorWHITE); } @@ -88,7 +92,7 @@ struct Pair { static uint32_t getPixel(int x, int y, const SkBitmap& bm) { uint32_t val = 0; uint16_t val16; - uint8_t val8; + uint8_t val8, shift; SkAutoLockPixels lock(bm); const void* rawAddr = bm.getAddr(x,y); @@ -106,6 +110,11 @@ static uint32_t getPixel(int x, int y, const SkBitmap& bm) { memcpy(&val8, rawAddr, sizeof(uint8_t)); val = val8; break; + case SkBitmap::kA1_Config: + memcpy(&val8, rawAddr, sizeof(uint8_t)); + shift = x % 8; + val = (val8 >> shift) & 0x1 ; + break; default: break; } @@ -117,7 +126,7 @@ static uint32_t getPixel(int x, int y, const SkBitmap& bm) { // converted to, but at present uint32_t can handle all formats. static void setPixel(int x, int y, uint32_t val, SkBitmap& bm) { uint16_t val16; - uint8_t val8; + uint8_t val8, shift; SkAutoLockPixels lock(bm); void* rawAddr = bm.getAddr(x,y); @@ -135,6 +144,15 @@ static void setPixel(int x, int y, uint32_t val, SkBitmap& bm) { val8 = val & 0xFF; memcpy(rawAddr, &val8, sizeof(uint8_t)); break; + case SkBitmap::kA1_Config: + shift = x % 8; // We assume we're in the right byte. + memcpy(&val8, rawAddr, sizeof(uint8_t)); + if (val & 0x1) // Turn bit on. + val8 |= (0x1 << shift); + else // Turn bit off. + val8 &= ~(0x1 << shift); + memcpy(rawAddr, &val8, sizeof(uint8_t)); + break; default: // Ignore. break; @@ -146,6 +164,7 @@ static void setPixel(int x, int y, uint32_t val, SkBitmap& bm) { static const char* getSkConfigName(const SkBitmap& bm) { switch (bm.config()) { case SkBitmap::kNo_Config: return "SkBitmap::kNo_Config"; + case SkBitmap::kA1_Config: return "SkBitmap::kA1_Config"; case SkBitmap::kA8_Config: return "SkBitmap::kA8_Config"; case SkBitmap::kIndex8_Config: return "SkBitmap::kIndex8_Config"; case SkBitmap::kRGB_565_Config: return "SkBitmap::kRGB_565_Config"; @@ -206,12 +225,13 @@ static void writeCoordPixels(SkBitmap& bm, const Coordinates& coords) { static void TestBitmapCopy(skiatest::Reporter* reporter) { static const Pair gPairs[] = { - { SkBitmap::kNo_Config, "0000000" }, - { SkBitmap::kA8_Config, "0101010" }, - { SkBitmap::kIndex8_Config, "0111010" }, - { SkBitmap::kRGB_565_Config, "0101010" }, - { SkBitmap::kARGB_4444_Config, "0101110" }, - { SkBitmap::kARGB_8888_Config, "0101110" }, + { SkBitmap::kNo_Config, "00000000" }, + { SkBitmap::kA1_Config, "01000000" }, + { SkBitmap::kA8_Config, "00101010" }, + { SkBitmap::kIndex8_Config, "00111010" }, + { SkBitmap::kRGB_565_Config, "00101010" }, + { SkBitmap::kARGB_4444_Config, "00101110" }, + { SkBitmap::kARGB_8888_Config, "00101110" }, }; static const bool isExtracted[] = { @@ -355,6 +375,12 @@ static void TestBitmapCopy(skiatest::Reporter* reporter) { case SkBitmap::kNo_Config: break; + case SkBitmap::kA1_Config: + if (safeSize.fHi != 0x470DE || + safeSize.fLo != 0x4DF82000) + sizeFail = true; + break; + case SkBitmap::kA8_Config: case SkBitmap::kIndex8_Config: if (safeSize.fHi != 0x2386F2 || @@ -385,8 +411,21 @@ static void TestBitmapCopy(skiatest::Reporter* reporter) { reporter->reportFailed(str); } - int subW = 2; - int subH = 2; + int subW, subH; + // Set sizes to be height = 2 to force the last row of the + // source to be used, thus verifying correct operation if + // the bitmap is an extracted subset. + if (gPairs[i].fConfig == SkBitmap::kA1_Config) { + // If one-bit per pixel, use 9 pixels to force more than + // one byte per row. + subW = 9; + subH = 2; + } else { + // All other configurations are at least one byte per pixel, + // and different configs will test copying different numbers + // of bytes. + subW = subH = 2; + } // Create bitmap to act as source for copies and subsets. SkBitmap src, subset; @@ -410,7 +449,12 @@ static void TestBitmapCopy(skiatest::Reporter* reporter) { // The extractedSubset() test case allows us to test copy- // ing when src and dst mave possibly different strides. SkIRect r; - r.set(1, 0, 1 + subW, subH); // 2x2 extracted bitmap + if (gPairs[i].fConfig == SkBitmap::kA1_Config) + // This config seems to need byte-alignment of + // extracted subset bits. + r.set(0, 0, subW, subH); + else + r.set(1, 0, 1 + subW, subH); // 2x2 extracted bitmap srcReady = src.extractSubset(&subset, r); } else { diff --git a/tests/BitmapGetColorTest.cpp b/tests/BitmapGetColorTest.cpp index 40aa3e26bf..11c22e6fa3 100644 --- a/tests/BitmapGetColorTest.cpp +++ b/tests/BitmapGetColorTest.cpp @@ -10,6 +10,67 @@ #include "SkRect.h" #include "SkRandom.h" +static int nextRand(SkRandom& rand, int min, int max) { + return min + (int)rand.nextRangeU(0, max - min); +} + +static void rand_irect(SkIRect* rect, int W, int H, SkRandom& rand) { + const int DX = W / 2; + const int DY = H / 2; + + rect->fLeft = nextRand(rand, -DX, W + DX); + rect->fTop = nextRand(rand, -DY, H + DY); + rect->fRight = nextRand(rand, -DX, W + DX); + rect->fBottom = nextRand(rand, -DY, H + DY); + rect->sort(); +} + +static void test_equal_A1_A8(skiatest::Reporter* reporter, + const SkBitmap& bm1, const SkBitmap& bm8) { + SkASSERT(SkBitmap::kA1_Config == bm1.config()); + SkASSERT(SkBitmap::kA8_Config == bm8.config()); + + REPORTER_ASSERT(reporter, bm1.width() == bm8.width()); + REPORTER_ASSERT(reporter, bm1.height() == bm8.height()); + for (int y = 0; y < bm1.height(); ++y) { + for (int x = 0; x < bm1.width(); ++x) { + int p1 = *bm1.getAddr1(x, y) & (1 << (7 - (x & 7))); + SkASSERT(SkIsPow2(p1)); + p1 = p1 ? 0xFF : 0; + + int p8 = *bm8.getAddr8(x, y); + SkASSERT(0 == p8 || 0xFF == p8); + + REPORTER_ASSERT(reporter, p1 == p8); + } + } +} + +static void test_eraserect_A1(skiatest::Reporter* reporter) { + const int W = 43; + const int H = 13; + + SkBitmap bm1, bm8; + + bm1.setConfig(SkBitmap::kA1_Config, W, H); + bm1.allocPixels(); + bm8.setConfig(SkBitmap::kA8_Config, W, H); + bm8.allocPixels(); + + SkRandom rand; + for (int i = 0; i < 10000; ++i) { + SkIRect area; + rand_irect(&area, W, H, rand); + + bm1.eraseColor(0); + bm8.eraseColor(0); + + bm1.eraseArea(area, SK_ColorWHITE); + bm8.eraseArea(area, SK_ColorWHITE); + test_equal_A1_A8(reporter, bm1, bm8); + } +} + static void TestGetColor(skiatest::Reporter* reporter) { static const struct Rec { SkBitmap::Config fConfig; @@ -44,6 +105,8 @@ static void TestGetColor(skiatest::Reporter* reporter) { SkColor c = bm.getColor(1, 1); REPORTER_ASSERT(reporter, c == gRec[i].fOutColor); } + + test_eraserect_A1(reporter); } #include "TestClassDef.h" diff --git a/tests/BlitRowTest.cpp b/tests/BlitRowTest.cpp index 85761104b2..3903efbfba 100644 --- a/tests/BlitRowTest.cpp +++ b/tests/BlitRowTest.cpp @@ -14,7 +14,7 @@ // these are in the same order as the SkBitmap::Config enum static const char* gConfigName[] = { - "None", "A8", "Index8", "565", "4444", "8888" + "None", "A1", "A8", "Index8", "565", "4444", "8888", "RLE_Index8" }; /** Returns -1 on success, else the x coord of the first bad pixel, return its diff --git a/tests/ImageDecodingTest.cpp b/tests/ImageDecodingTest.cpp index 6fcef1d315..56193f4e47 100644 --- a/tests/ImageDecodingTest.cpp +++ b/tests/ImageDecodingTest.cpp @@ -148,7 +148,7 @@ public: // the list is that each one is different, so we can test // to make sure the correct config is chosen. const SkBitmap::Config configs[] = { - SkBitmap::kA8_Config, + SkBitmap::kA1_Config, SkBitmap::kA8_Config, SkBitmap::kIndex8_Config, SkBitmap::kRGB_565_Config, |