Simplify interface to StructureElementNode.
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>
This commit is contained in:
parent
1d589a578c
commit
6ffabbb4c4
@ -108,11 +108,19 @@ private:
|
||||
NodeIDs should be unique within each tree.
|
||||
*/
|
||||
struct StructureElementNode {
|
||||
SkString fTypeString;
|
||||
std::vector<std::unique_ptr<StructureElementNode>> fChildVector;
|
||||
int fNodeId = 0;
|
||||
AttributeList fAttributes;
|
||||
SkString fAlt;
|
||||
SkString fLang;
|
||||
|
||||
// Deprecated. Use fChildVector instead.
|
||||
StructureElementNode* fChildren = nullptr;
|
||||
size_t fChildCount = 0;
|
||||
int fNodeId = 0;
|
||||
|
||||
// Deprecated. Use fTypeString instead.
|
||||
DocumentStructureType fType = DocumentStructureType::kNonStruct;
|
||||
AttributeList fAttributes;
|
||||
};
|
||||
|
||||
/** Optional metadata to be passed into the PDF factory function.
|
||||
|
@ -140,6 +140,9 @@ struct SkPDFTagNode {
|
||||
SkTArray<MarkedContentInfo> fMarkedContent;
|
||||
int fNodeId;
|
||||
SkPDF::DocumentStructureType fType;
|
||||
SkString fTypeString;
|
||||
SkString fAlt;
|
||||
SkString fLang;
|
||||
SkPDFIndirectReference fRef;
|
||||
enum State {
|
||||
kUnknown,
|
||||
@ -159,15 +162,31 @@ void SkPDFTagTree::Copy(SkPDF::StructureElementNode& node,
|
||||
SkArenaAlloc* arena,
|
||||
SkTHashMap<int, SkPDFTagNode*>* nodeMap) {
|
||||
nodeMap->set(node.fNodeId, dst);
|
||||
size_t childCount = node.fChildCount;
|
||||
SkPDFTagNode* children = arena->makeArray<SkPDFTagNode>(childCount);
|
||||
dst->fChildCount = childCount;
|
||||
dst->fNodeId = node.fNodeId;
|
||||
dst->fType = node.fType;
|
||||
dst->fChildren = children;
|
||||
for (size_t i = 0; i < childCount; ++i) {
|
||||
Copy(node.fChildren[i], &children[i], arena, nodeMap);
|
||||
dst->fTypeString = node.fTypeString;
|
||||
dst->fAlt = node.fAlt;
|
||||
dst->fLang = node.fLang;
|
||||
|
||||
// Temporarily support both raw fChildren and fChildVector.
|
||||
if (node.fChildren) {
|
||||
size_t childCount = node.fChildCount;
|
||||
SkPDFTagNode* children = arena->makeArray<SkPDFTagNode>(childCount);
|
||||
dst->fChildCount = childCount;
|
||||
dst->fChildren = children;
|
||||
for (size_t i = 0; i < childCount; ++i) {
|
||||
Copy(node.fChildren[i], &children[i], arena, nodeMap);
|
||||
}
|
||||
} else {
|
||||
size_t childCount = node.fChildVector.size();
|
||||
SkPDFTagNode* children = arena->makeArray<SkPDFTagNode>(childCount);
|
||||
dst->fChildCount = childCount;
|
||||
dst->fChildren = children;
|
||||
for (size_t i = 0; i < childCount; ++i) {
|
||||
Copy(*node.fChildVector[i], &children[i], arena, nodeMap);
|
||||
}
|
||||
}
|
||||
|
||||
dst->fAttributes = std::move(node.fAttributes.fAttrs);
|
||||
}
|
||||
|
||||
@ -248,7 +267,17 @@ SkPDFIndirectReference prepare_tag_tree_to_emit(SkPDFIndirectReference parent,
|
||||
}
|
||||
node->fRef = ref;
|
||||
SkPDFDict dict("StructElem");
|
||||
dict.insertName("S", tag_name_from_type(node->fType));
|
||||
if (!node->fTypeString.isEmpty()) {
|
||||
dict.insertName("S", node->fTypeString.c_str());
|
||||
} else {
|
||||
dict.insertName("S", tag_name_from_type(node->fType));
|
||||
}
|
||||
if (!node->fAlt.isEmpty()) {
|
||||
dict.insertName("Alt", node->fAlt);
|
||||
}
|
||||
if (!node->fLang.isEmpty()) {
|
||||
dict.insertName("Lang", node->fLang);
|
||||
}
|
||||
dict.insertRef("P", parent);
|
||||
dict.insertObject("K", std::move(kids));
|
||||
SkString idString;
|
||||
|
@ -47,61 +47,58 @@ DEF_TEST(SkPDF_tagged_table, r) {
|
||||
};
|
||||
|
||||
// The document tag.
|
||||
PDFTag root;
|
||||
root.fNodeId = 1;
|
||||
root.fType = SkPDF::DocumentStructureType::kDocument;
|
||||
root.fChildCount = 2;
|
||||
PDFTag rootChildren[2];
|
||||
auto root = std::make_unique<PDFTag>();
|
||||
root->fNodeId = 1;
|
||||
root->fTypeString = "Document";
|
||||
root->fLang = "en-US";
|
||||
|
||||
// Heading.
|
||||
PDFTag& h1 = rootChildren[0];
|
||||
h1.fNodeId = 2;
|
||||
h1.fType = SkPDF::DocumentStructureType::kH1;
|
||||
h1.fChildCount = 0;
|
||||
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.
|
||||
PDFTag& table = rootChildren[1];
|
||||
table.fNodeId = 3;
|
||||
table.fType = SkPDF::DocumentStructureType::kTable;
|
||||
table.fChildCount = 5;
|
||||
table.fAttributes.appendFloatArray("Layout", "BBox", {72, 72, 360, 360});
|
||||
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});
|
||||
|
||||
PDFTag rows[kRowCount];
|
||||
PDFTag all_cells[kRowCount * kColCount];
|
||||
for (int rowIndex = 0; rowIndex < kRowCount; rowIndex++) {
|
||||
PDFTag& row = rows[rowIndex];
|
||||
row.fNodeId = 4 + rowIndex;
|
||||
row.fType = SkPDF::DocumentStructureType::kTR;
|
||||
row.fChildCount = kColCount;
|
||||
PDFTag* cells = &all_cells[rowIndex * kColCount];
|
||||
|
||||
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;
|
||||
PDFTag& cell = cells[colIndex];
|
||||
cell.fNodeId = 10 + cellIndex;
|
||||
if (!cellData[cellIndex])
|
||||
cell.fType = SkPDF::DocumentStructureType::kNonStruct;
|
||||
else if (rowIndex == 0 || colIndex == 0)
|
||||
cell.fType = SkPDF::DocumentStructureType::kTH;
|
||||
else
|
||||
cell.fType = SkPDF::DocumentStructureType::kTD;
|
||||
cell.fChildCount = 0;
|
||||
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);
|
||||
cell->fAttributes.appendInt("Table", "RowSpan", 2);
|
||||
} else if (cellIndex == 14 || cellIndex == 18) {
|
||||
cell.fAttributes.appendInt("Table", "ColSpan", 2);
|
||||
} else if (cell.fType == SkPDF::DocumentStructureType::kTH) {
|
||||
cell.fAttributes.appendString(
|
||||
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));
|
||||
}
|
||||
row.fChildren = cells;
|
||||
rows.push_back(std::move(row));
|
||||
}
|
||||
table.fChildren = rows;
|
||||
root.fChildren = rootChildren;
|
||||
root->fChildVector.push_back(std::move(table));
|
||||
|
||||
metadata.fStructureElementTreeRoot = &root;
|
||||
metadata.fStructureElementTreeRoot = root.get();
|
||||
sk_sp<SkDocument> document = SkPDF::MakeDocument(
|
||||
&outputStream, metadata);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user