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