1 /*
2  * Copyright 2013 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  *
7  * This test confirms that a MultiPictureDocument can be serialized and deserailzied without error.
8  * And that the pictures within it are re-created accurately
9  */
10 
11 #include "include/core/SkCanvas.h"
12 #include "include/core/SkDocument.h"
13 #include "include/core/SkFont.h"
14 #include "include/core/SkPicture.h"
15 #include "include/core/SkPictureRecorder.h"
16 #include "include/core/SkString.h"
17 #include "include/core/SkSurface.h"
18 #include "include/core/SkTextBlob.h"
19 #include "src/utils/SkMultiPictureDocument.h"
20 #include "tests/Test.h"
21 #include "tools/SkSharingProc.h"
22 #include "tools/ToolUtils.h"
23 
24 // Covers rects, ovals, paths, images, text
draw_basic(SkCanvas * canvas,int seed,sk_sp<SkImage> image)25 static void draw_basic(SkCanvas* canvas, int seed, sk_sp<SkImage> image) {
26     canvas->drawColor(SK_ColorWHITE);
27 
28     SkPaint paint;
29     paint.setStyle(SkPaint::kStroke_Style);
30     paint.setStrokeWidth(seed);
31     paint.setColor(SK_ColorRED);
32 
33     SkRect rect = SkRect::MakeXYWH(50+seed, 50+seed, 4*seed, 60);
34     canvas->drawRect(rect, paint);
35 
36     SkRRect oval;
37     oval.setOval(rect);
38     oval.offset(40, 60+seed);
39     paint.setColor(SK_ColorBLUE);
40     canvas->drawRRect(oval, paint);
41 
42     paint.setColor(SK_ColorCYAN);
43     canvas->drawCircle(180, 50, 5*seed, paint);
44 
45     rect.offset(80, 0);
46     paint.setColor(SK_ColorYELLOW);
47     canvas->drawRoundRect(rect, 10, 10, paint);
48 
49     SkPath path;
50     path.cubicTo(768, 0, -512, 256, 256, 256);
51     paint.setColor(SK_ColorGREEN);
52     canvas->drawPath(path, paint);
53 
54     canvas->drawImage(image, 128-seed, 128, &paint);
55 
56     if (seed % 2 == 0) {
57         SkRect rect2 = SkRect::MakeXYWH(0, 0, 40, 60);
58         canvas->drawImageRect(image, rect2, &paint);
59     }
60 
61     SkPaint paint2;
62     auto text = SkTextBlob::MakeFromString(
63         SkStringPrintf("Frame %d", seed).c_str(), SkFont(nullptr, 2+seed));
64     canvas->drawTextBlob(text.get(), 50, 25, paint2);
65 }
66 
67 // Covers all of the above and drawing nested sub-pictures.
draw_advanced(SkCanvas * canvas,int seed,sk_sp<SkImage> image,sk_sp<SkPicture> sub)68 static void draw_advanced(SkCanvas* canvas, int seed, sk_sp<SkImage> image, sk_sp<SkPicture> sub) {
69     draw_basic(canvas, seed, image);
70 
71     // Use subpicture twice in different places
72     canvas->drawPicture(sub);
73     canvas->save();
74     canvas->translate(seed, seed);
75     canvas->drawPicture(sub);
76     canvas->restore();
77 }
78 
79 // Test serialization and deserialization of multi picture document
DEF_TEST(Serialize_and_deserialize_multi_skp,reporter)80 DEF_TEST(Serialize_and_deserialize_multi_skp, reporter) {
81     // Create the stream we will serialize into.
82     SkDynamicMemoryWStream stream;
83 
84     // Create the image sharing proc.
85     SkSharingSerialContext ctx;
86     SkSerialProcs procs;
87     procs.fImageProc = SkSharingSerialContext::serializeImage;
88     procs.fImageCtx = &ctx;
89 
90     // Create the multi picture document used for recording frames.
91     sk_sp<SkDocument> multipic = SkMakeMultiPictureDocument(&stream, &procs);
92 
93     static const int NUM_FRAMES = 12;
94     static const int WIDTH = 256;
95     static const int HEIGHT = 256;
96 
97     // Make an image to be used in a later step.
98     auto surface(SkSurface::MakeRasterN32Premul(100, 100));
99     surface->getCanvas()->clear(SK_ColorGREEN);
100     sk_sp<SkImage> image(surface->makeImageSnapshot());
101     REPORTER_ASSERT(reporter, image);
102 
103     // Make a subpicture to be used in a later step
104     SkPictureRecorder pr;
105     SkCanvas* subCanvas = pr.beginRecording(100, 100);
106     draw_basic(subCanvas, 42, image);
107     sk_sp<SkPicture> sub = pr.finishRecordingAsPicture();
108 
109     const SkImageInfo info = SkImageInfo::MakeN32Premul(WIDTH, HEIGHT);
110     std::vector<sk_sp<SkImage>> pages;
111 
112     for (int i=0; i<NUM_FRAMES; i++) {
113         SkCanvas* pictureCanvas = multipic->beginPage(WIDTH, HEIGHT);
114         draw_advanced(pictureCanvas, i, image, sub);
115         multipic->endPage();
116         // Also record the same commands to separate SkRecords for later comparison
117         auto surf = SkSurface::MakeRaster(info);
118         draw_advanced(surf->getCanvas(), i, image, sub);
119         pages.push_back(surf->makeImageSnapshot());
120     }
121     // Finalize
122     multipic->close();
123 
124     // Confirm written data is at least as large as the magic word
125     std::unique_ptr<SkStreamAsset> writtenStream = stream.detachAsStream();
126     REPORTER_ASSERT(reporter, writtenStream->getLength() > 24,
127         "Written data length too short (%zu)", writtenStream->getLength());
128     // SkDebugf("Multi Frame file size = %zu\n", writtenStream->getLength());
129 
130     // Set up deserialization
131     SkSharingDeserialContext deserialContext;
132     SkDeserialProcs dprocs;
133     dprocs.fImageProc = SkSharingDeserialContext::deserializeImage;
134     dprocs.fImageCtx = &deserialContext;
135 
136     // Confirm data is a MultiPictureDocument
137     int frame_count = SkMultiPictureDocumentReadPageCount(writtenStream.get());
138     REPORTER_ASSERT(reporter, frame_count == NUM_FRAMES,
139         "Expected %d frames, got %d. \n 0 frames may indicate the written file was not a "
140         "MultiPictureDocument.", NUM_FRAMES, frame_count);
141 
142     // Deserailize
143     std::vector<SkDocumentPage> frames(frame_count);
144     REPORTER_ASSERT(reporter,
145         SkMultiPictureDocumentRead(writtenStream.get(), frames.data(), frame_count, &dprocs),
146         "Failed while reading MultiPictureDocument");
147 
148     // Examine each frame.
149     int i=0;
150     for (const auto& frame : frames) {
151         SkRect bounds = frame.fPicture->cullRect();
152         REPORTER_ASSERT(reporter, bounds.width() == WIDTH,
153             "Page width: expected (%d) got (%d)", WIDTH, (int)bounds.width());
154         REPORTER_ASSERT(reporter, bounds.height() == HEIGHT,
155             "Page height: expected (%d) got (%d)", HEIGHT, (int)bounds.height());
156 
157         auto surf = SkSurface::MakeRaster(info);
158         surf->getCanvas()->drawPicture(frame.fPicture);
159         auto img = surf->makeImageSnapshot();
160         REPORTER_ASSERT(reporter, ToolUtils::equal_pixels(img.get(), pages[i].get()));
161 
162         i++;
163     }
164 }
165