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