• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
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::kStringSkS:
35             fSkString.~SkString();
36             return;
37         case Type::kObject:
38             fObject.~PDFObject();
39             return;
40         default:
41             return;
42     }
43 }
44 
SkPDFUnion(SkPDFUnion && that)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 
operator =(SkPDFUnion && that)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 
isName() const88 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.
is_valid_name(const char * n)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).
write_name_escaped(SkWStream * o,const char * name)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 
write_string(SkWStream * wStream,const char * cin,size_t len)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 extraCharacterCount = 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 
SkPDFWriteString(SkWStream * wStream,const char * cin,size_t len)164 void SkPDFWriteString(SkWStream* wStream, const char* cin, size_t len) {
165     write_string(wStream, cin, len);
166 }
167 
emitObject(SkWStream * stream) const168 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 
Int(int32_t value)214 SkPDFUnion SkPDFUnion::Int(int32_t value) {
215     return SkPDFUnion(Type::kInt, value);
216 }
217 
ColorComponent(uint8_t value)218 SkPDFUnion SkPDFUnion::ColorComponent(uint8_t value) {
219     return SkPDFUnion(Type::kColorComponent,  SkTo<int32_t>(value));
220 }
221 
ColorComponentF(float value)222 SkPDFUnion SkPDFUnion::ColorComponentF(float value) {
223     return SkPDFUnion(Type::kColorComponentF, SkFloatToScalar(value));
224 }
225 
Bool(bool value)226 SkPDFUnion SkPDFUnion::Bool(bool value) {
227     return SkPDFUnion(Type::kBool, value);
228 }
229 
Scalar(SkScalar value)230 SkPDFUnion SkPDFUnion::Scalar(SkScalar value) {
231     return SkPDFUnion(Type::kScalar, value);
232 }
233 
Name(const char * value)234 SkPDFUnion SkPDFUnion::Name(const char* value) {
235     SkASSERT(value);
236     SkASSERT(is_valid_name(value));
237     return SkPDFUnion(Type::kName, value);
238 }
239 
String(const char * value)240 SkPDFUnion SkPDFUnion::String(const char* value) {
241     SkASSERT(value);
242     return SkPDFUnion(Type::kString, value);
243 }
244 
Name(SkString s)245 SkPDFUnion SkPDFUnion::Name(SkString s) {
246     return SkPDFUnion(Type::kNameSkS, std::move(s));
247 }
248 
String(SkString s)249 SkPDFUnion SkPDFUnion::String(SkString s) {
250     return SkPDFUnion(Type::kStringSkS, std::move(s));
251 }
252 
Object(std::unique_ptr<SkPDFObject> objSp)253 SkPDFUnion SkPDFUnion::Object(std::unique_ptr<SkPDFObject> objSp) {
254     SkASSERT(objSp.get());
255     return SkPDFUnion(Type::kObject, std::move(objSp));
256 }
257 
Ref(SkPDFIndirectReference ref)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 
SkPDFArray()273 SkPDFArray::SkPDFArray() {}
274 
~SkPDFArray()275 SkPDFArray::~SkPDFArray() {}
276 
size() const277 size_t SkPDFArray::size() const { return fValues.size(); }
278 
reserve(int length)279 void SkPDFArray::reserve(int length) {
280     fValues.reserve(length);
281 }
282 
emitObject(SkWStream * stream) const283 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 
append(SkPDFUnion && value)294 void SkPDFArray::append(SkPDFUnion&& value) {
295     fValues.emplace_back(std::move(value));
296 }
297 
appendInt(int32_t value)298 void SkPDFArray::appendInt(int32_t value) {
299     this->append(SkPDFUnion::Int(value));
300 }
301 
appendColorComponent(uint8_t value)302 void SkPDFArray::appendColorComponent(uint8_t value) {
303     this->append(SkPDFUnion::ColorComponent(value));
304 }
305 
appendBool(bool value)306 void SkPDFArray::appendBool(bool value) {
307     this->append(SkPDFUnion::Bool(value));
308 }
309 
appendScalar(SkScalar value)310 void SkPDFArray::appendScalar(SkScalar value) {
311     this->append(SkPDFUnion::Scalar(value));
312 }
313 
appendName(const char name[])314 void SkPDFArray::appendName(const char name[]) {
315     this->append(SkPDFUnion::Name(SkString(name)));
316 }
317 
appendName(SkString name)318 void SkPDFArray::appendName(SkString name) {
319     this->append(SkPDFUnion::Name(std::move(name)));
320 }
321 
appendString(SkString value)322 void SkPDFArray::appendString(SkString value) {
323     this->append(SkPDFUnion::String(std::move(value)));
324 }
325 
appendString(const char value[])326 void SkPDFArray::appendString(const char value[]) {
327     this->append(SkPDFUnion::String(value));
328 }
329 
appendObject(std::unique_ptr<SkPDFObject> && objSp)330 void SkPDFArray::appendObject(std::unique_ptr<SkPDFObject>&& objSp) {
331     this->append(SkPDFUnion::Object(std::move(objSp)));
332 }
333 
appendRef(SkPDFIndirectReference ref)334 void SkPDFArray::appendRef(SkPDFIndirectReference ref) {
335     this->append(SkPDFUnion::Ref(ref));
336 }
337 
338 ///////////////////////////////////////////////////////////////////////////////
339 
~SkPDFDict()340 SkPDFDict::~SkPDFDict() {}
341 
SkPDFDict(const char type[])342 SkPDFDict::SkPDFDict(const char type[]) {
343     if (type) {
344         this->insertName("Type", type);
345     }
346 }
347 
emitObject(SkWStream * stream) const348 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 
size() const362 size_t SkPDFDict::size() const { return fRecords.size(); }
363 
reserve(int n)364 void SkPDFDict::reserve(int n) {
365     fRecords.reserve(n);
366 }
367 
insertRef(const char key[],SkPDFIndirectReference ref)368 void SkPDFDict::insertRef(const char key[], SkPDFIndirectReference ref) {
369     fRecords.emplace_back(SkPDFUnion::Name(key), SkPDFUnion::Ref(ref));
370 }
371 
insertRef(SkString key,SkPDFIndirectReference ref)372 void SkPDFDict::insertRef(SkString key, SkPDFIndirectReference ref) {
373     fRecords.emplace_back(SkPDFUnion::Name(std::move(key)), SkPDFUnion::Ref(ref));
374 }
375 
insertObject(const char key[],std::unique_ptr<SkPDFObject> && objSp)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 }
insertObject(SkString key,std::unique_ptr<SkPDFObject> && objSp)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 
insertBool(const char key[],bool value)384 void SkPDFDict::insertBool(const char key[], bool value) {
385     fRecords.emplace_back(SkPDFUnion::Name(key), SkPDFUnion::Bool(value));
386 }
387 
insertInt(const char key[],int32_t value)388 void SkPDFDict::insertInt(const char key[], int32_t value) {
389     fRecords.emplace_back(SkPDFUnion::Name(key), SkPDFUnion::Int(value));
390 }
391 
insertInt(const char key[],size_t value)392 void SkPDFDict::insertInt(const char key[], size_t value) {
393     this->insertInt(key, SkToS32(value));
394 }
395 
insertColorComponentF(const char key[],SkScalar value)396 void SkPDFDict::insertColorComponentF(const char key[], SkScalar value) {
397     fRecords.emplace_back(SkPDFUnion::Name(key), SkPDFUnion::ColorComponentF(value));
398 }
399 
insertScalar(const char key[],SkScalar value)400 void SkPDFDict::insertScalar(const char key[], SkScalar value) {
401     fRecords.emplace_back(SkPDFUnion::Name(key), SkPDFUnion::Scalar(value));
402 }
403 
insertName(const char key[],const char name[])404 void SkPDFDict::insertName(const char key[], const char name[]) {
405     fRecords.emplace_back(SkPDFUnion::Name(key), SkPDFUnion::Name(name));
406 }
407 
insertName(const char key[],SkString name)408 void SkPDFDict::insertName(const char key[], SkString name) {
409     fRecords.emplace_back(SkPDFUnion::Name(key), SkPDFUnion::Name(std::move(name)));
410 }
411 
insertString(const char key[],const char value[])412 void SkPDFDict::insertString(const char key[], const char value[]) {
413     fRecords.emplace_back(SkPDFUnion::Name(key), SkPDFUnion::String(value));
414 }
415 
insertString(const char key[],SkString value)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 
serialize_stream(SkPDFDict * origDict,SkStreamAsset * stream,bool deflate,SkPDFDocument * doc,SkPDFIndirectReference ref)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 
SkPDFStreamOut(std::unique_ptr<SkPDFDict> dict,std::unique_ptr<SkStreamAsset> content,SkPDFDocument * doc,bool deflate)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