• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2020 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 #ifdef SK_SUPPORT_PDF
10 
11 #include "include/core/SkCanvas.h"
12 #include "include/core/SkFont.h"
13 #include "include/core/SkStream.h"
14 #include "include/docs/SkPDFDocument.h"
15 
16 using PDFTag = SkPDF::StructureElementNode;
17 
18 // Test building a tagged PDF containing a table.
19 // Add this to args.gn to output the PDF to a file:
20 //   extra_cflags = [ "-DSK_PDF_TEST_TAGS_OUTPUT_PATH=\"/tmp/table.pdf\"" ]
DEF_TEST(SkPDF_tagged_table,r)21 DEF_TEST(SkPDF_tagged_table, r) {
22     REQUIRE_PDF_DOCUMENT(SkPDF_tagged, r);
23 #ifdef SK_PDF_TEST_TAGS_OUTPUT_PATH
24     SkFILEWStream outputStream(SK_PDF_TEST_TAGS_OUTPUT_PATH);
25 #else
26     SkDynamicMemoryWStream outputStream;
27 #endif
28 
29     SkSize pageSize = SkSize::Make(612, 792);  // U.S. Letter
30 
31     SkPDF::Metadata metadata;
32     metadata.fTitle = "Example Tagged Table PDF";
33     metadata.fCreator = "Skia";
34     SkTime::DateTime now;
35     SkTime::GetDateTime(&now);
36     metadata.fCreation = now;
37     metadata.fModified = now;
38 
39     constexpr int kRowCount = 5;
40     constexpr int kColCount = 4;
41     const char* cellData[kRowCount * kColCount] = {
42         "Car",                  "Engine",   "City MPG", "Highway MPG",
43         "Mitsubishi Mirage ES", "Gas",      "28",       "47",
44         "Toyota Prius Three",   "Hybrid",   "43",       "59",
45         "Nissan Leaf SL",       "Electric", "N/A",      nullptr,
46         "Tesla Model 3",        nullptr,    "N/A",      nullptr
47     };
48 
49     // The document tag.
50     auto root = std::make_unique<PDFTag>();
51     root->fNodeId = 1;
52     root->fTypeString = "Document";
53     root->fLang = "en-US";
54 
55     // Heading.
56     auto h1 = std::make_unique<PDFTag>();
57     h1->fNodeId = 2;
58     h1->fTypeString = "H1";
59     h1->fAlt = "Tagged PDF Table Alt Text";
60     root->fChildVector.push_back(std::move(h1));
61 
62     // Table.
63     auto table = std::make_unique<PDFTag>();
64     table->fNodeId = 3;
65     table->fTypeString = "Table";
66     auto& rows = table->fChildVector;
67     table->fAttributes.appendFloatArray("Layout", "BBox", {72, 72, 360, 360});
68 
69     for (int rowIndex = 0; rowIndex < kRowCount; rowIndex++) {
70         auto row = std::make_unique<PDFTag>();
71         row->fNodeId = 4 + rowIndex;
72         row->fTypeString = "TR";
73         auto& cells = row->fChildVector;
74         for (int colIndex = 0; colIndex < kColCount; colIndex++) {
75             auto cell = std::make_unique<PDFTag>();
76             int cellIndex = rowIndex * kColCount + colIndex;
77             cell->fNodeId = 10 + cellIndex;
78             if (!cellData[cellIndex]) {
79                 cell->fTypeString = "NonStruct";
80             } else if (rowIndex == 0 || colIndex == 0) {
81                 cell->fTypeString = "TH";
82             } else {
83                 cell->fTypeString = "TD";
84                 std::vector<int> headerIds;
85                 headerIds.push_back(10 + rowIndex * kColCount);  // Row header
86                 headerIds.push_back(10 + colIndex);  // Col header.
87                 cell->fAttributes.appendNodeIdArray(
88                     "Table", "Headers", headerIds);
89             }
90 
91             if (cellIndex == 13) {
92                 cell->fAttributes.appendInt("Table", "RowSpan", 2);
93             } else if (cellIndex == 14 || cellIndex == 18) {
94                 cell->fAttributes.appendInt("Table", "ColSpan", 2);
95             } else if (rowIndex == 0 || colIndex == 0) {
96                 cell->fAttributes.appendName(
97                     "Table", "Scope", rowIndex == 0 ? "Column" : "Row");
98             }
99             cells.push_back(std::move(cell));
100         }
101         rows.push_back(std::move(row));
102     }
103     root->fChildVector.push_back(std::move(table));
104 
105     metadata.fStructureElementTreeRoot = root.get();
106     sk_sp<SkDocument> document = SkPDF::MakeDocument(
107         &outputStream, metadata);
108 
109     SkPaint paint;
110     paint.setColor(SK_ColorBLACK);
111 
112     SkCanvas* canvas =
113             document->beginPage(pageSize.width(),
114                                 pageSize.height());
115     SkPDF::SetNodeId(canvas, 2);
116     SkFont font(nullptr, 36);
117     canvas->drawString("Tagged PDF Table", 72, 72, font, paint);
118 
119     font.setSize(14);
120     for (int rowIndex = 0; rowIndex < kRowCount; rowIndex++) {
121         for (int colIndex = 0; colIndex < kColCount; colIndex++) {
122             int cellIndex = rowIndex * kColCount + colIndex;
123             const char* str = cellData[cellIndex];
124             if (!str)
125                 continue;
126 
127             int x = 72 + colIndex * 108 + (colIndex > 0 ? 72 : 0);
128             int y = 144 + rowIndex * 48;
129 
130             SkPDF::SetNodeId(canvas, 10 + cellIndex);
131             canvas->drawString(str, x, y, font, paint);
132         }
133     }
134 
135     document->endPage();
136     document->close();
137     outputStream.flush();
138 }
139 
140 #endif
141