зеркало из 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());
|
||||
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 SkStream;
|
||||
class SkStreamRewindable;
|
||||
class SkData;
|
||||
|
||||
/**
|
||||
|
@ -34,4 +35,12 @@ size_t SkCopyStreamToStorage(SkAutoMalloc* storage, 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
|
||||
|
|
|
@ -30,7 +30,7 @@ SkPDFStream::SkPDFStream(SkData* data) : fState(kUnused_State) {
|
|||
SkPDFStream::SkPDFStream(const SkPDFStream& pdfStream)
|
||||
: SkPDFDict(),
|
||||
fState(kUnused_State) {
|
||||
this->setData(pdfStream.fData.get());
|
||||
this->setData(pdfStream.fDataStream.get());
|
||||
bool removeLength = true;
|
||||
// Don't uncompress an already compressed stream, but we could.
|
||||
if (pdfStream.fState == kCompressed_State) {
|
||||
|
@ -57,9 +57,8 @@ void SkPDFStream::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
|
|||
|
||||
this->INHERITED::emitObject(stream, catalog, false);
|
||||
stream->writeText(" stream\n");
|
||||
if (fData.get()) {
|
||||
stream->write(fData->data(), fData->size());
|
||||
}
|
||||
stream->writeStream(fDataStream.get(), fDataStream->getLength());
|
||||
SkAssertResult(fDataStream->rewind());
|
||||
stream->writeText("\nendstream");
|
||||
}
|
||||
|
||||
|
@ -79,22 +78,31 @@ size_t SkPDFStream::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
|
|||
SkPDFStream::SkPDFStream() : fState(kUnused_State) {}
|
||||
|
||||
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) {
|
||||
// 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) {
|
||||
SkASSERT(stream->getPosition() == 0);
|
||||
fData.reset(SkCopyStreamToData(stream));
|
||||
SkAssertResult(stream->rewind());
|
||||
// SkStreamRewindableFromSkStream will try stream->duplicate().
|
||||
fDataStream.reset(SkStreamRewindableFromSkStream(stream));
|
||||
SkASSERT(fDataStream.get());
|
||||
} else {
|
||||
fData.reset(NULL);
|
||||
fDataStream.reset(SkRef(&fMemoryStream));
|
||||
}
|
||||
}
|
||||
|
||||
size_t SkPDFStream::dataSize() const {
|
||||
return fData.get() ? fData->size() : 0;
|
||||
SkASSERT(fDataStream->hasLength());
|
||||
return fDataStream->getLength();
|
||||
}
|
||||
|
||||
bool SkPDFStream::populate(SkPDFCatalog* catalog) {
|
||||
|
@ -102,9 +110,11 @@ bool SkPDFStream::populate(SkPDFCatalog* catalog) {
|
|||
if (!skip_compression(catalog) && SkFlate::HaveFlate()) {
|
||||
SkDynamicMemoryWStream compressedData;
|
||||
|
||||
SkAssertResult(SkFlate::Deflate(fData.get(), &compressedData));
|
||||
SkAssertResult(
|
||||
SkFlate::Deflate(fDataStream.get(), &compressedData));
|
||||
SkAssertResult(fDataStream->rewind());
|
||||
if (compressedData.getOffset() < this->dataSize()) {
|
||||
fData.reset(compressedData.copyToData());
|
||||
this->setData(compressedData.detachAsStream());
|
||||
insertName("Filter", "FlateDecode");
|
||||
}
|
||||
fState = kCompressed_State;
|
||||
|
|
|
@ -21,19 +21,20 @@ class SkPDFCatalog;
|
|||
|
||||
A stream object in a PDF. Note, all streams must be indirect objects (via
|
||||
SkObjRef).
|
||||
TODO(vandebo): SkStream should be replaced by SkStreamRewindable when that
|
||||
is feasible.
|
||||
*/
|
||||
class SkPDFStream : public SkPDFDict {
|
||||
SK_DECLARE_INST_COUNT(SkPDFStream)
|
||||
public:
|
||||
/** Create a PDF stream. A Length entry is automatically added to the
|
||||
* stream dictionary. The stream may be retained (stream->ref() may be
|
||||
* called) so its contents must not be changed after calling this.
|
||||
* @param data The data part of the stream.
|
||||
* stream dictionary.
|
||||
* @param data The data part of the stream. Will be ref()ed.
|
||||
*/
|
||||
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);
|
||||
|
||||
virtual ~SkPDFStream();
|
||||
|
@ -79,8 +80,6 @@ protected:
|
|||
|
||||
size_t dataSize() const;
|
||||
|
||||
SkData* getData() const { return fData.get(); }
|
||||
|
||||
void setState(State state) {
|
||||
fState = state;
|
||||
}
|
||||
|
@ -93,10 +92,13 @@ private:
|
|||
// Indicates what form (or if) the stream has been requested.
|
||||
State fState;
|
||||
|
||||
// Mutex guards fState, fData, and fSubstitute in public interface.
|
||||
// Mutex guards fState, fDataStream, and fSubstitute in public interface.
|
||||
SkMutex fMutex;
|
||||
|
||||
SkAutoTUnref<SkData> fData;
|
||||
SkMemoryStream fMemoryStream; // Used by fDataStream when
|
||||
// fDataStream needs to be backed
|
||||
// by SkData.
|
||||
SkAutoTUnref<SkStreamRewindable> fDataStream;
|
||||
SkAutoTUnref<SkPDFStream> fSubstitute;
|
||||
|
||||
typedef SkPDFDict INHERITED;
|
||||
|
|
Загрузка…
Ссылка в новой задаче