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 | |
10 #include "SkPDFTypes.h" | 9 #include "SkPDFTypes.h" |
11 #include "SkStream.h" | 10 #include "SkStream.h" |
12 | 11 |
13 #ifdef SK_BUILD_FOR_WIN | 12 #ifdef SK_BUILD_FOR_WIN |
14 #define SNPRINTF _snprintf | 13 #define SNPRINTF _snprintf |
15 #else | 14 #else |
16 #define SNPRINTF snprintf | 15 #define SNPRINTF snprintf |
17 #endif | 16 #endif |
18 | 17 |
19 //////////////////////////////////////////////////////////////////////////////// | 18 //////////////////////////////////////////////////////////////////////////////// |
20 | 19 |
21 SkPDFObjRef::SkPDFObjRef(SkPDFObject* obj) : fObj(obj) { | 20 SkString* pun(char* x) { return reinterpret_cast<SkString*>(x); } |
22 SkSafeRef(obj); | 21 const SkString* pun(const char* x) { |
23 } | 22 return reinterpret_cast<const SkString*>(x); |
24 | 23 } |
25 SkPDFObjRef::~SkPDFObjRef() {} | 24 |
26 | 25 SkPDFUnion::SkPDFUnion(Type t) : fType(t) {} |
27 void SkPDFObjRef::emitObject(SkWStream* stream, | 26 |
28 const SkPDFObjNumMap& objNumMap, | 27 SkPDFUnion::~SkPDFUnion() { |
29 const SkPDFSubstituteMap& substitutes) { | 28 switch (fType) { |
30 SkPDFObject* obj = substitutes.getSubstitute(fObj); | 29 case Type::kNameSkS: |
31 stream->writeDecAsText(objNumMap.getObjectNumber(obj)); | 30 case Type::kStringSkS: |
32 stream->writeText(" 0 R"); // Generation number is always 0. | 31 pun(fSkString)->~SkString(); |
33 } | 32 return; |
34 | 33 case Type::kObjRef: |
35 void SkPDFObjRef::addResources(SkPDFObjNumMap* catalog, | 34 case Type::kObject: |
36 const SkPDFSubstituteMap& substitutes) const { | 35 SkSafeUnref(fObject); |
37 SkPDFObject* obj = substitutes.getSubstitute(fObj); | 36 return; |
38 SkASSERT(obj); | 37 default: |
39 if (catalog->addObject(obj)) { | 38 return; |
40 obj->addResources(catalog, substitutes); | 39 } |
41 } | 40 } |
| 41 |
| 42 SkPDFUnion& SkPDFUnion::operator=(SkPDFUnion&& other) { |
| 43 if (this != &other) { |
| 44 this->~SkPDFUnion(); |
| 45 SkNEW_PLACEMENT_ARGS(this, SkPDFUnion, (other.move())); |
| 46 } |
| 47 return *this; |
| 48 } |
| 49 |
| 50 SkPDFUnion::SkPDFUnion(SkPDFUnion&& other) { |
| 51 SkASSERT(this != &other); |
| 52 memcpy(this, &other, sizeof(*this)); |
| 53 other.fType = Type::kDestroyed; |
| 54 } |
| 55 |
| 56 #if 0 |
| 57 SkPDFUnion SkPDFUnion::copy() const { |
| 58 SkPDFUnion u(fType); |
| 59 memcpy(&u, this, sizeof(u)); |
| 60 switch (fType) { |
| 61 case Type::kNameSkS: |
| 62 case Type::kStringSkS: |
| 63 SkNEW_PLACEMENT_ARGS(pun(u.fSkString), SkString, |
| 64 (*pun(fSkString))); |
| 65 return u.move(); |
| 66 case Type::kObjRef: |
| 67 case Type::kObject: |
| 68 SkRef(u.fObject); |
| 69 return u.move(); |
| 70 default: |
| 71 return u.move(); |
| 72 } |
| 73 } |
| 74 SkPDFUnion& SkPDFUnion::operator=(const SkPDFUnion& other) { |
| 75 return *this = other.copy(); |
| 76 } |
| 77 SkPDFUnion::SkPDFUnion(const SkPDFUnion& other) { |
| 78 *this = other.copy(); |
| 79 } |
| 80 #endif |
| 81 |
| 82 bool SkPDFUnion::isName() const { |
| 83 return Type::kName == fType || Type::kNameSkS == fType; |
| 84 } |
| 85 |
| 86 #ifdef SK_DEBUG |
| 87 // Most names need no escaping. Such names are handled as static |
| 88 // const strings. |
| 89 bool is_valid_name(const char* n) { |
| 90 static const char kControlChars[] = "/%()<>[]{}"; |
| 91 while (*n) { |
| 92 if (*n < '!' || *n > '~' || strchr(kControlChars, *n)) { |
| 93 return false; |
| 94 } |
| 95 ++n; |
| 96 } |
| 97 return true; |
| 98 } |
| 99 #endif // SK_DEBUG |
| 100 |
| 101 // Given an arbitrary string, convert it to a valid name. |
| 102 static SkString escape_name(const char* name, size_t len) { |
| 103 static const char kToEscape[] = "#/%()<>[]{}"; |
| 104 int count = 0; |
| 105 const char* const end = &name[len]; |
| 106 for (const char* n = name; n != end; ++n) { |
| 107 if (*n < '!' || *n > '~' || strchr(kToEscape, *n)) { |
| 108 count += 2; |
| 109 } |
| 110 ++count; |
| 111 } |
| 112 SkString result(count); |
| 113 char* s = result.writable_str(); |
| 114 static const char kHex[] = "0123456789ABCDEF"; |
| 115 for (const char* n = name; n != end; ++n) { |
| 116 if (*n < '!' || *n > '~' || strchr(kToEscape, *n)) { |
| 117 *s++ = '#'; |
| 118 *s++ = kHex[(*n >> 4) & 0xF]; |
| 119 *s++ = kHex[*n & 0xF]; |
| 120 } else { |
| 121 *s++ = *n; |
| 122 } |
| 123 } |
| 124 SkASSERT(&result.writable_str()[count] == s); // don't over-write |
| 125 return result; // allocated space |
| 126 } |
| 127 |
| 128 static SkString escape_name(const SkString& name) { |
| 129 return escape_name(name.c_str(), name.size()); |
| 130 } |
| 131 |
| 132 static void write_string(SkWStream* o, const SkString& s) { |
| 133 o->write(s.c_str(), s.size()); |
| 134 } |
| 135 |
| 136 static SkString format_string(const SkString& s) { |
| 137 return SkPDFString::FormatString(s.c_str(), s.size()); |
| 138 } |
| 139 |
| 140 static SkString format_string(const char* s) { |
| 141 return SkPDFString::FormatString(s, strlen(s)); |
| 142 } |
| 143 |
| 144 void SkPDFUnion::emitObject(SkWStream* stream, |
| 145 const SkPDFObjNumMap& objNumMap, |
| 146 const SkPDFSubstituteMap& substitutes) const { |
| 147 switch (fType) { |
| 148 case Type::kInt: |
| 149 stream->writeDecAsText(fIntValue); |
| 150 return; |
| 151 case Type::kBool: |
| 152 stream->writeText(fBoolValue ? "true" : "false"); |
| 153 return; |
| 154 case Type::kScalar: |
| 155 SkPDFScalar::Append(fScalarValue, stream); |
| 156 return; |
| 157 case Type::kName: |
| 158 stream->writeText("/"); |
| 159 SkASSERT(is_valid_name(fStaticString)); |
| 160 stream->writeText(fStaticString); |
| 161 return; |
| 162 case Type::kString: |
| 163 SkASSERT(fStaticString); |
| 164 write_string(stream, format_string(fStaticString)); |
| 165 return; |
| 166 case Type::kNameSkS: |
| 167 stream->writeText("/"); |
| 168 write_string(stream, escape_name(*pun(fSkString))); |
| 169 return; |
| 170 case Type::kStringSkS: |
| 171 write_string(stream, format_string(*pun(fSkString))); |
| 172 return; |
| 173 case Type::kObjRef: |
| 174 stream->writeDecAsText(objNumMap.getObjectNumber( |
| 175 substitutes.getSubstitute(fObject))); |
| 176 stream->writeText(" 0 R"); // Generation number is always 0. |
| 177 return; |
| 178 case Type::kObject: |
| 179 fObject->emitObject(stream, objNumMap, substitutes); |
| 180 return; |
| 181 default: |
| 182 SkDEBUGFAIL("SkPDFUnion::emitObject with bad type"); |
| 183 } |
| 184 } |
| 185 |
| 186 void SkPDFUnion::addResources(SkPDFObjNumMap* objNumMap, |
| 187 const SkPDFSubstituteMap& substituteMap) const { |
| 188 switch (fType) { |
| 189 case Type::kInt: |
| 190 case Type::kBool: |
| 191 case Type::kScalar: |
| 192 case Type::kName: |
| 193 case Type::kString: |
| 194 case Type::kNameSkS: |
| 195 case Type::kStringSkS: |
| 196 return; // These have no resources. |
| 197 case Type::kObjRef: { |
| 198 SkPDFObject* obj = substituteMap.getSubstitute(fObject); |
| 199 if (objNumMap->addObject(obj)) { |
| 200 obj->addResources(objNumMap, substituteMap); |
| 201 } |
| 202 return; |
| 203 } |
| 204 case Type::kObject: |
| 205 fObject->addResources(objNumMap, substituteMap); |
| 206 return; |
| 207 default: |
| 208 SkDEBUGFAIL("SkPDFUnion::addResources with bad type"); |
| 209 } |
| 210 } |
| 211 |
| 212 SkPDFUnion SkPDFUnion::Int(int32_t value) { |
| 213 SkPDFUnion u(Type::kInt); |
| 214 u.fIntValue = value; |
| 215 return u.move(); |
| 216 } |
| 217 |
| 218 SkPDFUnion SkPDFUnion::Bool(bool value) { |
| 219 SkPDFUnion u(Type::kBool); |
| 220 u.fBoolValue = value; |
| 221 return u.move(); |
| 222 } |
| 223 |
| 224 SkPDFUnion SkPDFUnion::Scalar(SkScalar value) { |
| 225 SkPDFUnion u(Type::kScalar); |
| 226 u.fScalarValue = value; |
| 227 return u.move(); |
| 228 } |
| 229 |
| 230 SkPDFUnion SkPDFUnion::Name(const char* value) { |
| 231 SkPDFUnion u(Type::kName); |
| 232 SkASSERT(value); |
| 233 SkASSERT(is_valid_name(value)); |
| 234 u.fStaticString = value; |
| 235 return u.move(); |
| 236 } |
| 237 |
| 238 SkPDFUnion SkPDFUnion::String(const char* value) { |
| 239 SkPDFUnion u(Type::kString); |
| 240 SkASSERT(value); |
| 241 u.fStaticString = value; |
| 242 return u.move(); |
| 243 } |
| 244 |
| 245 SkPDFUnion SkPDFUnion::Name(const SkString& s) { |
| 246 SkPDFUnion u(Type::kNameSkS); |
| 247 SkNEW_PLACEMENT_ARGS(pun(u.fSkString), SkString, (s)); |
| 248 return u.move(); |
| 249 } |
| 250 |
| 251 SkPDFUnion SkPDFUnion::String(const SkString& s) { |
| 252 SkPDFUnion u(Type::kStringSkS); |
| 253 SkNEW_PLACEMENT_ARGS(pun(u.fSkString), SkString, (s)); |
| 254 return u.move(); |
| 255 } |
| 256 |
| 257 SkPDFUnion SkPDFUnion::ObjRef(SkPDFObject* ptr) { |
| 258 SkPDFUnion u(Type::kObjRef); |
| 259 SkASSERT(ptr); |
| 260 u.fObject = ptr; |
| 261 return u.move(); |
| 262 } |
| 263 |
| 264 SkPDFUnion SkPDFUnion::Object(SkPDFObject* ptr) { |
| 265 SkPDFUnion u(Type::kObject); |
| 266 SkASSERT(ptr); |
| 267 u.fObject = ptr; |
| 268 return u.move(); |
42 } | 269 } |
43 | 270 |
44 //////////////////////////////////////////////////////////////////////////////// | 271 //////////////////////////////////////////////////////////////////////////////// |
45 | 272 |
46 SkPDFInt::SkPDFInt(int32_t value) : fValue(value) {} | 273 void SkPDFAtom::emitObject(SkWStream* stream, |
47 SkPDFInt::~SkPDFInt() {} | 274 const SkPDFObjNumMap& objNumMap, |
48 | 275 const SkPDFSubstituteMap& substitutes) { |
49 void SkPDFInt::emitObject(SkWStream* stream, | 276 fValue.emitObject(stream, objNumMap, substitutes); |
50 const SkPDFObjNumMap&, | 277 } |
51 const SkPDFSubstituteMap&) { | 278 void SkPDFAtom::addResources(SkPDFObjNumMap* map, |
52 stream->writeDecAsText(fValue); | 279 const SkPDFSubstituteMap& substitutes) const { |
| 280 fValue.addResources(map, substitutes); |
53 } | 281 } |
54 | 282 |
55 //////////////////////////////////////////////////////////////////////////////// | 283 //////////////////////////////////////////////////////////////////////////////// |
56 | 284 |
57 SkPDFBool::SkPDFBool(bool value) : fValue(value) {} | |
58 SkPDFBool::~SkPDFBool() {} | |
59 | |
60 void SkPDFBool::emitObject(SkWStream* stream, | |
61 const SkPDFObjNumMap&, | |
62 const SkPDFSubstituteMap&) { | |
63 stream->writeText(fValue ? "true" : "false"); | |
64 } | |
65 | |
66 //////////////////////////////////////////////////////////////////////////////// | |
67 | |
68 SkPDFScalar::SkPDFScalar(SkScalar value) : fValue(value) {} | |
69 SkPDFScalar::~SkPDFScalar() {} | |
70 | |
71 void SkPDFScalar::emitObject(SkWStream* stream, | |
72 const SkPDFObjNumMap&, | |
73 const SkPDFSubstituteMap&) { | |
74 SkPDFScalar::Append(fValue, stream); | |
75 } | |
76 | |
77 // static | 285 // static |
78 void SkPDFScalar::Append(SkScalar value, SkWStream* stream) { | 286 void SkPDFScalar::Append(SkScalar value, SkWStream* stream) { |
79 // The range of reals in PDF/A is the same as SkFixed: +/- 32,767 and | 287 // The range of reals in PDF/A is the same as SkFixed: +/- 32,767 and |
80 // +/- 1/65,536 (though integers can range from 2^31 - 1 to -2^31). | 288 // +/- 1/65,536 (though integers can range from 2^31 - 1 to -2^31). |
81 // When using floats that are outside the whole value range, we can use | 289 // When using floats that are outside the whole value range, we can use |
82 // integers instead. | 290 // integers instead. |
83 | 291 |
84 #if !defined(SK_ALLOW_LARGE_PDF_SCALARS) | 292 #if !defined(SK_ALLOW_LARGE_PDF_SCALARS) |
85 if (value > 32767 || value < -32767) { | 293 if (value > 32767 || value < -32767) { |
86 stream->writeDecAsText(SkScalarRoundToInt(value)); | 294 stream->writeDecAsText(SkScalarRoundToInt(value)); |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
118 if (buffer[len - 1] == '.') { | 326 if (buffer[len - 1] == '.') { |
119 buffer[len - 1] = '\0'; | 327 buffer[len - 1] = '\0'; |
120 } | 328 } |
121 stream->writeText(buffer); | 329 stream->writeText(buffer); |
122 return; | 330 return; |
123 #endif // SK_ALLOW_LARGE_PDF_SCALARS | 331 #endif // SK_ALLOW_LARGE_PDF_SCALARS |
124 } | 332 } |
125 | 333 |
126 //////////////////////////////////////////////////////////////////////////////// | 334 //////////////////////////////////////////////////////////////////////////////// |
127 | 335 |
128 SkPDFString::SkPDFString(const char value[]) | 336 // static |
129 : fValue(FormatString(value, strlen(value))) { | |
130 } | |
131 | 337 |
132 SkPDFString::SkPDFString(const SkString& value) | |
133 : fValue(FormatString(value.c_str(), value.size())) { | |
134 } | |
135 | |
136 SkPDFString::~SkPDFString() {} | |
137 | |
138 void SkPDFString::emitObject(SkWStream* stream, | |
139 const SkPDFObjNumMap&, | |
140 const SkPDFSubstituteMap&) { | |
141 stream->write(fValue.c_str(), fValue.size()); | |
142 } | |
143 | |
144 // static | |
145 SkString SkPDFString::FormatString(const char* cin, size_t len) { | 338 SkString SkPDFString::FormatString(const char* cin, size_t len) { |
146 SkASSERT(len <= kMaxLen); | 339 SkASSERT(len <= kMaxLen); |
147 | 340 |
148 // 7-bit clean is a heuristic to decide what string format to use; | 341 // 7-bit clean is a heuristic to decide what string format to use; |
149 // a 7-bit clean string should require little escaping. | 342 // a 7-bit clean string should require little escaping. |
150 bool sevenBitClean = true; | 343 bool sevenBitClean = true; |
151 size_t characterCount = 2 + len; | 344 size_t characterCount = 2 + len; |
152 for (size_t i = 0; i < len; i++) { | 345 for (size_t i = 0; i < len; i++) { |
153 if (cin[i] > '~' || cin[i] < ' ') { | 346 if (cin[i] > '~' || cin[i] < ' ') { |
154 sevenBitClean = false; | 347 sevenBitClean = false; |
(...skipping 25 matching lines...) Expand all Loading... |
180 *str++ = gHex[(c >> 4) & 0xF]; | 373 *str++ = gHex[(c >> 4) & 0xF]; |
181 *str++ = gHex[(c ) & 0xF]; | 374 *str++ = gHex[(c ) & 0xF]; |
182 } | 375 } |
183 *str++ = '>'; | 376 *str++ = '>'; |
184 } | 377 } |
185 return result; | 378 return result; |
186 } | 379 } |
187 | 380 |
188 //////////////////////////////////////////////////////////////////////////////// | 381 //////////////////////////////////////////////////////////////////////////////// |
189 | 382 |
190 SkPDFName::SkPDFName(const char name[]) : fValue(FormatName(SkString(name))) {} | |
191 SkPDFName::SkPDFName(const SkString& name) : fValue(FormatName(name)) {} | |
192 SkPDFName::~SkPDFName() {} | |
193 | |
194 bool SkPDFName::operator==(const SkPDFName& b) const { | |
195 return fValue == b.fValue; | |
196 } | |
197 | |
198 void SkPDFName::emitObject(SkWStream* stream, | |
199 const SkPDFObjNumMap&, | |
200 const SkPDFSubstituteMap&) { | |
201 stream->write(fValue.c_str(), fValue.size()); | |
202 } | |
203 | |
204 // static | |
205 SkString SkPDFName::FormatName(const SkString& input) { | |
206 SkASSERT(input.size() <= kMaxLen); | |
207 // TODO(vandebo) If more escaping is needed, improve the linear scan. | |
208 static const char escaped[] = "#/%()<>[]{}"; | |
209 | |
210 SkString result("/"); | |
211 for (size_t i = 0; i < input.size(); i++) { | |
212 if (input[i] & 0x80 || input[i] < '!' || strchr(escaped, input[i])) { | |
213 result.append("#"); | |
214 // Mask with 0xFF to avoid sign extension. i.e. #FFFFFF81 | |
215 result.appendHex(input[i] & 0xFF, 2); | |
216 } else { | |
217 result.append(input.c_str() + i, 1); | |
218 } | |
219 } | |
220 | |
221 return result; | |
222 } | |
223 | |
224 //////////////////////////////////////////////////////////////////////////////// | |
225 | |
226 SkPDFArray::SkPDFArray() {} | 383 SkPDFArray::SkPDFArray() {} |
227 SkPDFArray::~SkPDFArray() { | 384 SkPDFArray::~SkPDFArray() { |
228 fValue.unrefAll(); | 385 for (SkPDFUnion& value : fValues) { |
| 386 value.~SkPDFUnion(); |
| 387 } |
| 388 fValues.reset(); |
229 } | 389 } |
230 | 390 |
| 391 int SkPDFArray::size() const { return fValues.count(); } |
| 392 |
| 393 void SkPDFArray::reserve(int length) { fValues.setReserve(length); } |
| 394 |
231 void SkPDFArray::emitObject(SkWStream* stream, | 395 void SkPDFArray::emitObject(SkWStream* stream, |
232 const SkPDFObjNumMap& objNumMap, | 396 const SkPDFObjNumMap& objNumMap, |
233 const SkPDFSubstituteMap& substitutes) { | 397 const SkPDFSubstituteMap& substitutes) { |
234 stream->writeText("["); | 398 stream->writeText("["); |
235 for (int i = 0; i < fValue.count(); i++) { | 399 for (int i = 0; i < fValues.count(); i++) { |
236 SkASSERT(substitutes.getSubstitute(fValue[i]) == fValue[i]); | 400 fValues[i].emitObject(stream, objNumMap, substitutes); |
237 fValue[i]->emitObject(stream, objNumMap, substitutes); | 401 if (i + 1 < fValues.count()) { |
238 if (i + 1 < fValue.count()) { | |
239 stream->writeText(" "); | 402 stream->writeText(" "); |
240 } | 403 } |
241 } | 404 } |
242 stream->writeText("]"); | 405 stream->writeText("]"); |
243 } | 406 } |
244 | 407 |
245 void SkPDFArray::addResources(SkPDFObjNumMap* catalog, | 408 void SkPDFArray::addResources(SkPDFObjNumMap* catalog, |
246 const SkPDFSubstituteMap& substitutes) const { | 409 const SkPDFSubstituteMap& substitutes) const { |
247 for (int i = 0; i < fValue.count(); i++) { | 410 for (const SkPDFUnion& value : fValues) { |
248 SkASSERT(substitutes.getSubstitute(fValue[i]) == fValue[i]); | 411 value.addResources(catalog, substitutes); |
249 fValue[i]->addResources(catalog, substitutes); | |
250 } | 412 } |
251 } | 413 } |
252 | 414 |
253 void SkPDFArray::reserve(int length) { | 415 void SkPDFArray::append(SkPDFUnion&& value) { |
254 SkASSERT(length <= kMaxLen); | 416 SkNEW_PLACEMENT_ARGS(fValues.append(), SkPDFUnion, (value.move())); |
255 fValue.setReserve(length); | |
256 } | 417 } |
257 | 418 |
258 SkPDFObject* SkPDFArray::append(SkPDFObject* value) { | 419 SkPDFObject* SkPDFArray::append(SkPDFObject* value) { |
259 SkASSERT(fValue.count() < kMaxLen); | 420 // DEPRECATED |
260 value->ref(); | 421 this->append(SkPDFUnion::Object(SkRef(value))); |
261 fValue.push(value); | |
262 return value; | 422 return value; |
263 } | 423 } |
264 | 424 |
265 void SkPDFArray::appendInt(int32_t value) { | 425 void SkPDFArray::appendInt(int32_t value) { |
266 SkASSERT(fValue.count() < kMaxLen); | 426 this->append(SkPDFUnion::Int(value)); |
267 fValue.push(new SkPDFInt(value)); | 427 } |
| 428 |
| 429 void SkPDFArray::appendBool(bool value) { |
| 430 this->append(SkPDFUnion::Bool(value)); |
268 } | 431 } |
269 | 432 |
270 void SkPDFArray::appendScalar(SkScalar value) { | 433 void SkPDFArray::appendScalar(SkScalar value) { |
271 SkASSERT(fValue.count() < kMaxLen); | 434 this->append(SkPDFUnion::Scalar(value)); |
272 fValue.push(new SkPDFScalar(value)); | |
273 } | 435 } |
274 | 436 |
275 void SkPDFArray::appendName(const char name[]) { | 437 void SkPDFArray::appendName(const char name[]) { |
276 SkASSERT(fValue.count() < kMaxLen); | 438 this->append(SkPDFUnion::Name(SkString(name))); |
277 fValue.push(new SkPDFName(name)); | 439 } |
| 440 |
| 441 void SkPDFArray::appendName(const SkString& name) { |
| 442 this->append(SkPDFUnion::Name(name)); |
| 443 } |
| 444 |
| 445 void SkPDFArray::appendString(const SkString& value) { |
| 446 this->append(SkPDFUnion::String(value)); |
| 447 } |
| 448 |
| 449 void SkPDFArray::appendString(const char value[]) { |
| 450 this->append(SkPDFUnion::String(value)); |
| 451 } |
| 452 |
| 453 void SkPDFArray::appendObject(SkPDFObject* value) { |
| 454 this->append(SkPDFUnion::Object(value)); |
| 455 } |
| 456 |
| 457 void SkPDFArray::appendObjRef(SkPDFObject* value) { |
| 458 this->append(SkPDFUnion::ObjRef(value)); |
278 } | 459 } |
279 | 460 |
280 /////////////////////////////////////////////////////////////////////////////// | 461 /////////////////////////////////////////////////////////////////////////////// |
281 | 462 |
282 SkPDFDict::SkPDFDict() {} | 463 SkPDFDict::SkPDFDict() {} |
283 | 464 |
284 SkPDFDict::SkPDFDict(const char type[]) { | 465 SkPDFDict::~SkPDFDict() { this->clear(); } |
285 insertName("Type", type); | |
286 } | |
287 | 466 |
288 SkPDFDict::~SkPDFDict() { | 467 SkPDFDict::SkPDFDict(const char type[]) { this->insertName("Type", type); } |
289 clear(); | |
290 } | |
291 | |
292 int SkPDFDict::size() const { | |
293 return fValue.count(); | |
294 } | |
295 | 468 |
296 void SkPDFDict::emitObject(SkWStream* stream, | 469 void SkPDFDict::emitObject(SkWStream* stream, |
297 const SkPDFObjNumMap& objNumMap, | 470 const SkPDFObjNumMap& objNumMap, |
298 const SkPDFSubstituteMap& substitutes) { | 471 const SkPDFSubstituteMap& substitutes) { |
299 stream->writeText("<<"); | 472 stream->writeText("<<"); |
300 for (int i = 0; i < fValue.count(); i++) { | 473 for (int i = 0; i < fRecords.count(); i++) { |
301 SkASSERT(fValue[i].key); | 474 fRecords[i].fKey.emitObject(stream, objNumMap, substitutes); |
302 SkASSERT(fValue[i].value); | |
303 SkASSERT(substitutes.getSubstitute(fValue[i].key) == fValue[i].key); | |
304 SkASSERT(substitutes.getSubstitute(fValue[i].value) == fValue[i].value); | |
305 fValue[i].key->emitObject(stream, objNumMap, substitutes); | |
306 stream->writeText(" "); | 475 stream->writeText(" "); |
307 fValue[i].value->emitObject(stream, objNumMap, substitutes); | 476 fRecords[i].fValue.emitObject(stream, objNumMap, substitutes); |
308 if (i + 1 < fValue.count()) { | 477 if (i + 1 < fRecords.count()) { |
309 stream->writeText("\n"); | 478 stream->writeText("\n"); |
310 } | 479 } |
311 } | 480 } |
312 stream->writeText(">>"); | 481 stream->writeText(">>"); |
313 } | 482 } |
314 | 483 |
315 void SkPDFDict::addResources(SkPDFObjNumMap* catalog, | 484 void SkPDFDict::addResources(SkPDFObjNumMap* catalog, |
316 const SkPDFSubstituteMap& substitutes) const { | 485 const SkPDFSubstituteMap& substitutes) const { |
317 for (int i = 0; i < fValue.count(); i++) { | 486 for (int i = 0; i < fRecords.count(); i++) { |
318 SkASSERT(fValue[i].key); | 487 fRecords[i].fKey.addResources(catalog, substitutes); |
319 SkASSERT(fValue[i].value); | 488 fRecords[i].fValue.addResources(catalog, substitutes); |
320 fValue[i].key->addResources(catalog, substitutes); | |
321 SkASSERT(substitutes.getSubstitute(fValue[i].value) == fValue[i].value); | |
322 fValue[i].value->addResources(catalog, substitutes); | |
323 } | 489 } |
324 } | 490 } |
325 | 491 |
326 SkPDFObject* SkPDFDict::append(SkPDFName* key, SkPDFObject* value) { | 492 void SkPDFDict::set(SkPDFUnion&& name, SkPDFUnion&& value) { |
327 SkASSERT(key); | 493 Record* rec = fRecords.append(); |
328 SkASSERT(value); | 494 SkASSERT(name.isName()); |
329 *(fValue.append()) = Rec(key, value); | 495 SkNEW_PLACEMENT_ARGS(&rec->fKey, SkPDFUnion, (name.move())); |
| 496 SkNEW_PLACEMENT_ARGS(&rec->fValue, SkPDFUnion, (value.move())); |
| 497 } |
| 498 |
| 499 int SkPDFDict::size() const { return fRecords.count(); } |
| 500 |
| 501 void SkPDFDict::insertObjRef(const char key[], SkPDFObject* value) { |
| 502 this->set(SkPDFUnion::Name(key), SkPDFUnion::ObjRef(value)); |
| 503 } |
| 504 void SkPDFDict::insertObjRef(const SkString& key, SkPDFObject* value) { |
| 505 this->set(SkPDFUnion::Name(key), SkPDFUnion::ObjRef(value)); |
| 506 } |
| 507 |
| 508 void SkPDFDict::insertObject(const char key[], SkPDFObject* value) { |
| 509 this->set(SkPDFUnion::Name(key), SkPDFUnion::Object(value)); |
| 510 } |
| 511 void SkPDFDict::insertObject(const SkString& key, SkPDFObject* value) { |
| 512 this->set(SkPDFUnion::Name(key), SkPDFUnion::Object(value)); |
| 513 } |
| 514 |
| 515 // DEPRECATED |
| 516 SkPDFObject* SkPDFDict::insert(const char key[], SkPDFObject* value) { |
| 517 this->set(SkPDFUnion::Name(key), SkPDFUnion::Object(SkRef(value))); |
330 return value; | 518 return value; |
331 } | 519 } |
332 | 520 |
333 SkPDFObject* SkPDFDict::insert(SkPDFName* key, SkPDFObject* value) { | 521 void SkPDFDict::insertInt(const char key[], int32_t value) { |
334 return this->append(SkRef(key), SkRef(value)); | 522 this->set(SkPDFUnion::Name(key), SkPDFUnion::Int(value)); |
335 } | 523 } |
336 | 524 |
337 SkPDFObject* SkPDFDict::insert(const char key[], SkPDFObject* value) { | 525 void SkPDFDict::insertInt(const char key[], size_t value) { |
338 return this->append(new SkPDFName(key), SkRef(value)); | 526 this->insertInt(key, SkToS32(value)); |
339 } | |
340 | |
341 void SkPDFDict::insertInt(const char key[], int32_t value) { | |
342 (void)this->append(new SkPDFName(key), new SkPDFInt(value)); | |
343 } | 527 } |
344 | 528 |
345 void SkPDFDict::insertScalar(const char key[], SkScalar value) { | 529 void SkPDFDict::insertScalar(const char key[], SkScalar value) { |
346 (void)this->append(new SkPDFName(key), new SkPDFScalar(value)); | 530 this->set(SkPDFUnion::Name(key), SkPDFUnion::Scalar(value)); |
347 } | 531 } |
348 | 532 |
349 void SkPDFDict::insertName(const char key[], const char name[]) { | 533 void SkPDFDict::insertName(const char key[], const char name[]) { |
350 (void)this->append(new SkPDFName(key), new SkPDFName(name)); | 534 this->set(SkPDFUnion::Name(key), SkPDFUnion::Name(name)); |
| 535 } |
| 536 |
| 537 void SkPDFDict::insertName(const char key[], const SkString& name) { |
| 538 this->set(SkPDFUnion::Name(key), SkPDFUnion::Name(name)); |
| 539 } |
| 540 |
| 541 void SkPDFDict::insertString(const char key[], const char value[]) { |
| 542 this->set(SkPDFUnion::Name(key), SkPDFUnion::String(value)); |
| 543 } |
| 544 |
| 545 void SkPDFDict::insertString(const char key[], const SkString& value) { |
| 546 this->set(SkPDFUnion::Name(key), SkPDFUnion::String(value)); |
351 } | 547 } |
352 | 548 |
353 void SkPDFDict::clear() { | 549 void SkPDFDict::clear() { |
354 for (int i = 0; i < fValue.count(); i++) { | 550 for (Record& rec : fRecords) { |
355 SkASSERT(fValue[i].key); | 551 rec.fKey.~SkPDFUnion(); |
356 SkASSERT(fValue[i].value); | 552 rec.fValue.~SkPDFUnion(); |
357 fValue[i].key->unref(); | |
358 fValue[i].value->unref(); | |
359 } | 553 } |
360 fValue.reset(); | 554 fRecords.reset(); |
361 } | |
362 | |
363 void SkPDFDict::remove(const char key[]) { | |
364 SkASSERT(key); | |
365 SkPDFName name(key); | |
366 for (int i = 0; i < fValue.count(); i++) { | |
367 SkASSERT(fValue[i].key); | |
368 if (*(fValue[i].key) == name) { | |
369 fValue[i].key->unref(); | |
370 SkASSERT(fValue[i].value); | |
371 fValue[i].value->unref(); | |
372 fValue.removeShuffle(i); | |
373 return; | |
374 } | |
375 } | |
376 } | |
377 | |
378 void SkPDFDict::mergeFrom(const SkPDFDict& other) { | |
379 for (int i = 0; i < other.fValue.count(); i++) { | |
380 *(fValue.append()) = | |
381 Rec(SkRef(other.fValue[i].key), SkRef(other.fValue[i].value)); | |
382 } | |
383 } | 555 } |
384 | 556 |
385 //////////////////////////////////////////////////////////////////////////////// | 557 //////////////////////////////////////////////////////////////////////////////// |
386 | 558 |
387 SkPDFSubstituteMap::~SkPDFSubstituteMap() { | 559 SkPDFSubstituteMap::~SkPDFSubstituteMap() { |
388 fSubstituteMap.foreach( | 560 fSubstituteMap.foreach( |
389 [](SkPDFObject*, SkPDFObject** v) { (*v)->unref(); }); | 561 [](SkPDFObject*, SkPDFObject** v) { (*v)->unref(); }); |
390 } | 562 } |
391 | 563 |
392 void SkPDFSubstituteMap::setSubstitute(SkPDFObject* original, | 564 void SkPDFSubstituteMap::setSubstitute(SkPDFObject* original, |
(...skipping 18 matching lines...) Expand all Loading... |
411 fObjects.push(obj); | 583 fObjects.push(obj); |
412 return true; | 584 return true; |
413 } | 585 } |
414 | 586 |
415 int32_t SkPDFObjNumMap::getObjectNumber(SkPDFObject* obj) const { | 587 int32_t SkPDFObjNumMap::getObjectNumber(SkPDFObject* obj) const { |
416 int32_t* objectNumberFound = fObjectNumbers.find(obj); | 588 int32_t* objectNumberFound = fObjectNumbers.find(obj); |
417 SkASSERT(objectNumberFound); | 589 SkASSERT(objectNumberFound); |
418 return *objectNumberFound; | 590 return *objectNumberFound; |
419 } | 591 } |
420 | 592 |
OLD | NEW |