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 #include "SkStreamPriv.h"
     16 
     17 static bool skip_compression(SkPDFCatalog* catalog) {
     18     return SkToBool(catalog->getDocumentFlags() &
     19                     SkPDFDocument::kFavorSpeedOverSize_Flags);
     20 }
     21 
     22 SkPDFStream::SkPDFStream(SkStream* stream) : fState(kUnused_State) {
     23     this->setData(stream);
     24 }
     25 
     26 SkPDFStream::SkPDFStream(SkData* data) : fState(kUnused_State) {
     27     this->setData(data);
     28 }
     29 
     30 SkPDFStream::SkPDFStream(const SkPDFStream& pdfStream)
     31         : SkPDFDict(),
     32           fState(kUnused_State) {
     33     this->setData(pdfStream.fDataStream.get());
     34     bool removeLength = true;
     35     // Don't uncompress an already compressed stream, but we could.
     36     if (pdfStream.fState == kCompressed_State) {
     37         fState = kCompressed_State;
     38         removeLength = false;
     39     }
     40     this->mergeFrom(pdfStream);
     41     if (removeLength) {
     42         this->remove("Length");
     43     }
     44 }
     45 
     46 SkPDFStream::~SkPDFStream() {}
     47 
     48 void SkPDFStream::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
     49                              bool indirect) {
     50     if (indirect) {
     51         return emitIndirectObject(stream, catalog);
     52     }
     53     SkAutoMutexAcquire lock(fMutex);  // multiple threads could be calling emit
     54     if (!this->populate(catalog)) {
     55         return fSubstitute->emitObject(stream, catalog, indirect);
     56     }
     57 
     58     this->INHERITED::emitObject(stream, catalog, false);
     59     stream->writeText(" stream\n");
     60     stream->writeStream(fDataStream.get(), fDataStream->getLength());
     61     SkAssertResult(fDataStream->rewind());
     62     stream->writeText("\nendstream");
     63 }
     64 
     65 size_t SkPDFStream::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
     66     if (indirect) {
     67         return getIndirectOutputSize(catalog);
     68     }
     69     SkAutoMutexAcquire lock(fMutex);  // multiple threads could be calling emit
     70     if (!this->populate(catalog)) {
     71         return fSubstitute->getOutputSize(catalog, indirect);
     72     }
     73 
     74     return this->INHERITED::getOutputSize(catalog, false) +
     75         strlen(" stream\n\nendstream") + this->dataSize();
     76 }
     77 
     78 SkPDFStream::SkPDFStream() : fState(kUnused_State) {}
     79 
     80 void SkPDFStream::setData(SkData* data) {
     81     fMemoryStream.setData(data);
     82     if (&fMemoryStream != fDataStream.get()) {
     83         fDataStream.reset(SkRef(&fMemoryStream));
     84     }
     85 }
     86 
     87 void SkPDFStream::setData(SkStream* stream) {
     88     // Code assumes that the stream starts at the beginning and is rewindable.
     89     if (&fMemoryStream == fDataStream.get()) {
     90         SkASSERT(&fMemoryStream != stream);
     91         fMemoryStream.setData(NULL);
     92     }
     93     SkASSERT(0 == fMemoryStream.getLength());
     94     if (stream) {
     95         // SkStreamRewindableFromSkStream will try stream->duplicate().
     96         fDataStream.reset(SkStreamRewindableFromSkStream(stream));
     97         SkASSERT(fDataStream.get());
     98     } else {
     99         fDataStream.reset(SkRef(&fMemoryStream));
    100     }
    101 }
    102 
    103 size_t SkPDFStream::dataSize() const {
    104     SkASSERT(fDataStream->hasLength());
    105     return fDataStream->getLength();
    106 }
    107 
    108 bool SkPDFStream::populate(SkPDFCatalog* catalog) {
    109     if (fState == kUnused_State) {
    110         if (!skip_compression(catalog) && SkFlate::HaveFlate()) {
    111             SkDynamicMemoryWStream compressedData;
    112 
    113             SkAssertResult(
    114                     SkFlate::Deflate(fDataStream.get(), &compressedData));
    115             SkAssertResult(fDataStream->rewind());
    116             if (compressedData.getOffset() < this->dataSize()) {
    117                 SkAutoTUnref<SkStream> compressed(
    118                         compressedData.detachAsStream());
    119                 this->setData(compressed.get());
    120                 insertName("Filter", "FlateDecode");
    121             }
    122             fState = kCompressed_State;
    123         } else {
    124             fState = kNoCompression_State;
    125         }
    126         insertInt("Length", this->dataSize());
    127     } else if (fState == kNoCompression_State && !skip_compression(catalog) &&
    128                SkFlate::HaveFlate()) {
    129         if (!fSubstitute.get()) {
    130             fSubstitute.reset(new SkPDFStream(*this));
    131             catalog->setSubstitute(this, fSubstitute.get());
    132         }
    133         return false;
    134     }
    135     return true;
    136 }
    137