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