Home | History | Annotate | Download | only in pdf
      1 /*
      2  * Copyright 2011 Google Inc.
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #include "SkData.h"
      9 #include "SkDeflate.h"
     10 #include "SkMakeUnique.h"
     11 #include "SkPDFTypes.h"
     12 #include "SkPDFUtils.h"
     13 #include "SkStream.h"
     14 #include "SkStreamPriv.h"
     15 
     16 ////////////////////////////////////////////////////////////////////////////////
     17 
     18 SkString* pun(char* x) { return reinterpret_cast<SkString*>(x); }
     19 const SkString* pun(const char* x) {
     20     return reinterpret_cast<const SkString*>(x);
     21 }
     22 
     23 SkPDFUnion::SkPDFUnion(Type t) : fType(t) {}
     24 
     25 SkPDFUnion::~SkPDFUnion() {
     26     switch (fType) {
     27         case Type::kNameSkS:
     28         case Type::kStringSkS:
     29             pun(fSkString)->~SkString();
     30             return;
     31         case Type::kObjRef:
     32         case Type::kObject:
     33             SkASSERT(fObject);
     34             fObject->unref();
     35             return;
     36         default:
     37             return;
     38     }
     39 }
     40 
     41 SkPDFUnion& SkPDFUnion::operator=(SkPDFUnion&& other) {
     42     if (this != &other) {
     43         this->~SkPDFUnion();
     44         new (this) SkPDFUnion(std::move(other));
     45     }
     46     return *this;
     47 }
     48 
     49 SkPDFUnion::SkPDFUnion(SkPDFUnion&& other) {
     50     SkASSERT(this != &other);
     51     memcpy(this, &other, sizeof(*this));
     52     other.fType = Type::kDestroyed;
     53 }
     54 
     55 #if 0
     56 SkPDFUnion SkPDFUnion::copy() const {
     57     SkPDFUnion u(fType);
     58     memcpy(&u, this, sizeof(u));
     59     switch (fType) {
     60         case Type::kNameSkS:
     61         case Type::kStringSkS:
     62             new (pun(u.fSkString)) SkString(*pun(fSkString));
     63             return u;
     64         case Type::kObjRef:
     65         case Type::kObject:
     66             SkRef(u.fObject);
     67             return u;
     68         default:
     69             return u;
     70     }
     71 }
     72 SkPDFUnion& SkPDFUnion::operator=(const SkPDFUnion& other) {
     73     return *this = other.copy();
     74 }
     75 SkPDFUnion::SkPDFUnion(const SkPDFUnion& other) {
     76     *this = other.copy();
     77 }
     78 #endif
     79 
     80 bool SkPDFUnion::isName() const {
     81     return Type::kName == fType || Type::kNameSkS == fType;
     82 }
     83 
     84 #ifdef SK_DEBUG
     85 // Most names need no escaping.  Such names are handled as static
     86 // const strings.
     87 bool is_valid_name(const char* n) {
     88     static const char kControlChars[] = "/%()<>[]{}";
     89     while (*n) {
     90         if (*n < '!' || *n > '~' || strchr(kControlChars, *n)) {
     91             return false;
     92         }
     93         ++n;
     94     }
     95     return true;
     96 }
     97 #endif  // SK_DEBUG
     98 
     99 // Given an arbitrary string, write it as a valid name (not including
    100 // leading slash).
    101 static void write_name_escaped(SkWStream* o, const char* name) {
    102     static const char kToEscape[] = "#/%()<>[]{}";
    103     for (const uint8_t* n = reinterpret_cast<const uint8_t*>(name); *n; ++n) {
    104         uint8_t v = *n;
    105         if (v < '!' || v > '~' || strchr(kToEscape, v)) {
    106             char buffer[3] = {'#',
    107                               SkHexadecimalDigits::gUpper[v >> 4],
    108                               SkHexadecimalDigits::gUpper[v & 0xF]};
    109             o->write(buffer, sizeof(buffer));
    110         } else {
    111             o->write(n, 1);
    112         }
    113     }
    114 }
    115 
    116 void SkPDFUnion::emitObject(SkWStream* stream,
    117                             const SkPDFObjNumMap& objNumMap) const {
    118     switch (fType) {
    119         case Type::kInt:
    120             stream->writeDecAsText(fIntValue);
    121             return;
    122         case Type::kColorComponent:
    123             SkPDFUtils::AppendColorComponent(SkToU8(fIntValue), stream);
    124             return;
    125         case Type::kBool:
    126             stream->writeText(fBoolValue ? "true" : "false");
    127             return;
    128         case Type::kScalar:
    129             SkPDFUtils::AppendScalar(fScalarValue, stream);
    130             return;
    131         case Type::kName:
    132             stream->writeText("/");
    133             SkASSERT(is_valid_name(fStaticString));
    134             stream->writeText(fStaticString);
    135             return;
    136         case Type::kString:
    137             SkASSERT(fStaticString);
    138             SkPDFUtils::WriteString(stream, fStaticString,
    139                                     strlen(fStaticString));
    140             return;
    141         case Type::kNameSkS:
    142             stream->writeText("/");
    143             write_name_escaped(stream, pun(fSkString)->c_str());
    144             return;
    145         case Type::kStringSkS:
    146             SkPDFUtils::WriteString(stream, pun(fSkString)->c_str(),
    147                                     pun(fSkString)->size());
    148             return;
    149         case Type::kObjRef:
    150             stream->writeDecAsText(objNumMap.getObjectNumber(fObject));
    151             stream->writeText(" 0 R");  // Generation number is always 0.
    152             return;
    153         case Type::kObject:
    154             fObject->emitObject(stream, objNumMap);
    155             return;
    156         default:
    157             SkDEBUGFAIL("SkPDFUnion::emitObject with bad type");
    158     }
    159 }
    160 
    161 void SkPDFUnion::addResources(SkPDFObjNumMap* objNumMap) const {
    162     switch (fType) {
    163         case Type::kInt:
    164         case Type::kColorComponent:
    165         case Type::kBool:
    166         case Type::kScalar:
    167         case Type::kName:
    168         case Type::kString:
    169         case Type::kNameSkS:
    170         case Type::kStringSkS:
    171             return;  // These have no resources.
    172         case Type::kObjRef:
    173             objNumMap->addObjectRecursively(fObject);
    174             return;
    175         case Type::kObject:
    176             fObject->addResources(objNumMap);
    177             return;
    178         default:
    179             SkDEBUGFAIL("SkPDFUnion::addResources with bad type");
    180     }
    181 }
    182 
    183 SkPDFUnion SkPDFUnion::Int(int32_t value) {
    184     SkPDFUnion u(Type::kInt);
    185     u.fIntValue = value;
    186     return u;
    187 }
    188 
    189 SkPDFUnion SkPDFUnion::ColorComponent(uint8_t value) {
    190     SkPDFUnion u(Type::kColorComponent);
    191     u.fIntValue = value;
    192     return u;
    193 }
    194 
    195 SkPDFUnion SkPDFUnion::Bool(bool value) {
    196     SkPDFUnion u(Type::kBool);
    197     u.fBoolValue = value;
    198     return u;
    199 }
    200 
    201 SkPDFUnion SkPDFUnion::Scalar(SkScalar value) {
    202     SkPDFUnion u(Type::kScalar);
    203     u.fScalarValue = value;
    204     return u;
    205 }
    206 
    207 SkPDFUnion SkPDFUnion::Name(const char* value) {
    208     SkPDFUnion u(Type::kName);
    209     SkASSERT(value);
    210     SkASSERT(is_valid_name(value));
    211     u.fStaticString = value;
    212     return u;
    213 }
    214 
    215 SkPDFUnion SkPDFUnion::String(const char* value) {
    216     SkPDFUnion u(Type::kString);
    217     SkASSERT(value);
    218     u.fStaticString = value;
    219     return u;
    220 }
    221 
    222 SkPDFUnion SkPDFUnion::Name(const SkString& s) {
    223     SkPDFUnion u(Type::kNameSkS);
    224     new (pun(u.fSkString)) SkString(s);
    225     return u;
    226 }
    227 
    228 SkPDFUnion SkPDFUnion::String(const SkString& s) {
    229     SkPDFUnion u(Type::kStringSkS);
    230     new (pun(u.fSkString)) SkString(s);
    231     return u;
    232 }
    233 
    234 SkPDFUnion SkPDFUnion::ObjRef(sk_sp<SkPDFObject> objSp) {
    235     SkPDFUnion u(Type::kObjRef);
    236     SkASSERT(objSp.get());
    237     u.fObject = objSp.release();  // take ownership into union{}
    238     return u;
    239 }
    240 
    241 SkPDFUnion SkPDFUnion::Object(sk_sp<SkPDFObject> objSp) {
    242     SkPDFUnion u(Type::kObject);
    243     SkASSERT(objSp.get());
    244     u.fObject = objSp.release();  // take ownership into union{}
    245     return u;
    246 }
    247 
    248 ////////////////////////////////////////////////////////////////////////////////
    249 
    250 #if 0  // Enable if needed.
    251 void SkPDFAtom::emitObject(SkWStream* stream,
    252                            const SkPDFObjNumMap& objNumMap) const {
    253     fValue.emitObject(stream, objNumMap);
    254 }
    255 void SkPDFAtom::addResources(SkPDFObjNumMap* map) const {
    256     fValue.addResources(map);
    257 }
    258 #endif  // 0
    259 
    260 ////////////////////////////////////////////////////////////////////////////////
    261 
    262 SkPDFArray::SkPDFArray() { SkDEBUGCODE(fDumped = false;) }
    263 
    264 SkPDFArray::~SkPDFArray() { this->drop(); }
    265 
    266 void SkPDFArray::drop() {
    267     fValues.reset();
    268     SkDEBUGCODE(fDumped = true;)
    269 }
    270 
    271 int SkPDFArray::size() const { return fValues.count(); }
    272 
    273 void SkPDFArray::reserve(int length) {
    274     fValues.reserve(length);
    275 }
    276 
    277 void SkPDFArray::emitObject(SkWStream* stream,
    278                             const SkPDFObjNumMap& objNumMap) const {
    279     SkASSERT(!fDumped);
    280     stream->writeText("[");
    281     for (int i = 0; i < fValues.count(); i++) {
    282         fValues[i].emitObject(stream, objNumMap);
    283         if (i + 1 < fValues.count()) {
    284             stream->writeText(" ");
    285         }
    286     }
    287     stream->writeText("]");
    288 }
    289 
    290 void SkPDFArray::addResources(SkPDFObjNumMap* catalog) const {
    291     SkASSERT(!fDumped);
    292     for (const SkPDFUnion& value : fValues) {
    293         value.addResources(catalog);
    294     }
    295 }
    296 
    297 void SkPDFArray::append(SkPDFUnion&& value) {
    298     fValues.emplace_back(std::move(value));
    299 }
    300 
    301 void SkPDFArray::appendInt(int32_t value) {
    302     this->append(SkPDFUnion::Int(value));
    303 }
    304 
    305 void SkPDFArray::appendColorComponent(uint8_t value) {
    306     this->append(SkPDFUnion::ColorComponent(value));
    307 }
    308 
    309 void SkPDFArray::appendBool(bool value) {
    310     this->append(SkPDFUnion::Bool(value));
    311 }
    312 
    313 void SkPDFArray::appendScalar(SkScalar value) {
    314     this->append(SkPDFUnion::Scalar(value));
    315 }
    316 
    317 void SkPDFArray::appendName(const char name[]) {
    318     this->append(SkPDFUnion::Name(SkString(name)));
    319 }
    320 
    321 void SkPDFArray::appendName(const SkString& name) {
    322     this->append(SkPDFUnion::Name(name));
    323 }
    324 
    325 void SkPDFArray::appendString(const SkString& value) {
    326     this->append(SkPDFUnion::String(value));
    327 }
    328 
    329 void SkPDFArray::appendString(const char value[]) {
    330     this->append(SkPDFUnion::String(value));
    331 }
    332 
    333 void SkPDFArray::appendObject(sk_sp<SkPDFObject> objSp) {
    334     this->append(SkPDFUnion::Object(std::move(objSp)));
    335 }
    336 
    337 void SkPDFArray::appendObjRef(sk_sp<SkPDFObject> objSp) {
    338     this->append(SkPDFUnion::ObjRef(std::move(objSp)));
    339 }
    340 
    341 ///////////////////////////////////////////////////////////////////////////////
    342 
    343 SkPDFDict::~SkPDFDict() { this->drop(); }
    344 
    345 void SkPDFDict::drop() {
    346     fRecords.reset();
    347     SkDEBUGCODE(fDumped = true;)
    348 }
    349 
    350 SkPDFDict::SkPDFDict(const char type[]) {
    351     SkDEBUGCODE(fDumped = false;)
    352     if (type) {
    353         this->insertName("Type", type);
    354     }
    355 }
    356 
    357 void SkPDFDict::emitObject(SkWStream* stream,
    358                            const SkPDFObjNumMap& objNumMap) const {
    359     stream->writeText("<<");
    360     this->emitAll(stream, objNumMap);
    361     stream->writeText(">>");
    362 }
    363 
    364 void SkPDFDict::emitAll(SkWStream* stream,
    365                         const SkPDFObjNumMap& objNumMap) const {
    366     SkASSERT(!fDumped);
    367     for (int i = 0; i < fRecords.count(); i++) {
    368         fRecords[i].fKey.emitObject(stream, objNumMap);
    369         stream->writeText(" ");
    370         fRecords[i].fValue.emitObject(stream, objNumMap);
    371         if (i + 1 < fRecords.count()) {
    372             stream->writeText("\n");
    373         }
    374     }
    375 }
    376 
    377 void SkPDFDict::addResources(SkPDFObjNumMap* catalog) const {
    378     SkASSERT(!fDumped);
    379     for (int i = 0; i < fRecords.count(); i++) {
    380         fRecords[i].fKey.addResources(catalog);
    381         fRecords[i].fValue.addResources(catalog);
    382     }
    383 }
    384 
    385 int SkPDFDict::size() const { return fRecords.count(); }
    386 
    387 void SkPDFDict::reserve(int n) {
    388     fRecords.reserve(n);
    389 }
    390 
    391 void SkPDFDict::insertObjRef(const char key[], sk_sp<SkPDFObject> objSp) {
    392     fRecords.emplace_back(Record{SkPDFUnion::Name(key), SkPDFUnion::ObjRef(std::move(objSp))});
    393 }
    394 
    395 void SkPDFDict::insertObjRef(const SkString& key, sk_sp<SkPDFObject> objSp) {
    396     fRecords.emplace_back(Record{SkPDFUnion::Name(key), SkPDFUnion::ObjRef(std::move(objSp))});
    397 }
    398 
    399 void SkPDFDict::insertObject(const char key[], sk_sp<SkPDFObject> objSp) {
    400     fRecords.emplace_back(Record{SkPDFUnion::Name(key), SkPDFUnion::Object(std::move(objSp))});
    401 }
    402 void SkPDFDict::insertObject(const SkString& key, sk_sp<SkPDFObject> objSp) {
    403     fRecords.emplace_back(Record{SkPDFUnion::Name(key), SkPDFUnion::Object(std::move(objSp))});
    404 }
    405 
    406 void SkPDFDict::insertBool(const char key[], bool value) {
    407     fRecords.emplace_back(Record{SkPDFUnion::Name(key), SkPDFUnion::Bool(value)});
    408 }
    409 
    410 void SkPDFDict::insertInt(const char key[], int32_t value) {
    411     fRecords.emplace_back(Record{SkPDFUnion::Name(key), SkPDFUnion::Int(value)});
    412 }
    413 
    414 void SkPDFDict::insertInt(const char key[], size_t value) {
    415     this->insertInt(key, SkToS32(value));
    416 }
    417 
    418 void SkPDFDict::insertScalar(const char key[], SkScalar value) {
    419     fRecords.emplace_back(Record{SkPDFUnion::Name(key), SkPDFUnion::Scalar(value)});
    420 }
    421 
    422 void SkPDFDict::insertName(const char key[], const char name[]) {
    423     fRecords.emplace_back(Record{SkPDFUnion::Name(key), SkPDFUnion::Name(name)});
    424 }
    425 
    426 void SkPDFDict::insertName(const char key[], const SkString& name) {
    427     fRecords.emplace_back(Record{SkPDFUnion::Name(key), SkPDFUnion::Name(name)});
    428 }
    429 
    430 void SkPDFDict::insertString(const char key[], const char value[]) {
    431     fRecords.emplace_back(Record{SkPDFUnion::Name(key), SkPDFUnion::String(value)});
    432 }
    433 
    434 void SkPDFDict::insertString(const char key[], const SkString& value) {
    435     fRecords.emplace_back(Record{SkPDFUnion::Name(key), SkPDFUnion::String(value)});
    436 }
    437 
    438 ////////////////////////////////////////////////////////////////////////////////
    439 
    440 SkPDFSharedStream::SkPDFSharedStream(std::unique_ptr<SkStreamAsset> data)
    441     : fAsset(std::move(data)) {
    442     SkASSERT(fAsset);
    443 }
    444 
    445 SkPDFSharedStream::~SkPDFSharedStream() { this->drop(); }
    446 
    447 void SkPDFSharedStream::drop() {
    448     fAsset = nullptr;;
    449     fDict.drop();
    450 }
    451 
    452 #ifdef SK_PDF_LESS_COMPRESSION
    453 void SkPDFSharedStream::emitObject(
    454         SkWStream* stream,
    455         const SkPDFObjNumMap& objNumMap) const {
    456     SkASSERT(fAsset);
    457     std::unique_ptr<SkStreamAsset> dup(fAsset->duplicate());
    458     SkASSERT(dup && dup->hasLength());
    459     size_t length = dup->getLength();
    460     stream->writeText("<<");
    461     fDict.emitAll(stream, objNumMap);
    462     stream->writeText("\n");
    463     SkPDFUnion::Name("Length").emitObject(stream, objNumMap);
    464     stream->writeText(" ");
    465     SkPDFUnion::Int(length).emitObject(stream, objNumMap);
    466     stream->writeText("\n>>stream\n");
    467     SkStreamCopy(stream, dup.get());
    468     stream->writeText("\nendstream");
    469 }
    470 #else
    471 void SkPDFSharedStream::emitObject(
    472         SkWStream* stream,
    473         const SkPDFObjNumMap& objNumMap) const {
    474     SkASSERT(fAsset);
    475     SkDynamicMemoryWStream buffer;
    476     SkDeflateWStream deflateWStream(&buffer);
    477     // Since emitObject is const, this function doesn't change the dictionary.
    478     std::unique_ptr<SkStreamAsset> dup(fAsset->duplicate());  // Cheap copy
    479     SkASSERT(dup);
    480     SkStreamCopy(&deflateWStream, dup.get());
    481     deflateWStream.finalize();
    482     size_t length = buffer.bytesWritten();
    483     stream->writeText("<<");
    484     fDict.emitAll(stream, objNumMap);
    485     stream->writeText("\n");
    486     SkPDFUnion::Name("Length").emitObject(stream, objNumMap);
    487     stream->writeText(" ");
    488     SkPDFUnion::Int(length).emitObject(stream, objNumMap);
    489     stream->writeText("\n");
    490     SkPDFUnion::Name("Filter").emitObject(stream, objNumMap);
    491     stream->writeText(" ");
    492     SkPDFUnion::Name("FlateDecode").emitObject(stream, objNumMap);
    493     stream->writeText(">>");
    494     stream->writeText(" stream\n");
    495     buffer.writeToAndReset(stream);
    496     stream->writeText("\nendstream");
    497 }
    498 #endif
    499 
    500 void SkPDFSharedStream::addResources(
    501         SkPDFObjNumMap* catalog) const {
    502     SkASSERT(fAsset);
    503     fDict.addResources(catalog);
    504 }
    505 
    506 
    507 ////////////////////////////////////////////////////////////////////////////////
    508 
    509 SkPDFStream:: SkPDFStream(sk_sp<SkData> data) {
    510     this->setData(skstd::make_unique<SkMemoryStream>(std::move(data)));
    511 }
    512 
    513 SkPDFStream::SkPDFStream(std::unique_ptr<SkStreamAsset> stream) {
    514     this->setData(std::move(stream));
    515 }
    516 
    517 SkPDFStream::SkPDFStream() {}
    518 
    519 SkPDFStream::~SkPDFStream() {}
    520 
    521 void SkPDFStream::addResources(SkPDFObjNumMap* catalog) const {
    522     SkASSERT(fCompressedData);
    523     fDict.addResources(catalog);
    524 }
    525 
    526 void SkPDFStream::drop() {
    527     fCompressedData.reset(nullptr);
    528     fDict.drop();
    529 }
    530 
    531 void SkPDFStream::emitObject(SkWStream* stream,
    532                              const SkPDFObjNumMap& objNumMap) const {
    533     SkASSERT(fCompressedData);
    534     fDict.emitObject(stream, objNumMap);
    535     // duplicate (a cheap operation) preserves const on fCompressedData.
    536     std::unique_ptr<SkStreamAsset> dup(fCompressedData->duplicate());
    537     SkASSERT(dup);
    538     SkASSERT(dup->hasLength());
    539     stream->writeText(" stream\n");
    540     stream->writeStream(dup.get(), dup->getLength());
    541     stream->writeText("\nendstream");
    542 }
    543 
    544 void SkPDFStream::setData(std::unique_ptr<SkStreamAsset> stream) {
    545     SkASSERT(!fCompressedData);  // Only call this function once.
    546     SkASSERT(stream);
    547     // Code assumes that the stream starts at the beginning.
    548 
    549     #ifdef SK_PDF_LESS_COMPRESSION
    550     fCompressedData = std::move(stream);
    551     SkASSERT(fCompressedData && fCompressedData->hasLength());
    552     fDict.insertInt("Length", fCompressedData->getLength());
    553     #else
    554 
    555     SkASSERT(stream->hasLength());
    556     SkDynamicMemoryWStream compressedData;
    557     SkDeflateWStream deflateWStream(&compressedData);
    558     if (stream->getLength() > 0) {
    559         SkStreamCopy(&deflateWStream, stream.get());
    560     }
    561     deflateWStream.finalize();
    562     size_t compressedLength = compressedData.bytesWritten();
    563     size_t originalLength = stream->getLength();
    564 
    565     if (originalLength <= compressedLength + strlen("/Filter_/FlateDecode_")) {
    566         SkAssertResult(stream->rewind());
    567         fCompressedData = std::move(stream);
    568         fDict.insertInt("Length", originalLength);
    569         return;
    570     }
    571     fCompressedData = compressedData.detachAsStream();
    572     fDict.insertName("Filter", "FlateDecode");
    573     fDict.insertInt("Length", compressedLength);
    574     #endif
    575 }
    576 
    577 ////////////////////////////////////////////////////////////////////////////////
    578 
    579 bool SkPDFObjNumMap::addObject(SkPDFObject* obj) {
    580     if (fObjectNumbers.find(obj)) {
    581         return false;
    582     }
    583     fObjectNumbers.set(obj, fObjectNumbers.count() + 1);
    584     fObjects.emplace_back(sk_ref_sp(obj));
    585     return true;
    586 }
    587 
    588 void SkPDFObjNumMap::addObjectRecursively(SkPDFObject* obj) {
    589     if (obj && this->addObject(obj)) {
    590         obj->addResources(this);
    591     }
    592 }
    593 
    594 int32_t SkPDFObjNumMap::getObjectNumber(SkPDFObject* obj) const {
    595     int32_t* objectNumberFound = fObjectNumbers.find(obj);
    596     SkASSERT(objectNumberFound);
    597     return *objectNumberFound;
    598 }
    599 
    600 #ifdef SK_PDF_IMAGE_STATS
    601 SkAtomic<int> gDrawImageCalls(0);
    602 SkAtomic<int> gJpegImageObjects(0);
    603 SkAtomic<int> gRegularImageObjects(0);
    604 
    605 void SkPDFImageDumpStats() {
    606     SkDebugf("\ntotal PDF drawImage/drawBitmap calls: %d\n"
    607              "total PDF jpeg images: %d\n"
    608              "total PDF regular images: %d\n",
    609              gDrawImageCalls.load(),
    610              gJpegImageObjects.load(),
    611              gRegularImageObjects.load());
    612 }
    613 #endif // SK_PDF_IMAGE_STATS
    614