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