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/base/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
SkPDFUnion(Type t,int32_t v)24 SkPDFUnion::SkPDFUnion(Type t, int32_t v) : fIntValue (v) , fType(t) {}
SkPDFUnion(Type t,bool v)25 SkPDFUnion::SkPDFUnion(Type t, bool v) : fBoolValue (v) , fType(t) {}
SkPDFUnion(Type t,SkScalar v)26 SkPDFUnion::SkPDFUnion(Type t, SkScalar v) : fScalarValue (v) , fType(t) {}
SkPDFUnion(Type t,const char * v)27 SkPDFUnion::SkPDFUnion(Type t, const char* v) : fStaticString (v) , fType(t) {}
SkPDFUnion(Type t,SkString v)28 SkPDFUnion::SkPDFUnion(Type t, SkString v) : fSkString(std::move(v)), fType(t) {}
SkPDFUnion(Type t,PDFObject v)29 SkPDFUnion::SkPDFUnion(Type t, PDFObject v) : fObject (std::move(v)), fType(t) {}
30
~SkPDFUnion()31 SkPDFUnion::~SkPDFUnion() {
32 switch (fType) {
33 case Type::kNameSkS:
34 case Type::kByteStringSkS:
35 case Type::kTextStringSkS:
36 fSkString.~SkString();
37 return;
38 case Type::kObject:
39 fObject.~PDFObject();
40 return;
41 default:
42 return;
43 }
44 }
45
SkPDFUnion(SkPDFUnion && that)46 SkPDFUnion::SkPDFUnion(SkPDFUnion&& that) : fType(that.fType) {
47 SkASSERT(this != &that);
48
49 switch (fType) {
50 case Type::kDestroyed:
51 break;
52 case Type::kInt:
53 case Type::kColorComponent:
54 case Type::kRef:
55 fIntValue = that.fIntValue;
56 break;
57 case Type::kBool:
58 fBoolValue = that.fBoolValue;
59 break;
60 case Type::kColorComponentF:
61 case Type::kScalar:
62 fScalarValue = that.fScalarValue;
63 break;
64 case Type::kName:
65 case Type::kByteString:
66 case Type::kTextString:
67 fStaticString = that.fStaticString;
68 break;
69 case Type::kNameSkS:
70 case Type::kByteStringSkS:
71 case Type::kTextStringSkS:
72 new (&fSkString) SkString(std::move(that.fSkString));
73 break;
74 case Type::kObject:
75 new (&fObject) PDFObject(std::move(that.fObject));
76 break;
77 default:
78 SkDEBUGFAIL("SkPDFUnion::SkPDFUnion with bad type");
79 }
80 that.fType = Type::kDestroyed;
81 }
82
operator =(SkPDFUnion && that)83 SkPDFUnion& SkPDFUnion::operator=(SkPDFUnion&& that) {
84 if (this != &that) {
85 this->~SkPDFUnion();
86 new (this) SkPDFUnion(std::move(that));
87 }
88 return *this;
89 }
90
isName() const91 bool SkPDFUnion::isName() const {
92 return Type::kName == fType || Type::kNameSkS == fType;
93 }
94
95 #ifdef SK_DEBUG
96 // Most names need no escaping. Such names are handled as static const strings.
is_valid_name(const char * n)97 bool is_valid_name(const char* n) {
98 static const char kControlChars[] = "/%()<>[]{}";
99 while (*n) {
100 if (*n < '!' || *n > '~' || strchr(kControlChars, *n)) {
101 return false;
102 }
103 ++n;
104 }
105 return true;
106 }
107 #endif // SK_DEBUG
108
109 // Given an arbitrary string, write it as a valid name (not including leading slash).
write_name_escaped(SkWStream * o,const char * name)110 static void write_name_escaped(SkWStream* o, const char* name) {
111 static const char kToEscape[] = "#/%()<>[]{}";
112 for (const uint8_t* n = reinterpret_cast<const uint8_t*>(name); *n; ++n) {
113 uint8_t v = *n;
114 if (v < '!' || v > '~' || strchr(kToEscape, v)) {
115 char buffer[3] = {'#',
116 SkHexadecimalDigits::gUpper[v >> 4],
117 SkHexadecimalDigits::gUpper[v & 0xF]};
118 o->write(buffer, sizeof(buffer));
119 } else {
120 o->write(n, 1);
121 }
122 }
123 }
124
write_literal_byte_string(SkWStream * wStream,const char * cin,size_t len)125 static void write_literal_byte_string(SkWStream* wStream, const char* cin, size_t len) {
126 wStream->writeText("(");
127 for (size_t i = 0; i < len; i++) {
128 uint8_t c = static_cast<uint8_t>(cin[i]);
129 if (c < ' ' || '~' < c) {
130 uint8_t octal[4] = { '\\',
131 (uint8_t)('0' | ( c >> 6 )),
132 (uint8_t)('0' | ((c >> 3) & 0x07)),
133 (uint8_t)('0' | ( c & 0x07)) };
134 wStream->write(octal, 4);
135 } else {
136 if (c == '\\' || c == '(' || c == ')') {
137 wStream->writeText("\\");
138 }
139 wStream->write(&c, 1);
140 }
141 }
142 wStream->writeText(")");
143 }
144
write_hex_byte_string(SkWStream * wStream,const char * cin,size_t len)145 static void write_hex_byte_string(SkWStream* wStream, const char* cin, size_t len) {
146 SkDEBUGCODE(static const size_t kMaxLen = 65535;)
147 SkASSERT(len <= kMaxLen);
148
149 wStream->writeText("<");
150 for (size_t i = 0; i < len; i++) {
151 uint8_t c = static_cast<uint8_t>(cin[i]);
152 char hexValue[2] = { SkHexadecimalDigits::gUpper[c >> 4],
153 SkHexadecimalDigits::gUpper[c & 0xF] };
154 wStream->write(hexValue, 2);
155 }
156 wStream->writeText(">");
157 }
158
write_optimized_byte_string(SkWStream * wStream,const char * cin,size_t len,size_t literalExtras)159 static void write_optimized_byte_string(SkWStream* wStream, const char* cin, size_t len,
160 size_t literalExtras) {
161 const size_t hexLength = 2 + 2*len;
162 const size_t literalLength = 2 + len + literalExtras;
163 if (literalLength <= hexLength) {
164 write_literal_byte_string(wStream, cin, len);
165 } else {
166 write_hex_byte_string(wStream, cin, len);
167 }
168 }
169
write_byte_string(SkWStream * wStream,const char * cin,size_t len)170 static void write_byte_string(SkWStream* wStream, const char* cin, size_t len) {
171 SkDEBUGCODE(static const size_t kMaxLen = 65535;)
172 SkASSERT(len <= kMaxLen);
173
174 size_t literalExtras = 0;
175 {
176 for (size_t i = 0; i < len; i++) {
177 uint8_t c = static_cast<uint8_t>(cin[i]);
178 if (c < ' ' || '~' < c) {
179 literalExtras += 3;
180 } else if (c == '\\' || c == '(' || c == ')') {
181 ++literalExtras;
182 }
183 }
184 }
185 write_optimized_byte_string(wStream, cin, len, literalExtras);
186 }
187
write_text_string(SkWStream * wStream,const char * cin,size_t len)188 static void write_text_string(SkWStream* wStream, const char* cin, size_t len) {
189 SkDEBUGCODE(static const size_t kMaxLen = 65535;)
190 SkASSERT(len <= kMaxLen);
191
192 bool inputIsValidUTF8 = true;
193 bool inputIsPDFDocEncoding = true;
194 size_t literalExtras = 0;
195 {
196 const char* textPtr = cin;
197 const char* textEnd = cin + len;
198 while (textPtr < textEnd) {
199 SkUnichar unichar = SkUTF::NextUTF8(&textPtr, textEnd);
200 if (unichar < 0) {
201 inputIsValidUTF8 = false;
202 break;
203 }
204 // See Table D.2 (PDFDocEncoding Character Set) in the PDF3200_2008 spec.
205 // Could convert from UTF-8 to PDFDocEncoding and, if successful, use that.
206 if ((0x15 < unichar && unichar < 0x20) || 0x7E < unichar) {
207 inputIsPDFDocEncoding = false;
208 break;
209 }
210 if (unichar < ' ' || '~' < unichar) {
211 literalExtras += 3;
212 } else if (unichar == '\\' || unichar == '(' || unichar == ')') {
213 ++literalExtras;
214 }
215 }
216 }
217
218 if (!inputIsValidUTF8) {
219 SkDebugf("Invalid UTF8: %.*s\n", (int)len, cin);
220 wStream->writeText("<>");
221 return;
222 }
223
224 if (inputIsPDFDocEncoding) {
225 write_optimized_byte_string(wStream, cin, len, literalExtras);
226 return;
227 }
228
229 wStream->writeText("<FEFF");
230 const char* textPtr = cin;
231 const char* textEnd = cin + len;
232 while (textPtr < textEnd) {
233 SkUnichar unichar = SkUTF::NextUTF8(&textPtr, textEnd);
234 SkPDFUtils::WriteUTF16beHex(wStream, unichar);
235 }
236 wStream->writeText(">");
237 }
238
SkPDFWriteTextString(SkWStream * wStream,const char * cin,size_t len)239 void SkPDFWriteTextString(SkWStream* wStream, const char* cin, size_t len) {
240 write_text_string(wStream, cin, len);
241 }
SkPDFWriteByteString(SkWStream * wStream,const char * cin,size_t len)242 void SkPDFWriteByteString(SkWStream* wStream, const char* cin, size_t len) {
243 write_byte_string(wStream, cin, len);
244 }
245
emitObject(SkWStream * stream) const246 void SkPDFUnion::emitObject(SkWStream* stream) const {
247 switch (fType) {
248 case Type::kInt:
249 stream->writeDecAsText(fIntValue);
250 return;
251 case Type::kColorComponent:
252 SkPDFUtils::AppendColorComponent(SkToU8(fIntValue), stream);
253 return;
254 case Type::kColorComponentF:
255 SkPDFUtils::AppendColorComponentF(fScalarValue, stream);
256 return;
257 case Type::kBool:
258 stream->writeText(fBoolValue ? "true" : "false");
259 return;
260 case Type::kScalar:
261 SkPDFUtils::AppendScalar(fScalarValue, stream);
262 return;
263 case Type::kName:
264 stream->writeText("/");
265 SkASSERT(is_valid_name(fStaticString));
266 stream->writeText(fStaticString);
267 return;
268 case Type::kByteString:
269 SkASSERT(fStaticString);
270 write_byte_string(stream, fStaticString, strlen(fStaticString));
271 return;
272 case Type::kTextString:
273 SkASSERT(fStaticString);
274 write_text_string(stream, fStaticString, strlen(fStaticString));
275 return;
276 case Type::kNameSkS:
277 stream->writeText("/");
278 write_name_escaped(stream, fSkString.c_str());
279 return;
280 case Type::kByteStringSkS:
281 write_byte_string(stream, fSkString.c_str(), fSkString.size());
282 return;
283 case Type::kTextStringSkS:
284 write_text_string(stream, fSkString.c_str(), fSkString.size());
285 return;
286 case Type::kObject:
287 fObject->emitObject(stream);
288 return;
289 case Type::kRef:
290 SkASSERT(fIntValue >= 0);
291 stream->writeDecAsText(fIntValue);
292 stream->writeText(" 0 R"); // Generation number is always 0.
293 return;
294 default:
295 SkDEBUGFAIL("SkPDFUnion::emitObject with bad type");
296 }
297 }
298
Int(int32_t value)299 SkPDFUnion SkPDFUnion::Int(int32_t value) {
300 return SkPDFUnion(Type::kInt, value);
301 }
302
ColorComponent(uint8_t value)303 SkPDFUnion SkPDFUnion::ColorComponent(uint8_t value) {
304 return SkPDFUnion(Type::kColorComponent, SkTo<int32_t>(value));
305 }
306
ColorComponentF(float value)307 SkPDFUnion SkPDFUnion::ColorComponentF(float value) {
308 return SkPDFUnion(Type::kColorComponentF, SkFloatToScalar(value));
309 }
310
Bool(bool value)311 SkPDFUnion SkPDFUnion::Bool(bool value) {
312 return SkPDFUnion(Type::kBool, value);
313 }
314
Scalar(SkScalar value)315 SkPDFUnion SkPDFUnion::Scalar(SkScalar value) {
316 return SkPDFUnion(Type::kScalar, value);
317 }
318
Name(const char * value)319 SkPDFUnion SkPDFUnion::Name(const char* value) {
320 SkASSERT(value);
321 SkASSERT(is_valid_name(value));
322 return SkPDFUnion(Type::kName, value);
323 }
324
ByteString(const char * value)325 SkPDFUnion SkPDFUnion::ByteString(const char* value) {
326 SkASSERT(value);
327 return SkPDFUnion(Type::kByteString, value);
328 }
329
TextString(const char * value)330 SkPDFUnion SkPDFUnion::TextString(const char* value) {
331 SkASSERT(value);
332 return SkPDFUnion(Type::kTextString, value);
333 }
334
Name(SkString s)335 SkPDFUnion SkPDFUnion::Name(SkString s) {
336 return SkPDFUnion(Type::kNameSkS, std::move(s));
337 }
338
ByteString(SkString s)339 SkPDFUnion SkPDFUnion::ByteString(SkString s) {
340 return SkPDFUnion(Type::kByteStringSkS, std::move(s));
341 }
342
TextString(SkString s)343 SkPDFUnion SkPDFUnion::TextString(SkString s) {
344 return SkPDFUnion(Type::kTextStringSkS, std::move(s));
345 }
346
Object(std::unique_ptr<SkPDFObject> objSp)347 SkPDFUnion SkPDFUnion::Object(std::unique_ptr<SkPDFObject> objSp) {
348 SkASSERT(objSp.get());
349 return SkPDFUnion(Type::kObject, std::move(objSp));
350 }
351
Ref(SkPDFIndirectReference ref)352 SkPDFUnion SkPDFUnion::Ref(SkPDFIndirectReference ref) {
353 SkASSERT(ref.fValue > 0);
354 return SkPDFUnion(Type::kRef, SkTo<int32_t>(ref.fValue));
355 }
356
357 ////////////////////////////////////////////////////////////////////////////////
358
359 #if 0 // Enable if needed.
360 void SkPDFAtom::emitObject(SkWStream* stream) const {
361 fValue.emitObject(stream);
362 }
363 #endif // 0
364
365 ////////////////////////////////////////////////////////////////////////////////
366
SkPDFArray()367 SkPDFArray::SkPDFArray() {}
368
~SkPDFArray()369 SkPDFArray::~SkPDFArray() {}
370
size() const371 size_t SkPDFArray::size() const { return fValues.size(); }
372
reserve(int length)373 void SkPDFArray::reserve(int length) {
374 fValues.reserve(length);
375 }
376
emitObject(SkWStream * stream) const377 void SkPDFArray::emitObject(SkWStream* stream) const {
378 stream->writeText("[");
379 for (size_t i = 0; i < fValues.size(); i++) {
380 fValues[i].emitObject(stream);
381 if (i + 1 < fValues.size()) {
382 stream->writeText(" ");
383 }
384 }
385 stream->writeText("]");
386 }
387
append(SkPDFUnion && value)388 void SkPDFArray::append(SkPDFUnion&& value) {
389 fValues.emplace_back(std::move(value));
390 }
391
appendInt(int32_t value)392 void SkPDFArray::appendInt(int32_t value) {
393 this->append(SkPDFUnion::Int(value));
394 }
395
appendColorComponent(uint8_t value)396 void SkPDFArray::appendColorComponent(uint8_t value) {
397 this->append(SkPDFUnion::ColorComponent(value));
398 }
399
appendBool(bool value)400 void SkPDFArray::appendBool(bool value) {
401 this->append(SkPDFUnion::Bool(value));
402 }
403
appendScalar(SkScalar value)404 void SkPDFArray::appendScalar(SkScalar value) {
405 this->append(SkPDFUnion::Scalar(value));
406 }
407
appendName(const char name[])408 void SkPDFArray::appendName(const char name[]) {
409 this->append(SkPDFUnion::Name(SkString(name)));
410 }
411
appendName(SkString name)412 void SkPDFArray::appendName(SkString name) {
413 this->append(SkPDFUnion::Name(std::move(name)));
414 }
415
appendByteString(SkString value)416 void SkPDFArray::appendByteString(SkString value) {
417 this->append(SkPDFUnion::ByteString(std::move(value)));
418 }
419
appendTextString(SkString value)420 void SkPDFArray::appendTextString(SkString value) {
421 this->append(SkPDFUnion::TextString(std::move(value)));
422 }
423
appendByteString(const char value[])424 void SkPDFArray::appendByteString(const char value[]) {
425 this->append(SkPDFUnion::ByteString(value));
426 }
427
appendTextString(const char value[])428 void SkPDFArray::appendTextString(const char value[]) {
429 this->append(SkPDFUnion::TextString(value));
430 }
431
appendObject(std::unique_ptr<SkPDFObject> && objSp)432 void SkPDFArray::appendObject(std::unique_ptr<SkPDFObject>&& objSp) {
433 this->append(SkPDFUnion::Object(std::move(objSp)));
434 }
435
appendRef(SkPDFIndirectReference ref)436 void SkPDFArray::appendRef(SkPDFIndirectReference ref) {
437 this->append(SkPDFUnion::Ref(ref));
438 }
439
440 ///////////////////////////////////////////////////////////////////////////////
441
~SkPDFDict()442 SkPDFDict::~SkPDFDict() {}
443
SkPDFDict(const char type[])444 SkPDFDict::SkPDFDict(const char type[]) {
445 if (type) {
446 this->insertName("Type", type);
447 }
448 }
449
emitObject(SkWStream * stream) const450 void SkPDFDict::emitObject(SkWStream* stream) const {
451 stream->writeText("<<");
452 for (size_t i = 0; i < fRecords.size(); ++i) {
453 const std::pair<SkPDFUnion, SkPDFUnion>& record = fRecords[i];
454 record.first.emitObject(stream);
455 stream->writeText(" ");
456 record.second.emitObject(stream);
457 if (i + 1 < fRecords.size()) {
458 stream->writeText("\n");
459 }
460 }
461 stream->writeText(">>");
462 }
463
size() const464 size_t SkPDFDict::size() const { return fRecords.size(); }
465
reserve(int n)466 void SkPDFDict::reserve(int n) {
467 fRecords.reserve(n);
468 }
469
insertRef(const char key[],SkPDFIndirectReference ref)470 void SkPDFDict::insertRef(const char key[], SkPDFIndirectReference ref) {
471 fRecords.emplace_back(SkPDFUnion::Name(key), SkPDFUnion::Ref(ref));
472 }
473
insertRef(SkString key,SkPDFIndirectReference ref)474 void SkPDFDict::insertRef(SkString key, SkPDFIndirectReference ref) {
475 fRecords.emplace_back(SkPDFUnion::Name(std::move(key)), SkPDFUnion::Ref(ref));
476 }
477
insertObject(const char key[],std::unique_ptr<SkPDFObject> && objSp)478 void SkPDFDict::insertObject(const char key[], std::unique_ptr<SkPDFObject>&& objSp) {
479 fRecords.emplace_back(SkPDFUnion::Name(key), SkPDFUnion::Object(std::move(objSp)));
480 }
insertObject(SkString key,std::unique_ptr<SkPDFObject> && objSp)481 void SkPDFDict::insertObject(SkString key, std::unique_ptr<SkPDFObject>&& objSp) {
482 fRecords.emplace_back(SkPDFUnion::Name(std::move(key)),
483 SkPDFUnion::Object(std::move(objSp)));
484 }
485
insertBool(const char key[],bool value)486 void SkPDFDict::insertBool(const char key[], bool value) {
487 fRecords.emplace_back(SkPDFUnion::Name(key), SkPDFUnion::Bool(value));
488 }
489
insertInt(const char key[],int32_t value)490 void SkPDFDict::insertInt(const char key[], int32_t value) {
491 fRecords.emplace_back(SkPDFUnion::Name(key), SkPDFUnion::Int(value));
492 }
493
insertInt(const char key[],size_t value)494 void SkPDFDict::insertInt(const char key[], size_t value) {
495 this->insertInt(key, SkToS32(value));
496 }
497
insertColorComponentF(const char key[],SkScalar value)498 void SkPDFDict::insertColorComponentF(const char key[], SkScalar value) {
499 fRecords.emplace_back(SkPDFUnion::Name(key), SkPDFUnion::ColorComponentF(value));
500 }
501
insertScalar(const char key[],SkScalar value)502 void SkPDFDict::insertScalar(const char key[], SkScalar value) {
503 fRecords.emplace_back(SkPDFUnion::Name(key), SkPDFUnion::Scalar(value));
504 }
505
insertName(const char key[],const char name[])506 void SkPDFDict::insertName(const char key[], const char name[]) {
507 fRecords.emplace_back(SkPDFUnion::Name(key), SkPDFUnion::Name(name));
508 }
509
insertName(const char key[],SkString name)510 void SkPDFDict::insertName(const char key[], SkString name) {
511 fRecords.emplace_back(SkPDFUnion::Name(key), SkPDFUnion::Name(std::move(name)));
512 }
513
insertByteString(const char key[],const char value[])514 void SkPDFDict::insertByteString(const char key[], const char value[]) {
515 fRecords.emplace_back(SkPDFUnion::Name(key), SkPDFUnion::ByteString(value));
516 }
517
insertTextString(const char key[],const char value[])518 void SkPDFDict::insertTextString(const char key[], const char value[]) {
519 fRecords.emplace_back(SkPDFUnion::Name(key), SkPDFUnion::TextString(value));
520 }
521
insertByteString(const char key[],SkString value)522 void SkPDFDict::insertByteString(const char key[], SkString value) {
523 fRecords.emplace_back(SkPDFUnion::Name(key), SkPDFUnion::ByteString(std::move(value)));
524 }
525
insertTextString(const char key[],SkString value)526 void SkPDFDict::insertTextString(const char key[], SkString value) {
527 fRecords.emplace_back(SkPDFUnion::Name(key), SkPDFUnion::TextString(std::move(value)));
528 }
529
530 ////////////////////////////////////////////////////////////////////////////////
531
532
533
serialize_stream(SkPDFDict * origDict,SkStreamAsset * stream,SkPDFSteamCompressionEnabled compress,SkPDFDocument * doc,SkPDFIndirectReference ref)534 static void serialize_stream(SkPDFDict* origDict,
535 SkStreamAsset* stream,
536 SkPDFSteamCompressionEnabled compress,
537 SkPDFDocument* doc,
538 SkPDFIndirectReference ref) {
539 // Code assumes that the stream starts at the beginning.
540 SkASSERT(stream && stream->hasLength());
541
542 std::unique_ptr<SkStreamAsset> tmp;
543 SkPDFDict tmpDict;
544 SkPDFDict& dict = origDict ? *origDict : tmpDict;
545 static const size_t kMinimumSavings = strlen("/Filter_/FlateDecode_");
546 if (doc->metadata().fCompressionLevel != SkPDF::Metadata::CompressionLevel::None &&
547 compress == SkPDFSteamCompressionEnabled::Yes &&
548 stream->getLength() > kMinimumSavings)
549 {
550 SkDynamicMemoryWStream compressedData;
551 SkDeflateWStream deflateWStream(&compressedData,SkToInt(doc->metadata().fCompressionLevel));
552 SkStreamCopy(&deflateWStream, stream);
553 deflateWStream.finalize();
554 #ifdef SK_PDF_BASE85_BINARY
555 {
556 SkPDFUtils::Base85Encode(compressedData.detachAsStream(), &compressedData);
557 tmp = compressedData.detachAsStream();
558 stream = tmp.get();
559 auto filters = SkPDFMakeArray();
560 filters->appendName("ASCII85Decode");
561 filters->appendName("FlateDecode");
562 dict.insertObject("Filter", std::move(filters));
563 }
564 #else
565 if (stream->getLength() > compressedData.bytesWritten() + kMinimumSavings) {
566 tmp = compressedData.detachAsStream();
567 stream = tmp.get();
568 dict.insertName("Filter", "FlateDecode");
569 } else {
570 SkAssertResult(stream->rewind());
571 }
572 #endif
573
574 }
575 dict.insertInt("Length", stream->getLength());
576 doc->emitStream(dict,
577 [stream](SkWStream* dst) { dst->writeStream(stream, stream->getLength()); },
578 ref);
579 }
580
SkPDFStreamOut(std::unique_ptr<SkPDFDict> dict,std::unique_ptr<SkStreamAsset> content,SkPDFDocument * doc,SkPDFSteamCompressionEnabled compress)581 SkPDFIndirectReference SkPDFStreamOut(std::unique_ptr<SkPDFDict> dict,
582 std::unique_ptr<SkStreamAsset> content,
583 SkPDFDocument* doc,
584 SkPDFSteamCompressionEnabled compress) {
585 SkPDFIndirectReference ref = doc->reserveRef();
586 if (SkExecutor* executor = doc->executor()) {
587 SkPDFDict* dictPtr = dict.release();
588 SkStreamAsset* contentPtr = content.release();
589 // Pass ownership of both pointers into a std::function, which should
590 // only be executed once.
591 doc->incrementJobCount();
592 executor->add([dictPtr, contentPtr, compress, doc, ref]() {
593 serialize_stream(dictPtr, contentPtr, compress, doc, ref);
594 delete dictPtr;
595 delete contentPtr;
596 doc->signalJobComplete();
597 });
598 return ref;
599 }
600 serialize_stream(dict.get(), content.get(), compress, doc, ref);
601 return ref;
602 }
603