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 
    144 #if defined(SK_SCALAR_IS_FIXED)
    145     stream->writeScalarAsText(value);
    146     return;
    147 #endif  // SK_SCALAR_IS_FIXED
    148 
    149 #if !defined(SK_ALLOW_LARGE_PDF_SCALARS)
    150     if (value > 32767 || value < -32767) {
    151         stream->writeDecAsText(SkScalarRound(value));
    152         return;
    153     }
    154 
    155     char buffer[SkStrAppendScalar_MaxSize];
    156     char* end = SkStrAppendFixed(buffer, SkScalarToFixed(value));
    157     stream->write(buffer, end - buffer);
    158     return;
    159 #endif  // !SK_ALLOW_LARGE_PDF_SCALARS
    160 
    161 #if defined(SK_SCALAR_IS_FLOAT) && defined(SK_ALLOW_LARGE_PDF_SCALARS)
    162     // Floats have 24bits of significance, so anything outside that range is
    163     // no more precise than an int. (Plus PDF doesn't support scientific
    164     // notation, so this clamps to SK_Max/MinS32).
    165     if (value > (1 << 24) || value < -(1 << 24)) {
    166         stream->writeDecAsText(value);
    167         return;
    168     }
    169     // Continue to enforce the PDF limits for small floats.
    170     if (value < 1.0f/65536 && value > -1.0f/65536) {
    171         stream->writeDecAsText(0);
    172         return;
    173     }
    174     // SkStrAppendFloat might still use scientific notation, so use snprintf
    175     // directly..
    176     static const int kFloat_MaxSize = 19;
    177     char buffer[kFloat_MaxSize];
    178     int len = SNPRINTF(buffer, kFloat_MaxSize, "%#.8f", value);
    179     // %f always prints trailing 0s, so strip them.
    180     for (; buffer[len - 1] == '0' && len > 0; len--) {
    181         buffer[len - 1] = '\0';
    182     }
    183     if (buffer[len - 1] == '.') {
    184         buffer[len - 1] = '\0';
    185     }
    186     stream->writeText(buffer);
    187     return;
    188 #endif  // SK_SCALAR_IS_FLOAT && SK_ALLOW_LARGE_PDF_SCALARS
    189 }
    190 
    191 SkPDFString::SkPDFString(const char value[])
    192     : fValue(FormatString(value, strlen(value))) {
    193 }
    194 
    195 SkPDFString::SkPDFString(const SkString& value)
    196     : fValue(FormatString(value.c_str(), value.size())) {
    197 }
    198 
    199 SkPDFString::SkPDFString(const uint16_t* value, size_t len, bool wideChars)
    200     : fValue(FormatString(value, len, wideChars)) {
    201 }
    202 
    203 SkPDFString::~SkPDFString() {}
    204 
    205 void SkPDFString::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
    206                              bool indirect) {
    207     if (indirect)
    208         return emitIndirectObject(stream, catalog);
    209     stream->write(fValue.c_str(), fValue.size());
    210 }
    211 
    212 size_t SkPDFString::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
    213     if (indirect)
    214         return getIndirectOutputSize(catalog);
    215     return fValue.size();
    216 }
    217 
    218 // static
    219 SkString SkPDFString::FormatString(const char* input, size_t len) {
    220     return DoFormatString(input, len, false, false);
    221 }
    222 
    223 SkString SkPDFString::FormatString(const uint16_t* input, size_t len,
    224                                    bool wideChars) {
    225     return DoFormatString(input, len, true, wideChars);
    226 }
    227 
    228 // static
    229 SkString SkPDFString::DoFormatString(const void* input, size_t len,
    230                                      bool wideInput, bool wideOutput) {
    231     SkASSERT(len <= kMaxLen);
    232     const uint16_t* win = (const uint16_t*) input;
    233     const char* cin = (const char*) input;
    234 
    235     if (wideOutput) {
    236         SkASSERT(wideInput);
    237         SkString result;
    238         result.append("<");
    239         for (size_t i = 0; i < len; i++) {
    240             result.appendHex(win[i], 4);
    241         }
    242         result.append(">");
    243         return result;
    244     }
    245 
    246     // 7-bit clean is a heuristic to decide what string format to use;
    247     // a 7-bit clean string should require little escaping.
    248     bool sevenBitClean = true;
    249     for (size_t i = 0; i < len; i++) {
    250         SkASSERT(!wideInput || !(win[i] & ~0xFF));
    251         char val = wideInput ? win[i] : cin[i];
    252         if (val > '~' || val < ' ') {
    253             sevenBitClean = false;
    254             break;
    255         }
    256     }
    257 
    258     SkString result;
    259     if (sevenBitClean) {
    260         result.append("(");
    261         for (size_t i = 0; i < len; i++) {
    262             SkASSERT(!wideInput || !(win[i] & ~0xFF));
    263             char val = wideInput ? win[i] : cin[i];
    264             if (val == '\\' || val == '(' || val == ')') {
    265                 result.append("\\");
    266             }
    267             result.append(&val, 1);
    268         }
    269         result.append(")");
    270     } else {
    271         result.append("<");
    272         for (size_t i = 0; i < len; i++) {
    273             SkASSERT(!wideInput || !(win[i] & ~0xFF));
    274             unsigned char val = wideInput ? win[i] : cin[i];
    275             result.appendHex(val, 2);
    276         }
    277         result.append(">");
    278     }
    279 
    280     return result;
    281 }
    282 
    283 SkPDFName::SkPDFName(const char name[]) : fValue(FormatName(SkString(name))) {}
    284 SkPDFName::SkPDFName(const SkString& name) : fValue(FormatName(name)) {}
    285 SkPDFName::~SkPDFName() {}
    286 
    287 bool SkPDFName::operator==(const SkPDFName& b) const {
    288     return fValue == b.fValue;
    289 }
    290 
    291 void SkPDFName::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
    292                            bool indirect) {
    293     SkASSERT(!indirect);
    294     stream->write(fValue.c_str(), fValue.size());
    295 }
    296 
    297 size_t SkPDFName::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
    298     SkASSERT(!indirect);
    299     return fValue.size();
    300 }
    301 
    302 // static
    303 SkString SkPDFName::FormatName(const SkString& input) {
    304     SkASSERT(input.size() <= kMaxLen);
    305     // TODO(vandebo) If more escaping is needed, improve the linear scan.
    306     static const char escaped[] = "#/%()<>[]{}";
    307 
    308     SkString result("/");
    309     for (size_t i = 0; i < input.size(); i++) {
    310         if (input[i] & 0x80 || input[i] < '!' || strchr(escaped, input[i])) {
    311             result.append("#");
    312             // Mask with 0xFF to avoid sign extension. i.e. #FFFFFF81
    313             result.appendHex(input[i] & 0xFF, 2);
    314         } else {
    315             result.append(input.c_str() + i, 1);
    316         }
    317     }
    318 
    319     return result;
    320 }
    321 
    322 SkPDFArray::SkPDFArray() {}
    323 SkPDFArray::~SkPDFArray() {
    324     fValue.unrefAll();
    325 }
    326 
    327 void SkPDFArray::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
    328                             bool indirect) {
    329     if (indirect) {
    330         return emitIndirectObject(stream, catalog);
    331     }
    332 
    333     stream->writeText("[");
    334     for (int i = 0; i < fValue.count(); i++) {
    335         fValue[i]->emit(stream, catalog, false);
    336         if (i + 1 < fValue.count()) {
    337             stream->writeText(" ");
    338         }
    339     }
    340     stream->writeText("]");
    341 }
    342 
    343 size_t SkPDFArray::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
    344     if (indirect) {
    345         return getIndirectOutputSize(catalog);
    346     }
    347 
    348     size_t result = strlen("[]");
    349     if (fValue.count()) {
    350         result += fValue.count() - 1;
    351     }
    352     for (int i = 0; i < fValue.count(); i++) {
    353         result += fValue[i]->getOutputSize(catalog, false);
    354     }
    355     return result;
    356 }
    357 
    358 void SkPDFArray::reserve(int length) {
    359     SkASSERT(length <= kMaxLen);
    360     fValue.setReserve(length);
    361 }
    362 
    363 SkPDFObject* SkPDFArray::setAt(int offset, SkPDFObject* value) {
    364     SkASSERT(offset < fValue.count());
    365     value->ref();
    366     fValue[offset]->unref();
    367     fValue[offset] = value;
    368     return value;
    369 }
    370 
    371 SkPDFObject* SkPDFArray::append(SkPDFObject* value) {
    372     SkASSERT(fValue.count() < kMaxLen);
    373     value->ref();
    374     fValue.push(value);
    375     return value;
    376 }
    377 
    378 void SkPDFArray::appendInt(int32_t value) {
    379     SkASSERT(fValue.count() < kMaxLen);
    380     fValue.push(new SkPDFInt(value));
    381 }
    382 
    383 void SkPDFArray::appendScalar(SkScalar value) {
    384     SkASSERT(fValue.count() < kMaxLen);
    385     fValue.push(new SkPDFScalar(value));
    386 }
    387 
    388 void SkPDFArray::appendName(const char name[]) {
    389     SkASSERT(fValue.count() < kMaxLen);
    390     fValue.push(new SkPDFName(name));
    391 }
    392 
    393 ///////////////////////////////////////////////////////////////////////////////
    394 
    395 SkPDFDict::SkPDFDict() {}
    396 
    397 SkPDFDict::SkPDFDict(const char type[]) {
    398     insertName("Type", type);
    399 }
    400 
    401 SkPDFDict::~SkPDFDict() {
    402     clear();
    403 }
    404 
    405 void SkPDFDict::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
    406                            bool indirect) {
    407     if (indirect) {
    408         return emitIndirectObject(stream, catalog);
    409     }
    410 
    411     stream->writeText("<<");
    412     for (int i = 0; i < fValue.count(); i++) {
    413         fValue[i].key->emitObject(stream, catalog, false);
    414         stream->writeText(" ");
    415         fValue[i].value->emit(stream, catalog, false);
    416         stream->writeText("\n");
    417     }
    418     stream->writeText(">>");
    419 }
    420 
    421 size_t SkPDFDict::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
    422     if (indirect) {
    423         return getIndirectOutputSize(catalog);
    424     }
    425 
    426     size_t result = strlen("<<>>") + (fValue.count() * 2);
    427     for (int i = 0; i < fValue.count(); i++) {
    428         result += fValue[i].key->getOutputSize(catalog, false);
    429         result += fValue[i].value->getOutputSize(catalog, false);
    430     }
    431     return result;
    432 }
    433 
    434 SkPDFObject* SkPDFDict::insert(SkPDFName* key, SkPDFObject* value) {
    435     key->ref();
    436     value->ref();
    437     struct Rec* newEntry = fValue.append();
    438     newEntry->key = key;
    439     newEntry->value = value;
    440     return value;
    441 }
    442 
    443 SkPDFObject* SkPDFDict::insert(const char key[], SkPDFObject* value) {
    444     value->ref();
    445     struct Rec* newEntry = fValue.append();
    446     newEntry->key = new SkPDFName(key);
    447     newEntry->value = value;
    448     return value;
    449 }
    450 
    451 void SkPDFDict::insertInt(const char key[], int32_t value) {
    452     struct Rec* newEntry = fValue.append();
    453     newEntry->key = new SkPDFName(key);
    454     newEntry->value = new SkPDFInt(value);
    455 }
    456 
    457 void SkPDFDict::insertScalar(const char key[], SkScalar value) {
    458     struct Rec* newEntry = fValue.append();
    459     newEntry->key = new SkPDFName(key);
    460     newEntry->value = new SkPDFScalar(value);
    461 }
    462 
    463 void SkPDFDict::insertName(const char key[], const char name[]) {
    464     struct Rec* newEntry = fValue.append();
    465     newEntry->key = new SkPDFName(key);
    466     newEntry->value = new SkPDFName(name);
    467 }
    468 
    469 void SkPDFDict::clear() {
    470     for (int i = 0; i < fValue.count(); i++) {
    471         fValue[i].key->unref();
    472         fValue[i].value->unref();
    473     }
    474     fValue.reset();
    475 }
    476 
    477 SkPDFDict::Iter::Iter(const SkPDFDict& dict)
    478     : fIter(dict.fValue.begin()),
    479       fStop(dict.fValue.end()) {
    480 }
    481 
    482 SkPDFName* SkPDFDict::Iter::next(SkPDFObject** value) {
    483     if (fIter != fStop) {
    484         const Rec* cur = fIter;
    485         fIter++;
    486         *value = cur->value;
    487         return cur->key;
    488     }
    489     *value = NULL;
    490     return NULL;
    491 }
    492