OLD | NEW |
1 | 1 |
2 /* | 2 /* |
3 * Copyright 2011 Google Inc. | 3 * Copyright 2011 Google Inc. |
4 * | 4 * |
5 * Use of this source code is governed by a BSD-style license that can be | 5 * Use of this source code is governed by a BSD-style license that can be |
6 * found in the LICENSE file. | 6 * found in the LICENSE file. |
7 */ | 7 */ |
8 | 8 |
9 | 9 |
10 #include "SkPDFCatalog.h" | |
11 #include "SkPDFTypes.h" | 10 #include "SkPDFTypes.h" |
12 #include "SkStream.h" | 11 #include "SkStream.h" |
13 | 12 |
14 #ifdef SK_BUILD_FOR_WIN | 13 #ifdef SK_BUILD_FOR_WIN |
15 #define SNPRINTF _snprintf | 14 #define SNPRINTF _snprintf |
16 #else | 15 #else |
17 #define SNPRINTF snprintf | 16 #define SNPRINTF snprintf |
18 #endif | 17 #endif |
19 | 18 |
20 //////////////////////////////////////////////////////////////////////////////// | 19 //////////////////////////////////////////////////////////////////////////////// |
21 | 20 |
22 SkPDFObjRef::SkPDFObjRef(SkPDFObject* obj) : fObj(obj) { | 21 SkPDFObjRef::SkPDFObjRef(SkPDFObject* obj) : fObj(obj) { |
23 SkSafeRef(obj); | 22 SkSafeRef(obj); |
24 } | 23 } |
25 | 24 |
26 SkPDFObjRef::~SkPDFObjRef() {} | 25 SkPDFObjRef::~SkPDFObjRef() {} |
27 | 26 |
28 void SkPDFObjRef::emitObject(SkWStream* stream, SkPDFCatalog* catalog) { | 27 void SkPDFObjRef::emitObject(SkWStream* stream, |
29 SkPDFObject* obj = catalog->getSubstituteObject(fObj); | 28 const SkPDFObjNumMap& objNumMap, |
30 stream->writeDecAsText(catalog->getObjectNumber(obj)); | 29 const SkPDFSubstituteMap& substitutes) { |
| 30 SkPDFObject* obj = substitutes.getSubstitute(fObj); |
| 31 stream->writeDecAsText(objNumMap.getObjectNumber(obj)); |
31 stream->writeText(" 0 R"); // Generation number is always 0. | 32 stream->writeText(" 0 R"); // Generation number is always 0. |
32 } | 33 } |
33 | 34 |
34 void SkPDFObjRef::addResources(SkPDFCatalog* catalog) const { | 35 void SkPDFObjRef::addResources(SkPDFObjNumMap* catalog, |
35 SkPDFObject* obj = catalog->getSubstituteObject(fObj); | 36 const SkPDFSubstituteMap& substitutes) const { |
| 37 SkPDFObject* obj = substitutes.getSubstitute(fObj); |
36 SkASSERT(obj); | 38 SkASSERT(obj); |
37 if (catalog->addObject(obj)) { | 39 if (catalog->addObject(obj)) { |
38 obj->addResources(catalog); | 40 obj->addResources(catalog, substitutes); |
39 } | 41 } |
40 } | 42 } |
41 | 43 |
42 //////////////////////////////////////////////////////////////////////////////// | 44 //////////////////////////////////////////////////////////////////////////////// |
43 | 45 |
44 SkPDFInt::SkPDFInt(int32_t value) : fValue(value) {} | 46 SkPDFInt::SkPDFInt(int32_t value) : fValue(value) {} |
45 SkPDFInt::~SkPDFInt() {} | 47 SkPDFInt::~SkPDFInt() {} |
46 | 48 |
47 void SkPDFInt::emitObject(SkWStream* stream, SkPDFCatalog* catalog) { | 49 void SkPDFInt::emitObject(SkWStream* stream, |
| 50 const SkPDFObjNumMap&, |
| 51 const SkPDFSubstituteMap&) { |
48 stream->writeDecAsText(fValue); | 52 stream->writeDecAsText(fValue); |
49 } | 53 } |
50 | 54 |
51 //////////////////////////////////////////////////////////////////////////////// | 55 //////////////////////////////////////////////////////////////////////////////// |
52 | 56 |
53 SkPDFBool::SkPDFBool(bool value) : fValue(value) {} | 57 SkPDFBool::SkPDFBool(bool value) : fValue(value) {} |
54 SkPDFBool::~SkPDFBool() {} | 58 SkPDFBool::~SkPDFBool() {} |
55 | 59 |
56 void SkPDFBool::emitObject(SkWStream* stream, SkPDFCatalog* catalog) { | 60 void SkPDFBool::emitObject(SkWStream* stream, |
57 if (fValue) { | 61 const SkPDFObjNumMap&, |
58 stream->writeText("true"); | 62 const SkPDFSubstituteMap&) { |
59 } else { | 63 stream->writeText(fValue ? "true" : "false"); |
60 stream->writeText("false"); | |
61 } | |
62 } | 64 } |
63 | 65 |
64 //////////////////////////////////////////////////////////////////////////////// | 66 //////////////////////////////////////////////////////////////////////////////// |
65 | 67 |
66 SkPDFScalar::SkPDFScalar(SkScalar value) : fValue(value) {} | 68 SkPDFScalar::SkPDFScalar(SkScalar value) : fValue(value) {} |
67 SkPDFScalar::~SkPDFScalar() {} | 69 SkPDFScalar::~SkPDFScalar() {} |
68 | 70 |
69 void SkPDFScalar::emitObject(SkWStream* stream, SkPDFCatalog* catalog) { | 71 void SkPDFScalar::emitObject(SkWStream* stream, |
70 Append(fValue, stream); | 72 const SkPDFObjNumMap&, |
| 73 const SkPDFSubstituteMap&) { |
| 74 SkPDFScalar::Append(fValue, stream); |
71 } | 75 } |
72 | 76 |
73 // static | 77 // static |
74 void SkPDFScalar::Append(SkScalar value, SkWStream* stream) { | 78 void SkPDFScalar::Append(SkScalar value, SkWStream* stream) { |
75 // The range of reals in PDF/A is the same as SkFixed: +/- 32,767 and | 79 // The range of reals in PDF/A is the same as SkFixed: +/- 32,767 and |
76 // +/- 1/65,536 (though integers can range from 2^31 - 1 to -2^31). | 80 // +/- 1/65,536 (though integers can range from 2^31 - 1 to -2^31). |
77 // When using floats that are outside the whole value range, we can use | 81 // When using floats that are outside the whole value range, we can use |
78 // integers instead. | 82 // integers instead. |
79 | 83 |
80 #if !defined(SK_ALLOW_LARGE_PDF_SCALARS) | 84 #if !defined(SK_ALLOW_LARGE_PDF_SCALARS) |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
128 SkPDFString::SkPDFString(const SkString& value) | 132 SkPDFString::SkPDFString(const SkString& value) |
129 : fValue(FormatString(value.c_str(), value.size())) { | 133 : fValue(FormatString(value.c_str(), value.size())) { |
130 } | 134 } |
131 | 135 |
132 SkPDFString::SkPDFString(const uint16_t* value, size_t len, bool wideChars) | 136 SkPDFString::SkPDFString(const uint16_t* value, size_t len, bool wideChars) |
133 : fValue(FormatString(value, len, wideChars)) { | 137 : fValue(FormatString(value, len, wideChars)) { |
134 } | 138 } |
135 | 139 |
136 SkPDFString::~SkPDFString() {} | 140 SkPDFString::~SkPDFString() {} |
137 | 141 |
138 void SkPDFString::emitObject(SkWStream* stream, SkPDFCatalog* catalog) { | 142 void SkPDFString::emitObject(SkWStream* stream, |
| 143 const SkPDFObjNumMap&, |
| 144 const SkPDFSubstituteMap&) { |
139 stream->write(fValue.c_str(), fValue.size()); | 145 stream->write(fValue.c_str(), fValue.size()); |
140 } | 146 } |
141 | 147 |
142 // static | 148 // static |
143 SkString SkPDFString::FormatString(const char* input, size_t len) { | 149 SkString SkPDFString::FormatString(const char* input, size_t len) { |
144 return DoFormatString(input, len, false, false); | 150 return DoFormatString(input, len, false, false); |
145 } | 151 } |
146 | 152 |
147 SkString SkPDFString::FormatString(const uint16_t* input, size_t len, | 153 SkString SkPDFString::FormatString(const uint16_t* input, size_t len, |
148 bool wideChars) { | 154 bool wideChars) { |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
207 //////////////////////////////////////////////////////////////////////////////// | 213 //////////////////////////////////////////////////////////////////////////////// |
208 | 214 |
209 SkPDFName::SkPDFName(const char name[]) : fValue(FormatName(SkString(name))) {} | 215 SkPDFName::SkPDFName(const char name[]) : fValue(FormatName(SkString(name))) {} |
210 SkPDFName::SkPDFName(const SkString& name) : fValue(FormatName(name)) {} | 216 SkPDFName::SkPDFName(const SkString& name) : fValue(FormatName(name)) {} |
211 SkPDFName::~SkPDFName() {} | 217 SkPDFName::~SkPDFName() {} |
212 | 218 |
213 bool SkPDFName::operator==(const SkPDFName& b) const { | 219 bool SkPDFName::operator==(const SkPDFName& b) const { |
214 return fValue == b.fValue; | 220 return fValue == b.fValue; |
215 } | 221 } |
216 | 222 |
217 void SkPDFName::emitObject(SkWStream* stream, SkPDFCatalog* catalog) { | 223 void SkPDFName::emitObject(SkWStream* stream, |
| 224 const SkPDFObjNumMap&, |
| 225 const SkPDFSubstituteMap&) { |
218 stream->write(fValue.c_str(), fValue.size()); | 226 stream->write(fValue.c_str(), fValue.size()); |
219 } | 227 } |
220 | 228 |
221 // static | 229 // static |
222 SkString SkPDFName::FormatName(const SkString& input) { | 230 SkString SkPDFName::FormatName(const SkString& input) { |
223 SkASSERT(input.size() <= kMaxLen); | 231 SkASSERT(input.size() <= kMaxLen); |
224 // TODO(vandebo) If more escaping is needed, improve the linear scan. | 232 // TODO(vandebo) If more escaping is needed, improve the linear scan. |
225 static const char escaped[] = "#/%()<>[]{}"; | 233 static const char escaped[] = "#/%()<>[]{}"; |
226 | 234 |
227 SkString result("/"); | 235 SkString result("/"); |
(...skipping 10 matching lines...) Expand all Loading... |
238 return result; | 246 return result; |
239 } | 247 } |
240 | 248 |
241 //////////////////////////////////////////////////////////////////////////////// | 249 //////////////////////////////////////////////////////////////////////////////// |
242 | 250 |
243 SkPDFArray::SkPDFArray() {} | 251 SkPDFArray::SkPDFArray() {} |
244 SkPDFArray::~SkPDFArray() { | 252 SkPDFArray::~SkPDFArray() { |
245 fValue.unrefAll(); | 253 fValue.unrefAll(); |
246 } | 254 } |
247 | 255 |
248 void SkPDFArray::emitObject(SkWStream* stream, SkPDFCatalog* catalog) { | 256 void SkPDFArray::emitObject(SkWStream* stream, |
| 257 const SkPDFObjNumMap& objNumMap, |
| 258 const SkPDFSubstituteMap& substitutes) { |
249 stream->writeText("["); | 259 stream->writeText("["); |
250 for (int i = 0; i < fValue.count(); i++) { | 260 for (int i = 0; i < fValue.count(); i++) { |
251 catalog->getSubstituteObject(fValue[i])->emitObject(stream, catalog); | 261 SkASSERT(substitutes.getSubstitute(fValue[i]) == fValue[i]); |
| 262 fValue[i]->emitObject(stream, objNumMap, substitutes); |
252 if (i + 1 < fValue.count()) { | 263 if (i + 1 < fValue.count()) { |
253 stream->writeText(" "); | 264 stream->writeText(" "); |
254 } | 265 } |
255 } | 266 } |
256 stream->writeText("]"); | 267 stream->writeText("]"); |
257 } | 268 } |
258 | 269 |
259 void SkPDFArray::addResources(SkPDFCatalog* catalog) const { | 270 void SkPDFArray::addResources(SkPDFObjNumMap* catalog, |
| 271 const SkPDFSubstituteMap& substitutes) const { |
260 for (int i = 0; i < fValue.count(); i++) { | 272 for (int i = 0; i < fValue.count(); i++) { |
261 catalog->getSubstituteObject(fValue[i])->addResources(catalog); | 273 SkASSERT(substitutes.getSubstitute(fValue[i]) == fValue[i]); |
| 274 fValue[i]->addResources(catalog, substitutes); |
262 } | 275 } |
263 } | 276 } |
264 | 277 |
265 void SkPDFArray::reserve(int length) { | 278 void SkPDFArray::reserve(int length) { |
266 SkASSERT(length <= kMaxLen); | 279 SkASSERT(length <= kMaxLen); |
267 fValue.setReserve(length); | 280 fValue.setReserve(length); |
268 } | 281 } |
269 | 282 |
270 SkPDFObject* SkPDFArray::setAt(int offset, SkPDFObject* value) { | 283 SkPDFObject* SkPDFArray::setAt(int offset, SkPDFObject* value) { |
271 SkASSERT(offset < fValue.count()); | 284 SkASSERT(offset < fValue.count()); |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
306 } | 319 } |
307 | 320 |
308 SkPDFDict::~SkPDFDict() { | 321 SkPDFDict::~SkPDFDict() { |
309 clear(); | 322 clear(); |
310 } | 323 } |
311 | 324 |
312 int SkPDFDict::size() const { | 325 int SkPDFDict::size() const { |
313 return fValue.count(); | 326 return fValue.count(); |
314 } | 327 } |
315 | 328 |
316 void SkPDFDict::emitObject(SkWStream* stream, SkPDFCatalog* catalog) { | 329 void SkPDFDict::emitObject(SkWStream* stream, |
| 330 const SkPDFObjNumMap& objNumMap, |
| 331 const SkPDFSubstituteMap& substitutes) { |
317 stream->writeText("<<"); | 332 stream->writeText("<<"); |
318 for (int i = 0; i < fValue.count(); i++) { | 333 for (int i = 0; i < fValue.count(); i++) { |
319 SkASSERT(fValue[i].key); | 334 SkASSERT(fValue[i].key); |
320 SkASSERT(fValue[i].value); | 335 SkASSERT(fValue[i].value); |
321 fValue[i].key->emitObject(stream, catalog); | 336 SkASSERT(substitutes.getSubstitute(fValue[i].key) == fValue[i].key); |
| 337 SkASSERT(substitutes.getSubstitute(fValue[i].value) == fValue[i].value); |
| 338 fValue[i].key->emitObject(stream, objNumMap, substitutes); |
322 stream->writeText(" "); | 339 stream->writeText(" "); |
323 catalog->getSubstituteObject(fValue[i].value) | 340 fValue[i].value->emitObject(stream, objNumMap, substitutes); |
324 ->emitObject(stream, catalog); | 341 if (i + 1 < fValue.count()) { |
325 stream->writeText("\n"); | 342 stream->writeText("\n"); |
| 343 } |
326 } | 344 } |
327 stream->writeText(">>"); | 345 stream->writeText(">>"); |
328 } | 346 } |
329 | 347 |
330 void SkPDFDict::addResources(SkPDFCatalog* catalog) const { | 348 void SkPDFDict::addResources(SkPDFObjNumMap* catalog, |
| 349 const SkPDFSubstituteMap& substitutes) const { |
331 for (int i = 0; i < fValue.count(); i++) { | 350 for (int i = 0; i < fValue.count(); i++) { |
332 SkASSERT(fValue[i].key); | 351 SkASSERT(fValue[i].key); |
333 SkASSERT(fValue[i].value); | 352 SkASSERT(fValue[i].value); |
334 fValue[i].key->addResources(catalog); | 353 fValue[i].key->addResources(catalog, substitutes); |
335 catalog->getSubstituteObject(fValue[i].value)->addResources(catalog); | 354 SkASSERT(substitutes.getSubstitute(fValue[i].value) == fValue[i].value); |
| 355 fValue[i].value->addResources(catalog, substitutes); |
336 } | 356 } |
337 } | 357 } |
338 | 358 |
339 SkPDFObject* SkPDFDict::append(SkPDFName* key, SkPDFObject* value) { | 359 SkPDFObject* SkPDFDict::append(SkPDFName* key, SkPDFObject* value) { |
340 SkASSERT(key); | 360 SkASSERT(key); |
341 SkASSERT(value); | 361 SkASSERT(value); |
342 *(fValue.append()) = Rec(key, value); | 362 *(fValue.append()) = Rec(key, value); |
343 return value; | 363 return value; |
344 } | 364 } |
345 | 365 |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
387 } | 407 } |
388 } | 408 } |
389 } | 409 } |
390 | 410 |
391 void SkPDFDict::mergeFrom(const SkPDFDict& other) { | 411 void SkPDFDict::mergeFrom(const SkPDFDict& other) { |
392 for (int i = 0; i < other.fValue.count(); i++) { | 412 for (int i = 0; i < other.fValue.count(); i++) { |
393 *(fValue.append()) = | 413 *(fValue.append()) = |
394 Rec(SkRef(other.fValue[i].key), SkRef(other.fValue[i].value)); | 414 Rec(SkRef(other.fValue[i].key), SkRef(other.fValue[i].value)); |
395 } | 415 } |
396 } | 416 } |
| 417 |
| 418 //////////////////////////////////////////////////////////////////////////////// |
| 419 |
| 420 SkPDFSubstituteMap::~SkPDFSubstituteMap() { |
| 421 fSubstituteMap.foreach( |
| 422 [](SkPDFObject*, SkPDFObject** v) { (*v)->unref(); }); |
| 423 } |
| 424 |
| 425 void SkPDFSubstituteMap::setSubstitute(SkPDFObject* original, |
| 426 SkPDFObject* substitute) { |
| 427 SkASSERT(original != substitute); |
| 428 SkASSERT(!fSubstituteMap.find(original)); |
| 429 fSubstituteMap.set(original, SkRef(substitute)); |
| 430 } |
| 431 |
| 432 SkPDFObject* SkPDFSubstituteMap::getSubstitute(SkPDFObject* object) const { |
| 433 SkPDFObject** found = fSubstituteMap.find(object); |
| 434 return found ? *found : object; |
| 435 } |
| 436 |
| 437 //////////////////////////////////////////////////////////////////////////////// |
| 438 |
| 439 bool SkPDFObjNumMap::addObject(SkPDFObject* obj) { |
| 440 if (fObjectNumbers.find(obj)) { |
| 441 return false; |
| 442 } |
| 443 fObjectNumbers.set(obj, fObjectNumbers.count() + 1); |
| 444 fObjects.push(obj); |
| 445 return true; |
| 446 } |
| 447 |
| 448 int32_t SkPDFObjNumMap::getObjectNumber(SkPDFObject* obj) const { |
| 449 int32_t* objectNumberFound = fObjectNumbers.find(obj); |
| 450 SkASSERT(objectNumberFound); |
| 451 return *objectNumberFound; |
| 452 } |
| 453 |
OLD | NEW |