| Index: dm/DMWriteTask.cpp | 
| diff --git a/dm/DMWriteTask.cpp b/dm/DMWriteTask.cpp | 
| index e30cbdbf855e5fcc060b39a377e44b0788f45fde..04479e94fbcda3a89f2de0af4e32d6fef64fc1ef 100644 | 
| --- a/dm/DMWriteTask.cpp | 
| +++ b/dm/DMWriteTask.cpp | 
| @@ -3,10 +3,9 @@ | 
| #include "DMUtil.h" | 
| #include "SkColorPriv.h" | 
| #include "SkCommandLineFlags.h" | 
| -#include "SkImageDecoder.h" | 
| #include "SkImageEncoder.h" | 
| #include "SkString.h" | 
| -#include "SkUnPreMultiply.h" | 
| +#include "SkStream.h" | 
|  | 
| DEFINE_string2(writePath, w, "", "If set, write GMs here as .pngs."); | 
|  | 
| @@ -39,6 +38,58 @@ void WriteTask::makeDirOrFail(SkString dir) { | 
| } | 
| } | 
|  | 
| +// One file that first contains a .png of an SkBitmap, then its raw pixels. | 
| +// We use this custom format to avoid premultiplied/unpremultiplied pixel conversions. | 
| +struct PngAndRaw { | 
| +    static bool Encode(SkBitmap bitmap, const char* path) { | 
| +        SkFILEWStream stream(path); | 
| +        if (!stream.isValid()) { | 
| +            SkDebugf("Can't write %s.\n", path); | 
| +            return false; | 
| +        } | 
| + | 
| +        // Write a PNG first for humans and other tools to look at. | 
| +        if (!SkImageEncoder::EncodeStream(&stream, bitmap, SkImageEncoder::kPNG_Type, 100)) { | 
| +            SkDebugf("Can't encode a PNG.\n"); | 
| +            return false; | 
| +        } | 
| + | 
| +        // Then write our secret raw pixels that only DM reads. | 
| +        SkAutoLockPixels lock(bitmap); | 
| +        return stream.write(bitmap.getPixels(), bitmap.getSize()); | 
| +    } | 
| + | 
| +    // This assumes bitmap already has allocated pixels of the correct size. | 
| +    static bool Decode(const char* path, SkBitmap* bitmap) { | 
| +        SkAutoTUnref<SkStreamRewindable> stream(SkStream::NewFromFile(path)); | 
| +        if (NULL == stream.get()) { | 
| +            SkDebugf("Can't read %s.\n", path); | 
| +            return false; | 
| +        } | 
| + | 
| +        // The raw pixels are at the end of the stream.  Seek ahead to skip beyond the encoded PNG. | 
| +        const size_t bitmapBytes = bitmap->getSize(); | 
| +        if (stream->getLength() < bitmapBytes) { | 
| +            SkDebugf("%s is too small to contain the bitmap we're looking for.\n", path); | 
| +            return false; | 
| +        } | 
| +        SkAssertResult(stream->seek(stream->getLength() - bitmapBytes)); | 
| + | 
| +        // Read the raw pixels. | 
| +        // TODO(mtklein): can we install a pixelref that just hangs onto the stream instead of | 
| +        // copying into a malloc'd buffer? | 
| +        SkAutoLockPixels lock(*bitmap); | 
| +        if (bitmapBytes != stream->read(bitmap->getPixels(), bitmapBytes)) { | 
| +            SkDebugf("Couldn't read raw bitmap from %s at %lu of %lu.\n", | 
| +                     path, stream->getPosition(), stream->getLength()); | 
| +            return false; | 
| +        } | 
| + | 
| +        SkASSERT(stream->isAtEnd()); | 
| +        return true; | 
| +    } | 
| +}; | 
| + | 
| void WriteTask::draw() { | 
| SkString dir(FLAGS_writePath[0]); | 
| this->makeDirOrFail(dir); | 
| @@ -48,10 +99,7 @@ void WriteTask::draw() { | 
| } | 
| SkString path = SkOSPath::SkPathJoin(dir.c_str(), fGmName.c_str()); | 
| path.append(".png"); | 
| -    if (!SkImageEncoder::EncodeFile(path.c_str(), | 
| -                                    fBitmap, | 
| -                                    SkImageEncoder::kPNG_Type, | 
| -                                    100/*quality*/)) { | 
| +    if (!PngAndRaw::Encode(fBitmap, path.c_str())) { | 
| this->fail(); | 
| } | 
| } | 
| @@ -85,8 +133,6 @@ static SkString path_to_expected_image(const char* root, const Task& task) { | 
| filename.remove(filename.size() - suffixLength, suffixLength); | 
| filename.append(".png"); | 
|  | 
| -    //SkDebugf("dir %s, filename %s\n", dir.c_str(), filename.c_str()); | 
| - | 
| return SkOSPath::SkPathJoin(dir.c_str(), filename.c_str()); | 
| } | 
|  | 
| @@ -96,58 +142,13 @@ bool WriteTask::Expectations::check(const Task& task, SkBitmap bitmap) const { | 
| return false; | 
| } | 
|  | 
| -    // PNG is stored unpremultiplied, and going from premul to unpremul to premul is lossy.  To | 
| -    // skirt this problem, we decode the PNG into an unpremul bitmap, convert our bitmap to unpremul | 
| -    // if needed, and compare those.  Each image goes once from premul to unpremul, never back. | 
| const SkString path = path_to_expected_image(fRoot, task); | 
| - | 
| -    SkAutoTUnref<SkStreamRewindable> stream(SkStream::NewFromFile(path.c_str())); | 
| -    if (NULL == stream.get()) { | 
| -        SkDebugf("Could not read %s.\n", path.c_str()); | 
| -        return false; | 
| -    } | 
| - | 
| -    SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(stream)); | 
| -    if (NULL == decoder.get()) { | 
| -        SkDebugf("Could not find a decoder for %s.\n", path.c_str()); | 
| -        return false; | 
| -    } | 
| - | 
| -    const SkImageInfo info = bitmap.info(); | 
| - | 
| SkBitmap expected; | 
| -    expected.allocPixels(info); | 
| - | 
| -    // expected will be unpremultiplied. | 
| -    decoder->setRequireUnpremultipliedColors(true); | 
| -    if (!decoder->decode(stream, &expected, SkImageDecoder::kDecodePixels_Mode)) { | 
| -        SkDebugf("Could not decode %s.\n", path.c_str()); | 
| +    expected.allocPixels(bitmap.info()); | 
| +    if (!PngAndRaw::Decode(path.c_str(), &expected)) { | 
| return false; | 
| } | 
|  | 
| -    // We always seem to decode to 8888.  This puts 565 back in 565. | 
| -    if (expected.colorType() != bitmap.colorType()) { | 
| -        SkBitmap converted; | 
| -        SkAssertResult(expected.copyTo(&converted, bitmap.colorType())); | 
| -        expected.swap(converted); | 
| -    } | 
| -    SkASSERT(expected.config() == bitmap.config()); | 
| - | 
| -    // Manually unpremultiply 8888 bitmaps to match expected. | 
| -    // Their pixels are shared, concurrently even, so we must copy them. | 
| -    if (info.colorType() == kPMColor_SkColorType) { | 
| -        SkBitmap unpremul; | 
| -        unpremul.allocPixels(info); | 
| - | 
| -        SkAutoLockPixels lockSrc(bitmap), lockDst(unpremul); | 
| -        const SkPMColor* src = (SkPMColor*)bitmap.getPixels(); | 
| -        uint32_t* dst = (uint32_t*)unpremul.getPixels(); | 
| -        for (size_t i = 0; i < bitmap.getSize()/4; i++) { | 
| -            dst[i] = SkUnPreMultiply::UnPreMultiplyPreservingByteOrder(src[i]); | 
| -        } | 
| -        bitmap.swap(unpremul); | 
| -    } | 
| - | 
| return BitmapsEqual(expected, bitmap); | 
| } | 
|  | 
|  |