1
2 /*
3 * Copyright 2011 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9 #include "SkDeflate.h"
10 #include "SkPDFTypes.h"
11 #include "SkPDFUtils.h"
12 #include "SkStreamPriv.h"
13
14 ////////////////////////////////////////////////////////////////////////////////
15
pun(char * x)16 SkString* pun(char* x) { return reinterpret_cast<SkString*>(x); }
pun(const char * x)17 const SkString* pun(const char* x) {
18 return reinterpret_cast<const SkString*>(x);
19 }
20
SkPDFUnion(Type t)21 SkPDFUnion::SkPDFUnion(Type t) : fType(t) {}
22
~SkPDFUnion()23 SkPDFUnion::~SkPDFUnion() {
24 switch (fType) {
25 case Type::kNameSkS:
26 case Type::kStringSkS:
27 pun(fSkString)->~SkString();
28 return;
29 case Type::kObjRef:
30 case Type::kObject:
31 SkSafeUnref(fObject);
32 return;
33 default:
34 return;
35 }
36 }
37
operator =(SkPDFUnion && other)38 SkPDFUnion& SkPDFUnion::operator=(SkPDFUnion&& other) {
39 if (this != &other) {
40 this->~SkPDFUnion();
41 new (this) SkPDFUnion(other.move());
42 }
43 return *this;
44 }
45
SkPDFUnion(SkPDFUnion && other)46 SkPDFUnion::SkPDFUnion(SkPDFUnion&& other) {
47 SkASSERT(this != &other);
48 memcpy(this, &other, sizeof(*this));
49 other.fType = Type::kDestroyed;
50 }
51
52 #if 0
53 SkPDFUnion SkPDFUnion::copy() const {
54 SkPDFUnion u(fType);
55 memcpy(&u, this, sizeof(u));
56 switch (fType) {
57 case Type::kNameSkS:
58 case Type::kStringSkS:
59 new (pun(u.fSkString)) SkString (*pun(fSkString));
60 return u.move();
61 case Type::kObjRef:
62 case Type::kObject:
63 SkRef(u.fObject);
64 return u.move();
65 default:
66 return u.move();
67 }
68 }
69 SkPDFUnion& SkPDFUnion::operator=(const SkPDFUnion& other) {
70 return *this = other.copy();
71 }
72 SkPDFUnion::SkPDFUnion(const SkPDFUnion& other) {
73 *this = other.copy();
74 }
75 #endif
76
isName() const77 bool SkPDFUnion::isName() const {
78 return Type::kName == fType || Type::kNameSkS == fType;
79 }
80
81 #ifdef SK_DEBUG
82 // Most names need no escaping. Such names are handled as static
83 // const strings.
is_valid_name(const char * n)84 bool is_valid_name(const char* n) {
85 static const char kControlChars[] = "/%()<>[]{}";
86 while (*n) {
87 if (*n < '!' || *n > '~' || strchr(kControlChars, *n)) {
88 return false;
89 }
90 ++n;
91 }
92 return true;
93 }
94 #endif // SK_DEBUG
95
96 // Given an arbitrary string, write it as a valid name (not including
97 // leading slash).
write_name_escaped(SkWStream * o,const char * name)98 static void write_name_escaped(SkWStream* o, const char* name) {
99 static const char kToEscape[] = "#/%()<>[]{}";
100 static const char kHex[] = "0123456789ABCDEF";
101 for (const uint8_t* n = reinterpret_cast<const uint8_t*>(name); *n; ++n) {
102 if (*n < '!' || *n > '~' || strchr(kToEscape, *n)) {
103 char buffer[3] = {'#', '\0', '\0'};
104 buffer[1] = kHex[(*n >> 4) & 0xF];
105 buffer[2] = kHex[*n & 0xF];
106 o->write(buffer, sizeof(buffer));
107 } else {
108 o->write(n, 1);
109 }
110 }
111 }
112
write_string(SkWStream * o,const SkString & s)113 static void write_string(SkWStream* o, const SkString& s) {
114 o->write(s.c_str(), s.size());
115 }
116
format_string(const SkString & s)117 static SkString format_string(const SkString& s) {
118 return SkPDFUtils::FormatString(s.c_str(), s.size());
119 }
120
format_string(const char * s)121 static SkString format_string(const char* s) {
122 return SkPDFUtils::FormatString(s, strlen(s));
123 }
124
emitObject(SkWStream * stream,const SkPDFObjNumMap & objNumMap,const SkPDFSubstituteMap & substitutes) const125 void SkPDFUnion::emitObject(SkWStream* stream,
126 const SkPDFObjNumMap& objNumMap,
127 const SkPDFSubstituteMap& substitutes) const {
128 switch (fType) {
129 case Type::kInt:
130 stream->writeDecAsText(fIntValue);
131 return;
132 case Type::kBool:
133 stream->writeText(fBoolValue ? "true" : "false");
134 return;
135 case Type::kScalar:
136 SkPDFUtils::AppendScalar(fScalarValue, stream);
137 return;
138 case Type::kName:
139 stream->writeText("/");
140 SkASSERT(is_valid_name(fStaticString));
141 stream->writeText(fStaticString);
142 return;
143 case Type::kString:
144 SkASSERT(fStaticString);
145 write_string(stream, format_string(fStaticString));
146 return;
147 case Type::kNameSkS:
148 stream->writeText("/");
149 write_name_escaped(stream, pun(fSkString)->c_str());
150 return;
151 case Type::kStringSkS:
152 write_string(stream, format_string(*pun(fSkString)));
153 return;
154 case Type::kObjRef:
155 stream->writeDecAsText(objNumMap.getObjectNumber(
156 substitutes.getSubstitute(fObject)));
157 stream->writeText(" 0 R"); // Generation number is always 0.
158 return;
159 case Type::kObject:
160 fObject->emitObject(stream, objNumMap, substitutes);
161 return;
162 default:
163 SkDEBUGFAIL("SkPDFUnion::emitObject with bad type");
164 }
165 }
166
addResources(SkPDFObjNumMap * objNumMap,const SkPDFSubstituteMap & substituteMap) const167 void SkPDFUnion::addResources(SkPDFObjNumMap* objNumMap,
168 const SkPDFSubstituteMap& substituteMap) const {
169 switch (fType) {
170 case Type::kInt:
171 case Type::kBool:
172 case Type::kScalar:
173 case Type::kName:
174 case Type::kString:
175 case Type::kNameSkS:
176 case Type::kStringSkS:
177 return; // These have no resources.
178 case Type::kObjRef: {
179 SkPDFObject* obj = substituteMap.getSubstitute(fObject);
180 objNumMap->addObjectRecursively(obj, substituteMap);
181 return;
182 }
183 case Type::kObject:
184 fObject->addResources(objNumMap, substituteMap);
185 return;
186 default:
187 SkDEBUGFAIL("SkPDFUnion::addResources with bad type");
188 }
189 }
190
Int(int32_t value)191 SkPDFUnion SkPDFUnion::Int(int32_t value) {
192 SkPDFUnion u(Type::kInt);
193 u.fIntValue = value;
194 return u.move();
195 }
196
Bool(bool value)197 SkPDFUnion SkPDFUnion::Bool(bool value) {
198 SkPDFUnion u(Type::kBool);
199 u.fBoolValue = value;
200 return u.move();
201 }
202
Scalar(SkScalar value)203 SkPDFUnion SkPDFUnion::Scalar(SkScalar value) {
204 SkPDFUnion u(Type::kScalar);
205 u.fScalarValue = value;
206 return u.move();
207 }
208
Name(const char * value)209 SkPDFUnion SkPDFUnion::Name(const char* value) {
210 SkPDFUnion u(Type::kName);
211 SkASSERT(value);
212 SkASSERT(is_valid_name(value));
213 u.fStaticString = value;
214 return u.move();
215 }
216
String(const char * value)217 SkPDFUnion SkPDFUnion::String(const char* value) {
218 SkPDFUnion u(Type::kString);
219 SkASSERT(value);
220 u.fStaticString = value;
221 return u.move();
222 }
223
Name(const SkString & s)224 SkPDFUnion SkPDFUnion::Name(const SkString& s) {
225 SkPDFUnion u(Type::kNameSkS);
226 new (pun(u.fSkString)) SkString(s);
227 return u.move();
228 }
229
String(const SkString & s)230 SkPDFUnion SkPDFUnion::String(const SkString& s) {
231 SkPDFUnion u(Type::kStringSkS);
232 new (pun(u.fSkString)) SkString(s);
233 return u.move();
234 }
235
ObjRef(SkPDFObject * ptr)236 SkPDFUnion SkPDFUnion::ObjRef(SkPDFObject* ptr) {
237 SkPDFUnion u(Type::kObjRef);
238 SkASSERT(ptr);
239 u.fObject = ptr;
240 return u.move();
241 }
242
Object(SkPDFObject * ptr)243 SkPDFUnion SkPDFUnion::Object(SkPDFObject* ptr) {
244 SkPDFUnion u(Type::kObject);
245 SkASSERT(ptr);
246 u.fObject = ptr;
247 return u.move();
248 }
249
250 ////////////////////////////////////////////////////////////////////////////////
251
252 #if 0 // Enable if needed.
253 void SkPDFAtom::emitObject(SkWStream* stream,
254 const SkPDFObjNumMap& objNumMap,
255 const SkPDFSubstituteMap& substitutes) const {
256 fValue.emitObject(stream, objNumMap, substitutes);
257 }
258 void SkPDFAtom::addResources(SkPDFObjNumMap* map,
259 const SkPDFSubstituteMap& substitutes) const {
260 fValue.addResources(map, substitutes);
261 }
262 #endif // 0
263
264 ////////////////////////////////////////////////////////////////////////////////
265
SkPDFArray()266 SkPDFArray::SkPDFArray() {}
~SkPDFArray()267 SkPDFArray::~SkPDFArray() {
268 for (SkPDFUnion& value : fValues) {
269 value.~SkPDFUnion();
270 }
271 fValues.reset();
272 }
273
size() const274 int SkPDFArray::size() const { return fValues.count(); }
275
reserve(int length)276 void SkPDFArray::reserve(int length) { fValues.setReserve(length); }
277
emitObject(SkWStream * stream,const SkPDFObjNumMap & objNumMap,const SkPDFSubstituteMap & substitutes) const278 void SkPDFArray::emitObject(SkWStream* stream,
279 const SkPDFObjNumMap& objNumMap,
280 const SkPDFSubstituteMap& substitutes) const {
281 stream->writeText("[");
282 for (int i = 0; i < fValues.count(); i++) {
283 fValues[i].emitObject(stream, objNumMap, substitutes);
284 if (i + 1 < fValues.count()) {
285 stream->writeText(" ");
286 }
287 }
288 stream->writeText("]");
289 }
290
addResources(SkPDFObjNumMap * catalog,const SkPDFSubstituteMap & substitutes) const291 void SkPDFArray::addResources(SkPDFObjNumMap* catalog,
292 const SkPDFSubstituteMap& substitutes) const {
293 for (const SkPDFUnion& value : fValues) {
294 value.addResources(catalog, substitutes);
295 }
296 }
297
append(SkPDFUnion && value)298 void SkPDFArray::append(SkPDFUnion&& value) { new (fValues.append()) SkPDFUnion(value.move()); }
299
appendInt(int32_t value)300 void SkPDFArray::appendInt(int32_t value) {
301 this->append(SkPDFUnion::Int(value));
302 }
303
appendBool(bool value)304 void SkPDFArray::appendBool(bool value) {
305 this->append(SkPDFUnion::Bool(value));
306 }
307
appendScalar(SkScalar value)308 void SkPDFArray::appendScalar(SkScalar value) {
309 this->append(SkPDFUnion::Scalar(value));
310 }
311
appendName(const char name[])312 void SkPDFArray::appendName(const char name[]) {
313 this->append(SkPDFUnion::Name(SkString(name)));
314 }
315
appendName(const SkString & name)316 void SkPDFArray::appendName(const SkString& name) {
317 this->append(SkPDFUnion::Name(name));
318 }
319
appendString(const SkString & value)320 void SkPDFArray::appendString(const SkString& value) {
321 this->append(SkPDFUnion::String(value));
322 }
323
appendString(const char value[])324 void SkPDFArray::appendString(const char value[]) {
325 this->append(SkPDFUnion::String(value));
326 }
327
appendObject(SkPDFObject * value)328 void SkPDFArray::appendObject(SkPDFObject* value) {
329 this->append(SkPDFUnion::Object(value));
330 }
331
appendObjRef(SkPDFObject * value)332 void SkPDFArray::appendObjRef(SkPDFObject* value) {
333 this->append(SkPDFUnion::ObjRef(value));
334 }
335
336 ///////////////////////////////////////////////////////////////////////////////
337
SkPDFDict()338 SkPDFDict::SkPDFDict() {}
339
~SkPDFDict()340 SkPDFDict::~SkPDFDict() { this->clear(); }
341
SkPDFDict(const char type[])342 SkPDFDict::SkPDFDict(const char type[]) { this->insertName("Type", type); }
343
emitObject(SkWStream * stream,const SkPDFObjNumMap & objNumMap,const SkPDFSubstituteMap & substitutes) const344 void SkPDFDict::emitObject(SkWStream* stream,
345 const SkPDFObjNumMap& objNumMap,
346 const SkPDFSubstituteMap& substitutes) const {
347 stream->writeText("<<");
348 this->emitAll(stream, objNumMap, substitutes);
349 stream->writeText(">>");
350 }
351
emitAll(SkWStream * stream,const SkPDFObjNumMap & objNumMap,const SkPDFSubstituteMap & substitutes) const352 void SkPDFDict::emitAll(SkWStream* stream,
353 const SkPDFObjNumMap& objNumMap,
354 const SkPDFSubstituteMap& substitutes) const {
355 for (int i = 0; i < fRecords.count(); i++) {
356 fRecords[i].fKey.emitObject(stream, objNumMap, substitutes);
357 stream->writeText(" ");
358 fRecords[i].fValue.emitObject(stream, objNumMap, substitutes);
359 if (i + 1 < fRecords.count()) {
360 stream->writeText("\n");
361 }
362 }
363 }
364
addResources(SkPDFObjNumMap * catalog,const SkPDFSubstituteMap & substitutes) const365 void SkPDFDict::addResources(SkPDFObjNumMap* catalog,
366 const SkPDFSubstituteMap& substitutes) const {
367 for (int i = 0; i < fRecords.count(); i++) {
368 fRecords[i].fKey.addResources(catalog, substitutes);
369 fRecords[i].fValue.addResources(catalog, substitutes);
370 }
371 }
372
set(SkPDFUnion && name,SkPDFUnion && value)373 void SkPDFDict::set(SkPDFUnion&& name, SkPDFUnion&& value) {
374 Record* rec = fRecords.append();
375 SkASSERT(name.isName());
376 new (&rec->fKey) SkPDFUnion(name.move());
377 new (&rec->fValue) SkPDFUnion(value.move());
378 }
379
size() const380 int SkPDFDict::size() const { return fRecords.count(); }
381
insertObjRef(const char key[],SkPDFObject * value)382 void SkPDFDict::insertObjRef(const char key[], SkPDFObject* value) {
383 this->set(SkPDFUnion::Name(key), SkPDFUnion::ObjRef(value));
384 }
insertObjRef(const SkString & key,SkPDFObject * value)385 void SkPDFDict::insertObjRef(const SkString& key, SkPDFObject* value) {
386 this->set(SkPDFUnion::Name(key), SkPDFUnion::ObjRef(value));
387 }
388
insertObject(const char key[],SkPDFObject * value)389 void SkPDFDict::insertObject(const char key[], SkPDFObject* value) {
390 this->set(SkPDFUnion::Name(key), SkPDFUnion::Object(value));
391 }
insertObject(const SkString & key,SkPDFObject * value)392 void SkPDFDict::insertObject(const SkString& key, SkPDFObject* value) {
393 this->set(SkPDFUnion::Name(key), SkPDFUnion::Object(value));
394 }
395
insertBool(const char key[],bool value)396 void SkPDFDict::insertBool(const char key[], bool value) {
397 this->set(SkPDFUnion::Name(key), SkPDFUnion::Bool(value));
398 }
399
insertInt(const char key[],int32_t value)400 void SkPDFDict::insertInt(const char key[], int32_t value) {
401 this->set(SkPDFUnion::Name(key), SkPDFUnion::Int(value));
402 }
403
insertInt(const char key[],size_t value)404 void SkPDFDict::insertInt(const char key[], size_t value) {
405 this->insertInt(key, SkToS32(value));
406 }
407
insertScalar(const char key[],SkScalar value)408 void SkPDFDict::insertScalar(const char key[], SkScalar value) {
409 this->set(SkPDFUnion::Name(key), SkPDFUnion::Scalar(value));
410 }
411
insertName(const char key[],const char name[])412 void SkPDFDict::insertName(const char key[], const char name[]) {
413 this->set(SkPDFUnion::Name(key), SkPDFUnion::Name(name));
414 }
415
insertName(const char key[],const SkString & name)416 void SkPDFDict::insertName(const char key[], const SkString& name) {
417 this->set(SkPDFUnion::Name(key), SkPDFUnion::Name(name));
418 }
419
insertString(const char key[],const char value[])420 void SkPDFDict::insertString(const char key[], const char value[]) {
421 this->set(SkPDFUnion::Name(key), SkPDFUnion::String(value));
422 }
423
insertString(const char key[],const SkString & value)424 void SkPDFDict::insertString(const char key[], const SkString& value) {
425 this->set(SkPDFUnion::Name(key), SkPDFUnion::String(value));
426 }
427
clear()428 void SkPDFDict::clear() {
429 for (Record& rec : fRecords) {
430 rec.fKey.~SkPDFUnion();
431 rec.fValue.~SkPDFUnion();
432 }
433 fRecords.reset();
434 }
435
436 ////////////////////////////////////////////////////////////////////////////////
437
emitObject(SkWStream * stream,const SkPDFObjNumMap & objNumMap,const SkPDFSubstituteMap & substitutes) const438 void SkPDFSharedStream::emitObject(
439 SkWStream* stream,
440 const SkPDFObjNumMap& objNumMap,
441 const SkPDFSubstituteMap& substitutes) const {
442 SkDynamicMemoryWStream buffer;
443 SkDeflateWStream deflateWStream(&buffer);
444 // Since emitObject is const, this function doesn't change the dictionary.
445 SkAutoTDelete<SkStreamAsset> dup(fAsset->duplicate()); // Cheap copy
446 SkASSERT(dup);
447 SkStreamCopy(&deflateWStream, dup.get());
448 deflateWStream.finalize();
449 size_t length = buffer.bytesWritten();
450 stream->writeText("<<");
451 fDict->emitAll(stream, objNumMap, substitutes);
452 stream->writeText("\n");
453 SkPDFUnion::Name("Length").emitObject(stream, objNumMap, substitutes);
454 stream->writeText(" ");
455 SkPDFUnion::Int(length).emitObject(stream, objNumMap, substitutes);
456 stream->writeText("\n");
457 SkPDFUnion::Name("Filter").emitObject(stream, objNumMap, substitutes);
458 stream->writeText(" ");
459 SkPDFUnion::Name("FlateDecode").emitObject(stream, objNumMap, substitutes);
460 stream->writeText(">>");
461 stream->writeText(" stream\n");
462 buffer.writeToStream(stream);
463 stream->writeText("\nendstream");
464 }
465
addResources(SkPDFObjNumMap * catalog,const SkPDFSubstituteMap & substitutes) const466 void SkPDFSharedStream::addResources(
467 SkPDFObjNumMap* catalog, const SkPDFSubstituteMap& substitutes) const {
468 fDict->addResources(catalog, substitutes);
469 }
470
471 ////////////////////////////////////////////////////////////////////////////////
472
~SkPDFSubstituteMap()473 SkPDFSubstituteMap::~SkPDFSubstituteMap() {
474 fSubstituteMap.foreach(
475 [](SkPDFObject*, SkPDFObject** v) { (*v)->unref(); });
476 }
477
setSubstitute(SkPDFObject * original,SkPDFObject * substitute)478 void SkPDFSubstituteMap::setSubstitute(SkPDFObject* original,
479 SkPDFObject* substitute) {
480 SkASSERT(original != substitute);
481 SkASSERT(!fSubstituteMap.find(original));
482 fSubstituteMap.set(original, SkRef(substitute));
483 }
484
getSubstitute(SkPDFObject * object) const485 SkPDFObject* SkPDFSubstituteMap::getSubstitute(SkPDFObject* object) const {
486 SkPDFObject** found = fSubstituteMap.find(object);
487 return found ? *found : object;
488 }
489
490 ////////////////////////////////////////////////////////////////////////////////
491
addObject(SkPDFObject * obj)492 bool SkPDFObjNumMap::addObject(SkPDFObject* obj) {
493 if (fObjectNumbers.find(obj)) {
494 return false;
495 }
496 fObjectNumbers.set(obj, fObjectNumbers.count() + 1);
497 fObjects.push(obj);
498 return true;
499 }
500
addObjectRecursively(SkPDFObject * obj,const SkPDFSubstituteMap & subs)501 void SkPDFObjNumMap::addObjectRecursively(SkPDFObject* obj,
502 const SkPDFSubstituteMap& subs) {
503 if (obj && this->addObject(obj)) {
504 obj->addResources(this, subs);
505 }
506 }
507
getObjectNumber(SkPDFObject * obj) const508 int32_t SkPDFObjNumMap::getObjectNumber(SkPDFObject* obj) const {
509 int32_t* objectNumberFound = fObjectNumbers.find(obj);
510 SkASSERT(objectNumberFound);
511 return *objectNumberFound;
512 }
513
514 #ifdef SK_PDF_IMAGE_STATS
515 SkAtomic<int> gDrawImageCalls(0);
516 SkAtomic<int> gJpegImageObjects(0);
517 SkAtomic<int> gRegularImageObjects(0);
518
SkPDFImageDumpStats()519 void SkPDFImageDumpStats() {
520 SkDebugf("\ntotal PDF drawImage/drawBitmap calls: %d\n"
521 "total PDF jpeg images: %d\n"
522 "total PDF regular images: %d\n",
523 gDrawImageCalls.load(),
524 gJpegImageObjects.load(),
525 gRegularImageObjects.load());
526 }
527 #endif // SK_PDF_IMAGE_STATS
528