1/*
2 * Copyright 2011 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "src/pdf/SkPDFTypes.h"
9
10#include "include/core/SkData.h"
11#include "include/core/SkExecutor.h"
12#include "include/core/SkStream.h"
13#include "include/private/SkTo.h"
14#include "src/core/SkStreamPriv.h"
15#include "src/pdf/SkDeflate.h"
16#include "src/pdf/SkPDFDocumentPriv.h"
17#include "src/pdf/SkPDFUnion.h"
18#include "src/pdf/SkPDFUtils.h"
19
20#include <new>
21
22////////////////////////////////////////////////////////////////////////////////
23
24SkPDFUnion::SkPDFUnion(Type t, int32_t v) : fIntValue (v) , fType(t) {}
25SkPDFUnion::SkPDFUnion(Type t, bool v) : fBoolValue (v) , fType(t) {}
26SkPDFUnion::SkPDFUnion(Type t, SkScalar v) : fScalarValue (v) , fType(t) {}
27SkPDFUnion::SkPDFUnion(Type t, const char* v) : fStaticString (v) , fType(t) {}
28SkPDFUnion::SkPDFUnion(Type t, SkString v) : fSkString(std::move(v)), fType(t) {}
29SkPDFUnion::SkPDFUnion(Type t, PDFObject v) : fObject (std::move(v)), fType(t) {}
30
31SkPDFUnion::~SkPDFUnion() {
32 switch (fType) {
33 case Type::kNameSkS:
34 case Type::kStringSkS:
35 fSkString.~SkString();
36 return;
37 case Type::kObject:
38 fObject.~PDFObject();
39 return;
40 default:
41 return;
42 }
43}
44
45SkPDFUnion::SkPDFUnion(SkPDFUnion&& that) : fType(that.fType) {
46 SkASSERT(this != &that);
47
48 switch (fType) {
49 case Type::kDestroyed:
50 break;
51 case Type::kInt:
52 case Type::kColorComponent:
53 case Type::kRef:
54 fIntValue = that.fIntValue;
55 break;
56 case Type::kBool:
57 fBoolValue = that.fBoolValue;
58 break;
59 case Type::kColorComponentF:
60 case Type::kScalar:
61 fScalarValue = that.fScalarValue;
62 break;
63 case Type::kName:
64 case Type::kString:
65 fStaticString = that.fStaticString;
66 break;
67 case Type::kNameSkS:
68 case Type::kStringSkS:
69 new (&fSkString) SkString(std::move(that.fSkString));
70 break;
71 case Type::kObject:
72 new (&fObject) PDFObject(std::move(that.fObject));
73 break;
74 default:
75 SkDEBUGFAIL("SkPDFUnion::SkPDFUnion with bad type");
76 }
77 that.fType = Type::kDestroyed;
78}
79
80SkPDFUnion& SkPDFUnion::operator=(SkPDFUnion&& that) {
81 if (this != &that) {
82 this->~SkPDFUnion();
83 new (this) SkPDFUnion(std::move(that));
84 }
85 return *this;
86}
87
88bool SkPDFUnion::isName() const {
89 return Type::kName == fType || Type::kNameSkS == fType;
90}
91
92#ifdef SK_DEBUG
93// Most names need no escaping. Such names are handled as static const strings.
94bool is_valid_name(const char* n) {
95 static const char kControlChars[] = "/%()<>[]{}";
96 while (*n) {
97 if (*n < '!' || *n > '~' || strchr(kControlChars, *n)) {
98 return false;
99 }
100 ++n;
101 }
102 return true;
103}
104#endif // SK_DEBUG
105
106// Given an arbitrary string, write it as a valid name (not including leading slash).
107static void write_name_escaped(SkWStream* o, const char* name) {
108 static const char kToEscape[] = "#/%()<>[]{}";
109 for (const uint8_t* n = reinterpret_cast<const uint8_t*>(name); *n; ++n) {
110 uint8_t v = *n;
111 if (v < '!' || v > '~' || strchr(kToEscape, v)) {
112 char buffer[3] = {'#',
113 SkHexadecimalDigits::gUpper[v >> 4],
114 SkHexadecimalDigits::gUpper[v & 0xF]};
115 o->write(buffer, sizeof(buffer));
116 } else {
117 o->write(n, 1);
118 }
119 }
120}
121
122static void write_string(SkWStream* wStream, const char* cin, size_t len) {
123 SkDEBUGCODE(static const size_t kMaxLen = 65535;)
124 SkASSERT(len <= kMaxLen);
125
126 size_t extraCharacterCount = 0;
127 for (size_t i = 0; i < len; i++) {
128 if (cin[i] > '~' || cin[i] < ' ') {
129 extraCharacterCount += 3;
130 } else if (cin[i] == '\\' || cin[i] == '(' || cin[i] == ')') {
131 ++extraCharacterCount;
132 }
133 }
134 if (extraCharacterCount <= len) {
135 wStream->writeText("(");
136 for (size_t i = 0; i < len; i++) {
137 if (cin[i] > '~' || cin[i] < ' ') {
138 uint8_t c = static_cast<uint8_t>(cin[i]);
139 uint8_t octal[4] = { '\\',
140 (uint8_t)('0' | ( c >> 6 )),
141 (uint8_t)('0' | ((c >> 3) & 0x07)),
142 (uint8_t)('0' | ( c & 0x07)) };
143 wStream->write(octal, 4);
144 } else {
145 if (cin[i] == '\\' || cin[i] == '(' || cin[i] == ')') {
146 wStream->writeText("\\");
147 }
148 wStream->write(&cin[i], 1);
149 }
150 }
151 wStream->writeText(")");
152 } else {
153 wStream->writeText("<");
154 for (size_t i = 0; i < len; i++) {
155 uint8_t c = static_cast<uint8_t>(cin[i]);
156 char hexValue[2] = { SkHexadecimalDigits::gUpper[c >> 4],
157 SkHexadecimalDigits::gUpper[c & 0xF] };
158 wStream->write(hexValue, 2);
159 }
160 wStream->writeText(">");
161 }
162}
163
164void SkPDFWriteString(SkWStream* wStream, const char* cin, size_t len) {
165 write_string(wStream, cin, len);
166}
167
168void SkPDFUnion::emitObject(SkWStream* stream) const {
169 switch (fType) {
170 case Type::kInt:
171 stream->writeDecAsText(fIntValue);
172 return;
173 case Type::kColorComponent:
174 SkPDFUtils::AppendColorComponent(SkToU8(fIntValue), stream);
175 return;
176 case Type::kColorComponentF:
177 SkPDFUtils::AppendColorComponentF(fScalarValue, stream);
178 return;
179 case Type::kBool:
180 stream->writeText(fBoolValue ? "true" : "false");
181 return;
182 case Type::kScalar:
183 SkPDFUtils::AppendScalar(fScalarValue, stream);
184 return;
185 case Type::kName:
186 stream->writeText("/");
187 SkASSERT(is_valid_name(fStaticString));
188 stream->writeText(fStaticString);
189 return;
190 case Type::kString:
191 SkASSERT(fStaticString);
192 write_string(stream, fStaticString, strlen(fStaticString));
193 return;
194 case Type::kNameSkS:
195 stream->writeText("/");
196 write_name_escaped(stream, fSkString.c_str());
197 return;
198 case Type::kStringSkS:
199 write_string(stream, fSkString.c_str(), fSkString.size());
200 return;
201 case Type::kObject:
202 fObject->emitObject(stream);
203 return;
204 case Type::kRef:
205 SkASSERT(fIntValue >= 0);
206 stream->writeDecAsText(fIntValue);
207 stream->writeText(" 0 R"); // Generation number is always 0.
208 return;
209 default:
210 SkDEBUGFAIL("SkPDFUnion::emitObject with bad type");
211 }
212}
213
214SkPDFUnion SkPDFUnion::Int(int32_t value) {
215 return SkPDFUnion(Type::kInt, value);
216}
217
218SkPDFUnion SkPDFUnion::ColorComponent(uint8_t value) {
219 return SkPDFUnion(Type::kColorComponent, SkTo<int32_t>(value));
220}
221
222SkPDFUnion SkPDFUnion::ColorComponentF(float value) {
223 return SkPDFUnion(Type::kColorComponentF, SkFloatToScalar(value));
224}
225
226SkPDFUnion SkPDFUnion::Bool(bool value) {
227 return SkPDFUnion(Type::kBool, value);
228}
229
230SkPDFUnion SkPDFUnion::Scalar(SkScalar value) {
231 return SkPDFUnion(Type::kScalar, value);
232}
233
234SkPDFUnion SkPDFUnion::Name(const char* value) {
235 SkASSERT(value);
236 SkASSERT(is_valid_name(value));
237 return SkPDFUnion(Type::kName, value);
238}
239
240SkPDFUnion SkPDFUnion::String(const char* value) {
241 SkASSERT(value);
242 return SkPDFUnion(Type::kString, value);
243}
244
245SkPDFUnion SkPDFUnion::Name(SkString s) {
246 return SkPDFUnion(Type::kNameSkS, std::move(s));
247}
248
249SkPDFUnion SkPDFUnion::String(SkString s) {
250 return SkPDFUnion(Type::kStringSkS, std::move(s));
251}
252
253SkPDFUnion SkPDFUnion::Object(std::unique_ptr<SkPDFObject> objSp) {
254 SkASSERT(objSp.get());
255 return SkPDFUnion(Type::kObject, std::move(objSp));
256}
257
258SkPDFUnion SkPDFUnion::Ref(SkPDFIndirectReference ref) {
259 SkASSERT(ref.fValue > 0);
260 return SkPDFUnion(Type::kRef, SkTo<int32_t>(ref.fValue));
261}
262
263////////////////////////////////////////////////////////////////////////////////
264
265#if 0 // Enable if needed.
266void SkPDFAtom::emitObject(SkWStream* stream) const {
267 fValue.emitObject(stream);
268}
269#endif // 0
270
271////////////////////////////////////////////////////////////////////////////////
272
273SkPDFArray::SkPDFArray() {}
274
275SkPDFArray::~SkPDFArray() {}
276
277size_t SkPDFArray::size() const { return fValues.size(); }
278
279void SkPDFArray::reserve(int length) {
280 fValues.reserve(length);
281}
282
283void SkPDFArray::emitObject(SkWStream* stream) const {
284 stream->writeText("[");
285 for (size_t i = 0; i < fValues.size(); i++) {
286 fValues[i].emitObject(stream);
287 if (i + 1 < fValues.size()) {
288 stream->writeText(" ");
289 }
290 }
291 stream->writeText("]");
292}
293
294void SkPDFArray::append(SkPDFUnion&& value) {
295 fValues.emplace_back(std::move(value));
296}
297
298void SkPDFArray::appendInt(int32_t value) {
299 this->append(SkPDFUnion::Int(value));
300}
301
302void SkPDFArray::appendColorComponent(uint8_t value) {
303 this->append(SkPDFUnion::ColorComponent(value));
304}
305
306void SkPDFArray::appendBool(bool value) {
307 this->append(SkPDFUnion::Bool(value));
308}
309
310void SkPDFArray::appendScalar(SkScalar value) {
311 this->append(SkPDFUnion::Scalar(value));
312}
313
314void SkPDFArray::appendName(const char name[]) {
315 this->append(SkPDFUnion::Name(SkString(name)));
316}
317
318void SkPDFArray::appendName(SkString name) {
319 this->append(SkPDFUnion::Name(std::move(name)));
320}
321
322void SkPDFArray::appendString(SkString value) {
323 this->append(SkPDFUnion::String(std::move(value)));
324}
325
326void SkPDFArray::appendString(const char value[]) {
327 this->append(SkPDFUnion::String(value));
328}
329
330void SkPDFArray::appendObject(std::unique_ptr<SkPDFObject>&& objSp) {
331 this->append(SkPDFUnion::Object(std::move(objSp)));
332}
333
334void SkPDFArray::appendRef(SkPDFIndirectReference ref) {
335 this->append(SkPDFUnion::Ref(ref));
336}
337
338///////////////////////////////////////////////////////////////////////////////
339
340SkPDFDict::~SkPDFDict() {}
341
342SkPDFDict::SkPDFDict(const char type[]) {
343 if (type) {
344 this->insertName("Type", type);
345 }
346}
347
348void SkPDFDict::emitObject(SkWStream* stream) const {
349 stream->writeText("<<");
350 for (size_t i = 0; i < fRecords.size(); ++i) {
351 const std::pair<SkPDFUnion, SkPDFUnion>& record = fRecords[i];
352 record.first.emitObject(stream);
353 stream->writeText(" ");
354 record.second.emitObject(stream);
355 if (i + 1 < fRecords.size()) {
356 stream->writeText("\n");
357 }
358 }
359 stream->writeText(">>");
360}
361
362size_t SkPDFDict::size() const { return fRecords.size(); }
363
364void SkPDFDict::reserve(int n) {
365 fRecords.reserve(n);
366}
367
368void SkPDFDict::insertRef(const char key[], SkPDFIndirectReference ref) {
369 fRecords.emplace_back(SkPDFUnion::Name(key), SkPDFUnion::Ref(ref));
370}
371
372void SkPDFDict::insertRef(SkString key, SkPDFIndirectReference ref) {
373 fRecords.emplace_back(SkPDFUnion::Name(std::move(key)), SkPDFUnion::Ref(ref));
374}
375
376void SkPDFDict::insertObject(const char key[], std::unique_ptr<SkPDFObject>&& objSp) {
377 fRecords.emplace_back(SkPDFUnion::Name(key), SkPDFUnion::Object(std::move(objSp)));
378}
379void SkPDFDict::insertObject(SkString key, std::unique_ptr<SkPDFObject>&& objSp) {
380 fRecords.emplace_back(SkPDFUnion::Name(std::move(key)),
381 SkPDFUnion::Object(std::move(objSp)));
382}
383
384void SkPDFDict::insertBool(const char key[], bool value) {
385 fRecords.emplace_back(SkPDFUnion::Name(key), SkPDFUnion::Bool(value));
386}
387
388void SkPDFDict::insertInt(const char key[], int32_t value) {
389 fRecords.emplace_back(SkPDFUnion::Name(key), SkPDFUnion::Int(value));
390}
391
392void SkPDFDict::insertInt(const char key[], size_t value) {
393 this->insertInt(key, SkToS32(value));
394}
395
396void SkPDFDict::insertColorComponentF(const char key[], SkScalar value) {
397 fRecords.emplace_back(SkPDFUnion::Name(key), SkPDFUnion::ColorComponentF(value));
398}
399
400void SkPDFDict::insertScalar(const char key[], SkScalar value) {
401 fRecords.emplace_back(SkPDFUnion::Name(key), SkPDFUnion::Scalar(value));
402}
403
404void SkPDFDict::insertName(const char key[], const char name[]) {
405 fRecords.emplace_back(SkPDFUnion::Name(key), SkPDFUnion::Name(name));
406}
407
408void SkPDFDict::insertName(const char key[], SkString name) {
409 fRecords.emplace_back(SkPDFUnion::Name(key), SkPDFUnion::Name(std::move(name)));
410}
411
412void SkPDFDict::insertString(const char key[], const char value[]) {
413 fRecords.emplace_back(SkPDFUnion::Name(key), SkPDFUnion::String(value));
414}
415
416void SkPDFDict::insertString(const char key[], SkString value) {
417 fRecords.emplace_back(SkPDFUnion::Name(key), SkPDFUnion::String(std::move(value)));
418}
419
420////////////////////////////////////////////////////////////////////////////////
421
422
423
424static void serialize_stream(SkPDFDict* origDict,
425 SkStreamAsset* stream,
426 bool deflate,
427 SkPDFDocument* doc,
428 SkPDFIndirectReference ref) {
429 // Code assumes that the stream starts at the beginning.
430 SkASSERT(stream && stream->hasLength());
431
432 std::unique_ptr<SkStreamAsset> tmp;
433 SkPDFDict tmpDict;
434 SkPDFDict& dict = origDict ? *origDict : tmpDict;
435 static const size_t kMinimumSavings = strlen("/Filter_/FlateDecode_");
436 if (deflate && stream->getLength() > kMinimumSavings) {
437 SkDynamicMemoryWStream compressedData;
438 SkDeflateWStream deflateWStream(&compressedData);
439 SkStreamCopy(&deflateWStream, stream);
440 deflateWStream.finalize();
441 #ifdef SK_PDF_BASE85_BINARY
442 {
443 SkPDFUtils::Base85Encode(compressedData.detachAsStream(), &compressedData);
444 tmp = compressedData.detachAsStream();
445 stream = tmp.get();
446 auto filters = SkPDFMakeArray();
447 filters->appendName("ASCII85Decode");
448 filters->appendName("FlateDecode");
449 dict.insertObject("Filter", std::move(filters));
450 }
451 #else
452 if (stream->getLength() > compressedData.bytesWritten() + kMinimumSavings) {
453 tmp = compressedData.detachAsStream();
454 stream = tmp.get();
455 dict.insertName("Filter", "FlateDecode");
456 } else {
457 SkAssertResult(stream->rewind());
458 }
459 #endif
460
461 }
462 dict.insertInt("Length", stream->getLength());
463 doc->emitStream(dict,
464 [stream](SkWStream* dst) { dst->writeStream(stream, stream->getLength()); },
465 ref);
466}
467
468SkPDFIndirectReference SkPDFStreamOut(std::unique_ptr<SkPDFDict> dict,
469 std::unique_ptr<SkStreamAsset> content,
470 SkPDFDocument* doc,
471 bool deflate) {
472 SkPDFIndirectReference ref = doc->reserveRef();
473 if (SkExecutor* executor = doc->executor()) {
474 SkPDFDict* dictPtr = dict.release();
475 SkStreamAsset* contentPtr = content.release();
476 // Pass ownership of both pointers into a std::function, which should
477 // only be executed once.
478 doc->incrementJobCount();
479 executor->add([dictPtr, contentPtr, deflate, doc, ref]() {
480 serialize_stream(dictPtr, contentPtr, deflate, doc, ref);
481 delete dictPtr;
482 delete contentPtr;
483 doc->signalJobComplete();
484 });
485 return ref;
486 }
487 serialize_stream(dict.get(), content.get(), deflate, doc, ref);
488 return ref;
489}
490