blob: 61b6720ad868e4b74c475360b8fde3c2efc4006d [file] [log] [blame]
/*
* Copyright 2013 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
* This test confirms that a MultiPictureDocument can be serialized and deserailzied without error.
* And that the pictures within it are re-created accurately
*/
#include "include/core/SkCanvas.h"
#include "include/core/SkDocument.h"
#include "include/core/SkFont.h"
#include "include/core/SkPicture.h"
#include "include/core/SkPictureRecorder.h"
#include "include/core/SkString.h"
#include "include/core/SkSurface.h"
#include "include/core/SkTextBlob.h"
#include "src/utils/SkMultiPictureDocument.h"
#include "tests/Test.h"
#include "tools/SkSharingProc.h"
#include "tools/ToolUtils.h"
// Covers rects, ovals, paths, images, text
static void draw_basic(SkCanvas* canvas, int seed, sk_sp<SkImage> image) {
canvas->drawColor(SK_ColorWHITE);
SkPaint paint;
paint.setStyle(SkPaint::kStroke_Style);
paint.setStrokeWidth(seed);
paint.setColor(SK_ColorRED);
SkRect rect = SkRect::MakeXYWH(50+seed, 50+seed, 4*seed, 60);
canvas->drawRect(rect, paint);
SkRRect oval;
oval.setOval(rect);
oval.offset(40, 60+seed);
paint.setColor(SK_ColorBLUE);
canvas->drawRRect(oval, paint);
paint.setColor(SK_ColorCYAN);
canvas->drawCircle(180, 50, 5*seed, paint);
rect.offset(80, 0);
paint.setColor(SK_ColorYELLOW);
canvas->drawRoundRect(rect, 10, 10, paint);
SkPath path;
path.cubicTo(768, 0, -512, 256, 256, 256);
paint.setColor(SK_ColorGREEN);
canvas->drawPath(path, paint);
canvas->drawImage(image, 128-seed, 128, &paint);
if (seed % 2 == 0) {
SkRect rect2 = SkRect::MakeXYWH(0, 0, 40, 60);
canvas->drawImageRect(image, rect2, &paint);
}
SkPaint paint2;
auto text = SkTextBlob::MakeFromString(
SkStringPrintf("Frame %d", seed).c_str(), SkFont(nullptr, 2+seed));
canvas->drawTextBlob(text.get(), 50, 25, paint2);
}
// Covers all of the above and drawing nested sub-pictures.
static void draw_advanced(SkCanvas* canvas, int seed, sk_sp<SkImage> image, sk_sp<SkPicture> sub) {
draw_basic(canvas, seed, image);
// Use subpicture twice in different places
canvas->drawPicture(sub);
canvas->save();
canvas->translate(seed, seed);
canvas->drawPicture(sub);
canvas->restore();
}
// Test serialization and deserialization of multi picture document
DEF_TEST(Serialize_and_deserialize_multi_skp, reporter) {
// Create the stream we will serialize into.
SkDynamicMemoryWStream stream;
// Create the image sharing proc.
SkSharingSerialContext ctx;
SkSerialProcs procs;
procs.fImageProc = SkSharingSerialContext::serializeImage;
procs.fImageCtx = &ctx;
// Create the multi picture document used for recording frames.
sk_sp<SkDocument> multipic = SkMakeMultiPictureDocument(&stream, &procs);
static const int NUM_FRAMES = 12;
static const int WIDTH = 256;
static const int HEIGHT = 256;
// Make an image to be used in a later step.
auto surface(SkSurface::MakeRasterN32Premul(100, 100));
surface->getCanvas()->clear(SK_ColorGREEN);
sk_sp<SkImage> image(surface->makeImageSnapshot());
REPORTER_ASSERT(reporter, image);
// Make a subpicture to be used in a later step
SkPictureRecorder pr;
SkCanvas* subCanvas = pr.beginRecording(100, 100);
draw_basic(subCanvas, 42, image);
sk_sp<SkPicture> sub = pr.finishRecordingAsPicture();
const SkImageInfo info = SkImageInfo::MakeN32Premul(WIDTH, HEIGHT);
std::vector<sk_sp<SkImage>> pages;
for (int i=0; i<NUM_FRAMES; i++) {
SkCanvas* pictureCanvas = multipic->beginPage(WIDTH, HEIGHT);
draw_advanced(pictureCanvas, i, image, sub);
multipic->endPage();
// Also record the same commands to separate SkRecords for later comparison
auto surf = SkSurface::MakeRaster(info);
draw_advanced(surf->getCanvas(), i, image, sub);
pages.push_back(surf->makeImageSnapshot());
}
// Finalize
multipic->close();
// Confirm written data is at least as large as the magic word
std::unique_ptr<SkStreamAsset> writtenStream = stream.detachAsStream();
REPORTER_ASSERT(reporter, writtenStream->getLength() > 24,
"Written data length too short (%zu)", writtenStream->getLength());
// SkDebugf("Multi Frame file size = %zu\n", writtenStream->getLength());
// Set up deserialization
SkSharingDeserialContext deserialContext;
SkDeserialProcs dprocs;
dprocs.fImageProc = SkSharingDeserialContext::deserializeImage;
dprocs.fImageCtx = &deserialContext;
// Confirm data is a MultiPictureDocument
int frame_count = SkMultiPictureDocumentReadPageCount(writtenStream.get());
REPORTER_ASSERT(reporter, frame_count == NUM_FRAMES,
"Expected %d frames, got %d. \n 0 frames may indicate the written file was not a "
"MultiPictureDocument.", NUM_FRAMES, frame_count);
// Deserailize
std::vector<SkDocumentPage> frames(frame_count);
REPORTER_ASSERT(reporter,
SkMultiPictureDocumentRead(writtenStream.get(), frames.data(), frame_count, &dprocs),
"Failed while reading MultiPictureDocument");
// Examine each frame.
int i=0;
for (const auto& frame : frames) {
SkRect bounds = frame.fPicture->cullRect();
REPORTER_ASSERT(reporter, bounds.width() == WIDTH,
"Page width: expected (%d) got (%d)", WIDTH, (int)bounds.width());
REPORTER_ASSERT(reporter, bounds.height() == HEIGHT,
"Page height: expected (%d) got (%d)", HEIGHT, (int)bounds.height());
auto surf = SkSurface::MakeRaster(info);
surf->getCanvas()->drawPicture(frame.fPicture);
auto img = surf->makeImageSnapshot();
REPORTER_ASSERT(reporter, ToolUtils::equal_pixels(img.get(), pages[i].get()));
i++;
}
}