PDF: why do we have flags no one uses (or can use)?

BUG=skia:

Review URL: https://codereview.chromium.org/936403002
This commit is contained in:
mtklein 2015-02-19 08:29:24 -08:00 committed by Commit bot
parent ce07afb8fa
commit cabc08c429
10 changed files with 58 additions and 136 deletions

View File

@ -30,14 +30,6 @@ static size_t pixel_count(const SkBitmap& bm) {
return SkToSizeT(bm.width()) * SkToSizeT(bm.height());
}
static bool skip_compression(SkPDFDocument::Flags flag) {
#ifndef SK_NO_FLATE
return SkToBool(flag & SkPDFDocument::kFavorSpeedOverSize_Flags);
#else
return true;
#endif // SK_NO_FLATE
}
// write a single byte to a stream n times.
static void fill_stream(SkWStream* out, char value, size_t n) {
char buffer[4096];
@ -164,14 +156,6 @@ private:
void PDFAlphaBitmap::emitObject(SkWStream* stream, SkPDFCatalog* catalog) {
SkAutoLockPixels autoLockPixels(fBitmap);
if (skip_compression(catalog->getDocumentFlags())) {
this->emitDict(stream, catalog, pixel_count(fBitmap),
/*deflate=*/false);
pdf_stream_begin(stream);
pmcolor_alpha_to_a8(fBitmap, stream);
pdf_stream_end(stream);
return;
}
#ifndef SK_NO_FLATE
// Write to a temporary buffer to get the compressed length.
SkDynamicMemoryWStream buffer;
@ -184,6 +168,11 @@ void PDFAlphaBitmap::emitObject(SkWStream* stream, SkPDFCatalog* catalog) {
pdf_stream_begin(stream);
stream->writeStream(asset.get(), asset->getLength());
pdf_stream_end(stream);
#else
this->emitDict(stream, catalog, pixel_count(fBitmap), /*deflate=*/false);
pdf_stream_begin(stream);
pmcolor_alpha_to_a8(fBitmap, stream);
pdf_stream_end(stream);
#endif // SK_NO_FLATE
}
@ -217,14 +206,6 @@ void SkPDFBitmap::addResources(SkTSet<SkPDFObject*>* resourceSet,
void SkPDFBitmap::emitObject(SkWStream* stream, SkPDFCatalog* catalog) {
SkAutoLockPixels autoLockPixels(fBitmap);
if (skip_compression(catalog->getDocumentFlags())) {
this->emitDict(stream, catalog, 3 * pixel_count(fBitmap),
/*deflate=*/false);
pdf_stream_begin(stream);
pmcolor_to_rgb24(fBitmap, stream);
pdf_stream_end(stream);
return;
}
#ifndef SK_NO_FLATE
// Write to a temporary buffer to get the compressed length.
SkDynamicMemoryWStream buffer;
@ -237,6 +218,12 @@ void SkPDFBitmap::emitObject(SkWStream* stream, SkPDFCatalog* catalog) {
pdf_stream_begin(stream);
stream->writeStream(asset.get(), asset->getLength());
pdf_stream_end(stream);
#else
this->emitDict(stream, catalog, 3 * pixel_count(fBitmap), /*deflate=*/false);
pdf_stream_begin(stream);
pmcolor_to_rgb24(fBitmap, stream);
pdf_stream_end(stream);
return;
#endif // SK_NO_FLATE
}

View File

@ -12,12 +12,10 @@
#include "SkStream.h"
#include "SkTypes.h"
SkPDFCatalog::SkPDFCatalog(SkPDFDocument::Flags flags)
: fFirstPageCount(0),
fNextObjNum(1),
fNextFirstPageObjNum(0),
fDocumentFlags(flags) {
}
SkPDFCatalog::SkPDFCatalog()
: fFirstPageCount(0)
, fNextObjNum(1)
, fNextFirstPageObjNum(0) {}
SkPDFCatalog::~SkPDFCatalog() {
fSubstituteResourcesRemaining.safeUnrefAll();

View File

@ -26,7 +26,7 @@ class SkPDFCatalog {
public:
/** Create a PDF catalog.
*/
explicit SkPDFCatalog(SkPDFDocument::Flags flags);
SkPDFCatalog();
~SkPDFCatalog();
/** Add the passed object to the catalog. Refs obj.
@ -48,10 +48,6 @@ public:
*/
int32_t getObjectNumber(SkPDFObject* obj);
/** Return the document flags in effect for this catalog/document.
*/
SkPDFDocument::Flags getDocumentFlags() const { return fDocumentFlags; }
/** Output the cross reference table for objects in the catalog.
* Returns the total number of objects.
* @param stream The writable output stream to send the output to.
@ -106,8 +102,6 @@ private:
// Next object number to assign on the first page.
uint32_t fNextFirstPageObjNum;
SkPDFDocument::Flags fDocumentFlags;
int findObjectIndex(SkPDFObject* obj);
int assignObjNum(SkPDFObject* obj);

View File

@ -47,10 +47,10 @@ static void perform_font_subsetting(SkPDFCatalog* catalog,
}
}
SkPDFDocument::SkPDFDocument(Flags flags)
SkPDFDocument::SkPDFDocument()
: fXRefFileOffset(0),
fTrailerDict(NULL) {
fCatalog.reset(new SkPDFCatalog(flags));
fCatalog.reset(SkNEW(SkPDFCatalog));
fDocCatalog = SkNEW_ARGS(SkPDFDict, ("Catalog"));
fCatalog->addObject(fDocCatalog, true);
fFirstPageResources = NULL;

View File

@ -29,18 +29,7 @@ template <typename T> class SkTSet;
*/
class SkPDFDocument {
public:
enum Flags {
kNoCompression_Flags = 0x01, //!< DEPRECATED.
kFavorSpeedOverSize_Flags = 0x01, //!< Don't compress the stream, but
// if it is already compressed return
// the compressed stream.
kNoLinks_Flags = 0x02, //!< do not honor link annotations.
kDraftMode_Flags = 0x01,
};
/** Create a PDF document.
*/
explicit SK_API SkPDFDocument(Flags flags = (Flags)0);
SK_API SkPDFDocument();
SK_API ~SkPDFDocument();
/** Output the PDF to the passed stream. It is an error to call this (it

View File

@ -22,11 +22,6 @@
static const int kNoColorTransform = 0;
static bool skip_compression(SkPDFCatalog* catalog) {
return SkToBool(catalog->getDocumentFlags() &
SkPDFDocument::kFavorSpeedOverSize_Flags);
}
static size_t get_uncompressed_size(const SkBitmap& bitmap,
const SkIRect& srcRect) {
switch (bitmap.colorType()) {
@ -603,8 +598,7 @@ SkPDFImage::SkPDFImage(SkPDFImage& pdfImage)
bool SkPDFImage::populate(SkPDFCatalog* catalog) {
if (getState() == kUnused_State) {
// Initializing image data for the first time.
if (!skip_compression(catalog) && fEncoder &&
get_uncompressed_size(fBitmap, fSrcRect) > 1) {
if (fEncoder && get_uncompressed_size(fBitmap, fSrcRect) > 1) {
SkBitmap subset;
// Extract subset
if (!fBitmap.extractSubset(&subset, fSrcRect)) {
@ -633,11 +627,9 @@ bool SkPDFImage::populate(SkPDFCatalog* catalog) {
return INHERITED::populate(catalog);
}
#ifndef SK_NO_FLATE
else if (getState() == kNoCompression_State && !skip_compression(catalog)) {
else if (getState() == kNoCompression_State) {
#else // SK_NO_FLATE
else if (getState() == kNoCompression_State &&
!skip_compression(catalog) &&
fEncoder) {
else if (getState() == kNoCompression_State && fEncoder) {
#endif // SK_NO_FLATE
// Compression has not been requested when the stream was first created,
// but the new catalog wants it compressed.

View File

@ -27,12 +27,9 @@ void SkPDFPage::finalizePage(SkPDFCatalog* catalog, bool firstPage,
if (fContentStream.get() == NULL) {
this->insert("Resources", fDevice->getResourceDict());
SkSafeUnref(this->insert("MediaBox", fDevice->copyMediaBox()));
if (!SkToBool(catalog->getDocumentFlags() &
SkPDFDocument::kNoLinks_Flags)) {
SkPDFArray* annots = fDevice->getAnnotations();
if (annots && annots->size() > 0) {
insert("Annots", annots);
}
SkPDFArray* annots = fDevice->getAnnotations();
if (annots && annots->size() > 0) {
insert("Annots", annots);
}
SkAutoTUnref<SkData> content(fDevice->copyContentToData());

View File

@ -14,11 +14,6 @@
#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);
}
@ -94,25 +89,21 @@ bool SkPDFStream::populate(SkPDFCatalog* catalog) {
if (fState == kUnused_State) {
fState = kNoCompression_State;
if (!skip_compression(catalog)) {
SkDynamicMemoryWStream compressedData;
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;
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;
insertInt("Length", this->dataSize());
}
else if (fState == kNoCompression_State && !skip_compression(catalog)) {
else if (fState == kNoCompression_State) {
if (!fSubstitute.get()) {
fSubstitute.reset(new SkPDFStream(*this));
catalog->setSubstitute(this, fSubstitute.get());

View File

@ -39,11 +39,6 @@ DEF_TEST(Annotation_NoDraw, reporter) {
REPORTER_ASSERT(reporter, 0 == *bm.getAddr32(0, 0));
}
struct testCase {
SkPDFDocument::Flags flags;
bool expectAnnotations;
};
DEF_TEST(Annotation_PdfLink, reporter) {
SkISize size = SkISize::Make(612, 792);
SkMatrix initialTransform;
@ -56,20 +51,14 @@ DEF_TEST(Annotation_PdfLink, reporter) {
SkAutoDataUnref data(SkData::NewWithCString("http://www.gooogle.com"));
SkAnnotateRectWithURL(&canvas, r, data.get());
testCase tests[] = {{(SkPDFDocument::Flags)0, true},
{SkPDFDocument::kNoLinks_Flags, false}};
for (size_t testNum = 0; testNum < SK_ARRAY_COUNT(tests); testNum++) {
SkPDFDocument doc(tests[testNum].flags);
doc.appendPage(&device);
SkDynamicMemoryWStream outStream;
doc.emitPDF(&outStream);
SkAutoDataUnref out(outStream.copyToData());
const char* rawOutput = (const char*)out->data();
SkPDFDocument doc;
doc.appendPage(&device);
SkDynamicMemoryWStream outStream;
doc.emitPDF(&outStream);
SkAutoDataUnref out(outStream.copyToData());
const char* rawOutput = (const char*)out->data();
REPORTER_ASSERT(reporter,
ContainsString(rawOutput, out->size(), "/Annots ")
== tests[testNum].expectAnnotations);
}
REPORTER_ASSERT(reporter, ContainsString(rawOutput, out->size(), "/Annots "));
}
DEF_TEST(Annotation_NamedDestination, reporter) {

View File

@ -75,12 +75,8 @@ static size_t get_output_size(SkPDFObject* object,
static void CheckObjectOutput(skiatest::Reporter* reporter, SkPDFObject* obj,
const char* expectedData, size_t expectedSize,
bool indirect, bool compression) {
SkPDFDocument::Flags docFlags = (SkPDFDocument::Flags) 0;
if (!compression) {
docFlags = SkTBitOr(docFlags, SkPDFDocument::kFavorSpeedOverSize_Flags);
}
SkPDFCatalog catalog(docFlags);
bool indirect) {
SkPDFCatalog catalog;
size_t directSize = get_output_size(obj, &catalog, false);
REPORTER_ASSERT(reporter, directSize == expectedSize);
@ -118,7 +114,7 @@ static void SimpleCheckObjectOutput(skiatest::Reporter* reporter,
SkPDFObject* obj,
const char* expectedResult) {
CheckObjectOutput(reporter, obj, expectedResult,
strlen(expectedResult), true, false);
strlen(expectedResult), true);
}
static void TestPDFStream(skiatest::Reporter* reporter) {
@ -148,32 +144,21 @@ static void TestPDFStream(skiatest::Reporter* reporter) {
SkFlate::Deflate(streamData2.get(), &compressedByteStream);
SkAutoDataUnref compressedData(compressedByteStream.copyToData());
// Check first without compression.
SkDynamicMemoryWStream expectedResult1;
expectedResult1.writeText("<</Length 167\n>> stream\n");
expectedResult1.writeText(streamBytes2);
expectedResult1.writeText("\nendstream");
SkAutoDataUnref expectedResultData1(expectedResult1.copyToData());
CheckObjectOutput(reporter, stream.get(),
(const char*) expectedResultData1->data(),
expectedResultData1->size(), true, false);
// Then again with compression.
SkDynamicMemoryWStream expectedResult2;
expectedResult2.writeText("<</Filter /FlateDecode\n/Length 116\n"
SkDynamicMemoryWStream expected;
expected.writeText("<</Filter /FlateDecode\n/Length 116\n"
">> stream\n");
expectedResult2.write(compressedData->data(), compressedData->size());
expectedResult2.writeText("\nendstream");
SkAutoDataUnref expectedResultData2(expectedResult2.copyToData());
expected.write(compressedData->data(), compressedData->size());
expected.writeText("\nendstream");
SkAutoDataUnref expectedResultData2(expected.copyToData());
CheckObjectOutput(reporter, stream.get(),
(const char*) expectedResultData2->data(),
expectedResultData2->size(), true, true);
expectedResultData2->size(), true);
}
#endif // SK_NO_FLATE
}
static void TestCatalog(skiatest::Reporter* reporter) {
SkPDFCatalog catalog((SkPDFDocument::Flags)0);
SkPDFCatalog catalog;
SkAutoTUnref<SkPDFInt> int1(new SkPDFInt(1));
SkAutoTUnref<SkPDFInt> int2(new SkPDFInt(2));
SkAutoTUnref<SkPDFInt> int3(new SkPDFInt(3));
@ -195,7 +180,7 @@ static void TestObjectRef(skiatest::Reporter* reporter) {
SkAutoTUnref<SkPDFInt> int2(new SkPDFInt(2));
SkAutoTUnref<SkPDFObjRef> int2ref(new SkPDFObjRef(int2.get()));
SkPDFCatalog catalog((SkPDFDocument::Flags)0);
SkPDFCatalog catalog;
catalog.addObject(int1.get(), false);
catalog.addObject(int2.get(), false);
REPORTER_ASSERT(reporter, catalog.getObjectNumber(int1.get()) == 1);
@ -216,7 +201,7 @@ static void TestSubstitute(skiatest::Reporter* reporter) {
proxy->insert("Value", new SkPDFInt(33))->unref();
stub->insert("Value", new SkPDFInt(44))->unref();
SkPDFCatalog catalog((SkPDFDocument::Flags)0);
SkPDFCatalog catalog;
catalog.addObject(proxy.get(), false);
catalog.setSubstitute(proxy.get(), stub.get());
@ -278,12 +263,12 @@ DEF_TEST(PDFPrimitives, reporter) {
SkAutoTUnref<SkPDFName> name(new SkPDFName("Test name\twith#tab"));
const char expectedResult[] = "/Test#20name#09with#23tab";
CheckObjectOutput(reporter, name.get(), expectedResult,
strlen(expectedResult), false, false);
strlen(expectedResult), false);
SkAutoTUnref<SkPDFName> escapedName(new SkPDFName("A#/%()<>[]{}B"));
const char escapedNameExpected[] = "/A#23#2F#25#28#29#3C#3E#5B#5D#7B#7DB";
CheckObjectOutput(reporter, escapedName.get(), escapedNameExpected,
strlen(escapedNameExpected), false, false);
strlen(escapedNameExpected), false);
// Test that we correctly handle characters with the high-bit set.
const unsigned char highBitCString[] = {0xDE, 0xAD, 'b', 'e', 0xEF, 0};
@ -291,7 +276,7 @@ DEF_TEST(PDFPrimitives, reporter) {
new SkPDFName((const char*)highBitCString));
const char highBitExpectedResult[] = "/#DE#ADbe#EF";
CheckObjectOutput(reporter, highBitName.get(), highBitExpectedResult,
strlen(highBitExpectedResult), false, false);
strlen(highBitExpectedResult), false);
SkAutoTUnref<SkPDFArray> array(new SkPDFArray);
SimpleCheckObjectOutput(reporter, array.get(), "[]");