blob: b3200156c6170de6fb40920ba77cd6705b81e491 [file] [log] [blame]
halcanary8ee06f22015-08-11 10:30:12 -07001/*
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 */
commit-bot@chromium.org8c908272013-10-22 14:49:03 +00007#include "Test.h"
commit-bot@chromium.org8c908272013-10-22 14:49:03 +00008
halcanary712fdf72015-12-10 08:59:43 -08009#include "Resources.h"
commit-bot@chromium.org8c908272013-10-22 14:49:03 +000010#include "SkCanvas.h"
11#include "SkDocument.h"
12#include "SkOSFile.h"
Ben Wagnerbf111d72016-11-07 18:05:29 -050013#include "SkOSPath.h"
commit-bot@chromium.org8c908272013-10-22 14:49:03 +000014#include "SkStream.h"
halcanary712fdf72015-12-10 08:59:43 -080015#include "SkPixelSerializer.h"
commit-bot@chromium.org8c908272013-10-22 14:49:03 +000016
Hal Canarydb683012016-11-23 08:55:18 -070017#include "sk_tool_utils.h"
18
commit-bot@chromium.org8c908272013-10-22 14:49:03 +000019static void test_empty(skiatest::Reporter* reporter) {
20 SkDynamicMemoryWStream stream;
21
halcanary4b656662016-04-27 07:45:18 -070022 sk_sp<SkDocument> doc(SkDocument::MakePDF(&stream));
commit-bot@chromium.org8c908272013-10-22 14:49:03 +000023
24 doc->close();
25
26 REPORTER_ASSERT(reporter, stream.bytesWritten() == 0);
27}
28
29static void test_abort(skiatest::Reporter* reporter) {
30 SkDynamicMemoryWStream stream;
halcanary4b656662016-04-27 07:45:18 -070031 sk_sp<SkDocument> doc(SkDocument::MakePDF(&stream));
commit-bot@chromium.org8c908272013-10-22 14:49:03 +000032
33 SkCanvas* canvas = doc->beginPage(100, 100);
34 canvas->drawColor(SK_ColorRED);
35 doc->endPage();
36
37 doc->abort();
38
halcanary50e82e62016-03-21 13:45:05 -070039 // Test that only the header is written, not the full document.
40 REPORTER_ASSERT(reporter, stream.bytesWritten() < 256);
commit-bot@chromium.org8c908272013-10-22 14:49:03 +000041}
42
43static void test_abortWithFile(skiatest::Reporter* reporter) {
halcanary87f3ba42015-01-20 09:30:20 -080044 SkString tmpDir = skiatest::GetTmpDir();
commit-bot@chromium.org8c908272013-10-22 14:49:03 +000045
46 if (tmpDir.isEmpty()) {
47 return; // TODO(edisonn): unfortunatelly this pattern is used in other
48 // tests, but if GetTmpDir() starts returning and empty dir
49 // allways, then all these tests will be disabled.
50 }
51
tfarinaa8e2e152014-07-28 19:26:58 -070052 SkString path = SkOSPath::Join(tmpDir.c_str(), "aborted.pdf");
commit-bot@chromium.org8c908272013-10-22 14:49:03 +000053
54 // Make sure doc's destructor is called to flush.
55 {
halcanary4b656662016-04-27 07:45:18 -070056 sk_sp<SkDocument> doc(SkDocument::MakePDF(path.c_str()));
commit-bot@chromium.org8c908272013-10-22 14:49:03 +000057
58 SkCanvas* canvas = doc->beginPage(100, 100);
59 canvas->drawColor(SK_ColorRED);
60 doc->endPage();
61
62 doc->abort();
63 }
64
65 FILE* file = fopen(path.c_str(), "r");
Hal Canary399bbd92016-11-10 13:03:21 -050066 // Test that only the header is written, not the full document.
67 char buffer[256];
68 REPORTER_ASSERT(reporter, fread(buffer, 1, sizeof(buffer), file) < sizeof(buffer));
commit-bot@chromium.org8c908272013-10-22 14:49:03 +000069 fclose(file);
70}
71
72static void test_file(skiatest::Reporter* reporter) {
halcanary87f3ba42015-01-20 09:30:20 -080073 SkString tmpDir = skiatest::GetTmpDir();
commit-bot@chromium.org8c908272013-10-22 14:49:03 +000074 if (tmpDir.isEmpty()) {
75 return; // TODO(edisonn): unfortunatelly this pattern is used in other
76 // tests, but if GetTmpDir() starts returning and empty dir
77 // allways, then all these tests will be disabled.
78 }
79
tfarinaa8e2e152014-07-28 19:26:58 -070080 SkString path = SkOSPath::Join(tmpDir.c_str(), "file.pdf");
commit-bot@chromium.org8c908272013-10-22 14:49:03 +000081
halcanary4b656662016-04-27 07:45:18 -070082 sk_sp<SkDocument> doc(SkDocument::MakePDF(path.c_str()));
commit-bot@chromium.org8c908272013-10-22 14:49:03 +000083
84 SkCanvas* canvas = doc->beginPage(100, 100);
85
86 canvas->drawColor(SK_ColorRED);
87 doc->endPage();
88 doc->close();
89
90 FILE* file = fopen(path.c_str(), "r");
halcanary96fcdcc2015-08-27 07:41:13 -070091 REPORTER_ASSERT(reporter, file != nullptr);
commit-bot@chromium.org8c908272013-10-22 14:49:03 +000092 char header[100];
edisonn@google.com5237b7f2013-10-22 18:33:21 +000093 REPORTER_ASSERT(reporter, fread(header, 4, 1, file) != 0);
commit-bot@chromium.org8c908272013-10-22 14:49:03 +000094 REPORTER_ASSERT(reporter, strncmp(header, "%PDF", 4) == 0);
95 fclose(file);
96}
97
98static void test_close(skiatest::Reporter* reporter) {
99 SkDynamicMemoryWStream stream;
halcanary4b656662016-04-27 07:45:18 -0700100 sk_sp<SkDocument> doc(SkDocument::MakePDF(&stream));
commit-bot@chromium.org8c908272013-10-22 14:49:03 +0000101
102 SkCanvas* canvas = doc->beginPage(100, 100);
103 canvas->drawColor(SK_ColorRED);
104 doc->endPage();
105
106 doc->close();
107
108 REPORTER_ASSERT(reporter, stream.bytesWritten() != 0);
109}
110
halcanary57f744e2016-09-09 11:41:59 -0700111DEF_TEST(SkPDF_document_tests, reporter) {
halcanary2ccdb632015-08-11 13:35:12 -0700112 REQUIRE_PDF_DOCUMENT(document_tests, reporter);
commit-bot@chromium.org8c908272013-10-22 14:49:03 +0000113 test_empty(reporter);
114 test_abort(reporter);
115 test_abortWithFile(reporter);
116 test_file(reporter);
117 test_close(reporter);
118}
halcanary712fdf72015-12-10 08:59:43 -0800119
120namespace {
121class JPEGSerializer final : public SkPixelSerializer {
122 bool onUseEncodedData(const void*, size_t) override { return true; }
123 SkData* onEncode(const SkPixmap& pixmap) override {
Hal Canarydb683012016-11-23 08:55:18 -0700124 return sk_tool_utils::EncodeImageToData(pixmap, SkEncodedImageFormat::kJPEG, 85).release();
halcanary712fdf72015-12-10 08:59:43 -0800125 }
126};
127} // namespace
128
129size_t count_bytes(const SkBitmap& bm, bool useDCT) {
130 SkDynamicMemoryWStream stream;
halcanary4b656662016-04-27 07:45:18 -0700131 sk_sp<SkDocument> doc;
halcanary712fdf72015-12-10 08:59:43 -0800132 if (useDCT) {
halcanary4b656662016-04-27 07:45:18 -0700133 doc = SkDocument::MakePDF(&stream, SK_ScalarDefaultRasterDPI,
134 SkDocument::PDFMetadata(),
135 sk_make_sp<JPEGSerializer>(), false);
halcanary712fdf72015-12-10 08:59:43 -0800136 } else {
halcanary4b656662016-04-27 07:45:18 -0700137 doc = SkDocument::MakePDF(&stream);
halcanary712fdf72015-12-10 08:59:43 -0800138 }
139 SkCanvas* canvas = doc->beginPage(64, 64);
140 canvas->drawBitmap(bm, 0, 0);
141 doc->endPage();
142 doc->close();
143 return stream.bytesWritten();
144}
145
halcanary57f744e2016-09-09 11:41:59 -0700146DEF_TEST(SkPDF_document_dct_encoder, r) {
147 REQUIRE_PDF_DOCUMENT(SkPDF_document_dct_encoder, r);
halcanary712fdf72015-12-10 08:59:43 -0800148 SkBitmap bm;
149 if (GetResourceAsBitmap("mandrill_64.png", &bm)) {
150 // Lossy encoding works better on photographs.
151 REPORTER_ASSERT(r, count_bytes(bm, true) < count_bytes(bm, false));
152 }
153}
halcanary53b1c092016-01-06 09:02:25 -0800154
halcanary57f744e2016-09-09 11:41:59 -0700155DEF_TEST(SkPDF_document_skbug_4734, r) {
156 REQUIRE_PDF_DOCUMENT(SkPDF_document_skbug_4734, r);
halcanary53b1c092016-01-06 09:02:25 -0800157 SkDynamicMemoryWStream stream;
halcanary4b656662016-04-27 07:45:18 -0700158 sk_sp<SkDocument> doc(SkDocument::MakePDF(&stream));
halcanary53b1c092016-01-06 09:02:25 -0800159 SkCanvas* canvas = doc->beginPage(64, 64);
160 canvas->scale(10000.0f, 10000.0f);
161 canvas->translate(20.0f, 10.0f);
162 canvas->rotate(30.0f);
163 const char text[] = "HELLO";
164 canvas->drawText(text, strlen(text), 0, 0, SkPaint());
165}
halcanary57f744e2016-09-09 11:41:59 -0700166
167static bool contains(const uint8_t* result, size_t size, const char expectation[]) {
168 size_t len = strlen(expectation);
169 size_t N = 1 + size - len;
170 for (size_t i = 0; i < N; ++i) {
171 if (0 == memcmp(result + i, expectation, len)) {
172 return true;
173 }
174 }
175 return false;
176}
177
178// verify that the PDFA flag does something.
179DEF_TEST(SkPDF_pdfa_document, r) {
180 REQUIRE_PDF_DOCUMENT(SkPDF_pdfa_document, r);
181
182 SkDocument::PDFMetadata pdfMetadata;
183 pdfMetadata.fTitle = "test document";
184 pdfMetadata.fCreation.fEnabled = true;
185 pdfMetadata.fCreation.fDateTime = {0, 1999, 12, 5, 31, 23, 59, 59};
186
187 SkDynamicMemoryWStream buffer;
188 auto doc = SkDocument::MakePDF(&buffer, SK_ScalarDefaultRasterDPI,
189 pdfMetadata, nullptr, /* pdfa = */ true);
190 doc->beginPage(64, 64)->drawColor(SK_ColorRED);
191 doc->close();
reed42943c82016-09-12 12:01:44 -0700192 sk_sp<SkData> data(buffer.detachAsData());
193
halcanary57f744e2016-09-09 11:41:59 -0700194 static const char* expectations[] = {
195 "sRGB IEC61966-2.1",
196 "<dc:title><rdf:Alt><rdf:li xml:lang=\"x-default\">test document",
197 "<xmp:CreateDate>1999-12-31T23:59:59+00:00</xmp:CreateDate>",
198 "/Subtype /XML",
199 "/CreationDate (D:19991231235959+00'00')>>",
200 };
201 for (const char* expectation : expectations) {
202 if (!contains(data->bytes(), data->size(), expectation)) {
203 ERRORF(r, "PDFA expectation missing: '%s'.", expectation);
204 }
205 }
206 pdfMetadata.fProducer = "phoney library";
207 doc = SkDocument::MakePDF(&buffer, SK_ScalarDefaultRasterDPI,
208 pdfMetadata, nullptr, /* pdfa = */ true);
209 doc->beginPage(64, 64)->drawColor(SK_ColorRED);
210 doc->close();
reed42943c82016-09-12 12:01:44 -0700211 data = buffer.detachAsData();
halcanary57f744e2016-09-09 11:41:59 -0700212
213 static const char* moreExpectations[] = {
214 "/Producer (phoney library)",
215 "/ProductionLibrary (Skia/PDF m",
216 "<!-- <skia:ProductionLibrary>Skia/PDF m",
217 "<pdf:Producer>phoney library</pdf:Producer>",
218 };
219 for (const char* expectation : moreExpectations) {
220 if (!contains(data->bytes(), data->size(), expectation)) {
221 ERRORF(r, "PDFA expectation missing: '%s'.", expectation);
222 }
223 }
224}