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