6ffabbb4c4
Use a std::vector of std::unique_ptr for the children, rather than an error-prone raw pointer. Use a string for the element type, rather than an enum. In both cases, both the old and new format are supported and tested within Skia until Chromium has migrated. Also add support for Alt and Lang, which are like attributes but go right on the structure node. There are only a small handful of attributes that go on the structure node so this seems like the simplest solution. Bug: chromium:607777 Change-Id: I4f315685df35dd9dcd8e1bca6d275cbeb8f2c67a Reviewed-on: https://skia-review.googlesource.com/c/skia/+/271816 Reviewed-by: Mike Reed <reed@google.com> Commit-Queue: Dominic Mazzoni <dmazzoni@chromium.org>
137 lines
4.4 KiB
C++
137 lines
4.4 KiB
C++
/*
|
|
* Copyright 2020 Google Inc.
|
|
*
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
* found in the LICENSE file.
|
|
*/
|
|
#include "tests/Test.h"
|
|
|
|
#ifdef SK_SUPPORT_PDF
|
|
|
|
#include "include/core/SkCanvas.h"
|
|
#include "include/core/SkFont.h"
|
|
#include "include/core/SkStream.h"
|
|
#include "include/docs/SkPDFDocument.h"
|
|
|
|
using PDFTag = SkPDF::StructureElementNode;
|
|
|
|
// Test building a tagged PDF containing a table.
|
|
// Add this to args.gn to output the PDF to a file:
|
|
// extra_cflags = [ "-DSK_PDF_TEST_TAGS_OUTPUT_PATH=\"/tmp/table.pdf\"" ]
|
|
DEF_TEST(SkPDF_tagged_table, r) {
|
|
REQUIRE_PDF_DOCUMENT(SkPDF_tagged, r);
|
|
#ifdef SK_PDF_TEST_TAGS_OUTPUT_PATH
|
|
SkFILEWStream outputStream(SK_PDF_TEST_TAGS_OUTPUT_PATH);
|
|
#else
|
|
SkDynamicMemoryWStream outputStream;
|
|
#endif
|
|
|
|
SkSize pageSize = SkSize::Make(612, 792); // U.S. Letter
|
|
|
|
SkPDF::Metadata metadata;
|
|
metadata.fTitle = "Example Tagged Table PDF";
|
|
metadata.fCreator = "Skia";
|
|
SkTime::DateTime now;
|
|
SkTime::GetDateTime(&now);
|
|
metadata.fCreation = now;
|
|
metadata.fModified = now;
|
|
|
|
constexpr int kRowCount = 5;
|
|
constexpr int kColCount = 4;
|
|
const char* cellData[kRowCount * kColCount] = {
|
|
"Car", "Engine", "City MPG", "Highway MPG",
|
|
"Mitsubishi Mirage ES", "Gas", "28", "47",
|
|
"Toyota Prius Three", "Hybrid", "43", "59",
|
|
"Nissan Leaf SL", "Electric", "N/A", nullptr,
|
|
"Tesla Model 3", nullptr, "N/A", nullptr
|
|
};
|
|
|
|
// The document tag.
|
|
auto root = std::make_unique<PDFTag>();
|
|
root->fNodeId = 1;
|
|
root->fTypeString = "Document";
|
|
root->fLang = "en-US";
|
|
|
|
// Heading.
|
|
auto h1 = std::make_unique<PDFTag>();
|
|
h1->fNodeId = 2;
|
|
h1->fTypeString = "H1";
|
|
h1->fAlt = "Tagged PDF Table Alt Text";
|
|
root->fChildVector.push_back(std::move(h1));
|
|
|
|
// Table.
|
|
auto table = std::make_unique<PDFTag>();
|
|
table->fNodeId = 3;
|
|
table->fTypeString = "Table";
|
|
auto& rows = table->fChildVector;
|
|
table->fAttributes.appendFloatArray("Layout", "BBox", {72, 72, 360, 360});
|
|
|
|
for (int rowIndex = 0; rowIndex < kRowCount; rowIndex++) {
|
|
auto row = std::make_unique<PDFTag>();
|
|
row->fNodeId = 4 + rowIndex;
|
|
row->fTypeString = "TR";
|
|
auto& cells = row->fChildVector;
|
|
for (int colIndex = 0; colIndex < kColCount; colIndex++) {
|
|
auto cell = std::make_unique<PDFTag>();
|
|
int cellIndex = rowIndex * kColCount + colIndex;
|
|
cell->fNodeId = 10 + cellIndex;
|
|
if (!cellData[cellIndex]) {
|
|
cell->fTypeString = "NonStruct";
|
|
} else if (rowIndex == 0 || colIndex == 0) {
|
|
cell->fTypeString = "TH";
|
|
} else {
|
|
cell->fTypeString = "TD";
|
|
}
|
|
cell->fChildCount = 0;
|
|
|
|
if (cellIndex == 13) {
|
|
cell->fAttributes.appendInt("Table", "RowSpan", 2);
|
|
} else if (cellIndex == 14 || cellIndex == 18) {
|
|
cell->fAttributes.appendInt("Table", "ColSpan", 2);
|
|
} else if (rowIndex == 0 || colIndex == 0) {
|
|
cell->fAttributes.appendString(
|
|
"Table", "Scope", rowIndex == 0 ? "Column" : "Row");
|
|
}
|
|
cells.push_back(std::move(cell));
|
|
}
|
|
rows.push_back(std::move(row));
|
|
}
|
|
root->fChildVector.push_back(std::move(table));
|
|
|
|
metadata.fStructureElementTreeRoot = root.get();
|
|
sk_sp<SkDocument> document = SkPDF::MakeDocument(
|
|
&outputStream, metadata);
|
|
|
|
SkPaint paint;
|
|
paint.setColor(SK_ColorBLACK);
|
|
|
|
SkCanvas* canvas =
|
|
document->beginPage(pageSize.width(),
|
|
pageSize.height());
|
|
SkPDF::SetNodeId(canvas, 2);
|
|
SkFont font(nullptr, 36);
|
|
canvas->drawString("Tagged PDF Table", 72, 72, font, paint);
|
|
|
|
font.setSize(14);
|
|
for (int rowIndex = 0; rowIndex < kRowCount; rowIndex++) {
|
|
for (int colIndex = 0; colIndex < kColCount; colIndex++) {
|
|
int cellIndex = rowIndex * kColCount + colIndex;
|
|
const char* str = cellData[cellIndex];
|
|
if (!str)
|
|
continue;
|
|
|
|
int x = 72 + colIndex * 108 + (colIndex > 0 ? 72 : 0);
|
|
int y = 144 + rowIndex * 48;
|
|
|
|
SkPDF::SetNodeId(canvas, 10 + cellIndex);
|
|
canvas->drawString(str, x, y, font, paint);
|
|
}
|
|
}
|
|
|
|
document->endPage();
|
|
document->close();
|
|
outputStream.flush();
|
|
}
|
|
|
|
#endif
|