127c607818
In PDF files, "names" and "strings" are not the same thing, but I was conflating them. Separate out the interfaces for adding attributes to PDF struct tree elements so there's a way to add either a name or a string, and similarly for arrays of names or arrays of strings. Fix the table test to correctly use a name for the "Scope" attribute and an array of strings for the "Headers" attribute. Bug: chromium:607777 Change-Id: Ib30bded2bbcf96e31ba6925fb062615558dea0db Reviewed-on: https://skia-review.googlesource.com/c/skia/+/296338 Reviewed-by: Ben Wagner <bungeman@google.com> Reviewed-by: Derek Sollenberger <djsollen@google.com> Auto-Submit: Dominic Mazzoni <dmazzoni@chromium.org> Commit-Queue: Derek Sollenberger <djsollen@google.com>
146 lines
4.9 KiB
C++
146 lines
4.9 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";
|
|
std::vector<SkString> headers;
|
|
SkString rowHeaderIdString;
|
|
rowHeaderIdString.printf("node%08d", 10 + rowIndex * kColCount);
|
|
headers.push_back(rowHeaderIdString);
|
|
SkString colHeaderIdString;
|
|
colHeaderIdString.printf("node%08d", 10 + colIndex);
|
|
headers.push_back(colHeaderIdString);
|
|
cell->fAttributes.appendStringArray(
|
|
"Table", "Headers", headers);
|
|
}
|
|
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.appendName(
|
|
"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
|