halcanary | 8ee06f2 | 2015-08-11 10:30:12 -0700 | [diff] [blame] | 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 | */ |
commit-bot@chromium.org | 8c90827 | 2013-10-22 14:49:03 +0000 | [diff] [blame] | 7 | #include "Test.h" |
commit-bot@chromium.org | 8c90827 | 2013-10-22 14:49:03 +0000 | [diff] [blame] | 8 | |
halcanary | 712fdf7 | 2015-12-10 08:59:43 -0800 | [diff] [blame] | 9 | #include "Resources.h" |
commit-bot@chromium.org | 8c90827 | 2013-10-22 14:49:03 +0000 | [diff] [blame] | 10 | #include "SkCanvas.h" |
| 11 | #include "SkDocument.h" |
| 12 | #include "SkOSFile.h" |
Ben Wagner | bf111d7 | 2016-11-07 18:05:29 -0500 | [diff] [blame] | 13 | #include "SkOSPath.h" |
commit-bot@chromium.org | 8c90827 | 2013-10-22 14:49:03 +0000 | [diff] [blame] | 14 | #include "SkStream.h" |
| 15 | |
Hal Canary | db68301 | 2016-11-23 08:55:18 -0700 | [diff] [blame] | 16 | #include "sk_tool_utils.h" |
| 17 | |
commit-bot@chromium.org | 8c90827 | 2013-10-22 14:49:03 +0000 | [diff] [blame] | 18 | static void test_empty(skiatest::Reporter* reporter) { |
| 19 | SkDynamicMemoryWStream stream; |
| 20 | |
halcanary | 4b65666 | 2016-04-27 07:45:18 -0700 | [diff] [blame] | 21 | sk_sp<SkDocument> doc(SkDocument::MakePDF(&stream)); |
commit-bot@chromium.org | 8c90827 | 2013-10-22 14:49:03 +0000 | [diff] [blame] | 22 | |
| 23 | doc->close(); |
| 24 | |
| 25 | REPORTER_ASSERT(reporter, stream.bytesWritten() == 0); |
| 26 | } |
| 27 | |
| 28 | static void test_abort(skiatest::Reporter* reporter) { |
| 29 | SkDynamicMemoryWStream stream; |
halcanary | 4b65666 | 2016-04-27 07:45:18 -0700 | [diff] [blame] | 30 | sk_sp<SkDocument> doc(SkDocument::MakePDF(&stream)); |
commit-bot@chromium.org | 8c90827 | 2013-10-22 14:49:03 +0000 | [diff] [blame] | 31 | |
| 32 | SkCanvas* canvas = doc->beginPage(100, 100); |
| 33 | canvas->drawColor(SK_ColorRED); |
| 34 | doc->endPage(); |
| 35 | |
| 36 | doc->abort(); |
| 37 | |
halcanary | 50e82e6 | 2016-03-21 13:45:05 -0700 | [diff] [blame] | 38 | // Test that only the header is written, not the full document. |
| 39 | REPORTER_ASSERT(reporter, stream.bytesWritten() < 256); |
commit-bot@chromium.org | 8c90827 | 2013-10-22 14:49:03 +0000 | [diff] [blame] | 40 | } |
| 41 | |
| 42 | static void test_abortWithFile(skiatest::Reporter* reporter) { |
halcanary | 87f3ba4 | 2015-01-20 09:30:20 -0800 | [diff] [blame] | 43 | SkString tmpDir = skiatest::GetTmpDir(); |
commit-bot@chromium.org | 8c90827 | 2013-10-22 14:49:03 +0000 | [diff] [blame] | 44 | |
| 45 | if (tmpDir.isEmpty()) { |
Hal Canary | 925e31e | 2017-12-11 14:42:58 -0500 | [diff] [blame] | 46 | ERRORF(reporter, "missing tmpDir."); |
| 47 | return; |
commit-bot@chromium.org | 8c90827 | 2013-10-22 14:49:03 +0000 | [diff] [blame] | 48 | } |
| 49 | |
tfarina | a8e2e15 | 2014-07-28 19:26:58 -0700 | [diff] [blame] | 50 | SkString path = SkOSPath::Join(tmpDir.c_str(), "aborted.pdf"); |
Hal Canary | 925e31e | 2017-12-11 14:42:58 -0500 | [diff] [blame] | 51 | if (!SkFILEWStream(path.c_str()).isValid()) { |
| 52 | ERRORF(reporter, "unable to write to: %s", path.c_str()); |
| 53 | return; |
| 54 | } |
commit-bot@chromium.org | 8c90827 | 2013-10-22 14:49:03 +0000 | [diff] [blame] | 55 | |
| 56 | // Make sure doc's destructor is called to flush. |
| 57 | { |
Mike Reed | a4daf19 | 2017-12-14 13:25:04 -0500 | [diff] [blame] | 58 | SkFILEWStream stream(path.c_str()); |
| 59 | sk_sp<SkDocument> doc = SkDocument::MakePDF(&stream); |
commit-bot@chromium.org | 8c90827 | 2013-10-22 14:49:03 +0000 | [diff] [blame] | 60 | |
| 61 | SkCanvas* canvas = doc->beginPage(100, 100); |
| 62 | canvas->drawColor(SK_ColorRED); |
| 63 | doc->endPage(); |
| 64 | |
| 65 | doc->abort(); |
| 66 | } |
| 67 | |
| 68 | FILE* file = fopen(path.c_str(), "r"); |
Hal Canary | 399bbd9 | 2016-11-10 13:03:21 -0500 | [diff] [blame] | 69 | // Test that only the header is written, not the full document. |
| 70 | char buffer[256]; |
| 71 | REPORTER_ASSERT(reporter, fread(buffer, 1, sizeof(buffer), file) < sizeof(buffer)); |
commit-bot@chromium.org | 8c90827 | 2013-10-22 14:49:03 +0000 | [diff] [blame] | 72 | fclose(file); |
| 73 | } |
| 74 | |
| 75 | static void test_file(skiatest::Reporter* reporter) { |
halcanary | 87f3ba4 | 2015-01-20 09:30:20 -0800 | [diff] [blame] | 76 | SkString tmpDir = skiatest::GetTmpDir(); |
commit-bot@chromium.org | 8c90827 | 2013-10-22 14:49:03 +0000 | [diff] [blame] | 77 | if (tmpDir.isEmpty()) { |
Hal Canary | 925e31e | 2017-12-11 14:42:58 -0500 | [diff] [blame] | 78 | ERRORF(reporter, "missing tmpDir."); |
| 79 | return; |
commit-bot@chromium.org | 8c90827 | 2013-10-22 14:49:03 +0000 | [diff] [blame] | 80 | } |
| 81 | |
tfarina | a8e2e15 | 2014-07-28 19:26:58 -0700 | [diff] [blame] | 82 | SkString path = SkOSPath::Join(tmpDir.c_str(), "file.pdf"); |
Hal Canary | 925e31e | 2017-12-11 14:42:58 -0500 | [diff] [blame] | 83 | if (!SkFILEWStream(path.c_str()).isValid()) { |
| 84 | ERRORF(reporter, "unable to write to: %s", path.c_str()); |
| 85 | return; |
| 86 | } |
commit-bot@chromium.org | 8c90827 | 2013-10-22 14:49:03 +0000 | [diff] [blame] | 87 | |
Mike Reed | a4daf19 | 2017-12-14 13:25:04 -0500 | [diff] [blame] | 88 | { |
| 89 | SkFILEWStream stream(path.c_str()); |
| 90 | sk_sp<SkDocument> doc = SkDocument::MakePDF(&stream); |
| 91 | SkCanvas* canvas = doc->beginPage(100, 100); |
commit-bot@chromium.org | 8c90827 | 2013-10-22 14:49:03 +0000 | [diff] [blame] | 92 | |
Mike Reed | a4daf19 | 2017-12-14 13:25:04 -0500 | [diff] [blame] | 93 | canvas->drawColor(SK_ColorRED); |
| 94 | doc->endPage(); |
| 95 | doc->close(); |
| 96 | } |
commit-bot@chromium.org | 8c90827 | 2013-10-22 14:49:03 +0000 | [diff] [blame] | 97 | |
| 98 | FILE* file = fopen(path.c_str(), "r"); |
halcanary | 96fcdcc | 2015-08-27 07:41:13 -0700 | [diff] [blame] | 99 | REPORTER_ASSERT(reporter, file != nullptr); |
commit-bot@chromium.org | 8c90827 | 2013-10-22 14:49:03 +0000 | [diff] [blame] | 100 | char header[100]; |
edisonn@google.com | 5237b7f | 2013-10-22 18:33:21 +0000 | [diff] [blame] | 101 | REPORTER_ASSERT(reporter, fread(header, 4, 1, file) != 0); |
commit-bot@chromium.org | 8c90827 | 2013-10-22 14:49:03 +0000 | [diff] [blame] | 102 | REPORTER_ASSERT(reporter, strncmp(header, "%PDF", 4) == 0); |
| 103 | fclose(file); |
| 104 | } |
| 105 | |
| 106 | static void test_close(skiatest::Reporter* reporter) { |
| 107 | SkDynamicMemoryWStream stream; |
halcanary | 4b65666 | 2016-04-27 07:45:18 -0700 | [diff] [blame] | 108 | sk_sp<SkDocument> doc(SkDocument::MakePDF(&stream)); |
commit-bot@chromium.org | 8c90827 | 2013-10-22 14:49:03 +0000 | [diff] [blame] | 109 | |
| 110 | SkCanvas* canvas = doc->beginPage(100, 100); |
| 111 | canvas->drawColor(SK_ColorRED); |
| 112 | doc->endPage(); |
| 113 | |
| 114 | doc->close(); |
| 115 | |
| 116 | REPORTER_ASSERT(reporter, stream.bytesWritten() != 0); |
| 117 | } |
| 118 | |
halcanary | 57f744e | 2016-09-09 11:41:59 -0700 | [diff] [blame] | 119 | DEF_TEST(SkPDF_document_tests, reporter) { |
halcanary | 2ccdb63 | 2015-08-11 13:35:12 -0700 | [diff] [blame] | 120 | REQUIRE_PDF_DOCUMENT(document_tests, reporter); |
commit-bot@chromium.org | 8c90827 | 2013-10-22 14:49:03 +0000 | [diff] [blame] | 121 | test_empty(reporter); |
| 122 | test_abort(reporter); |
| 123 | test_abortWithFile(reporter); |
| 124 | test_file(reporter); |
| 125 | test_close(reporter); |
| 126 | } |
halcanary | 712fdf7 | 2015-12-10 08:59:43 -0800 | [diff] [blame] | 127 | |
halcanary | 57f744e | 2016-09-09 11:41:59 -0700 | [diff] [blame] | 128 | DEF_TEST(SkPDF_document_skbug_4734, r) { |
| 129 | REQUIRE_PDF_DOCUMENT(SkPDF_document_skbug_4734, r); |
halcanary | 53b1c09 | 2016-01-06 09:02:25 -0800 | [diff] [blame] | 130 | SkDynamicMemoryWStream stream; |
halcanary | 4b65666 | 2016-04-27 07:45:18 -0700 | [diff] [blame] | 131 | sk_sp<SkDocument> doc(SkDocument::MakePDF(&stream)); |
halcanary | 53b1c09 | 2016-01-06 09:02:25 -0800 | [diff] [blame] | 132 | SkCanvas* canvas = doc->beginPage(64, 64); |
| 133 | canvas->scale(10000.0f, 10000.0f); |
| 134 | canvas->translate(20.0f, 10.0f); |
| 135 | canvas->rotate(30.0f); |
| 136 | const char text[] = "HELLO"; |
Cary Clark | 2a475ea | 2017-04-28 15:35:12 -0400 | [diff] [blame] | 137 | canvas->drawString(text, 0, 0, SkPaint()); |
halcanary | 53b1c09 | 2016-01-06 09:02:25 -0800 | [diff] [blame] | 138 | } |
halcanary | 57f744e | 2016-09-09 11:41:59 -0700 | [diff] [blame] | 139 | |
| 140 | static bool contains(const uint8_t* result, size_t size, const char expectation[]) { |
| 141 | size_t len = strlen(expectation); |
| 142 | size_t N = 1 + size - len; |
| 143 | for (size_t i = 0; i < N; ++i) { |
| 144 | if (0 == memcmp(result + i, expectation, len)) { |
| 145 | return true; |
| 146 | } |
| 147 | } |
| 148 | return false; |
| 149 | } |
| 150 | |
| 151 | // verify that the PDFA flag does something. |
| 152 | DEF_TEST(SkPDF_pdfa_document, r) { |
| 153 | REQUIRE_PDF_DOCUMENT(SkPDF_pdfa_document, r); |
| 154 | |
| 155 | SkDocument::PDFMetadata pdfMetadata; |
| 156 | pdfMetadata.fTitle = "test document"; |
| 157 | pdfMetadata.fCreation.fEnabled = true; |
| 158 | pdfMetadata.fCreation.fDateTime = {0, 1999, 12, 5, 31, 23, 59, 59}; |
Mike Reed | a4daf19 | 2017-12-14 13:25:04 -0500 | [diff] [blame] | 159 | pdfMetadata.fPDFA = true; |
halcanary | 57f744e | 2016-09-09 11:41:59 -0700 | [diff] [blame] | 160 | |
| 161 | SkDynamicMemoryWStream buffer; |
Mike Reed | a4daf19 | 2017-12-14 13:25:04 -0500 | [diff] [blame] | 162 | auto doc = SkDocument::MakePDF(&buffer, pdfMetadata); |
halcanary | 57f744e | 2016-09-09 11:41:59 -0700 | [diff] [blame] | 163 | doc->beginPage(64, 64)->drawColor(SK_ColorRED); |
| 164 | doc->close(); |
reed | 42943c8 | 2016-09-12 12:01:44 -0700 | [diff] [blame] | 165 | sk_sp<SkData> data(buffer.detachAsData()); |
| 166 | |
halcanary | 57f744e | 2016-09-09 11:41:59 -0700 | [diff] [blame] | 167 | static const char* expectations[] = { |
| 168 | "sRGB IEC61966-2.1", |
| 169 | "<dc:title><rdf:Alt><rdf:li xml:lang=\"x-default\">test document", |
| 170 | "<xmp:CreateDate>1999-12-31T23:59:59+00:00</xmp:CreateDate>", |
| 171 | "/Subtype /XML", |
| 172 | "/CreationDate (D:19991231235959+00'00')>>", |
| 173 | }; |
| 174 | for (const char* expectation : expectations) { |
| 175 | if (!contains(data->bytes(), data->size(), expectation)) { |
| 176 | ERRORF(r, "PDFA expectation missing: '%s'.", expectation); |
| 177 | } |
| 178 | } |
| 179 | pdfMetadata.fProducer = "phoney library"; |
Mike Reed | a4daf19 | 2017-12-14 13:25:04 -0500 | [diff] [blame] | 180 | pdfMetadata.fPDFA = true; |
| 181 | doc = SkDocument::MakePDF(&buffer, pdfMetadata); |
halcanary | 57f744e | 2016-09-09 11:41:59 -0700 | [diff] [blame] | 182 | doc->beginPage(64, 64)->drawColor(SK_ColorRED); |
| 183 | doc->close(); |
reed | 42943c8 | 2016-09-12 12:01:44 -0700 | [diff] [blame] | 184 | data = buffer.detachAsData(); |
halcanary | 57f744e | 2016-09-09 11:41:59 -0700 | [diff] [blame] | 185 | |
| 186 | static const char* moreExpectations[] = { |
| 187 | "/Producer (phoney library)", |
| 188 | "/ProductionLibrary (Skia/PDF m", |
| 189 | "<!-- <skia:ProductionLibrary>Skia/PDF m", |
| 190 | "<pdf:Producer>phoney library</pdf:Producer>", |
| 191 | }; |
| 192 | for (const char* expectation : moreExpectations) { |
| 193 | if (!contains(data->bytes(), data->size(), expectation)) { |
| 194 | ERRORF(r, "PDFA expectation missing: '%s'.", expectation); |
| 195 | } |
| 196 | } |
| 197 | } |
Hal Canary | 691fd1b | 2018-02-28 14:10:42 -0500 | [diff] [blame] | 198 | |
| 199 | |
| 200 | DEF_TEST(SkPDF_unicode_metadata, r) { |
| 201 | REQUIRE_PDF_DOCUMENT(SkPDF_unicode_metadata, r); |
| 202 | SkDocument::PDFMetadata pdfMetadata; |
| 203 | pdfMetadata.fTitle = "πππππ πππππ"; // Out of basic multilingual plane |
| 204 | pdfMetadata.fAuthor = "ABCDE FGHIJ"; // ASCII |
| 205 | pdfMetadata.fSubject = "αβγδΡ ΢ηθικ"; // inside basic multilingual plane |
| 206 | pdfMetadata.fPDFA = true; |
| 207 | SkDynamicMemoryWStream wStream; |
| 208 | { |
| 209 | auto doc = SkDocument::MakePDF(&wStream, pdfMetadata); |
| 210 | doc->beginPage(612, 792)->drawColor(SK_ColorCYAN); |
| 211 | } |
| 212 | sk_sp<SkData> data(wStream.detachAsData()); |
| 213 | static const char* expectations[] = { |
| 214 | "<</Title <FEFFD835DCD0D835DCD1D835DCD2D835DCD3D835DCD40020" |
| 215 | "D835DCD5D835DCD6D835DCD7D835DCD8D835DCD9>", |
| 216 | "/Author (ABCDE FGHIJ)", |
| 217 | "Subject <FEFF03B103B203B303B403B5002003B603B703B803B903BA>", |
| 218 | }; |
| 219 | for (const char* expectation : expectations) { |
| 220 | if (!contains(data->bytes(), data->size(), expectation)) { |
| 221 | ERRORF(r, "PDF expectation missing: '%s'.", expectation); |
| 222 | } |
| 223 | } |
| 224 | } |