• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
2 /*
3  * Copyright 2010 The Android Open Source Project
4  *
5  * Use of this source code is governed by a BSD-style license that can be
6  * found in the LICENSE file.
7  */
8 
9 
10 #include "SkPDFCatalog.h"
11 #include "SkPDFDevice.h"
12 #include "SkPDFPage.h"
13 #include "SkStream.h"
14 
SkPDFPage(SkPDFDevice * content)15 SkPDFPage::SkPDFPage(SkPDFDevice* content)
16     : SkPDFDict("Page"),
17       fDevice(content) {
18 }
19 
~SkPDFPage()20 SkPDFPage::~SkPDFPage() {}
21 
finalizePage(SkPDFCatalog * catalog,bool firstPage,SkTDArray<SkPDFObject * > * resourceObjects)22 void SkPDFPage::finalizePage(SkPDFCatalog* catalog, bool firstPage,
23                              SkTDArray<SkPDFObject*>* resourceObjects) {
24     if (fContentStream.get() == NULL) {
25         insert("Resources", fDevice->getResourceDict());
26         insert("MediaBox", fDevice->getMediaBox().get());
27 
28         SkRefPtr<SkStream> content = fDevice->content();
29         content->unref();  // SkRefPtr and content() both took a reference.
30         fContentStream = new SkPDFStream(content.get());
31         fContentStream->unref();  // SkRefPtr and new both took a reference.
32         insert("Contents", new SkPDFObjRef(fContentStream.get()))->unref();
33     }
34     catalog->addObject(fContentStream.get(), firstPage);
35     fDevice->getResources(resourceObjects);
36 }
37 
getPageSize(SkPDFCatalog * catalog,off_t fileOffset)38 off_t SkPDFPage::getPageSize(SkPDFCatalog* catalog, off_t fileOffset) {
39     SkASSERT(fContentStream.get() != NULL);
40     catalog->setFileOffset(fContentStream.get(), fileOffset);
41     return fContentStream->getOutputSize(catalog, true);
42 }
43 
emitPage(SkWStream * stream,SkPDFCatalog * catalog)44 void SkPDFPage::emitPage(SkWStream* stream, SkPDFCatalog* catalog) {
45     SkASSERT(fContentStream.get() != NULL);
46     fContentStream->emitObject(stream, catalog, true);
47 }
48 
49 // static
GeneratePageTree(const SkTDArray<SkPDFPage * > & pages,SkPDFCatalog * catalog,SkTDArray<SkPDFDict * > * pageTree,SkPDFDict ** rootNode)50 void SkPDFPage::GeneratePageTree(const SkTDArray<SkPDFPage*>& pages,
51                                  SkPDFCatalog* catalog,
52                                  SkTDArray<SkPDFDict*>* pageTree,
53                                  SkPDFDict** rootNode) {
54     // PDF wants a tree describing all the pages in the document.  We arbitrary
55     // choose 8 (kNodeSize) as the number of allowed children.  The internal
56     // nodes have type "Pages" with an array of children, a parent pointer, and
57     // the number of leaves below the node as "Count."  The leaves are passed
58     // into the method, have type "Page" and need a parent pointer. This method
59     // builds the tree bottom up, skipping internal nodes that would have only
60     // one child.
61     static const int kNodeSize = 8;
62 
63     SkRefPtr<SkPDFName> kidsName = new SkPDFName("Kids");
64     kidsName->unref();  // SkRefPtr and new both took a reference.
65     SkRefPtr<SkPDFName> countName = new SkPDFName("Count");
66     countName->unref();  // SkRefPtr and new both took a reference.
67     SkRefPtr<SkPDFName> parentName = new SkPDFName("Parent");
68     parentName->unref();  // SkRefPtr and new both took a reference.
69 
70     // curNodes takes a reference to its items, which it passes to pageTree.
71     SkTDArray<SkPDFDict*> curNodes;
72     curNodes.setReserve(pages.count());
73     for (int i = 0; i < pages.count(); i++) {
74         SkSafeRef(pages[i]);
75         curNodes.push(pages[i]);
76     }
77 
78     // nextRoundNodes passes its references to nodes on to curNodes.
79     SkTDArray<SkPDFDict*> nextRoundNodes;
80     nextRoundNodes.setReserve((pages.count() + kNodeSize - 1)/kNodeSize);
81 
82     int treeCapacity = kNodeSize;
83     do {
84         for (int i = 0; i < curNodes.count(); ) {
85             if (i > 0 && i + 1 == curNodes.count()) {
86                 nextRoundNodes.push(curNodes[i]);
87                 break;
88             }
89 
90             SkPDFDict* newNode = new SkPDFDict("Pages");
91             SkRefPtr<SkPDFObjRef> newNodeRef = new SkPDFObjRef(newNode);
92             newNodeRef->unref();  // SkRefPtr and new both took a reference.
93 
94             SkRefPtr<SkPDFArray> kids = new SkPDFArray;
95             kids->unref();  // SkRefPtr and new both took a reference.
96             kids->reserve(kNodeSize);
97 
98             int count = 0;
99             for (; i < curNodes.count() && count < kNodeSize; i++, count++) {
100                 curNodes[i]->insert(parentName.get(), newNodeRef.get());
101                 kids->append(new SkPDFObjRef(curNodes[i]))->unref();
102 
103                 // TODO(vandebo): put the objects in strict access order.
104                 // Probably doesn't matter because they are so small.
105                 if (curNodes[i] != pages[0]) {
106                     pageTree->push(curNodes[i]);  // Transfer reference.
107                     catalog->addObject(curNodes[i], false);
108                 } else {
109                     SkSafeUnref(curNodes[i]);
110                     catalog->addObject(curNodes[i], true);
111                 }
112             }
113 
114             newNode->insert(kidsName.get(), kids.get());
115             int pageCount = treeCapacity;
116             if (count < kNodeSize) {
117                 pageCount = pages.count() % treeCapacity;
118             }
119             newNode->insert(countName.get(), new SkPDFInt(pageCount))->unref();
120             nextRoundNodes.push(newNode);  // Transfer reference.
121         }
122 
123         curNodes = nextRoundNodes;
124         nextRoundNodes.rewind();
125         treeCapacity *= kNodeSize;
126     } while (curNodes.count() > 1);
127 
128     pageTree->push(curNodes[0]);  // Transfer reference.
129     catalog->addObject(curNodes[0], false);
130     if (rootNode) {
131         *rootNode = curNodes[0];
132     }
133 }
134 
getFontResources() const135 const SkTDArray<SkPDFFont*>& SkPDFPage::getFontResources() const {
136     return fDevice->getFontResources();
137 }
138 
getFontGlyphUsage() const139 const SkPDFGlyphSetMap& SkPDFPage::getFontGlyphUsage() const {
140     return fDevice->getFontGlyphUsage();
141 }
142