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