SkPDF/Tests: imporve test coverage.

Also: make sure that all SkPDF unit tests are named SkPDF_* to
make testing changes to SkPDF easier.  Other cleanup.

Add test: SkPDF_pdfa_document to verify that flag in public API
works.

SkPDF_JpegIdentification test: test slightly malformed JPEGs to
verify that all code paths work.

BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2322133003

Review-Url: https://codereview.chromium.org/2322133003
This commit is contained in:
halcanary 2016-09-09 11:41:59 -07:00 committed by Commit bot
parent 8d914908d8
commit 57f744e303
6 changed files with 183 additions and 20 deletions

View File

@ -101,7 +101,7 @@ SkStreamAsset* stream_inflate(skiatest::Reporter* reporter, SkStream* src) {
}
} // namespace
DEF_TEST(SkDeflateWStream, r) {
DEF_TEST(SkPDF_DeflateWStream, r) {
SkRandom random(123456);
for (int i = 0; i < 50; ++i) {
uint32_t size = random.nextULessThan(10000);
@ -123,6 +123,7 @@ DEF_TEST(SkDeflateWStream, r) {
}
j += writeSize;
}
REPORTER_ASSERT(r, deflateWStream.bytesWritten() == size);
}
SkAutoTDelete<SkStreamAsset> compressed(
dynamicMemoryWStream.detachAsStream());
@ -159,4 +160,6 @@ DEF_TEST(SkDeflateWStream, r) {
}
}
}
SkDeflateWStream emptyDeflateWStream(nullptr);
REPORTER_ASSERT(r, !emptyDeflateWStream.writeText("FOO"));
}

View File

@ -105,7 +105,7 @@ static void test_close(skiatest::Reporter* reporter) {
REPORTER_ASSERT(reporter, stream.bytesWritten() != 0);
}
DEF_TEST(document_tests, reporter) {
DEF_TEST(SkPDF_document_tests, reporter) {
REQUIRE_PDF_DOCUMENT(document_tests, reporter);
test_empty(reporter);
test_abort(reporter);
@ -147,8 +147,8 @@ size_t count_bytes(const SkBitmap& bm, bool useDCT) {
return stream.bytesWritten();
}
DEF_TEST(document_dct_encoder, r) {
REQUIRE_PDF_DOCUMENT(document_dct_encoder, r);
DEF_TEST(SkPDF_document_dct_encoder, r) {
REQUIRE_PDF_DOCUMENT(SkPDF_document_dct_encoder, r);
SkBitmap bm;
if (GetResourceAsBitmap("mandrill_64.png", &bm)) {
// Lossy encoding works better on photographs.
@ -156,8 +156,8 @@ DEF_TEST(document_dct_encoder, r) {
}
}
DEF_TEST(document_skbug_4734, r) {
REQUIRE_PDF_DOCUMENT(document_skbug_4734, r);
DEF_TEST(SkPDF_document_skbug_4734, r) {
REQUIRE_PDF_DOCUMENT(SkPDF_document_skbug_4734, r);
SkDynamicMemoryWStream stream;
sk_sp<SkDocument> doc(SkDocument::MakePDF(&stream));
SkCanvas* canvas = doc->beginPage(64, 64);
@ -167,3 +167,63 @@ DEF_TEST(document_skbug_4734, r) {
const char text[] = "HELLO";
canvas->drawText(text, strlen(text), 0, 0, SkPaint());
}
static bool contains(const uint8_t* result, size_t size, const char expectation[]) {
size_t len = strlen(expectation);
size_t N = 1 + size - len;
for (size_t i = 0; i < N; ++i) {
if (0 == memcmp(result + i, expectation, len)) {
return true;
}
}
return false;
}
// verify that the PDFA flag does something.
DEF_TEST(SkPDF_pdfa_document, r) {
REQUIRE_PDF_DOCUMENT(SkPDF_pdfa_document, r);
SkDocument::PDFMetadata pdfMetadata;
pdfMetadata.fTitle = "test document";
pdfMetadata.fCreation.fEnabled = true;
pdfMetadata.fCreation.fDateTime = {0, 1999, 12, 5, 31, 23, 59, 59};
SkDynamicMemoryWStream buffer;
auto doc = SkDocument::MakePDF(&buffer, SK_ScalarDefaultRasterDPI,
pdfMetadata, nullptr, /* pdfa = */ true);
doc->beginPage(64, 64)->drawColor(SK_ColorRED);
doc->close();
sk_sp<SkData> data(buffer.copyToData());
buffer.reset();
static const char* expectations[] = {
"sRGB IEC61966-2.1",
"<dc:title><rdf:Alt><rdf:li xml:lang=\"x-default\">test document",
"<xmp:CreateDate>1999-12-31T23:59:59+00:00</xmp:CreateDate>",
"/Subtype /XML",
"/CreationDate (D:19991231235959+00'00')>>",
};
for (const char* expectation : expectations) {
if (!contains(data->bytes(), data->size(), expectation)) {
ERRORF(r, "PDFA expectation missing: '%s'.", expectation);
}
}
pdfMetadata.fProducer = "phoney library";
doc = SkDocument::MakePDF(&buffer, SK_ScalarDefaultRasterDPI,
pdfMetadata, nullptr, /* pdfa = */ true);
doc->beginPage(64, 64)->drawColor(SK_ColorRED);
doc->close();
data.reset(buffer.copyToData());
buffer.reset();
static const char* moreExpectations[] = {
"/Producer (phoney library)",
"/ProductionLibrary (Skia/PDF m",
"<!-- <skia:ProductionLibrary>Skia/PDF m",
"<pdf:Producer>phoney library</pdf:Producer>",
};
for (const char* expectation : moreExpectations) {
if (!contains(data->bytes(), data->size(), expectation)) {
ERRORF(r, "PDFA expectation missing: '%s'.", expectation);
}
}
}

View File

@ -25,7 +25,7 @@ static bool stream_equals(const SkDynamicMemoryWStream& stream, size_t offset,
return memcmp(data->bytes() + offset, buffer, len) == 0;
}
DEF_TEST(ToUnicode, reporter) {
DEF_TEST(SkPDF_ToUnicode, reporter) {
SkTDArray<SkUnichar> glyphToUnicode;
SkTDArray<uint16_t> glyphsInSubset;
SkBitSet subset(kMaximumGlyphCount);

View File

@ -43,9 +43,12 @@ SkBitmap make_invalid_bitmap(SkColorType colorType) {
} // namespace
DEF_TEST(PDFInvalidBitmap, reporter) {
DEF_TEST(SkPDF_InvalidBitmap, reporter) {
SkDynamicMemoryWStream stream;
sk_sp<SkDocument> document(SkDocument::MakePDF(&stream));
if (!document) {
return;
}
SkCanvas* canvas = document->beginPage(100, 100);
canvas->drawBitmap(SkBitmap(), 0, 0);

View File

@ -5,10 +5,11 @@
* found in the LICENSE file.
*/
#include "SkDocument.h"
#include "SkCanvas.h"
#include "SkImageGenerator.h"
#include "SkData.h"
#include "SkDocument.h"
#include "SkImageGenerator.h"
#include "SkJpegInfo.h"
#include "SkStream.h"
#include "Resources.h"
@ -54,8 +55,9 @@ static sk_sp<SkData> load_resource(
* directly embedded into the PDF (without re-encoding) when that
* makes sense.
*/
DEF_TEST(PDFJpegEmbedTest, r) {
const char test[] = "PDFJpegEmbedTest";
DEF_TEST(SkPDF_JpegEmbedTest, r) {
REQUIRE_PDF_DOCUMENT(SkPDF_JpegEmbedTest, r);
const char test[] = "SkPDF_JpegEmbedTest";
sk_sp<SkData> mandrillData(load_resource(r, test, "mandrill_512_q075.jpg"));
sk_sp<SkData> cmykData(load_resource(r, test, "CMYK.jpg"));
if (!mandrillData || !cmykData) {
@ -111,9 +113,7 @@ DEF_TEST(PDFJpegEmbedTest, r) {
REPORTER_ASSERT(r, !is_subset_of(cmykData.get(), pdfData.get()));
}
#include "SkJpegInfo.h"
DEF_TEST(JpegIdentification, r) {
DEF_TEST(SkPDF_JpegIdentification, r) {
static struct {
const char* path;
bool isJfif;
@ -144,4 +144,100 @@ DEF_TEST(JpegIdentification, r) {
INFOF(r, "\nJpegIdentification: %s [%d x %d]\n", kTests[i].path,
info.fSize.width(), info.fSize.height());
}
// Test several malformed jpegs.
SkJFIFInfo info;
{
static const char goodJpeg[] =
"\377\330\377\340\0\20JFIF\0\1\1\0\0\1\0\1\0\0\377\333\0C\0\10\6\6\7"
"\6\5\10\7\7\7\t\t\10\n\14\24\r\14\13\13\14\31\22\23\17\24\35\32\37"
"\36\35\32\34\34 $.' \",#\34\34(7),01444\37'9=82<.342\377\333\0C\1\t"
"\t\t\14\13\14\30\r\r\0302!\34!222222222222222222222222222222222222"
"22222222222222\377\300\0\21\10\2\0\2\0\3\1\"\0\2\21\1\3\21\001";
size_t goodJpegLength = 177;
auto data = SkData::MakeWithoutCopy(goodJpeg, goodJpegLength);
REPORTER_ASSERT(r, SkIsJFIF(data.get(), &info));
REPORTER_ASSERT(r, info.fSize == SkISize::Make(512, 512));
REPORTER_ASSERT(r, info.fType == SkJFIFInfo::kYCbCr);
// Not long enough to read first (SOI) segment marker.
data = SkData::MakeWithoutCopy(goodJpeg, 1);
REPORTER_ASSERT(r, !SkIsJFIF(data.get(), &info));
// Not long enough to read second segment (APP0) marker.
data = SkData::MakeWithoutCopy(goodJpeg, 3);
REPORTER_ASSERT(r, !SkIsJFIF(data.get(), &info));
// Not long enough to read second segment's length.
data = SkData::MakeWithoutCopy(goodJpeg, 5);
REPORTER_ASSERT(r, !SkIsJFIF(data.get(), &info));
// APP0 segment is truncated.
data = SkData::MakeWithoutCopy(goodJpeg, 7);
REPORTER_ASSERT(r, !SkIsJFIF(data.get(), &info));
// Missing SOF segment.
data = SkData::MakeWithoutCopy(goodJpeg, 89);
REPORTER_ASSERT(r, !SkIsJFIF(data.get(), &info));
}
{
// JFIF tag missing.
static const char jpeg[] =
"\377\330\377\340\0\20JFIX\0\1\1\0\0\1\0\1\0\0\377\333\0C\0\10\6\6\7"
"\6\5\10\7\7\7\t\t\10\n\14\24\r\14\13\13\14\31\22\23\17\24\35\32\37"
"\36\35\32\34\34 $.' \",#\34\34(7),01444\37'9=82<.342\377\333\0C\1\t"
"\t\t\14\13\14\30\r\r\0302!\34!222222222222222222222222222222222222"
"22222222222222\377\300\0\21\10\2\0\2\0\3\1\"\0\2\21\1\3\21\001";
size_t jpegLength = 177;
auto data = SkData::MakeWithoutCopy(jpeg, jpegLength);
REPORTER_ASSERT(r, !SkIsJFIF(data.get(), &info));
}
{
// APP0 segment short (byte 6 changed).
static const char jpeg[] =
"\377\330\377\340\0\5JFIF\0\1\1\0\0\1\0\1\0\0\377\333\0C\0\10\6\6\7"
"\6\5\10\7\7\7\t\t\10\n\14\24\r\14\13\13\14\31\22\23\17\24\35\32\37"
"\36\35\32\34\34 $.' \",#\34\34(7),01444\37'9=82<.342\377\333\0C\1\t"
"\t\t\14\13\14\30\r\r\0302!\34!222222222222222222222222222222222222"
"22222222222222\377\300\0\21\10\2\0\2\0\3\1\"\0\2\21\1\3\21\001";
size_t jpegLength = 177;
auto data = SkData::MakeWithoutCopy(jpeg, jpegLength);
REPORTER_ASSERT(r, !SkIsJFIF(data.get(), &info));
}
{
// SOF segment short. ('\21' replaced with '\5')
static const char jpeg[] =
"\377\330\377\340\0\20JFIF\0\1\1\0\0\1\0\1\0\0\377\333\0C\0\10\6\6\7"
"\6\5\10\7\7\7\t\t\10\n\14\24\r\14\13\13\14\31\22\23\17\24\35\32\37"
"\36\35\32\34\34 $.' \",#\34\34(7),01444\37'9=82<.342\377\333\0C\1\t"
"\t\t\14\13\14\30\r\r\0302!\34!222222222222222222222222222222222222"
"22222222222222\377\300\0\5\10\2\0\2\0\3\1\"\0\2\21\1\3\21\001";
size_t jpegLength = 177;
auto data = SkData::MakeWithoutCopy(jpeg, jpegLength);
REPORTER_ASSERT(r, !SkIsJFIF(data.get(), &info));
}
{
// Unsupported 12-bit components. ('\10' replaced with '\14')
static const char jpeg[] =
"\377\330\377\340\0\20JFIF\0\1\1\0\0\1\0\1\0\0\377\333\0C\0\10\6\6\7"
"\6\5\10\7\7\7\t\t\10\n\14\24\r\14\13\13\14\31\22\23\17\24\35\32\37"
"\36\35\32\34\34 $.' \",#\34\34(7),01444\37'9=82<.342\377\333\0C\1\t"
"\t\t\14\13\14\30\r\r\0302!\34!222222222222222222222222222222222222"
"22222222222222\377\300\0\21\14\2\0\2\0\3\1\"\0\2\21\1\3\21\001";
size_t jpegLength = 177;
auto data = SkData::MakeWithoutCopy(jpeg, jpegLength);
REPORTER_ASSERT(r, !SkIsJFIF(data.get(), &info));
}
{
// Two color channels. ('\3' replaced with '\2')
static const char jpeg[] =
"\377\330\377\340\0\20JFIF\0\1\1\0\0\1\0\1\0\0\377\333\0C\0\10\6\6\7"
"\6\5\10\7\7\7\t\t\10\n\14\24\r\14\13\13\14\31\22\23\17\24\35\32\37"
"\36\35\32\34\34 $.' \",#\34\34(7),01444\37'9=82<.342\377\333\0C\1\t"
"\t\t\14\13\14\30\r\r\0302!\34!222222222222222222222222222222222222"
"22222222222222\377\300\0\21\10\2\0\2\0\2\1\"\0\2\21\1\3\21\001";
size_t jpegLength = 177;
auto data = SkData::MakeWithoutCopy(jpeg, jpegLength);
REPORTER_ASSERT(r, !SkIsJFIF(data.get(), &info));
}
}

View File

@ -334,7 +334,7 @@ static void TestPDFDict(skiatest::Reporter* reporter) {
assert_eq(reporter, result, "<</Type /DType\n/n1 1 0 R>>");
}
DEF_TEST(PDFPrimitives, reporter) {
DEF_TEST(SkPDF_Primitives, reporter) {
TestPDFUnion(reporter);
TestPDFArray(reporter);
TestPDFDict(reporter);
@ -389,7 +389,8 @@ void DummyImageFilter::toString(SkString* str) const {
// Check that PDF rendering of image filters successfully falls back to
// CPU rasterization.
DEF_TEST(PDFImageFilter, reporter) {
DEF_TEST(SkPDF_ImageFilter, reporter) {
REQUIRE_PDF_DOCUMENT(SkPDF_ImageFilter, reporter);
SkDynamicMemoryWStream stream;
sk_sp<SkDocument> doc(SkDocument::MakePDF(&stream));
SkCanvas* canvas = doc->beginPage(100.0f, 100.0f);
@ -409,7 +410,7 @@ DEF_TEST(PDFImageFilter, reporter) {
// Check that PDF rendering of image filters successfully falls back to
// CPU rasterization.
DEF_TEST(PDFFontCanEmbedTypeface, reporter) {
DEF_TEST(SkPDF_FontCanEmbedTypeface, reporter) {
SkPDFCanon canon;
const char resource[] = "fonts/Roboto2-Regular_NoEmbed.ttf";
@ -453,7 +454,7 @@ static void check_pdf_scalar_serialization(
}
// Test SkPDFUtils::AppendScalar for accuracy.
DEF_TEST(PDFPrimitives_Scalar, reporter) {
DEF_TEST(SkPDF_Primitives_Scalar, reporter) {
SkRandom random(0x5EED);
int iterationCount = 512;
while (iterationCount-- > 0) {
@ -474,7 +475,7 @@ DEF_TEST(PDFPrimitives_Scalar, reporter) {
}
// Test SkPDFUtils:: for accuracy.
DEF_TEST(PDFPrimitives_Color, reporter) {
DEF_TEST(SkPDF_Primitives_Color, reporter) {
char buffer[5];
for (int i = 0; i < 256; ++i) {
size_t len = SkPDFUtils::ColorToDecimal(i, buffer);