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 #include "Test.h" 8 9 #include "Resources.h" 10 #include "SkCanvas.h" 11 #include "SkDocument.h" 12 #include "SkOSFile.h" 13 #include "SkOSPath.h" 14 #include "SkStream.h" 15 16 #include "sk_tool_utils.h" 17 18 static void test_empty(skiatest::Reporter* reporter) { 19 SkDynamicMemoryWStream stream; 20 21 sk_sp<SkDocument> doc(SkDocument::MakePDF(&stream)); 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; 30 sk_sp<SkDocument> doc(SkDocument::MakePDF(&stream)); 31 32 SkCanvas* canvas = doc->beginPage(100, 100); 33 canvas->drawColor(SK_ColorRED); 34 doc->endPage(); 35 36 doc->abort(); 37 38 // Test that only the header is written, not the full document. 39 REPORTER_ASSERT(reporter, stream.bytesWritten() < 256); 40 } 41 42 static void test_abortWithFile(skiatest::Reporter* reporter) { 43 SkString tmpDir = skiatest::GetTmpDir(); 44 45 if (tmpDir.isEmpty()) { 46 ERRORF(reporter, "missing tmpDir."); 47 return; 48 } 49 50 SkString path = SkOSPath::Join(tmpDir.c_str(), "aborted.pdf"); 51 if (!SkFILEWStream(path.c_str()).isValid()) { 52 ERRORF(reporter, "unable to write to: %s", path.c_str()); 53 return; 54 } 55 56 // Make sure doc's destructor is called to flush. 57 { 58 SkFILEWStream stream(path.c_str()); 59 sk_sp<SkDocument> doc = SkDocument::MakePDF(&stream); 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"); 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)); 72 fclose(file); 73 } 74 75 static void test_file(skiatest::Reporter* reporter) { 76 SkString tmpDir = skiatest::GetTmpDir(); 77 if (tmpDir.isEmpty()) { 78 ERRORF(reporter, "missing tmpDir."); 79 return; 80 } 81 82 SkString path = SkOSPath::Join(tmpDir.c_str(), "file.pdf"); 83 if (!SkFILEWStream(path.c_str()).isValid()) { 84 ERRORF(reporter, "unable to write to: %s", path.c_str()); 85 return; 86 } 87 88 { 89 SkFILEWStream stream(path.c_str()); 90 sk_sp<SkDocument> doc = SkDocument::MakePDF(&stream); 91 SkCanvas* canvas = doc->beginPage(100, 100); 92 93 canvas->drawColor(SK_ColorRED); 94 doc->endPage(); 95 doc->close(); 96 } 97 98 FILE* file = fopen(path.c_str(), "r"); 99 REPORTER_ASSERT(reporter, file != nullptr); 100 char header[100]; 101 REPORTER_ASSERT(reporter, fread(header, 4, 1, file) != 0); 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; 108 sk_sp<SkDocument> doc(SkDocument::MakePDF(&stream)); 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 119 DEF_TEST(SkPDF_document_tests, reporter) { 120 REQUIRE_PDF_DOCUMENT(document_tests, reporter); 121 test_empty(reporter); 122 test_abort(reporter); 123 test_abortWithFile(reporter); 124 test_file(reporter); 125 test_close(reporter); 126 } 127 128 DEF_TEST(SkPDF_document_skbug_4734, r) { 129 REQUIRE_PDF_DOCUMENT(SkPDF_document_skbug_4734, r); 130 SkDynamicMemoryWStream stream; 131 sk_sp<SkDocument> doc(SkDocument::MakePDF(&stream)); 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"; 137 canvas->drawString(text, 0, 0, SkPaint()); 138 } 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}; 159 pdfMetadata.fPDFA = true; 160 161 SkDynamicMemoryWStream buffer; 162 auto doc = SkDocument::MakePDF(&buffer, pdfMetadata); 163 doc->beginPage(64, 64)->drawColor(SK_ColorRED); 164 doc->close(); 165 sk_sp<SkData> data(buffer.detachAsData()); 166 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"; 180 pdfMetadata.fPDFA = true; 181 doc = SkDocument::MakePDF(&buffer, pdfMetadata); 182 doc->beginPage(64, 64)->drawColor(SK_ColorRED); 183 doc->close(); 184 data = buffer.detachAsData(); 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 } 198