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