1/*
2 * Copyright 2016 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
8#include "Resources.h"
9#include "SkCanvas.h"
10#include "SkPipe.h"
11#include "SkPaint.h"
12#include "SkStream.h"
13#include "SkSurface.h"
14#include "Test.h"
15
16#include "SkNullCanvas.h"
17#include "SkAutoPixmapStorage.h"
18#include "SkPictureRecorder.h"
19
20static void drain(SkPipeDeserializer* deserial, SkDynamicMemoryWStream* stream) {
21    std::unique_ptr<SkCanvas> canvas = SkMakeNullCanvas();
22    sk_sp<SkData> data = stream->detachAsData();
23    deserial->playback(data->data(), data->size(), canvas.get());
24}
25
26static bool deep_equal(SkImage* a, SkImage* b) {
27    if (a->width() != b->width() || a->height() != b->height()) {
28        return false;
29    }
30
31    const SkImageInfo info = SkImageInfo::MakeN32Premul(a->width(), a->height());
32    SkAutoPixmapStorage pmapA, pmapB;
33    pmapA.alloc(info);
34    pmapB.alloc(info);
35
36    if (!a->readPixels(pmapA, 0, 0) || !b->readPixels(pmapB, 0, 0)) {
37        return false;
38    }
39
40    for (int y = 0; y < info.height(); ++y) {
41        if (memcmp(pmapA.addr32(0, y), pmapB.addr32(0, y), info.width() * sizeof(SkPMColor))) {
42            return false;
43        }
44    }
45    return true;
46}
47
48DEF_TEST(Pipe_image_draw_first, reporter) {
49    sk_sp<SkImage> img = GetResourceAsImage("mandrill_128.png");
50    SkASSERT(img.get());
51
52    SkPipeSerializer serializer;
53    SkPipeDeserializer deserializer;
54
55    SkDynamicMemoryWStream stream;
56    SkCanvas* wc = serializer.beginWrite(SkRect::MakeWH(100, 100), &stream);
57    wc->drawImage(img, 0, 0, nullptr);
58    serializer.endWrite();
59    size_t offset0 = stream.bytesWritten();
60    REPORTER_ASSERT(reporter, offset0 > 100);   // the raw image must be sorta big
61    drain(&deserializer, &stream);
62
63    // try drawing the same image again -- it should be much smaller
64    wc = serializer.beginWrite(SkRect::MakeWH(100, 100), &stream);
65    wc->drawImage(img, 0, 0, nullptr);
66    size_t offset1 = stream.bytesWritten();
67    serializer.endWrite();
68    REPORTER_ASSERT(reporter, offset1 <= 32);
69    drain(&deserializer, &stream);
70
71    // try serializing the same image directly, again it should be small
72    sk_sp<SkData> data = serializer.writeImage(img.get());
73    size_t offset2 = data->size();
74    REPORTER_ASSERT(reporter, offset2 <= 32);
75    auto img1 = deserializer.readImage(data.get());
76    REPORTER_ASSERT(reporter, deep_equal(img.get(), img1.get()));
77
78    // try serializing the same image directly (again), check that it is the same!
79    data = serializer.writeImage(img.get());
80    size_t offset3 = data->size();
81    REPORTER_ASSERT(reporter, offset3 <= 32);
82    auto img2 = deserializer.readImage(data.get());
83    REPORTER_ASSERT(reporter, img1.get() == img2.get());
84}
85
86DEF_TEST(Pipe_image_draw_second, reporter) {
87    sk_sp<SkImage> img = GetResourceAsImage("mandrill_128.png");
88    SkASSERT(img.get());
89
90    SkPipeSerializer serializer;
91    SkPipeDeserializer deserializer;
92    SkDynamicMemoryWStream stream;
93
94    sk_sp<SkData> data = serializer.writeImage(img.get());
95    size_t offset0 = data->size();
96    REPORTER_ASSERT(reporter, offset0 > 100);   // the raw image must be sorta big
97    auto img1 = deserializer.readImage(data.get());
98
99    // The 2nd image should be nice and small
100    data = serializer.writeImage(img.get());
101    size_t offset1 = data->size();
102    REPORTER_ASSERT(reporter, offset1 <= 16);
103    auto img2 = deserializer.readImage(data.get());
104    REPORTER_ASSERT(reporter, img1.get() == img2.get());
105
106    // Now try drawing the image, it should also be small
107    SkCanvas* wc = serializer.beginWrite(SkRect::MakeWH(100, 100), &stream);
108    wc->drawImage(img, 0, 0, nullptr);
109    serializer.endWrite();
110    size_t offset2 = stream.bytesWritten();
111    REPORTER_ASSERT(reporter, offset2 <= 16);
112}
113
114DEF_TEST(Pipe_picture_draw_first, reporter) {
115    sk_sp<SkPicture> picture = []() {
116        SkPictureRecorder rec;
117        SkCanvas* c = rec.beginRecording(SkRect::MakeWH(100, 100));
118        for (int i = 0; i < 100; ++i) {
119            c->drawColor(i);
120        }
121        return rec.finishRecordingAsPicture();
122    }();
123    SkPipeSerializer serializer;
124    SkPipeDeserializer deserializer;
125
126    SkDynamicMemoryWStream stream;
127    SkCanvas* wc = serializer.beginWrite(SkRect::MakeWH(100, 100), &stream);
128    wc->drawPicture(picture);
129    serializer.endWrite();
130    size_t offset0 = stream.bytesWritten();
131    REPORTER_ASSERT(reporter, offset0 > 100);   // the raw picture must be sorta big
132    drain(&deserializer, &stream);
133
134    // try drawing the same picture again -- it should be much smaller
135    wc = serializer.beginWrite(SkRect::MakeWH(100, 100), &stream);
136    wc->drawPicture(picture);
137    size_t offset1 = stream.bytesWritten();
138    serializer.endWrite();
139    REPORTER_ASSERT(reporter, offset1 <= 16);
140    drain(&deserializer, &stream);
141
142    // try writing the picture directly, it should also be small
143    sk_sp<SkData> data = serializer.writePicture(picture.get());
144    size_t offset2 = data->size();
145    REPORTER_ASSERT(reporter, offset2 <= 16);
146    auto pic1 = deserializer.readPicture(data.get());
147
148    // try writing the picture directly, it should also be small
149    data = serializer.writePicture(picture.get());
150    size_t offset3 = data->size();
151    REPORTER_ASSERT(reporter, offset3 == offset2);
152    auto pic2 = deserializer.readPicture(data.get());
153    REPORTER_ASSERT(reporter, pic1.get() == pic2.get());
154}
155
156DEF_TEST(Pipe_picture_draw_second, reporter) {
157    sk_sp<SkPicture> picture = []() {
158        SkPictureRecorder rec;
159        SkCanvas* c = rec.beginRecording(SkRect::MakeWH(100, 100));
160        for (int i = 0; i < 100; ++i) {
161            c->drawColor(i);
162        }
163        return rec.finishRecordingAsPicture();
164    }();
165    SkPipeSerializer serializer;
166    SkPipeDeserializer deserializer;
167    SkDynamicMemoryWStream stream;
168
169    sk_sp<SkData> data = serializer.writePicture(picture.get());
170    size_t offset0 = data->size();
171    REPORTER_ASSERT(reporter, offset0 > 100);   // the raw picture must be sorta big
172    auto pic1 = deserializer.readPicture(data.get());
173
174    // The 2nd picture should be nice and small
175    data = serializer.writePicture(picture.get());
176    size_t offset1 = data->size();
177    REPORTER_ASSERT(reporter, offset1 <= 16);
178    auto pic2 = deserializer.readPicture(data.get());
179    SkASSERT(pic1.get() == pic2.get());
180
181    // Now try drawing the image, it should also be small
182    SkCanvas* wc = serializer.beginWrite(SkRect::MakeWH(100, 100), &stream);
183    wc->drawPicture(picture);
184    serializer.endWrite();
185    size_t offset2 = stream.bytesWritten();
186    REPORTER_ASSERT(reporter, offset2 <= 16);
187}
188