blob: f5f23ca709c5e5627af33a320f2621b7aa9fbf56 [file] [log] [blame]
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +00001/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "SkPDFCatalog.h"
18#include "SkPDFTypes.h"
19#include "SkStream.h"
20
vandebo@chromium.orgf66025d2010-10-01 23:26:55 +000021SkPDFObject::SkPDFObject() {}
22SkPDFObject::~SkPDFObject() {}
23
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +000024size_t SkPDFObject::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
25 SkDynamicMemoryWStream buffer;
26 emitObject(&buffer, catalog, indirect);
27 return buffer.getOffset();
28}
29
30void SkPDFObject::emitIndirectObject(SkWStream* stream, SkPDFCatalog* catalog) {
31 catalog->emitObjectNumber(stream, this);
32 stream->writeText(" obj\n");
33 emitObject(stream, catalog, false);
34 stream->writeText("\nendobj\n");
35}
36
vandebo@chromium.orgf66025d2010-10-01 23:26:55 +000037SkPDFObjRef::SkPDFObjRef(SkPDFObject* obj) : fObj(obj) {}
38SkPDFObjRef::~SkPDFObjRef() {}
39
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +000040size_t SkPDFObject::getIndirectOutputSize(SkPDFCatalog* catalog) {
41 return catalog->getObjectNumberSize(this) + strlen(" obj\n") +
42 this->getOutputSize(catalog, false) + strlen("\nendobj\n");
43}
44
45void SkPDFObjRef::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
46 bool indirect) {
47 SkASSERT(!indirect);
48 catalog->emitObjectNumber(stream, fObj.get());
49 stream->writeText(" R");
50}
51
52size_t SkPDFObjRef::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
53 SkASSERT(!indirect);
54 return catalog->getObjectNumberSize(fObj.get()) + strlen(" R");
55}
56
vandebo@chromium.orgf66025d2010-10-01 23:26:55 +000057SkPDFInt::SkPDFInt(int32_t value) : fValue(value) {}
58SkPDFInt::~SkPDFInt() {}
59
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +000060void SkPDFInt::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
61 bool indirect) {
62 if (indirect)
63 return emitIndirectObject(stream, catalog);
64 stream->writeDecAsText(fValue);
65}
66
vandebo@chromium.orgf66025d2010-10-01 23:26:55 +000067SkPDFScalar::SkPDFScalar(SkScalar value) : fValue(value) {}
68SkPDFScalar::~SkPDFScalar() {}
69
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +000070void SkPDFScalar::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
71 bool indirect) {
72 if (indirect)
73 return emitIndirectObject(stream, catalog);
74 stream->writeScalarAsText(fValue);
75}
76
77SkPDFString::SkPDFString(const char value[])
78 : fValue(formatString(SkString(value))) {
79}
80
81SkPDFString::SkPDFString(const SkString& value)
82 : fValue(formatString(value)) {
83}
84
vandebo@chromium.orgf66025d2010-10-01 23:26:55 +000085SkPDFString::~SkPDFString() {}
86
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +000087void SkPDFString::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
88 bool indirect) {
89 if (indirect)
90 return emitIndirectObject(stream, catalog);
91 stream->write(fValue.c_str(), fValue.size());
92}
93
94size_t SkPDFString::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
95 if (indirect)
96 return getIndirectOutputSize(catalog);
97 return fValue.size();
98}
99
100SkString SkPDFString::formatString(const SkString& input) {
101 SkASSERT(input.size() <= kMaxLen);
102
103 // 7-bit clean is a heuristic to decide what string format to use;
104 // a 7-bit clean string should require little escaping.
105 bool sevenBitClean = true;
106 for (size_t i = 0; i < input.size(); i++) {
vandebo@chromium.orgf66025d2010-10-01 23:26:55 +0000107 if (input[i] & 0x80 || input[i] < ' ') {
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000108 sevenBitClean = false;
109 break;
110 }
111 }
112
113 SkString result;
114 if (sevenBitClean) {
115 result.append("(");
116 for (size_t i = 0; i < input.size(); i++) {
117 if (input[i] == '\\' || input[i] == '(' || input[i] == ')')
118 result.append("\\");
119 result.append(input.c_str() + i, 1);
120 }
121 result.append(")");
122 } else {
123 result.append("<");
124 for (size_t i = 0; i < input.size(); i++)
125 result.appendHex(input[i], 2);
126 result.append(">");
127 }
128
129 return result;
130}
131
132SkPDFName::SkPDFName(const char name[]) : fValue(formatName(SkString(name))) {}
133SkPDFName::SkPDFName(const SkString& name) : fValue(formatName(name)) {}
vandebo@chromium.orgf66025d2010-10-01 23:26:55 +0000134SkPDFName::~SkPDFName() {}
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000135
136void SkPDFName::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
137 bool indirect) {
138 SkASSERT(!indirect);
139 stream->write(fValue.c_str(), fValue.size());
140}
141
142size_t SkPDFName::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
143 SkASSERT(!indirect);
144 return fValue.size();
145}
146
vandebo@chromium.orgf66025d2010-10-01 23:26:55 +0000147// static
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000148SkString SkPDFName::formatName(const SkString& input) {
149 SkASSERT(input.size() <= kMaxLen);
150
151 SkString result("/");
152 for (size_t i = 0; i < input.size(); i++) {
vandebo@chromium.orgf66025d2010-10-01 23:26:55 +0000153 if (input[i] & 0x80 || input[i] < '!' || input[i] == '#') {
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000154 result.append("#");
155 result.appendHex(input[i], 2);
156 } else {
157 result.append(input.c_str() + i, 1);
158 }
159 }
160
161 return result;
162}
163
vandebo@chromium.orgf66025d2010-10-01 23:26:55 +0000164SkPDFArray::SkPDFArray() {}
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000165SkPDFArray::~SkPDFArray() {
166 fValue.safeUnrefAll();
167}
168
169void SkPDFArray::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
170 bool indirect) {
171 if (indirect)
172 return emitIndirectObject(stream, catalog);
173
174 stream->writeText("[");
175 for (int i = 0; i < fValue.count(); i++) {
176 fValue[i]->emitObject(stream, catalog, false);
177 if (i + 1 < fValue.count())
178 stream->writeText(" ");
179 }
180 stream->writeText("]");
181}
182
183size_t SkPDFArray::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
184 if (indirect)
185 return getIndirectOutputSize(catalog);
186
187 size_t result = strlen("[]");
188 if (fValue.count())
189 result += fValue.count() - 1;
190 for (int i = 0; i < fValue.count(); i++)
191 result += fValue[i]->getOutputSize(catalog, false);
192 return result;
193}
194
195void SkPDFArray::reserve(int length) {
196 SkASSERT(length <= kMaxLen);
197 fValue.setReserve(length);
198}
199
200void SkPDFArray::setAt(int offset, SkPDFObject* value) {
201 SkASSERT(offset < fValue.count());
202 SkSafeUnref(fValue[offset]);
203 fValue[offset] = value;
204 SkSafeRef(fValue[offset]);
205}
206
207void SkPDFArray::append(SkPDFObject* value) {
208 SkASSERT(fValue.count() < kMaxLen);
209 SkSafeRef(value);
210 fValue.push(value);
211}
212
vandebo@chromium.orgf66025d2010-10-01 23:26:55 +0000213SkPDFDict::SkPDFDict() {}
vandebo@chromium.org8459d4e2010-09-24 22:25:30 +0000214SkPDFDict::~SkPDFDict() {
215 for (int i = 0; i < fValue.count(); i++) {
216 SkSafeUnref(fValue[i].key);
217 SkSafeUnref(fValue[i].value);
218 }
219}
220
221void SkPDFDict::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
222 bool indirect) {
223 if (indirect)
224 return emitIndirectObject(stream, catalog);
225
226 stream->writeText("<<");
227 for (int i = 0; i < fValue.count(); i++) {
228 fValue[i].key->emitObject(stream, catalog, false);
229 stream->writeText(" ");
230 fValue[i].value->emitObject(stream, catalog, false);
231 stream->writeText("\n");
232 }
233 stream->writeText(">>");
234}
235
236size_t SkPDFDict::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
237 if (indirect)
238 return getIndirectOutputSize(catalog);
239
240 size_t result = strlen("<<>>") + (fValue.count() * 2);
241 for (int i = 0; i < fValue.count(); i++) {
242 result += fValue[i].key->getOutputSize(catalog, false);
243 result += fValue[i].value->getOutputSize(catalog, false);
244 }
245 return result;
246}
247
248void SkPDFDict::insert(SkPDFName* key, SkPDFObject* value) {
249 struct Rec* newEntry = fValue.append();
250 newEntry->key = key;
251 SkSafeRef(newEntry->key);
252 newEntry->value = value;
253 SkSafeRef(newEntry->value);
254}