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