aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/pdf/SkPDFStream.cpp
blob: 5eaa6c28b69b3968247b0f72cc11f0dff2d3d0a5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113

/*
 * Copyright 2010 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */


#include "SkData.h"
#include "SkFlate.h"
#include "SkPDFCatalog.h"
#include "SkPDFStream.h"
#include "SkStream.h"
#include "SkStreamPriv.h"

static bool skip_compression(SkPDFCatalog* catalog) {
    return SkToBool(catalog->getDocumentFlags() &
                    SkPDFDocument::kFavorSpeedOverSize_Flags);
}

SkPDFStream::SkPDFStream(SkStream* stream) : fState(kUnused_State) {
    this->setData(stream);
}

SkPDFStream::SkPDFStream(SkData* data) : fState(kUnused_State) {
    this->setData(data);
}

SkPDFStream::SkPDFStream(const SkPDFStream& pdfStream)
        : SkPDFDict(),
          fState(kUnused_State) {
    this->setData(pdfStream.fDataStream.get());
    bool removeLength = true;
    // Don't uncompress an already compressed stream, but we could.
    if (pdfStream.fState == kCompressed_State) {
        fState = kCompressed_State;
        removeLength = false;
    }
    this->mergeFrom(pdfStream);
    if (removeLength) {
        this->remove("Length");
    }
}

SkPDFStream::~SkPDFStream() {}

void SkPDFStream::emitObject(SkWStream* stream, SkPDFCatalog* catalog) {
    SkAutoMutexAcquire lock(fMutex);  // multiple threads could be calling emit
    if (!this->populate(catalog)) {
        return fSubstitute->emitObject(stream, catalog);
    }

    this->INHERITED::emitObject(stream, catalog);
    stream->writeText(" stream\n");
    stream->writeStream(fDataStream.get(), fDataStream->getLength());
    SkAssertResult(fDataStream->rewind());
    stream->writeText("\nendstream");
}

SkPDFStream::SkPDFStream() : fState(kUnused_State) {}

void SkPDFStream::setData(SkData* data) {
    // FIXME: Don't swap if the data is the same.
    fDataStream.reset(SkNEW_ARGS(SkMemoryStream, (data)));
}

void SkPDFStream::setData(SkStream* stream) {
    // Code assumes that the stream starts at the beginning and is rewindable.
    if (stream) {
        // SkStreamRewindableFromSkStream will try stream->duplicate().
        fDataStream.reset(SkStreamRewindableFromSkStream(stream));
        SkASSERT(fDataStream.get());
    } else {
        // Use an empty memory stream.
        fDataStream.reset(SkNEW(SkMemoryStream));
    }
}

size_t SkPDFStream::dataSize() const {
    SkASSERT(fDataStream->hasLength());
    return fDataStream->getLength();
}

bool SkPDFStream::populate(SkPDFCatalog* catalog) {
    if (fState == kUnused_State) {
        if (!skip_compression(catalog) && SkFlate::HaveFlate()) {
            SkDynamicMemoryWStream compressedData;

            SkAssertResult(
                    SkFlate::Deflate(fDataStream.get(), &compressedData));
            SkAssertResult(fDataStream->rewind());
            if (compressedData.getOffset() < this->dataSize()) {
                SkAutoTDelete<SkStream> compressed(
                        compressedData.detachAsStream());
                this->setData(compressed.get());
                insertName("Filter", "FlateDecode");
            }
            fState = kCompressed_State;
        } else {
            fState = kNoCompression_State;
        }
        insertInt("Length", this->dataSize());
    } else if (fState == kNoCompression_State && !skip_compression(catalog) &&
               SkFlate::HaveFlate()) {
        if (!fSubstitute.get()) {
            fSubstitute.reset(new SkPDFStream(*this));
            catalog->setSubstitute(this, fSubstitute.get());
        }
        return false;
    }
    return true;
}