Example #1
0
DEF_TEST(BitmapCopy, reporter) {
    static const bool isExtracted[] = {
        false, true
    };

    for (size_t i = 0; i < SK_ARRAY_COUNT(gPairs); i++) {
        SkBitmap srcOpaque, srcPremul;
        setup_src_bitmaps(&srcOpaque, &srcPremul, gPairs[i].fColorType);

        for (size_t j = 0; j < SK_ARRAY_COUNT(gPairs); j++) {
            SkBitmap dst;

            bool success = srcPremul.copyTo(&dst, gPairs[j].fColorType);
            bool expected = gPairs[i].fValid[j] != '0';
            if (success != expected) {
                ERRORF(reporter, "SkBitmap::copyTo from %s to %s. expected %s "
                       "returned %s", gColorTypeName[i], gColorTypeName[j],
                       boolStr(expected), boolStr(success));
            }

            bool canSucceed = srcPremul.canCopyTo(gPairs[j].fColorType);
            if (success != canSucceed) {
                ERRORF(reporter, "SkBitmap::copyTo from %s to %s. returned %s "
                       "canCopyTo %s", gColorTypeName[i], gColorTypeName[j],
                       boolStr(success), boolStr(canSucceed));
            }

            if (success) {
                REPORTER_ASSERT(reporter, srcPremul.width() == dst.width());
                REPORTER_ASSERT(reporter, srcPremul.height() == dst.height());
                REPORTER_ASSERT(reporter, dst.colorType() == gPairs[j].fColorType);
                test_isOpaque(reporter, srcOpaque, srcPremul, dst.colorType());
                if (srcPremul.colorType() == dst.colorType()) {
                    SkAutoLockPixels srcLock(srcPremul);
                    SkAutoLockPixels dstLock(dst);
                    REPORTER_ASSERT(reporter, srcPremul.readyToDraw());
                    REPORTER_ASSERT(reporter, dst.readyToDraw());
                    const char* srcP = (const char*)srcPremul.getAddr(0, 0);
                    const char* dstP = (const char*)dst.getAddr(0, 0);
                    REPORTER_ASSERT(reporter, srcP != dstP);
                    REPORTER_ASSERT(reporter, !memcmp(srcP, dstP,
                                                      srcPremul.getSize()));
                    REPORTER_ASSERT(reporter, srcPremul.getGenerationID() == dst.getGenerationID());
                } else {
                    REPORTER_ASSERT(reporter, srcPremul.getGenerationID() != dst.getGenerationID());
                }
            } else {
                // dst should be unchanged from its initial state
                REPORTER_ASSERT(reporter, dst.colorType() == kUnknown_SkColorType);
                REPORTER_ASSERT(reporter, dst.width() == 0);
                REPORTER_ASSERT(reporter, dst.height() == 0);
            }
        } // for (size_t j = ...

        // Tests for getSafeSize(), getSafeSize64(), copyPixelsTo(),
        // copyPixelsFrom().
        //
        for (size_t copyCase = 0; copyCase < SK_ARRAY_COUNT(isExtracted);
             ++copyCase) {
            // Test copying to/from external buffer.
            // Note: the tests below have hard-coded values ---
            //       Please take care if modifying.

            // Tests for getSafeSize64().
            // Test with a very large configuration without pixel buffer
            // attached.
            SkBitmap tstSafeSize;
            tstSafeSize.setInfo(SkImageInfo::Make(100000000U, 100000000U,
                                                  gPairs[i].fColorType, kPremul_SkAlphaType));
            int64_t safeSize = tstSafeSize.computeSafeSize64();
            if (safeSize < 0) {
                ERRORF(reporter, "getSafeSize64() negative: %s",
                       gColorTypeName[tstSafeSize.colorType()]);
            }
            bool sizeFail = false;
            // Compare against hand-computed values.
            switch (gPairs[i].fColorType) {
                case kUnknown_SkColorType:
                    break;

                case kAlpha_8_SkColorType:
                case kIndex_8_SkColorType:
                    if (safeSize != 0x2386F26FC10000LL) {
                        sizeFail = true;
                    }
                    break;

                case kRGB_565_SkColorType:
                case kARGB_4444_SkColorType:
                    if (safeSize != 0x470DE4DF820000LL) {
                        sizeFail = true;
                    }
                    break;

                case kN32_SkColorType:
                    if (safeSize != 0x8E1BC9BF040000LL) {
                        sizeFail = true;
                    }
                    break;

                default:
                    break;
            }
            if (sizeFail) {
                ERRORF(reporter, "computeSafeSize64() wrong size: %s",
                       gColorTypeName[tstSafeSize.colorType()]);
            }

            int subW = 2;
            int subH = 2;

            // Create bitmap to act as source for copies and subsets.
            SkBitmap src, subset;
            SkColorTable* ct = nullptr;
            if (kIndex_8_SkColorType == src.colorType()) {
                ct = init_ctable();
            }

            int localSubW;
            if (isExtracted[copyCase]) { // A larger image to extract from.
                localSubW = 2 * subW + 1;
            } else { // Tests expect a 2x2 bitmap, so make smaller.
                localSubW = subW;
            }
            // could fail if we pass kIndex_8 for the colortype
            if (src.tryAllocPixels(SkImageInfo::Make(localSubW, subH, gPairs[i].fColorType,
                                                     kPremul_SkAlphaType))) {
                // failure is fine, as we will notice later on
            }
            SkSafeUnref(ct);

            // Either copy src or extract into 'subset', which is used
            // for subsequent calls to copyPixelsTo/From.
            bool srcReady = false;
            // Test relies on older behavior that extractSubset will fail on
            // kUnknown_SkColorType
            if (kUnknown_SkColorType != src.colorType() &&
                isExtracted[copyCase]) {
                // 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

                srcReady = src.extractSubset(&subset, r);
            } else {
                srcReady = src.copyTo(&subset);
            }

            // Not all configurations will generate a valid 'subset'.
            if (srcReady) {

                // Allocate our target buffer 'buf' for all copies.
                // To simplify verifying correctness of copies attach
                // buf to a SkBitmap, but copies are done using the
                // raw buffer pointer.
                const size_t bufSize = subH *
                    SkColorTypeMinRowBytes(src.colorType(), subW) * 2;
                SkAutoTMalloc<uint8_t> autoBuf (bufSize);
                uint8_t* buf = autoBuf.get();

                SkBitmap bufBm; // Attach buf to this bitmap.
                bool successExpected;

                // Set up values for each pixel being copied.
                Coordinates coords(subW * subH);
                for (int x = 0; x < subW; ++x)
                    for (int y = 0; y < subH; ++y)
                    {
                        int index = y * subW + x;
                        SkASSERT(index < coords.length);
                        coords[index]->fX = x;
                        coords[index]->fY = y;
                    }

                writeCoordPixels(subset, coords);

                // Test #1 ////////////////////////////////////////////

                const SkImageInfo info = SkImageInfo::Make(subW, subH,
                                                           gPairs[i].fColorType,
                                                           kPremul_SkAlphaType);
                // Before/after comparisons easier if we attach buf
                // to an appropriately configured SkBitmap.
                memset(buf, 0xFF, bufSize);
                // Config with stride greater than src but that fits in buf.
                bufBm.installPixels(info, buf, info.minRowBytes() * 2);
                successExpected = false;
                // Then attempt to copy with a stride that is too large
                // to fit in the buffer.
                REPORTER_ASSERT(reporter,
                    subset.copyPixelsTo(buf, bufSize, bufBm.rowBytes() * 3)
                    == successExpected);

                if (successExpected)
                    reportCopyVerification(subset, bufBm, coords,
                        "copyPixelsTo(buf, bufSize, 1.5*maxRowBytes)",
                        reporter);

                // Test #2 ////////////////////////////////////////////
                // This test should always succeed, but in the case
                // of extracted bitmaps only because we handle the
                // issue of getSafeSize(). Without getSafeSize()
                // buffer overrun/read would occur.
                memset(buf, 0xFF, bufSize);
                bufBm.installPixels(info, buf, subset.rowBytes());
                successExpected = subset.getSafeSize() <= bufSize;
                REPORTER_ASSERT(reporter,
                    subset.copyPixelsTo(buf, bufSize) ==
                        successExpected);
                if (successExpected)
                    reportCopyVerification(subset, bufBm, coords,
                    "copyPixelsTo(buf, bufSize)", reporter);

                // Test #3 ////////////////////////////////////////////
                // Copy with different stride between src and dst.
                memset(buf, 0xFF, bufSize);
                bufBm.installPixels(info, buf, subset.rowBytes()+1);
                successExpected = true; // Should always work.
                REPORTER_ASSERT(reporter,
                        subset.copyPixelsTo(buf, bufSize,
                            subset.rowBytes()+1) == successExpected);
                if (successExpected)
                    reportCopyVerification(subset, bufBm, coords,
                    "copyPixelsTo(buf, bufSize, rowBytes+1)", reporter);

                // Test #4 ////////////////////////////////////////////
                // Test copy with stride too small.
                memset(buf, 0xFF, bufSize);
                bufBm.installPixels(info, buf, info.minRowBytes());
                successExpected = false;
                // Request copy with stride too small.
                REPORTER_ASSERT(reporter,
                    subset.copyPixelsTo(buf, bufSize, bufBm.rowBytes()-1)
                        == successExpected);
                if (successExpected)
                    reportCopyVerification(subset, bufBm, coords,
                    "copyPixelsTo(buf, bufSize, rowBytes()-1)", reporter);

#if 0   // copyPixelsFrom is gone
                // Test #5 ////////////////////////////////////////////
                // Tests the case where the source stride is too small
                // for the source configuration.
                memset(buf, 0xFF, bufSize);
                bufBm.installPixels(info, buf, info.minRowBytes());
                writeCoordPixels(bufBm, coords);
                REPORTER_ASSERT(reporter,
                    subset.copyPixelsFrom(buf, bufSize, 1) == false);

                // Test #6 ///////////////////////////////////////////
                // Tests basic copy from an external buffer to the bitmap.
                // If the bitmap is "extracted", this also tests the case
                // where the source stride is different from the dest.
                // stride.
                // We've made the buffer large enough to always succeed.
                bufBm.installPixels(info, buf, info.minRowBytes());
                writeCoordPixels(bufBm, coords);
                REPORTER_ASSERT(reporter,
                    subset.copyPixelsFrom(buf, bufSize, bufBm.rowBytes()) ==
                        true);
                reportCopyVerification(bufBm, subset, coords,
                    "copyPixelsFrom(buf, bufSize)",
                    reporter);

                // Test #7 ////////////////////////////////////////////
                // Tests the case where the source buffer is too small
                // for the transfer.
                REPORTER_ASSERT(reporter,
                    subset.copyPixelsFrom(buf, 1, subset.rowBytes()) ==
                        false);

#endif
            }
        } // for (size_t copyCase ...
    }
}