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 
     10 #include "SkPDFCatalog.h"
     11 #include "SkPDFTypes.h"
     12 #include "SkStream.h"
     13 
     14 #ifdef SK_BUILD_FOR_WIN
     15     #define SNPRINTF    _snprintf
     16 #else
     17     #define SNPRINTF    snprintf
     18 #endif
     19 
     20 ///////////////////////////////////////////////////////////////////////////////
     21 
     22 void SkPDFObject::emit(SkWStream* stream, SkPDFCatalog* catalog,
     23                        bool indirect) {
     24     SkPDFObject* realObject = catalog->getSubstituteObject(this);
     25     return realObject->emitObject(stream, catalog, indirect);
     26 }
     27 
     28 size_t SkPDFObject::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
     29     SkDynamicMemoryWStream buffer;
     30     emit(&buffer, catalog, indirect);
     31     return buffer.getOffset();
     32 }
     33 
     34 void SkPDFObject::getResources(const SkTSet<SkPDFObject*>& knownResourceObjects,
     35                                SkTSet<SkPDFObject*>* newResourceObjects) {}
     36 
     37 void SkPDFObject::emitIndirectObject(SkWStream* stream, SkPDFCatalog* catalog) {
     38     catalog->emitObjectNumber(stream, this);
     39     stream->writeText(" obj\n");
     40     emit(stream, catalog, false);
     41     stream->writeText("\nendobj\n");
     42 }
     43 
     44 size_t SkPDFObject::getIndirectOutputSize(SkPDFCatalog* catalog) {
     45     return catalog->getObjectNumberSize(this) + strlen(" obj\n") +
     46         this->getOutputSize(catalog, false) + strlen("\nendobj\n");
     47 }
     48 
     49 void SkPDFObject::AddResourceHelper(SkPDFObject* resource,
     50                                     SkTDArray<SkPDFObject*>* list) {
     51     list->push(resource);
     52     resource->ref();
     53 }
     54 
     55 void SkPDFObject::GetResourcesHelper(
     56         const SkTDArray<SkPDFObject*>* resources,
     57         const SkTSet<SkPDFObject*>& knownResourceObjects,
     58         SkTSet<SkPDFObject*>* newResourceObjects) {
     59     if (resources->count()) {
     60         newResourceObjects->setReserve(
     61             newResourceObjects->count() + resources->count());
     62         for (int i = 0; i < resources->count(); i++) {
     63             if (!knownResourceObjects.contains((*resources)[i]) &&
     64                     !newResourceObjects->contains((*resources)[i])) {
     65                 newResourceObjects->add((*resources)[i]);
     66                 (*resources)[i]->ref();
     67                 (*resources)[i]->getResources(knownResourceObjects,
     68                                               newResourceObjects);
     69             }
     70         }
     71     }
     72 }
     73 
     74 SkPDFObjRef::SkPDFObjRef(SkPDFObject* obj) : fObj(obj) {
     75     SkSafeRef(obj);
     76 }
     77 
     78 SkPDFObjRef::~SkPDFObjRef() {}
     79 
     80 void SkPDFObjRef::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
     81                              bool indirect) {
     82     SkASSERT(!indirect);
     83     catalog->emitObjectNumber(stream, fObj.get());
     84     stream->writeText(" R");
     85 }
     86 
     87 size_t SkPDFObjRef::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
     88     SkASSERT(!indirect);
     89     return catalog->getObjectNumberSize(fObj.get()) + strlen(" R");
     90 }
     91 
     92 SkPDFInt::SkPDFInt(int32_t value) : fValue(value) {}
     93 SkPDFInt::~SkPDFInt() {}
     94 
     95 void SkPDFInt::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
     96                           bool indirect) {
     97     if (indirect) {
     98         return emitIndirectObject(stream, catalog);
     99     }
    100     stream->writeDecAsText(fValue);
    101 }
    102 
    103 SkPDFBool::SkPDFBool(bool value) : fValue(value) {}
    104 SkPDFBool::~SkPDFBool() {}
    105 
    106 void SkPDFBool::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
    107                           bool indirect) {
    108     SkASSERT(!indirect);
    109     if (fValue) {
    110         stream->writeText("true");
    111     } else {
    112         stream->writeText("false");
    113     }
    114 }
    115 
    116 size_t SkPDFBool::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
    117     SkASSERT(!indirect);
    118     if (fValue) {
    119         return strlen("true");
    120     }
    121     return strlen("false");
    122 }
    123 
    124 SkPDFScalar::SkPDFScalar(SkScalar value) : fValue(value) {}
    125 SkPDFScalar::~SkPDFScalar() {}
    126 
    127 void SkPDFScalar::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
    128                              bool indirect) {
    129     if (indirect) {
    130         return emitIndirectObject(stream, catalog);
    131     }
    132 
    133     Append(fValue, stream);
    134 }
    135 
    136 // static
    137 void SkPDFScalar::Append(SkScalar value, SkWStream* stream) {
    138     // The range of reals in PDF/A is the same as SkFixed: +/- 32,767 and
    139     // +/- 1/65,536 (though integers can range from 2^31 - 1 to -2^31).
    140     // When using floats that are outside the whole value range, we can use
    141     // integers instead.
    142 
    143 #if !defined(SK_ALLOW_LARGE_PDF_SCALARS)
    144     if (value > 32767 || value < -32767) {
    145         stream->writeDecAsText(SkScalarRoundToInt(value));
    146         return;
    147     }
    148 
    149     char buffer[SkStrAppendScalar_MaxSize];
    150     char* end = SkStrAppendFixed(buffer, SkScalarToFixed(value));
    151     stream->write(buffer, end - buffer);
    152     return;
    153 #endif  // !SK_ALLOW_LARGE_PDF_SCALARS
    154 
    155 #if defined(SK_ALLOW_LARGE_PDF_SCALARS)
    156     // Floats have 24bits of significance, so anything outside that range is
    157     // no more precise than an int. (Plus PDF doesn't support scientific
    158     // notation, so this clamps to SK_Max/MinS32).
    159     if (value > (1 << 24) || value < -(1 << 24)) {
    160         stream->writeDecAsText(value);
    161         return;
    162     }
    163     // Continue to enforce the PDF limits for small floats.
    164     if (value < 1.0f/65536 && value > -1.0f/65536) {
    165         stream->writeDecAsText(0);
    166         return;
    167     }
    168     // SkStrAppendFloat might still use scientific notation, so use snprintf
    169     // directly..
    170     static const int kFloat_MaxSize = 19;
    171     char buffer[kFloat_MaxSize];
    172     int len = SNPRINTF(buffer, kFloat_MaxSize, "%#.8f", value);
    173     // %f always prints trailing 0s, so strip them.
    174     for (; buffer[len - 1] == '0' && len > 0; len--) {
    175         buffer[len - 1] = '\0';
    176     }
    177     if (buffer[len - 1] == '.') {
    178         buffer[len - 1] = '\0';
    179     }
    180     stream->writeText(buffer);
    181     return;
    182 #endif  // SK_ALLOW_LARGE_PDF_SCALARS
    183 }
    184 
    185 SkPDFString::SkPDFString(const char value[])
    186     : fValue(FormatString(value, strlen(value))) {
    187 }
    188 
    189 SkPDFString::SkPDFString(const SkString& value)
    190     : fValue(FormatString(value.c_str(), value.size())) {
    191 }
    192 
    193 SkPDFString::SkPDFString(const uint16_t* value, size_t len, bool wideChars)
    194     : fValue(FormatString(value, len, wideChars)) {
    195 }
    196 
    197 SkPDFString::~SkPDFString() {}
    198 
    199 void SkPDFString::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
    200                              bool indirect) {
    201     if (indirect)
    202         return emitIndirectObject(stream, catalog);
    203     stream->write(fValue.c_str(), fValue.size());
    204 }
    205 
    206 size_t SkPDFString::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
    207     if (indirect)
    208         return getIndirectOutputSize(catalog);
    209     return fValue.size();
    210 }
    211 
    212 // static
    213 SkString SkPDFString::FormatString(const char* input, size_t len) {
    214     return DoFormatString(input, len, false, false);
    215 }
    216 
    217 SkString SkPDFString::FormatString(const uint16_t* input, size_t len,
    218                                    bool wideChars) {
    219     return DoFormatString(input, len, true, wideChars);
    220 }
    221 
    222 // static
    223 SkString SkPDFString::DoFormatString(const void* input, size_t len,
    224                                      bool wideInput, bool wideOutput) {
    225     SkASSERT(len <= kMaxLen);
    226     const uint16_t* win = (const uint16_t*) input;
    227     const char* cin = (const char*) input;
    228 
    229     if (wideOutput) {
    230         SkASSERT(wideInput);
    231         SkString result;
    232         result.append("<");
    233         for (size_t i = 0; i < len; i++) {
    234             result.appendHex(win[i], 4);
    235         }
    236         result.append(">");
    237         return result;
    238     }
    239 
    240     // 7-bit clean is a heuristic to decide what string format to use;
    241     // a 7-bit clean string should require little escaping.
    242     bool sevenBitClean = true;
    243     for (size_t i = 0; i < len; i++) {
    244         SkASSERT(!wideInput || !(win[i] & ~0xFF));
    245         char val = wideInput ? win[i] : cin[i];
    246         if (val > '~' || val < ' ') {
    247             sevenBitClean = false;
    248             break;
    249         }
    250     }
    251 
    252     SkString result;
    253     if (sevenBitClean) {
    254         result.append("(");
    255         for (size_t i = 0; i < len; i++) {
    256             SkASSERT(!wideInput || !(win[i] & ~0xFF));
    257             char val = wideInput ? win[i] : cin[i];
    258             if (val == '\\' || val == '(' || val == ')') {
    259                 result.append("\\");
    260             }
    261             result.append(&val, 1);
    262         }
    263         result.append(")");
    264     } else {
    265         result.append("<");
    266         for (size_t i = 0; i < len; i++) {
    267             SkASSERT(!wideInput || !(win[i] & ~0xFF));
    268             unsigned char val = wideInput ? win[i] : cin[i];
    269             result.appendHex(val, 2);
    270         }
    271         result.append(">");
    272     }
    273 
    274     return result;
    275 }
    276 
    277 SkPDFName::SkPDFName(const char name[]) : fValue(FormatName(SkString(name))) {}
    278 SkPDFName::SkPDFName(const SkString& name) : fValue(FormatName(name)) {}
    279 SkPDFName::~SkPDFName() {}
    280 
    281 bool SkPDFName::operator==(const SkPDFName& b) const {
    282     return fValue == b.fValue;
    283 }
    284 
    285 void SkPDFName::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
    286                            bool indirect) {
    287     SkASSERT(!indirect);
    288     stream->write(fValue.c_str(), fValue.size());
    289 }
    290 
    291 size_t SkPDFName::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
    292     SkASSERT(!indirect);
    293     return fValue.size();
    294 }
    295 
    296 // static
    297 SkString SkPDFName::FormatName(const SkString& input) {
    298     SkASSERT(input.size() <= kMaxLen);
    299     // TODO(vandebo) If more escaping is needed, improve the linear scan.
    300     static const char escaped[] = "#/%()<>[]{}";
    301 
    302     SkString result("/");
    303     for (size_t i = 0; i < input.size(); i++) {
    304         if (input[i] & 0x80 || input[i] < '!' || strchr(escaped, input[i])) {
    305             result.append("#");
    306             // Mask with 0xFF to avoid sign extension. i.e. #FFFFFF81
    307             result.appendHex(input[i] & 0xFF, 2);
    308         } else {
    309             result.append(input.c_str() + i, 1);
    310         }
    311     }
    312 
    313     return result;
    314 }
    315 
    316 SkPDFArray::SkPDFArray() {}
    317 SkPDFArray::~SkPDFArray() {
    318     fValue.unrefAll();
    319 }
    320 
    321 void SkPDFArray::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
    322                             bool indirect) {
    323     if (indirect) {
    324         return emitIndirectObject(stream, catalog);
    325     }
    326 
    327     stream->writeText("[");
    328     for (int i = 0; i < fValue.count(); i++) {
    329         fValue[i]->emit(stream, catalog, false);
    330         if (i + 1 < fValue.count()) {
    331             stream->writeText(" ");
    332         }
    333     }
    334     stream->writeText("]");
    335 }
    336 
    337 size_t SkPDFArray::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
    338     if (indirect) {
    339         return getIndirectOutputSize(catalog);
    340     }
    341 
    342     size_t result = strlen("[]");
    343     if (fValue.count()) {
    344         result += fValue.count() - 1;
    345     }
    346     for (int i = 0; i < fValue.count(); i++) {
    347         result += fValue[i]->getOutputSize(catalog, false);
    348     }
    349     return result;
    350 }
    351 
    352 void SkPDFArray::reserve(int length) {
    353     SkASSERT(length <= kMaxLen);
    354     fValue.setReserve(length);
    355 }
    356 
    357 SkPDFObject* SkPDFArray::setAt(int offset, SkPDFObject* value) {
    358     SkASSERT(offset < fValue.count());
    359     value->ref();
    360     fValue[offset]->unref();
    361     fValue[offset] = value;
    362     return value;
    363 }
    364 
    365 SkPDFObject* SkPDFArray::append(SkPDFObject* value) {
    366     SkASSERT(fValue.count() < kMaxLen);
    367     value->ref();
    368     fValue.push(value);
    369     return value;
    370 }
    371 
    372 void SkPDFArray::appendInt(int32_t value) {
    373     SkASSERT(fValue.count() < kMaxLen);
    374     fValue.push(new SkPDFInt(value));
    375 }
    376 
    377 void SkPDFArray::appendScalar(SkScalar value) {
    378     SkASSERT(fValue.count() < kMaxLen);
    379     fValue.push(new SkPDFScalar(value));
    380 }
    381 
    382 void SkPDFArray::appendName(const char name[]) {
    383     SkASSERT(fValue.count() < kMaxLen);
    384     fValue.push(new SkPDFName(name));
    385 }
    386 
    387 ///////////////////////////////////////////////////////////////////////////////
    388 
    389 SkPDFDict::SkPDFDict() {}
    390 
    391 SkPDFDict::SkPDFDict(const char type[]) {
    392     insertName("Type", type);
    393 }
    394 
    395 SkPDFDict::~SkPDFDict() {
    396     clear();
    397 }
    398 
    399 int SkPDFDict::size() const {
    400     SkAutoMutexAcquire lock(fMutex);
    401     return fValue.count();
    402 }
    403 
    404 
    405 void SkPDFDict::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
    406                            bool indirect) {
    407     if (indirect) {
    408         return emitIndirectObject(stream, catalog);
    409     }
    410 
    411     SkAutoMutexAcquire lock(fMutex); // If another thread triggers a
    412                                      // resize while this thread is in
    413                                      // the for-loop, we can be left
    414                                      // with a bad fValue[i] reference.
    415     stream->writeText("<<");
    416     for (int i = 0; i < fValue.count(); i++) {
    417         SkASSERT(fValue[i].key);
    418         SkASSERT(fValue[i].value);
    419         fValue[i].key->emitObject(stream, catalog, false);
    420         stream->writeText(" ");
    421         fValue[i].value->emit(stream, catalog, false);
    422         stream->writeText("\n");
    423     }
    424     stream->writeText(">>");
    425 }
    426 
    427 size_t SkPDFDict::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
    428     if (indirect) {
    429         return getIndirectOutputSize(catalog);
    430     }
    431 
    432     SkAutoMutexAcquire lock(fMutex); // If another thread triggers a
    433                                      // resize while this thread is in
    434                                      // the for-loop, we can be left
    435                                      // with a bad fValue[i] reference.
    436     size_t result = strlen("<<>>") + (fValue.count() * 2);
    437     for (int i = 0; i < fValue.count(); i++) {
    438         SkASSERT(fValue[i].key);
    439         SkASSERT(fValue[i].value);
    440         result += fValue[i].key->getOutputSize(catalog, false);
    441         result += fValue[i].value->getOutputSize(catalog, false);
    442     }
    443     return result;
    444 }
    445 
    446 SkPDFObject*  SkPDFDict::append(SkPDFName* key, SkPDFObject* value) {
    447     SkASSERT(key);
    448     SkASSERT(value);
    449     SkAutoMutexAcquire lock(fMutex); // If the SkTDArray resizes while
    450                                      // two threads access array, one
    451                                      // is left with a bad pointer.
    452     *(fValue.append()) = Rec(key, value);
    453     return value;
    454 }
    455 
    456 SkPDFObject* SkPDFDict::insert(SkPDFName* key, SkPDFObject* value) {
    457     return this->append(SkRef(key), SkRef(value));
    458 }
    459 
    460 SkPDFObject* SkPDFDict::insert(const char key[], SkPDFObject* value) {
    461     return this->append(new SkPDFName(key), SkRef(value));
    462 }
    463 
    464 void SkPDFDict::insertInt(const char key[], int32_t value) {
    465     (void)this->append(new SkPDFName(key), new SkPDFInt(value));
    466 }
    467 
    468 void SkPDFDict::insertScalar(const char key[], SkScalar value) {
    469     (void)this->append(new SkPDFName(key), new SkPDFScalar(value));
    470 }
    471 
    472 void SkPDFDict::insertName(const char key[], const char name[]) {
    473     (void)this->append(new SkPDFName(key), new SkPDFName(name));
    474 }
    475 
    476 void SkPDFDict::clear() {
    477     SkAutoMutexAcquire lock(fMutex);
    478     for (int i = 0; i < fValue.count(); i++) {
    479         SkASSERT(fValue[i].key);
    480         SkASSERT(fValue[i].value);
    481         fValue[i].key->unref();
    482         fValue[i].value->unref();
    483     }
    484     fValue.reset();
    485 }
    486 
    487 void SkPDFDict::remove(const char key[]) {
    488     SkASSERT(key);
    489     SkPDFName name(key);
    490     SkAutoMutexAcquire lock(fMutex);
    491     for (int i = 0; i < fValue.count(); i++) {
    492         SkASSERT(fValue[i].key);
    493         if (*(fValue[i].key) == name) {
    494             fValue[i].key->unref();
    495             SkASSERT(fValue[i].value);
    496             fValue[i].value->unref();
    497             fValue.removeShuffle(i);
    498             return;
    499         }
    500     }
    501 }
    502 
    503 void SkPDFDict::mergeFrom(const SkPDFDict& other) {
    504     SkAutoMutexAcquire lockOther(other.fMutex);
    505     SkTDArray<Rec> copy(other.fValue);
    506     lockOther.release();  // Do not hold both mutexes at once.
    507 
    508     SkAutoMutexAcquire lock(fMutex);
    509     for (int i = 0; i < copy.count(); i++) {
    510         *(fValue.append()) = Rec(SkRef(copy[i].key), SkRef(copy[i].value));
    511     }
    512 }
    513