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
20SK_DEFINE_INST_COUNT(SkPDFArray)
21SK_DEFINE_INST_COUNT(SkPDFBool)
22SK_DEFINE_INST_COUNT(SkPDFDict)
23SK_DEFINE_INST_COUNT(SkPDFInt)
24SK_DEFINE_INST_COUNT(SkPDFName)
25SK_DEFINE_INST_COUNT(SkPDFObject)
26SK_DEFINE_INST_COUNT(SkPDFObjRef)
27SK_DEFINE_INST_COUNT(SkPDFScalar)
28SK_DEFINE_INST_COUNT(SkPDFString)
29
30///////////////////////////////////////////////////////////////////////////////
31
32void SkPDFObject::emit(SkWStream* stream, SkPDFCatalog* catalog,
33                       bool indirect) {
34    SkPDFObject* realObject = catalog->getSubstituteObject(this);
35    return realObject->emitObject(stream, catalog, indirect);
36}
37
38size_t SkPDFObject::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
39    SkDynamicMemoryWStream buffer;
40    emit(&buffer, catalog, indirect);
41    return buffer.getOffset();
42}
43
44void SkPDFObject::getResources(const SkTSet<SkPDFObject*>& knownResourceObjects,
45                               SkTSet<SkPDFObject*>* newResourceObjects) {}
46
47void 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
54size_t SkPDFObject::getIndirectOutputSize(SkPDFCatalog* catalog) {
55    return catalog->getObjectNumberSize(this) + strlen(" obj\n") +
56        this->getOutputSize(catalog, false) + strlen("\nendobj\n");
57}
58
59void SkPDFObject::AddResourceHelper(SkPDFObject* resource,
60                                    SkTDArray<SkPDFObject*>* list) {
61    list->push(resource);
62    resource->ref();
63}
64
65void 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
84SkPDFObjRef::SkPDFObjRef(SkPDFObject* obj) : fObj(obj) {
85    SkSafeRef(obj);
86}
87
88SkPDFObjRef::~SkPDFObjRef() {}
89
90void SkPDFObjRef::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
91                             bool indirect) {
92    SkASSERT(!indirect);
93    catalog->emitObjectNumber(stream, fObj.get());
94    stream->writeText(" R");
95}
96
97size_t SkPDFObjRef::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
98    SkASSERT(!indirect);
99    return catalog->getObjectNumberSize(fObj.get()) + strlen(" R");
100}
101
102SkPDFInt::SkPDFInt(int32_t value) : fValue(value) {}
103SkPDFInt::~SkPDFInt() {}
104
105void SkPDFInt::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
106                          bool indirect) {
107    if (indirect) {
108        return emitIndirectObject(stream, catalog);
109    }
110    stream->writeDecAsText(fValue);
111}
112
113SkPDFBool::SkPDFBool(bool value) : fValue(value) {}
114SkPDFBool::~SkPDFBool() {}
115
116void 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
126size_t SkPDFBool::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
127    SkASSERT(!indirect);
128    if (fValue) {
129        return strlen("true");
130    }
131    return strlen("false");
132}
133
134SkPDFScalar::SkPDFScalar(SkScalar value) : fValue(value) {}
135SkPDFScalar::~SkPDFScalar() {}
136
137void 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
147void 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
201SkPDFString::SkPDFString(const char value[])
202    : fValue(FormatString(value, strlen(value))) {
203}
204
205SkPDFString::SkPDFString(const SkString& value)
206    : fValue(FormatString(value.c_str(), value.size())) {
207}
208
209SkPDFString::SkPDFString(const uint16_t* value, size_t len, bool wideChars)
210    : fValue(FormatString(value, len, wideChars)) {
211}
212
213SkPDFString::~SkPDFString() {}
214
215void 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
222size_t SkPDFString::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
223    if (indirect)
224        return getIndirectOutputSize(catalog);
225    return fValue.size();
226}
227
228// static
229SkString SkPDFString::FormatString(const char* input, size_t len) {
230    return DoFormatString(input, len, false, false);
231}
232
233SkString SkPDFString::FormatString(const uint16_t* input, size_t len,
234                                   bool wideChars) {
235    return DoFormatString(input, len, true, wideChars);
236}
237
238// static
239SkString 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
293SkPDFName::SkPDFName(const char name[]) : fValue(FormatName(SkString(name))) {}
294SkPDFName::SkPDFName(const SkString& name) : fValue(FormatName(name)) {}
295SkPDFName::~SkPDFName() {}
296
297bool SkPDFName::operator==(const SkPDFName& b) const {
298    return fValue == b.fValue;
299}
300
301void SkPDFName::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
302                           bool indirect) {
303    SkASSERT(!indirect);
304    stream->write(fValue.c_str(), fValue.size());
305}
306
307size_t SkPDFName::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
308    SkASSERT(!indirect);
309    return fValue.size();
310}
311
312// static
313SkString 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
332SkPDFArray::SkPDFArray() {}
333SkPDFArray::~SkPDFArray() {
334    fValue.unrefAll();
335}
336
337void 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
353size_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
368void SkPDFArray::reserve(int length) {
369    SkASSERT(length <= kMaxLen);
370    fValue.setReserve(length);
371}
372
373SkPDFObject* 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
381SkPDFObject* SkPDFArray::append(SkPDFObject* value) {
382    SkASSERT(fValue.count() < kMaxLen);
383    value->ref();
384    fValue.push(value);
385    return value;
386}
387
388void SkPDFArray::appendInt(int32_t value) {
389    SkASSERT(fValue.count() < kMaxLen);
390    fValue.push(new SkPDFInt(value));
391}
392
393void SkPDFArray::appendScalar(SkScalar value) {
394    SkASSERT(fValue.count() < kMaxLen);
395    fValue.push(new SkPDFScalar(value));
396}
397
398void SkPDFArray::appendName(const char name[]) {
399    SkASSERT(fValue.count() < kMaxLen);
400    fValue.push(new SkPDFName(name));
401}
402
403///////////////////////////////////////////////////////////////////////////////
404
405SkPDFDict::SkPDFDict() {}
406
407SkPDFDict::SkPDFDict(const char type[]) {
408    insertName("Type", type);
409}
410
411SkPDFDict::~SkPDFDict() {
412    clear();
413}
414
415void 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
431size_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
444SkPDFObject* 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
453SkPDFObject* 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
461void 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
467void 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
473void 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
479void 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
487SkPDFDict::Iter::Iter(const SkPDFDict& dict)
488    : fIter(dict.fValue.begin()),
489      fStop(dict.fValue.end()) {
490}
491
492SkPDFName* 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