xref: /aosp_15_r20/external/skia/tests/PDFDocumentTest.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2013 Google Inc.
3*c8dee2aaSAndroid Build Coastguard Worker  *
4*c8dee2aaSAndroid Build Coastguard Worker  * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker  * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker  */
7*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkBitmap.h"
8*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkCanvas.h"
9*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColor.h"
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkData.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkDocument.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkExecutor.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkFont.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkImage.h" // IWYU pragma: keep
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPaint.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRefCnt.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkStream.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkString.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "include/docs/SkPDFDocument.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "src/utils/SkOSPath.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "tests/Test.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "tools/fonts/FontToolUtils.h"
23*c8dee2aaSAndroid Build Coastguard Worker 
24*c8dee2aaSAndroid Build Coastguard Worker #include <cstdint>
25*c8dee2aaSAndroid Build Coastguard Worker #include <cstdio>
26*c8dee2aaSAndroid Build Coastguard Worker #include <cstring>
27*c8dee2aaSAndroid Build Coastguard Worker #include <memory>
28*c8dee2aaSAndroid Build Coastguard Worker 
test_empty(skiatest::Reporter * reporter)29*c8dee2aaSAndroid Build Coastguard Worker static void test_empty(skiatest::Reporter* reporter) {
30*c8dee2aaSAndroid Build Coastguard Worker     SkDynamicMemoryWStream stream;
31*c8dee2aaSAndroid Build Coastguard Worker 
32*c8dee2aaSAndroid Build Coastguard Worker     auto doc = SkPDF::MakeDocument(&stream);
33*c8dee2aaSAndroid Build Coastguard Worker 
34*c8dee2aaSAndroid Build Coastguard Worker     doc->close();
35*c8dee2aaSAndroid Build Coastguard Worker 
36*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, stream.bytesWritten() == 0);
37*c8dee2aaSAndroid Build Coastguard Worker }
38*c8dee2aaSAndroid Build Coastguard Worker 
test_abort(skiatest::Reporter * reporter)39*c8dee2aaSAndroid Build Coastguard Worker static void test_abort(skiatest::Reporter* reporter) {
40*c8dee2aaSAndroid Build Coastguard Worker     SkDynamicMemoryWStream stream;
41*c8dee2aaSAndroid Build Coastguard Worker     auto doc = SkPDF::MakeDocument(&stream);
42*c8dee2aaSAndroid Build Coastguard Worker 
43*c8dee2aaSAndroid Build Coastguard Worker     SkCanvas* canvas = doc->beginPage(100, 100);
44*c8dee2aaSAndroid Build Coastguard Worker     canvas->drawColor(SK_ColorRED);
45*c8dee2aaSAndroid Build Coastguard Worker     doc->endPage();
46*c8dee2aaSAndroid Build Coastguard Worker 
47*c8dee2aaSAndroid Build Coastguard Worker     doc->abort();
48*c8dee2aaSAndroid Build Coastguard Worker 
49*c8dee2aaSAndroid Build Coastguard Worker     // Test that only the header is written, not the full document.
50*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, stream.bytesWritten() < 256);
51*c8dee2aaSAndroid Build Coastguard Worker }
52*c8dee2aaSAndroid Build Coastguard Worker 
test_abortWithFile(skiatest::Reporter * reporter)53*c8dee2aaSAndroid Build Coastguard Worker static void test_abortWithFile(skiatest::Reporter* reporter) {
54*c8dee2aaSAndroid Build Coastguard Worker     SkString tmpDir = skiatest::GetTmpDir();
55*c8dee2aaSAndroid Build Coastguard Worker 
56*c8dee2aaSAndroid Build Coastguard Worker     if (tmpDir.isEmpty()) {
57*c8dee2aaSAndroid Build Coastguard Worker         ERRORF(reporter, "missing tmpDir.");
58*c8dee2aaSAndroid Build Coastguard Worker         return;
59*c8dee2aaSAndroid Build Coastguard Worker     }
60*c8dee2aaSAndroid Build Coastguard Worker 
61*c8dee2aaSAndroid Build Coastguard Worker     SkString path = SkOSPath::Join(tmpDir.c_str(), "aborted.pdf");
62*c8dee2aaSAndroid Build Coastguard Worker     if (!SkFILEWStream(path.c_str()).isValid()) {
63*c8dee2aaSAndroid Build Coastguard Worker         ERRORF(reporter, "unable to write to: %s", path.c_str());
64*c8dee2aaSAndroid Build Coastguard Worker         return;
65*c8dee2aaSAndroid Build Coastguard Worker     }
66*c8dee2aaSAndroid Build Coastguard Worker 
67*c8dee2aaSAndroid Build Coastguard Worker     // Make sure doc's destructor is called to flush.
68*c8dee2aaSAndroid Build Coastguard Worker     {
69*c8dee2aaSAndroid Build Coastguard Worker         SkFILEWStream stream(path.c_str());
70*c8dee2aaSAndroid Build Coastguard Worker         auto doc = SkPDF::MakeDocument(&stream);
71*c8dee2aaSAndroid Build Coastguard Worker 
72*c8dee2aaSAndroid Build Coastguard Worker         SkCanvas* canvas = doc->beginPage(100, 100);
73*c8dee2aaSAndroid Build Coastguard Worker         canvas->drawColor(SK_ColorRED);
74*c8dee2aaSAndroid Build Coastguard Worker         doc->endPage();
75*c8dee2aaSAndroid Build Coastguard Worker 
76*c8dee2aaSAndroid Build Coastguard Worker         doc->abort();
77*c8dee2aaSAndroid Build Coastguard Worker     }
78*c8dee2aaSAndroid Build Coastguard Worker 
79*c8dee2aaSAndroid Build Coastguard Worker     FILE* file = fopen(path.c_str(), "r");
80*c8dee2aaSAndroid Build Coastguard Worker     // Test that only the header is written, not the full document.
81*c8dee2aaSAndroid Build Coastguard Worker     char buffer[256];
82*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, fread(buffer, 1, sizeof(buffer), file) < sizeof(buffer));
83*c8dee2aaSAndroid Build Coastguard Worker     fclose(file);
84*c8dee2aaSAndroid Build Coastguard Worker }
85*c8dee2aaSAndroid Build Coastguard Worker 
test_file(skiatest::Reporter * reporter)86*c8dee2aaSAndroid Build Coastguard Worker static void test_file(skiatest::Reporter* reporter) {
87*c8dee2aaSAndroid Build Coastguard Worker     SkString tmpDir = skiatest::GetTmpDir();
88*c8dee2aaSAndroid Build Coastguard Worker     if (tmpDir.isEmpty()) {
89*c8dee2aaSAndroid Build Coastguard Worker         ERRORF(reporter, "missing tmpDir.");
90*c8dee2aaSAndroid Build Coastguard Worker         return;
91*c8dee2aaSAndroid Build Coastguard Worker     }
92*c8dee2aaSAndroid Build Coastguard Worker 
93*c8dee2aaSAndroid Build Coastguard Worker     SkString path = SkOSPath::Join(tmpDir.c_str(), "file.pdf");
94*c8dee2aaSAndroid Build Coastguard Worker     if (!SkFILEWStream(path.c_str()).isValid()) {
95*c8dee2aaSAndroid Build Coastguard Worker         ERRORF(reporter, "unable to write to: %s", path.c_str());
96*c8dee2aaSAndroid Build Coastguard Worker         return;
97*c8dee2aaSAndroid Build Coastguard Worker     }
98*c8dee2aaSAndroid Build Coastguard Worker 
99*c8dee2aaSAndroid Build Coastguard Worker     {
100*c8dee2aaSAndroid Build Coastguard Worker         SkFILEWStream stream(path.c_str());
101*c8dee2aaSAndroid Build Coastguard Worker         auto doc = SkPDF::MakeDocument(&stream);
102*c8dee2aaSAndroid Build Coastguard Worker         SkCanvas* canvas = doc->beginPage(100, 100);
103*c8dee2aaSAndroid Build Coastguard Worker 
104*c8dee2aaSAndroid Build Coastguard Worker         canvas->drawColor(SK_ColorRED);
105*c8dee2aaSAndroid Build Coastguard Worker         doc->endPage();
106*c8dee2aaSAndroid Build Coastguard Worker         doc->close();
107*c8dee2aaSAndroid Build Coastguard Worker     }
108*c8dee2aaSAndroid Build Coastguard Worker 
109*c8dee2aaSAndroid Build Coastguard Worker     FILE* file = fopen(path.c_str(), "r");
110*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, file != nullptr);
111*c8dee2aaSAndroid Build Coastguard Worker     char header[100];
112*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, fread(header, 4, 1, file) != 0);
113*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, strncmp(header, "%PDF", 4) == 0);
114*c8dee2aaSAndroid Build Coastguard Worker     fclose(file);
115*c8dee2aaSAndroid Build Coastguard Worker }
116*c8dee2aaSAndroid Build Coastguard Worker 
test_close(skiatest::Reporter * reporter)117*c8dee2aaSAndroid Build Coastguard Worker static void test_close(skiatest::Reporter* reporter) {
118*c8dee2aaSAndroid Build Coastguard Worker     SkDynamicMemoryWStream stream;
119*c8dee2aaSAndroid Build Coastguard Worker     auto doc = SkPDF::MakeDocument(&stream);
120*c8dee2aaSAndroid Build Coastguard Worker 
121*c8dee2aaSAndroid Build Coastguard Worker     SkCanvas* canvas = doc->beginPage(100, 100);
122*c8dee2aaSAndroid Build Coastguard Worker     canvas->drawColor(SK_ColorRED);
123*c8dee2aaSAndroid Build Coastguard Worker     doc->endPage();
124*c8dee2aaSAndroid Build Coastguard Worker 
125*c8dee2aaSAndroid Build Coastguard Worker     doc->close();
126*c8dee2aaSAndroid Build Coastguard Worker 
127*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, stream.bytesWritten() != 0);
128*c8dee2aaSAndroid Build Coastguard Worker }
129*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(SkPDF_document_tests,reporter)130*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(SkPDF_document_tests, reporter) {
131*c8dee2aaSAndroid Build Coastguard Worker     REQUIRE_PDF_DOCUMENT(document_tests, reporter);
132*c8dee2aaSAndroid Build Coastguard Worker     test_empty(reporter);
133*c8dee2aaSAndroid Build Coastguard Worker     test_abort(reporter);
134*c8dee2aaSAndroid Build Coastguard Worker     test_abortWithFile(reporter);
135*c8dee2aaSAndroid Build Coastguard Worker     test_file(reporter);
136*c8dee2aaSAndroid Build Coastguard Worker     test_close(reporter);
137*c8dee2aaSAndroid Build Coastguard Worker }
138*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(SkPDF_document_skbug_4734,r)139*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(SkPDF_document_skbug_4734, r) {
140*c8dee2aaSAndroid Build Coastguard Worker     REQUIRE_PDF_DOCUMENT(SkPDF_document_skbug_4734, r);
141*c8dee2aaSAndroid Build Coastguard Worker     SkDynamicMemoryWStream stream;
142*c8dee2aaSAndroid Build Coastguard Worker     auto doc = SkPDF::MakeDocument(&stream);
143*c8dee2aaSAndroid Build Coastguard Worker     SkCanvas* canvas = doc->beginPage(64, 64);
144*c8dee2aaSAndroid Build Coastguard Worker     canvas->scale(10000.0f, 10000.0f);
145*c8dee2aaSAndroid Build Coastguard Worker     canvas->translate(20.0f, 10.0f);
146*c8dee2aaSAndroid Build Coastguard Worker     canvas->rotate(30.0f);
147*c8dee2aaSAndroid Build Coastguard Worker     const char text[] = "HELLO";
148*c8dee2aaSAndroid Build Coastguard Worker     canvas->drawString(text, 0, 0, ToolUtils::DefaultFont(), SkPaint());
149*c8dee2aaSAndroid Build Coastguard Worker }
150*c8dee2aaSAndroid Build Coastguard Worker 
contains(const uint8_t * result,size_t size,const char expectation[])151*c8dee2aaSAndroid Build Coastguard Worker static bool contains(const uint8_t* result, size_t size, const char expectation[]) {
152*c8dee2aaSAndroid Build Coastguard Worker     size_t len = strlen(expectation);
153*c8dee2aaSAndroid Build Coastguard Worker     size_t N = 1 + size - len;
154*c8dee2aaSAndroid Build Coastguard Worker     for (size_t i = 0; i < N; ++i) {
155*c8dee2aaSAndroid Build Coastguard Worker         if (0 == memcmp(result + i, expectation, len)) {
156*c8dee2aaSAndroid Build Coastguard Worker             return true;
157*c8dee2aaSAndroid Build Coastguard Worker         }
158*c8dee2aaSAndroid Build Coastguard Worker     }
159*c8dee2aaSAndroid Build Coastguard Worker     return false;
160*c8dee2aaSAndroid Build Coastguard Worker }
161*c8dee2aaSAndroid Build Coastguard Worker 
162*c8dee2aaSAndroid Build Coastguard Worker // verify that the PDFA flag does something.
DEF_TEST(SkPDF_pdfa_document,r)163*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(SkPDF_pdfa_document, r) {
164*c8dee2aaSAndroid Build Coastguard Worker     REQUIRE_PDF_DOCUMENT(SkPDF_pdfa_document, r);
165*c8dee2aaSAndroid Build Coastguard Worker 
166*c8dee2aaSAndroid Build Coastguard Worker     SkPDF::Metadata pdfMetadata;
167*c8dee2aaSAndroid Build Coastguard Worker     pdfMetadata.fTitle = "test document";
168*c8dee2aaSAndroid Build Coastguard Worker     pdfMetadata.fCreation = {0, 1999, 12, 5, 31, 23, 59, 59};
169*c8dee2aaSAndroid Build Coastguard Worker     pdfMetadata.fPDFA = true;
170*c8dee2aaSAndroid Build Coastguard Worker 
171*c8dee2aaSAndroid Build Coastguard Worker     SkDynamicMemoryWStream buffer;
172*c8dee2aaSAndroid Build Coastguard Worker     auto doc = SkPDF::MakeDocument(&buffer, pdfMetadata);
173*c8dee2aaSAndroid Build Coastguard Worker     doc->beginPage(64, 64)->drawColor(SK_ColorRED);
174*c8dee2aaSAndroid Build Coastguard Worker     doc->close();
175*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkData> data(buffer.detachAsData());
176*c8dee2aaSAndroid Build Coastguard Worker 
177*c8dee2aaSAndroid Build Coastguard Worker     static const char* expectations[] = {
178*c8dee2aaSAndroid Build Coastguard Worker         "sRGB IEC61966-2.1",
179*c8dee2aaSAndroid Build Coastguard Worker         "<dc:title><rdf:Alt><rdf:li xml:lang=\"x-default\">test document",
180*c8dee2aaSAndroid Build Coastguard Worker         "<xmp:CreateDate>1999-12-31T23:59:59+00:00</xmp:CreateDate>",
181*c8dee2aaSAndroid Build Coastguard Worker         "/Subtype /XML",
182*c8dee2aaSAndroid Build Coastguard Worker         "/CreationDate (D:19991231235959+00'00')>>",
183*c8dee2aaSAndroid Build Coastguard Worker     };
184*c8dee2aaSAndroid Build Coastguard Worker     for (const char* expectation : expectations) {
185*c8dee2aaSAndroid Build Coastguard Worker         if (!contains(data->bytes(), data->size(), expectation)) {
186*c8dee2aaSAndroid Build Coastguard Worker             ERRORF(r, "PDFA expectation missing: '%s'.", expectation);
187*c8dee2aaSAndroid Build Coastguard Worker         }
188*c8dee2aaSAndroid Build Coastguard Worker     }
189*c8dee2aaSAndroid Build Coastguard Worker     pdfMetadata.fProducer = "phoney library";
190*c8dee2aaSAndroid Build Coastguard Worker     pdfMetadata.fPDFA = true;
191*c8dee2aaSAndroid Build Coastguard Worker     doc = SkPDF::MakeDocument(&buffer, pdfMetadata);
192*c8dee2aaSAndroid Build Coastguard Worker     doc->beginPage(64, 64)->drawColor(SK_ColorRED);
193*c8dee2aaSAndroid Build Coastguard Worker     doc->close();
194*c8dee2aaSAndroid Build Coastguard Worker     data = buffer.detachAsData();
195*c8dee2aaSAndroid Build Coastguard Worker 
196*c8dee2aaSAndroid Build Coastguard Worker     static const char* moreExpectations[] = {
197*c8dee2aaSAndroid Build Coastguard Worker         "/Producer (phoney library)",
198*c8dee2aaSAndroid Build Coastguard Worker         "<pdf:Producer>phoney library</pdf:Producer>",
199*c8dee2aaSAndroid Build Coastguard Worker     };
200*c8dee2aaSAndroid Build Coastguard Worker     for (const char* expectation : moreExpectations) {
201*c8dee2aaSAndroid Build Coastguard Worker         if (!contains(data->bytes(), data->size(), expectation)) {
202*c8dee2aaSAndroid Build Coastguard Worker             ERRORF(r, "PDFA expectation missing: '%s'.", expectation);
203*c8dee2aaSAndroid Build Coastguard Worker         }
204*c8dee2aaSAndroid Build Coastguard Worker     }
205*c8dee2aaSAndroid Build Coastguard Worker }
206*c8dee2aaSAndroid Build Coastguard Worker 
207*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(SkPDF_unicode_metadata,r)208*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(SkPDF_unicode_metadata, r) {
209*c8dee2aaSAndroid Build Coastguard Worker     REQUIRE_PDF_DOCUMENT(SkPDF_unicode_metadata, r);
210*c8dee2aaSAndroid Build Coastguard Worker     SkPDF::Metadata pdfMetadata;
211*c8dee2aaSAndroid Build Coastguard Worker     pdfMetadata.fTitle   = "���������� ����������"; // Out of basic multilingual plane
212*c8dee2aaSAndroid Build Coastguard Worker     pdfMetadata.fAuthor  = "ABCDE FGHIJ"; // ASCII
213*c8dee2aaSAndroid Build Coastguard Worker     pdfMetadata.fSubject = "αβγδε ζηθικ"; // inside  basic multilingual plane
214*c8dee2aaSAndroid Build Coastguard Worker     pdfMetadata.fPDFA = true;
215*c8dee2aaSAndroid Build Coastguard Worker     SkDynamicMemoryWStream wStream;
216*c8dee2aaSAndroid Build Coastguard Worker     {
217*c8dee2aaSAndroid Build Coastguard Worker         auto doc = SkPDF::MakeDocument(&wStream, pdfMetadata);
218*c8dee2aaSAndroid Build Coastguard Worker         doc->beginPage(612, 792)->drawColor(SK_ColorCYAN);
219*c8dee2aaSAndroid Build Coastguard Worker     }
220*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkData> data(wStream.detachAsData());
221*c8dee2aaSAndroid Build Coastguard Worker     static const char* expectations[] = {
222*c8dee2aaSAndroid Build Coastguard Worker         ("<</Title <FEFFD835DCD0D835DCD1D835DCD2D835DCD3D835DCD40020"
223*c8dee2aaSAndroid Build Coastguard Worker             "D835DCD5D835DCD6D835DCD7D835DCD8D835DCD9>"),
224*c8dee2aaSAndroid Build Coastguard Worker          "/Author (ABCDE FGHIJ)",
225*c8dee2aaSAndroid Build Coastguard Worker          "Subject <FEFF03B103B203B303B403B5002003B603B703B803B903BA>",
226*c8dee2aaSAndroid Build Coastguard Worker          "/ViewerPreferences",
227*c8dee2aaSAndroid Build Coastguard Worker          "/DisplayDocTitle true",
228*c8dee2aaSAndroid Build Coastguard Worker     };
229*c8dee2aaSAndroid Build Coastguard Worker     for (const char* expectation : expectations) {
230*c8dee2aaSAndroid Build Coastguard Worker         if (!contains(data->bytes(), data->size(), expectation)) {
231*c8dee2aaSAndroid Build Coastguard Worker             ERRORF(r, "PDF expectation missing: '%s'.", expectation);
232*c8dee2aaSAndroid Build Coastguard Worker         }
233*c8dee2aaSAndroid Build Coastguard Worker     }
234*c8dee2aaSAndroid Build Coastguard Worker }
235*c8dee2aaSAndroid Build Coastguard Worker 
236*c8dee2aaSAndroid Build Coastguard Worker // Make sure we excercise the multi-page functionality without problems.
237*c8dee2aaSAndroid Build Coastguard Worker // Add this to args.gn to output the PDF to a file:
238*c8dee2aaSAndroid Build Coastguard Worker //   extra_cflags = [ "-DSK_PDF_TEST_MULTIPAGE=\"/tmp/skpdf_test_multipage.pdf\"" ]
DEF_TEST(SkPDF_multiple_pages,r)239*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(SkPDF_multiple_pages, r) {
240*c8dee2aaSAndroid Build Coastguard Worker     REQUIRE_PDF_DOCUMENT(SkPDF_multiple_pages, r);
241*c8dee2aaSAndroid Build Coastguard Worker     int n = 100;
242*c8dee2aaSAndroid Build Coastguard Worker #ifdef SK_PDF_TEST_MULTIPAGE
243*c8dee2aaSAndroid Build Coastguard Worker     SkFILEWStream wStream(SK_PDF_TEST_MULTIPAGE);
244*c8dee2aaSAndroid Build Coastguard Worker #else
245*c8dee2aaSAndroid Build Coastguard Worker     SkDynamicMemoryWStream wStream;
246*c8dee2aaSAndroid Build Coastguard Worker #endif
247*c8dee2aaSAndroid Build Coastguard Worker     auto doc = SkPDF::MakeDocument(&wStream);
248*c8dee2aaSAndroid Build Coastguard Worker     for (int i = 0; i < n; ++i) {
249*c8dee2aaSAndroid Build Coastguard Worker         doc->beginPage(612, 792)->drawColor(
250*c8dee2aaSAndroid Build Coastguard Worker                 SkColorSetARGB(0xFF, 0x00, (uint8_t)(255.0f * i / (n - 1)), 0x00));
251*c8dee2aaSAndroid Build Coastguard Worker     }
252*c8dee2aaSAndroid Build Coastguard Worker }
253*c8dee2aaSAndroid Build Coastguard Worker 
254*c8dee2aaSAndroid Build Coastguard Worker // Test to make sure that jobs launched by PDF backend don't cause a segfault
255*c8dee2aaSAndroid Build Coastguard Worker // after calling abort().
DEF_TEST(SkPDF_abort_jobs,rep)256*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(SkPDF_abort_jobs, rep) {
257*c8dee2aaSAndroid Build Coastguard Worker     REQUIRE_PDF_DOCUMENT(SkPDF_abort_jobs, rep);
258*c8dee2aaSAndroid Build Coastguard Worker     SkBitmap b;
259*c8dee2aaSAndroid Build Coastguard Worker     b.allocN32Pixels(612, 792);
260*c8dee2aaSAndroid Build Coastguard Worker     b.eraseColor(0x4F9643A0);
261*c8dee2aaSAndroid Build Coastguard Worker     SkPDF::Metadata metadata;
262*c8dee2aaSAndroid Build Coastguard Worker     std::unique_ptr<SkExecutor> executor = SkExecutor::MakeFIFOThreadPool();
263*c8dee2aaSAndroid Build Coastguard Worker     metadata.fExecutor = executor.get();
264*c8dee2aaSAndroid Build Coastguard Worker     SkNullWStream dst;
265*c8dee2aaSAndroid Build Coastguard Worker     auto doc = SkPDF::MakeDocument(&dst, metadata);
266*c8dee2aaSAndroid Build Coastguard Worker     doc->beginPage(612, 792)->drawImage(b.asImage(), 0, 0);
267*c8dee2aaSAndroid Build Coastguard Worker     doc->abort();
268*c8dee2aaSAndroid Build Coastguard Worker }
269*c8dee2aaSAndroid Build Coastguard Worker 
270