| /* |
| * Copyright 2018 Google LLC |
| * |
| * 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/SkTArray.h" |
| #include "src/core/SkArenaAlloc.h" |
| #include "src/core/SkTHash.h" |
| #include "src/pdf/SkPDFTypes.h" |
| |
| #include <cstddef> |
| #include <variant> |
| |
| 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[?::StructParents][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. |
| // |
| // If a true Mark is returned and structParentsKey is false, the Mark will be added to a new |
| // StructParents and structParentsKey will be updated to reference the StructParents entry. |
| SkPDFStructTree::Mark createMarkForElemId(int elemId, unsigned pageIndex, |
| SkPDFParentTreeKey& structParentsKey); |
| |
| static constexpr SkPDFIndirectReference kPageContentStreamRef = SkPDFIndirectReference{-2}; |
| void setContentStreamRefForStructParentsKey(SkPDFParentTreeKey structParentsKey, |
| SkPDFIndirectReference contentStreamRef); |
| SkPDFIndirectReference getContentStreamRefForStructParentsKey( |
| SkPDFParentTreeKey structParentsKey) const; |
| |
| // 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. |
| SkPDFParentTreeKey createStructParentKeyForElemId(int elemId, unsigned pageIndex, |
| SkPDFIndirectReference contentItemRef); |
| SkPDFIndirectReference getContentItemRefForStructParentKey( |
| SkPDFParentTreeKey structParentKey) const; |
| |
| 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; |
| |
| struct Item { |
| SkPDFStructElem* fStructElem; |
| SkPDFIndirectReference fContentItemRef; |
| }; |
| struct Stream { |
| skia_private::TArray<SkPDFStructElem*> fChildren; // indexed by mcid |
| // the non-page content stream reference, kPageContentStreamRef, or empty |
| SkPDFIndirectReference fContentStreamRef; |
| }; |
| using ParentTreeEntry = std::variant<Item, Stream>; |
| // indexed by ?::StructParent or ?::StructParents |
| skia_private::TArray<ParentTreeEntry> fParentTree; |
| }; |
| |
| #endif |