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