From: halcanary Date: Wed, 25 Mar 2015 19:45:28 +0000 (-0700) Subject: SkPDF: eliminate skpdfpage class X-Git-Tag: accepted/tizen/5.0/unified/20181102.025319~3040 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=2f7ebcb424cd1d1acf07478157f86b0a3eafd712;p=platform%2Fupstream%2FlibSkiaSharp.git SkPDF: eliminate skpdfpage class BUG=skia:3585 Review URL: https://codereview.chromium.org/1007083004 --- diff --git a/gyp/pdf.gypi b/gyp/pdf.gypi index 6377efd..9d406df 100644 --- a/gyp/pdf.gypi +++ b/gyp/pdf.gypi @@ -27,8 +27,6 @@ '<(skia_src_path)/pdf/SkPDFFormXObject.h', '<(skia_src_path)/pdf/SkPDFGraphicState.cpp', '<(skia_src_path)/pdf/SkPDFGraphicState.h', - '<(skia_src_path)/pdf/SkPDFPage.cpp', - '<(skia_src_path)/pdf/SkPDFPage.h', '<(skia_src_path)/pdf/SkPDFResourceDict.cpp', '<(skia_src_path)/pdf/SkPDFResourceDict.h', '<(skia_src_path)/pdf/SkPDFShader.cpp', diff --git a/src/doc/SkDocument_PDF.cpp b/src/doc/SkDocument_PDF.cpp index 979cd00..ae0386a 100644 --- a/src/doc/SkDocument_PDF.cpp +++ b/src/doc/SkDocument_PDF.cpp @@ -10,7 +10,8 @@ #include "SkPDFCatalog.h" #include "SkPDFDevice.h" #include "SkPDFFont.h" -#include "SkPDFPage.h" +#include "SkPDFResourceDict.h" +#include "SkPDFStream.h" #include "SkPDFTypes.h" #include "SkStream.h" @@ -40,13 +41,14 @@ static void emit_pdf_footer(SkWStream* stream, stream->writeText("\n%%EOF"); } -static void perform_font_subsetting(SkPDFCatalog* catalog, - const SkTDArray& pages) { +static void perform_font_subsetting( + const SkTDArray& pageDevices, + SkPDFCatalog* catalog) { SkASSERT(catalog); SkPDFGlyphSetMap usage; - for (int i = 0; i < pages.count(); ++i) { - usage.merge(pages[i]->getFontGlyphUsage()); + for (int i = 0; i < pageDevices.count(); ++i) { + usage.merge(pageDevices[i]->getFontGlyphUsage()); } SkPDFGlyphSetMap::F2BIter iterator(usage); const SkPDFGlyphSetMap::FontGlyphSetPair* entry = iterator.next(); @@ -60,23 +62,125 @@ static void perform_font_subsetting(SkPDFCatalog* catalog, } } +static SkPDFDict* create_pdf_page(const SkPDFDevice* pageDevice) { + SkAutoTUnref page(SkNEW_ARGS(SkPDFDict, ("Page"))); + SkAutoTUnref deviceResourceDict( + pageDevice->createResourceDict()); + page->insert("Resources", deviceResourceDict.get()); + + SkAutoTUnref mediaBox(pageDevice->copyMediaBox()); + page->insert("MediaBox", mediaBox.get()); + + SkPDFArray* annots = pageDevice->getAnnotations(); + if (annots && annots->size() > 0) { + page->insert("Annots", annots); + } + + SkAutoTDelete content(pageDevice->content()); + SkAutoTUnref contentStream( + SkNEW_ARGS(SkPDFStream, (content.get()))); + page->insert("Contents", new SkPDFObjRef(contentStream.get()))->unref(); + return page.detach(); +} + +static void generate_page_tree(const SkTDArray& pages, + SkTDArray* pageTree, + SkPDFDict** rootNode) { + // PDF wants a tree describing all the pages in the document. We arbitrary + // choose 8 (kNodeSize) as the number of allowed children. The internal + // nodes have type "Pages" with an array of children, a parent pointer, and + // the number of leaves below the node as "Count." The leaves are passed + // into the method, have type "Page" and need a parent pointer. This method + // builds the tree bottom up, skipping internal nodes that would have only + // one child. + static const int kNodeSize = 8; + + SkAutoTUnref kidsName(new SkPDFName("Kids")); + SkAutoTUnref countName(new SkPDFName("Count")); + SkAutoTUnref parentName(new SkPDFName("Parent")); + + // curNodes takes a reference to its items, which it passes to pageTree. + SkTDArray curNodes; + curNodes.setReserve(pages.count()); + for (int i = 0; i < pages.count(); i++) { + SkSafeRef(pages[i]); + curNodes.push(pages[i]); + } + + // nextRoundNodes passes its references to nodes on to curNodes. + SkTDArray nextRoundNodes; + nextRoundNodes.setReserve((pages.count() + kNodeSize - 1)/kNodeSize); + + int treeCapacity = kNodeSize; + do { + for (int i = 0; i < curNodes.count(); ) { + if (i > 0 && i + 1 == curNodes.count()) { + nextRoundNodes.push(curNodes[i]); + break; + } + + SkPDFDict* newNode = new SkPDFDict("Pages"); + SkAutoTUnref newNodeRef(new SkPDFObjRef(newNode)); + + SkAutoTUnref kids(new SkPDFArray); + kids->reserve(kNodeSize); + + int count = 0; + for (; i < curNodes.count() && count < kNodeSize; i++, count++) { + curNodes[i]->insert(parentName.get(), newNodeRef.get()); + kids->append(new SkPDFObjRef(curNodes[i]))->unref(); + + // TODO(vandebo): put the objects in strict access order. + // Probably doesn't matter because they are so small. + if (curNodes[i] != pages[0]) { + pageTree->push(curNodes[i]); // Transfer reference. + } else { + SkSafeUnref(curNodes[i]); + } + } + + // treeCapacity is the number of leaf nodes possible for the + // current set of subtrees being generated. (i.e. 8, 64, 512, ...). + // It is hard to count the number of leaf nodes in the current + // subtree. However, by construction, we know that unless it's the + // last subtree for the current depth, the leaf count will be + // treeCapacity, otherwise it's what ever is left over after + // consuming treeCapacity chunks. + int pageCount = treeCapacity; + if (i == curNodes.count()) { + pageCount = ((pages.count() - 1) % treeCapacity) + 1; + } + newNode->insert(countName.get(), new SkPDFInt(pageCount))->unref(); + newNode->insert(kidsName.get(), kids.get()); + nextRoundNodes.push(newNode); // Transfer reference. + } + + curNodes = nextRoundNodes; + nextRoundNodes.rewind(); + treeCapacity *= kNodeSize; + } while (curNodes.count() > 1); + + pageTree->push(curNodes[0]); // Transfer reference. + if (rootNode) { + *rootNode = curNodes[0]; + } +} + static bool emit_pdf_document(const SkTDArray& pageDevices, SkWStream* stream) { if (pageDevices.isEmpty()) { return false; } - SkTDArray pages; + SkTDArray pages; SkAutoTUnref dests(SkNEW(SkPDFDict)); for (int i = 0; i < pageDevices.count(); i++) { SkASSERT(pageDevices[i]); SkASSERT(i == 0 || pageDevices[i - 1]->getCanon() == pageDevices[i]->getCanon()); - // Reference from new passed to pages. - SkAutoTUnref page(SkNEW_ARGS(SkPDFPage, (pageDevices[i]))); - page->finalizePage(); - page->appendDestinations(dests); + SkAutoTUnref page(create_pdf_page(pageDevices[i])); + pageDevices[i]->appendDestinations(dests, page.get()); pages.push(page.detach()); } SkPDFCatalog catalog; @@ -85,7 +189,7 @@ static bool emit_pdf_document(const SkTDArray& pageDevices, SkAutoTUnref docCatalog(SkNEW_ARGS(SkPDFDict, ("Catalog"))); SkPDFDict* pageTreeRoot; - SkPDFPage::GeneratePageTree(pages, &pageTree, &pageTreeRoot); + generate_page_tree(pages, &pageTree, &pageTreeRoot); docCatalog->insert("Pages", new SkPDFObjRef(pageTreeRoot))->unref(); @@ -105,7 +209,7 @@ static bool emit_pdf_document(const SkTDArray& pageDevices, } // Build font subsetting info before proceeding. - perform_font_subsetting(&catalog, pages); + perform_font_subsetting(pageDevices, &catalog); SkTSet resourceSet; if (resourceSet.add(docCatalog.get())) { diff --git a/src/pdf/SkPDFPage.cpp b/src/pdf/SkPDFPage.cpp deleted file mode 100644 index 13a7ffe..0000000 --- a/src/pdf/SkPDFPage.cpp +++ /dev/null @@ -1,139 +0,0 @@ - -/* - * Copyright 2010 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#include "SkData.h" -#include "SkPDFCatalog.h" -#include "SkPDFDevice.h" -#include "SkPDFPage.h" -#include "SkPDFResourceDict.h" - -SkPDFPage::SkPDFPage(const SkPDFDevice* content) - : SkPDFDict("Page"), - fDevice(content) { - SkSafeRef(content); -} - -SkPDFPage::~SkPDFPage() {} - -void SkPDFPage::finalizePage() { - if (fContentStream.get() == NULL) { - SkAutoTUnref deviceResourceDict( - fDevice->createResourceDict()); - this->insert("Resources", deviceResourceDict.get()); - SkSafeUnref(this->insert("MediaBox", fDevice->copyMediaBox())); - SkPDFArray* annots = fDevice->getAnnotations(); - if (annots && annots->size() > 0) { - insert("Annots", annots); - } - - SkAutoTDelete content(fDevice->content()); - fContentStream.reset(new SkPDFStream(content.get())); - insert("Contents", new SkPDFObjRef(fContentStream.get()))->unref(); - } -} - -// static -void SkPDFPage::GeneratePageTree(const SkTDArray& pages, - SkTDArray* pageTree, - SkPDFDict** rootNode) { - // PDF wants a tree describing all the pages in the document. We arbitrary - // choose 8 (kNodeSize) as the number of allowed children. The internal - // nodes have type "Pages" with an array of children, a parent pointer, and - // the number of leaves below the node as "Count." The leaves are passed - // into the method, have type "Page" and need a parent pointer. This method - // builds the tree bottom up, skipping internal nodes that would have only - // one child. - static const int kNodeSize = 8; - - SkAutoTUnref kidsName(new SkPDFName("Kids")); - SkAutoTUnref countName(new SkPDFName("Count")); - SkAutoTUnref parentName(new SkPDFName("Parent")); - - // curNodes takes a reference to its items, which it passes to pageTree. - SkTDArray curNodes; - curNodes.setReserve(pages.count()); - for (int i = 0; i < pages.count(); i++) { - SkSafeRef(pages[i]); - curNodes.push(pages[i]); - } - - // nextRoundNodes passes its references to nodes on to curNodes. - SkTDArray nextRoundNodes; - nextRoundNodes.setReserve((pages.count() + kNodeSize - 1)/kNodeSize); - - int treeCapacity = kNodeSize; - do { - for (int i = 0; i < curNodes.count(); ) { - if (i > 0 && i + 1 == curNodes.count()) { - nextRoundNodes.push(curNodes[i]); - break; - } - - SkPDFDict* newNode = new SkPDFDict("Pages"); - SkAutoTUnref newNodeRef(new SkPDFObjRef(newNode)); - - SkAutoTUnref kids(new SkPDFArray); - kids->reserve(kNodeSize); - - int count = 0; - for (; i < curNodes.count() && count < kNodeSize; i++, count++) { - curNodes[i]->insert(parentName.get(), newNodeRef.get()); - kids->append(new SkPDFObjRef(curNodes[i]))->unref(); - - // TODO(vandebo): put the objects in strict access order. - // Probably doesn't matter because they are so small. - if (curNodes[i] != pages[0]) { - pageTree->push(curNodes[i]); // Transfer reference. - } else { - SkSafeUnref(curNodes[i]); - } - } - - // treeCapacity is the number of leaf nodes possible for the - // current set of subtrees being generated. (i.e. 8, 64, 512, ...). - // It is hard to count the number of leaf nodes in the current - // subtree. However, by construction, we know that unless it's the - // last subtree for the current depth, the leaf count will be - // treeCapacity, otherwise it's what ever is left over after - // consuming treeCapacity chunks. - int pageCount = treeCapacity; - if (i == curNodes.count()) { - pageCount = ((pages.count() - 1) % treeCapacity) + 1; - } - newNode->insert(countName.get(), new SkPDFInt(pageCount))->unref(); - newNode->insert(kidsName.get(), kids.get()); - nextRoundNodes.push(newNode); // Transfer reference. - } - - curNodes = nextRoundNodes; - nextRoundNodes.rewind(); - treeCapacity *= kNodeSize; - } while (curNodes.count() > 1); - - pageTree->push(curNodes[0]); // Transfer reference. - if (rootNode) { - *rootNode = curNodes[0]; - } -} - -const SkTDArray& SkPDFPage::getFontResources() const { - return fDevice->getFontResources(); -} - -const SkPDFGlyphSetMap& SkPDFPage::getFontGlyphUsage() const { - return fDevice->getFontGlyphUsage(); -} - -void SkPDFPage::appendDestinations(SkPDFDict* dict) { - fDevice->appendDestinations(dict, this); -} - -SkPDFObject* SkPDFPage::getContentStream() const { - return fContentStream.get(); -} diff --git a/src/pdf/SkPDFPage.h b/src/pdf/SkPDFPage.h deleted file mode 100644 index cf31b0a..0000000 --- a/src/pdf/SkPDFPage.h +++ /dev/null @@ -1,83 +0,0 @@ - -/* - * Copyright 2010 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#ifndef SkPDFPage_DEFINED -#define SkPDFPage_DEFINED - -#include "SkPDFTypes.h" -#include "SkPDFStream.h" -#include "SkRefCnt.h" -#include "SkTDArray.h" - -class SkPDFCatalog; -class SkPDFDevice; -class SkWStream; - -/** \class SkPDFPage - - A SkPDFPage contains meta information about a page, is used in the page - tree and points to the content of the page. -*/ -class SkPDFPage : public SkPDFDict { - SK_DECLARE_INST_COUNT(SkPDFPage) -public: - /** Create a PDF page with the passed PDF device. The device need not - * have content on it yet. - * @param content The page content. - */ - explicit SkPDFPage(const SkPDFDevice* content); - ~SkPDFPage(); - - /** Before a page and its contents can be sized and emitted, it must - * be finalized. No changes to the PDFDevice will be honored after - * finalizePage has been called. - */ - void finalizePage(); - - /** Add destinations for this page to the supplied dictionary. - * @param dict Dictionary to add destinations to. - */ - void appendDestinations(SkPDFDict* dict); - - /** Generate a page tree for the passed vector of pages. New objects are - * added to the catalog. The pageTree vector is populated with all of - * the 'Pages' dictionaries as well as the 'Page' objects. Page trees - * have both parent and children links, creating reference cycles, so - * it must be torn down explicitly. The first page is not added to - * the pageTree dictionary array so the caller can handle it specially. - * @param pages The ordered vector of page objects. - * @param pageTree An output vector with all of the internal and leaf - * nodes of the pageTree. - * @param rootNode An output parameter set to the root node. - */ - static void GeneratePageTree(const SkTDArray& pages, - SkTDArray* pageTree, - SkPDFDict** rootNode); - - /** Get the fonts used on this page. - */ - const SkTDArray& getFontResources() const; - - /** Returns a SkPDFGlyphSetMap which represents glyph usage of every font - * that shows on this page. - */ - const SkPDFGlyphSetMap& getFontGlyphUsage() const; - - SkPDFObject* getContentStream() const; - -private: - // Multiple pages may reference the content. - SkAutoTUnref fDevice; - - // Once the content is finalized, put it into a stream for output. - SkAutoTUnref fContentStream; - typedef SkPDFDict INHERITED; -}; - -#endif