11cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
20b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger/*
31cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger * Copyright 2010 The Android Open Source Project
40b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger *
51cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger * Use of this source code is governed by a BSD-style license that can be
61cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger * found in the LICENSE file.
70b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger */
80b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
91cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
100b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger#include "SkPDFCatalog.h"
110b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger#include "SkPDFDevice.h"
120b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger#include "SkPDFPage.h"
130b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger#include "SkStream.h"
140b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
151cab2921ab279367f8206cdadc9259d12e603548Derek SollenbergerSkPDFPage::SkPDFPage(SkPDFDevice* content)
160b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger    : SkPDFDict("Page"),
170b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger      fDevice(content) {
180b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger}
190b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
200b15698a8c76bb8abc1b555c1d91892669b4118fDerek SollenbergerSkPDFPage::~SkPDFPage() {}
210b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
220b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenbergervoid SkPDFPage::finalizePage(SkPDFCatalog* catalog, bool firstPage,
230b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger                             SkTDArray<SkPDFObject*>* resourceObjects) {
240b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger    if (fContentStream.get() == NULL) {
251cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger        insert("Resources", fDevice->getResourceDict());
260b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger        insert("MediaBox", fDevice->getMediaBox().get());
270b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
280b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger        SkRefPtr<SkStream> content = fDevice->content();
290b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger        content->unref();  // SkRefPtr and content() both took a reference.
300b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger        fContentStream = new SkPDFStream(content.get());
310b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger        fContentStream->unref();  // SkRefPtr and new both took a reference.
320b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger        insert("Contents", new SkPDFObjRef(fContentStream.get()))->unref();
330b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger    }
340b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger    catalog->addObject(fContentStream.get(), firstPage);
350b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger    fDevice->getResources(resourceObjects);
360b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger}
370b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
380b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenbergeroff_t SkPDFPage::getPageSize(SkPDFCatalog* catalog, off_t fileOffset) {
390b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger    SkASSERT(fContentStream.get() != NULL);
400b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger    catalog->setFileOffset(fContentStream.get(), fileOffset);
410b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger    return fContentStream->getOutputSize(catalog, true);
420b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger}
430b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
440b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenbergervoid SkPDFPage::emitPage(SkWStream* stream, SkPDFCatalog* catalog) {
450b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger    SkASSERT(fContentStream.get() != NULL);
460b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger    fContentStream->emitObject(stream, catalog, true);
470b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger}
480b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
490b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger// static
501cab2921ab279367f8206cdadc9259d12e603548Derek Sollenbergervoid SkPDFPage::GeneratePageTree(const SkTDArray<SkPDFPage*>& pages,
510b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger                                 SkPDFCatalog* catalog,
520b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger                                 SkTDArray<SkPDFDict*>* pageTree,
530b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger                                 SkPDFDict** rootNode) {
540b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger    // PDF wants a tree describing all the pages in the document.  We arbitrary
550b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger    // choose 8 (kNodeSize) as the number of allowed children.  The internal
560b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger    // nodes have type "Pages" with an array of children, a parent pointer, and
570b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger    // the number of leaves below the node as "Count."  The leaves are passed
580b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger    // into the method, have type "Page" and need a parent pointer. This method
590b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger    // builds the tree bottom up, skipping internal nodes that would have only
600b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger    // one child.
610b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger    static const int kNodeSize = 8;
620b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
630b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger    SkRefPtr<SkPDFName> kidsName = new SkPDFName("Kids");
640b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger    kidsName->unref();  // SkRefPtr and new both took a reference.
650b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger    SkRefPtr<SkPDFName> countName = new SkPDFName("Count");
660b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger    countName->unref();  // SkRefPtr and new both took a reference.
670b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger    SkRefPtr<SkPDFName> parentName = new SkPDFName("Parent");
680b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger    parentName->unref();  // SkRefPtr and new both took a reference.
690b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
700b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger    // curNodes takes a reference to its items, which it passes to pageTree.
710b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger    SkTDArray<SkPDFDict*> curNodes;
720b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger    curNodes.setReserve(pages.count());
730b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger    for (int i = 0; i < pages.count(); i++) {
740b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger        SkSafeRef(pages[i]);
750b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger        curNodes.push(pages[i]);
760b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger    }
770b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
780b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger    // nextRoundNodes passes its references to nodes on to curNodes.
790b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger    SkTDArray<SkPDFDict*> nextRoundNodes;
800b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger    nextRoundNodes.setReserve((pages.count() + kNodeSize - 1)/kNodeSize);
810b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
820b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger    int treeCapacity = kNodeSize;
830b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger    do {
840b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger        for (int i = 0; i < curNodes.count(); ) {
850b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger            if (i > 0 && i + 1 == curNodes.count()) {
860b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger                nextRoundNodes.push(curNodes[i]);
870b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger                break;
880b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger            }
890b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
900b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger            SkPDFDict* newNode = new SkPDFDict("Pages");
910b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger            SkRefPtr<SkPDFObjRef> newNodeRef = new SkPDFObjRef(newNode);
920b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger            newNodeRef->unref();  // SkRefPtr and new both took a reference.
930b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
940b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger            SkRefPtr<SkPDFArray> kids = new SkPDFArray;
950b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger            kids->unref();  // SkRefPtr and new both took a reference.
960b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger            kids->reserve(kNodeSize);
970b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
980b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger            int count = 0;
990b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger            for (; i < curNodes.count() && count < kNodeSize; i++, count++) {
1000b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger                curNodes[i]->insert(parentName.get(), newNodeRef.get());
1010b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger                kids->append(new SkPDFObjRef(curNodes[i]))->unref();
1020b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
1031cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                // TODO(vandebo): put the objects in strict access order.
1040b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger                // Probably doesn't matter because they are so small.
1050b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger                if (curNodes[i] != pages[0]) {
1061cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                    pageTree->push(curNodes[i]);  // Transfer reference.
1070b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger                    catalog->addObject(curNodes[i], false);
1080b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger                } else {
1090b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger                    SkSafeUnref(curNodes[i]);
1101cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger                    catalog->addObject(curNodes[i], true);
1110b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger                }
1120b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger            }
1130b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
1140b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger            newNode->insert(kidsName.get(), kids.get());
1150b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger            int pageCount = treeCapacity;
1160b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger            if (count < kNodeSize) {
1170b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger                pageCount = pages.count() % treeCapacity;
1180b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger            }
1190b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger            newNode->insert(countName.get(), new SkPDFInt(pageCount))->unref();
1200b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger            nextRoundNodes.push(newNode);  // Transfer reference.
1210b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger        }
1220b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
1230b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger        curNodes = nextRoundNodes;
1240b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger        nextRoundNodes.rewind();
1250b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger        treeCapacity *= kNodeSize;
1261cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    } while (curNodes.count() > 1);
1270b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
1281cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    pageTree->push(curNodes[0]);  // Transfer reference.
1290b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger    catalog->addObject(curNodes[0], false);
1301cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    if (rootNode) {
1310b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger        *rootNode = curNodes[0];
1321cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    }
1330b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger}
1340b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger
1350b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenbergerconst SkTDArray<SkPDFFont*>& SkPDFPage::getFontResources() const {
1360b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger    return fDevice->getFontResources();
1370b15698a8c76bb8abc1b555c1d91892669b4118fDerek Sollenberger}
1381cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
1391cab2921ab279367f8206cdadc9259d12e603548Derek Sollenbergerconst SkPDFGlyphSetMap& SkPDFPage::getFontGlyphUsage() const {
1401cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    return fDevice->getFontGlyphUsage();
1411cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger}
142