Home | History | Annotate | Download | only in pdf
      1 
      2 /*
      3  * Copyright 2010 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  */
      8 
      9 
     10 #include "SkData.h"
     11 #include "SkFlate.h"
     12 #include "SkPDFCatalog.h"
     13 #include "SkPDFStream.h"
     14 #include "SkStream.h"
     15 
     16 static bool skip_compression(SkPDFCatalog* catalog) {
     17     return SkToBool(catalog->getDocumentFlags() &
     18                     SkPDFDocument::kFavorSpeedOverSize_Flags);
     19 }
     20 
     21 SkPDFStream::SkPDFStream(SkStream* stream) : fState(kUnused_State) {
     22     setData(stream);
     23 }
     24 
     25 SkPDFStream::SkPDFStream(SkData* data) : fState(kUnused_State) {
     26     setData(data);
     27 }
     28 
     29 SkPDFStream::SkPDFStream(const SkPDFStream& pdfStream)
     30         : SkPDFDict(),
     31           fState(kUnused_State) {
     32     setData(pdfStream.fData.get());
     33     bool removeLength = true;
     34     // Don't uncompress an already compressed stream, but we could.
     35     if (pdfStream.fState == kCompressed_State) {
     36         fState = kCompressed_State;
     37         removeLength = false;
     38     }
     39     SkPDFDict::Iter dict(pdfStream);
     40     SkPDFName* key;
     41     SkPDFObject* value;
     42     SkPDFName lengthName("Length");
     43     for (key = dict.next(&value); key != NULL; key = dict.next(&value)) {
     44         if (removeLength && *key == lengthName) {
     45             continue;
     46         }
     47         this->insert(key, value);
     48     }
     49 }
     50 
     51 SkPDFStream::~SkPDFStream() {}
     52 
     53 void SkPDFStream::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
     54                              bool indirect) {
     55     if (indirect) {
     56         return emitIndirectObject(stream, catalog);
     57     }
     58     if (!this->populate(catalog)) {
     59         return fSubstitute->emitObject(stream, catalog, indirect);
     60     }
     61 
     62     this->INHERITED::emitObject(stream, catalog, false);
     63     stream->writeText(" stream\n");
     64     stream->writeStream(fData.get(), fData->getLength());
     65     fData->rewind();
     66     stream->writeText("\nendstream");
     67 }
     68 
     69 size_t SkPDFStream::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
     70     if (indirect) {
     71         return getIndirectOutputSize(catalog);
     72     }
     73     if (!this->populate(catalog)) {
     74         return fSubstitute->getOutputSize(catalog, indirect);
     75     }
     76 
     77     return this->INHERITED::getOutputSize(catalog, false) +
     78         strlen(" stream\n\nendstream") + fData->getLength();
     79 }
     80 
     81 SkPDFStream::SkPDFStream() : fState(kUnused_State) {}
     82 
     83 void SkPDFStream::setData(SkData* data) {
     84     SkMemoryStream* stream = new SkMemoryStream;
     85     stream->setData(data);
     86     fData.reset(stream);  // Transfer ownership.
     87 }
     88 
     89 void SkPDFStream::setData(SkStream* stream) {
     90     // Code assumes that the stream starts at the beginning and is rewindable.
     91     if (stream) {
     92         SkASSERT(stream->getPosition() == 0);
     93         SkASSERT(stream->rewind());
     94     }
     95     fData.reset(stream);
     96     SkSafeRef(stream);
     97 }
     98 
     99 bool SkPDFStream::populate(SkPDFCatalog* catalog) {
    100     if (fState == kUnused_State) {
    101         if (!skip_compression(catalog) && SkFlate::HaveFlate()) {
    102             SkDynamicMemoryWStream compressedData;
    103 
    104             SkAssertResult(SkFlate::Deflate(fData.get(), &compressedData));
    105             if (compressedData.getOffset() < fData->getLength()) {
    106                 SkMemoryStream* stream = new SkMemoryStream;
    107                 stream->setData(compressedData.copyToData())->unref();
    108                 fData.reset(stream);  // Transfer ownership.
    109                 insertName("Filter", "FlateDecode");
    110             }
    111             fState = kCompressed_State;
    112         } else {
    113             fState = kNoCompression_State;
    114         }
    115         insertInt("Length", fData->getLength());
    116     } else if (fState == kNoCompression_State && !skip_compression(catalog) &&
    117                SkFlate::HaveFlate()) {
    118         if (!fSubstitute.get()) {
    119             fSubstitute.reset(new SkPDFStream(*this));
    120             catalog->setSubstitute(this, fSubstitute.get());
    121         }
    122         return false;
    123     }
    124     return true;
    125 }
    126