1fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot/* 2fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * Copyright 2013 Google Inc. 3fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * 4fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * Use of this source code is governed by a BSD-style license that can be 5fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * found in the LICENSE file. 6fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot */ 7fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "Test.h" 8fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 9fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "Resources.h" 10fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkCanvas.h" 11fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkDocument.h" 12fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkOSFile.h" 13fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkOSPath.h" 14fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkStream.h" 15fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 16fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "sk_tool_utils.h" 17fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 18fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic void test_empty(skiatest::Reporter* reporter) { 19fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkDynamicMemoryWStream stream; 20fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 21fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot sk_sp<SkDocument> doc(SkDocument::MakePDF(&stream)); 22fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 23fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot doc->close(); 24fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 25fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot REPORTER_ASSERT(reporter, stream.bytesWritten() == 0); 26fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 27fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 28fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic void test_abort(skiatest::Reporter* reporter) { 29fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkDynamicMemoryWStream stream; 30fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot sk_sp<SkDocument> doc(SkDocument::MakePDF(&stream)); 31fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 32fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkCanvas* canvas = doc->beginPage(100, 100); 33fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot canvas->drawColor(SK_ColorRED); 34fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot doc->endPage(); 35fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 36fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot doc->abort(); 37fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 38fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // Test that only the header is written, not the full document. 39fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot REPORTER_ASSERT(reporter, stream.bytesWritten() < 256); 40fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 41fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 42fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic void test_abortWithFile(skiatest::Reporter* reporter) { 43fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkString tmpDir = skiatest::GetTmpDir(); 44fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 45fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (tmpDir.isEmpty()) { 46fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot ERRORF(reporter, "missing tmpDir."); 47fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return; 48fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 49fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 50fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkString path = SkOSPath::Join(tmpDir.c_str(), "aborted.pdf"); 51fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (!SkFILEWStream(path.c_str()).isValid()) { 52fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot ERRORF(reporter, "unable to write to: %s", path.c_str()); 53fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return; 54fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 55fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 56fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // Make sure doc's destructor is called to flush. 57fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot { 58fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkFILEWStream stream(path.c_str()); 59fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot sk_sp<SkDocument> doc = SkDocument::MakePDF(&stream); 60fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 61fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkCanvas* canvas = doc->beginPage(100, 100); 62fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot canvas->drawColor(SK_ColorRED); 63fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot doc->endPage(); 64fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 65fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot doc->abort(); 66fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 67fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 68fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot FILE* file = fopen(path.c_str(), "r"); 69fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // Test that only the header is written, not the full document. 70fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot char buffer[256]; 71fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot REPORTER_ASSERT(reporter, fread(buffer, 1, sizeof(buffer), file) < sizeof(buffer)); 72fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fclose(file); 73fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 74fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 75fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic void test_file(skiatest::Reporter* reporter) { 76fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkString tmpDir = skiatest::GetTmpDir(); 77fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (tmpDir.isEmpty()) { 78fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot ERRORF(reporter, "missing tmpDir."); 79fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return; 80fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 81fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 82fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkString path = SkOSPath::Join(tmpDir.c_str(), "file.pdf"); 83fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (!SkFILEWStream(path.c_str()).isValid()) { 84fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot ERRORF(reporter, "unable to write to: %s", path.c_str()); 85fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return; 86fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 87fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 88fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot { 89fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkFILEWStream stream(path.c_str()); 90fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot sk_sp<SkDocument> doc = SkDocument::MakePDF(&stream); 91fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkCanvas* canvas = doc->beginPage(100, 100); 92fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 93fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot canvas->drawColor(SK_ColorRED); 94fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot doc->endPage(); 95fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot doc->close(); 96fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 97fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 98fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot FILE* file = fopen(path.c_str(), "r"); 99fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot REPORTER_ASSERT(reporter, file != nullptr); 100fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot char header[100]; 101fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot REPORTER_ASSERT(reporter, fread(header, 4, 1, file) != 0); 102fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot REPORTER_ASSERT(reporter, strncmp(header, "%PDF", 4) == 0); 103fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot fclose(file); 104fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 105fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 106fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic void test_close(skiatest::Reporter* reporter) { 107fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkDynamicMemoryWStream stream; 108fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot sk_sp<SkDocument> doc(SkDocument::MakePDF(&stream)); 109fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 110fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkCanvas* canvas = doc->beginPage(100, 100); 111fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot canvas->drawColor(SK_ColorRED); 112fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot doc->endPage(); 113fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 114fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot doc->close(); 115fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 116fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot REPORTER_ASSERT(reporter, stream.bytesWritten() != 0); 117fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 118fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 119fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotDEF_TEST(SkPDF_document_tests, reporter) { 120fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot REQUIRE_PDF_DOCUMENT(document_tests, reporter); 121fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot test_empty(reporter); 122fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot test_abort(reporter); 123fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot test_abortWithFile(reporter); 124fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot test_file(reporter); 125fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot test_close(reporter); 126fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 127fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 128fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotDEF_TEST(SkPDF_document_skbug_4734, r) { 129fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot REQUIRE_PDF_DOCUMENT(SkPDF_document_skbug_4734, r); 130fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkDynamicMemoryWStream stream; 131fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot sk_sp<SkDocument> doc(SkDocument::MakePDF(&stream)); 132fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkCanvas* canvas = doc->beginPage(64, 64); 133fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot canvas->scale(10000.0f, 10000.0f); 134fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot canvas->translate(20.0f, 10.0f); 135fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot canvas->rotate(30.0f); 136fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot const char text[] = "HELLO"; 137fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot canvas->drawString(text, 0, 0, SkPaint()); 138fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 139fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 140fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic bool contains(const uint8_t* result, size_t size, const char expectation[]) { 141fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot size_t len = strlen(expectation); 142fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot size_t N = 1 + size - len; 143fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot for (size_t i = 0; i < N; ++i) { 144fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (0 == memcmp(result + i, expectation, len)) { 145fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return true; 146fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 147fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 148fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return false; 149fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 150fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 151fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// verify that the PDFA flag does something. 152fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotDEF_TEST(SkPDF_pdfa_document, r) { 153fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot REQUIRE_PDF_DOCUMENT(SkPDF_pdfa_document, r); 154fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 155fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkDocument::PDFMetadata pdfMetadata; 156fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot pdfMetadata.fTitle = "test document"; 157fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot pdfMetadata.fCreation.fEnabled = true; 158fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot pdfMetadata.fCreation.fDateTime = {0, 1999, 12, 5, 31, 23, 59, 59}; 159fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot pdfMetadata.fPDFA = true; 160fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 161fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkDynamicMemoryWStream buffer; 162fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot auto doc = SkDocument::MakePDF(&buffer, pdfMetadata); 163fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot doc->beginPage(64, 64)->drawColor(SK_ColorRED); 164fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot doc->close(); 165fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot sk_sp<SkData> data(buffer.detachAsData()); 166fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 167fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot static const char* expectations[] = { 168fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot "sRGB IEC61966-2.1", 169fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot "<dc:title><rdf:Alt><rdf:li xml:lang=\"x-default\">test document", 170fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot "<xmp:CreateDate>1999-12-31T23:59:59+00:00</xmp:CreateDate>", 171fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot "/Subtype /XML", 172fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot "/CreationDate (D:19991231235959+00'00')>>", 173fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot }; 174fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot for (const char* expectation : expectations) { 175fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (!contains(data->bytes(), data->size(), expectation)) { 176fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot ERRORF(r, "PDFA expectation missing: '%s'.", expectation); 177fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 178fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 179fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot pdfMetadata.fProducer = "phoney library"; 180fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot pdfMetadata.fPDFA = true; 181fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot doc = SkDocument::MakePDF(&buffer, pdfMetadata); 182fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot doc->beginPage(64, 64)->drawColor(SK_ColorRED); 183fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot doc->close(); 184fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot data = buffer.detachAsData(); 185fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 186fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot static const char* moreExpectations[] = { 187fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot "/Producer (phoney library)", 188fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot "/ProductionLibrary (Skia/PDF m", 189fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot "<!-- <skia:ProductionLibrary>Skia/PDF m", 190fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot "<pdf:Producer>phoney library</pdf:Producer>", 191fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot }; 192fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot for (const char* expectation : moreExpectations) { 193fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (!contains(data->bytes(), data->size(), expectation)) { 194fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot ERRORF(r, "PDFA expectation missing: '%s'.", expectation); 195fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 196fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 197fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 198