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