Home | History | Annotate | Download | only in pdf
      1 /*
      2  * Copyright (C) 2011 Google Inc.
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include "SkPDFCatalog.h"
     18 #include "SkPDFTypes.h"
     19 #include "SkStream.h"
     20 
     21 #ifdef SK_BUILD_FOR_WIN
     22     #define SNPRINTF    _snprintf
     23 #else
     24     #define SNPRINTF    snprintf
     25 #endif
     26 
     27 SkPDFObject::SkPDFObject() {}
     28 SkPDFObject::~SkPDFObject() {}
     29 
     30 size_t SkPDFObject::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
     31     SkDynamicMemoryWStream buffer;
     32     emitObject(&buffer, catalog, indirect);
     33     return buffer.getOffset();
     34 }
     35 
     36 void SkPDFObject::getResources(SkTDArray<SkPDFObject*>* resourceList) {}
     37 
     38 void SkPDFObject::emitIndirectObject(SkWStream* stream, SkPDFCatalog* catalog) {
     39     catalog->emitObjectNumber(stream, this);
     40     stream->writeText(" obj\n");
     41     emitObject(stream, catalog, false);
     42     stream->writeText("\nendobj\n");
     43 }
     44 
     45 SkPDFObjRef::SkPDFObjRef(SkPDFObject* obj) : fObj(obj) {}
     46 SkPDFObjRef::~SkPDFObjRef() {}
     47 
     48 size_t SkPDFObject::getIndirectOutputSize(SkPDFCatalog* catalog) {
     49     return catalog->getObjectNumberSize(this) + strlen(" obj\n") +
     50         this->getOutputSize(catalog, false) + strlen("\nendobj\n");
     51 }
     52 
     53 void SkPDFObjRef::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
     54                              bool indirect) {
     55     SkASSERT(!indirect);
     56     catalog->emitObjectNumber(stream, fObj.get());
     57     stream->writeText(" R");
     58 }
     59 
     60 size_t SkPDFObjRef::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
     61     SkASSERT(!indirect);
     62     return catalog->getObjectNumberSize(fObj.get()) + strlen(" R");
     63 }
     64 
     65 SkPDFInt::SkPDFInt(int32_t value) : fValue(value) {}
     66 SkPDFInt::~SkPDFInt() {}
     67 
     68 void SkPDFInt::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
     69                           bool indirect) {
     70     if (indirect)
     71         return emitIndirectObject(stream, catalog);
     72     stream->writeDecAsText(fValue);
     73 }
     74 
     75 SkPDFBool::SkPDFBool(bool value) : fValue(value) {}
     76 SkPDFBool::~SkPDFBool() {}
     77 
     78 void SkPDFBool::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
     79                           bool indirect) {
     80     SkASSERT(!indirect);
     81     if (fValue) {
     82         stream->writeText("true");
     83     } else {
     84         stream->writeText("false");
     85     }
     86 }
     87 
     88 size_t SkPDFBool::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
     89     SkASSERT(!indirect);
     90     if (fValue)
     91         return strlen("true");
     92     return strlen("false");
     93 }
     94 
     95 SkPDFScalar::SkPDFScalar(SkScalar value) : fValue(value) {}
     96 SkPDFScalar::~SkPDFScalar() {}
     97 
     98 void SkPDFScalar::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
     99                              bool indirect) {
    100     if (indirect)
    101         return emitIndirectObject(stream, catalog);
    102 
    103     Append(fValue, stream);
    104 }
    105 
    106 // static
    107 void SkPDFScalar::Append(SkScalar value, SkWStream* stream) {
    108     // The range of reals in PDF/A is the same as SkFixed: +/- 32,767 and
    109     // +/- 1/65,536 (though integers can range from 2^31 - 1 to -2^31).
    110     // When using floats that are outside the whole value range, we can use
    111     // integers instead.
    112 
    113 
    114 #if defined(SK_SCALAR_IS_FIXED)
    115     stream->writeScalarAsText(value);
    116     return;
    117 #endif  // SK_SCALAR_IS_FIXED
    118 
    119 #if !defined(SK_ALLOW_LARGE_PDF_SCALARS)
    120     if (value > 32767 || value < -32767) {
    121         stream->writeDecAsText(SkScalarRound(value));
    122         return;
    123     }
    124 
    125     char buffer[SkStrAppendScalar_MaxSize];
    126     char* end = SkStrAppendFixed(buffer, SkScalarToFixed(value));
    127     stream->write(buffer, end - buffer);
    128     return;
    129 #endif  // !SK_ALLOW_LARGE_PDF_SCALARS
    130 
    131 #if defined(SK_SCALAR_IS_FLOAT) && defined(SK_ALLOW_LARGE_PDF_SCALARS)
    132     // Floats have 24bits of significance, so anything outside that range is
    133     // no more precise than an int. (Plus PDF doesn't support scientific
    134     // notation, so this clamps to SK_Max/MinS32).
    135     if (value > (1 << 24) || value < -(1 << 24)) {
    136         stream->writeDecAsText(value);
    137         return;
    138     }
    139     // Continue to enforce the PDF limits for small floats.
    140     if (value < 1.0f/65536 && value > -1.0f/65536) {
    141         stream->writeDecAsText(0);
    142         return;
    143     }
    144     // SkStrAppendFloat might still use scientific notation, so use snprintf
    145     // directly..
    146     static const int kFloat_MaxSize = 19;
    147     char buffer[kFloat_MaxSize];
    148     int len = SNPRINTF(buffer, kFloat_MaxSize, "%#.8f", value);
    149     // %f always prints trailing 0s, so strip them.
    150     for (; buffer[len - 1] == '0' && len > 0; len--) {
    151         buffer[len - 1] = '\0';
    152     }
    153     if (buffer[len - 1] == '.') {
    154         buffer[len - 1] = '\0';
    155     }
    156     stream->writeText(buffer);
    157     return;
    158 #endif  // SK_SCALAR_IS_FLOAT && SK_ALLOW_LARGE_PDF_SCALARS
    159 }
    160 
    161 SkPDFString::SkPDFString(const char value[])
    162     : fValue(formatString(value, strlen(value))) {
    163 }
    164 
    165 SkPDFString::SkPDFString(const SkString& value)
    166     : fValue(formatString(value.c_str(), value.size())) {
    167 }
    168 
    169 SkPDFString::SkPDFString(const uint16_t* value, size_t len, bool wideChars)
    170     : fValue(formatString(value, len, wideChars)) {
    171 }
    172 
    173 SkPDFString::~SkPDFString() {}
    174 
    175 void SkPDFString::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
    176                              bool indirect) {
    177     if (indirect)
    178         return emitIndirectObject(stream, catalog);
    179     stream->write(fValue.c_str(), fValue.size());
    180 }
    181 
    182 size_t SkPDFString::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
    183     if (indirect)
    184         return getIndirectOutputSize(catalog);
    185     return fValue.size();
    186 }
    187 
    188 // static
    189 SkString SkPDFString::formatString(const char* input, size_t len) {
    190     return doFormatString(input, len, false, false);
    191 }
    192 
    193 SkString SkPDFString::formatString(const uint16_t* input, size_t len,
    194                                    bool wideChars) {
    195     return doFormatString(input, len, true, wideChars);
    196 }
    197 
    198 // static
    199 SkString SkPDFString::doFormatString(const void* input, size_t len,
    200                                      bool wideInput, bool wideOutput) {
    201     SkASSERT(len <= kMaxLen);
    202     const uint16_t* win = (const uint16_t*) input;
    203     const char* cin = (const char*) input;
    204 
    205     if (wideOutput) {
    206         SkASSERT(wideInput);
    207         SkString result;
    208         result.append("<");
    209         for (size_t i = 0; i < len; i++)
    210             result.appendHex(win[i], 4);
    211         result.append(">");
    212         return result;
    213     }
    214 
    215     // 7-bit clean is a heuristic to decide what string format to use;
    216     // a 7-bit clean string should require little escaping.
    217     bool sevenBitClean = true;
    218     for (size_t i = 0; i < len; i++) {
    219         SkASSERT(!wideInput || !(win[i] & ~0xFF));
    220         char val = wideInput ? win[i] : cin[i];
    221         if (val > '~' || val < ' ') {
    222             sevenBitClean = false;
    223             break;
    224         }
    225     }
    226 
    227     SkString result;
    228     if (sevenBitClean) {
    229         result.append("(");
    230         for (size_t i = 0; i < len; i++) {
    231             SkASSERT(!wideInput || !(win[i] & ~0xFF));
    232             char val = wideInput ? win[i] : cin[i];
    233             if (val == '\\' || val == '(' || val == ')')
    234                 result.append("\\");
    235             result.append(&val, 1);
    236         }
    237         result.append(")");
    238     } else {
    239         result.append("<");
    240         for (size_t i = 0; i < len; i++) {
    241             SkASSERT(!wideInput || !(win[i] & ~0xFF));
    242             unsigned char val = wideInput ? win[i] : cin[i];
    243             result.appendHex(val, 2);
    244         }
    245         result.append(">");
    246     }
    247 
    248     return result;
    249 }
    250 
    251 SkPDFName::SkPDFName(const char name[]) : fValue(formatName(SkString(name))) {}
    252 SkPDFName::SkPDFName(const SkString& name) : fValue(formatName(name)) {}
    253 SkPDFName::~SkPDFName() {}
    254 
    255 void SkPDFName::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
    256                            bool indirect) {
    257     SkASSERT(!indirect);
    258     stream->write(fValue.c_str(), fValue.size());
    259 }
    260 
    261 size_t SkPDFName::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
    262     SkASSERT(!indirect);
    263     return fValue.size();
    264 }
    265 
    266 // static
    267 SkString SkPDFName::formatName(const SkString& input) {
    268     SkASSERT(input.size() <= kMaxLen);
    269 
    270     SkString result("/");
    271     for (size_t i = 0; i < input.size(); i++) {
    272         if (input[i] & 0x80 || input[i] < '!' || input[i] == '#') {
    273             result.append("#");
    274             result.appendHex(input[i], 2);
    275         } else {
    276             result.append(input.c_str() + i, 1);
    277         }
    278     }
    279 
    280     return result;
    281 }
    282 
    283 SkPDFArray::SkPDFArray() {}
    284 SkPDFArray::~SkPDFArray() {
    285     fValue.safeUnrefAll();
    286 }
    287 
    288 void SkPDFArray::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
    289                             bool indirect) {
    290     if (indirect)
    291         return emitIndirectObject(stream, catalog);
    292 
    293     stream->writeText("[");
    294     for (int i = 0; i < fValue.count(); i++) {
    295         fValue[i]->emitObject(stream, catalog, false);
    296         if (i + 1 < fValue.count())
    297             stream->writeText(" ");
    298     }
    299     stream->writeText("]");
    300 }
    301 
    302 size_t SkPDFArray::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
    303     if (indirect)
    304         return getIndirectOutputSize(catalog);
    305 
    306     size_t result = strlen("[]");
    307     if (fValue.count())
    308         result += fValue.count() - 1;
    309     for (int i = 0; i < fValue.count(); i++)
    310         result += fValue[i]->getOutputSize(catalog, false);
    311     return result;
    312 }
    313 
    314 void SkPDFArray::reserve(int length) {
    315     SkASSERT(length <= kMaxLen);
    316     fValue.setReserve(length);
    317 }
    318 
    319 SkPDFObject* SkPDFArray::setAt(int offset, SkPDFObject* value) {
    320     SkASSERT(offset < fValue.count());
    321     SkSafeUnref(fValue[offset]);
    322     fValue[offset] = value;
    323     SkSafeRef(fValue[offset]);
    324     return value;
    325 }
    326 
    327 SkPDFObject* SkPDFArray::append(SkPDFObject* value) {
    328     SkASSERT(fValue.count() < kMaxLen);
    329     SkSafeRef(value);
    330     fValue.push(value);
    331     return value;
    332 }
    333 
    334 SkPDFDict::SkPDFDict() {}
    335 
    336 SkPDFDict::SkPDFDict(const char type[]) {
    337     insert("Type", new SkPDFName(type))->unref();
    338 }
    339 
    340 SkPDFDict::~SkPDFDict() {
    341     clear();
    342 }
    343 
    344 void SkPDFDict::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
    345                            bool indirect) {
    346     if (indirect)
    347         return emitIndirectObject(stream, catalog);
    348 
    349     stream->writeText("<<");
    350     for (int i = 0; i < fValue.count(); i++) {
    351         fValue[i].key->emitObject(stream, catalog, false);
    352         stream->writeText(" ");
    353         fValue[i].value->emitObject(stream, catalog, false);
    354         stream->writeText("\n");
    355     }
    356     stream->writeText(">>");
    357 }
    358 
    359 size_t SkPDFDict::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
    360     if (indirect)
    361         return getIndirectOutputSize(catalog);
    362 
    363     size_t result = strlen("<<>>") + (fValue.count() * 2);
    364     for (int i = 0; i < fValue.count(); i++) {
    365         result += fValue[i].key->getOutputSize(catalog, false);
    366         result += fValue[i].value->getOutputSize(catalog, false);
    367     }
    368     return result;
    369 }
    370 
    371 SkPDFObject* SkPDFDict::insert(SkPDFName* key, SkPDFObject* value) {
    372     struct Rec* newEntry = fValue.append();
    373     newEntry->key = key;
    374     SkSafeRef(newEntry->key);
    375     newEntry->value = value;
    376     SkSafeRef(newEntry->value);
    377     return value;
    378 }
    379 
    380 SkPDFObject* SkPDFDict::insert(const char key[], SkPDFObject* value) {
    381     SkRefPtr<SkPDFName> keyName = new SkPDFName(key);
    382     keyName->unref();  // SkRefPtr and new both took a reference.
    383     return insert(keyName.get(), value);
    384 }
    385 
    386 void SkPDFDict::clear() {
    387     for (int i = 0; i < fValue.count(); i++) {
    388         SkSafeUnref(fValue[i].key);
    389         SkSafeUnref(fValue[i].value);
    390     }
    391     fValue.reset();
    392 }
    393