blob: d479a22432bd79d95924218bb7ad32a9d9a78ec3 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +00002/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00003 * Copyright 2011 Google Inc.
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +00004 *
epoger@google.comec3ed6a2011-07-28 14:26:00 +00005 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +00007 */
8
epoger@google.comec3ed6a2011-07-28 14:26:00 +00009
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +000010#include "SkPDFCatalog.h"
11#include "SkPDFTypes.h"
12#include "SkStream.h"
13
vandebo@chromium.org094316b2011-03-04 03:15:13 +000014#ifdef SK_BUILD_FOR_WIN
15 #define SNPRINTF _snprintf
16#else
17 #define SNPRINTF snprintf
18#endif
19
reed@google.com3b429982012-06-26 15:30:08 +000020SK_DEFINE_INST_COUNT(SkPDFArray)
21SK_DEFINE_INST_COUNT(SkPDFBool)
22SK_DEFINE_INST_COUNT(SkPDFDict)
23SK_DEFINE_INST_COUNT(SkPDFInt)
24SK_DEFINE_INST_COUNT(SkPDFName)
robertphillips@google.com4d73ac22012-06-13 18:54:08 +000025SK_DEFINE_INST_COUNT(SkPDFObject)
reed@google.com3b429982012-06-26 15:30:08 +000026SK_DEFINE_INST_COUNT(SkPDFObjRef)
27SK_DEFINE_INST_COUNT(SkPDFScalar)
28SK_DEFINE_INST_COUNT(SkPDFString)
robertphillips@google.com4d73ac22012-06-13 18:54:08 +000029
reed@google.com3b429982012-06-26 15:30:08 +000030///////////////////////////////////////////////////////////////////////////////
vandebo@chromium.orgf66025d2010-10-01 23:26:55 +000031
vandebo@chromium.org2ef12d42011-07-06 23:31:24 +000032void SkPDFObject::emit(SkWStream* stream, SkPDFCatalog* catalog,
33 bool indirect) {
34 SkPDFObject* realObject = catalog->getSubstituteObject(this);
35 return realObject->emitObject(stream, catalog, indirect);
36}
37
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +000038size_t SkPDFObject::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
39 SkDynamicMemoryWStream buffer;
vandebo@chromium.org2ef12d42011-07-06 23:31:24 +000040 emit(&buffer, catalog, indirect);
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +000041 return buffer.getOffset();
42}
43
edisonn@google.com5bd26d32013-02-28 14:01:44 +000044void SkPDFObject::getResources(SkTDArray<SkPDFObject*>* resourceList) {}
vandebo@chromium.orga5180862010-10-26 19:48:49 +000045
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +000046void SkPDFObject::emitIndirectObject(SkWStream* stream, SkPDFCatalog* catalog) {
47 catalog->emitObjectNumber(stream, this);
48 stream->writeText(" obj\n");
vandebo@chromium.org2ef12d42011-07-06 23:31:24 +000049 emit(stream, catalog, false);
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +000050 stream->writeText("\nendobj\n");
51}
52
53size_t SkPDFObject::getIndirectOutputSize(SkPDFCatalog* catalog) {
54 return catalog->getObjectNumberSize(this) + strlen(" obj\n") +
55 this->getOutputSize(catalog, false) + strlen("\nendobj\n");
56}
57
vandebo@chromium.org421d6442011-07-20 17:39:01 +000058void SkPDFObject::AddResourceHelper(SkPDFObject* resource,
59 SkTDArray<SkPDFObject*>* list) {
60 list->push(resource);
61 resource->ref();
62}
63
edisonn@google.com5bd26d32013-02-28 14:01:44 +000064void SkPDFObject::GetResourcesHelper(SkTDArray<SkPDFObject*>* resources,
65 SkTDArray<SkPDFObject*>* result) {
vandebo@chromium.org421d6442011-07-20 17:39:01 +000066 if (resources->count()) {
edisonn@google.com5bd26d32013-02-28 14:01:44 +000067 result->setReserve(result->count() + resources->count());
vandebo@chromium.org421d6442011-07-20 17:39:01 +000068 for (int i = 0; i < resources->count(); i++) {
edisonn@google.com5bd26d32013-02-28 14:01:44 +000069 result->push((*resources)[i]);
70 (*resources)[i]->ref();
71 (*resources)[i]->getResources(result);
vandebo@chromium.org421d6442011-07-20 17:39:01 +000072 }
73 }
74}
75
vandebo@chromium.orgd96d17b2013-01-04 19:31:24 +000076SkPDFObjRef::SkPDFObjRef(SkPDFObject* obj) : fObj(obj) {
77 SkSafeRef(obj);
78}
79
vandebo@chromium.org421d6442011-07-20 17:39:01 +000080SkPDFObjRef::~SkPDFObjRef() {}
81
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +000082void SkPDFObjRef::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
83 bool indirect) {
84 SkASSERT(!indirect);
85 catalog->emitObjectNumber(stream, fObj.get());
86 stream->writeText(" R");
87}
88
89size_t SkPDFObjRef::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
90 SkASSERT(!indirect);
91 return catalog->getObjectNumberSize(fObj.get()) + strlen(" R");
92}
93
vandebo@chromium.orgf66025d2010-10-01 23:26:55 +000094SkPDFInt::SkPDFInt(int32_t value) : fValue(value) {}
95SkPDFInt::~SkPDFInt() {}
96
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +000097void SkPDFInt::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
98 bool indirect) {
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +000099 if (indirect) {
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000100 return emitIndirectObject(stream, catalog);
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000101 }
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000102 stream->writeDecAsText(fValue);
103}
104
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000105SkPDFBool::SkPDFBool(bool value) : fValue(value) {}
106SkPDFBool::~SkPDFBool() {}
107
108void SkPDFBool::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
109 bool indirect) {
110 SkASSERT(!indirect);
111 if (fValue) {
112 stream->writeText("true");
113 } else {
114 stream->writeText("false");
115 }
116}
117
118size_t SkPDFBool::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
119 SkASSERT(!indirect);
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000120 if (fValue) {
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000121 return strlen("true");
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000122 }
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000123 return strlen("false");
124}
125
vandebo@chromium.orgf66025d2010-10-01 23:26:55 +0000126SkPDFScalar::SkPDFScalar(SkScalar value) : fValue(value) {}
127SkPDFScalar::~SkPDFScalar() {}
128
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000129void SkPDFScalar::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
130 bool indirect) {
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000131 if (indirect) {
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000132 return emitIndirectObject(stream, catalog);
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000133 }
vandebo@chromium.org094316b2011-03-04 03:15:13 +0000134
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +0000135 Append(fValue, stream);
vandebo@chromium.org094316b2011-03-04 03:15:13 +0000136}
137
138// static
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +0000139void SkPDFScalar::Append(SkScalar value, SkWStream* stream) {
vandebo@chromium.org094316b2011-03-04 03:15:13 +0000140 // The range of reals in PDF/A is the same as SkFixed: +/- 32,767 and
141 // +/- 1/65,536 (though integers can range from 2^31 - 1 to -2^31).
142 // When using floats that are outside the whole value range, we can use
143 // integers instead.
144
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +0000145
vandebo@chromium.org094316b2011-03-04 03:15:13 +0000146#if defined(SK_SCALAR_IS_FIXED)
epoger@google.com2047f002011-05-17 17:36:59 +0000147 stream->writeScalarAsText(value);
vandebo@chromium.org094316b2011-03-04 03:15:13 +0000148 return;
149#endif // SK_SCALAR_IS_FIXED
150
151#if !defined(SK_ALLOW_LARGE_PDF_SCALARS)
152 if (value > 32767 || value < -32767) {
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +0000153 stream->writeDecAsText(SkScalarRound(value));
vandebo@chromium.org094316b2011-03-04 03:15:13 +0000154 return;
155 }
156
157 char buffer[SkStrAppendScalar_MaxSize];
158 char* end = SkStrAppendFixed(buffer, SkScalarToFixed(value));
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +0000159 stream->write(buffer, end - buffer);
vandebo@chromium.org094316b2011-03-04 03:15:13 +0000160 return;
161#endif // !SK_ALLOW_LARGE_PDF_SCALARS
162
163#if defined(SK_SCALAR_IS_FLOAT) && defined(SK_ALLOW_LARGE_PDF_SCALARS)
164 // Floats have 24bits of significance, so anything outside that range is
165 // no more precise than an int. (Plus PDF doesn't support scientific
166 // notation, so this clamps to SK_Max/MinS32).
167 if (value > (1 << 24) || value < -(1 << 24)) {
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +0000168 stream->writeDecAsText(value);
vandebo@chromium.org094316b2011-03-04 03:15:13 +0000169 return;
170 }
171 // Continue to enforce the PDF limits for small floats.
172 if (value < 1.0f/65536 && value > -1.0f/65536) {
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +0000173 stream->writeDecAsText(0);
vandebo@chromium.org094316b2011-03-04 03:15:13 +0000174 return;
175 }
176 // SkStrAppendFloat might still use scientific notation, so use snprintf
177 // directly..
178 static const int kFloat_MaxSize = 19;
179 char buffer[kFloat_MaxSize];
180 int len = SNPRINTF(buffer, kFloat_MaxSize, "%#.8f", value);
181 // %f always prints trailing 0s, so strip them.
182 for (; buffer[len - 1] == '0' && len > 0; len--) {
183 buffer[len - 1] = '\0';
184 }
185 if (buffer[len - 1] == '.') {
186 buffer[len - 1] = '\0';
187 }
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +0000188 stream->writeText(buffer);
vandebo@chromium.org094316b2011-03-04 03:15:13 +0000189 return;
190#endif // SK_SCALAR_IS_FLOAT && SK_ALLOW_LARGE_PDF_SCALARS
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000191}
192
193SkPDFString::SkPDFString(const char value[])
reed@google.comf6c3ebd2011-07-20 17:20:28 +0000194 : fValue(FormatString(value, strlen(value))) {
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000195}
196
197SkPDFString::SkPDFString(const SkString& value)
reed@google.comf6c3ebd2011-07-20 17:20:28 +0000198 : fValue(FormatString(value.c_str(), value.size())) {
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000199}
200
201SkPDFString::SkPDFString(const uint16_t* value, size_t len, bool wideChars)
reed@google.comf6c3ebd2011-07-20 17:20:28 +0000202 : fValue(FormatString(value, len, wideChars)) {
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000203}
204
vandebo@chromium.orgf66025d2010-10-01 23:26:55 +0000205SkPDFString::~SkPDFString() {}
206
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000207void SkPDFString::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
208 bool indirect) {
209 if (indirect)
210 return emitIndirectObject(stream, catalog);
211 stream->write(fValue.c_str(), fValue.size());
212}
213
214size_t SkPDFString::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
215 if (indirect)
216 return getIndirectOutputSize(catalog);
217 return fValue.size();
218}
219
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000220// static
reed@google.comf6c3ebd2011-07-20 17:20:28 +0000221SkString SkPDFString::FormatString(const char* input, size_t len) {
222 return DoFormatString(input, len, false, false);
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000223}
224
reed@google.comf6c3ebd2011-07-20 17:20:28 +0000225SkString SkPDFString::FormatString(const uint16_t* input, size_t len,
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000226 bool wideChars) {
reed@google.comf6c3ebd2011-07-20 17:20:28 +0000227 return DoFormatString(input, len, true, wideChars);
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000228}
229
230// static
reed@google.comf6c3ebd2011-07-20 17:20:28 +0000231SkString SkPDFString::DoFormatString(const void* input, size_t len,
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000232 bool wideInput, bool wideOutput) {
233 SkASSERT(len <= kMaxLen);
234 const uint16_t* win = (const uint16_t*) input;
235 const char* cin = (const char*) input;
236
237 if (wideOutput) {
238 SkASSERT(wideInput);
239 SkString result;
240 result.append("<");
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000241 for (size_t i = 0; i < len; i++) {
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000242 result.appendHex(win[i], 4);
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000243 }
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000244 result.append(">");
245 return result;
246 }
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000247
248 // 7-bit clean is a heuristic to decide what string format to use;
249 // a 7-bit clean string should require little escaping.
250 bool sevenBitClean = true;
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000251 for (size_t i = 0; i < len; i++) {
252 SkASSERT(!wideInput || !(win[i] & ~0xFF));
253 char val = wideInput ? win[i] : cin[i];
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000254 if (val > '~' || val < ' ') {
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000255 sevenBitClean = false;
256 break;
257 }
258 }
259
260 SkString result;
261 if (sevenBitClean) {
262 result.append("(");
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000263 for (size_t i = 0; i < len; i++) {
264 SkASSERT(!wideInput || !(win[i] & ~0xFF));
265 char val = wideInput ? win[i] : cin[i];
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000266 if (val == '\\' || val == '(' || val == ')') {
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000267 result.append("\\");
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000268 }
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000269 result.append(&val, 1);
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000270 }
271 result.append(")");
272 } else {
273 result.append("<");
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000274 for (size_t i = 0; i < len; i++) {
275 SkASSERT(!wideInput || !(win[i] & ~0xFF));
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000276 unsigned char val = wideInput ? win[i] : cin[i];
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000277 result.appendHex(val, 2);
278 }
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000279 result.append(">");
280 }
281
282 return result;
283}
284
reed@google.comf6c3ebd2011-07-20 17:20:28 +0000285SkPDFName::SkPDFName(const char name[]) : fValue(FormatName(SkString(name))) {}
286SkPDFName::SkPDFName(const SkString& name) : fValue(FormatName(name)) {}
vandebo@chromium.orgf66025d2010-10-01 23:26:55 +0000287SkPDFName::~SkPDFName() {}
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000288
vandebo@chromium.org421d6442011-07-20 17:39:01 +0000289bool SkPDFName::operator==(const SkPDFName& b) const {
290 return fValue == b.fValue;
291}
292
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000293void SkPDFName::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
294 bool indirect) {
295 SkASSERT(!indirect);
296 stream->write(fValue.c_str(), fValue.size());
297}
298
299size_t SkPDFName::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
300 SkASSERT(!indirect);
301 return fValue.size();
302}
303
vandebo@chromium.orgf66025d2010-10-01 23:26:55 +0000304// static
reed@google.comf6c3ebd2011-07-20 17:20:28 +0000305SkString SkPDFName::FormatName(const SkString& input) {
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000306 SkASSERT(input.size() <= kMaxLen);
vandebo@chromium.org251a7662012-09-21 17:50:50 +0000307 // TODO(vandebo) If more escaping is needed, improve the linear scan.
308 static const char escaped[] = "#/%()<>[]{}";
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000309
310 SkString result("/");
311 for (size_t i = 0; i < input.size(); i++) {
vandebo@chromium.org251a7662012-09-21 17:50:50 +0000312 if (input[i] & 0x80 || input[i] < '!' || strchr(escaped, input[i])) {
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000313 result.append("#");
vandebo@chromium.orgc0376fe2012-03-05 18:44:33 +0000314 // Mask with 0xFF to avoid sign extension. i.e. #FFFFFF81
315 result.appendHex(input[i] & 0xFF, 2);
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000316 } else {
317 result.append(input.c_str() + i, 1);
318 }
319 }
320
321 return result;
322}
323
vandebo@chromium.orgf66025d2010-10-01 23:26:55 +0000324SkPDFArray::SkPDFArray() {}
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000325SkPDFArray::~SkPDFArray() {
reed@google.com2812b802011-07-19 15:46:40 +0000326 fValue.unrefAll();
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000327}
328
329void SkPDFArray::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
330 bool indirect) {
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000331 if (indirect) {
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000332 return emitIndirectObject(stream, catalog);
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000333 }
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000334
335 stream->writeText("[");
336 for (int i = 0; i < fValue.count(); i++) {
vandebo@chromium.org2ef12d42011-07-06 23:31:24 +0000337 fValue[i]->emit(stream, catalog, false);
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000338 if (i + 1 < fValue.count()) {
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000339 stream->writeText(" ");
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000340 }
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000341 }
342 stream->writeText("]");
343}
344
345size_t SkPDFArray::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000346 if (indirect) {
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000347 return getIndirectOutputSize(catalog);
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000348 }
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000349
350 size_t result = strlen("[]");
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000351 if (fValue.count()) {
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000352 result += fValue.count() - 1;
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000353 }
354 for (int i = 0; i < fValue.count(); i++) {
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000355 result += fValue[i]->getOutputSize(catalog, false);
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000356 }
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000357 return result;
358}
359
360void SkPDFArray::reserve(int length) {
361 SkASSERT(length <= kMaxLen);
362 fValue.setReserve(length);
363}
364
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000365SkPDFObject* SkPDFArray::setAt(int offset, SkPDFObject* value) {
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000366 SkASSERT(offset < fValue.count());
reed@google.com2812b802011-07-19 15:46:40 +0000367 value->ref();
368 fValue[offset]->unref();
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000369 fValue[offset] = value;
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000370 return value;
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000371}
372
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000373SkPDFObject* SkPDFArray::append(SkPDFObject* value) {
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000374 SkASSERT(fValue.count() < kMaxLen);
reed@google.com2812b802011-07-19 15:46:40 +0000375 value->ref();
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000376 fValue.push(value);
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000377 return value;
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000378}
379
reed@google.comc789cf12011-07-20 12:14:33 +0000380void SkPDFArray::appendInt(int32_t value) {
381 SkASSERT(fValue.count() < kMaxLen);
382 fValue.push(new SkPDFInt(value));
383}
384
385void SkPDFArray::appendScalar(SkScalar value) {
386 SkASSERT(fValue.count() < kMaxLen);
387 fValue.push(new SkPDFScalar(value));
388}
389
390void SkPDFArray::appendName(const char name[]) {
391 SkASSERT(fValue.count() < kMaxLen);
392 fValue.push(new SkPDFName(name));
393}
394
395///////////////////////////////////////////////////////////////////////////////
396
vandebo@chromium.orgf66025d2010-10-01 23:26:55 +0000397SkPDFDict::SkPDFDict() {}
vandebo@chromium.orgd877fdb2010-10-12 23:08:13 +0000398
399SkPDFDict::SkPDFDict(const char type[]) {
vandebo@chromium.org06f7f402011-07-20 18:39:20 +0000400 insertName("Type", type);
vandebo@chromium.orgd877fdb2010-10-12 23:08:13 +0000401}
402
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000403SkPDFDict::~SkPDFDict() {
vandebo@chromium.orgd877fdb2010-10-12 23:08:13 +0000404 clear();
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000405}
406
407void SkPDFDict::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
408 bool indirect) {
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000409 if (indirect) {
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000410 return emitIndirectObject(stream, catalog);
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000411 }
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000412
413 stream->writeText("<<");
414 for (int i = 0; i < fValue.count(); i++) {
415 fValue[i].key->emitObject(stream, catalog, false);
416 stream->writeText(" ");
vandebo@chromium.org2ef12d42011-07-06 23:31:24 +0000417 fValue[i].value->emit(stream, catalog, false);
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000418 stream->writeText("\n");
419 }
420 stream->writeText(">>");
421}
422
423size_t SkPDFDict::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000424 if (indirect) {
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000425 return getIndirectOutputSize(catalog);
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000426 }
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000427
428 size_t result = strlen("<<>>") + (fValue.count() * 2);
429 for (int i = 0; i < fValue.count(); i++) {
430 result += fValue[i].key->getOutputSize(catalog, false);
431 result += fValue[i].value->getOutputSize(catalog, false);
432 }
433 return result;
434}
435
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000436SkPDFObject* SkPDFDict::insert(SkPDFName* key, SkPDFObject* value) {
reed@google.com2812b802011-07-19 15:46:40 +0000437 key->ref();
438 value->ref();
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000439 struct Rec* newEntry = fValue.append();
440 newEntry->key = key;
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000441 newEntry->value = value;
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000442 return value;
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000443}
vandebo@chromium.orgd877fdb2010-10-12 23:08:13 +0000444
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000445SkPDFObject* SkPDFDict::insert(const char key[], SkPDFObject* value) {
reed@google.com2812b802011-07-19 15:46:40 +0000446 value->ref();
447 struct Rec* newEntry = fValue.append();
448 newEntry->key = new SkPDFName(key);
449 newEntry->value = value;
450 return value;
vandebo@chromium.orgd877fdb2010-10-12 23:08:13 +0000451}
452
reed@google.comc789cf12011-07-20 12:14:33 +0000453void SkPDFDict::insertInt(const char key[], int32_t value) {
454 struct Rec* newEntry = fValue.append();
455 newEntry->key = new SkPDFName(key);
456 newEntry->value = new SkPDFInt(value);
457}
458
459void SkPDFDict::insertScalar(const char key[], SkScalar value) {
460 struct Rec* newEntry = fValue.append();
461 newEntry->key = new SkPDFName(key);
462 newEntry->value = new SkPDFScalar(value);
463}
464
465void SkPDFDict::insertName(const char key[], const char name[]) {
466 struct Rec* newEntry = fValue.append();
467 newEntry->key = new SkPDFName(key);
468 newEntry->value = new SkPDFName(name);
469}
470
vandebo@chromium.orgd877fdb2010-10-12 23:08:13 +0000471void SkPDFDict::clear() {
472 for (int i = 0; i < fValue.count(); i++) {
reed@google.com2812b802011-07-19 15:46:40 +0000473 fValue[i].key->unref();
474 fValue[i].value->unref();
vandebo@chromium.orgd877fdb2010-10-12 23:08:13 +0000475 }
476 fValue.reset();
477}
vandebo@chromium.org421d6442011-07-20 17:39:01 +0000478
479SkPDFDict::Iter::Iter(const SkPDFDict& dict)
480 : fIter(dict.fValue.begin()),
481 fStop(dict.fValue.end()) {
482}
483
484SkPDFName* SkPDFDict::Iter::next(SkPDFObject** value) {
485 if (fIter != fStop) {
commit-bot@chromium.orgaa537d42013-02-28 19:03:13 +0000486 const Rec* cur = fIter;
vandebo@chromium.org421d6442011-07-20 17:39:01 +0000487 fIter++;
488 *value = cur->value;
489 return cur->key;
490 }
491 *value = NULL;
492 return NULL;
493}