/* Hit a few SkPicture::Analysis cases not handled elsewhere. */ static void test_analysis(skiatest::Reporter* reporter) { SkPictureRecorder recorder; SkCanvas* canvas = recorder.beginRecording(100, 100); { canvas->drawRect(SkRect::MakeWH(10, 10), SkPaint ()); } SkAutoTUnref<SkPicture> picture(recorder.endRecording()); REPORTER_ASSERT(reporter, !picture->willPlayBackBitmaps()); canvas = recorder.beginRecording(100, 100); { SkPaint paint; // CreateBitmapShader is too smart for us; an empty (or 1x1) bitmap shader // gets optimized into a non-bitmap form, so we create a 2x2 bitmap here. SkBitmap bitmap; bitmap.allocPixels(SkImageInfo::MakeN32Premul(2, 2)); bitmap.eraseColor(SK_ColorBLUE); *(bitmap.getAddr32(0, 0)) = SK_ColorGREEN; SkShader* shader = SkShader::CreateBitmapShader(bitmap, SkShader::kClamp_TileMode, SkShader::kClamp_TileMode); paint.setShader(shader)->unref(); REPORTER_ASSERT(reporter, shader->asABitmap(NULL, NULL, NULL) == SkShader::kDefault_BitmapType); canvas->drawRect(SkRect::MakeWH(10, 10), paint); } picture.reset(recorder.endRecording()); REPORTER_ASSERT(reporter, picture->willPlayBackBitmaps()); }
PictureView() { fBitmap = load_bitmap(); SkPictureRecorder recorder; recorder.beginRecording(100, 100, NULL, 0); fSubPicture = recorder.endRecording(); SkCanvas* canvas = recorder.beginRecording(100, 100, NULL, 0); SkPaint paint; paint.setAntiAlias(true); canvas->drawBitmap(fBitmap, 0, 0, NULL); drawCircle(canvas, 50, SK_ColorBLACK); canvas->drawPicture(fSubPicture); canvas->translate(SkIntToScalar(50), 0); canvas->drawPicture(fSubPicture); canvas->translate(0, SkIntToScalar(50)); canvas->drawPicture(fSubPicture); canvas->translate(SkIntToScalar(-50), 0); canvas->drawPicture(fSubPicture); fPicture = recorder.endRecording(); // fPicture now has (4) references to fSubPicture. We can release our ref, // and just unref fPicture in our destructor, and it will in turn take care of // the other references to fSubPicture fSubPicture->unref(); }
static void test_unbalanced_save_restores(skiatest::Reporter* reporter) { SkCanvas testCanvas(100, 100); set_canvas_to_save_count_4(&testCanvas); REPORTER_ASSERT(reporter, 4 == testCanvas.getSaveCount()); SkPaint paint; SkRect rect = SkRect::MakeLTRB(-10000000, -10000000, 10000000, 10000000); SkPictureRecorder recorder; { // Create picture with 2 unbalanced saves SkCanvas* canvas = recorder.beginRecording(100, 100); canvas->save(); canvas->translate(10, 10); canvas->drawRect(rect, paint); canvas->save(); canvas->translate(10, 10); canvas->drawRect(rect, paint); SkAutoTUnref<SkPicture> extraSavePicture(recorder.endRecording()); testCanvas.drawPicture(extraSavePicture); REPORTER_ASSERT(reporter, 4 == testCanvas.getSaveCount()); } set_canvas_to_save_count_4(&testCanvas); { // Create picture with 2 unbalanced restores SkCanvas* canvas = recorder.beginRecording(100, 100); canvas->save(); canvas->translate(10, 10); canvas->drawRect(rect, paint); canvas->save(); canvas->translate(10, 10); canvas->drawRect(rect, paint); canvas->restore(); canvas->restore(); canvas->restore(); canvas->restore(); SkAutoTUnref<SkPicture> extraRestorePicture(recorder.endRecording()); testCanvas.drawPicture(extraRestorePicture); REPORTER_ASSERT(reporter, 4 == testCanvas.getSaveCount()); } set_canvas_to_save_count_4(&testCanvas); { SkCanvas* canvas = recorder.beginRecording(100, 100); canvas->translate(10, 10); canvas->drawRect(rect, paint); SkAutoTUnref<SkPicture> noSavePicture(recorder.endRecording()); testCanvas.drawPicture(noSavePicture); REPORTER_ASSERT(reporter, 4 == testCanvas.getSaveCount()); REPORTER_ASSERT(reporter, testCanvas.getTotalMatrix().isIdentity()); } }
TEST_F(DeferredImageDecoderTest, drawIntoSkPictureProgressive) { RefPtr<SharedBuffer> partialData = SharedBuffer::create(m_data->data(), m_data->size() - 10); // Received only half the file. m_lazyDecoder->setData(*partialData, false); RefPtr<NativeImageSkia> image = m_lazyDecoder->frameBufferAtIndex(0)->asNewNativeImage(); SkPictureRecorder recorder; SkCanvas* tempCanvas = recorder.beginRecording(100, 100, 0, 0); tempCanvas->drawBitmap(image->bitmap(), 0, 0); RefPtr<SkPicture> picture = adoptRef(recorder.endRecording()); m_surface->getCanvas()->drawPicture(picture.get()); // Fully received the file and draw the SkPicture again. m_lazyDecoder->setData(*m_data, true); image = m_lazyDecoder->frameBufferAtIndex(0)->asNewNativeImage(); tempCanvas = recorder.beginRecording(100, 100, 0, 0); tempCanvas->drawBitmap(image->bitmap(), 0, 0); picture = adoptRef(recorder.endRecording()); m_surface->getCanvas()->drawPicture(picture.get()); SkBitmap canvasBitmap; canvasBitmap.allocN32Pixels(100, 100); ASSERT_TRUE(m_surface->getCanvas()->readPixels(&canvasBitmap, 0, 0)); SkAutoLockPixels autoLock(canvasBitmap); EXPECT_EQ(SkColorSetARGB(255, 255, 255, 255), canvasBitmap.getColor(0, 0)); }
static void test_peephole() { SkRandom rand; SkPictureRecorder recorder; for (int j = 0; j < 100; j++) { SkRandom rand2(rand); // remember the seed SkCanvas* canvas = recorder.beginRecording(100, 100); for (int i = 0; i < 1000; ++i) { rand_op(canvas, rand); } SkAutoTUnref<SkPicture> picture(recorder.endRecording()); rand = rand2; } { SkCanvas* canvas = recorder.beginRecording(100, 100); SkRect rect = SkRect::MakeWH(50, 50); for (int i = 0; i < 100; ++i) { canvas->save(); } while (canvas->getSaveCount() > 1) { canvas->clipRect(rect); canvas->restore(); } SkAutoTUnref<SkPicture> picture(recorder.endRecording()); } }
SkPicture* SkDebugger::copyPicture() { // We can't just call clone here since we want to removed the "deleted" // commands. Playing back will strip those out. SkPictureRecorder recorder; SkCanvas* canvas = recorder.beginRecording(fPictureWidth, fPictureHeight, NULL, 0); bool vizMode = fDebugCanvas->getMegaVizMode(); fDebugCanvas->setMegaVizMode(false); bool overDraw = fDebugCanvas->getOverdrawViz(); fDebugCanvas->setOverdrawViz(false); bool pathOps = fDebugCanvas->getAllowSimplifyClip(); fDebugCanvas->setAllowSimplifyClip(false); int saveCount = fDebugCanvas->getOutstandingSaveCount(); fDebugCanvas->setOutstandingSaveCount(0); fDebugCanvas->draw(canvas); int temp = fDebugCanvas->getOutstandingSaveCount(); for (int i = 0; i < temp; ++i) { canvas->restore(); } fDebugCanvas->setMegaVizMode(vizMode); fDebugCanvas->setOverdrawViz(overDraw); fDebugCanvas->setOutstandingSaveCount(saveCount); fDebugCanvas->setAllowSimplifyClip(pathOps); return recorder.endRecording(); }
static SkImage* create_picture_image() { SkPictureRecorder recorder; SkCanvas* canvas = recorder.beginRecording(10, 10); canvas->clear(SK_ColorCYAN); SkAutoTUnref<SkPicture> picture(recorder.endRecording()); return SkImage::NewFromPicture(picture, SkISize::Make(10, 10), nullptr, nullptr); };
int DownloadHandler::handle(Request* request, MHD_Connection* connection, const char* url, const char* method, const char* upload_data, size_t* upload_data_size) { if (!request->hasPicture()) { return MHD_NO; } // TODO move to a function // Playback into picture recorder SkPictureRecorder recorder; SkCanvas* canvas = recorder.beginRecording(Request::kImageWidth, Request::kImageHeight); request->fDebugCanvas->draw(canvas); SkAutoTUnref<SkPicture> picture(recorder.endRecording()); SkDynamicMemoryWStream outStream; SkAutoTUnref<SkPixelSerializer> serializer(SkImageEncoder::CreatePixelSerializer()); picture->serialize(&outStream, serializer); SkAutoTUnref<SkData> data(outStream.copyToData()); // TODO fancier name handling return SendData(connection, data, "application/octet-stream", true, "attachment; filename=something.skp;"); }
static const SkPicture* make_sub_picture(const SkPicture* tri) { SkPictureRecorder recorder; SkCanvas* canvas = recorder.beginRecording(SkIntToScalar(kPicWidth), SkIntToScalar(kPicHeight)); canvas->scale(1.0f/2.0f, 1.0f/2.0f); canvas->save(); canvas->translate(SkScalarHalf(kTriSide), 0); canvas->drawPicture(tri); canvas->restore(); canvas->save(); canvas->translate(SkIntToScalar(kTriSide), 1.5f * kTriSide / kRoot3); canvas->drawPicture(tri); canvas->restore(); canvas->save(); canvas->translate(0, 1.5f * kTriSide / kRoot3); canvas->drawPicture(tri); canvas->restore(); return recorder.endRecording(); }
TEST_F(DeferredImageDecoderTest, decodeOnOtherThread) { m_lazyDecoder->setData(*m_data, true); RefPtr<SkImage> image = m_lazyDecoder->createFrameAtIndex(0); ASSERT_TRUE(image); EXPECT_EQ(1, image->width()); EXPECT_EQ(1, image->height()); SkPictureRecorder recorder; SkCanvas* tempCanvas = recorder.beginRecording(100, 100, 0, 0); tempCanvas->drawImage(image.get(), 0, 0); RefPtr<SkPicture> picture = adoptRef(recorder.endRecording()); EXPECT_EQ(0, m_decodeRequestCount); // Create a thread to rasterize SkPicture. OwnPtr<WebThread> thread = adoptPtr(Platform::current()->createThread("RasterThread")); thread->taskRunner()->postTask(BLINK_FROM_HERE, new Task(threadSafeBind(&rasterizeMain, AllowCrossThreadAccess(m_surface->getCanvas()), AllowCrossThreadAccess(picture.get())))); thread.clear(); EXPECT_EQ(0, m_decodeRequestCount); SkBitmap canvasBitmap; canvasBitmap.allocN32Pixels(100, 100); ASSERT_TRUE(m_surface->getCanvas()->readPixels(&canvasBitmap, 0, 0)); SkAutoLockPixels autoLock(canvasBitmap); EXPECT_EQ(SkColorSetARGB(255, 255, 255, 255), canvasBitmap.getColor(0, 0)); }
// Verify that associated bitmap cache entries are purged on SkImage destruction. DEF_TEST(BitmapCache_discarded_image, reporter) { // Cache entries associated with SkImages fall into two categories: // // 1) generated image bitmaps (managed by the image cacherator) // 2) scaled/resampled bitmaps (cached when HQ filters are used) // // To exercise the first cache type, we use generated/picture-backed SkImages. // To exercise the latter, we draw scaled bitmap images using HQ filters. const SkMatrix xforms[] = { SkMatrix::MakeScale(1, 1), SkMatrix::MakeScale(1.7f, 0.5f), }; for (size_t i = 0; i < SK_ARRAY_COUNT(xforms); ++i) { test_discarded_image(reporter, xforms[i], []() { SkAutoTUnref<SkSurface> surface(SkSurface::NewRasterN32Premul(10, 10)); surface->getCanvas()->clear(SK_ColorCYAN); return surface->newImageSnapshot(); }); test_discarded_image(reporter, xforms[i], []() { SkPictureRecorder recorder; SkCanvas* canvas = recorder.beginRecording(10, 10); canvas->clear(SK_ColorCYAN); SkAutoTUnref<SkPicture> picture(recorder.endRecording()); return SkImage::NewFromPicture(picture, SkISize::Make(10, 10), nullptr, nullptr); }); } }
static void serialize_and_compare_typeface(SkTypeface* typeface, const char* text, skiatest::Reporter* reporter) { // Create a paint with the typeface. SkPaint paint; paint.setColor(SK_ColorGRAY); paint.setTextSize(SkIntToScalar(30)); paint.setTypeface(typeface); // Paint some text. SkPictureRecorder recorder; SkIRect canvasRect = SkIRect::MakeWH(kBitmapSize, kBitmapSize); SkCanvas* canvas = recorder.beginRecording(SkIntToScalar(canvasRect.width()), SkIntToScalar(canvasRect.height()), nullptr, 0); canvas->drawColor(SK_ColorWHITE); canvas->drawText(text, 2, 24, 32, paint); SkAutoTUnref<SkPicture> picture(recorder.endRecording()); // Serlialize picture and create its clone from stream. SkDynamicMemoryWStream stream; picture->serialize(&stream); SkAutoTDelete<SkStream> inputStream(stream.detachAsStream()); SkAutoTUnref<SkPicture> loadedPicture(SkPicture::CreateFromStream(inputStream.get())); // Draw both original and clone picture and compare bitmaps -- they should be identical. SkBitmap origBitmap = draw_picture(*picture); SkBitmap destBitmap = draw_picture(*loadedPicture); compare_bitmaps(reporter, origBitmap, destBitmap); }
static void bench_record(SkPicture* src, const char* name, SkBBHFactory* bbhFactory) { BenchTimer timer; timer.start(); const int width = src ? src->width() : FLAGS_nullSize; const int height = src ? src->height() : FLAGS_nullSize; for (int i = 0; i < FLAGS_loops; i++) { if (FLAGS_skr) { EXPERIMENTAL::SkRecording recording(width, height); if (NULL != src) { src->draw(recording.canvas()); } // Release and delete the SkPlayback so that recording optimizes its SkRecord. SkDELETE(recording.releasePlayback()); } else { SkPictureRecorder recorder; SkCanvas* canvas = recorder.beginRecording(width, height, bbhFactory, FLAGS_flags); if (NULL != src) { src->draw(canvas); } if (FLAGS_endRecording) { SkAutoTUnref<SkPicture> dst(recorder.endRecording()); } } } timer.end(); const double msPerLoop = timer.fCpu / (double)FLAGS_loops; printf("%f\t%s\n", scale_time(msPerLoop), name); }
void onDrawContent(SkCanvas* canvas) override { this->drawSomething(canvas); SkPictureRecorder recorder; this->drawSomething(recorder.beginRecording(100, 100, NULL, 0)); SkAutoTUnref<SkPicture> pict(recorder.endRecording()); canvas->save(); canvas->translate(SkIntToScalar(300), SkIntToScalar(50)); canvas->scale(-SK_Scalar1, -SK_Scalar1); canvas->translate(-SkIntToScalar(100), -SkIntToScalar(50)); canvas->drawPicture(pict); canvas->restore(); canvas->save(); canvas->translate(SkIntToScalar(200), SkIntToScalar(150)); canvas->scale(SK_Scalar1, -SK_Scalar1); canvas->translate(0, -SkIntToScalar(50)); canvas->drawPicture(pict); canvas->restore(); canvas->save(); canvas->translate(SkIntToScalar(100), SkIntToScalar(100)); canvas->scale(-SK_Scalar1, SK_Scalar1); canvas->translate(-SkIntToScalar(100), 0); canvas->drawPicture(pict); canvas->restore(); }
DEF_TEST(Picture_BitmapLeak, r) { SkBitmap mut, immut; mut.allocN32Pixels(300, 200); immut.allocN32Pixels(300, 200); immut.setImmutable(); SkASSERT(!mut.isImmutable()); SkASSERT(immut.isImmutable()); // No one can hold a ref on our pixels yet. REPORTER_ASSERT(r, mut.pixelRef()->unique()); REPORTER_ASSERT(r, immut.pixelRef()->unique()); SkAutoTUnref<const SkPicture> pic; { // we want the recorder to go out of scope before our subsequent checks, so we // place it inside local braces. SkPictureRecorder rec; SkCanvas* canvas = rec.beginRecording(1920, 1200); canvas->drawBitmap(mut, 0, 0); canvas->drawBitmap(immut, 800, 600); pic.reset(rec.endRecording()); } // The picture shares the immutable pixels but copies the mutable ones. REPORTER_ASSERT(r, mut.pixelRef()->unique()); REPORTER_ASSERT(r, !immut.pixelRef()->unique()); // When the picture goes away, it's just our bitmaps holding the refs. pic.reset(NULL); REPORTER_ASSERT(r, mut.pixelRef()->unique()); REPORTER_ASSERT(r, immut.pixelRef()->unique()); }
TEST_F(DeferredImageDecoderTest, decodeOnOtherThread) { m_lazyDecoder->setData(*m_data, true); RefPtr<NativeImageSkia> image = m_lazyDecoder->frameBufferAtIndex(0)->asNewNativeImage(); EXPECT_EQ(1, image->bitmap().width()); EXPECT_EQ(1, image->bitmap().height()); EXPECT_FALSE(image->bitmap().isNull()); EXPECT_TRUE(image->bitmap().isImmutable()); SkPictureRecorder recorder; SkCanvas* tempCanvas = recorder.beginRecording(100, 100, 0, 0); tempCanvas->drawBitmap(image->bitmap(), 0, 0); RefPtr<SkPicture> picture = adoptRef(recorder.endRecording()); EXPECT_EQ(0, m_frameBufferRequestCount); // Create a thread to rasterize SkPicture. OwnPtr<WebThread> thread = adoptPtr(Platform::current()->createThread("RasterThread")); thread->postTask(new Task(WTF::bind(&rasterizeMain, m_surface->getCanvas(), picture.get()))); thread.clear(); EXPECT_EQ(0, m_frameBufferRequestCount); SkBitmap canvasBitmap; canvasBitmap.allocN32Pixels(100, 100); ASSERT_TRUE(m_surface->getCanvas()->readPixels(&canvasBitmap, 0, 0)); SkAutoLockPixels autoLock(canvasBitmap); EXPECT_EQ(SkColorSetARGB(255, 255, 255, 255), canvasBitmap.getColor(0, 0)); }
TEST_F(DeferredImageDecoderTest, drawIntoSkPicture) { m_lazyDecoder->setData(*m_data, true); SkBitmap bitmap; EXPECT_TRUE(m_lazyDecoder->createFrameAtIndex(0, &bitmap)); EXPECT_EQ(1, bitmap.width()); EXPECT_EQ(1, bitmap.height()); EXPECT_FALSE(bitmap.isNull()); EXPECT_TRUE(bitmap.isImmutable()); SkPictureRecorder recorder; SkCanvas* tempCanvas = recorder.beginRecording(100, 100, 0, 0); tempCanvas->drawBitmap(bitmap, 0, 0); RefPtr<SkPicture> picture = adoptRef(recorder.endRecording()); EXPECT_EQ(0, m_decodeRequestCount); m_surface->getCanvas()->drawPicture(picture.get()); EXPECT_EQ(0, m_decodeRequestCount); SkBitmap canvasBitmap; canvasBitmap.allocN32Pixels(100, 100); ASSERT_TRUE(m_surface->getCanvas()->readPixels(&canvasBitmap, 0, 0)); SkAutoLockPixels autoLock(canvasBitmap); EXPECT_EQ(SkColorSetARGB(255, 255, 255, 255), canvasBitmap.getColor(0, 0)); }
// Test that image encoding failures do not break picture serialization/deserialization. DEF_TEST(Image_Serialize_Encoding_Failure, reporter) { SkAutoTUnref<SkSurface> surface(SkSurface::NewRasterN32Premul(100, 100)); surface->getCanvas()->clear(SK_ColorGREEN); SkAutoTUnref<SkImage> image(surface->newImageSnapshot()); REPORTER_ASSERT(reporter, image); SkPictureRecorder recorder; SkCanvas* canvas = recorder.beginRecording(100, 100); canvas->drawImage(image, 0, 0); SkAutoTUnref<SkPicture> picture(recorder.endRecording()); REPORTER_ASSERT(reporter, picture); REPORTER_ASSERT(reporter, picture->approximateOpCount() > 0); MockSerializer emptySerializer([]() -> SkData* { return SkData::NewEmpty(); }); MockSerializer nullSerializer([]() -> SkData* { return nullptr; }); MockSerializer* serializers[] = { &emptySerializer, &nullSerializer }; for (size_t i = 0; i < SK_ARRAY_COUNT(serializers); ++i) { SkDynamicMemoryWStream wstream; REPORTER_ASSERT(reporter, !serializers[i]->didEncode()); picture->serialize(&wstream, serializers[i]); REPORTER_ASSERT(reporter, serializers[i]->didEncode()); SkAutoTDelete<SkStream> rstream(wstream.detachAsStream()); SkAutoTUnref<SkPicture> deserialized(SkPicture::CreateFromStream(rstream)); REPORTER_ASSERT(reporter, deserialized); REPORTER_ASSERT(reporter, deserialized->approximateOpCount() > 0); } }
// Create a Sierpinkski-like picture that starts with a top row with a picture // that just contains a triangle. Subsequent rows take the prior row's picture, // shrinks it and replicates it 3 times then draws and appropriate number of // copies of it. static const SkPicture* make_sierpinski_picture() { SkAutoTUnref<const SkPicture> pic(make_tri_picture()); SkPictureRecorder recorder; SkRTreeFactory bbhFactory; SkCanvas* canvas = recorder.beginRecording(SkIntToScalar(kPicWidth), SkIntToScalar(kPicHeight), &bbhFactory, SkPictureRecorder::kComputeSaveLayerInfo_RecordFlag); static const int kNumLevels = 4; for (int i = 0; i < kNumLevels; ++i) { canvas->save(); canvas->translate(kPicWidth/2 - (i+1) * (kTriSide/2.0f), 0.0f); for (int j = 0; j < i+1; ++j) { canvas->drawPicture(pic); canvas->translate(SkIntToScalar(kTriSide), 0); } canvas->restore(); pic.reset(make_sub_picture(pic)); canvas->translate(0, 1.5f * kTriSide / kRoot3); } return recorder.endRecording(); }
/** * Verify that we get the same culling bounds for text for (1) drawing glyphs * directly to a Canvas or (2) going through a SkPicture as an intermediate step. */ TEST(SkiaCanvasProxy, drawGlyphsViaPicture) { auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) { // setup test variables SkPaint paint; paint.setAntiAlias(true); paint.setTextSize(20); paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); static const char* text = "testing text bounds"; // draw text directly into Recording canvas TestUtils::drawUtf8ToCanvas(&canvas, text, paint, 25, 25); // record the same text draw into a SkPicture and replay it into a Recording canvas SkPictureRecorder recorder; SkCanvas* skCanvas = recorder.beginRecording(200, 200, NULL, 0); std::unique_ptr<Canvas> pictCanvas(Canvas::create_canvas(skCanvas)); TestUtils::drawUtf8ToCanvas(pictCanvas.get(), text, paint, 25, 25); SkAutoTUnref<const SkPicture> picture(recorder.endRecording()); canvas.asSkCanvas()->drawPicture(picture); }); // verify that the text bounds and matrices match ASSERT_EQ(2U, dl->getOps().size()); auto directOp = dl->getOps()[0]; auto pictureOp = dl->getOps()[1]; ASSERT_EQ(RecordedOpId::TextOp, directOp->opId); EXPECT_EQ(directOp->opId, pictureOp->opId); EXPECT_EQ(directOp->unmappedBounds, pictureOp->unmappedBounds); EXPECT_EQ(directOp->localMatrix, pictureOp->localMatrix); }
static const SkPicture* make_sub_picture(const SkPicture* tri) { SkPictureRecorder recorder; SkRTreeFactory bbhFactory; SkCanvas* canvas = recorder.beginRecording(SkIntToScalar(kPicWidth), SkIntToScalar(kPicHeight), &bbhFactory, SkPictureRecorder::kComputeSaveLayerInfo_RecordFlag); canvas->scale(1.0f/2.0f, 1.0f/2.0f); canvas->save(); canvas->translate(SkScalarHalf(kTriSide), 0); canvas->drawPicture(tri); canvas->restore(); canvas->save(); canvas->translate(SkIntToScalar(kTriSide), 1.5f * kTriSide / kRoot3); canvas->drawPicture(tri); canvas->restore(); canvas->save(); canvas->translate(0, 1.5f * kTriSide / kRoot3); canvas->drawPicture(tri); canvas->restore(); return recorder.endRecording(); }
static const SkPicture* make_tri_picture() { SkPath tri = make_tri_path(SkScalarHalf(kTriSide), 0); SkPaint fill; fill.setStyle(SkPaint::kFill_Style); fill.setColor(sk_tool_utils::color_to_565(SK_ColorLTGRAY)); SkPaint stroke; stroke.setStyle(SkPaint::kStroke_Style); stroke.setStrokeWidth(3); SkPictureRecorder recorder; SkRTreeFactory bbhFactory; SkCanvas* canvas = recorder.beginRecording(SkIntToScalar(kPicWidth), SkIntToScalar(kPicHeight), &bbhFactory, SkPictureRecorder::kComputeSaveLayerInfo_RecordFlag); SkRect r = tri.getBounds(); r.outset(2.0f, 2.0f); // outset for stroke canvas->clipRect(r); // The saveLayer/restore block is to exercise layer hoisting canvas->saveLayer(nullptr, nullptr); canvas->drawPath(tri, fill); canvas->drawPath(tri, stroke); canvas->restore(); return recorder.endRecording(); }
// Make sure the abort callback works DEF_TEST(RecordReplaceDraw_Abort, r) { SkAutoTUnref<const SkPicture> pic; { // Record two commands. SkPictureRecorder recorder; SkCanvas* canvas = recorder.beginRecording(SkIntToScalar(kWidth), SkIntToScalar(kHeight)); canvas->drawRect(SkRect::MakeWH(SkIntToScalar(kWidth), SkIntToScalar(kHeight)), SkPaint()); canvas->clipRect(SkRect::MakeWH(SkIntToScalar(kWidth), SkIntToScalar(kHeight))); pic.reset(recorder.endRecording()); } SkRecord rerecord; SkRecorder canvas(&rerecord, kWidth, kHeight); JustOneDraw callback; GrRecordReplaceDraw(pic, &canvas, nullptr, SkMatrix::I(), &callback); switch (rerecord.count()) { case 3: assert_type<SkRecords::Save>(r, rerecord, 0); assert_type<SkRecords::DrawRect>(r, rerecord, 1); assert_type<SkRecords::Restore>(r, rerecord, 2); break; case 1: assert_type<SkRecords::DrawRect>(r, rerecord, 0); break; default: REPORTER_ASSERT(r, false); } }
// Ensure that serializing an empty picture does not assert. Likewise only runs in debug mode. static void test_serializing_empty_picture() { SkPictureRecorder recorder; recorder.beginRecording(0, 0); SkAutoTUnref<SkPicture> picture(recorder.endRecording()); SkDynamicMemoryWStream stream; picture->serialize(&stream); }
// Ensure that deleting an empty SkPicture does not assert. Asserts only fire // in debug mode, so only run in debug mode. static void test_deleting_empty_picture() { SkPictureRecorder recorder; // Creates an SkPictureRecord recorder.beginRecording(0, 0); // Turns that into an SkPicture SkAutoTUnref<SkPicture> picture(recorder.endRecording()); // Ceates a new SkPictureRecord recorder.beginRecording(0, 0); }
static void rerecord(const SkPicture& src, SkBBHFactory* bbhFactory) { SkPictureRecorder recorder; if (FLAGS_skr) { src.draw(recorder.EXPERIMENTAL_beginRecording(src.width(), src.height(), bbhFactory)); } else { src.draw(recorder.beginRecording(src.width(), src.height(), bbhFactory)); } SkAutoTUnref<SkPicture> pic(recorder.endRecording()); }
SkPicture* RecordPicture(skiagm::GM* gm, uint32_t recordFlags, SkBBHFactory* factory) { const SkISize size = gm->getISize(); SkPictureRecorder recorder; SkCanvas* canvas = recorder.beginRecording(size.width(), size.height(), factory, recordFlags); canvas->concat(gm->getInitialTransform()); gm->draw(canvas); canvas->flush(); return recorder.endRecording(); }
SkPicture* SkPicture::Forwardport(const SkPictInfo& info, const SkPictureData* data) { if (!data) { return nullptr; } SkPicturePlayback playback(data); SkPictureRecorder r; playback.draw(r.beginRecording(info.fCullRect), nullptr/*no callback*/); return r.endRecording(); }
static void test_gen_id(skiatest::Reporter* reporter) { SkPictureRecorder recorder; recorder.beginRecording(0, 0); SkAutoTUnref<SkPicture> empty(recorder.endRecording()); // Empty pictures should still have a valid ID REPORTER_ASSERT(reporter, empty->uniqueID() != SK_InvalidGenID); SkCanvas* canvas = recorder.beginRecording(1, 1); canvas->drawARGB(255, 255, 255, 255); SkAutoTUnref<SkPicture> hasData(recorder.endRecording()); // picture should have a non-zero id after recording REPORTER_ASSERT(reporter, hasData->uniqueID() != SK_InvalidGenID); // both pictures should have different ids REPORTER_ASSERT(reporter, hasData->uniqueID() != empty->uniqueID()); }
// getRecordingCanvas() should return a SkCanvas when recording, null when not recording. DEF_TEST(Picture_getRecordingCanvas, r) { SkPictureRecorder rec; REPORTER_ASSERT(r, !rec.getRecordingCanvas()); for (int i = 0; i < 3; i++) { rec.beginRecording(100, 100); REPORTER_ASSERT(r, rec.getRecordingCanvas()); rec.endRecording()->unref(); REPORTER_ASSERT(r, !rec.getRecordingCanvas()); } }