• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 Google Inc.
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 
21 #ifdef SK_BUILD_FOR_WIN
22     #define SNPRINTF    _snprintf
23 #else
24     #define SNPRINTF    snprintf
25 #endif
26 
SkPDFObject()27 SkPDFObject::SkPDFObject() {}
~SkPDFObject()28 SkPDFObject::~SkPDFObject() {}
29 
getOutputSize(SkPDFCatalog * catalog,bool indirect)30 size_t SkPDFObject::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
31     SkDynamicMemoryWStream buffer;
32     emitObject(&buffer, catalog, indirect);
33     return buffer.getOffset();
34 }
35 
getResources(SkTDArray<SkPDFObject * > * resourceList)36 void SkPDFObject::getResources(SkTDArray<SkPDFObject*>* resourceList) {}
37 
emitIndirectObject(SkWStream * stream,SkPDFCatalog * catalog)38 void SkPDFObject::emitIndirectObject(SkWStream* stream, SkPDFCatalog* catalog) {
39     catalog->emitObjectNumber(stream, this);
40     stream->writeText(" obj\n");
41     emitObject(stream, catalog, false);
42     stream->writeText("\nendobj\n");
43 }
44 
SkPDFObjRef(SkPDFObject * obj)45 SkPDFObjRef::SkPDFObjRef(SkPDFObject* obj) : fObj(obj) {}
~SkPDFObjRef()46 SkPDFObjRef::~SkPDFObjRef() {}
47 
getIndirectOutputSize(SkPDFCatalog * catalog)48 size_t SkPDFObject::getIndirectOutputSize(SkPDFCatalog* catalog) {
49     return catalog->getObjectNumberSize(this) + strlen(" obj\n") +
50         this->getOutputSize(catalog, false) + strlen("\nendobj\n");
51 }
52 
emitObject(SkWStream * stream,SkPDFCatalog * catalog,bool indirect)53 void SkPDFObjRef::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
54                              bool indirect) {
55     SkASSERT(!indirect);
56     catalog->emitObjectNumber(stream, fObj.get());
57     stream->writeText(" R");
58 }
59 
getOutputSize(SkPDFCatalog * catalog,bool indirect)60 size_t SkPDFObjRef::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
61     SkASSERT(!indirect);
62     return catalog->getObjectNumberSize(fObj.get()) + strlen(" R");
63 }
64 
SkPDFInt(int32_t value)65 SkPDFInt::SkPDFInt(int32_t value) : fValue(value) {}
~SkPDFInt()66 SkPDFInt::~SkPDFInt() {}
67 
emitObject(SkWStream * stream,SkPDFCatalog * catalog,bool indirect)68 void SkPDFInt::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
69                           bool indirect) {
70     if (indirect)
71         return emitIndirectObject(stream, catalog);
72     stream->writeDecAsText(fValue);
73 }
74 
SkPDFBool(bool value)75 SkPDFBool::SkPDFBool(bool value) : fValue(value) {}
~SkPDFBool()76 SkPDFBool::~SkPDFBool() {}
77 
emitObject(SkWStream * stream,SkPDFCatalog * catalog,bool indirect)78 void SkPDFBool::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
79                           bool indirect) {
80     SkASSERT(!indirect);
81     if (fValue) {
82         stream->writeText("true");
83     } else {
84         stream->writeText("false");
85     }
86 }
87 
getOutputSize(SkPDFCatalog * catalog,bool indirect)88 size_t SkPDFBool::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
89     SkASSERT(!indirect);
90     if (fValue)
91         return strlen("true");
92     return strlen("false");
93 }
94 
SkPDFScalar(SkScalar value)95 SkPDFScalar::SkPDFScalar(SkScalar value) : fValue(value) {}
~SkPDFScalar()96 SkPDFScalar::~SkPDFScalar() {}
97 
emitObject(SkWStream * stream,SkPDFCatalog * catalog,bool indirect)98 void SkPDFScalar::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
99                              bool indirect) {
100     if (indirect)
101         return emitIndirectObject(stream, catalog);
102 
103     Append(fValue, stream);
104 }
105 
106 // static
Append(SkScalar value,SkWStream * stream)107 void SkPDFScalar::Append(SkScalar value, SkWStream* stream) {
108     // The range of reals in PDF/A is the same as SkFixed: +/- 32,767 and
109     // +/- 1/65,536 (though integers can range from 2^31 - 1 to -2^31).
110     // When using floats that are outside the whole value range, we can use
111     // integers instead.
112 
113 
114 #if defined(SK_SCALAR_IS_FIXED)
115     stream->writeScalarAsText(value);
116     return;
117 #endif  // SK_SCALAR_IS_FIXED
118 
119 #if !defined(SK_ALLOW_LARGE_PDF_SCALARS)
120     if (value > 32767 || value < -32767) {
121         stream->writeDecAsText(SkScalarRound(value));
122         return;
123     }
124 
125     char buffer[SkStrAppendScalar_MaxSize];
126     char* end = SkStrAppendFixed(buffer, SkScalarToFixed(value));
127     stream->write(buffer, end - buffer);
128     return;
129 #endif  // !SK_ALLOW_LARGE_PDF_SCALARS
130 
131 #if defined(SK_SCALAR_IS_FLOAT) && defined(SK_ALLOW_LARGE_PDF_SCALARS)
132     // Floats have 24bits of significance, so anything outside that range is
133     // no more precise than an int. (Plus PDF doesn't support scientific
134     // notation, so this clamps to SK_Max/MinS32).
135     if (value > (1 << 24) || value < -(1 << 24)) {
136         stream->writeDecAsText(value);
137         return;
138     }
139     // Continue to enforce the PDF limits for small floats.
140     if (value < 1.0f/65536 && value > -1.0f/65536) {
141         stream->writeDecAsText(0);
142         return;
143     }
144     // SkStrAppendFloat might still use scientific notation, so use snprintf
145     // directly..
146     static const int kFloat_MaxSize = 19;
147     char buffer[kFloat_MaxSize];
148     int len = SNPRINTF(buffer, kFloat_MaxSize, "%#.8f", value);
149     // %f always prints trailing 0s, so strip them.
150     for (; buffer[len - 1] == '0' && len > 0; len--) {
151         buffer[len - 1] = '\0';
152     }
153     if (buffer[len - 1] == '.') {
154         buffer[len - 1] = '\0';
155     }
156     stream->writeText(buffer);
157     return;
158 #endif  // SK_SCALAR_IS_FLOAT && SK_ALLOW_LARGE_PDF_SCALARS
159 }
160 
SkPDFString(const char value[])161 SkPDFString::SkPDFString(const char value[])
162     : fValue(formatString(value, strlen(value))) {
163 }
164 
SkPDFString(const SkString & value)165 SkPDFString::SkPDFString(const SkString& value)
166     : fValue(formatString(value.c_str(), value.size())) {
167 }
168 
SkPDFString(const uint16_t * value,size_t len,bool wideChars)169 SkPDFString::SkPDFString(const uint16_t* value, size_t len, bool wideChars)
170     : fValue(formatString(value, len, wideChars)) {
171 }
172 
~SkPDFString()173 SkPDFString::~SkPDFString() {}
174 
emitObject(SkWStream * stream,SkPDFCatalog * catalog,bool indirect)175 void SkPDFString::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
176                              bool indirect) {
177     if (indirect)
178         return emitIndirectObject(stream, catalog);
179     stream->write(fValue.c_str(), fValue.size());
180 }
181 
getOutputSize(SkPDFCatalog * catalog,bool indirect)182 size_t SkPDFString::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
183     if (indirect)
184         return getIndirectOutputSize(catalog);
185     return fValue.size();
186 }
187 
188 // static
formatString(const char * input,size_t len)189 SkString SkPDFString::formatString(const char* input, size_t len) {
190     return doFormatString(input, len, false, false);
191 }
192 
formatString(const uint16_t * input,size_t len,bool wideChars)193 SkString SkPDFString::formatString(const uint16_t* input, size_t len,
194                                    bool wideChars) {
195     return doFormatString(input, len, true, wideChars);
196 }
197 
198 // static
doFormatString(const void * input,size_t len,bool wideInput,bool wideOutput)199 SkString SkPDFString::doFormatString(const void* input, size_t len,
200                                      bool wideInput, bool wideOutput) {
201     SkASSERT(len <= kMaxLen);
202     const uint16_t* win = (const uint16_t*) input;
203     const char* cin = (const char*) input;
204 
205     if (wideOutput) {
206         SkASSERT(wideInput);
207         SkString result;
208         result.append("<");
209         for (size_t i = 0; i < len; i++)
210             result.appendHex(win[i], 4);
211         result.append(">");
212         return result;
213     }
214 
215     // 7-bit clean is a heuristic to decide what string format to use;
216     // a 7-bit clean string should require little escaping.
217     bool sevenBitClean = true;
218     for (size_t i = 0; i < len; i++) {
219         SkASSERT(!wideInput || !(win[i] & ~0xFF));
220         char val = wideInput ? win[i] : cin[i];
221         if (val > '~' || val < ' ') {
222             sevenBitClean = false;
223             break;
224         }
225     }
226 
227     SkString result;
228     if (sevenBitClean) {
229         result.append("(");
230         for (size_t i = 0; i < len; i++) {
231             SkASSERT(!wideInput || !(win[i] & ~0xFF));
232             char val = wideInput ? win[i] : cin[i];
233             if (val == '\\' || val == '(' || val == ')')
234                 result.append("\\");
235             result.append(&val, 1);
236         }
237         result.append(")");
238     } else {
239         result.append("<");
240         for (size_t i = 0; i < len; i++) {
241             SkASSERT(!wideInput || !(win[i] & ~0xFF));
242             unsigned char val = wideInput ? win[i] : cin[i];
243             result.appendHex(val, 2);
244         }
245         result.append(">");
246     }
247 
248     return result;
249 }
250 
SkPDFName(const char name[])251 SkPDFName::SkPDFName(const char name[]) : fValue(formatName(SkString(name))) {}
SkPDFName(const SkString & name)252 SkPDFName::SkPDFName(const SkString& name) : fValue(formatName(name)) {}
~SkPDFName()253 SkPDFName::~SkPDFName() {}
254 
emitObject(SkWStream * stream,SkPDFCatalog * catalog,bool indirect)255 void SkPDFName::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
256                            bool indirect) {
257     SkASSERT(!indirect);
258     stream->write(fValue.c_str(), fValue.size());
259 }
260 
getOutputSize(SkPDFCatalog * catalog,bool indirect)261 size_t SkPDFName::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
262     SkASSERT(!indirect);
263     return fValue.size();
264 }
265 
266 // static
formatName(const SkString & input)267 SkString SkPDFName::formatName(const SkString& input) {
268     SkASSERT(input.size() <= kMaxLen);
269 
270     SkString result("/");
271     for (size_t i = 0; i < input.size(); i++) {
272         if (input[i] & 0x80 || input[i] < '!' || input[i] == '#') {
273             result.append("#");
274             result.appendHex(input[i], 2);
275         } else {
276             result.append(input.c_str() + i, 1);
277         }
278     }
279 
280     return result;
281 }
282 
SkPDFArray()283 SkPDFArray::SkPDFArray() {}
~SkPDFArray()284 SkPDFArray::~SkPDFArray() {
285     fValue.safeUnrefAll();
286 }
287 
emitObject(SkWStream * stream,SkPDFCatalog * catalog,bool indirect)288 void SkPDFArray::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
289                             bool indirect) {
290     if (indirect)
291         return emitIndirectObject(stream, catalog);
292 
293     stream->writeText("[");
294     for (int i = 0; i < fValue.count(); i++) {
295         fValue[i]->emitObject(stream, catalog, false);
296         if (i + 1 < fValue.count())
297             stream->writeText(" ");
298     }
299     stream->writeText("]");
300 }
301 
getOutputSize(SkPDFCatalog * catalog,bool indirect)302 size_t SkPDFArray::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
303     if (indirect)
304         return getIndirectOutputSize(catalog);
305 
306     size_t result = strlen("[]");
307     if (fValue.count())
308         result += fValue.count() - 1;
309     for (int i = 0; i < fValue.count(); i++)
310         result += fValue[i]->getOutputSize(catalog, false);
311     return result;
312 }
313 
reserve(int length)314 void SkPDFArray::reserve(int length) {
315     SkASSERT(length <= kMaxLen);
316     fValue.setReserve(length);
317 }
318 
setAt(int offset,SkPDFObject * value)319 SkPDFObject* SkPDFArray::setAt(int offset, SkPDFObject* value) {
320     SkASSERT(offset < fValue.count());
321     SkSafeUnref(fValue[offset]);
322     fValue[offset] = value;
323     SkSafeRef(fValue[offset]);
324     return value;
325 }
326 
append(SkPDFObject * value)327 SkPDFObject* SkPDFArray::append(SkPDFObject* value) {
328     SkASSERT(fValue.count() < kMaxLen);
329     SkSafeRef(value);
330     fValue.push(value);
331     return value;
332 }
333 
SkPDFDict()334 SkPDFDict::SkPDFDict() {}
335 
SkPDFDict(const char type[])336 SkPDFDict::SkPDFDict(const char type[]) {
337     insert("Type", new SkPDFName(type))->unref();
338 }
339 
~SkPDFDict()340 SkPDFDict::~SkPDFDict() {
341     clear();
342 }
343 
emitObject(SkWStream * stream,SkPDFCatalog * catalog,bool indirect)344 void SkPDFDict::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
345                            bool indirect) {
346     if (indirect)
347         return emitIndirectObject(stream, catalog);
348 
349     stream->writeText("<<");
350     for (int i = 0; i < fValue.count(); i++) {
351         fValue[i].key->emitObject(stream, catalog, false);
352         stream->writeText(" ");
353         fValue[i].value->emitObject(stream, catalog, false);
354         stream->writeText("\n");
355     }
356     stream->writeText(">>");
357 }
358 
getOutputSize(SkPDFCatalog * catalog,bool indirect)359 size_t SkPDFDict::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
360     if (indirect)
361         return getIndirectOutputSize(catalog);
362 
363     size_t result = strlen("<<>>") + (fValue.count() * 2);
364     for (int i = 0; i < fValue.count(); i++) {
365         result += fValue[i].key->getOutputSize(catalog, false);
366         result += fValue[i].value->getOutputSize(catalog, false);
367     }
368     return result;
369 }
370 
insert(SkPDFName * key,SkPDFObject * value)371 SkPDFObject* SkPDFDict::insert(SkPDFName* key, SkPDFObject* value) {
372     struct Rec* newEntry = fValue.append();
373     newEntry->key = key;
374     SkSafeRef(newEntry->key);
375     newEntry->value = value;
376     SkSafeRef(newEntry->value);
377     return value;
378 }
379 
insert(const char key[],SkPDFObject * value)380 SkPDFObject* SkPDFDict::insert(const char key[], SkPDFObject* value) {
381     SkRefPtr<SkPDFName> keyName = new SkPDFName(key);
382     keyName->unref();  // SkRefPtr and new both took a reference.
383     return insert(keyName.get(), value);
384 }
385 
clear()386 void SkPDFDict::clear() {
387     for (int i = 0; i < fValue.count(); i++) {
388         SkSafeUnref(fValue[i].key);
389         SkSafeUnref(fValue[i].value);
390     }
391     fValue.reset();
392 }
393