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
emitObject(SkWStream * stream) const394 void SkPDFOptionalArray::emitObject(SkWStream* stream) const {
395 if (this->size() == 1) {
396 this->values()[0].emitObject(stream);
397 } else {
398 this->SkPDFArray::emitObject(stream);
399 }
400 }
401
append(SkPDFUnion && value)402 void SkPDFArray::append(SkPDFUnion&& value) {
403 fValues.emplace_back(std::move(value));
404 }
405
appendInt(int32_t value)406 void SkPDFArray::appendInt(int32_t value) {
407 this->append(SkPDFUnion::Int(value));
408 }
409
appendColorComponent(uint8_t value)410 void SkPDFArray::appendColorComponent(uint8_t value) {
411 this->append(SkPDFUnion::ColorComponent(value));
412 }
413
appendBool(bool value)414 void SkPDFArray::appendBool(bool value) {
415 this->append(SkPDFUnion::Bool(value));
416 }
417
appendScalar(SkScalar value)418 void SkPDFArray::appendScalar(SkScalar value) {
419 this->append(SkPDFUnion::Scalar(value));
420 }
421
appendName(const char name[])422 void SkPDFArray::appendName(const char name[]) {
423 this->append(SkPDFUnion::Name(SkString(name)));
424 }
425
appendName(SkString name)426 void SkPDFArray::appendName(SkString name) {
427 this->append(SkPDFUnion::Name(std::move(name)));
428 }
429
appendByteString(SkString value)430 void SkPDFArray::appendByteString(SkString value) {
431 this->append(SkPDFUnion::ByteString(std::move(value)));
432 }
433
appendTextString(SkString value)434 void SkPDFArray::appendTextString(SkString value) {
435 this->append(SkPDFUnion::TextString(std::move(value)));
436 }
437
appendByteString(const char value[])438 void SkPDFArray::appendByteString(const char value[]) {
439 this->append(SkPDFUnion::ByteString(value));
440 }
441
appendTextString(const char value[])442 void SkPDFArray::appendTextString(const char value[]) {
443 this->append(SkPDFUnion::TextString(value));
444 }
445
appendObject(std::unique_ptr<SkPDFObject> && objSp)446 void SkPDFArray::appendObject(std::unique_ptr<SkPDFObject>&& objSp) {
447 this->append(SkPDFUnion::Object(std::move(objSp)));
448 }
449
appendRef(SkPDFIndirectReference ref)450 void SkPDFArray::appendRef(SkPDFIndirectReference ref) {
451 this->append(SkPDFUnion::Ref(ref));
452 }
453
454 ///////////////////////////////////////////////////////////////////////////////
455
~SkPDFDict()456 SkPDFDict::~SkPDFDict() {}
457
SkPDFDict(const char type[])458 SkPDFDict::SkPDFDict(const char type[]) {
459 if (type) {
460 this->insertName("Type", type);
461 }
462 }
463
emitObject(SkWStream * stream) const464 void SkPDFDict::emitObject(SkWStream* stream) const {
465 stream->writeText("<<");
466 for (size_t i = 0; i < fRecords.size(); ++i) {
467 const std::pair<SkPDFUnion, SkPDFUnion>& record = fRecords[i];
468 record.first.emitObject(stream);
469 stream->writeText(" ");
470 record.second.emitObject(stream);
471 if (i + 1 < fRecords.size()) {
472 stream->writeText("\n");
473 }
474 }
475 stream->writeText(">>");
476 }
477
size() const478 size_t SkPDFDict::size() const { return fRecords.size(); }
479
reserve(int n)480 void SkPDFDict::reserve(int n) {
481 fRecords.reserve(n);
482 }
483
insertRef(const char key[],SkPDFIndirectReference ref)484 void SkPDFDict::insertRef(const char key[], SkPDFIndirectReference ref) {
485 fRecords.emplace_back(SkPDFUnion::Name(key), SkPDFUnion::Ref(ref));
486 }
487
insertRef(SkString key,SkPDFIndirectReference ref)488 void SkPDFDict::insertRef(SkString key, SkPDFIndirectReference ref) {
489 fRecords.emplace_back(SkPDFUnion::Name(std::move(key)), SkPDFUnion::Ref(ref));
490 }
491
insertObject(const char key[],std::unique_ptr<SkPDFObject> && objSp)492 void SkPDFDict::insertObject(const char key[], std::unique_ptr<SkPDFObject>&& objSp) {
493 fRecords.emplace_back(SkPDFUnion::Name(key), SkPDFUnion::Object(std::move(objSp)));
494 }
insertObject(SkString key,std::unique_ptr<SkPDFObject> && objSp)495 void SkPDFDict::insertObject(SkString key, std::unique_ptr<SkPDFObject>&& objSp) {
496 fRecords.emplace_back(SkPDFUnion::Name(std::move(key)),
497 SkPDFUnion::Object(std::move(objSp)));
498 }
499
insertBool(const char key[],bool value)500 void SkPDFDict::insertBool(const char key[], bool value) {
501 fRecords.emplace_back(SkPDFUnion::Name(key), SkPDFUnion::Bool(value));
502 }
503
insertInt(const char key[],int32_t value)504 void SkPDFDict::insertInt(const char key[], int32_t value) {
505 fRecords.emplace_back(SkPDFUnion::Name(key), SkPDFUnion::Int(value));
506 }
507
insertInt(const char key[],size_t value)508 void SkPDFDict::insertInt(const char key[], size_t value) {
509 this->insertInt(key, SkToS32(value));
510 }
511
insertColorComponentF(const char key[],SkScalar value)512 void SkPDFDict::insertColorComponentF(const char key[], SkScalar value) {
513 fRecords.emplace_back(SkPDFUnion::Name(key), SkPDFUnion::ColorComponentF(value));
514 }
515
insertScalar(const char key[],SkScalar value)516 void SkPDFDict::insertScalar(const char key[], SkScalar value) {
517 fRecords.emplace_back(SkPDFUnion::Name(key), SkPDFUnion::Scalar(value));
518 }
519
insertName(const char key[],const char name[])520 void SkPDFDict::insertName(const char key[], const char name[]) {
521 fRecords.emplace_back(SkPDFUnion::Name(key), SkPDFUnion::Name(name));
522 }
523
insertName(const char key[],SkString name)524 void SkPDFDict::insertName(const char key[], SkString name) {
525 fRecords.emplace_back(SkPDFUnion::Name(key), SkPDFUnion::Name(std::move(name)));
526 }
527
insertByteString(const char key[],const char value[])528 void SkPDFDict::insertByteString(const char key[], const char value[]) {
529 fRecords.emplace_back(SkPDFUnion::Name(key), SkPDFUnion::ByteString(value));
530 }
531
insertTextString(const char key[],const char value[])532 void SkPDFDict::insertTextString(const char key[], const char value[]) {
533 fRecords.emplace_back(SkPDFUnion::Name(key), SkPDFUnion::TextString(value));
534 }
535
insertByteString(const char key[],SkString value)536 void SkPDFDict::insertByteString(const char key[], SkString value) {
537 fRecords.emplace_back(SkPDFUnion::Name(key), SkPDFUnion::ByteString(std::move(value)));
538 }
539
insertTextString(const char key[],SkString value)540 void SkPDFDict::insertTextString(const char key[], SkString value) {
541 fRecords.emplace_back(SkPDFUnion::Name(key), SkPDFUnion::TextString(std::move(value)));
542 }
543
insertUnion(const char key[],SkPDFUnion && value)544 void SkPDFDict::insertUnion(const char key[], SkPDFUnion&& value) {
545 fRecords.emplace_back(SkPDFUnion::Name(key), std::move(value));
546 }
547
548 ////////////////////////////////////////////////////////////////////////////////
549
550
551
serialize_stream(SkPDFDict * origDict,SkStreamAsset * stream,SkPDFSteamCompressionEnabled compress,SkPDFDocument * doc,SkPDFIndirectReference ref)552 static void serialize_stream(SkPDFDict* origDict,
553 SkStreamAsset* stream,
554 SkPDFSteamCompressionEnabled compress,
555 SkPDFDocument* doc,
556 SkPDFIndirectReference ref) {
557 // Code assumes that the stream starts at the beginning.
558 SkASSERT(stream && stream->hasLength());
559
560 std::unique_ptr<SkStreamAsset> tmp;
561 SkPDFDict tmpDict;
562 SkPDFDict& dict = origDict ? *origDict : tmpDict;
563 static const size_t kMinimumSavings = strlen("/Filter_/FlateDecode_");
564 if (doc->metadata().fCompressionLevel != SkPDF::Metadata::CompressionLevel::None &&
565 compress == SkPDFSteamCompressionEnabled::Yes &&
566 stream->getLength() > kMinimumSavings)
567 {
568 SkDynamicMemoryWStream compressedData;
569 SkDeflateWStream deflateWStream(&compressedData,SkToInt(doc->metadata().fCompressionLevel));
570 SkStreamCopy(&deflateWStream, stream);
571 deflateWStream.finalize();
572 if (stream->getLength() > compressedData.bytesWritten() + kMinimumSavings) {
573 tmp = compressedData.detachAsStream();
574 stream = tmp.get();
575 dict.insertName("Filter", "FlateDecode");
576 } else {
577 SkAssertResult(stream->rewind());
578 }
579
580 }
581 dict.insertInt("Length", stream->getLength());
582 doc->emitStream(dict,
583 [stream](SkWStream* dst) { dst->writeStream(stream, stream->getLength()); },
584 ref);
585 }
586
SkPDFStreamOut(std::unique_ptr<SkPDFDict> dict,std::unique_ptr<SkStreamAsset> content,SkPDFDocument * doc,SkPDFSteamCompressionEnabled compress)587 SkPDFIndirectReference SkPDFStreamOut(std::unique_ptr<SkPDFDict> dict,
588 std::unique_ptr<SkStreamAsset> content,
589 SkPDFDocument* doc,
590 SkPDFSteamCompressionEnabled compress) {
591 SkPDFIndirectReference ref = doc->reserveRef();
592 if (SkExecutor* executor = doc->executor()) {
593 SkPDFDict* dictPtr = dict.release();
594 SkStreamAsset* contentPtr = content.release();
595 // Pass ownership of both pointers into a std::function, which should
596 // only be executed once.
597 doc->incrementJobCount();
598 executor->add([dictPtr, contentPtr, compress, doc, ref]() {
599 serialize_stream(dictPtr, contentPtr, compress, doc, ref);
600 delete dictPtr;
601 delete contentPtr;
602 doc->signalJobComplete();
603 });
604 return ref;
605 }
606 serialize_stream(dict.get(), content.get(), compress, doc, ref);
607 return ref;
608 }
609