예제 #1
0
static double quadAngle(skiatest::Reporter* reporter, const SkDQuad& quad, double t) {
    const SkDVector& pt = quad.ptAtT(t) - quad[0];
    double angle = (atan2(pt.fY, pt.fX) + SK_ScalarPI) * 8 / (SK_ScalarPI * 2);
    REPORTER_ASSERT(reporter, angle >= 0 && angle <= 8);
    return angle;
}
예제 #2
0
static bool bruteMinT(skiatest::Reporter* reporter, const SkDQuad& quad1, const SkDQuad& quad2,
        TRange* lowerRange, TRange* upperRange) {
    double maxRadius = SkTMin(maxDist(quad1), maxDist(quad2));
    double maxQuads = SkTMax(maxQuad(quad1), maxQuad(quad2));
    double r = maxRadius / 2;
    double rStep = r / 2;
    SkDPoint best1 = {SK_ScalarInfinity, SK_ScalarInfinity};
    SkDPoint best2 = {SK_ScalarInfinity, SK_ScalarInfinity};
    int bestCCW = -1;
    double bestR = maxRadius;
    upperRange->tMin = 0;
    lowerRange->tMin = 1;
    do {
        do {  // find upper bounds of single result
            TRange tRange;
            bool stepUp = orderTRange(reporter, quad1, quad2, r, &tRange);
            if (stepUp) {
                SkDPoint pt1 = quad1.ptAtT(tRange.t1);
                if (equalPoints(pt1, best1, maxQuads)) {
                    break;
                }
                best1 = pt1;
                SkDPoint pt2 = quad2.ptAtT(tRange.t2);
                if (equalPoints(pt2, best2, maxQuads)) {
                    break;
                }
                best2 = pt2;
                if (gPathOpsAngleIdeasVerbose) {
                    SkDebugf("u bestCCW=%d ccw=%d bestMin=%1.9g:%1.9g r=%1.9g tMin=%1.9g\n",
                            bestCCW, tRange.ccw, lowerRange->tMin, upperRange->tMin, r,
                            tRange.tMin);
                }
                if (bestCCW >= 0 && bestCCW != (int) tRange.ccw) {
                    if (tRange.tMin < upperRange->tMin) {
                        upperRange->tMin = 0;
                    } else {
                        stepUp = false;
                    }
                }
                if (upperRange->tMin < tRange.tMin) {
                    bestCCW = tRange.ccw;
                    bestR = r;
                    *upperRange = tRange;
                }
                if (lowerRange->tMin > tRange.tMin) {
                    *lowerRange = tRange;
                }
            }
            r += stepUp ? rStep : -rStep;
            rStep /= 2;
        } while (rStep > FLT_EPSILON);
        if (bestCCW < 0) {
            REPORTER_ASSERT(reporter, bestR < maxRadius);
            return false;
        }
        double lastHighR = bestR;
        r = bestR / 2;
        rStep = r / 2;
        do {  // find lower bounds of single result
            TRange tRange;
            bool success = orderTRange(reporter, quad1, quad2, r, &tRange);
            if (success) {
                if (gPathOpsAngleIdeasVerbose) {
                    SkDebugf("l bestCCW=%d ccw=%d bestMin=%1.9g:%1.9g r=%1.9g tMin=%1.9g\n",
                            bestCCW, tRange.ccw, lowerRange->tMin, upperRange->tMin, r,
                            tRange.tMin);
                }
                if (bestCCW != (int) tRange.ccw || upperRange->tMin < tRange.tMin) {
                    bestCCW = tRange.ccw;
                    *upperRange = tRange;
                    bestR = lastHighR;
                    break;  // need to establish a new upper bounds
                }
                SkDPoint pt1 = quad1.ptAtT(tRange.t1);
                SkDPoint pt2 = quad2.ptAtT(tRange.t2);
                if (equalPoints(pt1, best1, maxQuads)) {
                    goto breakOut;
                }
                best1 = pt1;
                if (equalPoints(pt2, best2, maxQuads)) {
                    goto breakOut;
                }
                best2 = pt2;
                if (equalPoints(pt1, pt2, maxQuads)) {
                    success = false;
                } else {
                    if (upperRange->tMin < tRange.tMin) {
                        *upperRange = tRange;
                    }
                    if (lowerRange->tMin > tRange.tMin) {
                        *lowerRange = tRange;
                    }
                }
                lastHighR = SkTMin(r, lastHighR);
            }
            r += success ? -rStep : rStep;
            rStep /= 2;
        } while (rStep > FLT_EPSILON);
    } while (rStep > FLT_EPSILON);
breakOut:
    if (gPathOpsAngleIdeasVerbose) {
        SkDebugf("l a2-a1==%1.9g\n", lowerRange->a2 - lowerRange->a1);
    }
    return true;
}
예제 #3
0
static void TestDeferredCanvasBitmapCaching(skiatest::Reporter* reporter) {
    SkBitmap store;
    store.setConfig(SkBitmap::kARGB_8888_Config, 100, 100);
    store.allocPixels();
    SkDevice device(store);
    NotificationCounter notificationCounter;
    SkDeferredCanvas canvas(&device);
    canvas.setNotificationClient(&notificationCounter);

    const int imageCount = 2;
    SkBitmap sourceImages[imageCount];
    for (int i = 0; i < imageCount; i++)
    {
        sourceImages[i].setConfig(SkBitmap::kARGB_8888_Config, 100, 100);
        sourceImages[i].allocPixels();
    }

    size_t bitmapSize = sourceImages[0].getSize();

    canvas.drawBitmap(sourceImages[0], 0, 0, NULL);
    REPORTER_ASSERT(reporter, 1 == notificationCounter.fStorageAllocatedChangedCount);
    // stored bitmap + drawBitmap command
    REPORTER_ASSERT(reporter, canvas.storageAllocatedForRecording() > bitmapSize);

    // verify that nothing can be freed at this point
    REPORTER_ASSERT(reporter, 0 == canvas.freeMemoryIfPossible(~0U));

    // verify that flush leaves image in cache
    REPORTER_ASSERT(reporter, 0 == notificationCounter.fFlushedDrawCommandsCount);
    REPORTER_ASSERT(reporter, 0 == notificationCounter.fPrepareForDrawCount);
    canvas.flush();
    REPORTER_ASSERT(reporter, 1 == notificationCounter.fFlushedDrawCommandsCount);
    REPORTER_ASSERT(reporter, 1 == notificationCounter.fPrepareForDrawCount);
    REPORTER_ASSERT(reporter, canvas.storageAllocatedForRecording() >= bitmapSize);

    // verify that after a flush, cached image can be freed
    REPORTER_ASSERT(reporter, canvas.freeMemoryIfPossible(~0U) >= bitmapSize);

    // Verify that caching works for avoiding multiple copies of the same bitmap
    canvas.drawBitmap(sourceImages[0], 0, 0, NULL);
    REPORTER_ASSERT(reporter, 2 == notificationCounter.fStorageAllocatedChangedCount);
    canvas.drawBitmap(sourceImages[0], 0, 0, NULL);
    REPORTER_ASSERT(reporter, 2 == notificationCounter.fStorageAllocatedChangedCount);
    REPORTER_ASSERT(reporter, 1 == notificationCounter.fFlushedDrawCommandsCount);
    REPORTER_ASSERT(reporter, canvas.storageAllocatedForRecording() < 2 * bitmapSize);

    // Verify partial eviction based on bytesToFree
    canvas.drawBitmap(sourceImages[1], 0, 0, NULL);
    REPORTER_ASSERT(reporter, 1 == notificationCounter.fFlushedDrawCommandsCount);
    canvas.flush();
    REPORTER_ASSERT(reporter, 2 == notificationCounter.fFlushedDrawCommandsCount);
    REPORTER_ASSERT(reporter, canvas.storageAllocatedForRecording() > 2 * bitmapSize);
    size_t bytesFreed = canvas.freeMemoryIfPossible(1);
    REPORTER_ASSERT(reporter, 2 == notificationCounter.fFlushedDrawCommandsCount);
    REPORTER_ASSERT(reporter,  bytesFreed >= bitmapSize);
    REPORTER_ASSERT(reporter,  bytesFreed < 2*bitmapSize);

    // Verifiy that partial purge works, image zero is in cache but not reffed by
    // a pending draw, while image 1 is locked-in.
    canvas.freeMemoryIfPossible(~0U);
    REPORTER_ASSERT(reporter, 2 == notificationCounter.fFlushedDrawCommandsCount);
    canvas.drawBitmap(sourceImages[0], 0, 0, NULL);
    canvas.flush();
    canvas.drawBitmap(sourceImages[1], 0, 0, NULL);
    bytesFreed = canvas.freeMemoryIfPossible(~0U);
    // only one bitmap should have been freed.
    REPORTER_ASSERT(reporter,  bytesFreed >= bitmapSize);
    REPORTER_ASSERT(reporter,  bytesFreed < 2*bitmapSize);
    // Clear for next test
    canvas.flush();
    canvas.freeMemoryIfPossible(~0U);
    REPORTER_ASSERT(reporter, canvas.storageAllocatedForRecording() < bitmapSize);

    // Verify the image cache is sensitive to genID bumps
    canvas.drawBitmap(sourceImages[1], 0, 0, NULL);
    sourceImages[1].notifyPixelsChanged();
    canvas.drawBitmap(sourceImages[1], 0, 0, NULL);
    REPORTER_ASSERT(reporter, canvas.storageAllocatedForRecording() > 2*bitmapSize);

    // Verify that nothing in this test caused commands to be skipped
    REPORTER_ASSERT(reporter, 0 == notificationCounter.fSkippedPendingDrawCommandsCount);
}
예제 #4
0
static void TestDeferredCanvasFreshFrame(skiatest::Reporter* reporter) {
    SkBitmap store;
    SkRect fullRect;
    fullRect.setXYWH(SkIntToScalar(0), SkIntToScalar(0), SkIntToScalar(gWidth),
        SkIntToScalar(gHeight));
    SkRect partialRect;
    partialRect.setXYWH(SkIntToScalar(0), SkIntToScalar(0),
        SkIntToScalar(1), SkIntToScalar(1));
    create(&store, SkBitmap::kARGB_8888_Config, 0xFFFFFFFF);
    SkDevice device(store);
    SkDeferredCanvas canvas(&device);

    // verify that frame is intially fresh
    REPORTER_ASSERT(reporter, canvas.isFreshFrame());
    // no clearing op since last call to isFreshFrame -> not fresh
    REPORTER_ASSERT(reporter, !canvas.isFreshFrame());

    // Verify that clear triggers a fresh frame
    canvas.clear(0x00000000);
    REPORTER_ASSERT(reporter, canvas.isFreshFrame());

    // Verify that clear with saved state triggers a fresh frame
    canvas.save(SkCanvas::kMatrixClip_SaveFlag);
    canvas.clear(0x00000000);
    canvas.restore();
    REPORTER_ASSERT(reporter, canvas.isFreshFrame());

    // Verify that clear within a layer does NOT trigger a fresh frame
    canvas.saveLayer(NULL, NULL, SkCanvas::kARGB_ClipLayer_SaveFlag);
    canvas.clear(0x00000000);
    canvas.restore();
    REPORTER_ASSERT(reporter, !canvas.isFreshFrame());

    // Verify that a clear with clipping triggers a fresh frame
    // (clear is not affected by clipping)
    canvas.save(SkCanvas::kMatrixClip_SaveFlag);
    canvas.clipRect(partialRect, SkRegion::kIntersect_Op, false);
    canvas.clear(0x00000000);
    canvas.restore();
    REPORTER_ASSERT(reporter, canvas.isFreshFrame());

    // Verify that full frame rects with different forms of opaque paint
    // trigger frames to be marked as fresh
    {
        SkPaint paint;
        paint.setStyle( SkPaint::kFill_Style );
        paint.setAlpha( 255 );
        canvas.drawRect(fullRect, paint);
        REPORTER_ASSERT(reporter, canvas.isFreshFrame());
    }
    {
        SkPaint paint;
        paint.setStyle( SkPaint::kFill_Style );
        paint.setAlpha( 255 );
        paint.setXfermodeMode(SkXfermode::kSrcIn_Mode);
        canvas.drawRect(fullRect, paint);
        REPORTER_ASSERT(reporter, !canvas.isFreshFrame());
    }
    {
        SkPaint paint;
        paint.setStyle( SkPaint::kFill_Style );
        SkBitmap bmp;
        create(&bmp, SkBitmap::kARGB_8888_Config, 0xFFFFFFFF);
        bmp.setIsOpaque(true);
        SkShader* shader = SkShader::CreateBitmapShader(bmp,
            SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);
        paint.setShader(shader)->unref();
        canvas.drawRect(fullRect, paint);
        REPORTER_ASSERT(reporter, canvas.isFreshFrame());
    }

    // Verify that full frame rects with different forms of non-opaque paint
    // do not trigger frames to be marked as fresh
    {
        SkPaint paint;
        paint.setStyle( SkPaint::kFill_Style );
        paint.setAlpha( 254 );
        canvas.drawRect(fullRect, paint);
        REPORTER_ASSERT(reporter, !canvas.isFreshFrame());
    }
    {
        SkPaint paint;
        paint.setStyle( SkPaint::kFill_Style );
        SkBitmap bmp;
        create(&bmp, SkBitmap::kARGB_8888_Config, 0xFFFFFFFF);
        bmp.setIsOpaque(false);
        SkShader* shader = SkShader::CreateBitmapShader(bmp,
            SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);
        paint.setShader(shader)->unref();
        canvas.drawRect(fullRect, paint);
        REPORTER_ASSERT(reporter, !canvas.isFreshFrame());
    }

    // Verify that incomplete coverage does not trigger a fresh frame
    {
        SkPaint paint;
        paint.setStyle(SkPaint::kFill_Style);
        paint.setAlpha(255);
        canvas.drawRect(partialRect, paint);
        REPORTER_ASSERT(reporter, !canvas.isFreshFrame());
    }

    // Verify that incomplete coverage due to clipping does not trigger a fresh
    // frame
    {
        canvas.save(SkCanvas::kMatrixClip_SaveFlag);
        canvas.clipRect(partialRect, SkRegion::kIntersect_Op, false);
        SkPaint paint;
        paint.setStyle(SkPaint::kFill_Style);
        paint.setAlpha(255);
        canvas.drawRect(fullRect, paint);
        canvas.restore();
        REPORTER_ASSERT(reporter, !canvas.isFreshFrame());
    }
    {
        canvas.save(SkCanvas::kMatrixClip_SaveFlag);
        SkPaint paint;
        paint.setStyle( SkPaint::kFill_Style );
        paint.setAlpha( 255 );
        SkPath path;
        path.addCircle(SkIntToScalar(0), SkIntToScalar(0), SkIntToScalar(2));
        canvas.clipPath(path, SkRegion::kIntersect_Op, false);
        canvas.drawRect(fullRect, paint);
        canvas.restore();
        REPORTER_ASSERT(reporter, !canvas.isFreshFrame());
    }

    // Verify that stroked rect does not trigger a fresh frame
    {
        SkPaint paint;
        paint.setStyle( SkPaint::kStroke_Style );
        paint.setAlpha( 255 );
        canvas.drawRect(fullRect, paint);
        REPORTER_ASSERT(reporter, !canvas.isFreshFrame());
    }

    // Verify kSrcMode triggers a fresh frame even with transparent color
    {
        SkPaint paint;
        paint.setStyle( SkPaint::kFill_Style );
        paint.setAlpha( 100 );
        paint.setXfermodeMode(SkXfermode::kSrc_Mode);
        canvas.drawRect(fullRect, paint);
        REPORTER_ASSERT(reporter, canvas.isFreshFrame());
    }
}
예제 #5
0
 ~TestAnnotationCanvas() {
     REPORTER_ASSERT(fReporter, fCount == fCurrIndex);
 }
static void test_treatAsSprite(skiatest::Reporter* reporter) {
    const unsigned bilerBits = kSkSubPixelBitsForBilerp;

    SkMatrix mat;
    SkISize  size;
    SkRandom rand;

    // assert: translate-only no-filter can always be treated as sprite
    for (int i = 0; i < 1000; ++i) {
        rand_matrix(&mat, rand, SkMatrix::kTranslate_Mask);
        for (int j = 0; j < 1000; ++j) {
            rand_size(&size, rand);
            REPORTER_ASSERT(reporter, treat_as_sprite(mat, size, 0));
        }
    }

    // assert: rotate/perspect is never treated as sprite
    for (int i = 0; i < 1000; ++i) {
        rand_matrix(&mat, rand, SkMatrix::kAffine_Mask | SkMatrix::kPerspective_Mask);
        for (int j = 0; j < 1000; ++j) {
            rand_size(&size, rand);
            REPORTER_ASSERT(reporter, !treat_as_sprite(mat, size, 0));
            REPORTER_ASSERT(reporter, !treat_as_sprite(mat, size, bilerBits));
        }
    }

    size.set(500, 600);

    const SkScalar tooMuchSubpixel = 100.1f;
    mat.setTranslate(tooMuchSubpixel, 0);
    REPORTER_ASSERT(reporter, !treat_as_sprite(mat, size, bilerBits));
    mat.setTranslate(0, tooMuchSubpixel);
    REPORTER_ASSERT(reporter, !treat_as_sprite(mat, size, bilerBits));

    const SkScalar tinySubPixel = 100.02f;
    mat.setTranslate(tinySubPixel, 0);
    REPORTER_ASSERT(reporter, treat_as_sprite(mat, size, bilerBits));
    mat.setTranslate(0, tinySubPixel);
    REPORTER_ASSERT(reporter, treat_as_sprite(mat, size, bilerBits));

    const SkScalar twoThirds = SK_Scalar1 * 2 / 3;
    const SkScalar bigScale = (size.width() + twoThirds) / size.width();
    mat.setScale(bigScale, bigScale);
    REPORTER_ASSERT(reporter, !treat_as_sprite(mat, size, false));
    REPORTER_ASSERT(reporter, !treat_as_sprite(mat, size, bilerBits));

    const SkScalar oneThird = SK_Scalar1 / 3;
    const SkScalar smallScale = (size.width() + oneThird) / size.width();
    mat.setScale(smallScale, smallScale);
    REPORTER_ASSERT(reporter, treat_as_sprite(mat, size, false));
    REPORTER_ASSERT(reporter, !treat_as_sprite(mat, size, bilerBits));

    const SkScalar oneFortyth = SK_Scalar1 / 40;
    const SkScalar tinyScale = (size.width() + oneFortyth) / size.width();
    mat.setScale(tinyScale, tinyScale);
    REPORTER_ASSERT(reporter, treat_as_sprite(mat, size, false));
    REPORTER_ASSERT(reporter, treat_as_sprite(mat, size, bilerBits));
}
예제 #7
0
static void TestWStream(skiatest::Reporter* reporter) {
    SkDynamicMemoryWStream  ds;
    const char s[] = "abcdefghijklmnopqrstuvwxyz";
    int i;
    for (i = 0; i < 100; i++) {
        REPORTER_ASSERT(reporter, ds.write(s, 26));
    }
    REPORTER_ASSERT(reporter, ds.getOffset() == 100 * 26);

    char* dst = new char[100 * 26 + 1];
    dst[100*26] = '*';
    ds.copyTo(dst);
    REPORTER_ASSERT(reporter, dst[100*26] == '*');
    for (i = 0; i < 100; i++) {
        REPORTER_ASSERT(reporter, memcmp(&dst[i * 26], s, 26) == 0);
    }

    {
        SkAutoTDelete<SkStreamAsset> stream(ds.detachAsStream());
        REPORTER_ASSERT(reporter, 100 * 26 == stream->getLength());
        REPORTER_ASSERT(reporter, ds.getOffset() == 0);
        test_loop_stream(reporter, stream.get(), s, 26, 100);

        SkAutoTDelete<SkStreamAsset> stream2(stream->duplicate());
        test_loop_stream(reporter, stream2.get(), s, 26, 100);

        SkAutoTDelete<SkStreamAsset> stream3(stream->fork());
        REPORTER_ASSERT(reporter, stream3->isAtEnd());
        char tmp;
        size_t bytes = stream->read(&tmp, 1);
        REPORTER_ASSERT(reporter, 0 == bytes);
        stream3->rewind();
        test_loop_stream(reporter, stream3.get(), s, 26, 100);
    }

    for (i = 0; i < 100; i++) {
        REPORTER_ASSERT(reporter, ds.write(s, 26));
    }
    REPORTER_ASSERT(reporter, ds.getOffset() == 100 * 26);

    {
        sk_sp<SkData> data(ds.copyToData());
        REPORTER_ASSERT(reporter, 100 * 26 == data->size());
        REPORTER_ASSERT(reporter, memcmp(dst, data->data(), data->size()) == 0);
    }

    {
        // Test that this works after a copyToData.
        SkAutoTDelete<SkStreamAsset> stream(ds.detachAsStream());
        REPORTER_ASSERT(reporter, ds.getOffset() == 0);
        test_loop_stream(reporter, stream.get(), s, 26, 100);

        SkAutoTDelete<SkStreamAsset> stream2(stream->duplicate());
        test_loop_stream(reporter, stream2.get(), s, 26, 100);
    }
    delete[] dst;

    SkString tmpDir = skiatest::GetTmpDir();
    if (!tmpDir.isEmpty()) {
        test_filestreams(reporter, tmpDir.c_str());
    }
}
예제 #8
0
DEF_TEST(Encode_WebpOptions, r) {
    SkBitmap bitmap;
    bool success = GetResourceAsBitmap("google_chrome.ico", &bitmap);
    if (!success) {
        return;
    }

    SkPixmap src;
    success = bitmap.peekPixels(&src);
    REPORTER_ASSERT(r, success);
    if (!success) {
        return;
    }

    SkDynamicMemoryWStream dst0, dst1, dst2, dst3;
    SkWebpEncoder::Options options;
    options.fCompression = SkWebpEncoder::Compression::kLossless;
    options.fQuality = 0.0f;
    success = SkWebpEncoder::Encode(&dst0, src, options);
    REPORTER_ASSERT(r, success);

    options.fQuality = 100.0f;
    success = SkWebpEncoder::Encode(&dst1, src, options);
    REPORTER_ASSERT(r, success);

    options.fCompression = SkWebpEncoder::Compression::kLossy;
    options.fQuality = 100.0f;
    success = SkWebpEncoder::Encode(&dst2, src, options);
    REPORTER_ASSERT(r, success);

    options.fCompression = SkWebpEncoder::Compression::kLossy;
    options.fQuality = 50.0f;
    success = SkWebpEncoder::Encode(&dst3, src, options);
    REPORTER_ASSERT(r, success);

    sk_sp<SkData> data0 = dst0.detachAsData();
    sk_sp<SkData> data1 = dst1.detachAsData();
    sk_sp<SkData> data2 = dst2.detachAsData();
    sk_sp<SkData> data3 = dst3.detachAsData();
    REPORTER_ASSERT(r, data0->size() > data1->size());
    REPORTER_ASSERT(r, data1->size() > data2->size());
    REPORTER_ASSERT(r, data2->size() > data3->size());

    SkBitmap bm0, bm1, bm2, bm3;
    SkImage::MakeFromEncoded(data0)->asLegacyBitmap(&bm0, SkImage::kRO_LegacyBitmapMode);
    SkImage::MakeFromEncoded(data1)->asLegacyBitmap(&bm1, SkImage::kRO_LegacyBitmapMode);
    SkImage::MakeFromEncoded(data2)->asLegacyBitmap(&bm2, SkImage::kRO_LegacyBitmapMode);
    SkImage::MakeFromEncoded(data3)->asLegacyBitmap(&bm3, SkImage::kRO_LegacyBitmapMode);
    REPORTER_ASSERT(r, almost_equals(bm0, bm1, 0));
    REPORTER_ASSERT(r, almost_equals(bm0, bm2, 90));
    REPORTER_ASSERT(r, almost_equals(bm2, bm3, 45));
}
예제 #9
0
static void test_fully_peekable_stream(skiatest::Reporter* r, SkStream* stream, size_t limit) {
    for (size_t i = 1; !stream->isAtEnd(); i++) {
        REPORTER_ASSERT(r, compare_peek_to_read(r, stream, i) == 0);
    }
}
예제 #10
0
DEF_TEST(StreamEmptyStreamMemoryBase, r) {
    SkDynamicMemoryWStream tmp;
    SkAutoTDelete<SkStreamAsset> asset(tmp.detachAsStream());
    REPORTER_ASSERT(r, nullptr == asset->getMemoryBase());
}
예제 #11
0
static void testTightBoundsQuads(PathOpsThreadState* data) {
    SkRandom ran;
    const int bitWidth = 32;
    const int bitHeight = 32;
    const float pathMin = 1;
    const float pathMax = (float) (bitHeight - 2);
    SkBitmap& bits = *data->fBitmap;
    if (bits.width() == 0) {
        bits.allocN32Pixels(bitWidth, bitHeight);
    }
    SkCanvas canvas(bits);
    SkPaint paint;
    for (int index = 0; index < 100; ++index) {
        SkPath path;
        int contourCount = ran.nextRangeU(1, 10);
        for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
            int lineCount = ran.nextRangeU(1, 10);
            path.moveTo(ran.nextRangeF(1, pathMax), ran.nextRangeF(pathMin, pathMax));
            for (int lIndex = 0; lIndex < lineCount; ++lIndex) {
                if (ran.nextBool()) {
                    path.lineTo(ran.nextRangeF(pathMin, pathMax), ran.nextRangeF(pathMin, pathMax));
                } else {
                    path.quadTo(ran.nextRangeF(pathMin, pathMax), ran.nextRangeF(pathMin, pathMax),
                            ran.nextRangeF(pathMin, pathMax), ran.nextRangeF(pathMin, pathMax));
                }
            }
            if (ran.nextBool()) {
                path.close();
            }
        }
        SkRect classicBounds = path.getBounds();
        SkRect tightBounds;
        REPORTER_ASSERT(data->fReporter, TightBounds(path, &tightBounds));
        REPORTER_ASSERT(data->fReporter, classicBounds.contains(tightBounds));
        canvas.drawColor(SK_ColorWHITE);
        canvas.drawPath(path, paint);
        SkIRect bitsWritten = {31, 31, 0, 0};
        for (int y = 0; y < bitHeight; ++y) {
            uint32_t* addr1 = data->fBitmap->getAddr32(0, y);
            bool lineWritten = false;
            for (int x = 0; x < bitWidth; ++x) {
                if (addr1[x] == (uint32_t) -1) {
                    continue;
                }
                lineWritten = true;
                bitsWritten.fLeft = SkTMin(bitsWritten.fLeft, x);
                bitsWritten.fRight = SkTMax(bitsWritten.fRight, x);
            }
            if (!lineWritten) {
                continue;
            }
            bitsWritten.fTop = SkTMin(bitsWritten.fTop, y);
            bitsWritten.fBottom = SkTMax(bitsWritten.fBottom, y);
        }
        if (!bitsWritten.isEmpty()) {
            SkIRect tightOut;
            tightBounds.roundOut(&tightOut);
            REPORTER_ASSERT(data->fReporter, tightOut.contains(bitsWritten));
        }
    }
}
예제 #12
0
static void assert_data(skiatest::Reporter* reporter, SkData* ref,
                        const void* data, size_t len) {
    REPORTER_ASSERT(reporter, ref->size() == len);
    REPORTER_ASSERT(reporter, !memcmp(ref->data(), data, len));
}
예제 #13
0
static void assert_len(skiatest::Reporter* reporter, SkData* ref, size_t len) {
    REPORTER_ASSERT(reporter, ref->size() == len);
}
예제 #14
0
static void testQuadAngles(skiatest::Reporter* reporter, const SkDQuad& quad1, const SkDQuad& quad2,
        int testNo) {
    SkPoint shortQuads[2][3];
    SkOpSegment seg[2];
    makeSegment(quad1, shortQuads[0], &seg[0]);
    makeSegment(quad2, shortQuads[1], &seg[1]);
    int realOverlap = PathOpsAngleTester::ConvexHullOverlaps(seg[0].angle(0), seg[1].angle(0));
    const SkDPoint& origin = quad1[0];
    REPORTER_ASSERT(reporter, origin == quad2[0]);
    double a1s = atan2(origin.fY - quad1[1].fY, quad1[1].fX - origin.fX);
    double a1e = atan2(origin.fY - quad1[2].fY, quad1[2].fX - origin.fX);
    double a2s = atan2(origin.fY - quad2[1].fY, quad2[1].fX - origin.fX);
    double a2e = atan2(origin.fY - quad2[2].fY, quad2[2].fX - origin.fX);
    bool oldSchoolOverlap = radianBetween(a1s, a2s, a1e)
        || radianBetween(a1s, a2e, a1e) || radianBetween(a2s, a1s, a2e)
        || radianBetween(a2s, a1e, a2e);
    int overlap = quadHullsOverlap(reporter, quad1, quad2);
    bool realMatchesOverlap = realOverlap == overlap || SK_ScalarPI - fabs(a2s - a1s) < 0.002;
    if (realOverlap != overlap) {
        SkDebugf("\nSK_ScalarPI - fabs(a2s - a1s) = %1.9g\n", SK_ScalarPI - fabs(a2s - a1s));
    }
    if (!realMatchesOverlap) {
        DumpQ(quad1, quad2, testNo);
    }
    REPORTER_ASSERT(reporter, realMatchesOverlap);
    if (oldSchoolOverlap != (overlap < 0)) {
        overlap = quadHullsOverlap(reporter, quad1, quad2);  // set a breakpoint and debug if assert fires
        REPORTER_ASSERT(reporter, oldSchoolOverlap == (overlap < 0));
    }
    SkDVector v1s = quad1[1] - quad1[0];
    SkDVector v1e = quad1[2] - quad1[0];
    SkDVector v2s = quad2[1] - quad2[0];
    SkDVector v2e = quad2[2] - quad2[0];
    double vDir[2] = { v1s.cross(v1e), v2s.cross(v2e) };
    bool ray1In2 = v1s.cross(v2s) * vDir[1] <= 0 && v1s.cross(v2e) * vDir[1] >= 0;
    bool ray2In1 = v2s.cross(v1s) * vDir[0] <= 0 && v2s.cross(v1e) * vDir[0] >= 0;
    if (overlap >= 0) {
        // verify that hulls really don't overlap
        REPORTER_ASSERT(reporter, !ray1In2);
        REPORTER_ASSERT(reporter, !ray2In1);
        bool ctrl1In2 = v1e.cross(v2s) * vDir[1] <= 0 && v1e.cross(v2e) * vDir[1] >= 0;
        REPORTER_ASSERT(reporter, !ctrl1In2);
        bool ctrl2In1 = v2e.cross(v1s) * vDir[0] <= 0 && v2e.cross(v1e) * vDir[0] >= 0;
        REPORTER_ASSERT(reporter, !ctrl2In1);
        // check answer against reference
        bruteForce(reporter, quad1, quad2, overlap > 0);
    }
    // continue end point rays and see if they intersect the opposite curve
    SkDLine rays[] = {{{origin, quad2[2]}}, {{origin, quad1[2]}}};
    const SkDQuad* quads[] = {&quad1, &quad2};
    SkDVector midSpokes[2];
    SkIntersections intersect[2];
    double minX, minY, maxX, maxY;
    minX = minY = SK_ScalarInfinity;
    maxX = maxY = -SK_ScalarInfinity;
    double maxWidth = 0;
    bool useIntersect = false;
    double smallestTs[] = {1, 1};
    for (unsigned index = 0; index < SK_ARRAY_COUNT(quads); ++index) {
        const SkDQuad& q = *quads[index];
        midSpokes[index] = q.ptAtT(0.5) - origin;
        minX = SkTMin(SkTMin(SkTMin(minX, origin.fX), q[1].fX), q[2].fX);
        minY = SkTMin(SkTMin(SkTMin(minY, origin.fY), q[1].fY), q[2].fY);
        maxX = SkTMax(SkTMax(SkTMax(maxX, origin.fX), q[1].fX), q[2].fX);
        maxY = SkTMax(SkTMax(SkTMax(maxY, origin.fY), q[1].fY), q[2].fY);
        maxWidth = SkTMax(maxWidth, SkTMax(maxX - minX, maxY - minY));
        intersect[index].intersectRay(q, rays[index]);
        const SkIntersections& i = intersect[index];
        REPORTER_ASSERT(reporter, i.used() >= 1);
        bool foundZero = false;
        double smallT = 1;
        for (int idx2 = 0; idx2 < i.used(); ++idx2) {
            double t = i[0][idx2];
            if (t == 0) {
                foundZero = true;
                continue;
            }
            if (smallT > t) {
                smallT = t;
            }
        }
        REPORTER_ASSERT(reporter, foundZero == true);
        if (smallT == 1) {
            continue;
        }
        SkDVector ray = q.ptAtT(smallT) - origin;
        SkDVector end = rays[index][1] - origin;
        if (ray.fX * end.fX < 0 || ray.fY * end.fY < 0) {
            continue;
        }
        double rayDist = ray.length();
        double endDist = end.length();
        double delta = fabs(rayDist - endDist) / maxWidth;
        if (delta > 1e-4) {
            useIntersect ^= true;
        }
        smallestTs[index] = smallT;
    }
    bool firstInside;
    if (useIntersect) {
        int sIndex = (int) (smallestTs[1] < 1);
        REPORTER_ASSERT(reporter, smallestTs[sIndex ^ 1] == 1);
        double t = smallestTs[sIndex];
        const SkDQuad& q = *quads[sIndex];
        SkDVector ray = q.ptAtT(t) - origin;
        SkDVector end = rays[sIndex][1] - origin;
        double rayDist = ray.length();
        double endDist = end.length();
        SkDVector mid = q.ptAtT(t / 2) - origin;
        double midXray = mid.crossCheck(ray);
        if (gPathOpsAngleIdeasVerbose) {
            SkDebugf("rayDist>endDist:%d sIndex==0:%d vDir[sIndex]<0:%d midXray<0:%d\n",
                    rayDist > endDist, sIndex == 0, vDir[sIndex] < 0, midXray < 0);
        }
        SkASSERT(SkScalarSignAsInt(SkDoubleToScalar(midXray))
            == SkScalarSignAsInt(SkDoubleToScalar(vDir[sIndex])));
        firstInside = (rayDist > endDist) ^ (sIndex == 0) ^ (vDir[sIndex] < 0);
    } else if (overlap >= 0) {
        return;  // answer has already been determined
    } else {
        firstInside = checkParallel(reporter, quad1, quad2);
    }
    if (overlap < 0) {
        SkDEBUGCODE(int realEnds =)
                PathOpsAngleTester::EndsIntersect(seg[0].angle(0), seg[1].angle(0));
        SkASSERT(realEnds == (firstInside ? 1 : 0));
    }
예제 #15
0
static void test_chunkalloc(skiatest::Reporter* reporter) {
    size_t min = 256;
    SkChunkAlloc alloc(min);

    REPORTER_ASSERT(reporter, 0 == alloc.totalCapacity());
    REPORTER_ASSERT(reporter, 0 == alloc.totalUsed());
    REPORTER_ASSERT(reporter, 0 == alloc.blockCount());
    REPORTER_ASSERT(reporter, !alloc.contains(NULL));
    REPORTER_ASSERT(reporter, !alloc.contains(reporter));

    alloc.reset();
    REPORTER_ASSERT(reporter, 0 == alloc.totalCapacity());
    REPORTER_ASSERT(reporter, 0 == alloc.totalUsed());
    REPORTER_ASSERT(reporter, 0 == alloc.blockCount());

    size_t size = min >> 1;
    void* ptr = alloc.allocThrow(size);
    REPORTER_ASSERT(reporter, alloc.totalCapacity() >= size);
    REPORTER_ASSERT(reporter, alloc.totalUsed() == size);
    REPORTER_ASSERT(reporter, alloc.blockCount() > 0);
    REPORTER_ASSERT(reporter, alloc.contains(ptr));

    alloc.reset();
    REPORTER_ASSERT(reporter, !alloc.contains(ptr));
    REPORTER_ASSERT(reporter, 0 == alloc.totalCapacity());
    REPORTER_ASSERT(reporter, 0 == alloc.totalUsed());
}
예제 #16
0
static void testPngComments(const SkPixmap& src, SkPngEncoder::Options& options,
        skiatest::Reporter* r) {
    std::vector<std::string> commentStrings;
    pushComment(commentStrings, "key", "text");
    pushComment(commentStrings, "test", "something");
    pushComment(commentStrings, "have some", "spaces in both");

    std::string longKey(PNG_KEYWORD_MAX_LENGTH, 'x');
#ifdef SK_DEBUG
    commentStrings.push_back(longKey);
#else
    // We call SkDEBUGFAILF it the key is too long so we'll only test this in release mode.
    commentStrings.push_back(longKey + "x");
#endif
    commentStrings.push_back("");

    std::vector<const char*> commentPointers;
    std::vector<size_t> commentSizes;
    for(auto& str : commentStrings) {
        commentPointers.push_back(str.c_str());
        commentSizes.push_back(str.length() + 1);
    }

    options.fComments = SkDataTable::MakeCopyArrays((void const *const *)commentPointers.data(),
            commentSizes.data(), commentStrings.size());


    SkDynamicMemoryWStream dst;
    bool success = SkPngEncoder::Encode(&dst, src, options);
    REPORTER_ASSERT(r, success);

    std::vector<char> output(dst.bytesWritten());
    dst.copyTo(output.data());

    // Each chunk is of the form length (4 bytes), chunk type (tEXt), data,
    // checksum (4 bytes).  Make sure we find all of them in the encoded
    // results.
    const char kExpected1[] =
        "\x00\x00\x00\x08tEXtkey\x00text\x9e\xe7\x66\x51";
    const char kExpected2[] =
        "\x00\x00\x00\x0etEXttest\x00something\x29\xba\xef\xac";
    const char kExpected3[] =
        "\x00\x00\x00\x18tEXthave some\x00spaces in both\x8d\x69\x34\x2d";
    std::string longKeyRecord = "tEXt" + longKey; // A snippet of our long key comment
    std::string tooLongRecord = "tExt" + longKey + "x"; // A snippet whose key is too long

    auto search1 = std::search(output.begin(), output.end(),
            kExpected1, kExpected1 + sizeof(kExpected1));
    auto search2 = std::search(output.begin(), output.end(),
            kExpected2, kExpected2 + sizeof(kExpected2));
    auto search3 = std::search(output.begin(), output.end(),
            kExpected3, kExpected3 + sizeof(kExpected3));
    auto search4 = std::search(output.begin(), output.end(),
            longKeyRecord.begin(), longKeyRecord.end());
    auto search5 = std::search(output.begin(), output.end(),
            tooLongRecord.begin(), tooLongRecord.end());

    REPORTER_ASSERT(r, search1 != output.end());
    REPORTER_ASSERT(r, search2 != output.end());
    REPORTER_ASSERT(r, search3 != output.end());
    REPORTER_ASSERT(r, search4 != output.end());
    REPORTER_ASSERT(r, search5 == output.end());
    // Comments test ends
}
예제 #17
0
DEF_TEST(Serialization, reporter) {
    // Test matrix serialization
    {
        SkMatrix matrix = SkMatrix::I();
        TestObjectSerialization(&matrix, reporter);
    }

    // Test path serialization
    {
        SkPath path;
        TestObjectSerialization(&path, reporter);
    }

    // Test region serialization
    {
        SkRegion region;
        TestObjectSerialization(&region, reporter);
    }

    // Test xfermode serialization
    {
        TestXfermodeSerialization(reporter);
    }

    // Test color filter serialization
    {
        TestColorFilterSerialization(reporter);
    }

    // Test string serialization
    {
        SkString string("string");
        TestObjectSerializationNoAlign<SkString, false>(&string, reporter);
        TestObjectSerializationNoAlign<SkString, true>(&string, reporter);
    }

    // Test rrect serialization
    {
        // SkRRect does not initialize anything.
        // An uninitialized SkRRect can be serialized,
        // but will branch on uninitialized data when deserialized.
        SkRRect rrect;
        SkRect rect = SkRect::MakeXYWH(1, 2, 20, 30);
        SkVector corners[4] = { {1, 2}, {2, 3}, {3,4}, {4,5} };
        rrect.setRectRadii(rect, corners);
        TestAlignment(&rrect, reporter);
    }

    // Test readByteArray
    {
        unsigned char data[kArraySize] = { 1, 2, 3 };
        TestArraySerialization(data, reporter);
    }

    // Test readColorArray
    {
        SkColor data[kArraySize] = { SK_ColorBLACK, SK_ColorWHITE, SK_ColorRED };
        TestArraySerialization(data, reporter);
    }

    // Test readIntArray
    {
        int32_t data[kArraySize] = { 1, 2, 4, 8 };
        TestArraySerialization(data, reporter);
    }

    // Test readPointArray
    {
        SkPoint data[kArraySize] = { {6, 7}, {42, 128} };
        TestArraySerialization(data, reporter);
    }

    // Test readScalarArray
    {
        SkScalar data[kArraySize] = { SK_Scalar1, SK_ScalarHalf, SK_ScalarMax };
        TestArraySerialization(data, reporter);
    }

    // Test invalid deserializations
    {
        SkImageInfo info = SkImageInfo::MakeN32Premul(kBitmapSize, kBitmapSize);

        SkBitmap validBitmap;
        validBitmap.setInfo(info);

        // Create a bitmap with a really large height
        SkBitmap invalidBitmap;
        invalidBitmap.setInfo(info.makeWH(info.width(), 1000000000));

        // The deserialization should succeed, and the rendering shouldn't crash,
        // even when the device fails to initialize, due to its size
        TestBitmapSerialization(validBitmap, invalidBitmap, true, reporter);
    }

    // Test simple SkPicture serialization
    {
        SkPictureRecorder recorder;
        draw_something(recorder.beginRecording(SkIntToScalar(kBitmapSize),
                                               SkIntToScalar(kBitmapSize),
                                               nullptr, 0));
        SkAutoTUnref<SkPicture> pict(recorder.endRecording());

        // Serialize picture
        SkWriteBuffer writer(SkWriteBuffer::kValidation_Flag);
        pict->flatten(writer);
        size_t size = writer.bytesWritten();
        SkAutoTMalloc<unsigned char> data(size);
        writer.writeToMemory(static_cast<void*>(data.get()));

        // Deserialize picture
        SkValidatingReadBuffer reader(static_cast<void*>(data.get()), size);
        SkAutoTUnref<SkPicture> readPict(
            SkPicture::CreateFromBuffer(reader));
        REPORTER_ASSERT(reporter, readPict.get());
    }

    TestPictureTypefaceSerialization(reporter);
}
예제 #18
0
static void test_ptrs(skiatest::Reporter* reporter) {
    SkRefCnt ref;
    REPORTER_ASSERT(reporter, ref.unique());

    {
        SkMetaData md0, md1;
        const char name[] = "refcnt";

        md0.setRefCnt(name, &ref);
        REPORTER_ASSERT(reporter, md0.findRefCnt(name));
        REPORTER_ASSERT(reporter, md0.hasRefCnt(name, &ref));
        REPORTER_ASSERT(reporter, !ref.unique());

        md1 = md0;
        REPORTER_ASSERT(reporter, md1.findRefCnt(name));
        REPORTER_ASSERT(reporter, md1.hasRefCnt(name, &ref));
        REPORTER_ASSERT(reporter, !ref.unique());

        REPORTER_ASSERT(reporter, md0.removeRefCnt(name));
        REPORTER_ASSERT(reporter, !md0.findRefCnt(name));
        REPORTER_ASSERT(reporter, !md0.hasRefCnt(name, &ref));
        REPORTER_ASSERT(reporter, !ref.unique());
    }
    REPORTER_ASSERT(reporter, ref.unique());
}
예제 #19
0
DEF_TEST(Serialization, reporter) {
    // Test matrix serialization
    {
        SkMatrix matrix = SkMatrix::I();
        TestObjectSerialization(&matrix, reporter);
    }

    // Test path serialization
    {
        SkPath path;
        TestObjectSerialization(&path, reporter);
    }

    // Test region serialization
    {
        SkRegion region;
        TestObjectSerialization(&region, reporter);
    }

    // Test xfermode serialization
    {
        TestXfermodeSerialization(reporter);
    }

    // Test color filter serialization
    {
        TestColorFilterSerialization(reporter);
    }

    // Test string serialization
    {
        SkString string("string");
        TestObjectSerializationNoAlign<SkString, false>(&string, reporter);
        TestObjectSerializationNoAlign<SkString, true>(&string, reporter);
    }

    // Test rrect serialization
    {
        // SkRRect does not initialize anything.
        // An uninitialized SkRRect can be serialized,
        // but will branch on uninitialized data when deserialized.
        SkRRect rrect;
        SkRect rect = SkRect::MakeXYWH(1, 2, 20, 30);
        SkVector corners[4] = { {1, 2}, {2, 3}, {3,4}, {4,5} };
        rrect.setRectRadii(rect, corners);
        TestAlignment(&rrect, reporter);
    }

    // Test readByteArray
    {
        unsigned char data[kArraySize] = { 1, 2, 3 };
        TestArraySerialization(data, reporter);
    }

    // Test readColorArray
    {
        SkColor data[kArraySize] = { SK_ColorBLACK, SK_ColorWHITE, SK_ColorRED };
        TestArraySerialization(data, reporter);
    }

    // Test readIntArray
    {
        int32_t data[kArraySize] = { 1, 2, 4, 8 };
        TestArraySerialization(data, reporter);
    }

    // Test readPointArray
    {
        SkPoint data[kArraySize] = { {6, 7}, {42, 128} };
        TestArraySerialization(data, reporter);
    }

    // Test readScalarArray
    {
        SkScalar data[kArraySize] = { SK_Scalar1, SK_ScalarHalf, SK_ScalarMax };
        TestArraySerialization(data, reporter);
    }

    // Test invalid deserializations
    {
        SkImageInfo info = SkImageInfo::MakeN32Premul(kBitmapSize, kBitmapSize);

        SkBitmap validBitmap;
        validBitmap.setInfo(info);

        // Create a bitmap with a really large height
        SkBitmap invalidBitmap;
        invalidBitmap.setInfo(info.makeWH(info.width(), 1000000000));

        // The deserialization should succeed, and the rendering shouldn't crash,
        // even when the device fails to initialize, due to its size
        TestBitmapSerialization(validBitmap, invalidBitmap, true, reporter);
    }

    // Test simple SkPicture serialization
    {
        SkPictureRecorder recorder;
        draw_something(recorder.beginRecording(SkIntToScalar(kBitmapSize),
                                               SkIntToScalar(kBitmapSize),
                                               nullptr, 0));
        sk_sp<SkPicture> pict(recorder.finishRecordingAsPicture());

        // Serialize picture
        SkBinaryWriteBuffer writer;
        pict->flatten(writer);
        size_t size = writer.bytesWritten();
        SkAutoTMalloc<unsigned char> data(size);
        writer.writeToMemory(static_cast<void*>(data.get()));

        // Deserialize picture
        SkValidatingReadBuffer reader(static_cast<void*>(data.get()), size);
        sk_sp<SkPicture> readPict(SkPicture::MakeFromBuffer(reader));
        REPORTER_ASSERT(reporter, readPict.get());
    }

    TestPictureTypefaceSerialization(reporter);

    // Test SkLightingShader/NormalMapSource serialization
    {
        const int kTexSize = 2;

        SkLights::Builder builder;

        builder.add(SkLights::Light(SkColor3f::Make(1.0f, 1.0f, 1.0f),
                                    SkVector3::Make(1.0f, 0.0f, 0.0f)));
        builder.add(SkLights::Light(SkColor3f::Make(0.2f, 0.2f, 0.2f)));

        sk_sp<SkLights> fLights = builder.finish();

        SkBitmap diffuse = sk_tool_utils::create_checkerboard_bitmap(
                kTexSize, kTexSize,
                sk_tool_utils::color_to_565(0x0),
                sk_tool_utils::color_to_565(0xFF804020),
                8);

        SkRect bitmapBounds = SkRect::MakeIWH(diffuse.width(), diffuse.height());

        SkMatrix matrix;
        SkRect r = SkRect::MakeWH(SkIntToScalar(kTexSize), SkIntToScalar(kTexSize));
        matrix.setRectToRect(bitmapBounds, r, SkMatrix::kFill_ScaleToFit);

        SkMatrix ctm;
        ctm.setRotate(45);
        SkBitmap normals;
        normals.allocN32Pixels(kTexSize, kTexSize);

        sk_tool_utils::create_frustum_normal_map(&normals, SkIRect::MakeWH(kTexSize, kTexSize));
        sk_sp<SkShader> normalMap = SkMakeBitmapShader(normals, SkShader::kClamp_TileMode,
                                                       SkShader::kClamp_TileMode, &matrix, nullptr);
        sk_sp<SkNormalSource> normalSource = SkNormalSource::MakeFromNormalMap(std::move(normalMap),
                                                                               ctm);
        sk_sp<SkShader> lightingShader = SkLightingShader::Make(diffuse, fLights, &matrix,
                                                                std::move(normalSource));

        SkAutoTUnref<SkShader>(TestFlattenableSerialization(lightingShader.get(), true, reporter));
        // TODO test equality?

    }
}