1 /* 2 * Copyright 2018 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #ifndef SkPDFTag_DEFINED 9 #define SkPDFTag_DEFINED 10 11 #include "include/core/SkSpan.h" 12 #include "include/core/SkString.h" 13 #include "include/docs/SkPDFDocument.h" 14 #include "include/private/base/SkTArray.h" 15 #include "src/base/SkArenaAlloc.h" 16 #include "src/core/SkTHash.h" 17 #include "src/pdf/SkPDFTypes.h" 18 19 #include <cstddef> 20 21 class SkPDFDocument; 22 struct SkPDFStructElem; 23 struct SkPoint; 24 25 class SkPDFStructTree { 26 public: 27 SkPDFStructTree(SkPDF::StructureElementNode*, SkPDF::Metadata::Outline); 28 SkPDFStructTree(const SkPDFStructTree&) = delete; 29 SkPDFStructTree& operator=(const SkPDFStructTree&) = delete; 30 SkPDFStructTree(SkPDFStructTree&&) = delete; 31 SkPDFStructTree& operator=(SkPDFStructTree&&) = delete; 32 ~SkPDFStructTree(); 33 34 class Mark { 35 SkPDFStructElem* fStructElem; 36 size_t fMarkIndex; 37 public: Mark(SkPDFStructElem * structElem,size_t markIndex)38 Mark(SkPDFStructElem* structElem, size_t markIndex) 39 : fStructElem(structElem), fMarkIndex(markIndex) {} Mark()40 Mark() : Mark(nullptr, 0) {} 41 Mark(const Mark&) = default; 42 Mark& operator=(const Mark&) = default; 43 Mark(Mark&&) = default; 44 Mark& operator=(Mark&&) = default; 45 46 explicit operator bool() const { return fStructElem; } 47 int mcid() const; // mcid < 0 means no active mark, if bool(this) always >= 0 48 int elemId() const; // 0 elemId means no active structure element 49 SkString structType() const; // only call when bool(this) 50 void accumulate(SkPoint); // only call when bool(this) 51 }; 52 53 // Create a new marked-content identifier (MCID) to be used with a marked-content sequence 54 // parented by the structure element (StructElem) with the given element identifier (elemId). 55 // The StructTreeRoot::ParentTree[Page::StructParent][mcid] will refer to the structure element. 56 // The structure element will add this MCID as its next child (in StructElem::K). 57 // Returns a false Mark if if elemId does not refer to a StructElem. 58 SkPDFStructTree::Mark createMarkForElemId(int elemId, unsigned pageIndex); 59 60 // Create a key to use with /StructParent in a content item (usually an annotation) which refers 61 // to the structure element (StructElem) with the given element identifier (elemId). 62 // The StructTreeRoot ParentTree will map from this key to the structure element. 63 // The structure element will add the content item as its next child (as StructElem::K::OBJR). 64 // Returns -1 if elemId does not refer to a StructElem. 65 int createStructParentKeyForElemId(int elemId, SkPDFIndirectReference contentItemRef, 66 unsigned pageIndex); 67 68 void addStructElemTitle(int elemId, SkSpan<const char>); 69 SkPDFIndirectReference emitStructTreeRoot(SkPDFDocument* doc) const; 70 SkPDFIndirectReference makeOutline(SkPDFDocument* doc) const; 71 SkString getRootLanguage(); 72 73 // An entry in an ordered map from an element identifier to an indirect reference to its 74 // corresponding structure element. 75 struct IDTreeEntry { 76 int elemId; 77 SkPDFIndirectReference structElemRef; 78 }; 79 private: 80 void move(SkPDF::StructureElementNode& node, SkPDFStructElem* structElem, bool wantTitle); 81 82 SkArenaAlloc fArena; 83 skia_private::THashMap<int, SkPDFStructElem*> fStructElemForElemId; 84 SkPDFStructElem* fRoot = nullptr; 85 SkPDF::Metadata::Outline fOutline = SkPDF::Metadata::Outline::None; 86 // fStructElemForMcidForPage[Page::StructParents][mcid] -> parent StructElem of mcid 87 skia_private::TArray<skia_private::TArray<SkPDFStructElem*>> fStructElemForMcidForPage; 88 // fStructElemForContentItem[?::StructParent] -> parent StructElem of content-item 89 skia_private::TArray<SkPDFStructElem*> fStructElemForContentItem; 90 }; 91 92 #endif 93