зеркало из https://github.com/mozilla/moz-skia.git
Move SkPDFStream back to SkStream to save memory.
SkPDFStream stores data as a SkStreamRewindable to minimize deep duplication and memory overhead. SkStreamToStreamRewindable function to deal with fact that SkTypeface returns a SkStream. BUG=skia:2743 R=djsollen@google.com, mtklein@google.com, bungeman@google.com, reed@google.com Author: halcanary@google.com Review URL: https://codereview.chromium.org/387863005
This commit is contained in:
Родитель
9c6878be37
Коммит
e322482f4d
|
@ -907,3 +907,35 @@ SkData* SkCopyStreamToData(SkStream* stream) {
|
||||||
} while (!stream->isAtEnd());
|
} while (!stream->isAtEnd());
|
||||||
return tempStream.copyToData();
|
return tempStream.copyToData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SkStreamRewindable* SkStreamRewindableFromSkStream(SkStream* stream) {
|
||||||
|
if (!stream) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
SkAutoTUnref<SkStreamRewindable> dupStream(stream->duplicate());
|
||||||
|
if (dupStream) {
|
||||||
|
return dupStream.detach();
|
||||||
|
}
|
||||||
|
stream->rewind();
|
||||||
|
if (stream->hasLength()) {
|
||||||
|
size_t length = stream->getLength();
|
||||||
|
if (stream->hasPosition()) { // If stream has length, but can't rewind.
|
||||||
|
length -= stream->getPosition();
|
||||||
|
}
|
||||||
|
SkAutoMalloc allocMemory(length);
|
||||||
|
SkDEBUGCODE(size_t read =) stream->read(allocMemory.get(), length);
|
||||||
|
SkASSERT(length == read);
|
||||||
|
SkAutoTUnref<SkData> data(
|
||||||
|
SkData::NewFromMalloc(allocMemory.detach(), length));
|
||||||
|
return SkNEW_ARGS(SkMemoryStream, (data.get()));
|
||||||
|
}
|
||||||
|
SkDynamicMemoryWStream tempStream;
|
||||||
|
const size_t bufferSize = 4096;
|
||||||
|
char buffer[bufferSize];
|
||||||
|
do {
|
||||||
|
size_t bytesRead = stream->read(buffer, bufferSize);
|
||||||
|
tempStream.write(buffer, bytesRead);
|
||||||
|
} while (!stream->isAtEnd());
|
||||||
|
return tempStream.detachAsStream(); // returns a SkBlockMemoryStream,
|
||||||
|
// cheaper than copying to SkData
|
||||||
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
|
|
||||||
class SkAutoMalloc;
|
class SkAutoMalloc;
|
||||||
class SkStream;
|
class SkStream;
|
||||||
|
class SkStreamRewindable;
|
||||||
class SkData;
|
class SkData;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -34,4 +35,12 @@ size_t SkCopyStreamToStorage(SkAutoMalloc* storage, SkStream* stream);
|
||||||
*/
|
*/
|
||||||
SkData *SkCopyStreamToData(SkStream* stream);
|
SkData *SkCopyStreamToData(SkStream* stream);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempt to convert this stream to a StreamRewindable in the
|
||||||
|
* cheapest possible manner (calling duplicate() if possible, and
|
||||||
|
* otherwise allocating memory for a copy). The position of the
|
||||||
|
* input stream is left in an indeterminate state.
|
||||||
|
*/
|
||||||
|
SkStreamRewindable* SkStreamRewindableFromSkStream(SkStream* stream);
|
||||||
|
|
||||||
#endif // SkStreamPriv_DEFINED
|
#endif // SkStreamPriv_DEFINED
|
||||||
|
|
|
@ -30,7 +30,7 @@ SkPDFStream::SkPDFStream(SkData* data) : fState(kUnused_State) {
|
||||||
SkPDFStream::SkPDFStream(const SkPDFStream& pdfStream)
|
SkPDFStream::SkPDFStream(const SkPDFStream& pdfStream)
|
||||||
: SkPDFDict(),
|
: SkPDFDict(),
|
||||||
fState(kUnused_State) {
|
fState(kUnused_State) {
|
||||||
this->setData(pdfStream.fData.get());
|
this->setData(pdfStream.fDataStream.get());
|
||||||
bool removeLength = true;
|
bool removeLength = true;
|
||||||
// Don't uncompress an already compressed stream, but we could.
|
// Don't uncompress an already compressed stream, but we could.
|
||||||
if (pdfStream.fState == kCompressed_State) {
|
if (pdfStream.fState == kCompressed_State) {
|
||||||
|
@ -57,9 +57,8 @@ void SkPDFStream::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
|
||||||
|
|
||||||
this->INHERITED::emitObject(stream, catalog, false);
|
this->INHERITED::emitObject(stream, catalog, false);
|
||||||
stream->writeText(" stream\n");
|
stream->writeText(" stream\n");
|
||||||
if (fData.get()) {
|
stream->writeStream(fDataStream.get(), fDataStream->getLength());
|
||||||
stream->write(fData->data(), fData->size());
|
SkAssertResult(fDataStream->rewind());
|
||||||
}
|
|
||||||
stream->writeText("\nendstream");
|
stream->writeText("\nendstream");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,22 +78,31 @@ size_t SkPDFStream::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
|
||||||
SkPDFStream::SkPDFStream() : fState(kUnused_State) {}
|
SkPDFStream::SkPDFStream() : fState(kUnused_State) {}
|
||||||
|
|
||||||
void SkPDFStream::setData(SkData* data) {
|
void SkPDFStream::setData(SkData* data) {
|
||||||
fData.reset(SkSafeRef(data));
|
fMemoryStream.setData(data);
|
||||||
|
if (&fMemoryStream != fDataStream.get()) {
|
||||||
|
fDataStream.reset(SkRef(&fMemoryStream));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkPDFStream::setData(SkStream* stream) {
|
void SkPDFStream::setData(SkStream* stream) {
|
||||||
// Code assumes that the stream starts at the beginning and is rewindable.
|
// Code assumes that the stream starts at the beginning and is rewindable.
|
||||||
|
if (&fMemoryStream == fDataStream.get()) {
|
||||||
|
SkASSERT(&fMemoryStream != stream);
|
||||||
|
fMemoryStream.setData(NULL);
|
||||||
|
}
|
||||||
|
SkASSERT(0 == fMemoryStream.getLength());
|
||||||
if (stream) {
|
if (stream) {
|
||||||
SkASSERT(stream->getPosition() == 0);
|
// SkStreamRewindableFromSkStream will try stream->duplicate().
|
||||||
fData.reset(SkCopyStreamToData(stream));
|
fDataStream.reset(SkStreamRewindableFromSkStream(stream));
|
||||||
SkAssertResult(stream->rewind());
|
SkASSERT(fDataStream.get());
|
||||||
} else {
|
} else {
|
||||||
fData.reset(NULL);
|
fDataStream.reset(SkRef(&fMemoryStream));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t SkPDFStream::dataSize() const {
|
size_t SkPDFStream::dataSize() const {
|
||||||
return fData.get() ? fData->size() : 0;
|
SkASSERT(fDataStream->hasLength());
|
||||||
|
return fDataStream->getLength();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SkPDFStream::populate(SkPDFCatalog* catalog) {
|
bool SkPDFStream::populate(SkPDFCatalog* catalog) {
|
||||||
|
@ -102,9 +110,11 @@ bool SkPDFStream::populate(SkPDFCatalog* catalog) {
|
||||||
if (!skip_compression(catalog) && SkFlate::HaveFlate()) {
|
if (!skip_compression(catalog) && SkFlate::HaveFlate()) {
|
||||||
SkDynamicMemoryWStream compressedData;
|
SkDynamicMemoryWStream compressedData;
|
||||||
|
|
||||||
SkAssertResult(SkFlate::Deflate(fData.get(), &compressedData));
|
SkAssertResult(
|
||||||
|
SkFlate::Deflate(fDataStream.get(), &compressedData));
|
||||||
|
SkAssertResult(fDataStream->rewind());
|
||||||
if (compressedData.getOffset() < this->dataSize()) {
|
if (compressedData.getOffset() < this->dataSize()) {
|
||||||
fData.reset(compressedData.copyToData());
|
this->setData(compressedData.detachAsStream());
|
||||||
insertName("Filter", "FlateDecode");
|
insertName("Filter", "FlateDecode");
|
||||||
}
|
}
|
||||||
fState = kCompressed_State;
|
fState = kCompressed_State;
|
||||||
|
|
|
@ -21,19 +21,20 @@ class SkPDFCatalog;
|
||||||
|
|
||||||
A stream object in a PDF. Note, all streams must be indirect objects (via
|
A stream object in a PDF. Note, all streams must be indirect objects (via
|
||||||
SkObjRef).
|
SkObjRef).
|
||||||
TODO(vandebo): SkStream should be replaced by SkStreamRewindable when that
|
|
||||||
is feasible.
|
|
||||||
*/
|
*/
|
||||||
class SkPDFStream : public SkPDFDict {
|
class SkPDFStream : public SkPDFDict {
|
||||||
SK_DECLARE_INST_COUNT(SkPDFStream)
|
SK_DECLARE_INST_COUNT(SkPDFStream)
|
||||||
public:
|
public:
|
||||||
/** Create a PDF stream. A Length entry is automatically added to the
|
/** Create a PDF stream. A Length entry is automatically added to the
|
||||||
* stream dictionary. The stream may be retained (stream->ref() may be
|
* stream dictionary.
|
||||||
* called) so its contents must not be changed after calling this.
|
* @param data The data part of the stream. Will be ref()ed.
|
||||||
* @param data The data part of the stream.
|
|
||||||
*/
|
*/
|
||||||
explicit SkPDFStream(SkData* data);
|
explicit SkPDFStream(SkData* data);
|
||||||
/** Deprecated constructor. */
|
|
||||||
|
/** Create a PDF stream. A Length entry is automatically added to the
|
||||||
|
* stream dictionary.
|
||||||
|
* @param stream The data part of the stream. Will be duplicate()d.
|
||||||
|
*/
|
||||||
explicit SkPDFStream(SkStream* stream);
|
explicit SkPDFStream(SkStream* stream);
|
||||||
|
|
||||||
virtual ~SkPDFStream();
|
virtual ~SkPDFStream();
|
||||||
|
@ -79,8 +80,6 @@ protected:
|
||||||
|
|
||||||
size_t dataSize() const;
|
size_t dataSize() const;
|
||||||
|
|
||||||
SkData* getData() const { return fData.get(); }
|
|
||||||
|
|
||||||
void setState(State state) {
|
void setState(State state) {
|
||||||
fState = state;
|
fState = state;
|
||||||
}
|
}
|
||||||
|
@ -93,10 +92,13 @@ private:
|
||||||
// Indicates what form (or if) the stream has been requested.
|
// Indicates what form (or if) the stream has been requested.
|
||||||
State fState;
|
State fState;
|
||||||
|
|
||||||
// Mutex guards fState, fData, and fSubstitute in public interface.
|
// Mutex guards fState, fDataStream, and fSubstitute in public interface.
|
||||||
SkMutex fMutex;
|
SkMutex fMutex;
|
||||||
|
|
||||||
SkAutoTUnref<SkData> fData;
|
SkMemoryStream fMemoryStream; // Used by fDataStream when
|
||||||
|
// fDataStream needs to be backed
|
||||||
|
// by SkData.
|
||||||
|
SkAutoTUnref<SkStreamRewindable> fDataStream;
|
||||||
SkAutoTUnref<SkPDFStream> fSubstitute;
|
SkAutoTUnref<SkPDFStream> fSubstitute;
|
||||||
|
|
||||||
typedef SkPDFDict INHERITED;
|
typedef SkPDFDict INHERITED;
|
||||||
|
|
Загрузка…
Ссылка в новой задаче