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

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

     2 /*
     3  * Copyright 2011 Google Inc.
     4  *
     5  * Use of this source code is governed by a BSD-style license that can be
     6  * found in the LICENSE file.
     7  */
    10 #include "SkPDFCatalog.h"
    11 #include "SkPDFDevice.h"
    12 #include "SkPDFDocument.h"
    13 #include "SkPDFFont.h"
    14 #include "SkPDFPage.h"
    15 #include "SkPDFTypes.h"
    16 #include "SkStream.h"
    17 #include "SkTSet.h"
    19 static void addResourcesToCatalog(bool firstPage,
    20                                   SkTSet<SkPDFObject*>* resourceSet,
    21                                   SkPDFCatalog* catalog) {
    22     for (int i = 0; i < resourceSet->count(); i++) {
    23         catalog->addObject((*resourceSet)[i], firstPage);
    24     }
    25 }
    27 static void perform_font_subsetting(SkPDFCatalog* catalog,
    28                                     const SkTDArray<SkPDFPage*>& pages,
    29                                     SkTDArray<SkPDFObject*>* substitutes) {
    30     SkASSERT(catalog);
    31     SkASSERT(substitutes);
    33     SkPDFGlyphSetMap usage;
    34     for (int i = 0; i < pages.count(); ++i) {
    35         usage.merge(pages[i]->getFontGlyphUsage());
    36     }
    37     SkPDFGlyphSetMap::F2BIter iterator(usage);
    38     const SkPDFGlyphSetMap::FontGlyphSetPair* entry = iterator.next();
    39     while (entry) {
    40         SkPDFFont* subsetFont =
    41             entry->fFont->getFontSubset(entry->fGlyphSet);
    42         if (subsetFont) {
    43             catalog->setSubstitute(entry->fFont, subsetFont);
    44             substitutes->push(subsetFont);  // Transfer ownership to substitutes
    45         }
    46         entry = iterator.next();
    47     }
    48 }
    50 SkPDFDocument::SkPDFDocument(Flags flags)
    51         : fXRefFileOffset(0),
    52           fTrailerDict(NULL) {
    53     fCatalog.reset(new SkPDFCatalog(flags));
    54     fDocCatalog = SkNEW_ARGS(SkPDFDict, ("Catalog"));
    55     fCatalog->addObject(fDocCatalog, true);
    56     fFirstPageResources = NULL;
    57     fOtherPageResources = NULL;
    58 }
    60 SkPDFDocument::~SkPDFDocument() {
    61     fPages.safeUnrefAll();
    63     // The page tree has both child and parent pointers, so it creates a
    64     // reference cycle.  We must clear that cycle to properly reclaim memory.
    65     for (int i = 0; i < fPageTree.count(); i++) {
    66         fPageTree[i]->clear();
    67     }
    68     fPageTree.safeUnrefAll();
    70     if (fFirstPageResources) {
    71         fFirstPageResources->safeUnrefAll();
    72     }
    73     if (fOtherPageResources) {
    74         fOtherPageResources->safeUnrefAll();
    75     }
    77     fSubstitutes.safeUnrefAll();
    79     fDocCatalog->unref();
    80     SkSafeUnref(fTrailerDict);
    81     SkDELETE(fFirstPageResources);
    82     SkDELETE(fOtherPageResources);
    83 }
    85 bool SkPDFDocument::emitPDF(SkWStream* stream) {
    86     if (fPages.isEmpty()) {
    87         return false;
    88     }
    89     for (int i = 0; i < fPages.count(); i++) {
    90         if (fPages[i] == NULL) {
    91             return false;
    92         }
    93     }
    95     fFirstPageResources = SkNEW(SkTSet<SkPDFObject*>);
    96     fOtherPageResources = SkNEW(SkTSet<SkPDFObject*>);
    98     // We haven't emitted the document before if fPageTree is empty.
    99     if (fPageTree.isEmpty()) {
   100         SkPDFDict* pageTreeRoot;
   101         SkPDFPage::GeneratePageTree(fPages, fCatalog.get(), &fPageTree,
   102                                     &pageTreeRoot);
   103         fDocCatalog->insert("Pages", new SkPDFObjRef(pageTreeRoot))->unref();
   105         /* TODO(vandebo): output intent
   106         SkAutoTUnref<SkPDFDict> outputIntent = new SkPDFDict("OutputIntent");
   107         outputIntent->insert("S", new SkPDFName("GTS_PDFA1"))->unref();
   108         outputIntent->insert("OutputConditionIdentifier",
   109                              new SkPDFString("sRGB"))->unref();
   110         SkAutoTUnref<SkPDFArray> intentArray = new SkPDFArray;
   111         intentArray->append(outputIntent.get());
   112         fDocCatalog->insert("OutputIntent", intentArray.get());
   113         */
   115         SkAutoTUnref<SkPDFDict> dests(SkNEW(SkPDFDict));
   117         bool firstPage = true;
   118         /* The references returned in newResources are transfered to
   119          * fFirstPageResources or fOtherPageResources depending on firstPage and
   120          * knownResources doesn't have a reference but just relies on the other
   121          * two sets to maintain a reference.
   122          */
   123         SkTSet<SkPDFObject*> knownResources;
   125         // mergeInto returns the number of duplicates.
   126         // If there are duplicates, there is a bug and we mess ref counting.
   127         SkDEBUGCODE(int duplicates =) knownResources.mergeInto(*fFirstPageResources);
   128         SkASSERT(duplicates == 0);
   130         for (int i = 0; i < fPages.count(); i++) {
   131             if (i == 1) {
   132                 firstPage = false;
   133                 SkDEBUGCODE(duplicates =) knownResources.mergeInto(*fOtherPageResources);
   134             }
   135             SkTSet<SkPDFObject*> newResources;
   136             fPages[i]->finalizePage(
   137                 fCatalog.get(), firstPage, knownResources, &newResources);
   138             addResourcesToCatalog(firstPage, &newResources, fCatalog.get());
   139             if (firstPage) {
   140                 SkDEBUGCODE(duplicates =) fFirstPageResources->mergeInto(newResources);
   141             } else {
   142                 SkDEBUGCODE(duplicates =) fOtherPageResources->mergeInto(newResources);
   143             }
   144             SkASSERT(duplicates == 0);
   146             SkDEBUGCODE(duplicates =) knownResources.mergeInto(newResources);
   147             SkASSERT(duplicates == 0);
   149             fPages[i]->appendDestinations(dests);
   150         }
   152         if (dests->size() > 0) {
   153             SkPDFDict* raw_dests = dests.get();
   154             fFirstPageResources->add(dests.detach());  // Transfer ownership.
   155             fCatalog->addObject(raw_dests, true /* onFirstPage */);
   156             fDocCatalog->insert("Dests", SkNEW_ARGS(SkPDFObjRef, (raw_dests)))->unref();
   157         }
   159         // Build font subsetting info before proceeding.
   160         perform_font_subsetting(fCatalog.get(), fPages, &fSubstitutes);
   162         // Figure out the size of things and inform the catalog of file offsets.
   163         off_t fileOffset = headerSize();
   164         fileOffset += fCatalog->setFileOffset(fDocCatalog, fileOffset);
   165         fileOffset += fCatalog->setFileOffset(fPages[0], fileOffset);
   166         fileOffset += fPages[0]->getPageSize(fCatalog.get(),
   167                 (size_t) fileOffset);
   168         for (int i = 0; i < fFirstPageResources->count(); i++) {
   169             fileOffset += fCatalog->setFileOffset((*fFirstPageResources)[i],
   170                                                   fileOffset);
   171         }
   172         // Add the size of resources of substitute objects used on page 1.
   173         fileOffset += fCatalog->setSubstituteResourcesOffsets(fileOffset, true);
   174         if (fPages.count() > 1) {
   175             // TODO(vandebo): For linearized format, save the start of the
   176             // first page xref table and calculate the size.
   177         }
   179         for (int i = 0; i < fPageTree.count(); i++) {
   180             fileOffset += fCatalog->setFileOffset(fPageTree[i], fileOffset);
   181         }
   183         for (int i = 1; i < fPages.count(); i++) {
   184             fileOffset += fPages[i]->getPageSize(fCatalog.get(), fileOffset);
   185         }
   187         for (int i = 0; i < fOtherPageResources->count(); i++) {
   188             fileOffset += fCatalog->setFileOffset(
   189                 (*fOtherPageResources)[i], fileOffset);
   190         }
   192         fileOffset += fCatalog->setSubstituteResourcesOffsets(fileOffset,
   193                                                               false);
   194         fXRefFileOffset = fileOffset;
   195     }
   197     emitHeader(stream);
   198     fDocCatalog->emitObject(stream, fCatalog.get(), true);
   199     fPages[0]->emitObject(stream, fCatalog.get(), true);
   200     fPages[0]->emitPage(stream, fCatalog.get());
   201     for (int i = 0; i < fFirstPageResources->count(); i++) {
   202         (*fFirstPageResources)[i]->emit(stream, fCatalog.get(), true);
   203     }
   204     fCatalog->emitSubstituteResources(stream, true);
   205     // TODO(vandebo): Support linearized format
   206     // if (fPages.size() > 1) {
   207     //     // TODO(vandebo): Save the file offset for the first page xref table.
   208     //     fCatalog->emitXrefTable(stream, true);
   209     // }
   211     for (int i = 0; i < fPageTree.count(); i++) {
   212         fPageTree[i]->emitObject(stream, fCatalog.get(), true);
   213     }
   215     for (int i = 1; i < fPages.count(); i++) {
   216         fPages[i]->emitPage(stream, fCatalog.get());
   217     }
   219     for (int i = 0; i < fOtherPageResources->count(); i++) {
   220         (*fOtherPageResources)[i]->emit(stream, fCatalog.get(), true);
   221     }
   223     fCatalog->emitSubstituteResources(stream, false);
   224     int64_t objCount = fCatalog->emitXrefTable(stream, fPages.count() > 1);
   225     emitFooter(stream, objCount);
   226     return true;
   227 }
   229 bool SkPDFDocument::setPage(int pageNumber, SkPDFDevice* pdfDevice) {
   230     if (!fPageTree.isEmpty()) {
   231         return false;
   232     }
   234     pageNumber--;
   235     SkASSERT(pageNumber >= 0);
   237     if (pageNumber >= fPages.count()) {
   238         int oldSize = fPages.count();
   239         fPages.setCount(pageNumber + 1);
   240         for (int i = oldSize; i <= pageNumber; i++) {
   241             fPages[i] = NULL;
   242         }
   243     }
   245     SkPDFPage* page = new SkPDFPage(pdfDevice);
   246     SkSafeUnref(fPages[pageNumber]);
   247     fPages[pageNumber] = page;  // Reference from new passed to fPages.
   248     return true;
   249 }
   251 bool SkPDFDocument::appendPage(SkPDFDevice* pdfDevice) {
   252     if (!fPageTree.isEmpty()) {
   253         return false;
   254     }
   256     SkPDFPage* page = new SkPDFPage(pdfDevice);
   257     fPages.push(page);  // Reference from new passed to fPages.
   258     return true;
   259 }
   261 void SkPDFDocument::getCountOfFontTypes(
   262         int counts[SkAdvancedTypefaceMetrics::kNotEmbeddable_Font + 1]) const {
   263     sk_bzero(counts, sizeof(int) *
   264                      (SkAdvancedTypefaceMetrics::kNotEmbeddable_Font + 1));
   265     SkTDArray<SkFontID> seenFonts;
   267     for (int pageNumber = 0; pageNumber < fPages.count(); pageNumber++) {
   268         const SkTDArray<SkPDFFont*>& fontResources =
   269                 fPages[pageNumber]->getFontResources();
   270         for (int font = 0; font < fontResources.count(); font++) {
   271             SkFontID fontID = fontResources[font]->typeface()->uniqueID();
   272             if (seenFonts.find(fontID) == -1) {
   273                 counts[fontResources[font]->getType()]++;
   274                 seenFonts.push(fontID);
   275             }
   276         }
   277     }
   278 }
   280 void SkPDFDocument::emitHeader(SkWStream* stream) {
   281     stream->writeText("%PDF-1.4\n%");
   282     // The PDF spec recommends including a comment with four bytes, all
   283     // with their high bits set.  This is "Skia" with the high bits set.
   284     stream->write32(0xD3EBE9E1);
   285     stream->writeText("\n");
   286 }
   288 size_t SkPDFDocument::headerSize() {
   289     SkDynamicMemoryWStream buffer;
   290     emitHeader(&buffer);
   291     return buffer.getOffset();
   292 }
   294 void SkPDFDocument::emitFooter(SkWStream* stream, int64_t objCount) {
   295     if (NULL == fTrailerDict) {
   296         fTrailerDict = SkNEW(SkPDFDict);
   298         // TODO(vandebo): Linearized format will take a Prev entry too.
   299         // TODO(vandebo): PDF/A requires an ID entry.
   300         fTrailerDict->insertInt("Size", int(objCount));
   301         fTrailerDict->insert("Root", new SkPDFObjRef(fDocCatalog))->unref();
   302     }
   304     stream->writeText("trailer\n");
   305     fTrailerDict->emitObject(stream, fCatalog.get(), false);
   306     stream->writeText("\nstartxref\n");
   307     stream->writeBigDecAsText(fXRefFileOffset);
   308     stream->writeText("\n%%EOF");
   309 }

mercurial