1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/skia/trunk/src/pdf/SkPDFPage.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,158 @@ 1.4 + 1.5 +/* 1.6 + * Copyright 2010 The Android Open Source Project 1.7 + * 1.8 + * Use of this source code is governed by a BSD-style license that can be 1.9 + * found in the LICENSE file. 1.10 + */ 1.11 + 1.12 + 1.13 +#include "SkPDFCatalog.h" 1.14 +#include "SkPDFDevice.h" 1.15 +#include "SkPDFPage.h" 1.16 +#include "SkPDFResourceDict.h" 1.17 +#include "SkStream.h" 1.18 + 1.19 +SkPDFPage::SkPDFPage(SkPDFDevice* content) 1.20 + : SkPDFDict("Page"), 1.21 + fDevice(content) { 1.22 + SkSafeRef(content); 1.23 +} 1.24 + 1.25 +SkPDFPage::~SkPDFPage() {} 1.26 + 1.27 +void SkPDFPage::finalizePage(SkPDFCatalog* catalog, bool firstPage, 1.28 + const SkTSet<SkPDFObject*>& knownResourceObjects, 1.29 + SkTSet<SkPDFObject*>* newResourceObjects) { 1.30 + SkPDFResourceDict* resourceDict = fDevice->getResourceDict(); 1.31 + if (fContentStream.get() == NULL) { 1.32 + insert("Resources", resourceDict); 1.33 + SkSafeUnref(this->insert("MediaBox", fDevice->copyMediaBox())); 1.34 + if (!SkToBool(catalog->getDocumentFlags() & 1.35 + SkPDFDocument::kNoLinks_Flags)) { 1.36 + SkPDFArray* annots = fDevice->getAnnotations(); 1.37 + if (annots && annots->size() > 0) { 1.38 + insert("Annots", annots); 1.39 + } 1.40 + } 1.41 + 1.42 + SkAutoTUnref<SkStream> content(fDevice->content()); 1.43 + fContentStream.reset(new SkPDFStream(content.get())); 1.44 + insert("Contents", new SkPDFObjRef(fContentStream.get()))->unref(); 1.45 + } 1.46 + catalog->addObject(fContentStream.get(), firstPage); 1.47 + resourceDict->getReferencedResources(knownResourceObjects, 1.48 + newResourceObjects, 1.49 + true); 1.50 +} 1.51 + 1.52 +off_t SkPDFPage::getPageSize(SkPDFCatalog* catalog, off_t fileOffset) { 1.53 + SkASSERT(fContentStream.get() != NULL); 1.54 + catalog->setFileOffset(fContentStream.get(), fileOffset); 1.55 + return fContentStream->getOutputSize(catalog, true); 1.56 +} 1.57 + 1.58 +void SkPDFPage::emitPage(SkWStream* stream, SkPDFCatalog* catalog) { 1.59 + SkASSERT(fContentStream.get() != NULL); 1.60 + fContentStream->emitObject(stream, catalog, true); 1.61 +} 1.62 + 1.63 +// static 1.64 +void SkPDFPage::GeneratePageTree(const SkTDArray<SkPDFPage*>& pages, 1.65 + SkPDFCatalog* catalog, 1.66 + SkTDArray<SkPDFDict*>* pageTree, 1.67 + SkPDFDict** rootNode) { 1.68 + // PDF wants a tree describing all the pages in the document. We arbitrary 1.69 + // choose 8 (kNodeSize) as the number of allowed children. The internal 1.70 + // nodes have type "Pages" with an array of children, a parent pointer, and 1.71 + // the number of leaves below the node as "Count." The leaves are passed 1.72 + // into the method, have type "Page" and need a parent pointer. This method 1.73 + // builds the tree bottom up, skipping internal nodes that would have only 1.74 + // one child. 1.75 + static const int kNodeSize = 8; 1.76 + 1.77 + SkAutoTUnref<SkPDFName> kidsName(new SkPDFName("Kids")); 1.78 + SkAutoTUnref<SkPDFName> countName(new SkPDFName("Count")); 1.79 + SkAutoTUnref<SkPDFName> parentName(new SkPDFName("Parent")); 1.80 + 1.81 + // curNodes takes a reference to its items, which it passes to pageTree. 1.82 + SkTDArray<SkPDFDict*> curNodes; 1.83 + curNodes.setReserve(pages.count()); 1.84 + for (int i = 0; i < pages.count(); i++) { 1.85 + SkSafeRef(pages[i]); 1.86 + curNodes.push(pages[i]); 1.87 + } 1.88 + 1.89 + // nextRoundNodes passes its references to nodes on to curNodes. 1.90 + SkTDArray<SkPDFDict*> nextRoundNodes; 1.91 + nextRoundNodes.setReserve((pages.count() + kNodeSize - 1)/kNodeSize); 1.92 + 1.93 + int treeCapacity = kNodeSize; 1.94 + do { 1.95 + for (int i = 0; i < curNodes.count(); ) { 1.96 + if (i > 0 && i + 1 == curNodes.count()) { 1.97 + nextRoundNodes.push(curNodes[i]); 1.98 + break; 1.99 + } 1.100 + 1.101 + SkPDFDict* newNode = new SkPDFDict("Pages"); 1.102 + SkAutoTUnref<SkPDFObjRef> newNodeRef(new SkPDFObjRef(newNode)); 1.103 + 1.104 + SkAutoTUnref<SkPDFArray> kids(new SkPDFArray); 1.105 + kids->reserve(kNodeSize); 1.106 + 1.107 + int count = 0; 1.108 + for (; i < curNodes.count() && count < kNodeSize; i++, count++) { 1.109 + curNodes[i]->insert(parentName.get(), newNodeRef.get()); 1.110 + kids->append(new SkPDFObjRef(curNodes[i]))->unref(); 1.111 + 1.112 + // TODO(vandebo): put the objects in strict access order. 1.113 + // Probably doesn't matter because they are so small. 1.114 + if (curNodes[i] != pages[0]) { 1.115 + pageTree->push(curNodes[i]); // Transfer reference. 1.116 + catalog->addObject(curNodes[i], false); 1.117 + } else { 1.118 + SkSafeUnref(curNodes[i]); 1.119 + catalog->addObject(curNodes[i], true); 1.120 + } 1.121 + } 1.122 + 1.123 + // treeCapacity is the number of leaf nodes possible for the 1.124 + // current set of subtrees being generated. (i.e. 8, 64, 512, ...). 1.125 + // It is hard to count the number of leaf nodes in the current 1.126 + // subtree. However, by construction, we know that unless it's the 1.127 + // last subtree for the current depth, the leaf count will be 1.128 + // treeCapacity, otherwise it's what ever is left over after 1.129 + // consuming treeCapacity chunks. 1.130 + int pageCount = treeCapacity; 1.131 + if (i == curNodes.count()) { 1.132 + pageCount = ((pages.count() - 1) % treeCapacity) + 1; 1.133 + } 1.134 + newNode->insert(countName.get(), new SkPDFInt(pageCount))->unref(); 1.135 + newNode->insert(kidsName.get(), kids.get()); 1.136 + nextRoundNodes.push(newNode); // Transfer reference. 1.137 + } 1.138 + 1.139 + curNodes = nextRoundNodes; 1.140 + nextRoundNodes.rewind(); 1.141 + treeCapacity *= kNodeSize; 1.142 + } while (curNodes.count() > 1); 1.143 + 1.144 + pageTree->push(curNodes[0]); // Transfer reference. 1.145 + catalog->addObject(curNodes[0], false); 1.146 + if (rootNode) { 1.147 + *rootNode = curNodes[0]; 1.148 + } 1.149 +} 1.150 + 1.151 +const SkTDArray<SkPDFFont*>& SkPDFPage::getFontResources() const { 1.152 + return fDevice->getFontResources(); 1.153 +} 1.154 + 1.155 +const SkPDFGlyphSetMap& SkPDFPage::getFontGlyphUsage() const { 1.156 + return fDevice->getFontGlyphUsage(); 1.157 +} 1.158 + 1.159 +void SkPDFPage::appendDestinations(SkPDFDict* dict) { 1.160 + fDevice->appendDestinations(dict, this); 1.161 +}