gfx/skia/trunk/src/pdf/SkPDFPage.cpp

changeset 0
6474c204b198
     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 +}

mercurial