1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com
28459d4e5e32608ec6da3f2b81731aaeb7b038843vandebo@chromium.org/*
3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright 2010 Google Inc.
48459d4e5e32608ec6da3f2b81731aaeb7b038843vandebo@chromium.org *
5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Use of this source code is governed by a BSD-style license that can be
6ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * found in the LICENSE file.
78459d4e5e32608ec6da3f2b81731aaeb7b038843vandebo@chromium.org */
88459d4e5e32608ec6da3f2b81731aaeb7b038843vandebo@chromium.org
9ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com
108a85d0c4938173476d037d7af0ee3b9436a1234ereed@google.com#include "SkData.h"
11a09ef977b6799f01cd3fd64725fb3069da8be4bcvandebo@chromium.org#include "SkFlate.h"
128459d4e5e32608ec6da3f2b81731aaeb7b038843vandebo@chromium.org#include "SkPDFCatalog.h"
138459d4e5e32608ec6da3f2b81731aaeb7b038843vandebo@chromium.org#include "SkPDFStream.h"
148459d4e5e32608ec6da3f2b81731aaeb7b038843vandebo@chromium.org#include "SkStream.h"
1567ec1f8eecfb48bc0a6ba04c0057f103c1c9696fhalcanary#include "SkStreamPriv.h"
168459d4e5e32608ec6da3f2b81731aaeb7b038843vandebo@chromium.org
17421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.orgstatic bool skip_compression(SkPDFCatalog* catalog) {
18238be8c7e5de5a83517440a3db7f7965b47fb010vandebo@chromium.org    return SkToBool(catalog->getDocumentFlags() &
198c020612bad088d1a26dd663f0a806deeef8029bedisonn@google.com                    SkPDFDocument::kFavorSpeedOverSize_Flags);
20421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org}
211cfa2c458626abe952a63b1a9397d8e496a134d6vandebo@chromium.org
2226e1449d85805c61e4caff1f68e4f57498359649vandebo@chromium.orgSkPDFStream::SkPDFStream(SkStream* stream) : fState(kUnused_State) {
2367ec1f8eecfb48bc0a6ba04c0057f103c1c9696fhalcanary    this->setData(stream);
248459d4e5e32608ec6da3f2b81731aaeb7b038843vandebo@chromium.org}
258459d4e5e32608ec6da3f2b81731aaeb7b038843vandebo@chromium.org
26421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.orgSkPDFStream::SkPDFStream(SkData* data) : fState(kUnused_State) {
2767ec1f8eecfb48bc0a6ba04c0057f103c1c9696fhalcanary    this->setData(data);
28421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org}
29421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org
30421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.orgSkPDFStream::SkPDFStream(const SkPDFStream& pdfStream)
31421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org        : SkPDFDict(),
3226e1449d85805c61e4caff1f68e4f57498359649vandebo@chromium.org          fState(kUnused_State) {
33e322482f4d82bc704e40b8c89843f2ea5b6ddc04halcanary    this->setData(pdfStream.fDataStream.get());
34421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org    bool removeLength = true;
35421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org    // Don't uncompress an already compressed stream, but we could.
36421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org    if (pdfStream.fState == kCompressed_State) {
37421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org        fState = kCompressed_State;
38421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org        removeLength = false;
39421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org    }
401f8ed022226c9f960b9fc95af9297d5111a07eadhalcanary    this->mergeFrom(pdfStream);
411f8ed022226c9f960b9fc95af9297d5111a07eadhalcanary    if (removeLength) {
421f8ed022226c9f960b9fc95af9297d5111a07eadhalcanary        this->remove("Length");
43421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org    }
448459d4e5e32608ec6da3f2b81731aaeb7b038843vandebo@chromium.org}
458459d4e5e32608ec6da3f2b81731aaeb7b038843vandebo@chromium.org
46421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.orgSkPDFStream::~SkPDFStream() {}
47421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org
488459d4e5e32608ec6da3f2b81731aaeb7b038843vandebo@chromium.orgvoid SkPDFStream::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
498459d4e5e32608ec6da3f2b81731aaeb7b038843vandebo@chromium.org                             bool indirect) {
50421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org    if (indirect) {
518459d4e5e32608ec6da3f2b81731aaeb7b038843vandebo@chromium.org        return emitIndirectObject(stream, catalog);
52421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org    }
5367ec1f8eecfb48bc0a6ba04c0057f103c1c9696fhalcanary    SkAutoMutexAcquire lock(fMutex);  // multiple threads could be calling emit
54421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org    if (!this->populate(catalog)) {
55421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org        return fSubstitute->emitObject(stream, catalog, indirect);
56421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org    }
578459d4e5e32608ec6da3f2b81731aaeb7b038843vandebo@chromium.org
58d90c141feb10c80581c16dbb57fcc97719a0c002vandebo@chromium.org    this->INHERITED::emitObject(stream, catalog, false);
598459d4e5e32608ec6da3f2b81731aaeb7b038843vandebo@chromium.org    stream->writeText(" stream\n");
60e322482f4d82bc704e40b8c89843f2ea5b6ddc04halcanary    stream->writeStream(fDataStream.get(), fDataStream->getLength());
61e322482f4d82bc704e40b8c89843f2ea5b6ddc04halcanary    SkAssertResult(fDataStream->rewind());
629b49dc0db8254e3dcdc2de4a1e0add4f8a7ac5a8vandebo@chromium.org    stream->writeText("\nendstream");
638459d4e5e32608ec6da3f2b81731aaeb7b038843vandebo@chromium.org}
648459d4e5e32608ec6da3f2b81731aaeb7b038843vandebo@chromium.org
658459d4e5e32608ec6da3f2b81731aaeb7b038843vandebo@chromium.orgsize_t SkPDFStream::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
66421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org    if (indirect) {
678459d4e5e32608ec6da3f2b81731aaeb7b038843vandebo@chromium.org        return getIndirectOutputSize(catalog);
68421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org    }
6967ec1f8eecfb48bc0a6ba04c0057f103c1c9696fhalcanary    SkAutoMutexAcquire lock(fMutex);  // multiple threads could be calling emit
70421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org    if (!this->populate(catalog)) {
71421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org        return fSubstitute->getOutputSize(catalog, indirect);
72421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org    }
738459d4e5e32608ec6da3f2b81731aaeb7b038843vandebo@chromium.org
74d90c141feb10c80581c16dbb57fcc97719a0c002vandebo@chromium.org    return this->INHERITED::getOutputSize(catalog, false) +
7567ec1f8eecfb48bc0a6ba04c0057f103c1c9696fhalcanary        strlen(" stream\n\nendstream") + this->dataSize();
76421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org}
77421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org
78421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.orgSkPDFStream::SkPDFStream() : fState(kUnused_State) {}
79421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org
80d8d976e7d2d302d4efb53f143034f153adc5565ccommit-bot@chromium.orgvoid SkPDFStream::setData(SkData* data) {
81e322482f4d82bc704e40b8c89843f2ea5b6ddc04halcanary    fMemoryStream.setData(data);
82e322482f4d82bc704e40b8c89843f2ea5b6ddc04halcanary    if (&fMemoryStream != fDataStream.get()) {
83e322482f4d82bc704e40b8c89843f2ea5b6ddc04halcanary        fDataStream.reset(SkRef(&fMemoryStream));
84e322482f4d82bc704e40b8c89843f2ea5b6ddc04halcanary    }
85d8d976e7d2d302d4efb53f143034f153adc5565ccommit-bot@chromium.org}
86d8d976e7d2d302d4efb53f143034f153adc5565ccommit-bot@chromium.org
87421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.orgvoid SkPDFStream::setData(SkStream* stream) {
8826e1449d85805c61e4caff1f68e4f57498359649vandebo@chromium.org    // Code assumes that the stream starts at the beginning and is rewindable.
89e322482f4d82bc704e40b8c89843f2ea5b6ddc04halcanary    if (&fMemoryStream == fDataStream.get()) {
90e322482f4d82bc704e40b8c89843f2ea5b6ddc04halcanary        SkASSERT(&fMemoryStream != stream);
91e322482f4d82bc704e40b8c89843f2ea5b6ddc04halcanary        fMemoryStream.setData(NULL);
92e322482f4d82bc704e40b8c89843f2ea5b6ddc04halcanary    }
93e322482f4d82bc704e40b8c89843f2ea5b6ddc04halcanary    SkASSERT(0 == fMemoryStream.getLength());
9426e1449d85805c61e4caff1f68e4f57498359649vandebo@chromium.org    if (stream) {
95e322482f4d82bc704e40b8c89843f2ea5b6ddc04halcanary        // SkStreamRewindableFromSkStream will try stream->duplicate().
96e322482f4d82bc704e40b8c89843f2ea5b6ddc04halcanary        fDataStream.reset(SkStreamRewindableFromSkStream(stream));
97e322482f4d82bc704e40b8c89843f2ea5b6ddc04halcanary        SkASSERT(fDataStream.get());
9867ec1f8eecfb48bc0a6ba04c0057f103c1c9696fhalcanary    } else {
99e322482f4d82bc704e40b8c89843f2ea5b6ddc04halcanary        fDataStream.reset(SkRef(&fMemoryStream));
10026e1449d85805c61e4caff1f68e4f57498359649vandebo@chromium.org    }
10167ec1f8eecfb48bc0a6ba04c0057f103c1c9696fhalcanary}
10267ec1f8eecfb48bc0a6ba04c0057f103c1c9696fhalcanary
10367ec1f8eecfb48bc0a6ba04c0057f103c1c9696fhalcanarysize_t SkPDFStream::dataSize() const {
104e322482f4d82bc704e40b8c89843f2ea5b6ddc04halcanary    SkASSERT(fDataStream->hasLength());
105e322482f4d82bc704e40b8c89843f2ea5b6ddc04halcanary    return fDataStream->getLength();
106421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org}
107421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org
108421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.orgbool SkPDFStream::populate(SkPDFCatalog* catalog) {
109421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org    if (fState == kUnused_State) {
110421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org        if (!skip_compression(catalog) && SkFlate::HaveFlate()) {
111421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org            SkDynamicMemoryWStream compressedData;
112421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org
113e322482f4d82bc704e40b8c89843f2ea5b6ddc04halcanary            SkAssertResult(
114e322482f4d82bc704e40b8c89843f2ea5b6ddc04halcanary                    SkFlate::Deflate(fDataStream.get(), &compressedData));
115e322482f4d82bc704e40b8c89843f2ea5b6ddc04halcanary            SkAssertResult(fDataStream->rewind());
11667ec1f8eecfb48bc0a6ba04c0057f103c1c9696fhalcanary            if (compressedData.getOffset() < this->dataSize()) {
117f459c85457c6f470af3fe096fef2524d5443401ahalcanary                SkAutoTUnref<SkStream> compressed(
118f459c85457c6f470af3fe096fef2524d5443401ahalcanary                        compressedData.detachAsStream());
119f459c85457c6f470af3fe096fef2524d5443401ahalcanary                this->setData(compressed.get());
120421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org                insertName("Filter", "FlateDecode");
121421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org            }
122421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org            fState = kCompressed_State;
123421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org        } else {
124421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org            fState = kNoCompression_State;
125421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org        }
12667ec1f8eecfb48bc0a6ba04c0057f103c1c9696fhalcanary        insertInt("Length", this->dataSize());
127421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org    } else if (fState == kNoCompression_State && !skip_compression(catalog) &&
128421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org               SkFlate::HaveFlate()) {
129421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org        if (!fSubstitute.get()) {
130d96d17b9c113ac694138224249ff2ce643e961ddvandebo@chromium.org            fSubstitute.reset(new SkPDFStream(*this));
131421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org            catalog->setSubstitute(this, fSubstitute.get());
132421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org        }
133421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org        return false;
134421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org    }
135421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org    return true;
1368459d4e5e32608ec6da3f2b81731aaeb7b038843vandebo@chromium.org}
137