• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
SkPDFObject()20 SkPDFObject::SkPDFObject() {}
~SkPDFObject()21 SkPDFObject::~SkPDFObject() {}
22 
emit(SkWStream * stream,SkPDFCatalog * catalog,bool indirect)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 
getOutputSize(SkPDFCatalog * catalog,bool indirect)29 size_t SkPDFObject::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
30     SkDynamicMemoryWStream buffer;
31     emit(&buffer, catalog, indirect);
32     return buffer.getOffset();
33 }
34 
getResources(SkTDArray<SkPDFObject * > * resourceList)35 void SkPDFObject::getResources(SkTDArray<SkPDFObject*>* resourceList) {}
36 
emitIndirectObject(SkWStream * stream,SkPDFCatalog * catalog)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 
getIndirectOutputSize(SkPDFCatalog * catalog)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 
AddResourceHelper(SkPDFObject * resource,SkTDArray<SkPDFObject * > * list)49 void SkPDFObject::AddResourceHelper(SkPDFObject* resource,
50                                     SkTDArray<SkPDFObject*>* list) {
51     list->push(resource);
52     resource->ref();
53 }
54 
GetResourcesHelper(SkTDArray<SkPDFObject * > * resources,SkTDArray<SkPDFObject * > * result)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 
SkPDFObjRef(SkPDFObject * obj)67 SkPDFObjRef::SkPDFObjRef(SkPDFObject* obj) : fObj(obj) {}
~SkPDFObjRef()68 SkPDFObjRef::~SkPDFObjRef() {}
69 
emitObject(SkWStream * stream,SkPDFCatalog * catalog,bool indirect)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 
getOutputSize(SkPDFCatalog * catalog,bool indirect)77 size_t SkPDFObjRef::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
78     SkASSERT(!indirect);
79     return catalog->getObjectNumberSize(fObj.get()) + strlen(" R");
80 }
81 
SkPDFInt(int32_t value)82 SkPDFInt::SkPDFInt(int32_t value) : fValue(value) {}
~SkPDFInt()83 SkPDFInt::~SkPDFInt() {}
84 
emitObject(SkWStream * stream,SkPDFCatalog * catalog,bool indirect)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 
SkPDFBool(bool value)93 SkPDFBool::SkPDFBool(bool value) : fValue(value) {}
~SkPDFBool()94 SkPDFBool::~SkPDFBool() {}
95 
emitObject(SkWStream * stream,SkPDFCatalog * catalog,bool indirect)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 
getOutputSize(SkPDFCatalog * catalog,bool indirect)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 
SkPDFScalar(SkScalar value)114 SkPDFScalar::SkPDFScalar(SkScalar value) : fValue(value) {}
~SkPDFScalar()115 SkPDFScalar::~SkPDFScalar() {}
116 
emitObject(SkWStream * stream,SkPDFCatalog * catalog,bool indirect)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
Append(SkScalar value,SkWStream * stream)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 
SkPDFString(const char value[])181 SkPDFString::SkPDFString(const char value[])
182     : fValue(FormatString(value, strlen(value))) {
183 }
184 
SkPDFString(const SkString & value)185 SkPDFString::SkPDFString(const SkString& value)
186     : fValue(FormatString(value.c_str(), value.size())) {
187 }
188 
SkPDFString(const uint16_t * value,size_t len,bool wideChars)189 SkPDFString::SkPDFString(const uint16_t* value, size_t len, bool wideChars)
190     : fValue(FormatString(value, len, wideChars)) {
191 }
192 
~SkPDFString()193 SkPDFString::~SkPDFString() {}
194 
emitObject(SkWStream * stream,SkPDFCatalog * catalog,bool indirect)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 
getOutputSize(SkPDFCatalog * catalog,bool indirect)202 size_t SkPDFString::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
203     if (indirect)
204         return getIndirectOutputSize(catalog);
205     return fValue.size();
206 }
207 
208 // static
FormatString(const char * input,size_t len)209 SkString SkPDFString::FormatString(const char* input, size_t len) {
210     return DoFormatString(input, len, false, false);
211 }
212 
FormatString(const uint16_t * input,size_t len,bool wideChars)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
DoFormatString(const void * input,size_t len,bool wideInput,bool wideOutput)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 
SkPDFName(const char name[])273 SkPDFName::SkPDFName(const char name[]) : fValue(FormatName(SkString(name))) {}
SkPDFName(const SkString & name)274 SkPDFName::SkPDFName(const SkString& name) : fValue(FormatName(name)) {}
~SkPDFName()275 SkPDFName::~SkPDFName() {}
276 
operator ==(const SkPDFName & b) const277 bool SkPDFName::operator==(const SkPDFName& b) const {
278     return fValue == b.fValue;
279 }
280 
emitObject(SkWStream * stream,SkPDFCatalog * catalog,bool indirect)281 void SkPDFName::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
282                            bool indirect) {
283     SkASSERT(!indirect);
284     stream->write(fValue.c_str(), fValue.size());
285 }
286 
getOutputSize(SkPDFCatalog * catalog,bool indirect)287 size_t SkPDFName::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
288     SkASSERT(!indirect);
289     return fValue.size();
290 }
291 
292 // static
FormatName(const SkString & input)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 
SkPDFArray()309 SkPDFArray::SkPDFArray() {}
~SkPDFArray()310 SkPDFArray::~SkPDFArray() {
311     fValue.unrefAll();
312 }
313 
emitObject(SkWStream * stream,SkPDFCatalog * catalog,bool indirect)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 
getOutputSize(SkPDFCatalog * catalog,bool indirect)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 
reserve(int length)345 void SkPDFArray::reserve(int length) {
346     SkASSERT(length <= kMaxLen);
347     fValue.setReserve(length);
348 }
349 
setAt(int offset,SkPDFObject * value)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 
append(SkPDFObject * value)358 SkPDFObject* SkPDFArray::append(SkPDFObject* value) {
359     SkASSERT(fValue.count() < kMaxLen);
360     value->ref();
361     fValue.push(value);
362     return value;
363 }
364 
appendInt(int32_t value)365 void SkPDFArray::appendInt(int32_t value) {
366     SkASSERT(fValue.count() < kMaxLen);
367     fValue.push(new SkPDFInt(value));
368 }
369 
appendScalar(SkScalar value)370 void SkPDFArray::appendScalar(SkScalar value) {
371     SkASSERT(fValue.count() < kMaxLen);
372     fValue.push(new SkPDFScalar(value));
373 }
374 
appendName(const char name[])375 void SkPDFArray::appendName(const char name[]) {
376     SkASSERT(fValue.count() < kMaxLen);
377     fValue.push(new SkPDFName(name));
378 }
379 
380 ///////////////////////////////////////////////////////////////////////////////
381 
SkPDFDict()382 SkPDFDict::SkPDFDict() {}
383 
SkPDFDict(const char type[])384 SkPDFDict::SkPDFDict(const char type[]) {
385     insertName("Type", type);
386 }
387 
~SkPDFDict()388 SkPDFDict::~SkPDFDict() {
389     clear();
390 }
391 
emitObject(SkWStream * stream,SkPDFCatalog * catalog,bool indirect)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 
getOutputSize(SkPDFCatalog * catalog,bool indirect)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 
insert(SkPDFName * key,SkPDFObject * value)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 
insert(const char key[],SkPDFObject * value)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 
insertInt(const char key[],int32_t value)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 
insertScalar(const char key[],SkScalar value)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 
insertName(const char key[],const char name[])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 
clear()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 
Iter(const SkPDFDict & dict)464 SkPDFDict::Iter::Iter(const SkPDFDict& dict)
465     : fIter(dict.fValue.begin()),
466       fStop(dict.fValue.end()) {
467 }
468 
next(SkPDFObject ** value)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