blob: 55871c507d2fc99c62ed4504a3390ad9dd36c837 [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 +000020///////////////////////////////////////////////////////////////////////////////
vandebo@chromium.orgf66025d2010-10-01 23:26:55 +000021
vandebo@chromium.org2ef12d42011-07-06 23:31:24 +000022void SkPDFObject::emit(SkWStream* stream, SkPDFCatalog* catalog,
23 bool indirect) {
24 SkPDFObject* realObject = catalog->getSubstituteObject(this);
25 return realObject->emitObject(stream, catalog, indirect);
26}
27
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +000028size_t SkPDFObject::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
29 SkDynamicMemoryWStream buffer;
vandebo@chromium.org2ef12d42011-07-06 23:31:24 +000030 emit(&buffer, catalog, indirect);
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +000031 return buffer.getOffset();
32}
33
edisonn@google.com6addb192013-04-02 15:33:08 +000034void SkPDFObject::getResources(const SkTSet<SkPDFObject*>& knownResourceObjects,
35 SkTSet<SkPDFObject*>* newResourceObjects) {}
vandebo@chromium.orga5180862010-10-26 19:48:49 +000036
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +000037void SkPDFObject::emitIndirectObject(SkWStream* stream, SkPDFCatalog* catalog) {
38 catalog->emitObjectNumber(stream, this);
39 stream->writeText(" obj\n");
vandebo@chromium.org2ef12d42011-07-06 23:31:24 +000040 emit(stream, catalog, false);
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +000041 stream->writeText("\nendobj\n");
42}
43
44size_t SkPDFObject::getIndirectOutputSize(SkPDFCatalog* catalog) {
45 return catalog->getObjectNumberSize(this) + strlen(" obj\n") +
46 this->getOutputSize(catalog, false) + strlen("\nendobj\n");
47}
48
vandebo@chromium.org421d6442011-07-20 17:39:01 +000049void SkPDFObject::AddResourceHelper(SkPDFObject* resource,
50 SkTDArray<SkPDFObject*>* list) {
51 list->push(resource);
52 resource->ref();
53}
54
edisonn@google.com6addb192013-04-02 15:33:08 +000055void SkPDFObject::GetResourcesHelper(
56 const SkTDArray<SkPDFObject*>* resources,
57 const SkTSet<SkPDFObject*>& knownResourceObjects,
58 SkTSet<SkPDFObject*>* newResourceObjects) {
vandebo@chromium.org421d6442011-07-20 17:39:01 +000059 if (resources->count()) {
edisonn@google.com6addb192013-04-02 15:33:08 +000060 newResourceObjects->setReserve(
61 newResourceObjects->count() + resources->count());
vandebo@chromium.org421d6442011-07-20 17:39:01 +000062 for (int i = 0; i < resources->count(); i++) {
edisonn@google.com6addb192013-04-02 15:33:08 +000063 if (!knownResourceObjects.contains((*resources)[i]) &&
64 !newResourceObjects->contains((*resources)[i])) {
65 newResourceObjects->add((*resources)[i]);
66 (*resources)[i]->ref();
67 (*resources)[i]->getResources(knownResourceObjects,
68 newResourceObjects);
69 }
vandebo@chromium.org421d6442011-07-20 17:39:01 +000070 }
71 }
72}
73
vandebo@chromium.orgd96d17b2013-01-04 19:31:24 +000074SkPDFObjRef::SkPDFObjRef(SkPDFObject* obj) : fObj(obj) {
75 SkSafeRef(obj);
76}
77
vandebo@chromium.org421d6442011-07-20 17:39:01 +000078SkPDFObjRef::~SkPDFObjRef() {}
79
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +000080void SkPDFObjRef::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
81 bool indirect) {
82 SkASSERT(!indirect);
83 catalog->emitObjectNumber(stream, fObj.get());
84 stream->writeText(" R");
85}
86
87size_t SkPDFObjRef::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
88 SkASSERT(!indirect);
89 return catalog->getObjectNumberSize(fObj.get()) + strlen(" R");
90}
91
vandebo@chromium.orgf66025d2010-10-01 23:26:55 +000092SkPDFInt::SkPDFInt(int32_t value) : fValue(value) {}
93SkPDFInt::~SkPDFInt() {}
94
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +000095void SkPDFInt::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
96 bool indirect) {
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +000097 if (indirect) {
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +000098 return emitIndirectObject(stream, catalog);
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +000099 }
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000100 stream->writeDecAsText(fValue);
101}
102
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000103SkPDFBool::SkPDFBool(bool value) : fValue(value) {}
104SkPDFBool::~SkPDFBool() {}
105
106void SkPDFBool::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
107 bool indirect) {
108 SkASSERT(!indirect);
109 if (fValue) {
110 stream->writeText("true");
111 } else {
112 stream->writeText("false");
113 }
114}
115
116size_t SkPDFBool::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
117 SkASSERT(!indirect);
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000118 if (fValue) {
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000119 return strlen("true");
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000120 }
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000121 return strlen("false");
122}
123
vandebo@chromium.orgf66025d2010-10-01 23:26:55 +0000124SkPDFScalar::SkPDFScalar(SkScalar value) : fValue(value) {}
125SkPDFScalar::~SkPDFScalar() {}
126
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000127void SkPDFScalar::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
128 bool indirect) {
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000129 if (indirect) {
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000130 return emitIndirectObject(stream, catalog);
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000131 }
vandebo@chromium.org094316b2011-03-04 03:15:13 +0000132
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +0000133 Append(fValue, stream);
vandebo@chromium.org094316b2011-03-04 03:15:13 +0000134}
135
136// static
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +0000137void SkPDFScalar::Append(SkScalar value, SkWStream* stream) {
vandebo@chromium.org094316b2011-03-04 03:15:13 +0000138 // The range of reals in PDF/A is the same as SkFixed: +/- 32,767 and
139 // +/- 1/65,536 (though integers can range from 2^31 - 1 to -2^31).
140 // When using floats that are outside the whole value range, we can use
141 // integers instead.
142
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +0000143
vandebo@chromium.org094316b2011-03-04 03:15:13 +0000144#if defined(SK_SCALAR_IS_FIXED)
epoger@google.com2047f002011-05-17 17:36:59 +0000145 stream->writeScalarAsText(value);
vandebo@chromium.org094316b2011-03-04 03:15:13 +0000146 return;
147#endif // SK_SCALAR_IS_FIXED
148
149#if !defined(SK_ALLOW_LARGE_PDF_SCALARS)
150 if (value > 32767 || value < -32767) {
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +0000151 stream->writeDecAsText(SkScalarRound(value));
vandebo@chromium.org094316b2011-03-04 03:15:13 +0000152 return;
153 }
154
155 char buffer[SkStrAppendScalar_MaxSize];
156 char* end = SkStrAppendFixed(buffer, SkScalarToFixed(value));
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +0000157 stream->write(buffer, end - buffer);
vandebo@chromium.org094316b2011-03-04 03:15:13 +0000158 return;
159#endif // !SK_ALLOW_LARGE_PDF_SCALARS
160
161#if defined(SK_SCALAR_IS_FLOAT) && defined(SK_ALLOW_LARGE_PDF_SCALARS)
162 // Floats have 24bits of significance, so anything outside that range is
163 // no more precise than an int. (Plus PDF doesn't support scientific
164 // notation, so this clamps to SK_Max/MinS32).
165 if (value > (1 << 24) || value < -(1 << 24)) {
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +0000166 stream->writeDecAsText(value);
vandebo@chromium.org094316b2011-03-04 03:15:13 +0000167 return;
168 }
169 // Continue to enforce the PDF limits for small floats.
170 if (value < 1.0f/65536 && value > -1.0f/65536) {
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +0000171 stream->writeDecAsText(0);
vandebo@chromium.org094316b2011-03-04 03:15:13 +0000172 return;
173 }
174 // SkStrAppendFloat might still use scientific notation, so use snprintf
175 // directly..
176 static const int kFloat_MaxSize = 19;
177 char buffer[kFloat_MaxSize];
178 int len = SNPRINTF(buffer, kFloat_MaxSize, "%#.8f", value);
179 // %f always prints trailing 0s, so strip them.
180 for (; buffer[len - 1] == '0' && len > 0; len--) {
181 buffer[len - 1] = '\0';
182 }
183 if (buffer[len - 1] == '.') {
184 buffer[len - 1] = '\0';
185 }
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +0000186 stream->writeText(buffer);
vandebo@chromium.org094316b2011-03-04 03:15:13 +0000187 return;
188#endif // SK_SCALAR_IS_FLOAT && SK_ALLOW_LARGE_PDF_SCALARS
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000189}
190
191SkPDFString::SkPDFString(const char value[])
reed@google.comf6c3ebd2011-07-20 17:20:28 +0000192 : fValue(FormatString(value, strlen(value))) {
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000193}
194
195SkPDFString::SkPDFString(const SkString& value)
reed@google.comf6c3ebd2011-07-20 17:20:28 +0000196 : fValue(FormatString(value.c_str(), value.size())) {
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000197}
198
199SkPDFString::SkPDFString(const uint16_t* value, size_t len, bool wideChars)
reed@google.comf6c3ebd2011-07-20 17:20:28 +0000200 : fValue(FormatString(value, len, wideChars)) {
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000201}
202
vandebo@chromium.orgf66025d2010-10-01 23:26:55 +0000203SkPDFString::~SkPDFString() {}
204
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000205void SkPDFString::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
206 bool indirect) {
207 if (indirect)
208 return emitIndirectObject(stream, catalog);
209 stream->write(fValue.c_str(), fValue.size());
210}
211
212size_t SkPDFString::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
213 if (indirect)
214 return getIndirectOutputSize(catalog);
215 return fValue.size();
216}
217
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000218// static
reed@google.comf6c3ebd2011-07-20 17:20:28 +0000219SkString SkPDFString::FormatString(const char* input, size_t len) {
220 return DoFormatString(input, len, false, false);
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000221}
222
reed@google.comf6c3ebd2011-07-20 17:20:28 +0000223SkString SkPDFString::FormatString(const uint16_t* input, size_t len,
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000224 bool wideChars) {
reed@google.comf6c3ebd2011-07-20 17:20:28 +0000225 return DoFormatString(input, len, true, wideChars);
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000226}
227
228// static
reed@google.comf6c3ebd2011-07-20 17:20:28 +0000229SkString SkPDFString::DoFormatString(const void* input, size_t len,
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000230 bool wideInput, bool wideOutput) {
231 SkASSERT(len <= kMaxLen);
232 const uint16_t* win = (const uint16_t*) input;
233 const char* cin = (const char*) input;
234
235 if (wideOutput) {
236 SkASSERT(wideInput);
237 SkString result;
238 result.append("<");
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000239 for (size_t i = 0; i < len; i++) {
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000240 result.appendHex(win[i], 4);
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000241 }
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000242 result.append(">");
243 return result;
244 }
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000245
246 // 7-bit clean is a heuristic to decide what string format to use;
247 // a 7-bit clean string should require little escaping.
248 bool sevenBitClean = true;
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000249 for (size_t i = 0; i < len; i++) {
250 SkASSERT(!wideInput || !(win[i] & ~0xFF));
251 char val = wideInput ? win[i] : cin[i];
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000252 if (val > '~' || val < ' ') {
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000253 sevenBitClean = false;
254 break;
255 }
256 }
257
258 SkString result;
259 if (sevenBitClean) {
260 result.append("(");
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000261 for (size_t i = 0; i < len; i++) {
262 SkASSERT(!wideInput || !(win[i] & ~0xFF));
263 char val = wideInput ? win[i] : cin[i];
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000264 if (val == '\\' || val == '(' || val == ')') {
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000265 result.append("\\");
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000266 }
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000267 result.append(&val, 1);
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000268 }
269 result.append(")");
270 } else {
271 result.append("<");
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000272 for (size_t i = 0; i < len; i++) {
273 SkASSERT(!wideInput || !(win[i] & ~0xFF));
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000274 unsigned char val = wideInput ? win[i] : cin[i];
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000275 result.appendHex(val, 2);
276 }
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000277 result.append(">");
278 }
279
280 return result;
281}
282
reed@google.comf6c3ebd2011-07-20 17:20:28 +0000283SkPDFName::SkPDFName(const char name[]) : fValue(FormatName(SkString(name))) {}
284SkPDFName::SkPDFName(const SkString& name) : fValue(FormatName(name)) {}
vandebo@chromium.orgf66025d2010-10-01 23:26:55 +0000285SkPDFName::~SkPDFName() {}
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000286
vandebo@chromium.org421d6442011-07-20 17:39:01 +0000287bool SkPDFName::operator==(const SkPDFName& b) const {
288 return fValue == b.fValue;
289}
290
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000291void SkPDFName::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
292 bool indirect) {
293 SkASSERT(!indirect);
294 stream->write(fValue.c_str(), fValue.size());
295}
296
297size_t SkPDFName::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
298 SkASSERT(!indirect);
299 return fValue.size();
300}
301
vandebo@chromium.orgf66025d2010-10-01 23:26:55 +0000302// static
reed@google.comf6c3ebd2011-07-20 17:20:28 +0000303SkString SkPDFName::FormatName(const SkString& input) {
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000304 SkASSERT(input.size() <= kMaxLen);
vandebo@chromium.org251a7662012-09-21 17:50:50 +0000305 // TODO(vandebo) If more escaping is needed, improve the linear scan.
306 static const char escaped[] = "#/%()<>[]{}";
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000307
308 SkString result("/");
309 for (size_t i = 0; i < input.size(); i++) {
vandebo@chromium.org251a7662012-09-21 17:50:50 +0000310 if (input[i] & 0x80 || input[i] < '!' || strchr(escaped, input[i])) {
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000311 result.append("#");
vandebo@chromium.orgc0376fe2012-03-05 18:44:33 +0000312 // Mask with 0xFF to avoid sign extension. i.e. #FFFFFF81
313 result.appendHex(input[i] & 0xFF, 2);
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000314 } else {
315 result.append(input.c_str() + i, 1);
316 }
317 }
318
319 return result;
320}
321
vandebo@chromium.orgf66025d2010-10-01 23:26:55 +0000322SkPDFArray::SkPDFArray() {}
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000323SkPDFArray::~SkPDFArray() {
reed@google.com2812b802011-07-19 15:46:40 +0000324 fValue.unrefAll();
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000325}
326
327void SkPDFArray::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
328 bool indirect) {
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000329 if (indirect) {
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000330 return emitIndirectObject(stream, catalog);
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000331 }
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000332
333 stream->writeText("[");
334 for (int i = 0; i < fValue.count(); i++) {
vandebo@chromium.org2ef12d42011-07-06 23:31:24 +0000335 fValue[i]->emit(stream, catalog, false);
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000336 if (i + 1 < fValue.count()) {
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000337 stream->writeText(" ");
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000338 }
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000339 }
340 stream->writeText("]");
341}
342
343size_t SkPDFArray::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000344 if (indirect) {
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000345 return getIndirectOutputSize(catalog);
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000346 }
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000347
348 size_t result = strlen("[]");
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000349 if (fValue.count()) {
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000350 result += fValue.count() - 1;
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000351 }
352 for (int i = 0; i < fValue.count(); i++) {
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000353 result += fValue[i]->getOutputSize(catalog, false);
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000354 }
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000355 return result;
356}
357
358void SkPDFArray::reserve(int length) {
359 SkASSERT(length <= kMaxLen);
360 fValue.setReserve(length);
361}
362
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000363SkPDFObject* SkPDFArray::setAt(int offset, SkPDFObject* value) {
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000364 SkASSERT(offset < fValue.count());
reed@google.com2812b802011-07-19 15:46:40 +0000365 value->ref();
366 fValue[offset]->unref();
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000367 fValue[offset] = value;
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000368 return value;
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000369}
370
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000371SkPDFObject* SkPDFArray::append(SkPDFObject* value) {
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000372 SkASSERT(fValue.count() < kMaxLen);
reed@google.com2812b802011-07-19 15:46:40 +0000373 value->ref();
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000374 fValue.push(value);
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000375 return value;
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000376}
377
reed@google.comc789cf12011-07-20 12:14:33 +0000378void SkPDFArray::appendInt(int32_t value) {
379 SkASSERT(fValue.count() < kMaxLen);
380 fValue.push(new SkPDFInt(value));
381}
382
383void SkPDFArray::appendScalar(SkScalar value) {
384 SkASSERT(fValue.count() < kMaxLen);
385 fValue.push(new SkPDFScalar(value));
386}
387
388void SkPDFArray::appendName(const char name[]) {
389 SkASSERT(fValue.count() < kMaxLen);
390 fValue.push(new SkPDFName(name));
391}
392
393///////////////////////////////////////////////////////////////////////////////
394
vandebo@chromium.orgf66025d2010-10-01 23:26:55 +0000395SkPDFDict::SkPDFDict() {}
vandebo@chromium.orgd877fdb2010-10-12 23:08:13 +0000396
397SkPDFDict::SkPDFDict(const char type[]) {
vandebo@chromium.org06f7f402011-07-20 18:39:20 +0000398 insertName("Type", type);
vandebo@chromium.orgd877fdb2010-10-12 23:08:13 +0000399}
400
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000401SkPDFDict::~SkPDFDict() {
vandebo@chromium.orgd877fdb2010-10-12 23:08:13 +0000402 clear();
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000403}
404
405void SkPDFDict::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
406 bool indirect) {
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000407 if (indirect) {
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000408 return emitIndirectObject(stream, catalog);
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000409 }
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000410
411 stream->writeText("<<");
412 for (int i = 0; i < fValue.count(); i++) {
413 fValue[i].key->emitObject(stream, catalog, false);
414 stream->writeText(" ");
vandebo@chromium.org2ef12d42011-07-06 23:31:24 +0000415 fValue[i].value->emit(stream, catalog, false);
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000416 stream->writeText("\n");
417 }
418 stream->writeText(">>");
419}
420
421size_t SkPDFDict::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000422 if (indirect) {
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000423 return getIndirectOutputSize(catalog);
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000424 }
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000425
426 size_t result = strlen("<<>>") + (fValue.count() * 2);
427 for (int i = 0; i < fValue.count(); i++) {
428 result += fValue[i].key->getOutputSize(catalog, false);
429 result += fValue[i].value->getOutputSize(catalog, false);
430 }
431 return result;
432}
433
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000434SkPDFObject* SkPDFDict::insert(SkPDFName* key, SkPDFObject* value) {
reed@google.com2812b802011-07-19 15:46:40 +0000435 key->ref();
436 value->ref();
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000437 struct Rec* newEntry = fValue.append();
438 newEntry->key = key;
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000439 newEntry->value = value;
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000440 return value;
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000441}
vandebo@chromium.orgd877fdb2010-10-12 23:08:13 +0000442
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000443SkPDFObject* SkPDFDict::insert(const char key[], SkPDFObject* value) {
reed@google.com2812b802011-07-19 15:46:40 +0000444 value->ref();
445 struct Rec* newEntry = fValue.append();
446 newEntry->key = new SkPDFName(key);
447 newEntry->value = value;
448 return value;
vandebo@chromium.orgd877fdb2010-10-12 23:08:13 +0000449}
450
reed@google.comc789cf12011-07-20 12:14:33 +0000451void SkPDFDict::insertInt(const char key[], int32_t value) {
452 struct Rec* newEntry = fValue.append();
453 newEntry->key = new SkPDFName(key);
454 newEntry->value = new SkPDFInt(value);
455}
456
457void SkPDFDict::insertScalar(const char key[], SkScalar value) {
458 struct Rec* newEntry = fValue.append();
459 newEntry->key = new SkPDFName(key);
460 newEntry->value = new SkPDFScalar(value);
461}
462
463void SkPDFDict::insertName(const char key[], const char name[]) {
464 struct Rec* newEntry = fValue.append();
465 newEntry->key = new SkPDFName(key);
466 newEntry->value = new SkPDFName(name);
467}
468
vandebo@chromium.orgd877fdb2010-10-12 23:08:13 +0000469void SkPDFDict::clear() {
470 for (int i = 0; i < fValue.count(); i++) {
reed@google.com2812b802011-07-19 15:46:40 +0000471 fValue[i].key->unref();
472 fValue[i].value->unref();
vandebo@chromium.orgd877fdb2010-10-12 23:08:13 +0000473 }
474 fValue.reset();
475}
vandebo@chromium.org421d6442011-07-20 17:39:01 +0000476
477SkPDFDict::Iter::Iter(const SkPDFDict& dict)
478 : fIter(dict.fValue.begin()),
479 fStop(dict.fValue.end()) {
480}
481
482SkPDFName* SkPDFDict::Iter::next(SkPDFObject** value) {
483 if (fIter != fStop) {
commit-bot@chromium.orgaa537d42013-02-28 19:03:13 +0000484 const Rec* cur = fIter;
vandebo@chromium.org421d6442011-07-20 17:39:01 +0000485 fIter++;
486 *value = cur->value;
487 return cur->key;
488 }
489 *value = NULL;
490 return NULL;
491}