Revert "remove kA1_Config, as it is no longer supported"
authorreed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Mon, 25 Nov 2013 20:54:56 +0000 (20:54 +0000)
committerreed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Mon, 25 Nov 2013 20:54:56 +0000 (20:54 +0000)
This reverts commit 2d72d8b242eac6e9d30228f5b0a407236491c369.

git-svn-id: http://skia.googlecode.com/svn/trunk@12387 2bbb7eff-a529-9590-31e7-b0007b416f81

20 files changed:
gm/bitmapcopy.cpp
gm/bitmapfilters.cpp
gyp/core.gypi
include/core/SkBitmap.h
include/core/SkImageDecoder.h
samplecode/SampleApp.cpp
samplecode/SampleFilter.cpp
src/animator/SkDrawBitmap.cpp
src/core/SkBitmap.cpp
src/core/SkBlitter.cpp
src/core/SkBlitter_A1.cpp [new file with mode: 0644]
src/core/SkCoreBlitters.h
src/core/SkScalerContext.cpp
src/effects/SkTransparentShader.cpp
src/pdf/SkPDFImage.cpp
src/utils/debugger/SkObjectParser.cpp
tests/BitmapCopyTest.cpp
tests/BitmapGetColorTest.cpp
tests/BlitRowTest.cpp
tests/ImageDecodingTest.cpp

index 928b4037c136000d0d9910102c37ad51c5a4a31d..5e88cfdd0fe2e0abf4fdf7be119163c834f13f82 100644 (file)
@@ -11,6 +11,7 @@ namespace skiagm {
 
 static const char* gConfigNames[] = {
     "unknown config",
+    "A1",
     "A8",
     "Index8",
     "565",
index 5856f87f66de158b765a309396fae12a8870faef..f0153e482bf9f7338ddc754c8300d3cade6a7105 100644 (file)
@@ -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",
index 530b11831abe0b54b377af78a084890c2bd49c37..54e23efb4f144b2dd9ae914d6c89733ab5d6603c 100644 (file)
@@ -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',
index cd85b6a9b1ad019102ba93271a6bec69ff4d97a1..b58925c9dbb63573178d3196537d7a7df8d466fa 100644 (file)
@@ -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
index 5745dbd5ba255032321bba0454d033684b15a21f..a7e36465539d7708c0eb8a411fba7ebb9980fd29 100644 (file)
@@ -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
index 7162b7b2ad51f86e95eea2fc29ccecc6c2d71b25..bb22685e249a119d514402e615a96bb34e916b0e 100644 (file)
@@ -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",
index 7f902d5b2e9390b64b2721fac72729927ad26511..71ab62fd5510d8b443a9332310e775acf06e8484 100644 (file)
@@ -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",
index 327e81365af40e2800646a0c07024a5b8699613c..568401d0e667cfe3ed63f4269a8361e24d99f848 100644 (file)
@@ -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);
 }
index 38594f8f3c638f6691cb70db44e56f56f20a65e6..2fae75ae3841dd39d53c305ee83f70b8ae806fe5 100644 (file)
@@ -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(),
index 9682d5572a97c3c245c7d381d6a535a6eb97a8d8..dc7946a4bdefd64e2ed0b43b681673ce84f7abc7 100644 (file)
@@ -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 (file)
index 0000000..b64afe2
--- /dev/null
@@ -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;
+    }
+}
index 1605a5273dcd7c2496fb65af8d741d7728cd8620..673b8745456061f85e37dfafcb05b0d4e68c73dc 100644 (file)
@@ -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
index f4f23911b0e3aedbae6194e6efa997a0c96cd946..1d6c2f79a5dcb427cfbf5b94f110596a207df977 100644 (file)
@@ -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);
index 1d7e80877e169f41612121cd1306c498427fd2b7..970e74faa80f41364e599e492bb685587cb4117e 100644 (file)
@@ -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;
     }
index 81adcc20d6b4c671229619c686794652d3d801cc..a99c9fe3903cb438df878a2760768a90cd8a5abe 100644 (file)
@@ -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);
 
index ebbd40018e79e3f7a5b243f35b9356986cdc3eeb..54ae0773fd265788a46acb315d9450889fefa9cf 100644 (file)
@@ -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()]);
index f61d55e953ab3df3ac06b9abc1c1f086f944182c..5cef1eb98668ed14a8a9183bc82f622722b59cd6 100644 (file)
@@ -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 {
index 40aa3e26bff813a53075064fb660cfa2d250d073..11c22e6fa3f2baaea8d307b26c2607d29276208c 100644 (file)
 #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"
index 85761104b2385e92e64e9c611f1e51baf5d4e218..3903efbfba35a9c7bc9a595a2dee75126a477d58 100644 (file)
@@ -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
index 6fcef1d31543ba782f2a77653e64a3a0e2b2bb8e..56193f4e470a8b0301c821331210caa59dace632 100644 (file)
@@ -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,