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 | |
24 | SkPDFUnion::SkPDFUnion(Type t, int32_t v) : fIntValue (v) , fType(t) {} |
25 | SkPDFUnion::SkPDFUnion(Type t, bool v) : fBoolValue (v) , fType(t) {} |
26 | SkPDFUnion::SkPDFUnion(Type t, SkScalar v) : fScalarValue (v) , fType(t) {} |
27 | SkPDFUnion::SkPDFUnion(Type t, const char* v) : fStaticString (v) , fType(t) {} |
28 | SkPDFUnion::SkPDFUnion(Type t, SkString v) : fSkString(std::move(v)), fType(t) {} |
29 | SkPDFUnion::SkPDFUnion(Type t, PDFObject v) : fObject (std::move(v)), fType(t) {} |
30 | |
31 | SkPDFUnion::~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 | |
45 | SkPDFUnion::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 | |
80 | SkPDFUnion& SkPDFUnion::operator=(SkPDFUnion&& that) { |
81 | if (this != &that) { |
82 | this->~SkPDFUnion(); |
83 | new (this) SkPDFUnion(std::move(that)); |
84 | } |
85 | return *this; |
86 | } |
87 | |
88 | bool 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. |
94 | bool 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). |
107 | static 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 | |
122 | static 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 = 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 | |
164 | void SkPDFWriteString(SkWStream* wStream, const char* cin, size_t len) { |
165 | write_string(wStream, cin, len); |
166 | } |
167 | |
168 | void 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 | |
214 | SkPDFUnion SkPDFUnion::Int(int32_t value) { |
215 | return SkPDFUnion(Type::kInt, value); |
216 | } |
217 | |
218 | SkPDFUnion SkPDFUnion::ColorComponent(uint8_t value) { |
219 | return SkPDFUnion(Type::kColorComponent, SkTo<int32_t>(value)); |
220 | } |
221 | |
222 | SkPDFUnion SkPDFUnion::ColorComponentF(float value) { |
223 | return SkPDFUnion(Type::kColorComponentF, SkFloatToScalar(value)); |
224 | } |
225 | |
226 | SkPDFUnion SkPDFUnion::Bool(bool value) { |
227 | return SkPDFUnion(Type::kBool, value); |
228 | } |
229 | |
230 | SkPDFUnion SkPDFUnion::Scalar(SkScalar value) { |
231 | return SkPDFUnion(Type::kScalar, value); |
232 | } |
233 | |
234 | SkPDFUnion SkPDFUnion::Name(const char* value) { |
235 | SkASSERT(value); |
236 | SkASSERT(is_valid_name(value)); |
237 | return SkPDFUnion(Type::kName, value); |
238 | } |
239 | |
240 | SkPDFUnion SkPDFUnion::String(const char* value) { |
241 | SkASSERT(value); |
242 | return SkPDFUnion(Type::kString, value); |
243 | } |
244 | |
245 | SkPDFUnion SkPDFUnion::Name(SkString s) { |
246 | return SkPDFUnion(Type::kNameSkS, std::move(s)); |
247 | } |
248 | |
249 | SkPDFUnion SkPDFUnion::String(SkString s) { |
250 | return SkPDFUnion(Type::kStringSkS, std::move(s)); |
251 | } |
252 | |
253 | SkPDFUnion SkPDFUnion::Object(std::unique_ptr<SkPDFObject> objSp) { |
254 | SkASSERT(objSp.get()); |
255 | return SkPDFUnion(Type::kObject, std::move(objSp)); |
256 | } |
257 | |
258 | SkPDFUnion 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. |
266 | void SkPDFAtom::emitObject(SkWStream* stream) const { |
267 | fValue.emitObject(stream); |
268 | } |
269 | #endif // 0 |
270 | |
271 | //////////////////////////////////////////////////////////////////////////////// |
272 | |
273 | SkPDFArray::SkPDFArray() {} |
274 | |
275 | SkPDFArray::~SkPDFArray() {} |
276 | |
277 | size_t SkPDFArray::size() const { return fValues.size(); } |
278 | |
279 | void SkPDFArray::reserve(int length) { |
280 | fValues.reserve(length); |
281 | } |
282 | |
283 | void 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 | |
294 | void SkPDFArray::append(SkPDFUnion&& value) { |
295 | fValues.emplace_back(std::move(value)); |
296 | } |
297 | |
298 | void SkPDFArray::appendInt(int32_t value) { |
299 | this->append(SkPDFUnion::Int(value)); |
300 | } |
301 | |
302 | void SkPDFArray::appendColorComponent(uint8_t value) { |
303 | this->append(SkPDFUnion::ColorComponent(value)); |
304 | } |
305 | |
306 | void SkPDFArray::appendBool(bool value) { |
307 | this->append(SkPDFUnion::Bool(value)); |
308 | } |
309 | |
310 | void SkPDFArray::appendScalar(SkScalar value) { |
311 | this->append(SkPDFUnion::Scalar(value)); |
312 | } |
313 | |
314 | void SkPDFArray::appendName(const char name[]) { |
315 | this->append(SkPDFUnion::Name(SkString(name))); |
316 | } |
317 | |
318 | void SkPDFArray::appendName(SkString name) { |
319 | this->append(SkPDFUnion::Name(std::move(name))); |
320 | } |
321 | |
322 | void SkPDFArray::appendString(SkString value) { |
323 | this->append(SkPDFUnion::String(std::move(value))); |
324 | } |
325 | |
326 | void SkPDFArray::appendString(const char value[]) { |
327 | this->append(SkPDFUnion::String(value)); |
328 | } |
329 | |
330 | void SkPDFArray::appendObject(std::unique_ptr<SkPDFObject>&& objSp) { |
331 | this->append(SkPDFUnion::Object(std::move(objSp))); |
332 | } |
333 | |
334 | void SkPDFArray::appendRef(SkPDFIndirectReference ref) { |
335 | this->append(SkPDFUnion::Ref(ref)); |
336 | } |
337 | |
338 | /////////////////////////////////////////////////////////////////////////////// |
339 | |
340 | SkPDFDict::~SkPDFDict() {} |
341 | |
342 | SkPDFDict::SkPDFDict(const char type[]) { |
343 | if (type) { |
344 | this->insertName("Type" , type); |
345 | } |
346 | } |
347 | |
348 | void 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 | |
362 | size_t SkPDFDict::size() const { return fRecords.size(); } |
363 | |
364 | void SkPDFDict::reserve(int n) { |
365 | fRecords.reserve(n); |
366 | } |
367 | |
368 | void SkPDFDict::insertRef(const char key[], SkPDFIndirectReference ref) { |
369 | fRecords.emplace_back(SkPDFUnion::Name(key), SkPDFUnion::Ref(ref)); |
370 | } |
371 | |
372 | void SkPDFDict::insertRef(SkString key, SkPDFIndirectReference ref) { |
373 | fRecords.emplace_back(SkPDFUnion::Name(std::move(key)), SkPDFUnion::Ref(ref)); |
374 | } |
375 | |
376 | void SkPDFDict::insertObject(const char key[], std::unique_ptr<SkPDFObject>&& objSp) { |
377 | fRecords.emplace_back(SkPDFUnion::Name(key), SkPDFUnion::Object(std::move(objSp))); |
378 | } |
379 | void 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 | |
384 | void SkPDFDict::insertBool(const char key[], bool value) { |
385 | fRecords.emplace_back(SkPDFUnion::Name(key), SkPDFUnion::Bool(value)); |
386 | } |
387 | |
388 | void SkPDFDict::insertInt(const char key[], int32_t value) { |
389 | fRecords.emplace_back(SkPDFUnion::Name(key), SkPDFUnion::Int(value)); |
390 | } |
391 | |
392 | void SkPDFDict::insertInt(const char key[], size_t value) { |
393 | this->insertInt(key, SkToS32(value)); |
394 | } |
395 | |
396 | void SkPDFDict::insertColorComponentF(const char key[], SkScalar value) { |
397 | fRecords.emplace_back(SkPDFUnion::Name(key), SkPDFUnion::ColorComponentF(value)); |
398 | } |
399 | |
400 | void SkPDFDict::insertScalar(const char key[], SkScalar value) { |
401 | fRecords.emplace_back(SkPDFUnion::Name(key), SkPDFUnion::Scalar(value)); |
402 | } |
403 | |
404 | void SkPDFDict::insertName(const char key[], const char name[]) { |
405 | fRecords.emplace_back(SkPDFUnion::Name(key), SkPDFUnion::Name(name)); |
406 | } |
407 | |
408 | void SkPDFDict::insertName(const char key[], SkString name) { |
409 | fRecords.emplace_back(SkPDFUnion::Name(key), SkPDFUnion::Name(std::move(name))); |
410 | } |
411 | |
412 | void SkPDFDict::insertString(const char key[], const char value[]) { |
413 | fRecords.emplace_back(SkPDFUnion::Name(key), SkPDFUnion::String(value)); |
414 | } |
415 | |
416 | void 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 | |
424 | static 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 | |
468 | SkPDFIndirectReference 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 | |