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 "SkStream.h"
14 #include "SkPixelSerializer.h"
15
test_empty(skiatest::Reporter * reporter)16 static void test_empty(skiatest::Reporter* reporter) {
17 SkDynamicMemoryWStream stream;
18
19 SkAutoTUnref<SkDocument> doc(SkDocument::CreatePDF(&stream));
20
21 doc->close();
22
23 REPORTER_ASSERT(reporter, stream.bytesWritten() == 0);
24 }
25
test_abort(skiatest::Reporter * reporter)26 static void test_abort(skiatest::Reporter* reporter) {
27 SkDynamicMemoryWStream stream;
28 SkAutoTUnref<SkDocument> doc(SkDocument::CreatePDF(&stream));
29
30 SkCanvas* canvas = doc->beginPage(100, 100);
31 canvas->drawColor(SK_ColorRED);
32 doc->endPage();
33
34 doc->abort();
35
36 REPORTER_ASSERT(reporter, stream.bytesWritten() == 0);
37 }
38
test_abortWithFile(skiatest::Reporter * reporter)39 static void test_abortWithFile(skiatest::Reporter* reporter) {
40 SkString tmpDir = skiatest::GetTmpDir();
41
42 if (tmpDir.isEmpty()) {
43 return; // TODO(edisonn): unfortunatelly this pattern is used in other
44 // tests, but if GetTmpDir() starts returning and empty dir
45 // allways, then all these tests will be disabled.
46 }
47
48 SkString path = SkOSPath::Join(tmpDir.c_str(), "aborted.pdf");
49
50 // Make sure doc's destructor is called to flush.
51 {
52 SkAutoTUnref<SkDocument> doc(SkDocument::CreatePDF(path.c_str()));
53
54 SkCanvas* canvas = doc->beginPage(100, 100);
55 canvas->drawColor(SK_ColorRED);
56 doc->endPage();
57
58 doc->abort();
59 }
60
61 FILE* file = fopen(path.c_str(), "r");
62 // The created file should be empty.
63 char buffer[100];
64 REPORTER_ASSERT(reporter, fread(buffer, 1, 1, file) == 0);
65 fclose(file);
66 }
67
test_file(skiatest::Reporter * reporter)68 static void test_file(skiatest::Reporter* reporter) {
69 SkString tmpDir = skiatest::GetTmpDir();
70 if (tmpDir.isEmpty()) {
71 return; // TODO(edisonn): unfortunatelly this pattern is used in other
72 // tests, but if GetTmpDir() starts returning and empty dir
73 // allways, then all these tests will be disabled.
74 }
75
76 SkString path = SkOSPath::Join(tmpDir.c_str(), "file.pdf");
77
78 SkAutoTUnref<SkDocument> doc(SkDocument::CreatePDF(path.c_str()));
79
80 SkCanvas* canvas = doc->beginPage(100, 100);
81
82 canvas->drawColor(SK_ColorRED);
83 doc->endPage();
84 doc->close();
85
86 FILE* file = fopen(path.c_str(), "r");
87 REPORTER_ASSERT(reporter, file != nullptr);
88 char header[100];
89 REPORTER_ASSERT(reporter, fread(header, 4, 1, file) != 0);
90 REPORTER_ASSERT(reporter, strncmp(header, "%PDF", 4) == 0);
91 fclose(file);
92 }
93
test_close(skiatest::Reporter * reporter)94 static void test_close(skiatest::Reporter* reporter) {
95 SkDynamicMemoryWStream stream;
96 SkAutoTUnref<SkDocument> doc(SkDocument::CreatePDF(&stream));
97
98 SkCanvas* canvas = doc->beginPage(100, 100);
99 canvas->drawColor(SK_ColorRED);
100 doc->endPage();
101
102 doc->close();
103
104 REPORTER_ASSERT(reporter, stream.bytesWritten() != 0);
105 }
106
DEF_TEST(document_tests,reporter)107 DEF_TEST(document_tests, reporter) {
108 REQUIRE_PDF_DOCUMENT(document_tests, reporter);
109 test_empty(reporter);
110 test_abort(reporter);
111 test_abortWithFile(reporter);
112 test_file(reporter);
113 test_close(reporter);
114 }
115
116 namespace {
117 class JPEGSerializer final : public SkPixelSerializer {
onUseEncodedData(const void *,size_t)118 bool onUseEncodedData(const void*, size_t) override { return true; }
onEncode(const SkPixmap & pixmap)119 SkData* onEncode(const SkPixmap& pixmap) override {
120 SkBitmap bm;
121 return bm.installPixels(pixmap.info(),
122 pixmap.writable_addr(),
123 pixmap.rowBytes(),
124 pixmap.ctable(),
125 nullptr, nullptr)
126 ? SkImageEncoder::EncodeData(bm, SkImageEncoder::kJPEG_Type, 85)
127 : nullptr;
128 }
129 };
130 } // namespace
131
count_bytes(const SkBitmap & bm,bool useDCT)132 size_t count_bytes(const SkBitmap& bm, bool useDCT) {
133 SkDynamicMemoryWStream stream;
134 SkAutoTUnref<SkDocument> doc;
135 if (useDCT) {
136 SkAutoTUnref<SkPixelSerializer> serializer(new JPEGSerializer);
137 doc.reset(SkDocument::CreatePDF(
138 &stream, SK_ScalarDefaultRasterDPI, serializer));
139 } else {
140 doc.reset(SkDocument::CreatePDF(&stream));
141 }
142 SkCanvas* canvas = doc->beginPage(64, 64);
143 canvas->drawBitmap(bm, 0, 0);
144 doc->endPage();
145 doc->close();
146 return stream.bytesWritten();
147 }
148
DEF_TEST(document_dct_encoder,r)149 DEF_TEST(document_dct_encoder, r) {
150 REQUIRE_PDF_DOCUMENT(document_dct_encoder, r);
151 SkBitmap bm;
152 if (GetResourceAsBitmap("mandrill_64.png", &bm)) {
153 // Lossy encoding works better on photographs.
154 REPORTER_ASSERT(r, count_bytes(bm, true) < count_bytes(bm, false));
155 }
156 }
157
DEF_TEST(document_skbug_4734,r)158 DEF_TEST(document_skbug_4734, r) {
159 REQUIRE_PDF_DOCUMENT(document_skbug_4734, r);
160 SkDynamicMemoryWStream stream;
161 SkAutoTUnref<SkDocument> doc(SkDocument::CreatePDF(&stream));
162 SkCanvas* canvas = doc->beginPage(64, 64);
163 canvas->scale(10000.0f, 10000.0f);
164 canvas->translate(20.0f, 10.0f);
165 canvas->rotate(30.0f);
166 const char text[] = "HELLO";
167 canvas->drawText(text, strlen(text), 0, 0, SkPaint());
168 }
169