blob: 7562528c041dc2cc4e250f4215bdc7f557cda11d [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);
halcanary4fc48af2015-01-12 10:07:50 -080025 if (indirect) {
26 realObject->emitIndirectObject(stream, catalog);
27 } else {
28 realObject->emitObject(stream, catalog);
29 }
vandebo@chromium.org2ef12d42011-07-06 23:31:24 +000030}
31
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +000032size_t SkPDFObject::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
33 SkDynamicMemoryWStream buffer;
vandebo@chromium.org2ef12d42011-07-06 23:31:24 +000034 emit(&buffer, catalog, indirect);
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +000035 return buffer.getOffset();
36}
37
edisonn@google.com6addb192013-04-02 15:33:08 +000038void SkPDFObject::getResources(const SkTSet<SkPDFObject*>& knownResourceObjects,
39 SkTSet<SkPDFObject*>* newResourceObjects) {}
vandebo@chromium.orga5180862010-10-26 19:48:49 +000040
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +000041void SkPDFObject::emitIndirectObject(SkWStream* stream, SkPDFCatalog* catalog) {
42 catalog->emitObjectNumber(stream, this);
43 stream->writeText(" obj\n");
vandebo@chromium.org2ef12d42011-07-06 23:31:24 +000044 emit(stream, catalog, false);
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +000045 stream->writeText("\nendobj\n");
46}
47
48size_t SkPDFObject::getIndirectOutputSize(SkPDFCatalog* catalog) {
49 return catalog->getObjectNumberSize(this) + strlen(" obj\n") +
50 this->getOutputSize(catalog, false) + strlen("\nendobj\n");
51}
52
vandebo@chromium.org421d6442011-07-20 17:39:01 +000053void SkPDFObject::AddResourceHelper(SkPDFObject* resource,
54 SkTDArray<SkPDFObject*>* list) {
55 list->push(resource);
56 resource->ref();
57}
58
edisonn@google.com6addb192013-04-02 15:33:08 +000059void SkPDFObject::GetResourcesHelper(
60 const SkTDArray<SkPDFObject*>* resources,
61 const SkTSet<SkPDFObject*>& knownResourceObjects,
62 SkTSet<SkPDFObject*>* newResourceObjects) {
vandebo@chromium.org421d6442011-07-20 17:39:01 +000063 if (resources->count()) {
edisonn@google.com6addb192013-04-02 15:33:08 +000064 newResourceObjects->setReserve(
65 newResourceObjects->count() + resources->count());
vandebo@chromium.org421d6442011-07-20 17:39:01 +000066 for (int i = 0; i < resources->count(); i++) {
edisonn@google.com6addb192013-04-02 15:33:08 +000067 if (!knownResourceObjects.contains((*resources)[i]) &&
68 !newResourceObjects->contains((*resources)[i])) {
69 newResourceObjects->add((*resources)[i]);
70 (*resources)[i]->ref();
71 (*resources)[i]->getResources(knownResourceObjects,
72 newResourceObjects);
73 }
vandebo@chromium.org421d6442011-07-20 17:39:01 +000074 }
75 }
76}
77
vandebo@chromium.orgd96d17b2013-01-04 19:31:24 +000078SkPDFObjRef::SkPDFObjRef(SkPDFObject* obj) : fObj(obj) {
79 SkSafeRef(obj);
80}
81
vandebo@chromium.org421d6442011-07-20 17:39:01 +000082SkPDFObjRef::~SkPDFObjRef() {}
83
halcanary4fc48af2015-01-12 10:07:50 -080084void SkPDFObjRef::emitObject(SkWStream* stream, SkPDFCatalog* catalog) {
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +000085 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
halcanary4fc48af2015-01-12 10:07:50 -080097void SkPDFInt::emitObject(SkWStream* stream, SkPDFCatalog* catalog) {
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +000098 stream->writeDecAsText(fValue);
99}
100
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000101SkPDFBool::SkPDFBool(bool value) : fValue(value) {}
102SkPDFBool::~SkPDFBool() {}
103
halcanary4fc48af2015-01-12 10:07:50 -0800104void SkPDFBool::emitObject(SkWStream* stream, SkPDFCatalog* catalog) {
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000105 if (fValue) {
106 stream->writeText("true");
107 } else {
108 stream->writeText("false");
109 }
110}
111
112size_t SkPDFBool::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
113 SkASSERT(!indirect);
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000114 if (fValue) {
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000115 return strlen("true");
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000116 }
vandebo@chromium.org9b49dc02010-10-20 22:23:29 +0000117 return strlen("false");
118}
119
vandebo@chromium.orgf66025d2010-10-01 23:26:55 +0000120SkPDFScalar::SkPDFScalar(SkScalar value) : fValue(value) {}
121SkPDFScalar::~SkPDFScalar() {}
122
halcanary4fc48af2015-01-12 10:07:50 -0800123void SkPDFScalar::emitObject(SkWStream* stream, SkPDFCatalog* catalog) {
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +0000124 Append(fValue, stream);
vandebo@chromium.org094316b2011-03-04 03:15:13 +0000125}
126
127// static
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +0000128void SkPDFScalar::Append(SkScalar value, SkWStream* stream) {
vandebo@chromium.org094316b2011-03-04 03:15:13 +0000129 // The range of reals in PDF/A is the same as SkFixed: +/- 32,767 and
130 // +/- 1/65,536 (though integers can range from 2^31 - 1 to -2^31).
131 // When using floats that are outside the whole value range, we can use
132 // integers instead.
133
vandebo@chromium.org094316b2011-03-04 03:15:13 +0000134#if !defined(SK_ALLOW_LARGE_PDF_SCALARS)
135 if (value > 32767 || value < -32767) {
reed@google.come1ca7052013-12-17 19:22:07 +0000136 stream->writeDecAsText(SkScalarRoundToInt(value));
vandebo@chromium.org094316b2011-03-04 03:15:13 +0000137 return;
138 }
139
140 char buffer[SkStrAppendScalar_MaxSize];
141 char* end = SkStrAppendFixed(buffer, SkScalarToFixed(value));
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +0000142 stream->write(buffer, end - buffer);
vandebo@chromium.org094316b2011-03-04 03:15:13 +0000143 return;
144#endif // !SK_ALLOW_LARGE_PDF_SCALARS
145
reed@google.com8f4d2302013-12-17 16:44:46 +0000146#if defined(SK_ALLOW_LARGE_PDF_SCALARS)
vandebo@chromium.org094316b2011-03-04 03:15:13 +0000147 // Floats have 24bits of significance, so anything outside that range is
148 // no more precise than an int. (Plus PDF doesn't support scientific
149 // notation, so this clamps to SK_Max/MinS32).
150 if (value > (1 << 24) || value < -(1 << 24)) {
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +0000151 stream->writeDecAsText(value);
vandebo@chromium.org094316b2011-03-04 03:15:13 +0000152 return;
153 }
154 // Continue to enforce the PDF limits for small floats.
155 if (value < 1.0f/65536 && value > -1.0f/65536) {
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +0000156 stream->writeDecAsText(0);
vandebo@chromium.org094316b2011-03-04 03:15:13 +0000157 return;
158 }
159 // SkStrAppendFloat might still use scientific notation, so use snprintf
160 // directly..
161 static const int kFloat_MaxSize = 19;
162 char buffer[kFloat_MaxSize];
163 int len = SNPRINTF(buffer, kFloat_MaxSize, "%#.8f", value);
164 // %f always prints trailing 0s, so strip them.
165 for (; buffer[len - 1] == '0' && len > 0; len--) {
166 buffer[len - 1] = '\0';
167 }
168 if (buffer[len - 1] == '.') {
169 buffer[len - 1] = '\0';
170 }
vandebo@chromium.orgcae5fba2011-03-28 19:03:50 +0000171 stream->writeText(buffer);
vandebo@chromium.org094316b2011-03-04 03:15:13 +0000172 return;
reed@google.com8f4d2302013-12-17 16:44:46 +0000173#endif // SK_ALLOW_LARGE_PDF_SCALARS
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000174}
175
176SkPDFString::SkPDFString(const char value[])
reed@google.comf6c3ebd2011-07-20 17:20:28 +0000177 : fValue(FormatString(value, strlen(value))) {
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000178}
179
180SkPDFString::SkPDFString(const SkString& value)
reed@google.comf6c3ebd2011-07-20 17:20:28 +0000181 : fValue(FormatString(value.c_str(), value.size())) {
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000182}
183
184SkPDFString::SkPDFString(const uint16_t* value, size_t len, bool wideChars)
reed@google.comf6c3ebd2011-07-20 17:20:28 +0000185 : fValue(FormatString(value, len, wideChars)) {
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000186}
187
vandebo@chromium.orgf66025d2010-10-01 23:26:55 +0000188SkPDFString::~SkPDFString() {}
189
halcanary4fc48af2015-01-12 10:07:50 -0800190void SkPDFString::emitObject(SkWStream* stream, SkPDFCatalog* catalog) {
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000191 stream->write(fValue.c_str(), fValue.size());
192}
193
194size_t SkPDFString::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
195 if (indirect)
196 return getIndirectOutputSize(catalog);
197 return fValue.size();
198}
199
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000200// static
reed@google.comf6c3ebd2011-07-20 17:20:28 +0000201SkString SkPDFString::FormatString(const char* input, size_t len) {
202 return DoFormatString(input, len, false, false);
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000203}
204
reed@google.comf6c3ebd2011-07-20 17:20:28 +0000205SkString SkPDFString::FormatString(const uint16_t* input, size_t len,
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000206 bool wideChars) {
reed@google.comf6c3ebd2011-07-20 17:20:28 +0000207 return DoFormatString(input, len, true, wideChars);
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000208}
209
210// static
reed@google.comf6c3ebd2011-07-20 17:20:28 +0000211SkString SkPDFString::DoFormatString(const void* input, size_t len,
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000212 bool wideInput, bool wideOutput) {
213 SkASSERT(len <= kMaxLen);
214 const uint16_t* win = (const uint16_t*) input;
215 const char* cin = (const char*) input;
216
217 if (wideOutput) {
218 SkASSERT(wideInput);
219 SkString result;
220 result.append("<");
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000221 for (size_t i = 0; i < len; i++) {
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000222 result.appendHex(win[i], 4);
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000223 }
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000224 result.append(">");
225 return result;
226 }
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000227
228 // 7-bit clean is a heuristic to decide what string format to use;
229 // a 7-bit clean string should require little escaping.
230 bool sevenBitClean = true;
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000231 for (size_t i = 0; i < len; i++) {
232 SkASSERT(!wideInput || !(win[i] & ~0xFF));
233 char val = wideInput ? win[i] : cin[i];
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000234 if (val > '~' || val < ' ') {
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000235 sevenBitClean = false;
236 break;
237 }
238 }
239
240 SkString result;
241 if (sevenBitClean) {
242 result.append("(");
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000243 for (size_t i = 0; i < len; i++) {
244 SkASSERT(!wideInput || !(win[i] & ~0xFF));
245 char val = wideInput ? win[i] : cin[i];
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000246 if (val == '\\' || val == '(' || val == ')') {
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000247 result.append("\\");
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000248 }
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000249 result.append(&val, 1);
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000250 }
251 result.append(")");
252 } else {
253 result.append("<");
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000254 for (size_t i = 0; i < len; i++) {
255 SkASSERT(!wideInput || !(win[i] & ~0xFF));
vandebo@chromium.org2a22e102011-01-25 21:01:34 +0000256 unsigned char val = wideInput ? win[i] : cin[i];
vandebo@chromium.org28be72b2010-11-11 21:37:00 +0000257 result.appendHex(val, 2);
258 }
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000259 result.append(">");
260 }
261
262 return result;
263}
264
reed@google.comf6c3ebd2011-07-20 17:20:28 +0000265SkPDFName::SkPDFName(const char name[]) : fValue(FormatName(SkString(name))) {}
266SkPDFName::SkPDFName(const SkString& name) : fValue(FormatName(name)) {}
vandebo@chromium.orgf66025d2010-10-01 23:26:55 +0000267SkPDFName::~SkPDFName() {}
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000268
vandebo@chromium.org421d6442011-07-20 17:39:01 +0000269bool SkPDFName::operator==(const SkPDFName& b) const {
270 return fValue == b.fValue;
271}
272
halcanary4fc48af2015-01-12 10:07:50 -0800273void SkPDFName::emitObject(SkWStream* stream, SkPDFCatalog* catalog) {
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000274 stream->write(fValue.c_str(), fValue.size());
275}
276
277size_t SkPDFName::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
278 SkASSERT(!indirect);
279 return fValue.size();
280}
281
vandebo@chromium.orgf66025d2010-10-01 23:26:55 +0000282// static
reed@google.comf6c3ebd2011-07-20 17:20:28 +0000283SkString SkPDFName::FormatName(const SkString& input) {
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000284 SkASSERT(input.size() <= kMaxLen);
vandebo@chromium.org251a7662012-09-21 17:50:50 +0000285 // TODO(vandebo) If more escaping is needed, improve the linear scan.
286 static const char escaped[] = "#/%()<>[]{}";
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000287
288 SkString result("/");
289 for (size_t i = 0; i < input.size(); i++) {
vandebo@chromium.org251a7662012-09-21 17:50:50 +0000290 if (input[i] & 0x80 || input[i] < '!' || strchr(escaped, input[i])) {
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000291 result.append("#");
vandebo@chromium.orgc0376fe2012-03-05 18:44:33 +0000292 // Mask with 0xFF to avoid sign extension. i.e. #FFFFFF81
293 result.appendHex(input[i] & 0xFF, 2);
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000294 } else {
295 result.append(input.c_str() + i, 1);
296 }
297 }
298
299 return result;
300}
301
vandebo@chromium.orgf66025d2010-10-01 23:26:55 +0000302SkPDFArray::SkPDFArray() {}
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000303SkPDFArray::~SkPDFArray() {
reed@google.com2812b802011-07-19 15:46:40 +0000304 fValue.unrefAll();
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000305}
306
halcanary4fc48af2015-01-12 10:07:50 -0800307void SkPDFArray::emitObject(SkWStream* stream, SkPDFCatalog* catalog) {
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000308 stream->writeText("[");
309 for (int i = 0; i < fValue.count(); i++) {
vandebo@chromium.org2ef12d42011-07-06 23:31:24 +0000310 fValue[i]->emit(stream, catalog, false);
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000311 if (i + 1 < fValue.count()) {
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000312 stream->writeText(" ");
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000313 }
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000314 }
315 stream->writeText("]");
316}
317
318size_t SkPDFArray::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000319 if (indirect) {
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000320 return getIndirectOutputSize(catalog);
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000321 }
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000322
323 size_t result = strlen("[]");
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000324 if (fValue.count()) {
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000325 result += fValue.count() - 1;
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000326 }
327 for (int i = 0; i < fValue.count(); i++) {
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000328 result += fValue[i]->getOutputSize(catalog, false);
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000329 }
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000330 return result;
331}
332
333void SkPDFArray::reserve(int length) {
334 SkASSERT(length <= kMaxLen);
335 fValue.setReserve(length);
336}
337
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000338SkPDFObject* SkPDFArray::setAt(int offset, SkPDFObject* value) {
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000339 SkASSERT(offset < fValue.count());
reed@google.com2812b802011-07-19 15:46:40 +0000340 value->ref();
341 fValue[offset]->unref();
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000342 fValue[offset] = value;
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000343 return value;
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000344}
345
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000346SkPDFObject* SkPDFArray::append(SkPDFObject* value) {
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000347 SkASSERT(fValue.count() < kMaxLen);
reed@google.com2812b802011-07-19 15:46:40 +0000348 value->ref();
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000349 fValue.push(value);
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000350 return value;
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000351}
352
reed@google.comc789cf12011-07-20 12:14:33 +0000353void SkPDFArray::appendInt(int32_t value) {
354 SkASSERT(fValue.count() < kMaxLen);
355 fValue.push(new SkPDFInt(value));
356}
357
358void SkPDFArray::appendScalar(SkScalar value) {
359 SkASSERT(fValue.count() < kMaxLen);
360 fValue.push(new SkPDFScalar(value));
361}
362
363void SkPDFArray::appendName(const char name[]) {
364 SkASSERT(fValue.count() < kMaxLen);
365 fValue.push(new SkPDFName(name));
366}
367
368///////////////////////////////////////////////////////////////////////////////
369
vandebo@chromium.orgf66025d2010-10-01 23:26:55 +0000370SkPDFDict::SkPDFDict() {}
vandebo@chromium.orgd877fdb2010-10-12 23:08:13 +0000371
372SkPDFDict::SkPDFDict(const char type[]) {
vandebo@chromium.org06f7f402011-07-20 18:39:20 +0000373 insertName("Type", type);
vandebo@chromium.orgd877fdb2010-10-12 23:08:13 +0000374}
375
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000376SkPDFDict::~SkPDFDict() {
vandebo@chromium.orgd877fdb2010-10-12 23:08:13 +0000377 clear();
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000378}
379
halcanary1f8ed022014-06-27 10:37:27 -0700380int SkPDFDict::size() const {
381 SkAutoMutexAcquire lock(fMutex);
382 return fValue.count();
383}
384
385
halcanary4fc48af2015-01-12 10:07:50 -0800386void SkPDFDict::emitObject(SkWStream* stream, SkPDFCatalog* catalog) {
halcanary1f8ed022014-06-27 10:37:27 -0700387 SkAutoMutexAcquire lock(fMutex); // If another thread triggers a
388 // resize while this thread is in
389 // the for-loop, we can be left
390 // with a bad fValue[i] reference.
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000391 stream->writeText("<<");
392 for (int i = 0; i < fValue.count(); i++) {
halcanary1f8ed022014-06-27 10:37:27 -0700393 SkASSERT(fValue[i].key);
394 SkASSERT(fValue[i].value);
halcanary4fc48af2015-01-12 10:07:50 -0800395 fValue[i].key->emitObject(stream, catalog);
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000396 stream->writeText(" ");
vandebo@chromium.org2ef12d42011-07-06 23:31:24 +0000397 fValue[i].value->emit(stream, catalog, false);
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000398 stream->writeText("\n");
399 }
400 stream->writeText(">>");
401}
402
403size_t SkPDFDict::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000404 if (indirect) {
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000405 return getIndirectOutputSize(catalog);
ctguil@chromium.org769fa6a2011-08-20 00:36:18 +0000406 }
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000407
halcanary1f8ed022014-06-27 10:37:27 -0700408 SkAutoMutexAcquire lock(fMutex); // If another thread triggers a
409 // resize while this thread is in
410 // the for-loop, we can be left
411 // with a bad fValue[i] reference.
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000412 size_t result = strlen("<<>>") + (fValue.count() * 2);
413 for (int i = 0; i < fValue.count(); i++) {
halcanary1f8ed022014-06-27 10:37:27 -0700414 SkASSERT(fValue[i].key);
415 SkASSERT(fValue[i].value);
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000416 result += fValue[i].key->getOutputSize(catalog, false);
417 result += fValue[i].value->getOutputSize(catalog, false);
418 }
419 return result;
420}
421
halcanary1f8ed022014-06-27 10:37:27 -0700422SkPDFObject* SkPDFDict::append(SkPDFName* key, SkPDFObject* value) {
423 SkASSERT(key);
424 SkASSERT(value);
425 SkAutoMutexAcquire lock(fMutex); // If the SkTDArray resizes while
426 // two threads access array, one
427 // is left with a bad pointer.
428 *(fValue.append()) = Rec(key, value);
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000429 return value;
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000430}
vandebo@chromium.orgd877fdb2010-10-12 23:08:13 +0000431
halcanary1f8ed022014-06-27 10:37:27 -0700432SkPDFObject* SkPDFDict::insert(SkPDFName* key, SkPDFObject* value) {
433 return this->append(SkRef(key), SkRef(value));
434}
435
vandebo@chromium.orgf7c15762011-02-01 22:19:44 +0000436SkPDFObject* SkPDFDict::insert(const char key[], SkPDFObject* value) {
halcanary1f8ed022014-06-27 10:37:27 -0700437 return this->append(new SkPDFName(key), SkRef(value));
vandebo@chromium.orgd877fdb2010-10-12 23:08:13 +0000438}
439
reed@google.comc789cf12011-07-20 12:14:33 +0000440void SkPDFDict::insertInt(const char key[], int32_t value) {
halcanary1f8ed022014-06-27 10:37:27 -0700441 (void)this->append(new SkPDFName(key), new SkPDFInt(value));
reed@google.comc789cf12011-07-20 12:14:33 +0000442}
443
444void SkPDFDict::insertScalar(const char key[], SkScalar value) {
halcanary1f8ed022014-06-27 10:37:27 -0700445 (void)this->append(new SkPDFName(key), new SkPDFScalar(value));
reed@google.comc789cf12011-07-20 12:14:33 +0000446}
447
448void SkPDFDict::insertName(const char key[], const char name[]) {
halcanary1f8ed022014-06-27 10:37:27 -0700449 (void)this->append(new SkPDFName(key), new SkPDFName(name));
reed@google.comc789cf12011-07-20 12:14:33 +0000450}
451
vandebo@chromium.orgd877fdb2010-10-12 23:08:13 +0000452void SkPDFDict::clear() {
halcanary1f8ed022014-06-27 10:37:27 -0700453 SkAutoMutexAcquire lock(fMutex);
vandebo@chromium.orgd877fdb2010-10-12 23:08:13 +0000454 for (int i = 0; i < fValue.count(); i++) {
halcanary1f8ed022014-06-27 10:37:27 -0700455 SkASSERT(fValue[i].key);
456 SkASSERT(fValue[i].value);
reed@google.com2812b802011-07-19 15:46:40 +0000457 fValue[i].key->unref();
458 fValue[i].value->unref();
vandebo@chromium.orgd877fdb2010-10-12 23:08:13 +0000459 }
460 fValue.reset();
461}
vandebo@chromium.org421d6442011-07-20 17:39:01 +0000462
halcanary1f8ed022014-06-27 10:37:27 -0700463void SkPDFDict::remove(const char key[]) {
464 SkASSERT(key);
465 SkPDFName name(key);
466 SkAutoMutexAcquire lock(fMutex);
467 for (int i = 0; i < fValue.count(); i++) {
468 SkASSERT(fValue[i].key);
469 if (*(fValue[i].key) == name) {
470 fValue[i].key->unref();
471 SkASSERT(fValue[i].value);
472 fValue[i].value->unref();
473 fValue.removeShuffle(i);
474 return;
475 }
476 }
vandebo@chromium.org421d6442011-07-20 17:39:01 +0000477}
478
halcanary1f8ed022014-06-27 10:37:27 -0700479void SkPDFDict::mergeFrom(const SkPDFDict& other) {
480 SkAutoMutexAcquire lockOther(other.fMutex);
481 SkTDArray<Rec> copy(other.fValue);
482 lockOther.release(); // Do not hold both mutexes at once.
483
484 SkAutoMutexAcquire lock(fMutex);
485 for (int i = 0; i < copy.count(); i++) {
486 *(fValue.append()) = Rec(SkRef(copy[i].key), SkRef(copy[i].value));
vandebo@chromium.org421d6442011-07-20 17:39:01 +0000487 }
vandebo@chromium.org421d6442011-07-20 17:39:01 +0000488}