1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com 2d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org/* 3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright 2010 The Android Open Source Project 4d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org * 5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Use of this source code is governed by a BSD-style license that can be 6ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * found in the LICENSE file. 7d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org */ 8d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org 9ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com 1067ec1f8eecfb48bc0a6ba04c0057f103c1c9696fhalcanary#include "SkData.h" 11d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org#include "SkPDFCatalog.h" 12d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org#include "SkPDFDevice.h" 13d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org#include "SkPDFPage.h" 1447401354074549d8591da7fa115241766d3ee3d2commit-bot@chromium.org#include "SkPDFResourceDict.h" 15d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org 161feb33068b1313d2647c50b90ae8e0a3d510db2ereed@google.comSkPDFPage::SkPDFPage(SkPDFDevice* content) 17d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org : SkPDFDict("Page"), 18d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org fDevice(content) { 19d96d17b9c113ac694138224249ff2ce643e961ddvandebo@chromium.org SkSafeRef(content); 20d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org} 21d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org 22d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.orgSkPDFPage::~SkPDFPage() {} 23d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org 24d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.orgvoid SkPDFPage::finalizePage(SkPDFCatalog* catalog, bool firstPage, 256addb1930013ebb2f984045141650fd7afcfa90fedisonn@google.com const SkTSet<SkPDFObject*>& knownResourceObjects, 266addb1930013ebb2f984045141650fd7afcfa90fedisonn@google.com SkTSet<SkPDFObject*>* newResourceObjects) { 2747401354074549d8591da7fa115241766d3ee3d2commit-bot@chromium.org SkPDFResourceDict* resourceDict = fDevice->getResourceDict(); 28d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org if (fContentStream.get() == NULL) { 2947401354074549d8591da7fa115241766d3ee3d2commit-bot@chromium.org insert("Resources", resourceDict); 302a006c112743e07ce258ca223631fc19233f5ddcreed@google.com SkSafeUnref(this->insert("MediaBox", fDevice->copyMediaBox())); 31238be8c7e5de5a83517440a3db7f7965b47fb010vandebo@chromium.org if (!SkToBool(catalog->getDocumentFlags() & 32238be8c7e5de5a83517440a3db7f7965b47fb010vandebo@chromium.org SkPDFDocument::kNoLinks_Flags)) { 332a006c112743e07ce258ca223631fc19233f5ddcreed@google.com SkPDFArray* annots = fDevice->getAnnotations(); 342a006c112743e07ce258ca223631fc19233f5ddcreed@google.com if (annots && annots->size() > 0) { 352a006c112743e07ce258ca223631fc19233f5ddcreed@google.com insert("Annots", annots); 36238be8c7e5de5a83517440a3db7f7965b47fb010vandebo@chromium.org } 37238be8c7e5de5a83517440a3db7f7965b47fb010vandebo@chromium.org } 38d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org 3967ec1f8eecfb48bc0a6ba04c0057f103c1c9696fhalcanary SkAutoTUnref<SkData> content(fDevice->copyContentToData()); 40d96d17b9c113ac694138224249ff2ce643e961ddvandebo@chromium.org fContentStream.reset(new SkPDFStream(content.get())); 41f7c157610ff85f7323f5e213b62478dcc66edbecvandebo@chromium.org insert("Contents", new SkPDFObjRef(fContentStream.get()))->unref(); 42d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org } 43d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org catalog->addObject(fContentStream.get(), firstPage); 4447401354074549d8591da7fa115241766d3ee3d2commit-bot@chromium.org resourceDict->getReferencedResources(knownResourceObjects, 4547401354074549d8591da7fa115241766d3ee3d2commit-bot@chromium.org newResourceObjects, 4647401354074549d8591da7fa115241766d3ee3d2commit-bot@chromium.org true); 47d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org} 48d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org 49d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.orgoff_t SkPDFPage::getPageSize(SkPDFCatalog* catalog, off_t fileOffset) { 50d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org SkASSERT(fContentStream.get() != NULL); 5130580f69493fd8aa86c223736b4f7564ce458760vandebo@chromium.org catalog->setFileOffset(fContentStream.get(), fileOffset); 52d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org return fContentStream->getOutputSize(catalog, true); 53d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org} 54d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org 55d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.orgvoid SkPDFPage::emitPage(SkWStream* stream, SkPDFCatalog* catalog) { 56d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org SkASSERT(fContentStream.get() != NULL); 57d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org fContentStream->emitObject(stream, catalog, true); 58d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org} 59d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org 60d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org// static 61f6c3ebdeb135dcdb9af225bd7af77f1fe1f92787reed@google.comvoid SkPDFPage::GeneratePageTree(const SkTDArray<SkPDFPage*>& pages, 62d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org SkPDFCatalog* catalog, 63d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org SkTDArray<SkPDFDict*>* pageTree, 64d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org SkPDFDict** rootNode) { 65bd36ebe29463c4b70f5c91bb2440cdcf45b22b52vandebo@chromium.org // PDF wants a tree describing all the pages in the document. We arbitrary 66bd36ebe29463c4b70f5c91bb2440cdcf45b22b52vandebo@chromium.org // choose 8 (kNodeSize) as the number of allowed children. The internal 67bd36ebe29463c4b70f5c91bb2440cdcf45b22b52vandebo@chromium.org // nodes have type "Pages" with an array of children, a parent pointer, and 68bd36ebe29463c4b70f5c91bb2440cdcf45b22b52vandebo@chromium.org // the number of leaves below the node as "Count." The leaves are passed 69bd36ebe29463c4b70f5c91bb2440cdcf45b22b52vandebo@chromium.org // into the method, have type "Page" and need a parent pointer. This method 70bd36ebe29463c4b70f5c91bb2440cdcf45b22b52vandebo@chromium.org // builds the tree bottom up, skipping internal nodes that would have only 71bd36ebe29463c4b70f5c91bb2440cdcf45b22b52vandebo@chromium.org // one child. 72d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org static const int kNodeSize = 8; 73d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org 74d96d17b9c113ac694138224249ff2ce643e961ddvandebo@chromium.org SkAutoTUnref<SkPDFName> kidsName(new SkPDFName("Kids")); 75d96d17b9c113ac694138224249ff2ce643e961ddvandebo@chromium.org SkAutoTUnref<SkPDFName> countName(new SkPDFName("Count")); 76d96d17b9c113ac694138224249ff2ce643e961ddvandebo@chromium.org SkAutoTUnref<SkPDFName> parentName(new SkPDFName("Parent")); 77d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org 78d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org // curNodes takes a reference to its items, which it passes to pageTree. 79d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org SkTDArray<SkPDFDict*> curNodes; 80d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org curNodes.setReserve(pages.count()); 81d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org for (int i = 0; i < pages.count(); i++) { 8282065d667f64e232bcde2ad849756a6096fcbe6freed@google.com SkSafeRef(pages[i]); 83d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org curNodes.push(pages[i]); 84d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org } 85d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org 86d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org // nextRoundNodes passes its references to nodes on to curNodes. 87d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org SkTDArray<SkPDFDict*> nextRoundNodes; 88d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org nextRoundNodes.setReserve((pages.count() + kNodeSize - 1)/kNodeSize); 89d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org 90bd36ebe29463c4b70f5c91bb2440cdcf45b22b52vandebo@chromium.org int treeCapacity = kNodeSize; 91d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org do { 92d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org for (int i = 0; i < curNodes.count(); ) { 93d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org if (i > 0 && i + 1 == curNodes.count()) { 94d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org nextRoundNodes.push(curNodes[i]); 95d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org break; 96d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org } 97d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org 98d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org SkPDFDict* newNode = new SkPDFDict("Pages"); 99d96d17b9c113ac694138224249ff2ce643e961ddvandebo@chromium.org SkAutoTUnref<SkPDFObjRef> newNodeRef(new SkPDFObjRef(newNode)); 100d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org 101d96d17b9c113ac694138224249ff2ce643e961ddvandebo@chromium.org SkAutoTUnref<SkPDFArray> kids(new SkPDFArray); 102d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org kids->reserve(kNodeSize); 103d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org 104d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org int count = 0; 105d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org for (; i < curNodes.count() && count < kNodeSize; i++, count++) { 106d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org curNodes[i]->insert(parentName.get(), newNodeRef.get()); 107f7c157610ff85f7323f5e213b62478dcc66edbecvandebo@chromium.org kids->append(new SkPDFObjRef(curNodes[i]))->unref(); 108d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org 109769fa6a013baca6d7404e2bf096a34a7e3635fa5ctguil@chromium.org // TODO(vandebo): put the objects in strict access order. 110d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org // Probably doesn't matter because they are so small. 111d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org if (curNodes[i] != pages[0]) { 112a5c7234e81748f76cbeede40e619351146e5286actguil@chromium.org pageTree->push(curNodes[i]); // Transfer reference. 113d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org catalog->addObject(curNodes[i], false); 114d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org } else { 11582065d667f64e232bcde2ad849756a6096fcbe6freed@google.com SkSafeUnref(curNodes[i]); 116fb6a53a406636a81094be8b75180fddcc02ff957vandebo@chromium.org catalog->addObject(curNodes[i], true); 117d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org } 118d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org } 119d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org 1203c974427a95e9f24eae39167cf972506d70359c9vandebo@chromium.org // treeCapacity is the number of leaf nodes possible for the 1213c974427a95e9f24eae39167cf972506d70359c9vandebo@chromium.org // current set of subtrees being generated. (i.e. 8, 64, 512, ...). 1223c974427a95e9f24eae39167cf972506d70359c9vandebo@chromium.org // It is hard to count the number of leaf nodes in the current 1233c974427a95e9f24eae39167cf972506d70359c9vandebo@chromium.org // subtree. However, by construction, we know that unless it's the 1243c974427a95e9f24eae39167cf972506d70359c9vandebo@chromium.org // last subtree for the current depth, the leaf count will be 1253c974427a95e9f24eae39167cf972506d70359c9vandebo@chromium.org // treeCapacity, otherwise it's what ever is left over after 1263c974427a95e9f24eae39167cf972506d70359c9vandebo@chromium.org // consuming treeCapacity chunks. 127bd36ebe29463c4b70f5c91bb2440cdcf45b22b52vandebo@chromium.org int pageCount = treeCapacity; 1283c974427a95e9f24eae39167cf972506d70359c9vandebo@chromium.org if (i == curNodes.count()) { 1293c974427a95e9f24eae39167cf972506d70359c9vandebo@chromium.org pageCount = ((pages.count() - 1) % treeCapacity) + 1; 130bd36ebe29463c4b70f5c91bb2440cdcf45b22b52vandebo@chromium.org } 131bd36ebe29463c4b70f5c91bb2440cdcf45b22b52vandebo@chromium.org newNode->insert(countName.get(), new SkPDFInt(pageCount))->unref(); 1323c974427a95e9f24eae39167cf972506d70359c9vandebo@chromium.org newNode->insert(kidsName.get(), kids.get()); 133d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org nextRoundNodes.push(newNode); // Transfer reference. 134d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org } 135d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org 136d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org curNodes = nextRoundNodes; 137d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org nextRoundNodes.rewind(); 138bd36ebe29463c4b70f5c91bb2440cdcf45b22b52vandebo@chromium.org treeCapacity *= kNodeSize; 139a5c7234e81748f76cbeede40e619351146e5286actguil@chromium.org } while (curNodes.count() > 1); 140d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org 141a5c7234e81748f76cbeede40e619351146e5286actguil@chromium.org pageTree->push(curNodes[0]); // Transfer reference. 142d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org catalog->addObject(curNodes[0], false); 143769fa6a013baca6d7404e2bf096a34a7e3635fa5ctguil@chromium.org if (rootNode) { 144d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org *rootNode = curNodes[0]; 145769fa6a013baca6d7404e2bf096a34a7e3635fa5ctguil@chromium.org } 146d877fdbb6e64692285c3e6532d88b9458f65b3cdvandebo@chromium.org} 147f0ec2666d9a3f0f1662f0d63b5147628c49648aavandebo@chromium.org 148f0ec2666d9a3f0f1662f0d63b5147628c49648aavandebo@chromium.orgconst SkTDArray<SkPDFFont*>& SkPDFPage::getFontResources() const { 149f0ec2666d9a3f0f1662f0d63b5147628c49648aavandebo@chromium.org return fDevice->getFontResources(); 150f0ec2666d9a3f0f1662f0d63b5147628c49648aavandebo@chromium.org} 1519859428e71c6041928e6dd741ae3284017e78e81vandebo@chromium.org 1529859428e71c6041928e6dd741ae3284017e78e81vandebo@chromium.orgconst SkPDFGlyphSetMap& SkPDFPage::getFontGlyphUsage() const { 1539859428e71c6041928e6dd741ae3284017e78e81vandebo@chromium.org return fDevice->getFontGlyphUsage(); 1549859428e71c6041928e6dd741ae3284017e78e81vandebo@chromium.org} 155b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com 156b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.comvoid SkPDFPage::appendDestinations(SkPDFDict* dict) { 157b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com fDevice->appendDestinations(dict, this); 158b58772f86659cfe0e8d9247fcee878dddd8fdad9epoger@google.com} 159