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
20SkPDFObject::SkPDFObject() {}
21SkPDFObject::~SkPDFObject() {}
22
23void SkPDFObject::emit(SkWStream* stream, SkPDFCatalog* catalog,
24                       bool indirect) {
25    SkPDFObject* realObject = catalog->getSubstituteObject(this);
26    return realObject->emitObject(stream, catalog, indirect);
27}
28
29size_t SkPDFObject::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
30    SkDynamicMemoryWStream buffer;
31    emit(&buffer, catalog, indirect);
32    return buffer.getOffset();
33}
34
35void SkPDFObject::getResources(SkTDArray<SkPDFObject*>* resourceList) {}
36
37void 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
44size_t SkPDFObject::getIndirectOutputSize(SkPDFCatalog* catalog) {
45    return catalog->getObjectNumberSize(this) + strlen(" obj\n") +
46        this->getOutputSize(catalog, false) + strlen("\nendobj\n");
47}
48
49void SkPDFObject::AddResourceHelper(SkPDFObject* resource,
50                                    SkTDArray<SkPDFObject*>* list) {
51    list->push(resource);
52    resource->ref();
53}
54
55void 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
67SkPDFObjRef::SkPDFObjRef(SkPDFObject* obj) : fObj(obj) {}
68SkPDFObjRef::~SkPDFObjRef() {}
69
70void SkPDFObjRef::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
71                             bool indirect) {
72    SkASSERT(!indirect);
73    catalog->emitObjectNumber(stream, fObj.get());
74    stream->writeText(" R");
75}
76
77size_t SkPDFObjRef::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
78    SkASSERT(!indirect);
79    return catalog->getObjectNumberSize(fObj.get()) + strlen(" R");
80}
81
82SkPDFInt::SkPDFInt(int32_t value) : fValue(value) {}
83SkPDFInt::~SkPDFInt() {}
84
85void SkPDFInt::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
86                          bool indirect) {
87    if (indirect) {
88        return emitIndirectObject(stream, catalog);
89    }
90    stream->writeDecAsText(fValue);
91}
92
93SkPDFBool::SkPDFBool(bool value) : fValue(value) {}
94SkPDFBool::~SkPDFBool() {}
95
96void 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
106size_t SkPDFBool::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
107    SkASSERT(!indirect);
108    if (fValue) {
109        return strlen("true");
110    }
111    return strlen("false");
112}
113
114SkPDFScalar::SkPDFScalar(SkScalar value) : fValue(value) {}
115SkPDFScalar::~SkPDFScalar() {}
116
117void 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
127void 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
181SkPDFString::SkPDFString(const char value[])
182    : fValue(FormatString(value, strlen(value))) {
183}
184
185SkPDFString::SkPDFString(const SkString& value)
186    : fValue(FormatString(value.c_str(), value.size())) {
187}
188
189SkPDFString::SkPDFString(const uint16_t* value, size_t len, bool wideChars)
190    : fValue(FormatString(value, len, wideChars)) {
191}
192
193SkPDFString::~SkPDFString() {}
194
195void 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
202size_t SkPDFString::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
203    if (indirect)
204        return getIndirectOutputSize(catalog);
205    return fValue.size();
206}
207
208// static
209SkString SkPDFString::FormatString(const char* input, size_t len) {
210    return DoFormatString(input, len, false, false);
211}
212
213SkString SkPDFString::FormatString(const uint16_t* input, size_t len,
214                                   bool wideChars) {
215    return DoFormatString(input, len, true, wideChars);
216}
217
218// static
219SkString 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
273SkPDFName::SkPDFName(const char name[]) : fValue(FormatName(SkString(name))) {}
274SkPDFName::SkPDFName(const SkString& name) : fValue(FormatName(name)) {}
275SkPDFName::~SkPDFName() {}
276
277bool SkPDFName::operator==(const SkPDFName& b) const {
278    return fValue == b.fValue;
279}
280
281void SkPDFName::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
282                           bool indirect) {
283    SkASSERT(!indirect);
284    stream->write(fValue.c_str(), fValue.size());
285}
286
287size_t SkPDFName::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
288    SkASSERT(!indirect);
289    return fValue.size();
290}
291
292// static
293SkString 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
309SkPDFArray::SkPDFArray() {}
310SkPDFArray::~SkPDFArray() {
311    fValue.unrefAll();
312}
313
314void 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
330size_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
345void SkPDFArray::reserve(int length) {
346    SkASSERT(length <= kMaxLen);
347    fValue.setReserve(length);
348}
349
350SkPDFObject* 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
358SkPDFObject* SkPDFArray::append(SkPDFObject* value) {
359    SkASSERT(fValue.count() < kMaxLen);
360    value->ref();
361    fValue.push(value);
362    return value;
363}
364
365void SkPDFArray::appendInt(int32_t value) {
366    SkASSERT(fValue.count() < kMaxLen);
367    fValue.push(new SkPDFInt(value));
368}
369
370void SkPDFArray::appendScalar(SkScalar value) {
371    SkASSERT(fValue.count() < kMaxLen);
372    fValue.push(new SkPDFScalar(value));
373}
374
375void SkPDFArray::appendName(const char name[]) {
376    SkASSERT(fValue.count() < kMaxLen);
377    fValue.push(new SkPDFName(name));
378}
379
380///////////////////////////////////////////////////////////////////////////////
381
382SkPDFDict::SkPDFDict() {}
383
384SkPDFDict::SkPDFDict(const char type[]) {
385    insertName("Type", type);
386}
387
388SkPDFDict::~SkPDFDict() {
389    clear();
390}
391
392void 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
408size_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
421SkPDFObject* 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
430SkPDFObject* 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
438void 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
444void 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
450void 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
456void 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
464SkPDFDict::Iter::Iter(const SkPDFDict& dict)
465    : fIter(dict.fValue.begin()),
466      fStop(dict.fValue.end()) {
467}
468
469SkPDFName* 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