blob: ef51d9fd86d431bd996fe7e543d0cb6532e06248 [file] [log] [blame]
/*
* Copyright 2018 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkPDFTag_DEFINED
#define SkPDFTag_DEFINED
#include "include/core/SkSpan.h"
#include "include/core/SkString.h"
#include "include/docs/SkPDFDocument.h"
#include "include/private/base/SkTArray.h"
#include "src/base/SkArenaAlloc.h"
#include "src/core/SkTHash.h"
#include "src/pdf/SkPDFTypes.h"
#include <cstddef>
class SkPDFDocument;
struct SkPDFStructElem;
struct SkPoint;
class SkPDFStructTree {
public:
SkPDFStructTree(SkPDF::StructureElementNode*, SkPDF::Metadata::Outline);
SkPDFStructTree(const SkPDFStructTree&) = delete;
SkPDFStructTree& operator=(const SkPDFStructTree&) = delete;
SkPDFStructTree(SkPDFStructTree&&) = delete;
SkPDFStructTree& operator=(SkPDFStructTree&&) = delete;
~SkPDFStructTree();
class Mark {
SkPDFStructElem* fStructElem;
size_t fMarkIndex;
public:
Mark(SkPDFStructElem* structElem, size_t markIndex)
: fStructElem(structElem), fMarkIndex(markIndex) {}
Mark() : Mark(nullptr, 0) {}
Mark(const Mark&) = default;
Mark& operator=(const Mark&) = default;
Mark(Mark&&) = default;
Mark& operator=(Mark&&) = default;
explicit operator bool() const { return fStructElem; }
int mcid() const; // mcid < 0 means no active mark, if bool(this) always >= 0
int elemId() const; // 0 elemId means no active structure element
SkString structType() const; // only call when bool(this)
void accumulate(SkPoint); // only call when bool(this)
};
// Create a new marked-content identifier (MCID) to be used with a marked-content sequence
// parented by the structure element (StructElem) with the given element identifier (elemId).
// The StructTreeRoot::ParentTree[Page::StructParent][mcid] will refer to the structure element.
// The structure element will add this MCID as its next child (in StructElem::K).
// Returns a false Mark if if elemId does not refer to a StructElem.
SkPDFStructTree::Mark createMarkForElemId(int elemId, unsigned pageIndex);
// Create a key to use with /StructParent in a content item (usually an annotation) which refers
// to the structure element (StructElem) with the given element identifier (elemId).
// The StructTreeRoot ParentTree will map from this key to the structure element.
// The structure element will add the content item as its next child (as StructElem::K::OBJR).
// Returns -1 if elemId does not refer to a StructElem.
int createStructParentKeyForElemId(int elemId, SkPDFIndirectReference contentItemRef,
unsigned pageIndex);
void addStructElemTitle(int elemId, SkSpan<const char>);
SkPDFIndirectReference emitStructTreeRoot(SkPDFDocument* doc) const;
SkPDFIndirectReference makeOutline(SkPDFDocument* doc) const;
SkString getRootLanguage();
// An entry in an ordered map from an element identifier to an indirect reference to its
// corresponding structure element.
struct IDTreeEntry {
int elemId;
SkPDFIndirectReference structElemRef;
};
private:
void move(SkPDF::StructureElementNode& node, SkPDFStructElem* structElem, bool wantTitle);
SkArenaAlloc fArena;
skia_private::THashMap<int, SkPDFStructElem*> fStructElemForElemId;
SkPDFStructElem* fRoot = nullptr;
SkPDF::Metadata::Outline fOutline = SkPDF::Metadata::Outline::None;
// fStructElemForMcidForPage[Page::StructParents][mcid] -> parent StructElem of mcid
skia_private::TArray<skia_private::TArray<SkPDFStructElem*>> fStructElemForMcidForPage;
// fStructElemForContentItem[?::StructParent] -> parent StructElem of content-item
skia_private::TArray<SkPDFStructElem*> fStructElemForContentItem;
};
#endif