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 catalog->getDocumentFlags() & SkPDFDocument::kNoCompression_Flag;
     18 }
     19 
     20 SkPDFStream::SkPDFStream(SkStream* stream)
     21     : fState(kUnused_State),
     22       fData(stream) {
     23 }
     24 
     25 SkPDFStream::SkPDFStream(SkData* data) : fState(kUnused_State) {
     26     SkMemoryStream* stream = new SkMemoryStream;
     27     stream->setData(data);
     28     fData = stream;
     29     fData->unref();  // SkRefPtr and new both took a reference.
     30 }
     31 
     32 SkPDFStream::SkPDFStream(const SkPDFStream& pdfStream)
     33         : SkPDFDict(),
     34           fState(kUnused_State),
     35           fData(pdfStream.fData) {
     36     bool removeLength = true;
     37     // Don't uncompress an already compressed stream, but we could.
     38     if (pdfStream.fState == kCompressed_State) {
     39         fState = kCompressed_State;
     40         removeLength = false;
     41     }
     42     SkPDFDict::Iter dict(pdfStream);
     43     SkPDFName* key;
     44     SkPDFObject* value;
     45     SkPDFName lengthName("Length");
     46     for (key = dict.next(&value); key != NULL; key = dict.next(&value)) {
     47         if (removeLength && *key == lengthName) {
     48             continue;
     49         }
     50         this->insert(key, value);
     51     }
     52 }
     53 
     54 SkPDFStream::~SkPDFStream() {}
     55 
     56 void SkPDFStream::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
     57                              bool indirect) {
     58     if (indirect) {
     59         return emitIndirectObject(stream, catalog);
     60     }
     61     if (!this->populate(catalog)) {
     62         return fSubstitute->emitObject(stream, catalog, indirect);
     63     }
     64 
     65     this->INHERITED::emitObject(stream, catalog, false);
     66     stream->writeText(" stream\n");
     67     stream->write(fData->getMemoryBase(), fData->getLength());
     68     stream->writeText("\nendstream");
     69 }
     70 
     71 size_t SkPDFStream::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
     72     if (indirect) {
     73         return getIndirectOutputSize(catalog);
     74     }
     75     if (!this->populate(catalog)) {
     76         return fSubstitute->getOutputSize(catalog, indirect);
     77     }
     78 
     79     return this->INHERITED::getOutputSize(catalog, false) +
     80         strlen(" stream\n\nendstream") + fData->getLength();
     81 }
     82 
     83 SkPDFStream::SkPDFStream() : fState(kUnused_State) {}
     84 
     85 void SkPDFStream::setData(SkStream* stream) {
     86     fData = stream;
     87 }
     88 
     89 bool SkPDFStream::populate(SkPDFCatalog* catalog) {
     90     if (fState == kUnused_State) {
     91         if (!skip_compression(catalog) && SkFlate::HaveFlate()) {
     92             SkDynamicMemoryWStream compressedData;
     93 
     94             SkAssertResult(SkFlate::Deflate(fData.get(), &compressedData));
     95             if (compressedData.getOffset() < fData->getLength()) {
     96                 SkMemoryStream* stream = new SkMemoryStream;
     97                 stream->setData(compressedData.copyToData());
     98                 fData = stream;
     99                 fData->unref();  // SkRefPtr and new both took a reference.
    100                 insertName("Filter", "FlateDecode");
    101             }
    102             fState = kCompressed_State;
    103         } else {
    104             fState = kNoCompression_State;
    105         }
    106         insertInt("Length", fData->getLength());
    107     } else if (fState == kNoCompression_State && !skip_compression(catalog) &&
    108                SkFlate::HaveFlate()) {
    109         if (!fSubstitute.get()) {
    110             fSubstitute = new SkPDFStream(*this);
    111             fSubstitute->unref();  // SkRefPtr and new both took a reference.
    112             catalog->setSubstitute(this, fSubstitute.get());
    113         }
    114         return false;
    115     }
    116     return true;
    117 }
    118