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 
25 SkPDFUnion::SkPDFUnion(Type t) : fType(t) {}
26 SkPDFUnion::SkPDFUnion(Type t, int32_t v)  : fIntValue    (v), fType(t) {}
27 SkPDFUnion::SkPDFUnion(Type t, bool v)     : fBoolValue   (v), fType(t) {}
28 SkPDFUnion::SkPDFUnion(Type t, SkScalar v) : fScalarValue (v), fType(t) {}
29 SkPDFUnion::SkPDFUnion(Type t, SkString v) : fType(t) { fSkString.init(std::move(v)); }
30 
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 
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 
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 
84 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.
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).
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 
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 
162 void SkPDFWriteString(SkWStream* wStream, const char* cin, size_t len) {
163     write_string(wStream, cin, len);
164 }
165 
166 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 
212 SkPDFUnion SkPDFUnion::Int(int32_t value) { return SkPDFUnion(Type::kInt, value); }
213 
214 SkPDFUnion SkPDFUnion::ColorComponent(uint8_t value) {
215     return SkPDFUnion(Type::kColorComponent, (int32_t)value);
216 }
217 
218 SkPDFUnion SkPDFUnion::ColorComponentF(float value) {
219     return SkPDFUnion(Type::kColorComponentF, (SkScalar)value);
220 }
221 
222 SkPDFUnion SkPDFUnion::Bool(bool value) {
223     return SkPDFUnion(Type::kBool, value);
224 }
225 
226 SkPDFUnion SkPDFUnion::Scalar(SkScalar value) {
227     return SkPDFUnion(Type::kScalar, value);
228 }
229 
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 
238 SkPDFUnion SkPDFUnion::String(const char* value) {
239     SkPDFUnion u(Type::kString);
240     SkASSERT(value);
241     u.fStaticString = value;
242     return u;
243 }
244 
245 SkPDFUnion SkPDFUnion::Name(SkString s) { return SkPDFUnion(Type::kNameSkS, std::move(s)); }
246 
247 SkPDFUnion SkPDFUnion::String(SkString s) { return SkPDFUnion(Type::kStringSkS, std::move(s)); }
248 
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 
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 
270 SkPDFArray::SkPDFArray() {}
271 
272 SkPDFArray::~SkPDFArray() {}
273 
274 size_t SkPDFArray::size() const { return fValues.size(); }
275 
276 void SkPDFArray::reserve(int length) {
277     fValues.reserve(length);
278 }
279 
280 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 
291 void SkPDFArray::append(SkPDFUnion&& value) {
292     fValues.emplace_back(std::move(value));
293 }
294 
295 void SkPDFArray::appendInt(int32_t value) {
296     this->append(SkPDFUnion::Int(value));
297 }
298 
299 void SkPDFArray::appendColorComponent(uint8_t value) {
300     this->append(SkPDFUnion::ColorComponent(value));
301 }
302 
303 void SkPDFArray::appendBool(bool value) {
304     this->append(SkPDFUnion::Bool(value));
305 }
306 
307 void SkPDFArray::appendScalar(SkScalar value) {
308     this->append(SkPDFUnion::Scalar(value));
309 }
310 
311 void SkPDFArray::appendName(const char name[]) {
312     this->append(SkPDFUnion::Name(SkString(name)));
313 }
314 
315 void SkPDFArray::appendName(SkString name) {
316     this->append(SkPDFUnion::Name(std::move(name)));
317 }
318 
319 void SkPDFArray::appendString(SkString value) {
320     this->append(SkPDFUnion::String(std::move(value)));
321 }
322 
323 void SkPDFArray::appendString(const char value[]) {
324     this->append(SkPDFUnion::String(value));
325 }
326 
327 void SkPDFArray::appendObject(std::unique_ptr<SkPDFObject>&& objSp) {
328     this->append(SkPDFUnion::Object(std::move(objSp)));
329 }
330 
331 void SkPDFArray::appendRef(SkPDFIndirectReference ref) {
332     this->append(SkPDFUnion::Ref(ref));
333 }
334 
335 ///////////////////////////////////////////////////////////////////////////////
336 
337 SkPDFDict::~SkPDFDict() {}
338 
339 SkPDFDict::SkPDFDict(const char type[]) {
340     if (type) {
341         this->insertName("Type", type);
342     }
343 }
344 
345 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 
359 size_t SkPDFDict::size() const { return fRecords.size(); }
360 
361 void SkPDFDict::reserve(int n) {
362     fRecords.reserve(n);
363 }
364 
365 void SkPDFDict::insertRef(const char key[], SkPDFIndirectReference ref) {
366     fRecords.emplace_back(SkPDFUnion::Name(key), SkPDFUnion::Ref(ref));
367 }
368 
369 void SkPDFDict::insertRef(SkString key, SkPDFIndirectReference ref) {
370     fRecords.emplace_back(SkPDFUnion::Name(std::move(key)), SkPDFUnion::Ref(ref));
371 }
372 
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 }
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 
381 void SkPDFDict::insertBool(const char key[], bool value) {
382     fRecords.emplace_back(SkPDFUnion::Name(key), SkPDFUnion::Bool(value));
383 }
384 
385 void SkPDFDict::insertInt(const char key[], int32_t value) {
386     fRecords.emplace_back(SkPDFUnion::Name(key), SkPDFUnion::Int(value));
387 }
388 
389 void SkPDFDict::insertInt(const char key[], size_t value) {
390     this->insertInt(key, SkToS32(value));
391 }
392 
393 void SkPDFDict::insertColorComponentF(const char key[], SkScalar value) {
394     fRecords.emplace_back(SkPDFUnion::Name(key), SkPDFUnion::ColorComponentF(value));
395 }
396 
397 void SkPDFDict::insertScalar(const char key[], SkScalar value) {
398     fRecords.emplace_back(SkPDFUnion::Name(key), SkPDFUnion::Scalar(value));
399 }
400 
401 void SkPDFDict::insertName(const char key[], const char name[]) {
402     fRecords.emplace_back(SkPDFUnion::Name(key), SkPDFUnion::Name(name));
403 }
404 
405 void SkPDFDict::insertName(const char key[], SkString name) {
406     fRecords.emplace_back(SkPDFUnion::Name(key), SkPDFUnion::Name(std::move(name)));
407 }
408 
409 void SkPDFDict::insertString(const char key[], const char value[]) {
410     fRecords.emplace_back(SkPDFUnion::Name(key), SkPDFUnion::String(value));
411 }
412 
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 
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 
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