Home | History | Annotate | Download | only in tests
      1 
      2 /*
      3  * Copyright 2010 The Android Open Source Project
      4  *
      5  * Use of this source code is governed by a BSD-style license that can be
      6  * found in the LICENSE file.
      7  */
      8 
      9 
     10 #include <string>
     11 
     12 #include "Test.h"
     13 #include "SkData.h"
     14 #include "SkFlate.h"
     15 #include "SkPDFCatalog.h"
     16 #include "SkPDFStream.h"
     17 #include "SkPDFTypes.h"
     18 #include "SkScalar.h"
     19 #include "SkStream.h"
     20 #include "SkTypes.h"
     21 
     22 class SkPDFTestDict : public SkPDFDict {
     23 public:
     24     void getResources(SkTDArray<SkPDFObject*>* resourceList) {
     25         resourceList->setReserve(resourceList->count() + fResources.count());
     26         for (int i = 0; i < fResources.count(); i++) {
     27             resourceList->push(fResources[i]);
     28             fResources[i]->ref();
     29         }
     30     }
     31 
     32     void addResource(SkPDFObject* object) {
     33         fResources.append(1, &object);
     34     }
     35 
     36 private:
     37     SkTDArray<SkPDFObject*> fResources;
     38 };
     39 
     40 static bool stream_equals(const SkDynamicMemoryWStream& stream, size_t offset,
     41                           const void* buffer, size_t len) {
     42     SkAutoDataUnref data(stream.copyToData());
     43     if (offset + len > data.size()) {
     44         return false;
     45     }
     46     return memcmp(data.bytes() + offset, buffer, len) == 0;
     47 }
     48 
     49 static void CheckObjectOutput(skiatest::Reporter* reporter, SkPDFObject* obj,
     50                               const char* expectedData, size_t expectedSize,
     51                               bool indirect, bool compression) {
     52     SkPDFDocument::Flags docFlags = (SkPDFDocument::Flags) 0;
     53     if (!compression) {
     54         docFlags = SkTBitOr(docFlags, SkPDFDocument::kNoCompression_Flag);
     55     }
     56     SkPDFCatalog catalog(docFlags);
     57     size_t directSize = obj->getOutputSize(&catalog, false);
     58     REPORTER_ASSERT(reporter, directSize == expectedSize);
     59 
     60     SkDynamicMemoryWStream buffer;
     61     obj->emit(&buffer, &catalog, false);
     62     REPORTER_ASSERT(reporter, directSize == buffer.getOffset());
     63     REPORTER_ASSERT(reporter, stream_equals(buffer, 0, expectedData,
     64                                             directSize));
     65 
     66     if (indirect) {
     67         // Indirect output.
     68         static char header[] = "1 0 obj\n";
     69         static size_t headerLen = strlen(header);
     70         static char footer[] = "\nendobj\n";
     71         static size_t footerLen = strlen(footer);
     72 
     73         catalog.addObject(obj, false);
     74 
     75         size_t indirectSize = obj->getOutputSize(&catalog, true);
     76         REPORTER_ASSERT(reporter,
     77                         indirectSize == directSize + headerLen + footerLen);
     78 
     79         buffer.reset();
     80         obj->emit(&buffer, &catalog, true);
     81         REPORTER_ASSERT(reporter, indirectSize == buffer.getOffset());
     82         REPORTER_ASSERT(reporter, stream_equals(buffer, 0, header, headerLen));
     83         REPORTER_ASSERT(reporter, stream_equals(buffer, headerLen, expectedData,
     84                                                 directSize));
     85         REPORTER_ASSERT(reporter, stream_equals(buffer, headerLen + directSize,
     86                                                 footer, footerLen));
     87     }
     88 }
     89 
     90 static void SimpleCheckObjectOutput(skiatest::Reporter* reporter,
     91                                     SkPDFObject* obj,
     92                                     const std::string& expectedResult) {
     93     CheckObjectOutput(reporter, obj, expectedResult.c_str(),
     94                       expectedResult.length(), true, false);
     95 }
     96 
     97 static void TestPDFStream(skiatest::Reporter* reporter) {
     98     char streamBytes[] = "Test\nFoo\tBar";
     99     SkRefPtr<SkMemoryStream> streamData = new SkMemoryStream(
    100         streamBytes, strlen(streamBytes), true);
    101     streamData->unref();  // SkRefPtr and new both took a reference.
    102     SkRefPtr<SkPDFStream> stream = new SkPDFStream(streamData.get());
    103     stream->unref();  // SkRefPtr and new both took a reference.
    104     SimpleCheckObjectOutput(
    105         reporter, stream.get(),
    106         "<</Length 12\n>> stream\nTest\nFoo\tBar\nendstream");
    107     stream->insert("Attribute", new SkPDFInt(42))->unref();
    108     SimpleCheckObjectOutput(reporter, stream.get(),
    109                             "<</Length 12\n/Attribute 42\n>> stream\n"
    110                                 "Test\nFoo\tBar\nendstream");
    111 
    112     if (SkFlate::HaveFlate()) {
    113         char streamBytes2[] = "This is a longer string, so that compression "
    114                               "can do something with it. With shorter strings, "
    115                               "the short circuit logic cuts in and we end up "
    116                               "with an uncompressed string.";
    117         SkAutoDataUnref streamData2(SkData::NewWithCopy(streamBytes2,
    118                                                         strlen(streamBytes2)));
    119         SkRefPtr<SkPDFStream> stream = new SkPDFStream(streamData2.get());
    120         stream->unref();  // SkRefPtr and new both took a reference.
    121 
    122         SkDynamicMemoryWStream compressedByteStream;
    123         SkFlate::Deflate(streamData2.get(), &compressedByteStream);
    124         SkAutoDataUnref compressedData(compressedByteStream.copyToData());
    125 
    126         // Check first without compression.
    127         SkDynamicMemoryWStream expectedResult1;
    128         expectedResult1.writeText("<</Length 167\n>> stream\n");
    129         expectedResult1.writeText(streamBytes2);
    130         expectedResult1.writeText("\nendstream");
    131         SkAutoDataUnref expectedResultData1(expectedResult1.copyToData());
    132         CheckObjectOutput(reporter, stream.get(),
    133                           (const char*) expectedResultData1.data(),
    134                           expectedResultData1.size(), true, false);
    135 
    136         // Then again with compression.
    137         SkDynamicMemoryWStream expectedResult2;
    138         expectedResult2.writeText("<</Filter /FlateDecode\n/Length 116\n"
    139                                  ">> stream\n");
    140         expectedResult2.write(compressedData.data(), compressedData.size());
    141         expectedResult2.writeText("\nendstream");
    142         SkAutoDataUnref expectedResultData2(expectedResult2.copyToData());
    143         CheckObjectOutput(reporter, stream.get(),
    144                           (const char*) expectedResultData2.data(),
    145                           expectedResultData2.size(), true, true);
    146     }
    147 }
    148 
    149 static void TestCatalog(skiatest::Reporter* reporter) {
    150     SkPDFCatalog catalog((SkPDFDocument::Flags)0);
    151     SkRefPtr<SkPDFInt> int1 = new SkPDFInt(1);
    152     int1->unref();  // SkRefPtr and new both took a reference.
    153     SkRefPtr<SkPDFInt> int2 = new SkPDFInt(2);
    154     int2->unref();  // SkRefPtr and new both took a reference.
    155     SkRefPtr<SkPDFInt> int3 = new SkPDFInt(3);
    156     int3->unref();  // SkRefPtr and new both took a reference.
    157     SkRefPtr<SkPDFInt> int1Again(int1.get());
    158 
    159     catalog.addObject(int1.get(), false);
    160     catalog.addObject(int2.get(), false);
    161     catalog.addObject(int3.get(), false);
    162 
    163     REPORTER_ASSERT(reporter, catalog.getObjectNumberSize(int1.get()) == 3);
    164     REPORTER_ASSERT(reporter, catalog.getObjectNumberSize(int2.get()) == 3);
    165     REPORTER_ASSERT(reporter, catalog.getObjectNumberSize(int3.get()) == 3);
    166 
    167     SkDynamicMemoryWStream buffer;
    168     catalog.emitObjectNumber(&buffer, int1.get());
    169     catalog.emitObjectNumber(&buffer, int2.get());
    170     catalog.emitObjectNumber(&buffer, int3.get());
    171     catalog.emitObjectNumber(&buffer, int1Again.get());
    172     char expectedResult[] = "1 02 03 01 0";
    173     REPORTER_ASSERT(reporter, stream_equals(buffer, 0, expectedResult,
    174                                             strlen(expectedResult)));
    175 }
    176 
    177 static void TestObjectRef(skiatest::Reporter* reporter) {
    178     SkRefPtr<SkPDFInt> int1 = new SkPDFInt(1);
    179     int1->unref();  // SkRefPtr and new both took a reference.
    180     SkRefPtr<SkPDFInt> int2 = new SkPDFInt(2);
    181     int2->unref();  // SkRefPtr and new both took a reference.
    182     SkRefPtr<SkPDFObjRef> int2ref = new SkPDFObjRef(int2.get());
    183     int2ref->unref();  // SkRefPtr and new both took a reference.
    184 
    185     SkPDFCatalog catalog((SkPDFDocument::Flags)0);
    186     catalog.addObject(int1.get(), false);
    187     catalog.addObject(int2.get(), false);
    188     REPORTER_ASSERT(reporter, catalog.getObjectNumberSize(int1.get()) == 3);
    189     REPORTER_ASSERT(reporter, catalog.getObjectNumberSize(int2.get()) == 3);
    190 
    191     char expectedResult[] = "2 0 R";
    192     SkDynamicMemoryWStream buffer;
    193     int2ref->emitObject(&buffer, &catalog, false);
    194     REPORTER_ASSERT(reporter, buffer.getOffset() == strlen(expectedResult));
    195     REPORTER_ASSERT(reporter, stream_equals(buffer, 0, expectedResult,
    196                                             buffer.getOffset()));
    197 }
    198 
    199 static void TestSubstitute(skiatest::Reporter* reporter) {
    200     SkRefPtr<SkPDFTestDict> proxy = new SkPDFTestDict();
    201     proxy->unref();  // SkRefPtr and new both took a reference.
    202     SkRefPtr<SkPDFTestDict> stub = new SkPDFTestDict();
    203     stub->unref();  // SkRefPtr and new both took a reference.
    204     SkRefPtr<SkPDFInt> int33 = new SkPDFInt(33);
    205     int33->unref();  // SkRefPtr and new both took a reference.
    206     SkRefPtr<SkPDFDict> stubResource = new SkPDFDict();
    207     stubResource->unref();  // SkRefPtr and new both took a reference.
    208     SkRefPtr<SkPDFInt> int44 = new SkPDFInt(44);
    209     int44->unref();  // SkRefPtr and new both took a reference.
    210 
    211     stub->insert("Value", int33.get());
    212     stubResource->insert("InnerValue", int44.get());
    213     stub->addResource(stubResource.get());
    214 
    215     SkPDFCatalog catalog((SkPDFDocument::Flags)0);
    216     catalog.addObject(proxy.get(), false);
    217     catalog.setSubstitute(proxy.get(), stub.get());
    218 
    219     SkDynamicMemoryWStream buffer;
    220     proxy->emit(&buffer, &catalog, false);
    221     catalog.emitSubstituteResources(&buffer, false);
    222 
    223     char objectResult[] = "2 0 obj\n<</Value 33\n>>\nendobj\n";
    224     REPORTER_ASSERT(
    225         reporter,
    226         catalog.setFileOffset(proxy.get(), 0) == strlen(objectResult));
    227 
    228     char expectedResult[] =
    229         "<</Value 33\n>>1 0 obj\n<</InnerValue 44\n>>\nendobj\n";
    230     REPORTER_ASSERT(reporter, buffer.getOffset() == strlen(expectedResult));
    231     REPORTER_ASSERT(reporter, stream_equals(buffer, 0, expectedResult,
    232                                             buffer.getOffset()));
    233 }
    234 
    235 static void TestPDFPrimitives(skiatest::Reporter* reporter) {
    236     SkRefPtr<SkPDFInt> int42 = new SkPDFInt(42);
    237     int42->unref();  // SkRefPtr and new both took a reference.
    238     SimpleCheckObjectOutput(reporter, int42.get(), "42");
    239 
    240     SkRefPtr<SkPDFScalar> realHalf = new SkPDFScalar(SK_ScalarHalf);
    241     realHalf->unref();  // SkRefPtr and new both took a reference.
    242     SimpleCheckObjectOutput(reporter, realHalf.get(), "0.5");
    243 
    244 #if defined(SK_SCALAR_IS_FLOAT)
    245     SkRefPtr<SkPDFScalar> bigScalar = new SkPDFScalar(110999.75);
    246     bigScalar->unref();  // SkRefPtr and new both took a reference.
    247 #if !defined(SK_ALLOW_LARGE_PDF_SCALARS)
    248     SimpleCheckObjectOutput(reporter, bigScalar.get(), "111000");
    249 #else
    250     SimpleCheckObjectOutput(reporter, bigScalar.get(), "110999.75");
    251 
    252     SkRefPtr<SkPDFScalar> biggerScalar = new SkPDFScalar(50000000.1);
    253     biggerScalar->unref();  // SkRefPtr and new both took a reference.
    254     SimpleCheckObjectOutput(reporter, biggerScalar.get(), "50000000");
    255 
    256     SkRefPtr<SkPDFScalar> smallestScalar = new SkPDFScalar(1.0/65536);
    257     smallestScalar->unref();  // SkRefPtr and new both took a reference.
    258     SimpleCheckObjectOutput(reporter, smallestScalar.get(), "0.00001526");
    259 #endif
    260 #endif
    261 
    262     SkRefPtr<SkPDFString> stringSimple = new SkPDFString("test ) string ( foo");
    263     stringSimple->unref();  // SkRefPtr and new both took a reference.
    264     SimpleCheckObjectOutput(reporter, stringSimple.get(),
    265                             "(test \\) string \\( foo)");
    266     SkRefPtr<SkPDFString> stringComplex =
    267         new SkPDFString("\ttest ) string ( foo");
    268     stringComplex->unref();  // SkRefPtr and new both took a reference.
    269     SimpleCheckObjectOutput(reporter, stringComplex.get(),
    270                             "<0974657374202920737472696E67202820666F6F>");
    271 
    272     SkRefPtr<SkPDFName> name = new SkPDFName("Test name\twith#tab");
    273     name->unref();  // SkRefPtr and new both took a reference.
    274     const char expectedResult[] = "/Test#20name#09with#23tab";
    275     CheckObjectOutput(reporter, name.get(), expectedResult,
    276                       strlen(expectedResult), false, false);
    277 
    278     SkRefPtr<SkPDFArray> array = new SkPDFArray;
    279     array->unref();  // SkRefPtr and new both took a reference.
    280     SimpleCheckObjectOutput(reporter, array.get(), "[]");
    281     array->append(int42.get());
    282     SimpleCheckObjectOutput(reporter, array.get(), "[42]");
    283     array->append(realHalf.get());
    284     SimpleCheckObjectOutput(reporter, array.get(), "[42 0.5]");
    285     SkRefPtr<SkPDFInt> int0 = new SkPDFInt(0);
    286     int0->unref();  // SkRefPtr and new both took a reference.
    287     array->append(int0.get());
    288     SimpleCheckObjectOutput(reporter, array.get(), "[42 0.5 0]");
    289     SkRefPtr<SkPDFInt> int1 = new SkPDFInt(1);
    290     int1->unref();  // SkRefPtr and new both took a reference.
    291     array->setAt(0, int1.get());
    292     SimpleCheckObjectOutput(reporter, array.get(), "[1 0.5 0]");
    293 
    294     SkRefPtr<SkPDFDict> dict = new SkPDFDict;
    295     dict->unref();  // SkRefPtr and new both took a reference.
    296     SimpleCheckObjectOutput(reporter, dict.get(), "<<>>");
    297     SkRefPtr<SkPDFName> n1 = new SkPDFName("n1");
    298     n1->unref();  // SkRefPtr and new both took a reference.
    299     dict->insert(n1.get(), int42.get());
    300     SimpleCheckObjectOutput(reporter, dict.get(), "<</n1 42\n>>");
    301     SkRefPtr<SkPDFName> n2 = new SkPDFName("n2");
    302     n2->unref();  // SkRefPtr and new both took a reference.
    303     SkRefPtr<SkPDFName> n3 = new SkPDFName("n3");
    304     n3->unref();  // SkRefPtr and new both took a reference.
    305     dict->insert(n2.get(), realHalf.get());
    306     dict->insert(n3.get(), array.get());
    307     SimpleCheckObjectOutput(reporter, dict.get(),
    308                             "<</n1 42\n/n2 0.5\n/n3 [1 0.5 0]\n>>");
    309 
    310     TestPDFStream(reporter);
    311 
    312     TestCatalog(reporter);
    313 
    314     TestObjectRef(reporter);
    315 
    316     TestSubstitute(reporter);
    317 }
    318 
    319 #include "TestClassDef.h"
    320 DEFINE_TESTCLASS("PDFPrimitives", PDFPrimitivesTestClass, TestPDFPrimitives)
    321