1 /*
2 * Copyright 2018 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 "tests/Test.h"
8
9 #include "include/core/SkBitmap.h"
10 #include "include/core/SkCanvas.h"
11 #include "include/core/SkFont.h"
12 #include "include/core/SkStream.h"
13 #include "include/docs/SkPDFDocument.h"
14
15 using PDFTag = SkPDF::StructureElementNode;
16
17 // Test building a tagged PDF.
18 // Add this to args.gn to output the PDF to a file:
19 // extra_cflags = [ "-DSK_PDF_TEST_TAGS_OUTPUT_PATH=\"/tmp/foo.pdf\"" ]
DEF_TEST(SkPDF_tagged_doc,r)20 DEF_TEST(SkPDF_tagged_doc, r) {
21 REQUIRE_PDF_DOCUMENT(SkPDF_tagged_doc, r);
22 #ifdef SK_PDF_TEST_TAGS_OUTPUT_PATH
23 SkFILEWStream outputStream(SK_PDF_TEST_TAGS_OUTPUT_PATH);
24 #else
25 SkDynamicMemoryWStream outputStream;
26 #endif
27
28 SkSize pageSize = SkSize::Make(612, 792); // U.S. Letter
29
30 SkPDF::Metadata metadata;
31 metadata.fTitle = "Example Tagged PDF";
32 metadata.fCreator = "Skia";
33 SkTime::DateTime now;
34 SkTime::GetDateTime(&now);
35 metadata.fCreation = now;
36 metadata.fModified = now;
37
38 // The document tag.
39 auto root = std::make_unique<PDFTag>();
40 root->fNodeId = 1;
41 root->fTypeString = "Document";
42
43 // Heading.
44 auto h1 = std::make_unique<PDFTag>();
45 h1->fNodeId = 2;
46 h1->fTypeString = "H1";
47 root->fChildVector.push_back(std::move(h1));
48
49 // Initial paragraph.
50 auto p = std::make_unique<PDFTag>();
51 p->fNodeId = 3;
52 p->fTypeString = "P";
53 root->fChildVector.push_back(std::move(p));
54
55 // Hidden div. This is never referenced by marked content
56 // so it should not appear in the resulting PDF.
57 auto div = std::make_unique<PDFTag>();
58 div->fNodeId = 4;
59 div->fTypeString = "Div";
60 root->fChildVector.push_back(std::move(div));
61
62 // A bulleted list of two items.
63 auto l = std::make_unique<PDFTag>();
64 l->fNodeId = 5;
65 l->fTypeString = "L";
66
67 auto lm1 = std::make_unique<PDFTag>();
68 lm1->fNodeId = 6;
69 lm1->fTypeString = "Lbl";
70 l->fChildVector.push_back(std::move(lm1));
71
72 auto li1 = std::make_unique<PDFTag>();
73 li1->fNodeId = 7;
74 li1->fTypeString = "LI";
75 l->fChildVector.push_back(std::move(li1));
76
77 auto lm2 = std::make_unique<PDFTag>();
78 lm2->fNodeId = 8;
79 lm2->fTypeString = "Lbl";
80 l->fChildVector.push_back(std::move(lm2));
81 auto li2 = std::make_unique<PDFTag>();
82 li2->fNodeId = 9;
83 li2->fTypeString = "LI";
84 l->fChildVector.push_back(std::move(li2));
85
86 root->fChildVector.push_back(std::move(l));
87
88 // Paragraph spanning two pages.
89 auto p2 = std::make_unique<PDFTag>();
90 p2->fNodeId = 10;
91 p2->fTypeString = "P";
92 root->fChildVector.push_back(std::move(p2));
93
94 // Image with alt text.
95 auto img = std::make_unique<PDFTag>();
96 img->fNodeId = 11;
97 img->fTypeString = "Figure";
98 img->fAlt = "Red box";
99 root->fChildVector.push_back(std::move(img));
100
101 metadata.fStructureElementTreeRoot = root.get();
102 sk_sp<SkDocument> document = SkPDF::MakeDocument(
103 &outputStream, metadata);
104
105 SkPaint paint;
106 paint.setColor(SK_ColorBLACK);
107
108 // First page.
109 SkCanvas* canvas =
110 document->beginPage(pageSize.width(),
111 pageSize.height());
112 SkPDF::SetNodeId(canvas, 2);
113 SkFont font(nullptr, 36);
114 const char* message = "This is the title";
115 canvas->translate(72, 72);
116 canvas->drawString(message, 0, 0, font, paint);
117
118 SkPDF::SetNodeId(canvas, 3);
119 font.setSize(14);
120 message = "This is a simple paragraph.";
121 canvas->translate(0, 72);
122 canvas->drawString(message, 0, 0, font, paint);
123
124 SkPDF::SetNodeId(canvas, 6);
125 font.setSize(14);
126 message = "*";
127 canvas->translate(0, 72);
128 canvas->drawString(message, 0, 0, font, paint);
129
130 SkPDF::SetNodeId(canvas, 7);
131 message = "List item 1";
132 canvas->translate(36, 0);
133 canvas->drawString(message, 0, 0, font, paint);
134
135 SkPDF::SetNodeId(canvas, 8);
136 message = "*";
137 canvas->translate(-36, 36);
138 canvas->drawString(message, 0, 0, font, paint);
139
140 SkPDF::SetNodeId(canvas, 9);
141 message = "List item 2";
142 canvas->translate(36, 0);
143 canvas->drawString(message, 0, 0, font, paint);
144
145 SkPDF::SetNodeId(canvas, 10);
146 message = "This is a paragraph that starts on one page";
147 canvas->translate(-36, 6 * 72);
148 canvas->drawString(message, 0, 0, font, paint);
149
150 document->endPage();
151
152 // Second page.
153 canvas = document->beginPage(pageSize.width(),
154 pageSize.height());
155 SkPDF::SetNodeId(canvas, 10);
156 message = "and finishes on the second page.";
157 canvas->translate(72, 72);
158 canvas->drawString(message, 0, 0, font, paint);
159
160 // Test a tagged image with alt text.
161 SkPDF::SetNodeId(canvas, 11);
162 SkBitmap testBitmap;
163 testBitmap.allocN32Pixels(72, 72);
164 testBitmap.eraseColor(SK_ColorRED);
165 canvas->translate(72, 72);
166 canvas->drawImage(testBitmap.asImage(), 0, 0);
167
168 // This has a node ID but never shows up in the tag tree so it
169 // won't be tagged.
170 SkPDF::SetNodeId(canvas, 999);
171 message = "Page 2";
172 canvas->translate(468, -36);
173 canvas->drawString(message, 0, 0, font, paint);
174
175 document->endPage();
176
177 document->close();
178
179 outputStream.flush();
180 }
181