blob: a4a11dbf03ad7fe6ad44d2df34e845551e53ba62 [file] [log] [blame]
Dominic Mazzoni656cefe2018-09-25 20:29:15 -07001/*
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 */
Mike Kleinc0bd9f92019-04-23 12:05:21 -05007#include "tests/Test.h"
Dominic Mazzoni656cefe2018-09-25 20:29:15 -07008
Mike Kleinc0bd9f92019-04-23 12:05:21 -05009#include "include/core/SkCanvas.h"
10#include "include/core/SkFont.h"
11#include "include/core/SkStream.h"
12#include "include/docs/SkPDFDocument.h"
Dominic Mazzoni656cefe2018-09-25 20:29:15 -070013
14using 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\"" ]
19DEF_TEST(SkPDF_tagged, r) {
Hal Canary0f888612018-10-04 13:34:44 -040020 REQUIRE_PDF_DOCUMENT(SkPDF_tagged, r);
Dominic Mazzoni656cefe2018-09-25 20:29:15 -070021#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);
Dominic Mazzoni656cefe2018-09-25 20:29:15 -0700102
103 // First page.
104 SkCanvas* canvas =
105 document->beginPage(pageSize.width(),
106 pageSize.height());
107 SkPDF::SetNodeId(canvas, 2);
Hal Canary3560ea72019-01-08 13:01:58 -0500108 SkFont font(nullptr, 36);
Dominic Mazzoni656cefe2018-09-25 20:29:15 -0700109 const char* message = "This is the title";
110 canvas->translate(72, 72);
Hal Canary3560ea72019-01-08 13:01:58 -0500111 canvas->drawString(message, 0, 0, font, paint);
Dominic Mazzoni656cefe2018-09-25 20:29:15 -0700112
113 SkPDF::SetNodeId(canvas, 3);
Hal Canary3560ea72019-01-08 13:01:58 -0500114 font.setSize(14);
Dominic Mazzoni656cefe2018-09-25 20:29:15 -0700115 message = "This is a simple paragraph.";
116 canvas->translate(0, 72);
Hal Canary3560ea72019-01-08 13:01:58 -0500117 canvas->drawString(message, 0, 0, font, paint);
Dominic Mazzoni656cefe2018-09-25 20:29:15 -0700118
119 SkPDF::SetNodeId(canvas, 6);
Hal Canary3560ea72019-01-08 13:01:58 -0500120 font.setSize(14);
Dominic Mazzoni656cefe2018-09-25 20:29:15 -0700121 message = "*";
122 canvas->translate(0, 72);
Hal Canary3560ea72019-01-08 13:01:58 -0500123 canvas->drawString(message, 0, 0, font, paint);
Dominic Mazzoni656cefe2018-09-25 20:29:15 -0700124
125 SkPDF::SetNodeId(canvas, 7);
126 message = "List item 1";
127 canvas->translate(36, 0);
Hal Canary3560ea72019-01-08 13:01:58 -0500128 canvas->drawString(message, 0, 0, font, paint);
Dominic Mazzoni656cefe2018-09-25 20:29:15 -0700129
130 SkPDF::SetNodeId(canvas, 8);
131 message = "*";
132 canvas->translate(-36, 36);
Hal Canary3560ea72019-01-08 13:01:58 -0500133 canvas->drawString(message, 0, 0, font, paint);
Dominic Mazzoni656cefe2018-09-25 20:29:15 -0700134
135 SkPDF::SetNodeId(canvas, 9);
136 message = "List item 2";
137 canvas->translate(36, 0);
Hal Canary3560ea72019-01-08 13:01:58 -0500138 canvas->drawString(message, 0, 0, font, paint);
Dominic Mazzoni656cefe2018-09-25 20:29:15 -0700139
140 SkPDF::SetNodeId(canvas, 10);
141 message = "This is a paragraph that starts on one page";
142 canvas->translate(-36, 6 * 72);
Hal Canary3560ea72019-01-08 13:01:58 -0500143 canvas->drawString(message, 0, 0, font, paint);
Dominic Mazzoni656cefe2018-09-25 20:29:15 -0700144
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);
Hal Canary3560ea72019-01-08 13:01:58 -0500153 canvas->drawString(message, 0, 0, font, paint);
Dominic Mazzoni656cefe2018-09-25 20:29:15 -0700154
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);
Hal Canary3560ea72019-01-08 13:01:58 -0500160 canvas->drawString(message, 0, 0, font, paint);
Dominic Mazzoni656cefe2018-09-25 20:29:15 -0700161
162 document->endPage();
163
164 document->close();
165
166 outputStream.flush();
167}