• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "SkPDFTypes.h"
10 #include "SkPDFUtils.h"
11 #include "SkStream.h"
12 
13 #ifdef SK_BUILD_FOR_WIN
14     #define SNPRINTF    _snprintf
15 #else
16     #define SNPRINTF    snprintf
17 #endif
18 
19 ////////////////////////////////////////////////////////////////////////////////
20 
pun(char * x)21 SkString* pun(char* x) { return reinterpret_cast<SkString*>(x); }
pun(const char * x)22 const SkString* pun(const char* x) {
23     return reinterpret_cast<const SkString*>(x);
24 }
25 
SkPDFUnion(Type t)26 SkPDFUnion::SkPDFUnion(Type t) : fType(t) {}
27 
~SkPDFUnion()28 SkPDFUnion::~SkPDFUnion() {
29     switch (fType) {
30         case Type::kNameSkS:
31         case Type::kStringSkS:
32             pun(fSkString)->~SkString();
33             return;
34         case Type::kObjRef:
35         case Type::kObject:
36             SkSafeUnref(fObject);
37             return;
38         default:
39             return;
40     }
41 }
42 
operator =(SkPDFUnion && other)43 SkPDFUnion& SkPDFUnion::operator=(SkPDFUnion&& other) {
44     if (this != &other) {
45         this->~SkPDFUnion();
46         SkNEW_PLACEMENT_ARGS(this, SkPDFUnion, (other.move()));
47     }
48     return *this;
49 }
50 
SkPDFUnion(SkPDFUnion && other)51 SkPDFUnion::SkPDFUnion(SkPDFUnion&& other) {
52     SkASSERT(this != &other);
53     memcpy(this, &other, sizeof(*this));
54     other.fType = Type::kDestroyed;
55 }
56 
57 #if 0
58 SkPDFUnion SkPDFUnion::copy() const {
59     SkPDFUnion u(fType);
60     memcpy(&u, this, sizeof(u));
61     switch (fType) {
62         case Type::kNameSkS:
63         case Type::kStringSkS:
64             SkNEW_PLACEMENT_ARGS(pun(u.fSkString), SkString,
65                                  (*pun(fSkString)));
66             return u.move();
67         case Type::kObjRef:
68         case Type::kObject:
69             SkRef(u.fObject);
70             return u.move();
71         default:
72             return u.move();
73     }
74 }
75 SkPDFUnion& SkPDFUnion::operator=(const SkPDFUnion& other) {
76     return *this = other.copy();
77 }
78 SkPDFUnion::SkPDFUnion(const SkPDFUnion& other) {
79     *this = other.copy();
80 }
81 #endif
82 
isName() const83 bool SkPDFUnion::isName() const {
84     return Type::kName == fType || Type::kNameSkS == fType;
85 }
86 
87 #ifdef SK_DEBUG
88 // Most names need no escaping.  Such names are handled as static
89 // const strings.
is_valid_name(const char * n)90 bool is_valid_name(const char* n) {
91     static const char kControlChars[] = "/%()<>[]{}";
92     while (*n) {
93         if (*n < '!' || *n > '~' || strchr(kControlChars, *n)) {
94             return false;
95         }
96         ++n;
97     }
98     return true;
99 }
100 #endif  // SK_DEBUG
101 
102 // Given an arbitrary string, convert it to a valid name.
escape_name(const char * name,size_t len)103 static SkString escape_name(const char* name, size_t len) {
104     static const char kToEscape[] = "#/%()<>[]{}";
105     int count = 0;
106     const char* const end = &name[len];
107     for (const char* n = name; n != end; ++n) {
108         if (*n < '!' || *n > '~' || strchr(kToEscape, *n)) {
109             count += 2;
110         }
111         ++count;
112     }
113     SkString result(count);
114     char* s = result.writable_str();
115     static const char kHex[] = "0123456789ABCDEF";
116     for (const char* n = name; n != end; ++n) {
117         if (*n < '!' || *n > '~' || strchr(kToEscape, *n)) {
118             *s++ = '#';
119             *s++ = kHex[(*n >> 4) & 0xF];
120             *s++ = kHex[*n & 0xF];
121         } else {
122             *s++ = *n;
123         }
124     }
125     SkASSERT(&result.writable_str()[count] == s);  // don't over-write
126     return result;                                 // allocated space
127 }
128 
escape_name(const SkString & name)129 static SkString escape_name(const SkString& name) {
130     return escape_name(name.c_str(), name.size());
131 }
132 
write_string(SkWStream * o,const SkString & s)133 static void write_string(SkWStream* o, const SkString& s) {
134     o->write(s.c_str(), s.size());
135 }
136 
format_string(const SkString & s)137 static SkString format_string(const SkString& s) {
138     return SkPDFUtils::FormatString(s.c_str(), s.size());
139 }
140 
format_string(const char * s)141 static SkString format_string(const char* s) {
142     return SkPDFUtils::FormatString(s, strlen(s));
143 }
144 
emitObject(SkWStream * stream,const SkPDFObjNumMap & objNumMap,const SkPDFSubstituteMap & substitutes) const145 void SkPDFUnion::emitObject(SkWStream* stream,
146                             const SkPDFObjNumMap& objNumMap,
147                             const SkPDFSubstituteMap& substitutes) const {
148     switch (fType) {
149         case Type::kInt:
150             stream->writeDecAsText(fIntValue);
151             return;
152         case Type::kBool:
153             stream->writeText(fBoolValue ? "true" : "false");
154             return;
155         case Type::kScalar:
156             SkPDFUtils::AppendScalar(fScalarValue, stream);
157             return;
158         case Type::kName:
159             stream->writeText("/");
160             SkASSERT(is_valid_name(fStaticString));
161             stream->writeText(fStaticString);
162             return;
163         case Type::kString:
164             SkASSERT(fStaticString);
165             write_string(stream, format_string(fStaticString));
166             return;
167         case Type::kNameSkS:
168             stream->writeText("/");
169             write_string(stream, escape_name(*pun(fSkString)));
170             return;
171         case Type::kStringSkS:
172             write_string(stream, format_string(*pun(fSkString)));
173             return;
174         case Type::kObjRef:
175             stream->writeDecAsText(objNumMap.getObjectNumber(
176                     substitutes.getSubstitute(fObject)));
177             stream->writeText(" 0 R");  // Generation number is always 0.
178             return;
179         case Type::kObject:
180             fObject->emitObject(stream, objNumMap, substitutes);
181             return;
182         default:
183             SkDEBUGFAIL("SkPDFUnion::emitObject with bad type");
184     }
185 }
186 
addResources(SkPDFObjNumMap * objNumMap,const SkPDFSubstituteMap & substituteMap) const187 void SkPDFUnion::addResources(SkPDFObjNumMap* objNumMap,
188                               const SkPDFSubstituteMap& substituteMap) const {
189     switch (fType) {
190         case Type::kInt:
191         case Type::kBool:
192         case Type::kScalar:
193         case Type::kName:
194         case Type::kString:
195         case Type::kNameSkS:
196         case Type::kStringSkS:
197             return;  // These have no resources.
198         case Type::kObjRef: {
199             SkPDFObject* obj = substituteMap.getSubstitute(fObject);
200             if (objNumMap->addObject(obj)) {
201                 obj->addResources(objNumMap, substituteMap);
202             }
203             return;
204         }
205         case Type::kObject:
206             fObject->addResources(objNumMap, substituteMap);
207             return;
208         default:
209             SkDEBUGFAIL("SkPDFUnion::addResources with bad type");
210     }
211 }
212 
Int(int32_t value)213 SkPDFUnion SkPDFUnion::Int(int32_t value) {
214     SkPDFUnion u(Type::kInt);
215     u.fIntValue = value;
216     return u.move();
217 }
218 
Bool(bool value)219 SkPDFUnion SkPDFUnion::Bool(bool value) {
220     SkPDFUnion u(Type::kBool);
221     u.fBoolValue = value;
222     return u.move();
223 }
224 
Scalar(SkScalar value)225 SkPDFUnion SkPDFUnion::Scalar(SkScalar value) {
226     SkPDFUnion u(Type::kScalar);
227     u.fScalarValue = value;
228     return u.move();
229 }
230 
Name(const char * value)231 SkPDFUnion SkPDFUnion::Name(const char* value) {
232     SkPDFUnion u(Type::kName);
233     SkASSERT(value);
234     SkASSERT(is_valid_name(value));
235     u.fStaticString = value;
236     return u.move();
237 }
238 
String(const char * value)239 SkPDFUnion SkPDFUnion::String(const char* value) {
240     SkPDFUnion u(Type::kString);
241     SkASSERT(value);
242     u.fStaticString = value;
243     return u.move();
244 }
245 
Name(const SkString & s)246 SkPDFUnion SkPDFUnion::Name(const SkString& s) {
247     SkPDFUnion u(Type::kNameSkS);
248     SkNEW_PLACEMENT_ARGS(pun(u.fSkString), SkString, (s));
249     return u.move();
250 }
251 
String(const SkString & s)252 SkPDFUnion SkPDFUnion::String(const SkString& s) {
253     SkPDFUnion u(Type::kStringSkS);
254     SkNEW_PLACEMENT_ARGS(pun(u.fSkString), SkString, (s));
255     return u.move();
256 }
257 
ObjRef(SkPDFObject * ptr)258 SkPDFUnion SkPDFUnion::ObjRef(SkPDFObject* ptr) {
259     SkPDFUnion u(Type::kObjRef);
260     SkASSERT(ptr);
261     u.fObject = ptr;
262     return u.move();
263 }
264 
Object(SkPDFObject * ptr)265 SkPDFUnion SkPDFUnion::Object(SkPDFObject* ptr) {
266     SkPDFUnion u(Type::kObject);
267     SkASSERT(ptr);
268     u.fObject = ptr;
269     return u.move();
270 }
271 
272 ////////////////////////////////////////////////////////////////////////////////
273 
274 #if 0  // Enable if needed.
275 void SkPDFAtom::emitObject(SkWStream* stream,
276                            const SkPDFObjNumMap& objNumMap,
277                            const SkPDFSubstituteMap& substitutes) {
278     fValue.emitObject(stream, objNumMap, substitutes);
279 }
280 void SkPDFAtom::addResources(SkPDFObjNumMap* map,
281                              const SkPDFSubstituteMap& substitutes) const {
282     fValue.addResources(map, substitutes);
283 }
284 #endif  // 0
285 
286 ////////////////////////////////////////////////////////////////////////////////
287 
SkPDFArray()288 SkPDFArray::SkPDFArray() {}
~SkPDFArray()289 SkPDFArray::~SkPDFArray() {
290     for (SkPDFUnion& value : fValues) {
291         value.~SkPDFUnion();
292     }
293     fValues.reset();
294 }
295 
size() const296 int SkPDFArray::size() const { return fValues.count(); }
297 
reserve(int length)298 void SkPDFArray::reserve(int length) { fValues.setReserve(length); }
299 
emitObject(SkWStream * stream,const SkPDFObjNumMap & objNumMap,const SkPDFSubstituteMap & substitutes)300 void SkPDFArray::emitObject(SkWStream* stream,
301                              const SkPDFObjNumMap& objNumMap,
302                              const SkPDFSubstituteMap& substitutes) {
303     stream->writeText("[");
304     for (int i = 0; i < fValues.count(); i++) {
305         fValues[i].emitObject(stream, objNumMap, substitutes);
306         if (i + 1 < fValues.count()) {
307             stream->writeText(" ");
308         }
309     }
310     stream->writeText("]");
311 }
312 
addResources(SkPDFObjNumMap * catalog,const SkPDFSubstituteMap & substitutes) const313 void SkPDFArray::addResources(SkPDFObjNumMap* catalog,
314                               const SkPDFSubstituteMap& substitutes) const {
315     for (const SkPDFUnion& value : fValues) {
316         value.addResources(catalog, substitutes);
317     }
318 }
319 
append(SkPDFUnion && value)320 void SkPDFArray::append(SkPDFUnion&& value) {
321     SkNEW_PLACEMENT_ARGS(fValues.append(), SkPDFUnion, (value.move()));
322 }
323 
appendInt(int32_t value)324 void SkPDFArray::appendInt(int32_t value) {
325     this->append(SkPDFUnion::Int(value));
326 }
327 
appendBool(bool value)328 void SkPDFArray::appendBool(bool value) {
329     this->append(SkPDFUnion::Bool(value));
330 }
331 
appendScalar(SkScalar value)332 void SkPDFArray::appendScalar(SkScalar value) {
333     this->append(SkPDFUnion::Scalar(value));
334 }
335 
appendName(const char name[])336 void SkPDFArray::appendName(const char name[]) {
337     this->append(SkPDFUnion::Name(SkString(name)));
338 }
339 
appendName(const SkString & name)340 void SkPDFArray::appendName(const SkString& name) {
341     this->append(SkPDFUnion::Name(name));
342 }
343 
appendString(const SkString & value)344 void SkPDFArray::appendString(const SkString& value) {
345     this->append(SkPDFUnion::String(value));
346 }
347 
appendString(const char value[])348 void SkPDFArray::appendString(const char value[]) {
349     this->append(SkPDFUnion::String(value));
350 }
351 
appendObject(SkPDFObject * value)352 void SkPDFArray::appendObject(SkPDFObject* value) {
353     this->append(SkPDFUnion::Object(value));
354 }
355 
appendObjRef(SkPDFObject * value)356 void SkPDFArray::appendObjRef(SkPDFObject* value) {
357     this->append(SkPDFUnion::ObjRef(value));
358 }
359 
360 ///////////////////////////////////////////////////////////////////////////////
361 
SkPDFDict()362 SkPDFDict::SkPDFDict() {}
363 
~SkPDFDict()364 SkPDFDict::~SkPDFDict() { this->clear(); }
365 
SkPDFDict(const char type[])366 SkPDFDict::SkPDFDict(const char type[]) { this->insertName("Type", type); }
367 
emitObject(SkWStream * stream,const SkPDFObjNumMap & objNumMap,const SkPDFSubstituteMap & substitutes)368 void SkPDFDict::emitObject(SkWStream* stream,
369                            const SkPDFObjNumMap& objNumMap,
370                            const SkPDFSubstituteMap& substitutes) {
371     stream->writeText("<<");
372     for (int i = 0; i < fRecords.count(); i++) {
373         fRecords[i].fKey.emitObject(stream, objNumMap, substitutes);
374         stream->writeText(" ");
375         fRecords[i].fValue.emitObject(stream, objNumMap, substitutes);
376         if (i + 1 < fRecords.count()) {
377             stream->writeText("\n");
378         }
379     }
380     stream->writeText(">>");
381 }
382 
addResources(SkPDFObjNumMap * catalog,const SkPDFSubstituteMap & substitutes) const383 void SkPDFDict::addResources(SkPDFObjNumMap* catalog,
384                              const SkPDFSubstituteMap& substitutes) const {
385     for (int i = 0; i < fRecords.count(); i++) {
386         fRecords[i].fKey.addResources(catalog, substitutes);
387         fRecords[i].fValue.addResources(catalog, substitutes);
388     }
389 }
390 
set(SkPDFUnion && name,SkPDFUnion && value)391 void SkPDFDict::set(SkPDFUnion&& name, SkPDFUnion&& value) {
392     Record* rec = fRecords.append();
393     SkASSERT(name.isName());
394     SkNEW_PLACEMENT_ARGS(&rec->fKey, SkPDFUnion, (name.move()));
395     SkNEW_PLACEMENT_ARGS(&rec->fValue, SkPDFUnion, (value.move()));
396 }
397 
size() const398 int SkPDFDict::size() const { return fRecords.count(); }
399 
insertObjRef(const char key[],SkPDFObject * value)400 void SkPDFDict::insertObjRef(const char key[], SkPDFObject* value) {
401     this->set(SkPDFUnion::Name(key), SkPDFUnion::ObjRef(value));
402 }
insertObjRef(const SkString & key,SkPDFObject * value)403 void SkPDFDict::insertObjRef(const SkString& key, SkPDFObject* value) {
404     this->set(SkPDFUnion::Name(key), SkPDFUnion::ObjRef(value));
405 }
406 
insertObject(const char key[],SkPDFObject * value)407 void SkPDFDict::insertObject(const char key[], SkPDFObject* value) {
408     this->set(SkPDFUnion::Name(key), SkPDFUnion::Object(value));
409 }
insertObject(const SkString & key,SkPDFObject * value)410 void SkPDFDict::insertObject(const SkString& key, SkPDFObject* value) {
411     this->set(SkPDFUnion::Name(key), SkPDFUnion::Object(value));
412 }
413 
insertBool(const char key[],bool value)414 void SkPDFDict::insertBool(const char key[], bool value) {
415     this->set(SkPDFUnion::Name(key), SkPDFUnion::Bool(value));
416 }
417 
insertInt(const char key[],int32_t value)418 void SkPDFDict::insertInt(const char key[], int32_t value) {
419     this->set(SkPDFUnion::Name(key), SkPDFUnion::Int(value));
420 }
421 
insertInt(const char key[],size_t value)422 void SkPDFDict::insertInt(const char key[], size_t value) {
423     this->insertInt(key, SkToS32(value));
424 }
425 
insertScalar(const char key[],SkScalar value)426 void SkPDFDict::insertScalar(const char key[], SkScalar value) {
427     this->set(SkPDFUnion::Name(key), SkPDFUnion::Scalar(value));
428 }
429 
insertName(const char key[],const char name[])430 void SkPDFDict::insertName(const char key[], const char name[]) {
431     this->set(SkPDFUnion::Name(key), SkPDFUnion::Name(name));
432 }
433 
insertName(const char key[],const SkString & name)434 void SkPDFDict::insertName(const char key[], const SkString& name) {
435     this->set(SkPDFUnion::Name(key), SkPDFUnion::Name(name));
436 }
437 
insertString(const char key[],const char value[])438 void SkPDFDict::insertString(const char key[], const char value[]) {
439     this->set(SkPDFUnion::Name(key), SkPDFUnion::String(value));
440 }
441 
insertString(const char key[],const SkString & value)442 void SkPDFDict::insertString(const char key[], const SkString& value) {
443     this->set(SkPDFUnion::Name(key), SkPDFUnion::String(value));
444 }
445 
clear()446 void SkPDFDict::clear() {
447     for (Record& rec : fRecords) {
448         rec.fKey.~SkPDFUnion();
449         rec.fValue.~SkPDFUnion();
450     }
451     fRecords.reset();
452 }
453 
454 ////////////////////////////////////////////////////////////////////////////////
455 
~SkPDFSubstituteMap()456 SkPDFSubstituteMap::~SkPDFSubstituteMap() {
457     fSubstituteMap.foreach(
458             [](SkPDFObject*, SkPDFObject** v) { (*v)->unref(); });
459 }
460 
setSubstitute(SkPDFObject * original,SkPDFObject * substitute)461 void SkPDFSubstituteMap::setSubstitute(SkPDFObject* original,
462                                        SkPDFObject* substitute) {
463     SkASSERT(original != substitute);
464     SkASSERT(!fSubstituteMap.find(original));
465     fSubstituteMap.set(original, SkRef(substitute));
466 }
467 
getSubstitute(SkPDFObject * object) const468 SkPDFObject* SkPDFSubstituteMap::getSubstitute(SkPDFObject* object) const {
469     SkPDFObject** found = fSubstituteMap.find(object);
470     return found ? *found : object;
471 }
472 
473 ////////////////////////////////////////////////////////////////////////////////
474 
addObject(SkPDFObject * obj)475 bool SkPDFObjNumMap::addObject(SkPDFObject* obj) {
476     if (fObjectNumbers.find(obj)) {
477         return false;
478     }
479     fObjectNumbers.set(obj, fObjectNumbers.count() + 1);
480     fObjects.push(obj);
481     return true;
482 }
483 
getObjectNumber(SkPDFObject * obj) const484 int32_t SkPDFObjNumMap::getObjectNumber(SkPDFObject* obj) const {
485     int32_t* objectNumberFound = fObjectNumbers.find(obj);
486     SkASSERT(objectNumberFound);
487     return *objectNumberFound;
488 }
489 
490